Version 1.13.0-dev.3.0

Merge commit '8d96919609c6f1916fafbcbbc7a0639131606fc4' into dev
diff --git a/.gitattributes b/.gitattributes
index 9dfc906..8378d02 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,5 +1,6 @@
 # Explicitly declare text files we want to be normalized.
 *.c text
+*.cc text
 *.cpp text
 *.h text
 *.gyp text
diff --git a/.gitignore b/.gitignore
index 116adee..eaa131d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,12 +15,12 @@
 /xcodebuild
 /.flaky.log
 /.debug.log
-/*.Makefile
+*.Makefile
 *.opensdf
 *.sdf
 *.sln
 *.suo
-/*.target.mk
+*.target.mk
 *.host.mk
 *.vcproj
 *.vcxproj
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 80077f2..d7daf24 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,7 +6,7 @@
     as all `allMatches` implementations are intended to be.
 
 * `dart:io`
-  * `HttpClient` no longer sends URI fragments in the requeust. This is not
+  * `HttpClient` no longer sends URI fragments in the request. This is not
     allowed by the HTTP protocol.
     The `HttpServer` still gracefully receives fragments, but discards them
     before delivering the request.
diff --git a/DEPS b/DEPS
index a111db0..948d24c 100644
--- a/DEPS
+++ b/DEPS
@@ -51,7 +51,7 @@
   "crypto_rev" : "@2df57a1e26dd88e8d0614207d4b062c73209917d",
   "csslib_tag" : "@0.12.0",
   "dart2js_info_rev" : "@bad01369f1f605ab688d505c135db54de927318f",
-  "dartdoc_rev" : "@8ef4cae550ea7ad47c5eb997b36ad2ba14ff53f7",
+  "dartdoc_rev" : "@ae12ca7aa2ea15535fac9e262cab65e3c2b66a04",
   "dart_services_rev" : "@7aea2574e6f3924bf409a80afb8ad52aa2be4f97",
   "dart_style_tag": "@0.2.0",
   "dev_compiler_rev": "@0.1.7",
@@ -68,15 +68,13 @@
   "intl_rev": "@32047558bd220a53c1f4d93a26d54b83533b1475",
   "jinja2_rev": "@2222b31554f03e62600cd7e383376a7c187967a1",
   "json_rpc_2_tag": "@1.1.1",
-  "linter_tag": "@0.1.0",
+  "linter_rev": "@140ee2d1d7a255cf1265e990e528c6575ab2d5bb",
   "logging_rev": "@85d83e002670545e9039ad3985f0018ab640e597",
   "markdown_rev": "@9a1071a859df9c9edd4f556e948f898f70bf1e5e",
   "matcher_tag": "@0.12.0",
   "metatest_rev": "@e5aa8e4e19fc4188ac2f6d38368a47d8f07c3df1",
   "mime_rev": "@75890811d4af5af080351ba8a2853ad4c8df98dd",
   "mustache4dart_rev" : "@5724cfd85151e5b6b53ddcd3380daf188fe47f92",
-  "net_nss_rev": "@f81948e9a402db94287a43bb34a07ee0daf56cb5",
-  "nss_rev": "@87b96db4268293187d7cf741907a6d5d1d8080e0",
   "oauth2_rev": "@1bff41f4d54505c36f2d1a001b83b8b745c452f5",
   "observe_rev": "@eee2b8ec34236fa46982575fbccff84f61202ac6",
   "observatory_pub_packages_rev": "@cdc4b3d4c15b9c0c8e7702dff127b440afbb7485",
@@ -86,22 +84,21 @@
   "ply_rev": "@604b32590ffad5cbb82e4afef1d305512d06ae93",
   "plugin_tag": "@0.1.0",
   "pool_rev": "@e454b4b54d2987e8d2f0fbd3ac519641ada9bd0f",
-  "pub_rev": "@d90268693d1a9dbe5ea11cd9c80b842e3bf1581c",
+  "pub_rev": "@1c08b841158e33b8090bb07e5c39df830db58d44",
   "pub_cache_tag": "@v0.1.0",
   "pub_semver_tag": "@1.2.1",
   "quiver_tag": "@0.21.4",
   "root_certificates_rev": "@c3a41df63afacec62fcb8135196177e35fe72f71",
   "scheduled_test_tag": "@0.12.1+2",
-  "shelf_rev": "@1e87b79b21ac5e6fa2f93576d6c06eaa65285ef4",
+  "shelf_tag": "@0.6.2+1",
   "smoke_rev" : "@f3361191cc2a85ebc1e4d4c33aec672d7915aba9",
   "source_maps_tag": "@0.10.1",
-  "sqlite_rev": "@38811b79f42801662adc0458a25270ab690a6b81",
-  "shelf_static_rev": "@v0.2.1",
-  "shelf_web_socket_rev": "@ff170cec2c0e4e5722cdf47c557be63b5035a602",
+  "shelf_static_tag": "@0.2.3+1",
+  "shelf_web_socket_tag": "@0.0.1+4",
   "source_map_stack_trace_tag": "@1.0.4",
-  "source_span_tag": "@1.1.2",
+  "source_span_tag": "@1.2.0",
   "stack_trace_tag": "@1.3.4",
-  "string_scanner_rev": "@3e7617d6f74ba382e9b6130b1cc12091d89a9bc5",
+  "string_scanner_tag": "@0.1.4",
   "sunflower_rev": "@879b704933413414679396b129f5dfa96f7a0b1e",
   "test_tag": "@0.12.3+8",
   "test_reflective_loader_tag": "@0.0.3",
@@ -113,7 +110,7 @@
   "which_tag": "@0.1.3+1",
   "web_components_rev": "@0e636b534d9b12c9e96f841e6679398e91a986ec",
   "WebCore_rev" : "@44061",
-  "yaml_rev": "@563a5ffd4a800a2897b8f4dd6b19f2a370df2f2b",
+  "yaml_tag": "@2.1.5",
   "zlib_rev": "@c3d0a6190f2f8c924a05ab6cc97b8f975bddd33f",
   "font_awesome_rev": "@31824",
   "barback-0.13.0_rev": "@34853",
@@ -130,21 +127,10 @@
   Var("dart_root") + "/tests/co19/src":
       (Var("github_mirror") % "co19") + Var("co19_rev"),
 
-  Var("dart_root") + "/third_party/nss":
-      Var("chromium_git") + "/chromium/deps/nss.git" + Var("nss_rev"),
-
-  Var("dart_root") + "/third_party/sqlite":
-      Var("chromium_git") + "/chromium/src/third_party/sqlite.git" +
-      Var("sqlite_rev"),
-
   Var("dart_root") + "/third_party/zlib":
       Var("chromium_git") + "/chromium/src/third_party/zlib.git" +
       Var("zlib_rev"),
 
-  Var("dart_root") + "/third_party/net_nss":
-      Var("chromium_git") + "/chromium/src/net/third_party/nss.git" +
-      Var("net_nss_rev"),
-
   Var("dart_root") + "/third_party/boringssl/src":
       "https://boringssl.googlesource.com/boringssl.git" +
       Var("boringssl_rev"),
@@ -231,7 +217,7 @@
   Var("dart_root") + "/third_party/pkg/json_rpc_2":
       (Var("github_mirror") % "json_rpc_2") + Var("json_rpc_2_tag"),
   Var("dart_root") + "/third_party/pkg/linter":
-      (Var("github_mirror") % "linter") + Var("linter_tag"),
+      (Var("github_mirror") % "linter") + Var("linter_rev"),
   Var("dart_root") + "/third_party/pkg/logging":
       (Var("github_mirror") % "logging") + Var("logging_rev"),
   Var("dart_root") + "/third_party/pkg/markdown":
@@ -275,12 +261,12 @@
   Var("dart_root") + "/third_party/pkg/scheduled_test":
       (Var("github_mirror") % "scheduled_test") + Var("scheduled_test_tag"),
   Var("dart_root") + "/third_party/pkg/shelf":
-      (Var("github_mirror") % "shelf") + Var("shelf_rev"),
+      (Var("github_mirror") % "shelf") + Var("shelf_tag"),
   Var("dart_root") + "/third_party/pkg/shelf_static":
-      (Var("github_mirror") % "shelf_static") + Var("shelf_static_rev"),
+      (Var("github_mirror") % "shelf_static") + Var("shelf_static_tag"),
   Var("dart_root") + "/third_party/pkg/shelf_web_socket":
       (Var("github_mirror") % "shelf_web_socket") +
-      Var("shelf_web_socket_rev"),
+      Var("shelf_web_socket_tag"),
   Var("dart_root") + "/third_party/pkg/smoke":
       (Var("github_mirror") % "smoke") + Var("smoke_rev"),
   Var("dart_root") + "/third_party/pkg/source_maps":
@@ -294,7 +280,7 @@
       (Var("github_mirror") % "stack_trace") + Var("stack_trace_tag"),
   Var("dart_root") + "/third_party/pkg/string_scanner":
       (Var("github_mirror") % "string_scanner") +
-      Var("string_scanner_rev"),
+      Var("string_scanner_tag"),
   Var("dart_root") + "/third_party/sunflower":
       (Var("github_mirror") % "sample-sunflower") +
       Var("sunflower_rev"),
@@ -319,7 +305,7 @@
   Var("dart_root") + "/third_party/pkg/which":
       (Var("github_mirror") % "which") + Var("which_tag"),
   Var("dart_root") + "/third_party/pkg/yaml":
-      (Var("github_mirror") % "yaml") + Var("yaml_rev"),
+      (Var("github_mirror") % "yaml") + Var("yaml_tag"),
 
   # These specific versions of barback and source_maps are used for testing and
   # should be pulled from bleeding_edge even on channels.
diff --git a/pkg/analysis_server/benchmark/integration/driver.dart b/pkg/analysis_server/benchmark/integration/driver.dart
index a3167810..80aec4c1 100644
--- a/pkg/analysis_server/benchmark/integration/driver.dart
+++ b/pkg/analysis_server/benchmark/integration/driver.dart
@@ -264,6 +264,7 @@
         m.printSummary(keyLen);
       }
     }
+
     /// TODO(danrubel) *** print warnings if driver caches are not empty ****
     print('''
 
diff --git a/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart b/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart
index 790da05..a43d4b4 100644
--- a/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart
+++ b/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart
@@ -29,8 +29,7 @@
    */
   StringBuffer readBuffer = null;
 
-  InstrumentationInputConverter(
-      String tmpSrcDirPath, PathMap srcPathMap)
+  InstrumentationInputConverter(String tmpSrcDirPath, PathMap srcPathMap)
       : super(tmpSrcDirPath, srcPathMap);
 
   @override
diff --git a/pkg/analysis_server/benchmark/integration/local_runner.dart b/pkg/analysis_server/benchmark/integration/local_runner.dart
index 78d8c2a..bd0ff6b 100644
--- a/pkg/analysis_server/benchmark/integration/local_runner.dart
+++ b/pkg/analysis_server/benchmark/integration/local_runner.dart
@@ -51,11 +51,8 @@
   if (!new Directory(join(gitDir.path, outDirName)).existsSync()) {
     throw 'failed to find out or xcodebuild directory';
   }
-  result = Process.runSync('ln', [
-    '-s',
-    join(gitDir.path, outDirName),
-    join(tmpSrcDirPath, outDirName)
-  ]);
+  result = Process.runSync('ln',
+      ['-s', join(gitDir.path, outDirName), join(tmpSrcDirPath, outDirName)]);
   if (result.exitCode != 0) throw 'failed to link out or xcodebuild: $result';
   /*
    * Collect arguments
diff --git a/pkg/analysis_server/benchmark/integration/main.dart b/pkg/analysis_server/benchmark/integration/main.dart
index 7cfb299..100ab6f 100644
--- a/pkg/analysis_server/benchmark/integration/main.dart
+++ b/pkg/analysis_server/benchmark/integration/main.dart
@@ -74,9 +74,11 @@
 ArgParser get argParser {
   _argParser = new ArgParser();
 
-  _argParser.addOption(INPUT_CMDLINE_OPTION, abbr: 'i', help: '<filePath>\n'
-      'The input file specifying how this client should interact with the server.\n'
-      'If the input file name is "stdin", then the instructions are read from standard input.');
+  _argParser.addOption(INPUT_CMDLINE_OPTION,
+      abbr: 'i',
+      help: '<filePath>\n'
+          'The input file specifying how this client should interact with the server.\n'
+          'If the input file name is "stdin", then the instructions are read from standard input.');
   _argParser.addOption(MAP_OPTION,
       abbr: 'm',
       allowMultiple: true,
@@ -87,9 +89,11 @@
           'to the target source directory <newSrcPath> used during performance testing.\n'
           'Multiple mappings can be specified.\n'
           'WARNING: The contents of the target directory will be modified');
-  _argParser.addOption(TMP_SRC_DIR_OPTION, abbr: 't', help: '<dirPath>\n'
-      'The temporary directory containing source used during performance measurement.\n'
-      'WARNING: The contents of the target directory will be modified');
+  _argParser.addOption(TMP_SRC_DIR_OPTION,
+      abbr: 't',
+      help: '<dirPath>\n'
+          'The temporary directory containing source used during performance measurement.\n'
+          'WARNING: The contents of the target directory will be modified');
   _argParser.addFlag(NEW_TASK_MODEL_OPTION,
       help: "enable the use of the new task model",
       defaultsTo: false,
@@ -119,7 +123,9 @@
     inputRaw = new File(args.inputPath).openRead();
   }
   for (PathMapEntry entry in args.srcPathMap.entries) {
-    logger.log(Level.INFO, 'mapping source path\n'
+    logger.log(
+        Level.INFO,
+        'mapping source path\n'
         '  from ${entry.oldSrcPrefix}\n  to   ${entry.newSrcPrefix}');
   }
   logger.log(Level.INFO, 'tmpSrcDir: ${args.tmpSrcDirPath}');
@@ -224,7 +230,6 @@
  * The performance measurement arguments specified on the command line.
  */
 class PerfArgs {
-
   /**
    * The file path of the instrumentation or log file
    * used to drive performance measurement,
diff --git a/pkg/analysis_server/benchmark/integration/operation.dart b/pkg/analysis_server/benchmark/integration/operation.dart
index 9e408d8..761698e 100644
--- a/pkg/analysis_server/benchmark/integration/operation.dart
+++ b/pkg/analysis_server/benchmark/integration/operation.dart
@@ -87,8 +87,8 @@
     void recordResult(bool success, result) {
       Duration elapsed = stopwatch.elapsed;
       driver.results.record(method, elapsed, success: success);
-      driver.logger.log(
-          Level.FINE, 'Response received: $method : $elapsed\n  $result');
+      driver.logger
+          .log(Level.FINE, 'Response received: $method : $elapsed\n  $result');
     }
 
     driver.send(method, json['params']).then((Map<String, dynamic> result) {
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 901200f..feaa424 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -3142,7 +3142,7 @@
             <p>
               The indexes of the targets (in the enclosing navigation response)
               to which the given region is bound. By opening the target, clients
-              can implement one form of navigation.
+              can implement one form of navigation. This list cannot be empty.
             </p>
           </dd></dl></dd><dt class="typeDefinition"><a name="type_NavigationTarget">NavigationTarget: object</a></dt><dd>
         <p>
diff --git a/pkg/analysis_server/lib/analysis/analysis_domain.dart b/pkg/analysis_server/lib/analysis/analysis_domain.dart
index 27e8678..a046665 100644
--- a/pkg/analysis_server/lib/analysis/analysis_domain.dart
+++ b/pkg/analysis_server/lib/analysis/analysis_domain.dart
@@ -3,7 +3,27 @@
 // BSD-style license that can be found in the LICENSE file.
 
 /**
- * Support for client code that extends the analysis aspect of analysis server.
+ * Support for client code that interacts with the analysis domain of an
+ * analysis server.
+ *
+ * Plugins can gain access to the request handler that implements the analysis
+ * domain in order to extend the functionality of that domain. The class
+ * [AnalysisDomain] defines the API of the analysis domain that plugins can use.
+ *
+ * If a plugin is interested in gaining access to the analysis domain, it should
+ * register a function by including code like the following in the plugin's
+ * registerExtensions method:
+ *
+ *     AnalysisDomain analysisDomain;
+ *
+ *     @override
+ *     void registerExtensions(RegisterExtension registerExtension) {
+ *       ...
+ *       registerExtension(
+ *           SET_ANALYSIS_DOMAIN_EXTENSION_POINT_ID,
+ *           (AnalysisDomain domain) => analysisDomain = domain);
+ *       ...
+ *     }
  */
 library analysis_server.analysis;
 
@@ -18,31 +38,37 @@
 import 'package:plugin/plugin.dart';
 
 /**
- * The identifier of the extension point that allows plugins to get access to
- * `AnalysisSite`. The object used as an extension must be
- * a [SetAnalysisDomain].
+ * The identifier of the extension point that allows plugins to get access to an
+ * [AnalysisDomain]. The object used as an extension must be a
+ * [SetAnalysisDomain].
  */
 final String SET_ANALYSIS_DOMAIN_EXTENSION_POINT_ID = Plugin.join(
     ServerPlugin.UNIQUE_IDENTIFIER,
     ServerPlugin.SET_ANALISYS_DOMAIN_EXTENSION_POINT);
 
 /**
- * A function that is invoked on the `analysis` domain creation.
+ * A function that is invoked after the analysis domain has been created and is
+ * initialized.
  */
-typedef void SetAnalysisDomain(AnalysisDomain site);
+typedef void SetAnalysisDomain(AnalysisDomain domain);
 
 /**
- * An object that gives [SetAnalysisDomain]s access to the `analysis` domain
- * of the analysis server.
+ * An object that gives plugins access to the analysis domain of the analysis
+ * server.
  *
  * Clients are not expected to subtype this class.
  */
 abstract class AnalysisDomain {
   /**
    * Return the stream that is notified when a new value for the given
-   * [descriptor] is computed.
+   * [result] is computed.
+   *
+   * This method should be used by plugins that need to perform some additional
+   * processing after analysis has completed. One example would be a plugin that
+   * needed to send a notification to the client because some data was now
+   * invalidated.
    */
-  Stream<ComputedResult> onResultComputed(ResultDescriptor descriptor);
+  Stream<ComputedResult> onResultComputed(ResultDescriptor result);
 
   /**
    * Schedule sending the given [service] notifications for the given [source]
diff --git a/pkg/analysis_server/lib/analysis/navigation/navigation_core.dart b/pkg/analysis_server/lib/analysis/navigation_core.dart
similarity index 69%
rename from pkg/analysis_server/lib/analysis/navigation/navigation_core.dart
rename to pkg/analysis_server/lib/analysis/navigation_core.dart
index c708d9a..e2f56f8 100644
--- a/pkg/analysis_server/lib/analysis/navigation/navigation_core.dart
+++ b/pkg/analysis_server/lib/analysis/navigation_core.dart
@@ -2,7 +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.
 
-library analysis_server.analysis.navigation.navigation_core;
+library analysis_server.analysis.navigation_core;
 
 import 'package:analysis_server/src/protocol.dart'
     show ElementKind, Location, NavigationRegion, NavigationTarget;
@@ -16,11 +16,11 @@
  */
 abstract class NavigationContributor {
   /**
-   * Contribute navigation regions for a part of the given [source] into the
-   * given [holder]. The part is specified by the [offset] and [length].
-   * The [context] can be used to get analysis results.
+   * Contribute navigation regions for a subset of the content of the given
+   * [source] into the given [collector]. The subset is specified by the
+   * [offset] and [length]. The [context] can be used to access analysis results.
    */
-  void computeNavigation(NavigationHolder holder, AnalysisContext context,
+  void computeNavigation(NavigationCollector collector, AnalysisContext context,
       Source source, int offset, int length);
 }
 
@@ -30,10 +30,10 @@
  *
  * Clients are not expected to subtype this class.
  */
-abstract class NavigationHolder {
+abstract class NavigationCollector {
   /**
    * Record a new navigation region with the given [offset] and [length] that
-   * should navigation to the given [targetLocation].
+   * should navigate to the given [targetLocation].
    */
   void addRegion(
       int offset, int length, ElementKind targetKind, Location targetLocation);
diff --git a/pkg/analysis_server/lib/analysis/occurrences_core.dart b/pkg/analysis_server/lib/analysis/occurrences_core.dart
new file mode 100644
index 0000000..2e24a9b
--- /dev/null
+++ b/pkg/analysis_server/lib/analysis/occurrences_core.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2015, 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 analysis_server.analysis.occurrences_core;
+
+import 'package:analysis_server/src/protocol.dart' show Element, Occurrences;
+import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
+import 'package:analyzer/src/generated/source.dart' show Source;
+
+/**
+ * An object used to produce occurrences.
+ *
+ * Clients are expected to subtype this class when implementing plugins.
+ */
+abstract class OccurrencesContributor {
+  /**
+   * Contribute occurrences into the given [collector].
+   * The [context] can be used to get analysis results.
+   */
+  void computeOccurrences(
+      OccurrencesCollector collector, AnalysisContext context, Source source);
+}
+
+/**
+ * An object that [OccurrencesContributor]s use to record occurrences into.
+ *
+ * Clients are not expected to subtype this class.
+ */
+abstract class OccurrencesCollector {
+  /**
+   * Record a new element occurrences.
+   */
+  void addOccurrences(Occurrences occurrences);
+}
diff --git a/pkg/analysis_server/lib/edit/assist/assist_dart.dart b/pkg/analysis_server/lib/edit/assist/assist_dart.dart
index ec6718c..742655c 100644
--- a/pkg/analysis_server/lib/edit/assist/assist_dart.dart
+++ b/pkg/analysis_server/lib/edit/assist/assist_dart.dart
@@ -13,7 +13,7 @@
  * An [AssistContributor] that can be used to contribute assists for Dart
  * files.
  *
- * Clients are expected to subtype this class when implementing plugins.
+ * Clients are expected to extend this class when implementing plugins.
  */
 abstract class DartAssistContributor extends AssistContributor {
   @override
diff --git a/pkg/analysis_server/lib/edit/fix/fix_dart.dart b/pkg/analysis_server/lib/edit/fix/fix_dart.dart
index c009e68..2229ed2 100644
--- a/pkg/analysis_server/lib/edit/fix/fix_dart.dart
+++ b/pkg/analysis_server/lib/edit/fix/fix_dart.dart
@@ -15,7 +15,7 @@
  * A [FixContributor] that can be used to contribute fixes for errors in Dart
  * files.
  *
- * Clients are expected to subtype this class when implementing plugins.
+ * Clients are expected to extend this class when implementing plugins.
  */
 abstract class DartFixContributor extends FixContributor {
   @override
diff --git a/pkg/analysis_server/lib/plugin/analyzed_files.dart b/pkg/analysis_server/lib/plugin/analyzed_files.dart
index 12c9214..7eda12c 100644
--- a/pkg/analysis_server/lib/plugin/analyzed_files.dart
+++ b/pkg/analysis_server/lib/plugin/analyzed_files.dart
@@ -11,6 +11,20 @@
  * The analysis server will invoke the contributed functions and analyze the
  * file if at least one of the functions returns `true`. (The server is not
  * required to invoke every function with every file.)
+ *
+ * If a plugin is interested in analyzing a certain kind of files, it needs to
+ * ensure that files of that kind will be analyzed. It should register a
+ * function by including code like the following in the plugin's
+ * registerExtensions method:
+ *
+ *     @override
+ *     void registerExtensions(RegisterExtension registerExtension) {
+ *       ...
+ *       registerExtension(
+ *           ANALYZE_FILE_EXTENSION_POINT_ID,
+ *           (File file) => file.path.endsWith(...));
+ *       ...
+ *     }
  */
 library analysis_server.plugin.analyzed_files;
 
diff --git a/pkg/analysis_server/lib/plugin/assist.dart b/pkg/analysis_server/lib/plugin/assist.dart
index 393a479..0955d10 100644
--- a/pkg/analysis_server/lib/plugin/assist.dart
+++ b/pkg/analysis_server/lib/plugin/assist.dart
@@ -5,6 +5,22 @@
 /**
  * Support for client code that extends the analysis server by adding new assist
  * contributors.
+ *
+ * Plugins can register assist contributors. The registered contributors will be
+ * used to get assists any time a client issues an 'edit.getAssists' request.
+ *
+ * If a plugin wants to add assists, it should implement the class
+ * [AssistContributor] and then register the contributor by including code like
+ * the following in the plugin's registerExtensions method:
+ *
+ *     @override
+ *     void registerExtensions(RegisterExtension registerExtension) {
+ *       ...
+ *       registerExtension(
+ *           ASSIST_CONTRIBUTOR_EXTENSION_POINT_ID,
+ *           new MyAssistContributor());
+ *       ...
+ *     }
  */
 library analysis_server.plugin.assist;
 
diff --git a/pkg/analysis_server/lib/plugin/completion.dart b/pkg/analysis_server/lib/plugin/completion.dart
index 8fd6159..9b1c4b5 100644
--- a/pkg/analysis_server/lib/plugin/completion.dart
+++ b/pkg/analysis_server/lib/plugin/completion.dart
@@ -5,6 +5,23 @@
 /**
  * Support for client code that extends the analysis server by adding new code
  * completion contributors.
+ *
+ * Plugins can register completion contributors. The registered contributors
+ * will be used to get completions any time a client issues a
+ * 'completion.getSuggestions' request.
+ *
+ * If a plugin wants to add completions, it should implement the class
+ * [CompletionContributor] and then register the contributor by including code
+ * like the following in the plugin's registerExtensions method:
+ *
+ *     @override
+ *     void registerExtensions(RegisterExtension registerExtension) {
+ *       ...
+ *       registerExtension(
+ *           COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
+ *           new MyCompletionContributor());
+ *       ...
+ *     }
  */
 library analysis_server.plugin.completion;
 
diff --git a/pkg/analysis_server/lib/plugin/fix.dart b/pkg/analysis_server/lib/plugin/fix.dart
index 45f69a6..d274f61 100644
--- a/pkg/analysis_server/lib/plugin/fix.dart
+++ b/pkg/analysis_server/lib/plugin/fix.dart
@@ -5,6 +5,22 @@
 /**
  * Support for client code that extends the analysis server by adding new fix
  * contributors.
+ *
+ * Plugins can register fix contributors. The registered contributors will be
+ * used to get fixes any time a client issues an 'edit.getFixes' request.
+ *
+ * If a plugin wants to add fixes, it should implement the class
+ * [FixContributor] and then register the contributor by including code like the
+ * following in the plugin's registerExtensions method:
+ *
+ *     @override
+ *     void registerExtensions(RegisterExtension registerExtension) {
+ *       ...
+ *       registerExtension(
+ *           FIX_CONTRIBUTOR_EXTENSION_POINT_ID,
+ *           new MyFixContributor());
+ *       ...
+ *     }
  */
 library analysis_server.plugin.fix;
 
diff --git a/pkg/analysis_server/lib/plugin/index.dart b/pkg/analysis_server/lib/plugin/index.dart
index 096c28d..088ae52 100644
--- a/pkg/analysis_server/lib/plugin/index.dart
+++ b/pkg/analysis_server/lib/plugin/index.dart
@@ -5,6 +5,28 @@
 /**
  * Support for client code that extends the analysis server by adding new index
  * contributors.
+ *
+ * Plugins can register index contributors. The registered contributors will be
+ * used to contribute relationships to the index when the analysis of a file has
+ * been completed.
+ *
+ * Typical relationships include things like "this variable is referenced here"
+ * or "this method is invoked here". The index is used to improve the
+ * performance of operations such as search or building a type hierarchy by
+ * pre-computing some of the information needed by those operations.
+ *
+ * If a plugin wants to contribute information to the index, it should implement
+ * the class [IndexContributor] and then register the contributor by including
+ * code like the following in the plugin's registerExtensions method:
+ *
+ *     @override
+ *     void registerExtensions(RegisterExtension registerExtension) {
+ *       ...
+ *       registerExtension(
+ *           INDEX_CONTRIBUTOR_EXTENSION_POINT_ID,
+ *           new MyIndexContributor());
+ *       ...
+ *     }
  */
 library analysis_server.plugin.index;
 
diff --git a/pkg/analysis_server/lib/plugin/navigation.dart b/pkg/analysis_server/lib/plugin/navigation.dart
index 23603f0..4ef8f2d 100644
--- a/pkg/analysis_server/lib/plugin/navigation.dart
+++ b/pkg/analysis_server/lib/plugin/navigation.dart
@@ -5,10 +5,28 @@
 /**
  * Support for client code that extends the analysis server by adding new
  * navigation contributors.
+ *
+ * Plugins can register navigation contributors. The registered contributors
+ * will be used to get navigation regions any time a client issues an
+ * 'analysis.getNavigation' request or the server is about to send an
+ * 'analysis.navigation' notification.
+ *
+ * If a plugin wants to add navigation regions, it should implement the class
+ * [NavigationContributor] and then register the contributor by including code
+ * like the following in the plugin's registerExtensions method:
+ *
+ *     @override
+ *     void registerExtensions(RegisterExtension registerExtension) {
+ *       ...
+ *       registerExtension(
+ *           NAVIGATION_CONTRIBUTOR_EXTENSION_POINT_ID,
+ *           new MyNavigationContributor());
+ *       ...
+ *     }
  */
 library analysis_server.plugin.navigation;
 
-import 'package:analysis_server/analysis/navigation/navigation_core.dart';
+import 'package:analysis_server/analysis/navigation_core.dart';
 import 'package:analysis_server/src/plugin/server_plugin.dart';
 import 'package:plugin/plugin.dart';
 
diff --git a/pkg/analysis_server/lib/plugin/occurrences.dart b/pkg/analysis_server/lib/plugin/occurrences.dart
new file mode 100644
index 0000000..5339ccc
--- /dev/null
+++ b/pkg/analysis_server/lib/plugin/occurrences.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2015, 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.
+
+/**
+ * Support for client code that extends the analysis server by adding new
+ * occurrences contributors.
+ */
+library analysis_server.plugin.occurrences;
+
+import 'package:analysis_server/analysis/occurrences_core.dart';
+import 'package:analysis_server/src/plugin/server_plugin.dart';
+import 'package:plugin/plugin.dart';
+
+/**
+ * The identifier of the extension point that allows plugins to register
+ * element occurrences. The object used as an extension must be
+ * a [OccurrencesContributor].
+ */
+final String OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT_ID = Plugin.join(
+    ServerPlugin.UNIQUE_IDENTIFIER,
+    ServerPlugin.OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT);
diff --git a/pkg/analysis_server/lib/src/analysis_logger.dart b/pkg/analysis_server/lib/src/analysis_logger.dart
index 56f1435..9e751a4 100644
--- a/pkg/analysis_server/lib/src/analysis_logger.dart
+++ b/pkg/analysis_server/lib/src/analysis_logger.dart
@@ -21,7 +21,11 @@
   AnalysisLogger() {
     logging.Logger.root.onRecord.listen((logging.LogRecord record) {
       AnalysisEngine.instance.instrumentationService.logLogEntry(
-          record.level.name, record.time, record.message, record.error, record.stackTrace);
+          record.level.name,
+          record.time,
+          record.message,
+          record.error,
+          record.stackTrace);
     });
   }
 
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 5d0fb7d..1df76ad 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -284,9 +284,6 @@
    * Initialize a newly created server to receive requests from and send
    * responses to the given [channel].
    *
-   * If a [contextManager] is provided, then the [packageResolverProvider] will
-   * be ignored.
-   *
    * If [rethrowExceptions] is true, then any exceptions thrown by analysis are
    * propagated up the call stack.  The default is true to allow analysis
    * exceptions to show up in unit tests, but it should be set to false when
@@ -301,17 +298,14 @@
       this.options,
       this.defaultSdk,
       this.instrumentationService,
-      {ContextManager contextManager: null,
-      ResolverProvider packageResolverProvider: null,
+      {ResolverProvider packageResolverProvider: null,
       this.rethrowExceptions: true})
       : index = _index,
         searchEngine = _index != null ? createSearchEngine(_index) : null {
     _performance = performanceDuringStartup;
     operationQueue = new ServerOperationQueue();
-    if (contextManager == null) {
-      contextManager = new ContextManagerImpl(resourceProvider,
-          packageResolverProvider, packageMapProvider, instrumentationService);
-    }
+    contextManager = new ContextManagerImpl(resourceProvider,
+        packageResolverProvider, packageMapProvider, instrumentationService);
     ServerContextManagerCallbacks contextManagerCallbacks =
         new ServerContextManagerCallbacks(this, resourceProvider);
     contextManager.callbacks = contextManagerCallbacks;
@@ -321,7 +315,6 @@
     defaultContextOptions.incrementalValidation =
         options.enableIncrementalResolutionValidation;
     defaultContextOptions.generateImplicitErrors = false;
-    this.contextManager = contextManager;
     _noErrorNotification = options.noErrorNotification;
     AnalysisEngine.instance.logger = new AnalysisLogger();
     _onAnalysisStartedController = new StreamController.broadcast();
@@ -484,9 +477,9 @@
    * first context that implicitly analyzes it.
    *
    * If the [path] is not analyzed by any context, a [ContextSourcePair] with
-   * a `null` context and `file` [Source] is returned.
+   * a `null` context and a `file` [Source] is returned.
    *
-   * If the [path] dosn't represent a file, a [ContextSourcePair] with a `null`
+   * If the [path] doesn't represent a file, a [ContextSourcePair] with a `null`
    * context and `null` [Source] is returned.
    *
    * Does not return `null`.
@@ -975,7 +968,7 @@
                 sendAnalysisNotificationNavigation(this, context, source);
                 break;
               case AnalysisService.OCCURRENCES:
-                sendAnalysisNotificationOccurrences(this, file, dartUnit);
+                sendAnalysisNotificationOccurrences(this, context, source);
                 break;
               case AnalysisService.OUTLINE:
                 AnalysisContext context = dartUnit.element.context;
diff --git a/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart b/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart
index bfcac2d..44d917e 100644
--- a/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart
+++ b/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart
@@ -30,7 +30,7 @@
 
   ByteStreamClientChannel(this.input, this.output) {
     Stream jsonStream = input
-        .transform((new Utf8Codec()).decoder)
+        .transform(const Utf8Decoder())
         .transform(new LineSplitter())
         .transform(new JsonStreamDecoder())
         .where((json) => json is Map)
@@ -106,7 +106,7 @@
   void listen(void onRequest(Request request),
       {Function onError, void onDone()}) {
     _input
-        .transform((new Utf8Codec()).decoder)
+        .transform(const Utf8Decoder())
         .transform(new LineSplitter())
         .listen((String data) => _readRequest(data, onRequest),
             onError: onError, onDone: () {
diff --git a/pkg/analysis_server/lib/src/computer/computer_occurrences.dart b/pkg/analysis_server/lib/src/computer/computer_occurrences.dart
deleted file mode 100644
index 4897a1a..0000000
--- a/pkg/analysis_server/lib/src/computer/computer_occurrences.dart
+++ /dev/null
@@ -1,78 +0,0 @@
-// 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 computer.occurrences;
-
-import 'dart:collection';
-
-import 'package:analysis_server/src/protocol_server.dart' as protocol;
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/element.dart';
-
-/**
- * A computer for elements occurrences in a Dart [CompilationUnit].
- */
-class DartUnitOccurrencesComputer {
-  final CompilationUnit _unit;
-
-  final Map<Element, List<int>> _elementsOffsets =
-      new HashMap<Element, List<int>>();
-
-  DartUnitOccurrencesComputer(this._unit);
-
-  /**
-   * Returns the computed occurrences, not `null`.
-   */
-  List<protocol.Occurrences> compute() {
-    _unit.accept(new _DartUnitOccurrencesComputerVisitor(this));
-    List<protocol.Occurrences> occurrences = <protocol.Occurrences>[];
-    _elementsOffsets.forEach((engineElement, offsets) {
-      var serverElement = protocol.newElement_fromEngine(engineElement);
-      var length = engineElement.displayName.length;
-      occurrences.add(new protocol.Occurrences(serverElement, offsets, length));
-    });
-    return occurrences;
-  }
-
-  void _addOccurrence(Element element, int offset) {
-    element = _canonicalizeElement(element);
-    if (element == null || element == DynamicElementImpl.instance) {
-      return;
-    }
-    List<int> offsets = _elementsOffsets[element];
-    if (offsets == null) {
-      offsets = <int>[];
-      _elementsOffsets[element] = offsets;
-    }
-    offsets.add(offset);
-  }
-
-  Element _canonicalizeElement(Element element) {
-    if (element is FieldFormalParameterElement) {
-      element = (element as FieldFormalParameterElement).field;
-    }
-    if (element is PropertyAccessorElement) {
-      element = (element as PropertyAccessorElement).variable;
-    }
-    if (element is Member) {
-      element = (element as Member).baseElement;
-    }
-    return element;
-  }
-}
-
-class _DartUnitOccurrencesComputerVisitor extends RecursiveAstVisitor {
-  final DartUnitOccurrencesComputer computer;
-
-  _DartUnitOccurrencesComputerVisitor(this.computer);
-
-  @override
-  visitSimpleIdentifier(SimpleIdentifier node) {
-    Element element = node.bestElement;
-    if (element != null) {
-      computer._addOccurrence(element, node.offset);
-    }
-    return super.visitSimpleIdentifier(node);
-  }
-}
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index ac5bced..153461a 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -531,6 +531,10 @@
       Resource resource = resourceProvider.getResource(path);
       if (resource is Folder) {
         includedFolders.add(resource);
+      } else if (!resource.exists) {
+        // Non-existent resources are ignored.  TODO(paulberry): we should set
+        // up a watcher to ensure that if the resource appears later, we will
+        // begin analyzing it.
       } else {
         // TODO(scheglov) implemented separate files analysis
         throw new UnimplementedError('$path is not a folder. '
@@ -1353,8 +1357,10 @@
   @override
   Iterable<UriResolver> createPackageUriResolvers(
           ResourceProvider resourceProvider) =>
-      <UriResolver>[new SdkExtUriResolver(packageMap),
-                    new PackageMapUriResolver(resourceProvider, packageMap)];
+      <UriResolver>[
+        new SdkExtUriResolver(packageMap),
+        new PackageMapUriResolver(resourceProvider, packageMap)
+      ];
 }
 
 /**
@@ -1372,7 +1378,7 @@
 
   @override
   Iterable<UriResolver> createPackageUriResolvers(
-          ResourceProvider resourceProvider) {
+      ResourceProvider resourceProvider) {
     if (packages != null) {
       // Construct package map for the SdkExtUriResolver.
       Map<String, List<Folder>> packageMap = <String, List<Folder>>{};
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index 5dd9feb..48dcc67 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -14,7 +14,10 @@
 import 'package:analysis_server/src/context_manager.dart';
 import 'package:analysis_server/src/domains/analysis/navigation.dart';
 import 'package:analysis_server/src/operation/operation_analysis.dart'
-    show sendAnalysisNotificationNavigation;
+    show
+        NavigationOperation,
+        OccurrencesOperation,
+        sendAnalysisNotificationNavigation;
 import 'package:analysis_server/src/protocol_server.dart';
 import 'package:analysis_server/src/services/dependencies/library_dependencies.dart';
 import 'package:analyzer/file_system/file_system.dart';
@@ -136,14 +139,14 @@
             server.sendResponse(new Response.getNavigationInvalidFile(request));
           } else {
             CompilationUnitElement unitElement = units.first.element;
-            NavigationHolderImpl holder = computeNavigation(
+            NavigationCollectorImpl collector = computeNavigation(
                 server,
                 unitElement.context,
                 unitElement.source,
                 params.offset,
                 params.length);
             server.sendResponse(new AnalysisGetNavigationResult(
-                    holder.files, holder.targets, holder.regions)
+                    collector.files, collector.targets, collector.regions)
                 .toResponse(request.id));
           }
           break;
@@ -347,11 +350,13 @@
   @override
   void scheduleNotification(
       engine.AnalysisContext context, Source source, AnalysisService service) {
-    // TODO(scheglov) schedule, don't do it right now
     String file = source.fullName;
     if (server.hasAnalysisSubscription(service, file)) {
       if (service == AnalysisService.NAVIGATION) {
-        sendAnalysisNotificationNavigation(server, context, source);
+        server.scheduleOperation(new NavigationOperation(context, source));
+      }
+      if (service == AnalysisService.OCCURRENCES) {
+        server.scheduleOperation(new OccurrencesOperation(context, source));
       }
     }
   }
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index 23536e2..81d7bf2 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -236,8 +236,11 @@
   /**
    * Send completion notification results.
    */
-  void sendCompletionNotification(String completionId, int replacementOffset,
-      int replacementLength, Iterable<CompletionSuggestion> results,
+  void sendCompletionNotification(
+      String completionId,
+      int replacementOffset,
+      int replacementLength,
+      Iterable<CompletionSuggestion> results,
       bool isLast) {
     server.sendNotification(new CompletionResultsParams(
             completionId, replacementOffset, replacementLength, results, isLast)
diff --git a/pkg/analysis_server/lib/src/domain_server.dart b/pkg/analysis_server/lib/src/domain_server.dart
index 81930b9..7bc7040 100644
--- a/pkg/analysis_server/lib/src/domain_server.dart
+++ b/pkg/analysis_server/lib/src/domain_server.dart
@@ -55,7 +55,8 @@
    */
   Response setSubscriptions(Request request) {
     server.serverServices =
-        new ServerSetSubscriptionsParams.fromRequest(request).subscriptions
+        new ServerSetSubscriptionsParams.fromRequest(request)
+            .subscriptions
             .toSet();
     return new ServerSetSubscriptionsResult().toResponse(request.id);
   }
diff --git a/pkg/analysis_server/lib/src/domains/analysis/navigation.dart b/pkg/analysis_server/lib/src/domains/analysis/navigation.dart
index 859cd7c..cb21c3d 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/navigation.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/navigation.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2015, 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.
 
@@ -6,7 +6,7 @@
 
 import 'dart:collection';
 
-import 'package:analysis_server/analysis/navigation/navigation_core.dart';
+import 'package:analysis_server/analysis/navigation_core.dart';
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/collections.dart';
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
@@ -18,28 +18,28 @@
 /**
  * Compute all known navigation information for the given part of [source].
  */
-NavigationHolderImpl computeNavigation(AnalysisServer server,
+NavigationCollectorImpl computeNavigation(AnalysisServer server,
     AnalysisContext context, Source source, int offset, int length) {
-  NavigationHolderImpl holder = new NavigationHolderImpl();
+  NavigationCollectorImpl collector = new NavigationCollectorImpl();
   List<NavigationContributor> contributors =
       server.serverPlugin.navigationContributors;
   for (NavigationContributor contributor in contributors) {
     try {
-      contributor.computeNavigation(holder, context, source, offset, length);
+      contributor.computeNavigation(collector, context, source, offset, length);
     } catch (exception, stackTrace) {
       AnalysisEngine.instance.logger.logError(
           'Exception from navigation contributor: ${contributor.runtimeType}',
           new CaughtException(exception, stackTrace));
     }
   }
-  holder.sortRegions();
-  return holder;
+  collector.sortRegions();
+  return collector;
 }
 
 /**
- * A concrete implementation of  [NavigationHolder].
+ * A concrete implementation of  [NavigationCollector].
  */
-class NavigationHolderImpl implements NavigationHolder {
+class NavigationCollectorImpl implements NavigationCollector {
   /**
    * A list of navigation regions.
    */
diff --git a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
index 37aaac1b..182f762 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
@@ -1,10 +1,10 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2015, 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 domains.analysis.navigation_dart;
 
-import 'package:analysis_server/analysis/navigation/navigation_core.dart';
+import 'package:analysis_server/analysis/navigation_core.dart';
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
@@ -17,16 +17,17 @@
  */
 class DartNavigationComputer implements NavigationContributor {
   @override
-  void computeNavigation(NavigationHolder holder, AnalysisContext context,
+  void computeNavigation(NavigationCollector collector, AnalysisContext context,
       Source source, int offset, int length) {
     List<Source> libraries = context.getLibrariesContaining(source);
     if (libraries.isNotEmpty) {
       CompilationUnit unit =
           context.getResolvedCompilationUnit2(source, libraries.first);
       if (unit != null) {
-        _DartNavigationHolder dartHolder = new _DartNavigationHolder(holder);
+        _DartNavigationCollector dartCollector =
+            new _DartNavigationCollector(collector);
         _DartNavigationComputerVisitor visitor =
-            new _DartNavigationComputerVisitor(dartHolder);
+            new _DartNavigationComputerVisitor(dartCollector);
         if (offset == null || length == null) {
           unit.accept(visitor);
         } else {
@@ -40,7 +41,7 @@
 }
 
 class _DartNavigationComputerVisitor extends RecursiveAstVisitor {
-  final _DartNavigationHolder computer;
+  final _DartNavigationCollector computer;
 
   _DartNavigationComputerVisitor(this.computer);
 
@@ -223,12 +224,12 @@
 }
 
 /**
- * A Dart specific wrapper around [NavigationHolder].
+ * A Dart specific wrapper around [NavigationCollector].
  */
-class _DartNavigationHolder {
-  final NavigationHolder holder;
+class _DartNavigationCollector {
+  final NavigationCollector collector;
 
-  _DartNavigationHolder(this.holder);
+  _DartNavigationCollector(this.collector);
 
   void _addRegion(int offset, int length, Element element) {
     if (element is FieldFormalParameterElement) {
@@ -246,7 +247,7 @@
     if (location == null) {
       return;
     }
-    holder.addRegion(offset, length, kind, location);
+    collector.addRegion(offset, length, kind, location);
   }
 
   void _addRegion_nodeStart_nodeEnd(AstNode a, AstNode b, Element element) {
diff --git a/pkg/analysis_server/lib/src/domains/analysis/occurrences.dart b/pkg/analysis_server/lib/src/domains/analysis/occurrences.dart
new file mode 100644
index 0000000..f0a9a1c
--- /dev/null
+++ b/pkg/analysis_server/lib/src/domains/analysis/occurrences.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2015, 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 domains.analysis.occurrences;
+
+import 'package:analysis_server/analysis/occurrences_core.dart';
+import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/protocol_server.dart' as protocol;
+import 'package:analyzer/src/generated/engine.dart'
+    show AnalysisContext, AnalysisEngine;
+import 'package:analyzer/src/generated/java_engine.dart' show CaughtException;
+import 'package:analyzer/src/generated/source.dart' show Source;
+
+/**
+ * Compute all known occurrences for the given [source].
+ */
+OccurrencesCollectorImpl computeOccurrences(
+    AnalysisServer server, AnalysisContext context, Source source) {
+  OccurrencesCollectorImpl collector = new OccurrencesCollectorImpl();
+  List<OccurrencesContributor> contributors =
+      server.serverPlugin.occurrencesContributors;
+  for (OccurrencesContributor contributor in contributors) {
+    try {
+      contributor.computeOccurrences(collector, context, source);
+    } catch (exception, stackTrace) {
+      AnalysisEngine.instance.logger.logError(
+          'Exception from occurrences contributor: ${contributor.runtimeType}',
+          new CaughtException(exception, stackTrace));
+    }
+  }
+  return collector;
+}
+
+/**
+ * A concrete implementation of [OccurrencesCollector].
+ */
+class OccurrencesCollectorImpl implements OccurrencesCollector {
+  Map<protocol.Element, protocol.Occurrences> elementOccurrences =
+      <protocol.Element, protocol.Occurrences>{};
+
+  List<protocol.Occurrences> get allOccurrences {
+    return elementOccurrences.values.toList();
+  }
+
+  @override
+  void addOccurrences(protocol.Occurrences current) {
+    protocol.Element element = current.element;
+    protocol.Occurrences existing = elementOccurrences[element];
+    if (existing != null) {
+      List<int> offsets = _merge(existing.offsets, current.offsets);
+      current = new protocol.Occurrences(element, offsets, existing.length);
+    }
+    elementOccurrences[element] = current;
+  }
+
+  static List<int> _merge(List<int> a, List<int> b) {
+    return <int>[]..addAll(a)..addAll(b);
+  }
+}
diff --git a/pkg/analysis_server/lib/src/domains/analysis/occurrences_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/occurrences_dart.dart
new file mode 100644
index 0000000..ebefbfb
--- /dev/null
+++ b/pkg/analysis_server/lib/src/domains/analysis/occurrences_dart.dart
@@ -0,0 +1,79 @@
+// Copyright (c) 2015, 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 domains.analysis.occurrences_dart;
+
+import 'package:analysis_server/analysis/occurrences_core.dart';
+import 'package:analysis_server/src/protocol_server.dart' as protocol;
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+/**
+ * A computer for occurrences in a Dart [CompilationUnit].
+ */
+class DartOccurrencesComputer implements OccurrencesContributor {
+  @override
+  void computeOccurrences(
+      OccurrencesCollector collector, AnalysisContext context, Source source) {
+    List<Source> libraries = context.getLibrariesContaining(source);
+    if (libraries.isNotEmpty) {
+      CompilationUnit unit =
+          context.getResolvedCompilationUnit2(source, libraries.first);
+      if (unit != null) {
+        _DartUnitOccurrencesComputerVisitor visitor =
+            new _DartUnitOccurrencesComputerVisitor();
+        unit.accept(visitor);
+        visitor.elementsOffsets.forEach((engineElement, offsets) {
+          int length = engineElement.displayName.length;
+          protocol.Element serverElement =
+              protocol.newElement_fromEngine(engineElement);
+          protocol.Occurrences occurrences =
+              new protocol.Occurrences(serverElement, offsets, length);
+          collector.addOccurrences(occurrences);
+        });
+      }
+    }
+  }
+}
+
+class _DartUnitOccurrencesComputerVisitor extends RecursiveAstVisitor {
+  final Map<Element, List<int>> elementsOffsets = <Element, List<int>>{};
+
+  @override
+  visitSimpleIdentifier(SimpleIdentifier node) {
+    Element element = node.bestElement;
+    if (element != null) {
+      _addOccurrence(element, node.offset);
+    }
+    return super.visitSimpleIdentifier(node);
+  }
+
+  void _addOccurrence(Element element, int offset) {
+    element = _canonicalizeElement(element);
+    if (element == null || element == DynamicElementImpl.instance) {
+      return;
+    }
+    List<int> offsets = elementsOffsets[element];
+    if (offsets == null) {
+      offsets = <int>[];
+      elementsOffsets[element] = offsets;
+    }
+    offsets.add(offset);
+  }
+
+  Element _canonicalizeElement(Element element) {
+    if (element is FieldFormalParameterElement) {
+      element = (element as FieldFormalParameterElement).field;
+    }
+    if (element is PropertyAccessorElement) {
+      element = (element as PropertyAccessorElement).variable;
+    }
+    if (element is Member) {
+      element = (element as Member).baseElement;
+    }
+    return element;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/generated_protocol.dart b/pkg/analysis_server/lib/src/generated_protocol.dart
index 4ee4157..672e029 100644
--- a/pkg/analysis_server/lib/src/generated_protocol.dart
+++ b/pkg/analysis_server/lib/src/generated_protocol.dart
@@ -11153,14 +11153,14 @@
   /**
    * The indexes of the targets (in the enclosing navigation response) to which
    * the given region is bound. By opening the target, clients can implement
-   * one form of navigation.
+   * one form of navigation. This list cannot be empty.
    */
   List<int> get targets => _targets;
 
   /**
    * The indexes of the targets (in the enclosing navigation response) to which
    * the given region is bound. By opening the target, clients can implement
-   * one form of navigation.
+   * one form of navigation. This list cannot be empty.
    */
   void set targets(List<int> value) {
     assert(value != null);
diff --git a/pkg/analysis_server/lib/src/get_handler.dart b/pkg/analysis_server/lib/src/get_handler.dart
index 7300d10..b527991 100644
--- a/pkg/analysis_server/lib/src/get_handler.dart
+++ b/pkg/analysis_server/lib/src/get_handler.dart
@@ -174,8 +174,8 @@
     if (analysisServer == null) {
       return null;
     }
-    return analysisServer.handlers.firstWhere(
-        (h) => h is CompletionDomainHandler, orElse: () => null);
+    return analysisServer.handlers
+        .firstWhere((h) => h is CompletionDomainHandler, orElse: () => null);
   }
 
   /**
@@ -218,7 +218,8 @@
    */
   Folder _findFolder(AnalysisServer analysisServer, String contextFilter) {
     return analysisServer.folderMap.keys.firstWhere(
-        (Folder folder) => folder.path == contextFilter, orElse: () => null);
+        (Folder folder) => folder.path == contextFilter,
+        orElse: () => null);
   }
 
   /**
@@ -299,12 +300,15 @@
           buffer.write('<p><b>Task performace data</b></p>');
           buffer.write(
               '<table style="border-collapse: separate; border-spacing: 10px 5px;">');
-          _writeRow(buffer, [
-            'Task Name',
-            'Count',
-            'Total Time (in ms)',
-            'Average Time (in ms)'
-          ], header: true);
+          _writeRow(
+              buffer,
+              [
+                'Task Name',
+                'Count',
+                'Total Time (in ms)',
+                'Average Time (in ms)'
+              ],
+              header: true);
 
           Map<Type, int> countMap = newTask.AnalysisTask.countMap;
           Map<Type, Stopwatch> stopwatchMap = newTask.AnalysisTask.stopwatchMap;
@@ -324,7 +328,12 @@
               count,
               taskTime,
               count <= 0 ? '-' : (taskTime / count).toStringAsFixed(3)
-            ], classes: [null, "right", "right", "right"]);
+            ], classes: [
+              null,
+              "right",
+              "right",
+              "right"
+            ]);
           });
           _writeRow(buffer, ['Total', '-', totalTime, '-'],
               classes: [null, "right", "right", "right"]);
@@ -392,10 +401,8 @@
     AnalysisContextImpl context = analysisServer.folderMap[folder];
 
     _writeResponse(request, (StringBuffer buffer) {
-      _writePage(buffer, 'Analysis Server - AST Structure', [
-        'Context: $contextFilter',
-        'File: $sourceUri'
-      ], (HttpResponse) {
+      _writePage(buffer, 'Analysis Server - AST Structure',
+          ['Context: $contextFilter', 'File: $sourceUri'], (HttpResponse) {
         Source source = context.sourceFactory.forUri(sourceUri);
         if (source == null) {
           buffer.write('<p>Not found.</p>');
@@ -465,10 +472,8 @@
     AnalysisContextImpl context = analysisServer.folderMap[folder];
 
     _writeResponse(request, (StringBuffer buffer) {
-      _writePage(buffer, 'Analysis Server - Cache Entry', [
-        'Context: $contextFilter',
-        'File: $sourceUri'
-      ], (HttpResponse) {
+      _writePage(buffer, 'Analysis Server - Cache Entry',
+          ['Context: $contextFilter', 'File: $sourceUri'], (HttpResponse) {
         buffer.write('<h3>Analyzing Contexts</h3><p>');
         bool first = true;
         allContexts.forEach((Folder folder) {
@@ -482,10 +487,13 @@
           if (analyzingContext == context) {
             buffer.write(folder.path);
           } else {
-            buffer.write(makeLink(CACHE_ENTRY_PATH, {
-              CONTEXT_QUERY_PARAM: folder.path,
-              SOURCE_QUERY_PARAM: sourceUri
-            }, HTML_ESCAPE.convert(folder.path)));
+            buffer.write(makeLink(
+                CACHE_ENTRY_PATH,
+                {
+                  CONTEXT_QUERY_PARAM: folder.path,
+                  SOURCE_QUERY_PARAM: sourceUri
+                },
+                HTML_ESCAPE.convert(folder.path)));
           }
           if (entryMap[folder].explicitlyAdded) {
             buffer.write(' (explicit)');
@@ -512,7 +520,9 @@
           for (Source librarySource in entry.containingLibraries) {
             String libraryName = HTML_ESCAPE.convert(librarySource.fullName);
             buffer.write('<h3>In library $libraryName:</h3>');
-            _writeDescriptorTable(buffer, entry.libraryDescriptors,
+            _writeDescriptorTable(
+                buffer,
+                entry.libraryDescriptors,
                 (DataDescriptor descriptor) =>
                     entry.getStateInLibrary(descriptor, librarySource),
                 (DataDescriptor descriptor) =>
@@ -575,10 +585,13 @@
       if (state != stateFilter || rowDesc.toString() != descriptorFilter) {
         return;
       }
-      String link = makeLink(CACHE_ENTRY_PATH, {
-        CONTEXT_QUERY_PARAM: folder.path,
-        SOURCE_QUERY_PARAM: source.uri.toString()
-      }, HTML_ESCAPE.convert(source.fullName));
+      String link = makeLink(
+          CACHE_ENTRY_PATH,
+          {
+            CONTEXT_QUERY_PARAM: folder.path,
+            SOURCE_QUERY_PARAM: source.uri.toString()
+          },
+          HTML_ESCAPE.convert(source.fullName));
       links.add(link);
     });
 
@@ -717,10 +730,14 @@
         if (exception != null) {
           exceptions.add(exception);
         }
-        String link = makeLink(CACHE_ENTRY_PATH, {
-          CONTEXT_QUERY_PARAM: folder.path,
-          SOURCE_QUERY_PARAM: source.uri.toString()
-        }, sourceName, exception != null);
+        String link = makeLink(
+            CACHE_ENTRY_PATH,
+            {
+              CONTEXT_QUERY_PARAM: folder.path,
+              SOURCE_QUERY_PARAM: source.uri.toString()
+            },
+            sourceName,
+            exception != null);
         if (sourceEntry.explicitlyAdded) {
           explicitNames.add(sourceName);
         } else {
@@ -759,8 +776,9 @@
     }
 
     _writeResponse(request, (StringBuffer buffer) {
-      _writePage(buffer, 'Analysis Server - Context',
-          ['Context: $contextFilter'], (StringBuffer buffer) {
+      _writePage(
+          buffer, 'Analysis Server - Context', ['Context: $contextFilter'],
+          (StringBuffer buffer) {
         List headerRowText = ['Context'];
         headerRowText.addAll(CacheState.values);
         buffer.write('<h3>Summary</h3>');
@@ -884,8 +902,8 @@
           buffer.write('<table border="1">');
           _writeRow(buffer, ['Element', 'Relationship', 'Location'],
               header: true);
-          relations.forEach((List<String> elementPath,
-              List<InspectLocation> relations) {
+          relations.forEach(
+              (List<String> elementPath, List<InspectLocation> relations) {
             String elementLocation = elementPath.join(' ');
             relations.forEach((InspectLocation location) {
               var relString = location.relationship.identifier;
@@ -1041,9 +1059,8 @@
           buffer.write('<br>');
         }
         String key = folder.shortName;
-        buffer.write(makeLink(CONTEXT_PATH, {
-          CONTEXT_QUERY_PARAM: folder.path
-        }, key, _hasException(folderMap[folder])));
+        buffer.write(makeLink(CONTEXT_PATH, {CONTEXT_QUERY_PARAM: folder.path},
+            key, _hasException(folderMap[folder])));
       });
       buffer.write('</p>');
 
@@ -1130,24 +1147,26 @@
       return;
     }
     buffer.write('<table>');
-    _writeRow(buffer, [
-      'Start Time',
-      '',
-      'First (ms)',
-      '',
-      'Complete (ms)',
-      '',
-      '# Notifications',
-      '',
-      '# Suggestions',
-      '',
-      'Snippet'
-    ], header: true);
+    _writeRow(
+        buffer,
+        [
+          'Start Time',
+          '',
+          'First (ms)',
+          '',
+          'Complete (ms)',
+          '',
+          '# Notifications',
+          '',
+          '# Suggestions',
+          '',
+          'Snippet'
+        ],
+        header: true);
     int index = 0;
     for (CompletionPerformance performance in handler.performanceList) {
-      String link = makeLink(COMPLETION_PATH, {
-        'index': '$index'
-      }, '${performance.startTimeAndMs}');
+      String link = makeLink(COMPLETION_PATH, {'index': '$index'},
+          '${performance.startTimeAndMs}');
       _writeRow(buffer, [
         link,
         '&nbsp;&nbsp;',
@@ -1189,9 +1208,12 @@
    * [linkParameters] will be used if the value is too large to be displayed on
    * the current page and needs to be linked to a separate page.
    */
-  void _writeDescriptorTable(StringBuffer buffer,
-      List<DataDescriptor> descriptors, CacheState getState(DataDescriptor),
-      dynamic getValue(DataDescriptor), Map<String, String> linkParameters) {
+  void _writeDescriptorTable(
+      StringBuffer buffer,
+      List<DataDescriptor> descriptors,
+      CacheState getState(DataDescriptor),
+      dynamic getValue(DataDescriptor),
+      Map<String, String> linkParameters) {
     buffer.write('<dl>');
     for (DataDescriptor descriptor in descriptors) {
       String descriptorName = HTML_ESCAPE.convert(descriptor.toString());
@@ -1363,9 +1385,9 @@
    */
   void _writePluginStatus(StringBuffer buffer) {
     void writePlugin(Plugin plugin) {
-      buffer.write(_server.serverPlugin.uniqueIdentifier);
+      buffer.write(plugin.uniqueIdentifier);
       buffer.write(' (');
-      buffer.write(_server.serverPlugin.runtimeType);
+      buffer.write(plugin.runtimeType);
       buffer.write(')<br>');
     }
     buffer.write('<h3>Plugin Status</h3><p>');
diff --git a/pkg/analysis_server/lib/src/operation/operation.dart b/pkg/analysis_server/lib/src/operation/operation.dart
index 6c5732d..1a43a188 100644
--- a/pkg/analysis_server/lib/src/operation/operation.dart
+++ b/pkg/analysis_server/lib/src/operation/operation.dart
@@ -9,6 +9,21 @@
 import 'package:analyzer/src/generated/source.dart';
 
 /**
+ * [MergeableOperation] can decide whether other operation can be merged into
+ * it, so that it should not be added as a separate operation.
+ */
+abstract class MergeableOperation extends ServerOperation {
+  MergeableOperation(AnalysisContext context) : super(context);
+
+  /**
+   * Attempt to merge the given [other] operation into this one, return `true`
+   * in case of success, so that [other] should not be added as a separate
+   * operation.
+   */
+  bool merge(ServerOperation other);
+}
+
+/**
  * The class [ServerOperation] defines the behavior of objects used to perform
  * operations on a [AnalysisServer].
  */
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index f18ad32..0270b27 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -7,10 +7,10 @@
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/computer/computer_highlights.dart';
 import 'package:analysis_server/src/computer/computer_highlights2.dart';
-import 'package:analysis_server/src/computer/computer_occurrences.dart';
 import 'package:analysis_server/src/computer/computer_outline.dart';
 import 'package:analysis_server/src/computer/computer_overrides.dart';
 import 'package:analysis_server/src/domains/analysis/navigation.dart';
+import 'package:analysis_server/src/domains/analysis/occurrences.dart';
 import 'package:analysis_server/src/operation/operation.dart';
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
 import 'package:analysis_server/src/services/dependencies/library_dependencies.dart';
@@ -77,13 +77,13 @@
     }
     if (server.hasAnalysisSubscription(
         protocol.AnalysisService.NAVIGATION, file)) {
-      server.scheduleOperation(
-          new _DartNavigationOperation(context, file, resolvedDartUnit));
+      Source source = resolvedDartUnit.element.source;
+      server.scheduleOperation(new NavigationOperation(context, source));
     }
     if (server.hasAnalysisSubscription(
         protocol.AnalysisService.OCCURRENCES, file)) {
-      server.scheduleOperation(
-          new _DartOccurrencesOperation(context, file, resolvedDartUnit));
+      Source source = resolvedDartUnit.element.source;
+      server.scheduleOperation(new OccurrencesOperation(context, source));
     }
     if (server.hasAnalysisSubscription(
         protocol.AnalysisService.OVERRIDES, file)) {
@@ -169,20 +169,23 @@
 void sendAnalysisNotificationNavigation(
     AnalysisServer server, AnalysisContext context, Source source) {
   _sendNotification(server, () {
-    NavigationHolderImpl holder =
+    NavigationCollectorImpl collector =
         computeNavigation(server, context, source, null, null);
     String file = source.fullName;
     var params = new protocol.AnalysisNavigationParams(
-        file, holder.regions, holder.targets, holder.files);
+        file, collector.regions, collector.targets, collector.files);
     server.sendNotification(params.toNotification());
   });
 }
 
 void sendAnalysisNotificationOccurrences(
-    AnalysisServer server, String file, CompilationUnit dartUnit) {
+    AnalysisServer server, AnalysisContext context, Source source) {
   _sendNotification(server, () {
-    var occurrences = new DartUnitOccurrencesComputer(dartUnit).compute();
-    var params = new protocol.AnalysisOccurrencesParams(file, occurrences);
+    OccurrencesCollectorImpl collector =
+        computeOccurrences(server, context, source);
+    String file = source.fullName;
+    var params =
+        new protocol.AnalysisOccurrencesParams(file, collector.allOccurrences);
     server.sendNotification(params.toNotification());
   });
 }
@@ -229,6 +232,42 @@
   });
 }
 
+class NavigationOperation extends _NotificationOperation
+    implements MergeableOperation {
+  NavigationOperation(AnalysisContext context, Source source)
+      : super(context, source);
+
+  @override
+  bool merge(ServerOperation other) {
+    return other is NavigationOperation &&
+        other.context == context &&
+        other.source == source;
+  }
+
+  @override
+  void perform(AnalysisServer server) {
+    sendAnalysisNotificationNavigation(server, context, source);
+  }
+}
+
+class OccurrencesOperation extends _NotificationOperation
+    implements MergeableOperation {
+  OccurrencesOperation(AnalysisContext context, Source source)
+      : super(context, source);
+
+  @override
+  bool merge(ServerOperation other) {
+    return other is OccurrencesOperation &&
+        other.context == context &&
+        other.source == source;
+  }
+
+  @override
+  void perform(AnalysisServer server) {
+    sendAnalysisNotificationOccurrences(server, context, source);
+  }
+}
+
 /**
  * Instances of [PerformAnalysisOperation] perform a single analysis task.
  */
@@ -380,18 +419,6 @@
   }
 }
 
-class _DartNavigationOperation extends _DartNotificationOperation {
-  _DartNavigationOperation(
-      AnalysisContext context, String file, CompilationUnit unit)
-      : super(context, file, unit);
-
-  @override
-  void perform(AnalysisServer server) {
-    Source source = unit.element.source;
-    sendAnalysisNotificationNavigation(server, context, source);
-  }
-}
-
 abstract class _DartNotificationOperation extends _SingleFileOperation {
   final CompilationUnit unit;
 
@@ -404,17 +431,6 @@
   }
 }
 
-class _DartOccurrencesOperation extends _DartNotificationOperation {
-  _DartOccurrencesOperation(
-      AnalysisContext context, String file, CompilationUnit unit)
-      : super(context, file, unit);
-
-  @override
-  void perform(AnalysisServer server) {
-    sendAnalysisNotificationOccurrences(server, file, unit);
-  }
-}
-
 class _DartOutlineOperation extends _DartNotificationOperation {
   final LineInfo lineInfo;
 
@@ -476,6 +492,22 @@
   }
 }
 
+abstract class _NotificationOperation extends SourceSensitiveOperation {
+  final Source source;
+
+  _NotificationOperation(AnalysisContext context, this.source) : super(context);
+
+  @override
+  ServerOperationPriority get priority {
+    return ServerOperationPriority.ANALYSIS_NOTIFICATION;
+  }
+
+  @override
+  bool shouldBeDiscardedOnSourceChange(Source source) {
+    return source == this.source;
+  }
+}
+
 abstract class _SingleFileOperation extends SourceSensitiveOperation {
   final String file;
 
diff --git a/pkg/analysis_server/lib/src/operation/operation_queue.dart b/pkg/analysis_server/lib/src/operation/operation_queue.dart
index ced4a8c..1687a4b 100644
--- a/pkg/analysis_server/lib/src/operation/operation_queue.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_queue.dart
@@ -39,6 +39,14 @@
   void add(ServerOperation operation) {
     int queueIndex = operation.priority.ordinal;
     Queue<ServerOperation> queue = _queues[queueIndex];
+    // try to merge into an existing operation
+    for (ServerOperation existingOperation in queue) {
+      if (existingOperation is MergeableOperation &&
+          existingOperation.merge(operation)) {
+        return;
+      }
+    }
+    // add it
     queue.addLast(operation);
   }
 
@@ -119,7 +127,7 @@
    */
   ServerOperation takeIf(bool test(ServerOperation operation)) {
     for (Queue<ServerOperation> queue in _queues) {
-      for (var operation in queue) {
+      for (ServerOperation operation in queue) {
         if (test(operation)) {
           queue.remove(operation);
           return operation;
diff --git a/pkg/analysis_server/lib/src/plugin/server_plugin.dart b/pkg/analysis_server/lib/src/plugin/server_plugin.dart
index c1deee0..14b8c33 100644
--- a/pkg/analysis_server/lib/src/plugin/server_plugin.dart
+++ b/pkg/analysis_server/lib/src/plugin/server_plugin.dart
@@ -6,7 +6,8 @@
 
 import 'package:analysis_server/analysis/analysis_domain.dart';
 import 'package:analysis_server/analysis/index/index_core.dart';
-import 'package:analysis_server/analysis/navigation/navigation_core.dart';
+import 'package:analysis_server/analysis/navigation_core.dart';
+import 'package:analysis_server/analysis/occurrences_core.dart';
 import 'package:analysis_server/completion/completion_core.dart';
 import 'package:analysis_server/edit/assist/assist_core.dart';
 import 'package:analysis_server/edit/fix/fix_core.dart';
@@ -14,12 +15,14 @@
 import 'package:analysis_server/plugin/assist.dart';
 import 'package:analysis_server/plugin/fix.dart';
 import 'package:analysis_server/plugin/navigation.dart';
+import 'package:analysis_server/plugin/occurrences.dart';
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/domain_analysis.dart';
 import 'package:analysis_server/src/domain_completion.dart';
 import 'package:analysis_server/src/domain_execution.dart';
 import 'package:analysis_server/src/domain_server.dart';
 import 'package:analysis_server/src/domains/analysis/navigation_dart.dart';
+import 'package:analysis_server/src/domains/analysis/occurrences_dart.dart';
 import 'package:analysis_server/src/edit/edit_domain.dart';
 import 'package:analysis_server/src/protocol.dart';
 import 'package:analysis_server/src/search/search_domain.dart';
@@ -86,6 +89,13 @@
 
   /**
    * The simple identifier of the extension point that allows plugins to
+   * register element occurrences.
+   */
+  static const String OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT =
+      'occurrencesContributor';
+
+  /**
+   * The simple identifier of the extension point that allows plugins to
    * register analysis result listeners.
    */
   static const String SET_ANALISYS_DOMAIN_EXTENSION_POINT = 'setAnalysisDomain';
@@ -130,11 +140,18 @@
   ExtensionPoint indexContributorExtensionPoint;
 
   /**
-   * The extension point that allows plugins to register navigation contributors.
+   * The extension point that allows plugins to register navigation
+   * contributors.
    */
   ExtensionPoint navigationContributorExtensionPoint;
 
   /**
+   * The extension point that allows plugins to register occurrences
+   * contributors.
+   */
+  ExtensionPoint occurrencesContributorExtensionPoint;
+
+  /**
    * The extension point that allows plugins to get access to the `analysis`
    * domain.
    */
@@ -187,6 +204,13 @@
       navigationContributorExtensionPoint.extensions;
 
   /**
+   * Return a list containing all of the occurrences contributors that were
+   * contributed.
+   */
+  List<OccurrencesContributor> get occurrencesContributors =>
+      occurrencesContributorExtensionPoint.extensions;
+
+  /**
    * Return a list containing all of the receivers of the `analysis` domain
    * instance.
    */
@@ -231,6 +255,9 @@
     navigationContributorExtensionPoint = registerExtensionPoint(
         NAVIGATION_CONTRIBUTOR_EXTENSION_POINT,
         _validateNavigationContributorExtension);
+    occurrencesContributorExtensionPoint = registerExtensionPoint(
+        OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT,
+        _validateOccurrencesContributorExtension);
   }
 
   @override
@@ -253,10 +280,12 @@
     // TODO(brianwilkerson) Register the completion contributors.
 //    registerExtension(COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID, ???);
     //
-    // Register navigation contributors.
+    // Register analysis contributors.
     //
     registerExtension(NAVIGATION_CONTRIBUTOR_EXTENSION_POINT_ID,
         new DartNavigationComputer());
+    registerExtension(OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT_ID,
+        new DartOccurrencesComputer());
     //
     // Register domains.
     //
@@ -369,6 +398,18 @@
 
   /**
    * Validate the given extension by throwing an [ExtensionError] if it is not a
+   * valid occurrences contributor.
+   */
+  void _validateOccurrencesContributorExtension(Object extension) {
+    if (extension is! OccurrencesContributor) {
+      String id = occurrencesContributorExtensionPoint.uniqueIdentifier;
+      throw new ExtensionError(
+          'Extensions to $id must be an OccurrencesContributor');
+    }
+  }
+
+  /**
+   * Validate the given extension by throwing an [ExtensionError] if it is not a
    * valid analysis domain receiver.
    */
   void _validateSetAnalysisDomainFunction(Object extension) {
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 8097f94..c5eb6bf 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -9,7 +9,6 @@
 import 'dart:math';
 
 import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analysis_server/src/context_manager.dart';
 import 'package:analysis_server/src/plugin/server_plugin.dart';
 import 'package:analysis_server/src/server/http_server.dart';
 import 'package:analysis_server/src/server/stdio_server.dart';
@@ -72,8 +71,13 @@
 
   /// Defines a flag.
   /// See [ArgParser.addFlag()].
-  void addFlag(String name, {String abbr, String help, bool defaultsTo: false,
-      bool negatable: true, void callback(bool value), bool hide: false}) {
+  void addFlag(String name,
+      {String abbr,
+      String help,
+      bool defaultsTo: false,
+      bool negatable: true,
+      void callback(bool value),
+      bool hide: false}) {
     _knownFlags.add(name);
     _parser.addFlag(name,
         abbr: abbr,
@@ -86,8 +90,13 @@
 
   /// Defines a value-taking option.
   /// See [ArgParser.addOption()].
-  void addOption(String name, {String abbr, String help, List<String> allowed,
-      Map<String, String> allowedHelp, String defaultsTo, void callback(value),
+  void addOption(String name,
+      {String abbr,
+      String help,
+      List<String> allowed,
+      Map<String, String> allowedHelp,
+      String defaultsTo,
+      void callback(value),
       bool allowMultiple: false}) {
     _knownFlags.add(name);
     _parser.addOption(name,
@@ -108,9 +117,9 @@
   /// flags and options defined by this parser, and returns the result. The
   /// values of any defined variables are captured in the given map.
   /// See [ArgParser].
-  ArgResults parse(
-      List<String> args, Map<String, String> definedVariables) => _parser
-      .parse(_filterUnknowns(parseDefinedVariables(args, definedVariables)));
+  ArgResults parse(List<String> args, Map<String, String> definedVariables) =>
+      _parser.parse(
+          _filterUnknowns(parseDefinedVariables(args, definedVariables)));
 
   List<String> parseDefinedVariables(
       List<String> args, Map<String, String> definedVariables) {
@@ -132,12 +141,10 @@
   }
 
   List<String> _filterUnknowns(List<String> args) {
-
     // Only filter args if the ignore flag is specified, or if
     // _alwaysIgnoreUnrecognized was set to true
     if (_alwaysIgnoreUnrecognized ||
         args.contains('--ignore-unrecognized-flags')) {
-
       // Filter all unrecognized flags and options.
       List<String> filtered = <String>[];
       for (int i = 0; i < args.length; ++i) {
@@ -291,16 +298,9 @@
   InstrumentationServer instrumentationServer;
 
   /**
-   * The context manager used to create analysis contexts within each of the
-   * analysis roots.
-   */
-  ContextManager contextManager;
-
-  /**
    * The package resolver provider used to override the way package URI's are
    * resolved in some contexts.
    */
-  @deprecated
   ResolverProvider packageResolverProvider;
 
   /**
@@ -412,7 +412,7 @@
     // Create the sockets and start listening for requests.
     //
     socketServer = new SocketServer(analysisServerOptions, defaultSdk, service,
-        serverPlugin, contextManager, packageResolverProvider);
+        serverPlugin, packageResolverProvider);
     httpServer = new HttpAnalysisServer(socketServer);
     stdioServer = new StdioAnalysisServer(socketServer);
     socketServer.userDefinedPlugins = _userDefinedPlugins;
@@ -430,9 +430,8 @@
         exit(0);
       });
     },
-        print: results[INTERNAL_PRINT_TO_CONSOLE]
-            ? null
-            : httpServer.recordPrint);
+        print:
+            results[INTERNAL_PRINT_TO_CONSOLE] ? null : httpServer.recordPrint);
   }
 
   /**
@@ -453,10 +452,10 @@
     Function printFunction = print == null
         ? null
         : (Zone self, ZoneDelegate parent, Zone zone, String line) {
-      // Note: we don't pass the line on to stdout, because that is reserved
-      // for communication to the client.
-      print(line);
-    };
+            // Note: we don't pass the line on to stdout, because that is reserved
+            // for communication to the client.
+            print(line);
+          };
     ZoneSpecification zoneSpecification = new ZoneSpecification(
         handleUncaughtError: errorFunction, print: printFunction);
     return runZoned(callback, zoneSpecification: zoneSpecification);
@@ -495,14 +494,15 @@
         defaultsTo: false,
         negatable: false);
     parser.addOption(INSTRUMENTATION_LOG_FILE,
-        help: "the path of the file to which instrumentation data will be written");
+        help:
+            "the path of the file to which instrumentation data will be written");
     parser.addFlag(INTERNAL_PRINT_TO_CONSOLE,
         help: "enable sending `print` output to the console",
         defaultsTo: false,
         negatable: false);
     parser.addOption(PORT_OPTION,
         help: "the http diagnostic port on which the server provides"
-        " status and performance information");
+            " status and performance information");
     parser.addOption(INTERNAL_DELAY_FREQUENCY);
     parser.addOption(SDK_OPTION, help: "[path] the path to the sdk");
     parser.addFlag(NO_ERROR_NOTIFICATION,
@@ -521,10 +521,10 @@
             "the file offset and range information incorrect.",
         allowed: ["as-is", "normalize-eol-always"],
         allowedHelp: {
-      "as-is": "file contents are read as-is, no file changes occur",
-      "normalize-eol-always":
-          r'file contents normalize the end of line characters to the single character new line `\n`'
-    },
+          "as-is": "file contents are read as-is, no file changes occur",
+          "normalize-eol-always":
+              r'file contents normalize the end of line characters to the single character new line `\n`'
+        },
         defaultsTo: "as-is");
 
     return parser;
@@ -546,7 +546,8 @@
   String _readUuid(InstrumentationService service) {
     File uuidFile = new File(PhysicalResourceProvider.INSTANCE
         .getStateLocation('.instrumentation')
-        .getChild('uuid.txt').path);
+        .getChild('uuid.txt')
+        .path);
     try {
       if (uuidFile.existsSync()) {
         String uuid = uuidFile.readAsStringSync();
diff --git a/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart
index 3d8261a..61194fc 100644
--- a/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart
@@ -19,8 +19,13 @@
     DartCompletionRequest request, List<String> namedArgs, String name) {
   if (name != null && name.length > 0 && !namedArgs.contains(name)) {
     request.addSuggestion(new CompletionSuggestion(
-        CompletionSuggestionKind.NAMED_ARGUMENT, DART_RELEVANCE_NAMED_PARAMETER,
-        '$name: ', name.length + 2, 0, false, false));
+        CompletionSuggestionKind.NAMED_ARGUMENT,
+        DART_RELEVANCE_NAMED_PARAMETER,
+        '$name: ',
+        name.length + 2,
+        0,
+        false,
+        false));
   }
 }
 
@@ -216,8 +221,13 @@
     }
     completion.write(')');
     CompletionSuggestion suggestion = new CompletionSuggestion(
-        CompletionSuggestionKind.ARGUMENT_LIST, DART_RELEVANCE_HIGH,
-        completion.toString(), completion.length, 0, false, false);
+        CompletionSuggestionKind.ARGUMENT_LIST,
+        DART_RELEVANCE_HIGH,
+        completion.toString(),
+        completion.length,
+        0,
+        false,
+        false);
     suggestion.parameterNames = paramNames;
     suggestion.parameterTypes = paramTypes;
     request.addSuggestion(suggestion);
@@ -353,8 +363,13 @@
     }
     completion.write(')');
     CompletionSuggestion suggestion = new CompletionSuggestion(
-        CompletionSuggestionKind.ARGUMENT_LIST, DART_RELEVANCE_HIGH,
-        completion.toString(), completion.length, 0, false, false);
+        CompletionSuggestionKind.ARGUMENT_LIST,
+        DART_RELEVANCE_HIGH,
+        completion.toString(),
+        completion.length,
+        0,
+        false,
+        false);
     suggestion.parameterNames = paramNames;
     suggestion.parameterTypes = paramTypes;
     request.addSuggestion(suggestion);
diff --git a/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart b/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart
index 70f1542..11b4f1b 100644
--- a/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart
@@ -99,7 +99,6 @@
  * An [AstVisitor] used to determine the best defining type of a node.
  */
 class _BestTypeVisitor extends GeneralizingAstVisitor {
-
   /**
    * The entity which the completed text will replace (or which will be
    * displaced once the completed text is inserted).  This may be an AstNode or
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_dart.dart b/pkg/analysis_server/lib/src/services/completion/completion_dart.dart
index 2dd4eeb..526d69d 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_dart.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_dart.dart
@@ -30,5 +30,5 @@
   DartCompletionRequestImpl(
       CompletionRequest request, this.unit, this.isResolved)
       : super(request.context, request.resourceProvider, request.source,
-          request.offset);
+            request.offset);
 }
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
index 986cc8b..ebc5054 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
@@ -21,7 +21,6 @@
  * for use in the next code completion.
  */
 abstract class CompletionCache {
-
   /**
    * The context in which the completion was computed.
    */
@@ -39,7 +38,6 @@
  * Manages completion contributors for a given completion request.
  */
 abstract class CompletionManager {
-
   /**
    * The context in which the completion was computed.
    */
@@ -222,7 +220,6 @@
  * Encapsulates information specific to a particular completion request.
  */
 class CompletionRequestImpl implements CompletionRequest {
-
   /**
    * The underlying analysis server for this completion request.
    */
@@ -247,7 +244,6 @@
  * Code completion result generated by an [CompletionManager].
  */
 class CompletionResultImpl implements CompletionResult {
-
   /**
    * The length of the text to be replaced if the remainder of the identifier
    * containing the cursor is to be replaced when the suggestion is applied
@@ -298,7 +294,6 @@
  * The performance of an operation when computing code completion.
  */
 class OperationPerformance {
-
   /**
    * The name of the operation
    */
diff --git a/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart b/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart
index 67a7245..7aa6704 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart
@@ -24,7 +24,6 @@
  * completion operation.
  */
 class DartCompletionCache extends CompletionCache {
-
   /**
    * A hash of the import directives
    * or `null` if nothing has been cached.
@@ -262,9 +261,14 @@
     CompletionSuggestion suggestion = null;
     String completion = importElem.prefix.displayName;
     if (completion != null && completion.length > 0) {
-      suggestion = new CompletionSuggestion(CompletionSuggestionKind.INVOCATION,
-          DART_RELEVANCE_DEFAULT, completion, completion.length, 0,
-          importElem.isDeprecated, false);
+      suggestion = new CompletionSuggestion(
+          CompletionSuggestionKind.INVOCATION,
+          DART_RELEVANCE_DEFAULT,
+          completion,
+          completion.length,
+          0,
+          importElem.isDeprecated,
+          false);
       LibraryElement lib = importElem.importedLibrary;
       if (lib != null) {
         suggestion.element = newElement_fromEngine(lib);
@@ -280,7 +284,6 @@
    */
   void _addNonImportedElementSuggestions(
       List<SearchMatch> matches, Set<LibraryElement> excludedLibs) {
-
     // Exclude internal Dart SDK libraries
     for (var lib in context.sourceFactory.dartSdk.sdkLibraries) {
       if (lib.isInternal) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
index 6186079..06c3c6a 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
@@ -322,17 +322,20 @@
       Source source, int offset, this.cache)
       : super(server, context, source, offset);
 
-  factory DartCompletionRequest.from(CompletionRequestImpl request,
-      DartCompletionCache cache) => new DartCompletionRequest(
-      request.server, request.context, request.source, request.offset, cache);
+  factory DartCompletionRequest.from(
+          CompletionRequestImpl request, DartCompletionCache cache) =>
+      new DartCompletionRequest(request.server, request.context, request.source,
+          request.offset, cache);
 
   /**
    * Return the original text from the [replacementOffset] to the [offset]
    * that can be used to filter the suggestions on the server side.
    */
   String get filterText {
-    return context.getContents(source).data.substring(
-        replacementOffset, offset);
+    return context
+        .getContents(source)
+        .data
+        .substring(replacementOffset, offset);
   }
 
   /**
@@ -378,9 +381,12 @@
         // because [DartCompletionCache] may be caching that suggestion
         // for future completion requests
         _suggestions[index] = new CompletionSuggestion(
-            CompletionSuggestionKind.IDENTIFIER, suggestion.relevance,
-            suggestion.completion, suggestion.selectionOffset,
-            suggestion.selectionLength, suggestion.isDeprecated,
+            CompletionSuggestionKind.IDENTIFIER,
+            suggestion.relevance,
+            suggestion.completion,
+            suggestion.selectionOffset,
+            suggestion.selectionLength,
+            suggestion.isDeprecated,
             suggestion.isPotential,
             declaringType: suggestion.declaringType,
             parameterNames: suggestion.parameterNames,
diff --git a/pkg/analysis_server/lib/src/services/completion/imported_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/imported_reference_contributor.dart
index b6ea6ec..dac0056 100644
--- a/pkg/analysis_server/lib/src/services/completion/imported_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/imported_reference_contributor.dart
@@ -25,7 +25,8 @@
   bool suggestionsComputed;
   _ImportedSuggestionBuilder builder;
 
-  ImportedReferenceContributor({this.shouldWaitForLowPrioritySuggestions: false});
+  ImportedReferenceContributor(
+      {this.shouldWaitForLowPrioritySuggestions: false});
 
   @override
   bool computeFast(DartCompletionRequest request) {
@@ -40,7 +41,8 @@
             shouldWaitForLowPrioritySuggestions;
         // If target is an argument in an argument list
         // then suggestions may need to be adjusted
-        suggestionsComputed = builder.computeFast(request.target.containingNode);
+        suggestionsComputed =
+            builder.computeFast(request.target.containingNode);
         return suggestionsComputed && request.target.argIndex == null;
       }
     }
diff --git a/pkg/analysis_server/lib/src/services/completion/local_suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/local_suggestion_builder.dart
index 324e1a7..74d5c95 100644
--- a/pkg/analysis_server/lib/src/services/completion/local_suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/local_suggestion_builder.dart
@@ -22,7 +22,9 @@
  */
 protocol.Element createElement(
     Source source, protocol.ElementKind kind, SimpleIdentifier id,
-    {String parameters, TypeName returnType, bool isAbstract: false,
+    {String parameters,
+    TypeName returnType,
+    bool isAbstract: false,
     bool isDeprecated: false}) {
   String name;
   Location location;
@@ -75,9 +77,14 @@
   }
   CompletionSuggestion suggestion = new CompletionSuggestion(
       CompletionSuggestionKind.INVOCATION,
-      isDeprecated ? DART_RELEVANCE_LOW : defaultRelevance, completion,
-      completion.length, 0, isDeprecated, false,
-      returnType: nameForType(returnType), element: element);
+      isDeprecated ? DART_RELEVANCE_LOW : defaultRelevance,
+      completion,
+      completion.length,
+      0,
+      isDeprecated,
+      false,
+      returnType: nameForType(returnType),
+      element: element);
   if (classDecl != null) {
     SimpleIdentifier classId = classDecl.name;
     if (classId != null) {
diff --git a/pkg/analysis_server/lib/src/services/completion/prefixed_element_contributor.dart b/pkg/analysis_server/lib/src/services/completion/prefixed_element_contributor.dart
index 0a6ca2c..1df4993 100644
--- a/pkg/analysis_server/lib/src/services/completion/prefixed_element_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/prefixed_element_contributor.dart
@@ -404,8 +404,11 @@
             bool typesOnly = node.parent is TypeName;
             bool instCreation =
                 typesOnly && node.parent.parent is ConstructorName;
-            LibraryElementSuggestionBuilder.suggestionsFor(request,
-                CompletionSuggestionKind.INVOCATION, library, typesOnly,
+            LibraryElementSuggestionBuilder.suggestionsFor(
+                request,
+                CompletionSuggestionKind.INVOCATION,
+                library,
+                typesOnly,
                 instCreation);
             modified = true;
             if (directive.deferredKeyword != null) {
diff --git a/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
index a2379ac..5a9f6c6 100644
--- a/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
@@ -25,9 +25,11 @@
  * If the suggestion is not currently in scope, then specify
  * importForSource as the source to which an import should be added.
  */
-CompletionSuggestion createSuggestion(Element element, {String completion,
+CompletionSuggestion createSuggestion(Element element,
+    {String completion,
     CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
-    int relevance: DART_RELEVANCE_DEFAULT, Source importForSource}) {
+    int relevance: DART_RELEVANCE_DEFAULT,
+    Source importForSource}) {
   if (element is ExecutableElement && element.isOperator) {
     // Do not include operators in suggestions
     return null;
@@ -36,9 +38,14 @@
     completion = element.displayName;
   }
   bool isDeprecated = element.isDeprecated;
-  CompletionSuggestion suggestion = new CompletionSuggestion(kind,
-      isDeprecated ? DART_RELEVANCE_LOW : relevance, completion,
-      completion.length, 0, isDeprecated, false);
+  CompletionSuggestion suggestion = new CompletionSuggestion(
+      kind,
+      isDeprecated ? DART_RELEVANCE_LOW : relevance,
+      completion,
+      completion.length,
+      0,
+      isDeprecated,
+      false);
   suggestion.element = protocol.newElement_fromEngine(element);
   Element enclosingElement = element.enclosingElement;
   if (enclosingElement is ClassElement) {
@@ -52,9 +59,10 @@
     suggestion.parameterTypes = element.parameters
         .map((ParameterElement parameter) => parameter.type.displayName)
         .toList();
-    suggestion.requiredParameterCount = element.parameters.where(
-        (ParameterElement parameter) =>
-            parameter.parameterKind == ParameterKind.REQUIRED).length;
+    suggestion.requiredParameterCount = element.parameters
+        .where((ParameterElement parameter) =>
+            parameter.parameterKind == ParameterKind.REQUIRED)
+        .length;
     suggestion.hasNamedParameters = element.parameters.any(
         (ParameterElement parameter) =>
             parameter.parameterKind == ParameterKind.NAMED);
@@ -177,7 +185,6 @@
  * Common mixin for sharing behavior
  */
 abstract class ElementSuggestionBuilder {
-
   /**
    * Return the kind of suggestions that should be built.
    */
@@ -434,8 +441,8 @@
       type = request.cache.objectClassElement.type;
     }
     if (type is InterfaceType) {
-      return new InterfaceTypeSuggestionBuilder(request)._buildSuggestions(
-          type, library, isSuper, containingMethodName);
+      return new InterfaceTypeSuggestionBuilder(request)
+          ._buildSuggestions(type, library, isSuper, containingMethodName);
     }
   }
 }
@@ -517,8 +524,11 @@
   /**
    * Add suggestions for the visible members in the given library
    */
-  static void suggestionsFor(DartCompletionRequest request,
-      CompletionSuggestionKind kind, LibraryElement library, bool typesOnly,
+  static void suggestionsFor(
+      DartCompletionRequest request,
+      CompletionSuggestionKind kind,
+      LibraryElement library,
+      bool typesOnly,
       bool instCreation) {
     if (library != null) {
       library.visitChildren(new LibraryElementSuggestionBuilder(
@@ -532,7 +542,8 @@
  * the visible named constructors in that class.
  */
 class NamedConstructorSuggestionBuilder extends GeneralizingElementVisitor
-    with ElementSuggestionBuilder implements SuggestionBuilder {
+    with ElementSuggestionBuilder
+    implements SuggestionBuilder {
   final DartCompletionRequest request;
 
   NamedConstructorSuggestionBuilder(this.request);
diff --git a/pkg/analysis_server/lib/src/services/correction/assist.dart b/pkg/analysis_server/lib/src/services/correction/assist.dart
index 5bdbe24..6cc4739 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist.dart
@@ -82,10 +82,12 @@
   static const REMOVE_TYPE_ANNOTATION =
       const AssistKind('REMOVE_TYPE_ANNOTATION', 29, "Remove type annotation");
   static const REPLACE_CONDITIONAL_WITH_IF_ELSE = const AssistKind(
-      'REPLACE_CONDITIONAL_WITH_IF_ELSE', 30,
+      'REPLACE_CONDITIONAL_WITH_IF_ELSE',
+      30,
       "Replace conditional with 'if-else'");
   static const REPLACE_IF_ELSE_WITH_CONDITIONAL = const AssistKind(
-      'REPLACE_IF_ELSE_WITH_CONDITIONAL', 30,
+      'REPLACE_IF_ELSE_WITH_CONDITIONAL',
+      30,
       "Replace 'if-else' with conditional ('c ? x : y')");
   static const SPLIT_AND_CONDITION =
       const AssistKind('SPLIT_AND_CONDITION', 30, "Split && condition");
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index d1ec86e..eca515b 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -452,6 +452,9 @@
       if (parent is PrefixedIdentifier) {
         PrefixedIdentifier prefixedIdentifier = parent;
         prefixElement = prefixedIdentifier.prefix.staticElement;
+        if (prefixElement == null) {
+          return;
+        }
         parent = prefixedIdentifier.parent;
         nameNode = prefixedIdentifier.identifier;
         name = prefixedIdentifier.identifier.name;
diff --git a/pkg/analysis_server/lib/src/services/correction/namespace.dart b/pkg/analysis_server/lib/src/services/correction/namespace.dart
index 305052a..1ca99ba 100644
--- a/pkg/analysis_server/lib/src/services/correction/namespace.dart
+++ b/pkg/analysis_server/lib/src/services/correction/namespace.dart
@@ -57,8 +57,10 @@
  * [element] - the referenced element.
  * [importElementsMap] - the cache of [Element]s imported by [ImportElement]s.
  */
-ImportElement internal_getImportElement(LibraryElement libraryElement,
-    String prefix, Element element,
+ImportElement internal_getImportElement(
+    LibraryElement libraryElement,
+    String prefix,
+    Element element,
     Map<ImportElement, Set<Element>> importElementsMap) {
   // validate Element
   if (element == null) {
diff --git a/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart b/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart
index de3da05..e7c8361 100644
--- a/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart
+++ b/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart
@@ -190,7 +190,8 @@
       AstNode lastNode = nodes.last;
       SourceRange rangeAfterLastNode = rangeEndEnd(lastNode, selection);
       if (_hasTokens(rangeAfterLastNode)) {
-        invalidSelection("The end of the selection contains characters that "
+        invalidSelection(
+            "The end of the selection contains characters that "
             "do not belong to a statement.",
             newLocation_fromUnit(unit, rangeAfterLastNode));
       }
diff --git a/pkg/analysis_server/lib/src/services/index/local_file_index.dart b/pkg/analysis_server/lib/src/services/index/local_file_index.dart
index c845c11..022fa1b 100644
--- a/pkg/analysis_server/lib/src/services/index/local_file_index.dart
+++ b/pkg/analysis_server/lib/src/services/index/local_file_index.dart
@@ -14,8 +14,12 @@
 Index createLocalFileIndex() {
   var fileManager = new TemporaryFolderFileManager();
   var stringCodec = new StringCodec();
-  var nodeManager = new FileNodeManager(fileManager,
-      AnalysisEngine.instance.logger, stringCodec, new ContextCodec(),
-      new ElementCodec(stringCodec), new RelationshipCodec(stringCodec));
+  var nodeManager = new FileNodeManager(
+      fileManager,
+      AnalysisEngine.instance.logger,
+      stringCodec,
+      new ContextCodec(),
+      new ElementCodec(stringCodec),
+      new RelationshipCodec(stringCodec));
   return new LocalIndex(nodeManager);
 }
diff --git a/pkg/analysis_server/lib/src/services/index/store/split_store.dart b/pkg/analysis_server/lib/src/services/index/store/split_store.dart
index ee5c3b8..8d94d74 100644
--- a/pkg/analysis_server/lib/src/services/index/store/split_store.dart
+++ b/pkg/analysis_server/lib/src/services/index/store/split_store.dart
@@ -482,8 +482,10 @@
   RelationKeyData.forData(
       this.elementId1, this.elementId2, this.elementId3, this.relationshipId);
 
-  RelationKeyData.forObject(ElementCodec elementCodec,
-      RelationshipCodec relationshipCodec, IndexableObject indexable,
+  RelationKeyData.forObject(
+      ElementCodec elementCodec,
+      RelationshipCodec relationshipCodec,
+      IndexableObject indexable,
       RelationshipImpl relationship)
       : elementId1 = elementCodec.encode1(indexable),
         elementId2 = elementCodec.encode2(indexable),
@@ -1050,8 +1052,10 @@
 
   factory _TopElementData(
       ElementCodec elementCodec, IndexableObject indexable) {
-    return new _TopElementData._(indexable.name,
-        elementCodec.encode1(indexable), elementCodec.encode2(indexable),
+    return new _TopElementData._(
+        indexable.name,
+        elementCodec.encode1(indexable),
+        elementCodec.encode2(indexable),
         elementCodec.encode3(indexable));
   }
 
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
index 3acc982..6cfd951 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
@@ -150,9 +150,11 @@
         String declStatement = prefix + indent + declarationSource + eol;
         String exprStatement = prefix + indent + 'return ';
         Expression expr = target.expression;
-        doSourceChange_addElementEdit(change, unitElement, new SourceEdit(
-            target.offset, expr.offset - target.offset,
-            '{' + eol + declStatement + exprStatement));
+        doSourceChange_addElementEdit(
+            change,
+            unitElement,
+            new SourceEdit(target.offset, expr.offset - target.offset,
+                '{' + eol + declStatement + exprStatement));
         doSourceChange_addElementEdit(change, unitElement,
             new SourceEdit(expr.end, 0, ';' + eol + prefix + '}'));
       }
@@ -378,7 +380,8 @@
           stringLiteralPart, excludedVariableNames));
     } else if (singleExpression != null) {
       names.addAll(getVariableNameSuggestionsForExpression(
-          singleExpression.staticType, singleExpression,
+          singleExpression.staticType,
+          singleExpression,
           excludedVariableNames));
     }
   }
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
index be9162d..da79930 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
@@ -731,7 +731,8 @@
     names.clear();
     if (_selectionExpression != null) {
       names.addAll(getVariableNameSuggestionsForExpression(
-          _selectionExpression.staticType, _selectionExpression,
+          _selectionExpression.staticType,
+          _selectionExpression,
           _excludedNames));
     }
   }
@@ -817,8 +818,10 @@
   Object visitConstructorInitializer(ConstructorInitializer node) {
     super.visitConstructorInitializer(node);
     if (_isFirstSelectedNode(node)) {
-      invalidSelection('Cannot extract a constructor initializer. '
-          'Select expression part of initializer.', newLocation_fromNode(node));
+      invalidSelection(
+          'Cannot extract a constructor initializer. '
+          'Select expression part of initializer.',
+          newLocation_fromNode(node));
     }
     return null;
   }
@@ -870,8 +873,10 @@
   Object visitVariableDeclaration(VariableDeclaration node) {
     super.visitVariableDeclaration(node);
     if (_isFirstSelectedNode(node)) {
-      invalidSelection('Cannot extract a variable declaration fragment. '
-          'Select whole declaration statement.', newLocation_fromNode(node));
+      invalidSelection(
+          'Cannot extract a variable declaration fragment. '
+          'Select whole declaration statement.',
+          newLocation_fromNode(node));
     }
     return null;
   }
diff --git a/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart b/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
index 35ba073..7c7e6356 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
@@ -45,13 +45,17 @@
  * Returns the source which should replace given invocation with given
  * arguments.
  */
-String _getMethodSourceForInvocation(RefactoringStatus status, _SourcePart part,
-    CorrectionUtils utils, AstNode contextNode, Expression targetExpression,
+String _getMethodSourceForInvocation(
+    RefactoringStatus status,
+    _SourcePart part,
+    CorrectionUtils utils,
+    AstNode contextNode,
+    Expression targetExpression,
     List<Expression> arguments) {
   // prepare edits to replace parameters with arguments
   List<SourceEdit> edits = <SourceEdit>[];
-  part._parameters.forEach((ParameterElement parameter,
-      List<_ParameterOccurrence> occurrences) {
+  part._parameters.forEach(
+      (ParameterElement parameter, List<_ParameterOccurrence> occurrences) {
     // prepare argument
     Expression argument = null;
     for (Expression arg in arguments) {
diff --git a/pkg/analysis_server/lib/src/services/refactoring/move_file.dart b/pkg/analysis_server/lib/src/services/refactoring/move_file.dart
index 849b9e1..d5663403 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/move_file.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/move_file.dart
@@ -172,9 +172,11 @@
           if (uri != null) {
             String oldPrefix = 'package:$oldPackageName/';
             if (uri.startsWith(oldPrefix)) {
-              doSourceChange_addElementEdit(change, library, new SourceEdit(
-                  element.uriOffset + 1, oldPrefix.length,
-                  'package:$newPackageName/'));
+              doSourceChange_addElementEdit(
+                  change,
+                  library,
+                  new SourceEdit(element.uriOffset + 1, oldPrefix.length,
+                      'package:$newPackageName/'));
             }
           }
         }
diff --git a/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart b/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
index 1a29c3e..f589fe9 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
@@ -278,8 +278,11 @@
   /**
    * Returns a new [MoveFileRefactoring] instance.
    */
-  factory MoveFileRefactoring(ResourceProvider resourceProvider,
-      SearchEngine searchEngine, AnalysisContext context, Source source,
+  factory MoveFileRefactoring(
+      ResourceProvider resourceProvider,
+      SearchEngine searchEngine,
+      AnalysisContext context,
+      Source source,
       String oldFile) {
     return new MoveFileRefactoringImpl(
         resourceProvider, searchEngine, context, source, oldFile);
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
index 791f4b8..6799486 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
@@ -152,10 +152,13 @@
   Future<RefactoringStatus> validate() async {
     // check if there is a member with "newName" in the same ClassElement
     for (Element newNameMember in getChildren(elementClass, name)) {
-      result.addError(format(
-          "Class '{0}' already declares {1} with name '{2}'.",
-          elementClass.displayName, getElementKindName(newNameMember),
-          name), newLocation_fromElement(newNameMember));
+      result.addError(
+          format(
+              "Class '{0}' already declares {1} with name '{2}'.",
+              elementClass.displayName,
+              getElementKindName(newNameMember),
+              name),
+          newLocation_fromElement(newNameMember));
     }
     // do chained computations
     Set<ClassElement> superClasses = getSuperClasses(elementClass);
@@ -170,17 +173,23 @@
       Element nameClass = nameElement.enclosingElement;
       // renamed Element shadows member of superclass
       if (superClasses.contains(nameClass)) {
-        result.addError(format(isRename
+        result.addError(
+            format(
+                isRename
                     ? "Renamed {0} will shadow {1} '{2}'."
                     : "Created {0} will shadow {1} '{2}'.",
-                elementKind.displayName, getElementKindName(nameElement),
+                elementKind.displayName,
+                getElementKindName(nameElement),
                 getElementQualifiedName(nameElement)),
             newLocation_fromElement(nameElement));
       }
       // renamed Element is shadowed by member of subclass
       if (isRename && subClasses.contains(nameClass)) {
-        result.addError(format("Renamed {0} will be shadowed by {1} '{2}'.",
-                elementKind.displayName, getElementKindName(nameElement),
+        result.addError(
+            format(
+                "Renamed {0} will be shadowed by {1} '{2}'.",
+                elementKind.displayName,
+                getElementKindName(nameElement),
                 getElementQualifiedName(nameElement)),
             newLocation_fromElement(nameElement));
       }
@@ -193,10 +202,13 @@
             subClasses.contains(enclosingClass)) {
           for (SearchMatch reference in references) {
             if (isReferenceInLocalRange(localElement, reference)) {
-              result.addError(format(
-                  "Usage of renamed {0} will be shadowed by {1} '{2}'.",
-                  elementKind.displayName, getElementKindName(localElement),
-                  localElement.displayName), newLocation_fromMatch(reference));
+              result.addError(
+                  format(
+                      "Usage of renamed {0} will be shadowed by {1} '{2}'.",
+                      elementKind.displayName,
+                      getElementKindName(localElement),
+                      localElement.displayName),
+                  newLocation_fromMatch(reference));
             }
           }
         }
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
index 636c8bb..d5c489a 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
@@ -72,7 +72,9 @@
     for (Element newNameMember in getChildren(parentClass, newName)) {
       String message = format(
           "Class '{0}' already declares {1} with name '{2}'.",
-          parentClass.displayName, getElementKindName(newNameMember), newName);
+          parentClass.displayName,
+          getElementKindName(newNameMember),
+          newName);
       result.addError(message, newLocation_fromElement(newNameMember));
     }
   }
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
index 608eb73..6b73dd9 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
@@ -82,8 +82,11 @@
         SimpleIdentifier interpolationIdentifier =
             _getInterpolationIdentifier(reference);
         if (interpolationIdentifier != null) {
-          doSourceChange_addElementEdit(change, reference.element,
-              new SourceEdit(interpolationIdentifier.offset,
+          doSourceChange_addElementEdit(
+              change,
+              reference.element,
+              new SourceEdit(
+                  interpolationIdentifier.offset,
                   interpolationIdentifier.length,
                   '{$newName.${interpolationIdentifier.name}}'));
         } else {
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart
index 2d2f797..8ab7de3 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart
@@ -198,7 +198,8 @@
           if (hasDisplayName(shadow, name)) {
             String message = format(
                 "Reference to renamed {0} will be shadowed by {1} '{2}'.",
-                getElementKindName(element), getElementKindName(shadow),
+                getElementKindName(element),
+                getElementKindName(shadow),
                 getElementQualifiedName(shadow));
             result.addError(message, newLocation_fromElement(shadow));
           }
@@ -249,10 +250,13 @@
           continue;
         }
         // OK, reference will be shadowed be the element being renamed
-        String message = format(isRename
+        String message = format(
+            isRename
                 ? "Renamed {0} will shadow {1} '{2}'."
-                : "Created {0} will shadow {1} '{2}'.", elementKind.displayName,
-            getElementKindName(member), getElementQualifiedName(member));
+                : "Created {0} will shadow {1} '{2}'.",
+            elementKind.displayName,
+            getElementKindName(member),
+            getElementQualifiedName(member));
         result.addError(message, newLocation_fromMatch(memberReference));
       }
     }
diff --git a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
index be37a96..6126e14 100644
--- a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
+++ b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
@@ -207,9 +207,12 @@
       for (LocationImpl location in locations) {
         IndexableObject indexable = location.indexable;
         if (indexable is IndexableElement) {
-          matches.add(new SearchMatch(kind, indexable.element,
+          matches.add(new SearchMatch(
+              kind,
+              indexable.element,
               new SourceRange(location.offset, location.length),
-              location.isResolved, location.isQualified));
+              location.isResolved,
+              location.isQualified));
         }
       }
       return matches;
diff --git a/pkg/analysis_server/lib/src/socket_server.dart b/pkg/analysis_server/lib/src/socket_server.dart
index d5abd12..7ec0a69 100644
--- a/pkg/analysis_server/lib/src/socket_server.dart
+++ b/pkg/analysis_server/lib/src/socket_server.dart
@@ -6,7 +6,6 @@
 
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/channel/channel.dart';
-import 'package:analysis_server/src/context_manager.dart';
 import 'package:analysis_server/src/plugin/server_plugin.dart';
 import 'package:analysis_server/src/protocol.dart';
 import 'package:analysis_server/src/services/index/index.dart';
@@ -29,7 +28,6 @@
   final DirectoryBasedDartSdk defaultSdk;
   final InstrumentationService instrumentationService;
   final ServerPlugin serverPlugin;
-  final ContextManager contextManager;
   final ResolverProvider packageResolverProvider;
 
   /**
@@ -43,8 +41,11 @@
    */
   List<Plugin> userDefinedPlugins;
 
-  SocketServer(this.analysisServerOptions, this.defaultSdk,
-      this.instrumentationService, this.serverPlugin, this.contextManager,
+  SocketServer(
+      this.analysisServerOptions,
+      this.defaultSdk,
+      this.instrumentationService,
+      this.serverPlugin,
       this.packageResolverProvider);
 
   /**
@@ -80,10 +81,15 @@
       index.run();
     }
 
-    analysisServer = new AnalysisServer(serverChannel, resourceProvider,
-        new PubPackageMapProvider(resourceProvider, defaultSdk), index,
-        serverPlugin, analysisServerOptions, defaultSdk, instrumentationService,
-        contextManager: contextManager,
+    analysisServer = new AnalysisServer(
+        serverChannel,
+        resourceProvider,
+        new PubPackageMapProvider(resourceProvider, defaultSdk),
+        index,
+        serverPlugin,
+        analysisServerOptions,
+        defaultSdk,
+        instrumentationService,
         packageResolverProvider: packageResolverProvider,
         rethrowExceptions: false);
     analysisServer.userDefinedPlugins = userDefinedPlugins;
diff --git a/pkg/analysis_server/lib/src/status/get_handler.dart b/pkg/analysis_server/lib/src/status/get_handler.dart
index 1f5f937..6a49946 100644
--- a/pkg/analysis_server/lib/src/status/get_handler.dart
+++ b/pkg/analysis_server/lib/src/status/get_handler.dart
@@ -179,8 +179,8 @@
     if (analysisServer == null) {
       return null;
     }
-    return analysisServer.handlers.firstWhere(
-        (h) => h is CompletionDomainHandler, orElse: () => null);
+    return analysisServer.handlers
+        .firstWhere((h) => h is CompletionDomainHandler, orElse: () => null);
   }
 
   /**
@@ -223,7 +223,8 @@
    */
   Folder _findFolder(AnalysisServer analysisServer, String contextFilter) {
     return analysisServer.folderMap.keys.firstWhere(
-        (Folder folder) => folder.path == contextFilter, orElse: () => null);
+        (Folder folder) => folder.path == contextFilter,
+        orElse: () => null);
   }
 
   /**
@@ -342,12 +343,15 @@
         buffer.write('<p><b>Task performace data</b></p>');
         buffer.write(
             '<table style="border-collapse: separate; border-spacing: 10px 5px;">');
-        _writeRow(buffer, [
-          'Task Name',
-          'Count',
-          'Total Time (in ms)',
-          'Average Time (in ms)'
-        ], header: true);
+        _writeRow(
+            buffer,
+            [
+              'Task Name',
+              'Count',
+              'Total Time (in ms)',
+              'Average Time (in ms)'
+            ],
+            header: true);
 
         Map<Type, int> countMap = AnalysisTask.countMap;
         Map<Type, Stopwatch> stopwatchMap = AnalysisTask.stopwatchMap;
@@ -367,7 +371,12 @@
             count,
             taskTime,
             count <= 0 ? '-' : (taskTime / count).toStringAsFixed(3)
-          ], classes: [null, "right", "right", "right"]);
+          ], classes: [
+            null,
+            "right",
+            "right",
+            "right"
+          ]);
         });
         _writeRow(buffer, ['Total', '-', totalTaskTime, '-'],
             classes: [null, "right", "right", "right"]);
@@ -402,10 +411,8 @@
     InternalAnalysisContext context = analysisServer.folderMap[folder];
 
     _writeResponse(request, (StringBuffer buffer) {
-      _writePage(buffer, 'Analysis Server - AST Structure', [
-        'Context: $contextFilter',
-        'File: $sourceUri'
-      ], (HttpResponse) {
+      _writePage(buffer, 'Analysis Server - AST Structure',
+          ['Context: $contextFilter', 'File: $sourceUri'], (HttpResponse) {
         Source source = context.sourceFactory.forUri(sourceUri);
         if (source == null) {
           buffer.write('<p>Not found.</p>');
@@ -486,10 +493,8 @@
     InternalAnalysisContext context = analysisServer.folderMap[folder];
 
     _writeResponse(request, (StringBuffer buffer) {
-      _writePage(buffer, 'Analysis Server - Cache Entry', [
-        'Context: $contextFilter',
-        'File: $sourceUri'
-      ], (HttpResponse) {
+      _writePage(buffer, 'Analysis Server - Cache Entry',
+          ['Context: $contextFilter', 'File: $sourceUri'], (HttpResponse) {
         buffer.write('<h3>Analyzing Contexts</h3><p>');
         bool first = true;
         allContexts.forEach((Folder folder) {
@@ -503,10 +508,13 @@
           if (analyzingContext == context) {
             buffer.write(folder.path);
           } else {
-            buffer.write(makeLink(CACHE_ENTRY_PATH, {
-              CONTEXT_QUERY_PARAM: folder.path,
-              SOURCE_QUERY_PARAM: sourceUri
-            }, HTML_ESCAPE.convert(folder.path)));
+            buffer.write(makeLink(
+                CACHE_ENTRY_PATH,
+                {
+                  CONTEXT_QUERY_PARAM: folder.path,
+                  SOURCE_QUERY_PARAM: sourceUri
+                },
+                HTML_ESCAPE.convert(folder.path)));
           }
           if (entryMap[folder][0].explicitlyAdded) {
             buffer.write(' (explicit)');
@@ -760,10 +768,14 @@
           if (exception != null) {
             exceptions.add(exception);
           }
-          String link = makeLink(CACHE_ENTRY_PATH, {
-            CONTEXT_QUERY_PARAM: folder.path,
-            SOURCE_QUERY_PARAM: source.uri.toString()
-          }, sourceName, exception != null);
+          String link = makeLink(
+              CACHE_ENTRY_PATH,
+              {
+                CONTEXT_QUERY_PARAM: folder.path,
+                SOURCE_QUERY_PARAM: source.uri.toString()
+              },
+              sourceName,
+              exception != null);
           if (entry.explicitlyAdded) {
             explicitNames.add(sourceName);
           } else {
@@ -803,8 +815,9 @@
     }
 
     _writeResponse(request, (StringBuffer buffer) {
-      _writePage(buffer, 'Analysis Server - Context',
-          ['Context: $contextFilter'], (StringBuffer buffer) {
+      _writePage(
+          buffer, 'Analysis Server - Context', ['Context: $contextFilter'],
+          (StringBuffer buffer) {
         List headerRowText = ['Context'];
         headerRowText.addAll(CacheState.values);
         buffer.write('<h3>Summary</h3>');
@@ -928,8 +941,8 @@
           buffer.write('<table border="1">');
           _writeRow(buffer, ['Element', 'Relationship', 'Location'],
               header: true);
-          relations.forEach((List<String> elementPath,
-              List<InspectLocation> relations) {
+          relations.forEach(
+              (List<String> elementPath, List<InspectLocation> relations) {
             String elementLocation = elementPath.join(' ');
             relations.forEach((InspectLocation location) {
               var relString = location.relationship.identifier;
@@ -1085,9 +1098,8 @@
           buffer.write('<br>');
         }
         String key = folder.shortName;
-        buffer.write(makeLink(CONTEXT_PATH, {
-          CONTEXT_QUERY_PARAM: folder.path
-        }, key, _hasException(folderMap[folder])));
+        buffer.write(makeLink(CONTEXT_PATH, {CONTEXT_QUERY_PARAM: folder.path},
+            key, _hasException(folderMap[folder])));
       });
       buffer.write('</p>');
 
@@ -1174,24 +1186,26 @@
       return;
     }
     buffer.write('<table>');
-    _writeRow(buffer, [
-      'Start Time',
-      '',
-      'First (ms)',
-      '',
-      'Complete (ms)',
-      '',
-      '# Notifications',
-      '',
-      '# Suggestions',
-      '',
-      'Snippet'
-    ], header: true);
+    _writeRow(
+        buffer,
+        [
+          'Start Time',
+          '',
+          'First (ms)',
+          '',
+          'Complete (ms)',
+          '',
+          '# Notifications',
+          '',
+          '# Suggestions',
+          '',
+          'Snippet'
+        ],
+        header: true);
     int index = 0;
     for (CompletionPerformance performance in handler.performanceList) {
-      String link = makeLink(COMPLETION_PATH, {
-        'index': '$index'
-      }, '${performance.startTimeAndMs}');
+      String link = makeLink(COMPLETION_PATH, {'index': '$index'},
+          '${performance.startTimeAndMs}');
       _writeRow(buffer, [
         link,
         '&nbsp;&nbsp;',
diff --git a/pkg/analysis_server/lib/src/status/tree_writer.dart b/pkg/analysis_server/lib/src/status/tree_writer.dart
index ec9fb85..4b5b3a4 100644
--- a/pkg/analysis_server/lib/src/status/tree_writer.dart
+++ b/pkg/analysis_server/lib/src/status/tree_writer.dart
@@ -124,9 +124,8 @@
           String name = value.name;
           if (name != null) {
             buffer.write('&nbsp;&nbsp;[');
-            buffer.write(GetHandler.makeLink(GetHandler.INDEX_ELEMENT_BY_NAME, {
-              'name': name
-            }, 'search index'));
+            buffer.write(GetHandler.makeLink(GetHandler.INDEX_ELEMENT_BY_NAME,
+                {'name': name}, 'search index'));
             buffer.write(']');
           }
         }
diff --git a/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart b/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart
index e6b1de9..14a2efc 100644
--- a/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart
+++ b/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart
@@ -58,9 +58,13 @@
   DartFileEditBuilderImpl get dartFileEditBuilder => fileEditBuilder;
 
   @override
-  void writeClassDeclaration(String name, {Iterable<DartType> interfaces,
-      bool isAbstract: false, void memberWriter(), Iterable<DartType> mixins,
-      String nameGroupName, DartType superclass}) {
+  void writeClassDeclaration(String name,
+      {Iterable<DartType> interfaces,
+      bool isAbstract: false,
+      void memberWriter(),
+      Iterable<DartType> mixins,
+      String nameGroupName,
+      DartType superclass}) {
     // TODO(brianwilkerson) Add support for type parameters, probably as a
     // parameterWriter parameter.
     // TODO(brianwilkerson) Add a superclassGroupName parameter.
@@ -95,7 +99,8 @@
 
   //@override
   void writeConstructorDeclaration(ClassElement classElement,
-      {ArgumentList argumentList, SimpleIdentifier constructorName,
+      {ArgumentList argumentList,
+      SimpleIdentifier constructorName,
       bool isConst: false}) {
     // TODO(brianwilkerson) Clean up the API and add it to the public API.
     //
@@ -134,9 +139,14 @@
   }
 
   @override
-  void writeFieldDeclaration(String name, {void initializerWriter(),
-      bool isConst: false, bool isFinal: false, bool isStatic: false,
-      String nameGroupName, DartType type, String typeGroupName}) {
+  void writeFieldDeclaration(String name,
+      {void initializerWriter(),
+      bool isConst: false,
+      bool isFinal: false,
+      bool isStatic: false,
+      String nameGroupName,
+      DartType type,
+      String typeGroupName}) {
     if (isStatic) {
       write(Keyword.STATIC.syntax);
       write(' ');
@@ -170,8 +180,11 @@
   }
 
   @override
-  void writeGetterDeclaration(String name, {void bodyWriter(),
-      bool isStatic: false, String nameGroupName, DartType returnType,
+  void writeGetterDeclaration(String name,
+      {void bodyWriter(),
+      bool isStatic: false,
+      String nameGroupName,
+      DartType returnType,
       String returnTypeGroupName}) {
     if (isStatic) {
       write(Keyword.STATIC.syntax);
@@ -349,8 +362,10 @@
   }
 
   @override
-  bool writeType(DartType type, {bool addSupertypeProposals: false,
-      String groupName, bool required: false}) {
+  bool writeType(DartType type,
+      {bool addSupertypeProposals: false,
+      String groupName,
+      bool required: false}) {
     if (type != null && !type.isDynamic) {
       String typeSource =
           utils.getTypeSource(type, dartFileEditBuilder.librariesToImport);
diff --git a/pkg/analysis_server/lib/starter.dart b/pkg/analysis_server/lib/starter.dart
index 87821c1..dc0b6ad 100644
--- a/pkg/analysis_server/lib/starter.dart
+++ b/pkg/analysis_server/lib/starter.dart
@@ -4,7 +4,6 @@
 
 library driver;
 
-import 'package:analysis_server/src/context_manager.dart';
 import 'package:analysis_server/src/server/driver.dart';
 import 'package:analysis_server/uri/resolver_provider.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
@@ -12,6 +11,8 @@
 
 /**
  * An object that can be used to start an analysis server.
+ *
+ * Clients are not expected to subtype this class.
  */
 abstract class ServerStarter {
   /**
@@ -20,12 +21,6 @@
   factory ServerStarter() = Driver;
 
   /**
-   * Set the context manager used to create analysis contexts within each of the
-   * analysis roots.
-   */
-  void set contextManager(ContextManager manager);
-
-  /**
    * Set the instrumentation [server] that is to be used by the analysis server.
    */
   void set instrumentationServer(InstrumentationServer server);
@@ -35,7 +30,6 @@
    * are resolved in some contexts. The provider should return `null` if the
    * default package resolution scheme should be used instead.
    */
-  @deprecated
   void set packageResolverProvider(ResolverProvider provider);
 
   /**
diff --git a/pkg/analysis_server/lib/utilities/change_builder_dart.dart b/pkg/analysis_server/lib/utilities/change_builder_dart.dart
index b81b22a..74ca528 100644
--- a/pkg/analysis_server/lib/utilities/change_builder_dart.dart
+++ b/pkg/analysis_server/lib/utilities/change_builder_dart.dart
@@ -56,9 +56,13 @@
    * list of [mixins] is provided but no [superclass] is given then the class
    * will extend `Object`.)
    */
-  void writeClassDeclaration(String name, {Iterable<DartType> interfaces,
-      bool isAbstract: false, void memberWriter(), Iterable<DartType> mixins,
-      String nameGroupName, DartType superclass});
+  void writeClassDeclaration(String name,
+      {Iterable<DartType> interfaces,
+      bool isAbstract: false,
+      void memberWriter(),
+      Iterable<DartType> mixins,
+      String nameGroupName,
+      DartType superclass});
 
   /**
    * Write the code for a declaration of a field with the given [name]. If an
@@ -76,9 +80,14 @@
    * required.) If a [typeGroupName] is provided, then if a type was written
    * it will be in the linked edit group with that name.
    */
-  void writeFieldDeclaration(String name, {void initializerWriter(),
-      bool isConst: false, bool isFinal: false, bool isStatic: false,
-      String nameGroupName, DartType type, String typeGroupName});
+  void writeFieldDeclaration(String name,
+      {void initializerWriter(),
+      bool isConst: false,
+      bool isFinal: false,
+      bool isStatic: false,
+      String nameGroupName,
+      DartType type,
+      String typeGroupName});
 
   /**
    * Write the code for a declaration of a getter with the given [name]. If a
@@ -91,8 +100,11 @@
    * getter. If a [returnTypeGroupName] is provided, then if a return type was
    * written it will be in the linked edit group with that name.
    */
-  void writeGetterDeclaration(String name, {void bodyWriter(),
-      bool isStatic: false, String nameGroupName, DartType returnType,
+  void writeGetterDeclaration(String name,
+      {void bodyWriter(),
+      bool isStatic: false,
+      String nameGroupName,
+      DartType returnType,
       String returnTypeGroupName});
 
   /**
@@ -130,8 +142,10 @@
    * `true`, then all of the supertypes of the [type] will be added as
    * suggestions for alternatives to the type name.
    */
-  bool writeType(DartType type, {bool addSupertypeProposals: false,
-      String groupName, bool required: false});
+  bool writeType(DartType type,
+      {bool addSupertypeProposals: false,
+      String groupName,
+      bool required: false});
 }
 
 /**
diff --git a/pkg/analysis_server/test/completion_test.dart b/pkg/analysis_server/test/completion_test.dart
index 0cebf2f..d602bde 100644
--- a/pkg/analysis_server/test/completion_test.dart
+++ b/pkg/analysis_server/test/completion_test.dart
@@ -1595,13 +1595,13 @@
   var v2 = p is!4;
 }''',
         <String>[
-          "1+MyClass",
-          "2+MyClass",
-          "3+MyClass",
-          "3-v1",
-          "4+is",
-          "4-isVariable"
-        ]);
+      "1+MyClass",
+      "2+MyClass",
+      "3+MyClass",
+      "3-v1",
+      "4+is",
+      "4-isVariable"
+    ]);
 
     buildTests(
         'testCompletion_is_asIdentifierStart',
diff --git a/pkg/analysis_server/test/completion_test_support.dart b/pkg/analysis_server/test/completion_test_support.dart
index 8d002eb..800a6f2 100644
--- a/pkg/analysis_server/test/completion_test_support.dart
+++ b/pkg/analysis_server/test/completion_test_support.dart
@@ -190,18 +190,14 @@
       if (!badPoints.isEmpty) {
         err.write("No test location for tests:");
         for (String ch in badPoints) {
-          err
-            ..write(' ')
-            ..write(ch);
+          err..write(' ')..write(ch);
         }
         err.write(' ');
       }
       if (!badResults.isEmpty) {
         err.write("No results for tests:");
         for (String ch in badResults) {
-          err
-            ..write(' ')
-            ..write(ch);
+          err..write(' ')..write(ch);
         }
       }
       throw new IllegalStateException(err.toString());
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index 4045228..20327de 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -366,8 +366,8 @@
 ''');
     // Setup .packages file
     newFile(
-      [projPath, '.packages'],
-      r'''
+        [projPath, '.packages'],
+        r'''
 test_pack:lib/
 ''');
     // Setup context.
@@ -382,7 +382,6 @@
     expect(source.fullName, equals('/my/proj/sdk_ext/entry.dart'));
   }
 
-
   test_refresh_folder_with_packagespec() {
     // create a context with a .packages file
     String packagespecFile = posix.join(projPath, '.packages');
diff --git a/pkg/analysis_server/test/domain_analysis_test.dart b/pkg/analysis_server/test/domain_analysis_test.dart
index d90922b..afcff2d 100644
--- a/pkg/analysis_server/test/domain_analysis_test.dart
+++ b/pkg/analysis_server/test/domain_analysis_test.dart
@@ -95,6 +95,18 @@
             expect(units, hasLength(1));
           });
         });
+
+        test('nonexistent folder', () async {
+          String fileB = '/project_b/b.dart';
+          resourceProvider.newFile(fileB, '// b');
+          var response = testSetAnalysisRoots(['/project_a', '/project_b'], []);
+          var serverRef = server;
+          expect(response, isResponseSuccess('0'));
+          // Non-existence of /project_a should not prevent files in /project_b
+          // from being analyzed.
+          await server.onAnalysisComplete;
+          expect(serverRef.getResolvedCompilationUnits(fileB), hasLength(1));
+        });
       });
     });
 
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index f09af0e..3c3306e 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -55,9 +55,14 @@
     ExtensionManager manager = new ExtensionManager();
     ServerPlugin serverPlugin = new ServerPlugin();
     manager.processPlugins([serverPlugin]);
-    return new Test_AnalysisServer(super.serverChannel, super.resourceProvider,
-        super.packageMapProvider, index, serverPlugin,
-        new AnalysisServerOptions(), new MockSdk(),
+    return new Test_AnalysisServer(
+        super.serverChannel,
+        super.resourceProvider,
+        super.packageMapProvider,
+        index,
+        serverPlugin,
+        new AnalysisServerOptions(),
+        new MockSdk(),
         InstrumentationService.NULL_SERVICE);
   }
 
@@ -422,8 +427,9 @@
         {testFile: new AddContentOverlay(revisedContent)}).toRequest('add1'));
 
     // Request code completion immediately after edit
-    Response response = handleSuccessfulRequest(new CompletionGetSuggestionsParams(
-        testFile, completionOffset).toRequest('0'));
+    Response response = handleSuccessfulRequest(
+        new CompletionGetSuggestionsParams(testFile, completionOffset)
+            .toRequest('0'));
     completionId = response.id;
     assertValidId(completionId);
     await waitForTasksFinished();
@@ -536,7 +542,9 @@
   }
 
   test_partFile() {
-    addFile('/project/bin/testA.dart', '''
+    addFile(
+        '/project/bin/testA.dart',
+        '''
       library libA;
       part "$testFile";
       import 'dart:html';
@@ -556,7 +564,9 @@
   }
 
   test_partFile2() {
-    addFile('/testA.dart', '''
+    addFile(
+        '/testA.dart',
+        '''
       part of libA;
       class A { }''');
     addTestFile('''
@@ -716,14 +726,24 @@
 class Test_AnalysisServer extends AnalysisServer {
   final MockContext mockContext = new MockContext();
 
-  Test_AnalysisServer(ServerCommunicationChannel channel,
+  Test_AnalysisServer(
+      ServerCommunicationChannel channel,
       ResourceProvider resourceProvider,
-      PubPackageMapProvider packageMapProvider, Index index,
-      ServerPlugin serverPlugin, AnalysisServerOptions analysisServerOptions,
-      DartSdk defaultSdk, InstrumentationService instrumentationService)
-      : super(channel, resourceProvider, packageMapProvider, index,
-          serverPlugin, analysisServerOptions, defaultSdk,
-          instrumentationService);
+      PubPackageMapProvider packageMapProvider,
+      Index index,
+      ServerPlugin serverPlugin,
+      AnalysisServerOptions analysisServerOptions,
+      DartSdk defaultSdk,
+      InstrumentationService instrumentationService)
+      : super(
+            channel,
+            resourceProvider,
+            packageMapProvider,
+            index,
+            serverPlugin,
+            analysisServerOptions,
+            defaultSdk,
+            instrumentationService);
 
   @override
   AnalysisContext getAnalysisContext(String path) {
diff --git a/pkg/analysis_server/test/integration/integration_tests.dart b/pkg/analysis_server/test/integration/integration_tests.dart
index 3345554..08fb56d 100644
--- a/pkg/analysis_server/test/integration/integration_tests.dart
+++ b/pkg/analysis_server/test/integration/integration_tests.dart
@@ -349,8 +349,8 @@
     if (requiredFields != null) {
       requiredFields.forEach((String key, Matcher valueMatcher) {
         if (!item.containsKey(key)) {
-          mismatches.add(
-              (Description mismatchDescription) => mismatchDescription
+          mismatches.add((Description mismatchDescription) =>
+              mismatchDescription
                   .add('is missing field ')
                   .addDescriptionOf(key)
                   .add(' (')
@@ -381,7 +381,10 @@
    */
   void _checkField(String key, value, Matcher valueMatcher,
       List<MismatchDescriber> mismatches) {
-    checkSubstructure(value, valueMatcher, mismatches,
+    checkSubstructure(
+        value,
+        valueMatcher,
+        mismatches,
         (Description description) =>
             description.add('field ').addDescriptionOf(key));
   }
@@ -590,8 +593,11 @@
    * `true`, the server will be started with "--observe" and
    * "--pause-isolates-on-exit", allowing the observatory to be used.
    */
-  Future start({bool debugServer: false, int diagnosticPort,
-      bool profileServer: false, bool newTaskModel: false,
+  Future start(
+      {bool debugServer: false,
+      int diagnosticPort,
+      bool profileServer: false,
+      bool newTaskModel: false,
       bool useAnalysisHighlight2: false}) {
     if (_process != null) {
       throw new Exception('Process already started');
@@ -696,8 +702,8 @@
   Description describeMismatch(
       item, Description mismatchDescription, Map matchState, bool verbose) {
     if (item is! List) {
-      return super.describeMismatch(
-          item, mismatchDescription, matchState, verbose);
+      return super
+          .describeMismatch(item, mismatchDescription, matchState, verbose);
     } else {
       return iterableMatcher.describeMismatch(
           item, mismatchDescription, matchState, verbose);
@@ -744,10 +750,16 @@
       return;
     }
     item.forEach((key, value) {
-      checkSubstructure(key, keyMatcher, mismatches,
+      checkSubstructure(
+          key,
+          keyMatcher,
+          mismatches,
           (Description description) =>
               description.add('key ').addDescriptionOf(key));
-      checkSubstructure(value, valueMatcher, mismatches,
+      checkSubstructure(
+          value,
+          valueMatcher,
+          mismatches,
           (Description description) =>
               description.add('field ').addDescriptionOf(key));
     });
@@ -850,8 +862,8 @@
       }
       return mismatchDescription;
     } else {
-      return super.describeMismatch(
-          item, mismatchDescription, matchState, verbose);
+      return super
+          .describeMismatch(item, mismatchDescription, matchState, verbose);
     }
   }
 
@@ -878,6 +890,6 @@
    */
   MismatchDescriber simpleDescription(String description) =>
       (Description mismatchDescription) {
-    mismatchDescription.add(description);
-  };
+        mismatchDescription.add(description);
+      };
 }
diff --git a/pkg/analysis_server/test/mock_sdk.dart b/pkg/analysis_server/test/mock_sdk.dart
index 78ee244..6d41c97 100644
--- a/pkg/analysis_server/test/mock_sdk.dart
+++ b/pkg/analysis_server/test/mock_sdk.dart
@@ -12,8 +12,10 @@
 import 'package:analyzer/src/generated/source.dart';
 
 class MockSdk implements DartSdk {
-  static const _MockSdkLibrary LIB_CORE = const _MockSdkLibrary('dart:core',
-      '/lib/core/core.dart', '''
+  static const _MockSdkLibrary LIB_CORE = const _MockSdkLibrary(
+      'dart:core',
+      '/lib/core/core.dart',
+      '''
 library dart.core;
 
 import 'dart:async';
@@ -112,8 +114,10 @@
 }
 ''');
 
-  static const _MockSdkLibrary LIB_ASYNC = const _MockSdkLibrary('dart:async',
-      '/lib/async/async.dart', '''
+  static const _MockSdkLibrary LIB_ASYNC = const _MockSdkLibrary(
+      'dart:async',
+      '/lib/async/async.dart',
+      '''
 library dart.async;
 
 import 'dart:math';
@@ -130,14 +134,18 @@
 ''');
 
   static const _MockSdkLibrary LIB_COLLECTION = const _MockSdkLibrary(
-      'dart:collection', '/lib/collection/collection.dart', '''
+      'dart:collection',
+      '/lib/collection/collection.dart',
+      '''
 library dart.collection;
 
 abstract class HashMap<K, V> implements Map<K, V> {}
 ''');
 
   static const _MockSdkLibrary LIB_CONVERT = const _MockSdkLibrary(
-      'dart:convert', '/lib/convert/convert.dart', '''
+      'dart:convert',
+      '/lib/convert/convert.dart',
+      '''
 library dart.convert;
 
 import 'dart:async';
@@ -146,8 +154,10 @@
 class JsonDecoder extends Converter<String, Object> {}
 ''');
 
-  static const _MockSdkLibrary LIB_MATH = const _MockSdkLibrary('dart:math',
-      '/lib/math/math.dart', '''
+  static const _MockSdkLibrary LIB_MATH = const _MockSdkLibrary(
+      'dart:math',
+      '/lib/math/math.dart',
+      '''
 library dart.math;
 const double E = 2.718281828459045;
 const double PI = 3.1415926535897932;
@@ -165,14 +175,18 @@
 }
 ''');
 
-  static const _MockSdkLibrary LIB_HTML = const _MockSdkLibrary('dart:html',
-      '/lib/html/dartium/html_dartium.dart', '''
+  static const _MockSdkLibrary LIB_HTML = const _MockSdkLibrary(
+      'dart:html',
+      '/lib/html/dartium/html_dartium.dart',
+      '''
 library dart.html;
 class HtmlElement {}
 ''');
 
   static const _MockSdkLibrary LIB_INTERNAL = const _MockSdkLibrary(
-      'dart:_internal', '/lib/internal/internal.dart', '''
+      'dart:_internal',
+      '/lib/internal/internal.dart',
+      '''
 library dart._internal;
 external void printToConsole(String line);
 ''');
diff --git a/pkg/analysis_server/test/operation/operation_queue_test.dart b/pkg/analysis_server/test/operation/operation_queue_test.dart
index 0be1a73..ed7fbca 100644
--- a/pkg/analysis_server/test/operation/operation_queue_test.dart
+++ b/pkg/analysis_server/test/operation/operation_queue_test.dart
@@ -60,6 +60,23 @@
 class ServerOperationQueueTest {
   ServerOperationQueue queue = new ServerOperationQueue();
 
+  void test_add_withMerge() {
+    var opA = new _MergeableOperationMock();
+    var opB = new _MergeableOperationMock();
+    var opC = new _MergeableOperationMock();
+    when(opA.merge(opC)).thenReturn(true);
+    when(opA.merge(anyObject)).thenReturn(false);
+    when(opB.merge(anyObject)).thenReturn(false);
+    when(opC.merge(anyObject)).thenReturn(false);
+    queue.add(opA);
+    queue.add(opB);
+    queue.add(opC);
+    expect(queue.take(), same(opA));
+    expect(queue.take(), same(opB));
+    // no opC, it was merged into opA
+    expect(queue.isEmpty, isTrue);
+  }
+
   void test_clear() {
     var operationA = mockOperation(ServerOperationPriority.ANALYSIS);
     var operationB = mockOperation(ServerOperationPriority.ANALYSIS_CONTINUE);
@@ -106,6 +123,20 @@
     expect(queue.isEmpty, isTrue);
   }
 
+  void test_peek() {
+    var operationA = mockOperation(ServerOperationPriority.ANALYSIS);
+    var operationB = mockOperation(ServerOperationPriority.ANALYSIS);
+    queue.add(operationA);
+    queue.add(operationB);
+    expect(queue.peek(), operationA);
+    expect(queue.peek(), operationA);
+    expect(queue.peek(), operationA);
+  }
+
+  void test_peek_empty() {
+    expect(queue.peek(), isNull);
+  }
+
   void test_reschedule() {
     var prioritySource = new MockSource();
     var analysisContextA = new AnalysisContextMock();
@@ -180,6 +211,27 @@
     expect(queue.take(), operationA);
     expect(queue.take(), isNull);
   }
+
+  void test_takeIf() {
+    var operationA = mockOperation(ServerOperationPriority.ANALYSIS);
+    var operationB = mockOperation(ServerOperationPriority.ANALYSIS);
+    queue.add(operationA);
+    queue.add(operationB);
+    expect(queue.takeIf((_) => false), isNull);
+    expect(queue.takeIf((operation) => operation == operationB), operationB);
+    expect(queue.takeIf((operation) => operation == operationB), isNull);
+    expect(queue.takeIf((operation) => operation == operationA), operationA);
+    expect(queue.isEmpty, isTrue);
+  }
+}
+
+class _MergeableOperationMock extends TypedMock implements MergeableOperation {
+  @override
+  ServerOperationPriority get priority {
+    return ServerOperationPriority.ANALYSIS_NOTIFICATION;
+  }
+
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 }
 
 class _ServerOperationMock extends TypedMock implements ServerOperation {
diff --git a/pkg/analysis_server/test/plugin/set_analysis_domain_test.dart b/pkg/analysis_server/test/plugin/set_analysis_domain_test.dart
index 38953fa0..02200c0 100644
--- a/pkg/analysis_server/test/plugin/set_analysis_domain_test.dart
+++ b/pkg/analysis_server/test/plugin/set_analysis_domain_test.dart
@@ -7,8 +7,10 @@
 import 'dart:async';
 
 import 'package:analysis_server/analysis/analysis_domain.dart';
-import 'package:analysis_server/analysis/navigation/navigation_core.dart';
+import 'package:analysis_server/analysis/navigation_core.dart';
+import 'package:analysis_server/analysis/occurrences_core.dart';
 import 'package:analysis_server/plugin/navigation.dart';
+import 'package:analysis_server/plugin/occurrences.dart';
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol.dart';
 import 'package:analyzer/src/generated/engine.dart';
@@ -37,11 +39,9 @@
 @reflectiveTest
 class SetAnalysisDomainTest extends AbstractAnalysisTest {
   final Set<String> parsedUnitFiles = new Set<String>();
-  bool contributorMayAddRegion = false;
 
-  List<NavigationRegion> regions;
-  List<NavigationTarget> targets;
-  List<String> targetFiles;
+  AnalysisNavigationParams navigationParams;
+  AnalysisOccurrencesParams occurrencesParams;
 
   @override
   void addServerPlugins(List<Plugin> plugins) {
@@ -53,15 +53,14 @@
   void processNotification(Notification notification) {
     if (notification.event == ANALYSIS_NAVIGATION) {
       var params = new AnalysisNavigationParams.fromNotification(notification);
-      // TODO(scheglov) we check for "params.regions.isNotEmpty" because
-      // normal, Dart only, navigation notifications are scheduled as
-      // operations, but plugins use "notificationSite.scheduleNavigation"
-      // which is not scheduled yet. So, it comes *before* the Dart one, and
-      // gets lost.
-      if (params.file == testFile && params.regions.isNotEmpty) {
-        regions = params.regions;
-        targets = params.targets;
-        targetFiles = params.files;
+      if (params.file == testFile) {
+        navigationParams = params;
+      }
+    }
+    if (notification.event == ANALYSIS_OCCURRENCES) {
+      var params = new AnalysisOccurrencesParams.fromNotification(notification);
+      if (params.file == testFile) {
+        occurrencesParams = params;
       }
     }
   }
@@ -69,27 +68,38 @@
   Future test_contributorIsInvoked() async {
     createProject();
     addAnalysisSubscription(AnalysisService.NAVIGATION, testFile);
+    addAnalysisSubscription(AnalysisService.OCCURRENCES, testFile);
     addTestFile('// usually no navigation');
     await server.onAnalysisComplete;
     // we have PARSED_UNIT
     expect(parsedUnitFiles, contains(testFile));
     // we have an additional navigation region/target
-    expect(regions, hasLength(1));
     {
-      NavigationRegion region = regions.single;
-      expect(region.offset, 1);
-      expect(region.length, 5);
-      expect(region.targets.single, 0);
+      expect(navigationParams.regions, hasLength(1));
+      {
+        NavigationRegion region = navigationParams.regions.single;
+        expect(region.offset, 1);
+        expect(region.length, 5);
+        expect(region.targets.single, 0);
+      }
+      {
+        NavigationTarget target = navigationParams.targets.single;
+        expect(target.fileIndex, 0);
+        expect(target.offset, 1);
+        expect(target.length, 2);
+        expect(target.startLine, 3);
+        expect(target.startColumn, 4);
+      }
+      expect(navigationParams.files.single, '/testLocation.dart');
     }
+    // we have additional occurrences
     {
-      NavigationTarget target = targets.single;
-      expect(target.fileIndex, 0);
-      expect(target.offset, 1);
-      expect(target.length, 2);
-      expect(target.startLine, 3);
-      expect(target.startColumn, 4);
+      expect(occurrencesParams.occurrences, hasLength(1));
+      Occurrences occurrences = occurrencesParams.occurrences.single;
+      expect(occurrences.element.name, 'TestElement');
+      expect(occurrences.length, 5);
+      expect(occurrences.offsets, unorderedEquals([1, 2, 3]));
     }
-    expect(targetFiles.single, '/testLocation.dart');
   }
 }
 
@@ -99,12 +109,24 @@
   TestNavigationContributor(this.test);
 
   @override
-  void computeNavigation(NavigationHolder holder, AnalysisContext context,
+  void computeNavigation(NavigationCollector collector, AnalysisContext context,
       Source source, int offset, int length) {
-    if (test.contributorMayAddRegion) {
-      holder.addRegion(1, 5, ElementKind.CLASS,
-          new Location('/testLocation.dart', 1, 2, 3, 4));
-    }
+    collector.addRegion(1, 5, ElementKind.CLASS,
+        new Location('/testLocation.dart', 1, 2, 3, 4));
+  }
+}
+
+class TestOccurrencesContributor implements OccurrencesContributor {
+  final SetAnalysisDomainTest test;
+
+  TestOccurrencesContributor(this.test);
+
+  @override
+  void computeOccurrences(
+      OccurrencesCollector collector, AnalysisContext context, Source source) {
+    Element element = new Element(ElementKind.UNKNOWN, 'TestElement', 0);
+    collector.addOccurrences(new Occurrences(element, <int>[1, 2], 5));
+    collector.addOccurrences(new Occurrences(element, <int>[3], 5));
   }
 }
 
@@ -124,6 +146,8 @@
     register(SET_ANALYSIS_DOMAIN_EXTENSION_POINT_ID, _setAnalysisDomain);
     register(NAVIGATION_CONTRIBUTOR_EXTENSION_POINT_ID,
         new TestNavigationContributor(test));
+    register(OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT_ID,
+        new TestOccurrencesContributor(test));
   }
 
   void _setAnalysisDomain(AnalysisDomain domain) {
@@ -133,14 +157,10 @@
       expect(result.value, isNotNull);
       Source source = result.target.source;
       test.parsedUnitFiles.add(source.fullName);
-      // let the navigation contributor to work
-      test.contributorMayAddRegion = true;
-      try {
-        domain.scheduleNotification(
-            result.context, source, AnalysisService.NAVIGATION);
-      } finally {
-        test.contributorMayAddRegion = false;
-      }
+      domain.scheduleNotification(
+          result.context, source, AnalysisService.NAVIGATION);
+      domain.scheduleNotification(
+          result.context, source, AnalysisService.OCCURRENCES);
     });
   }
 }
diff --git a/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart b/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart
index 0f391e8..433448b 100644
--- a/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart
@@ -42,8 +42,10 @@
     assertNoOtherSuggestions([cs]);
   }
 
-  void assertSuggestArgumentList_params(List<String> expectedNames,
-      List<String> expectedTypes, List<String> actualNames,
+  void assertSuggestArgumentList_params(
+      List<String> expectedNames,
+      List<String> expectedTypes,
+      List<String> actualNames,
       List<String> actualTypes) {
     if (actualNames != null &&
         actualNames.length == expectedNames.length &&
@@ -118,7 +120,9 @@
 
   test_ArgumentList_imported_function_0() {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
-    addSource('/libA.dart', '''
+    addSource(
+        '/libA.dart',
+        '''
       library A;
       bool hasLength(int expected) { }
       expect() { }
@@ -136,7 +140,9 @@
 
   test_ArgumentList_imported_function_1() {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
-    addSource('/libA.dart', '''
+    addSource(
+        '/libA.dart',
+        '''
       library A;
       bool hasLength(int expected) { }
       expect(String arg) { }
@@ -154,7 +160,9 @@
 
   test_ArgumentList_imported_function_2() {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
-    addSource('/libA.dart', '''
+    addSource(
+        '/libA.dart',
+        '''
       library A;
       bool hasLength(int expected) { }
       expect(String arg1, int arg2) { }
@@ -172,7 +180,9 @@
 
   test_ArgumentList_imported_function_3() {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
-    addSource('/libA.dart', '''
+    addSource(
+        '/libA.dart',
+        '''
       library A;
       bool hasLength(int expected) { }
       expect(String arg1, int arg2, {bool arg3}) { }
@@ -190,7 +200,9 @@
 
   test_ArgumentList_imported_function_3a() {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
-    addSource('/libA.dart', '''
+    addSource(
+        '/libA.dart',
+        '''
       library A;
       bool hasLength(int expected) { }
       expect(String arg1, int arg2, {bool arg3}) { }
@@ -208,7 +220,9 @@
 
   test_ArgumentList_imported_function_3b() {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
-    addSource('/libA.dart', '''
+    addSource(
+        '/libA.dart',
+        '''
       library A;
       bool hasLength(int expected) { }
       expect(String arg1, int arg2, {bool arg3}) { }
@@ -226,7 +240,9 @@
 
   test_ArgumentList_imported_function_3c() {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
-    addSource('/libA.dart', '''
+    addSource(
+        '/libA.dart',
+        '''
       library A;
       bool hasLength(int expected) { }
       expect(String arg1, int arg2, {bool arg3}) { }
@@ -244,7 +260,9 @@
 
   test_ArgumentList_imported_function_3d() {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
-    addSource('/libA.dart', '''
+    addSource(
+        '/libA.dart',
+        '''
       library A;
       bool hasLength(int expected) { }
       expect(String arg1, int arg2, {bool arg3}) { }
@@ -462,7 +480,9 @@
 
   test_ArgumentList_local_method_0() {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
-    addSource('/libA.dart', '''
+    addSource(
+        '/libA.dart',
+        '''
       library A;
       bool hasLength(int expected) { }
       void baz() { }''');
@@ -480,7 +500,9 @@
 
   test_ArgumentList_local_method_2() {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
-    addSource('/libA.dart', '''
+    addSource(
+        '/libA.dart',
+        '''
       library A;
       bool hasLength(int expected) { }
       void baz() { }''');
diff --git a/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart
index 2a537ed..cb29f97 100644
--- a/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart
@@ -25,8 +25,10 @@
   @override
   CompletionSuggestion assertSuggestLocalClass(String name,
       {CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
-      int relevance: DART_RELEVANCE_DEFAULT, bool isDeprecated: false,
-      String elemFile, int elemOffset}) {
+      int relevance: DART_RELEVANCE_DEFAULT,
+      bool isDeprecated: false,
+      String elemFile,
+      int elemOffset}) {
     return assertSuggestClass(name,
         elemFile: elemFile,
         elemOffset: elemOffset,
diff --git a/pkg/analysis_server/test/services/correction/fix_test.dart b/pkg/analysis_server/test/services/correction/fix_test.dart
index 5735dec..393c2f3 100644
--- a/pkg/analysis_server/test/services/correction/fix_test.dart
+++ b/pkg/analysis_server/test/services/correction/fix_test.dart
@@ -541,6 +541,15 @@
     _assertLinkedGroup(change.linkedEditGroups[0], ['Test v =', 'Test {']);
   }
 
+  void test_createClass_BAD_hasUnresolvedPrefix() {
+    resolveTestUnit('''
+main() {
+  prefix.Test v = null;
+}
+''');
+    assertNoFix(DartFixKind.CREATE_CLASS);
+  }
+
   void test_createClass_inLibraryOfPrefix() {
     String libCode = r'''
 library my.lib;
@@ -2612,44 +2621,6 @@
 ''');
   }
 
-  void test_importLibraryPrefix_withClass() {
-    resolveTestUnit('''
-import 'dart:async' as pref;
-main() {
-  pref.Stream s = null;
-  Future f = null;
-}
-''');
-    assertHasFix(
-        DartFixKind.IMPORT_LIBRARY_PREFIX,
-        '''
-import 'dart:async' as pref;
-main() {
-  pref.Stream s = null;
-  pref.Future f = null;
-}
-''');
-  }
-
-  void test_importLibraryPrefix_withTopLevelVariable() {
-    resolveTestUnit('''
-import 'dart:math' as pref;
-main() {
-  print(pref.E);
-  print(PI);
-}
-''');
-    assertHasFix(
-        DartFixKind.IMPORT_LIBRARY_PREFIX,
-        '''
-import 'dart:math' as pref;
-main() {
-  print(pref.E);
-  print(pref.PI);
-}
-''');
-  }
-
   void test_importLibraryProject_withClass_annotation() {
     addSource(
         '/lib.dart',
@@ -4364,6 +4335,44 @@
 ''');
   }
 
+  void test_useImportPrefix_withClass() {
+    resolveTestUnit('''
+import 'dart:async' as pref;
+main() {
+  pref.Stream s = null;
+  Future f = null;
+}
+''');
+    assertHasFix(
+        DartFixKind.IMPORT_LIBRARY_PREFIX,
+        '''
+import 'dart:async' as pref;
+main() {
+  pref.Stream s = null;
+  pref.Future f = null;
+}
+''');
+  }
+
+  void test_useImportPrefix_withTopLevelVariable() {
+    resolveTestUnit('''
+import 'dart:math' as pref;
+main() {
+  print(pref.E);
+  print(PI);
+}
+''');
+    assertHasFix(
+        DartFixKind.IMPORT_LIBRARY_PREFIX,
+        '''
+import 'dart:math' as pref;
+main() {
+  print(pref.E);
+  print(pref.PI);
+}
+''');
+  }
+
   /**
    * Computes fixes and verifies that there is a fix of the given kind.
    */
diff --git a/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart b/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
index 8ed4913..81d13c0 100644
--- a/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
+++ b/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
@@ -92,7 +92,8 @@
    */
   void assertRefactoringStatus(
       RefactoringStatus status, RefactoringProblemSeverity expectedSeverity,
-      {String expectedMessage, SourceRange expectedContextRange,
+      {String expectedMessage,
+      SourceRange expectedContextRange,
       String expectedContextSearch}) {
     expect(status.severity, expectedSeverity, reason: status.toString());
     if (expectedSeverity != null) {
diff --git a/pkg/analysis_server/test/socket_server_test.dart b/pkg/analysis_server/test/socket_server_test.dart
index a961aae..f1ef37e 100644
--- a/pkg/analysis_server/test/socket_server_test.dart
+++ b/pkg/analysis_server/test/socket_server_test.dart
@@ -116,7 +116,6 @@
         DirectoryBasedDartSdk.defaultSdk,
         InstrumentationService.NULL_SERVICE,
         serverPlugin,
-        null,
         null);
   }
 }
diff --git a/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart b/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
index 913b9b2..c7e387b 100644
--- a/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
+++ b/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
@@ -35,8 +35,8 @@
   'deprecated': '0x20'
 };
 
-final GeneratedFile target = new GeneratedFile(
-    '../../lib/src/generated_protocol.dart', () {
+final GeneratedFile target =
+    new GeneratedFile('../../lib/src/generated_protocol.dart', () {
   CodegenProtocolVisitor visitor = new CodegenProtocolVisitor(readApi());
   return visitor.collectCode(visitor.visitApi);
 });
@@ -563,8 +563,8 @@
       writeln('factory RefactoringOptions.fromJson(JsonDecoder jsonDecoder, '
           'String jsonPath, Object json, RefactoringKind kind) {');
       indent(() {
-        writeln(
-            'return _refactoringOptionsFromJson(jsonDecoder, jsonPath, ' 'json, kind);');
+        writeln('return _refactoringOptionsFromJson(jsonDecoder, jsonPath, '
+            'json, kind);');
       });
       writeln('}');
       return;
diff --git a/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart b/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart
index bc7bce6..38b3f20 100644
--- a/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart
+++ b/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart
@@ -160,11 +160,9 @@
   visitNotification(Notification notification) {
     String streamName =
         camelJoin(['on', notification.domainName, notification.event]);
-    String className = camelJoin([
-      notification.domainName,
-      notification.event,
-      'params'
-    ], doCapitalize: true);
+    String className = camelJoin(
+        [notification.domainName, notification.event, 'params'],
+        doCapitalize: true);
     writeln();
     docComment(toHtmlVisitor.collectHtml(() {
       toHtmlVisitor.translateHtml(notification.html);
@@ -234,7 +232,8 @@
     writeln('$futureClass $methodName(${args.join(', ')}) {');
     indent(() {
       String requestClass = camelJoin(
-          [request.domainName, request.method, 'params'], doCapitalize: true);
+          [request.domainName, request.method, 'params'],
+          doCapitalize: true);
       String paramsVar = 'null';
       if (request.params != null) {
         paramsVar = 'params';
diff --git a/pkg/analysis_server/tool/spec/codegen_matchers.dart b/pkg/analysis_server/tool/spec/codegen_matchers.dart
index e0e6448..5786493 100644
--- a/pkg/analysis_server/tool/spec/codegen_matchers.dart
+++ b/pkg/analysis_server/tool/spec/codegen_matchers.dart
@@ -15,8 +15,8 @@
 import 'implied_types.dart';
 import 'to_html.dart';
 
-final GeneratedFile target = new GeneratedFile(
-    '../../test/integration/protocol_matchers.dart', () {
+final GeneratedFile target =
+    new GeneratedFile('../../test/integration/protocol_matchers.dart', () {
   CodegenMatchersVisitor visitor = new CodegenMatchersVisitor(readApi());
   return visitor.collectCode(visitor.visitApi);
 });
diff --git a/pkg/analysis_server/tool/spec/codegen_tools.dart b/pkg/analysis_server/tool/spec/codegen_tools.dart
index 45dd4be..f3fcb5d 100644
--- a/pkg/analysis_server/tool/spec/codegen_tools.dart
+++ b/pkg/analysis_server/tool/spec/codegen_tools.dart
@@ -77,7 +77,8 @@
     try {
       _state = new _CodeGeneratorState();
       callback();
-      var text = _state.buffer.toString().replaceAll(trailingSpacesInLineRegExp, '');
+      var text =
+          _state.buffer.toString().replaceAll(trailingSpacesInLineRegExp, '');
       if (!removeTrailingNewLine) {
         return text;
       } else {
@@ -101,7 +102,7 @@
     bool javadocStyle = codeGeneratorSettings.languageName == 'java';
     indentBy(codeGeneratorSettings.docCommentLineLeader, () {
       write(nodesToText(docs, width - _state.indent.length, javadocStyle,
-        removeTrailingNewLine: removeTrailingNewLine));
+          removeTrailingNewLine: removeTrailingNewLine));
     });
     writeln(codeGeneratorSettings.docCommentEndMarker);
   }
@@ -110,8 +111,8 @@
    * Execute [callback], indenting any code it outputs.
    */
   void indent(void callback()) {
-    indentSpecial(codeGeneratorSettings.indent, codeGeneratorSettings.indent,
-      callback);
+    indentSpecial(
+        codeGeneratorSettings.indent, codeGeneratorSettings.indent, callback);
   }
 
   /**
@@ -250,10 +251,14 @@
    */
   String indent;
 
-  CodeGeneratorSettings({this.languageName: 'java',
-      this.lineCommentLineLeader: '// ', this.docCommentStartMarker: '/**',
-      this.docCommentLineLeader: ' * ', this.docCommentEndMarker: ' */',
-      this.commentLineLength: 99, this.indent: '  '});
+  CodeGeneratorSettings(
+      {this.languageName: 'java',
+      this.lineCommentLineLeader: '// ',
+      this.docCommentStartMarker: '/**',
+      this.docCommentLineLeader: ' * ',
+      this.docCommentEndMarker: ' */',
+      this.commentLineLength: 99,
+      this.indent: '  '});
 }
 
 abstract class GeneratedContent {
@@ -267,7 +272,6 @@
  * generated HTML). No other content should exist in the directory.
  */
 class GeneratedDirectory extends GeneratedContent {
-
   /**
    * The path to the directory that will have the generated content.
    */
@@ -308,8 +312,9 @@
         }
       }
       int nonHiddenFileCount = 0;
-      outputFile.listSync(recursive: false, followLinks: false).forEach(
-          (FileSystemEntity fileSystemEntity) {
+      outputFile
+          .listSync(recursive: false, followLinks: false)
+          .forEach((FileSystemEntity fileSystemEntity) {
         if (fileSystemEntity is File &&
             !basename(fileSystemEntity.path).startsWith('.')) {
           nonHiddenFileCount++;
diff --git a/pkg/analysis_server/tool/spec/from_html.dart b/pkg/analysis_server/tool/spec/from_html.dart
index 458142b..c3e3010 100644
--- a/pkg/analysis_server/tool/spec/from_html.dart
+++ b/pkg/analysis_server/tool/spec/from_html.dart
@@ -123,6 +123,7 @@
         '$context: Expected $expectedName, found ${element.localName}');
   }
 }
+
 /**
  * Create a [Domain] object from an HTML representation such as:
  *
@@ -419,6 +420,7 @@
   TypeDecl type = processContentsAsType(html, context);
   return new TypeDefinition(name, type, html);
 }
+
 /**
  * Create a [TypeEnum] from an HTML description.
  */
@@ -480,8 +482,8 @@
   checkName(html, 'field', context);
   String name = html.attributes['name'];
   context = '$context.${name != null ? name : 'field'}';
-  checkAttributes(
-      html, ['name'], context, optionalAttributes: ['optional', 'value']);
+  checkAttributes(html, ['name'], context,
+      optionalAttributes: ['optional', 'value']);
   bool optional = false;
   String optionalString = html.attributes['optional'];
   if (optionalString != null) {
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/NavigationRegion.java b/pkg/analysis_server/tool/spec/generated/java/types/NavigationRegion.java
index b42bdc7..8500056 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/NavigationRegion.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/NavigationRegion.java
@@ -55,7 +55,8 @@
 
   /**
    * The indexes of the targets (in the enclosing navigation response) to which the given region is
-   * bound. By opening the target, clients can implement one form of navigation.
+   * bound. By opening the target, clients can implement one form of navigation. This list cannot be
+   * empty.
    */
   private final int[] targets;
 
@@ -125,7 +126,8 @@
 
   /**
    * The indexes of the targets (in the enclosing navigation response) to which the given region is
-   * bound. By opening the target, clients can implement one form of navigation.
+   * bound. By opening the target, clients can implement one form of navigation. This list cannot be
+   * empty.
    */
   public int[] getTargets() {
     return targets;
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index 974eb97..5b0a431 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -3054,7 +3054,7 @@
             <p>
               The indexes of the targets (in the enclosing navigation response)
               to which the given region is bound. By opening the target, clients
-              can implement one form of navigation.
+              can implement one form of navigation. This list cannot be empty.
             </p>
           </field>
         </object>
diff --git a/pkg/analysis_server/tool/spec/text_formatter.dart b/pkg/analysis_server/tool/spec/text_formatter.dart
index 44c9ba0..a4eb82c 100644
--- a/pkg/analysis_server/tool/spec/text_formatter.dart
+++ b/pkg/analysis_server/tool/spec/text_formatter.dart
@@ -19,8 +19,8 @@
  * If [javadocStyle] is true, then the output is compatable with Javadoc,
  * which understands certain HTML constructs.
  */
-String nodesToText(List<dom.Node> desc, int width, bool javadocStyle, {
-    bool removeTrailingNewLine: false}) {
+String nodesToText(List<dom.Node> desc, int width, bool javadocStyle,
+    {bool removeTrailingNewLine: false}) {
   _TextFormatter formatter = new _TextFormatter(width, javadocStyle);
   return formatter.collectCode(() {
     formatter.addAll(desc);
diff --git a/pkg/analysis_server/tool/spec/to_html.dart b/pkg/analysis_server/tool/spec/to_html.dart
index 005ce6a..3d35b01 100644
--- a/pkg/analysis_server/tool/spec/to_html.dart
+++ b/pkg/analysis_server/tool/spec/to_html.dart
@@ -125,6 +125,7 @@
   void box(void callback()) {
     element('div', {'class': 'box'}, callback);
   }
+
   void br() => element('br', {});
   void dd(void callback()) => element('dd', {}, callback);
   void dl(void callback()) => element('dl', {}, callback);
@@ -140,6 +141,7 @@
     }
     return element('h2', {'class': cls}, callback);
   }
+
   void h3(void callback()) => element('h3', {}, callback);
   void h4(void callback()) => element('h4', {}, callback);
   void h5(void callback()) => element('h5', {}, callback);
@@ -151,6 +153,7 @@
   void link(String id, void callback()) {
     element('a', {'href': '#$id'}, callback);
   }
+
   void p(void callback()) => element('p', {}, callback);
   void pre(void callback()) => element('pre', {}, callback);
   void title(void callback()) => element('title', {}, callback);
@@ -526,8 +529,11 @@
     h5(() => write("Requests"));
     element('ul', {}, () {
       for (var request in requests) {
-        element('li', {}, () => link('request_${request.longMethod}', () =>
-          write(request.method)));
+        element(
+            'li',
+            {},
+            () => link(
+                'request_${request.longMethod}', () => write(request.method)));
       }
     });
   }
@@ -537,8 +543,11 @@
     element('div', {'class': 'subindex'}, () {
       element('ul', {}, () {
         for (var notification in notifications) {
-          element('li', {}, () => link('notification_${notification.longEvent}',
-            () => write(notification.event)));
+          element(
+              'li',
+              {},
+              () => link('notification_${notification.longEvent}',
+                  () => write(notification.event)));
         }
       });
     });
@@ -571,8 +580,11 @@
     element('div', {'class': 'subindex'}, () {
       element('ul', {}, () {
         for (var refactoring in refactorings) {
-          element('li', {}, () => link('refactoring_${refactoring.kind}',
-            () => write(refactoring.kind)));
+          element(
+              'li',
+              {},
+              () => link('refactoring_${refactoring.kind}',
+                  () => write(refactoring.kind)));
         }
       });
     });
diff --git a/pkg/analyzer/lib/file_system/physical_file_system.dart b/pkg/analyzer/lib/file_system/physical_file_system.dart
index b8fdcf1..303d175 100644
--- a/pkg/analyzer/lib/file_system/physical_file_system.dart
+++ b/pkg/analyzer/lib/file_system/physical_file_system.dart
@@ -19,8 +19,8 @@
  * A `dart:io` based implementation of [ResourceProvider].
  */
 class PhysicalResourceProvider implements ResourceProvider {
-  static final NORMALIZE_EOL_ALWAYS =
-      (String string) => string.replaceAll(new RegExp('\r\n?'), '\n');
+  static final NORMALIZE_EOL_ALWAYS = (String string) =>
+      string.replaceAll(new RegExp('\r\n?'), '\n');
 
   static final PhysicalResourceProvider INSTANCE =
       new PhysicalResourceProvider(null);
diff --git a/pkg/analyzer/lib/instrumentation/instrumentation.dart b/pkg/analyzer/lib/instrumentation/instrumentation.dart
index 40db35e..18772de 100644
--- a/pkg/analyzer/lib/instrumentation/instrumentation.dart
+++ b/pkg/analyzer/lib/instrumentation/instrumentation.dart
@@ -150,14 +150,21 @@
    * entry has the given [level] and [message], and was created at the given
    * [time].
    */
-  void logLogEntry(String level, DateTime time, String message, Object exception, StackTrace stackTrace) {
+  void logLogEntry(String level, DateTime time, String message,
+      Object exception, StackTrace stackTrace) {
     if (_instrumentationServer != null) {
       String timeStamp =
           time == null ? 'null' : time.millisecondsSinceEpoch.toString();
       String exceptionText = exception.toString();
       String stackTraceText = stackTrace.toString();
-      _instrumentationServer
-          .log(_join([TAG_LOG_ENTRY, level, timeStamp, message, exceptionText, stackTraceText]));
+      _instrumentationServer.log(_join([
+        TAG_LOG_ENTRY,
+        level,
+        timeStamp,
+        message,
+        exceptionText,
+        stackTraceText
+      ]));
     }
   }
 
diff --git a/pkg/analyzer/lib/plugin/options.dart b/pkg/analyzer/lib/plugin/options.dart
index cc0b88d..65775e1 100644
--- a/pkg/analyzer/lib/plugin/options.dart
+++ b/pkg/analyzer/lib/plugin/options.dart
@@ -18,7 +18,7 @@
     OptionsPlugin.OPTIONS_PROCESSOR_EXTENSION_POINT);
 
 /// Processes options defined in the analysis options file.
-/// 
+///
 /// The options file format is intentionally very open-ended, giving clients
 /// utmost flexibility in defining their own options.  The only hardfast
 /// expectation is that options files will contain a mapping from Strings
@@ -45,7 +45,6 @@
 ///     bool useMultiPackage =
 ///         options['compiler']['resolver']['useMultiPackage'];
 abstract class OptionsProcessor {
-
   /// Called when an error occurs in processing options.
   void onError(Exception exception);
 
diff --git a/pkg/analyzer/lib/plugin/task.dart b/pkg/analyzer/lib/plugin/task.dart
index 72c33fa..fd4dd7c 100644
--- a/pkg/analyzer/lib/plugin/task.dart
+++ b/pkg/analyzer/lib/plugin/task.dart
@@ -15,6 +15,32 @@
 
 /**
  * The identifier of the extension point that allows plugins to register new
+ * analysis error results to compute for a Dart source. The object used as an
+ * extension must be a [ResultDescriptor].
+ */
+final String DART_ERRORS_FOR_SOURCE_EXTENSION_POINT_ID = Plugin.join(
+    EnginePlugin.UNIQUE_IDENTIFIER,
+    EnginePlugin.DART_ERRORS_FOR_SOURCE_EXTENSION_POINT);
+
+/**
+ * The identifier of the extension point that allows plugins to register new
+ * analysis error results to compute for a Dart library specific unit. The
+ * object used as an extension must be a [ResultDescriptor].
+ */
+final String DART_ERRORS_FOR_UNIT_EXTENSION_POINT_ID = Plugin.join(
+    EnginePlugin.UNIQUE_IDENTIFIER,
+    EnginePlugin.DART_ERRORS_FOR_UNIT_EXTENSION_POINT);
+
+/**
+ * The identifier of the extension point that allows plugins to register new
+ * analysis error results to compute for an HTML source. The object used as an
+ * extension must be a [ResultDescriptor].
+ */
+final String HTML_ERRORS_EXTENSION_POINT_ID = Plugin.join(
+    EnginePlugin.UNIQUE_IDENTIFIER, EnginePlugin.HTML_ERRORS_EXTENSION_POINT);
+
+/**
+ * The identifier of the extension point that allows plugins to register new
  * analysis tasks with the analysis engine. The object used as an extension must
  * be a [TaskDescriptor].
  */
diff --git a/pkg/analyzer/lib/source/pub_package_map_provider.dart b/pkg/analyzer/lib/source/pub_package_map_provider.dart
index 3e9936d..07fdba7 100644
--- a/pkg/analyzer/lib/source/pub_package_map_provider.dart
+++ b/pkg/analyzer/lib/source/pub_package_map_provider.dart
@@ -162,8 +162,8 @@
     String workingDirectory = folder.path;
     int subprocessId = AnalysisEngine.instance.instrumentationService
         .logSubprocessStart(executablePath, arguments, workingDirectory);
-    io.ProcessResult result = io.Process.runSync(executablePath, arguments,
-        workingDirectory: workingDirectory);
+    io.ProcessResult result = io.Process
+        .runSync(executablePath, arguments, workingDirectory: workingDirectory);
     AnalysisEngine.instance.instrumentationService.logSubprocessResult(
         subprocessId, result.exitCode, result.stdout, result.stderr);
     return result;
diff --git a/pkg/analyzer/lib/source/sdk_ext.dart b/pkg/analyzer/lib/source/sdk_ext.dart
index d16bb47..646a19f 100644
--- a/pkg/analyzer/lib/source/sdk_ext.dart
+++ b/pkg/analyzer/lib/source/sdk_ext.dart
@@ -27,7 +27,7 @@
   static const String SDK_EXT_NAME = '_sdkext';
   static const String DART_COLON_PREFIX = 'dart:';
 
-  final Map<String, String> _urlMappings = <String,String>{};
+  final Map<String, String> _urlMappings = <String, String>{};
 
   /// Construct a [SdkExtUriResolver] from a package map
   /// (see [PackageMapProvider]).
@@ -42,7 +42,7 @@
   int get length => _urlMappings.length;
 
   /// Return the path mapping for [libName] or null if there is none.
-  String operator[](String libName) => _urlMappings[libName];
+  String operator [](String libName) => _urlMappings[libName];
 
   /// Programmatically add a new SDK extension given a JSON description
   /// ([sdkExtJSON]) and a lib directory ([libDir]).
diff --git a/pkg/analyzer/lib/src/cancelable_future.dart b/pkg/analyzer/lib/src/cancelable_future.dart
index 4ec7b26..733cac5 100644
--- a/pkg/analyzer/lib/src/cancelable_future.dart
+++ b/pkg/analyzer/lib/src/cancelable_future.dart
@@ -259,8 +259,8 @@
   Future timeout(Duration timeLimit, {onTimeout()}) {
     // TODO(paulberry): Implement this in such a way that a timeout cancels
     // the future.
-    return _completer._outerCompleter.future.timeout(timeLimit,
-        onTimeout: onTimeout);
+    return _completer._outerCompleter.future
+        .timeout(timeLimit, onTimeout: onTimeout);
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/context/cache.dart b/pkg/analyzer/lib/src/context/cache.dart
index d45c729..01ae4ea 100644
--- a/pkg/analyzer/lib/src/context/cache.dart
+++ b/pkg/analyzer/lib/src/context/cache.dart
@@ -38,8 +38,8 @@
   /**
    * The [StreamController] reporting [InvalidatedResult]s.
    */
-  final StreamController<InvalidatedResult> _onResultInvalidated =
-      new StreamController<InvalidatedResult>.broadcast(sync: true);
+  final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated =
+      new ReentrantSynchronousStream<InvalidatedResult>();
 
   /**
    * Initialize a newly created cache to have the given [partitions]. The
@@ -50,17 +50,11 @@
   AnalysisCache(this._partitions) {
     for (CachePartition partition in _partitions) {
       partition.onResultInvalidated.listen((InvalidatedResult event) {
-        _onResultInvalidated.add(event);
+        onResultInvalidated.add(event);
       });
     }
   }
 
-  /**
-   * Return the stream that is notified when a value is invalidated.
-   */
-  Stream<InvalidatedResult> get onResultInvalidated =>
-      _onResultInvalidated.stream;
-
   // TODO(brianwilkerson) Implement or delete this.
 //  /**
 //   * Return information about each of the partitions in this cache.
@@ -465,8 +459,11 @@
    * Set the value of the result represented by the given [descriptor] to the
    * given [value].
    */
-  /*<V>*/ void setValue(ResultDescriptor /*<V>*/ descriptor, dynamic /*V*/
-      value, List<TargetedResult> dependedOn) {
+  /*<V>*/ void setValue(
+      ResultDescriptor /*<V>*/ descriptor,
+      dynamic /*V*/
+      value,
+      List<TargetedResult> dependedOn) {
 //    {
 //      String valueStr = '$value';
 //      if (valueStr.length > 20) {
@@ -493,9 +490,9 @@
    */
   void setValueIncremental(ResultDescriptor descriptor, dynamic value) {
     ResultData data = getResultData(descriptor);
-    List<TargetedResult> dependedOn = data.dependedOnResults;
-    _invalidate(descriptor, null);
-    setValue(descriptor, value, dependedOn);
+    _invalidateDependentResults(data, null);
+    data.state = CacheState.VALID;
+    data.value = value;
   }
 
   @override
@@ -538,26 +535,20 @@
     TargetedResult thisResult = new TargetedResult(target, descriptor);
     for (TargetedResult dependedOnResult in thisData.dependedOnResults) {
       ResultData data = _partition._getDataFor(dependedOnResult);
-      if (data != null) {
+      if (data != null && deltaResult != DeltaResult.KEEP_CONTINUE) {
         data.dependentResults.remove(thisResult);
       }
     }
     // Invalidate results that depend on this result.
-    List<TargetedResult> dependentResults = thisData.dependentResults.toList();
-    for (TargetedResult dependentResult in dependentResults) {
-      CacheEntry entry = _partition.get(dependentResult.target);
-      if (entry != null) {
-        entry._invalidate(dependentResult.result, delta);
-      }
-    }
+    _invalidateDependentResults(thisData, delta);
     // If empty, remove the entry altogether.
     if (_resultMap.isEmpty) {
       _partition._targetMap.remove(target);
       _partition._removeIfSource(target);
     }
     // Notify controller.
-    _partition._onResultInvalidated
-        .add(new InvalidatedResult(this, descriptor));
+    _partition.onResultInvalidated
+        .add(new InvalidatedResult(this, descriptor, thisData.value));
   }
 
   /**
@@ -571,6 +562,19 @@
   }
 
   /**
+   * Invalidate results that depend on [thisData].
+   */
+  void _invalidateDependentResults(ResultData thisData, Delta delta) {
+    List<TargetedResult> dependentResults = thisData.dependentResults.toList();
+    for (TargetedResult dependentResult in dependentResults) {
+      CacheEntry entry = _partition.get(dependentResult.target);
+      if (entry != null) {
+        entry._invalidate(dependentResult.result, delta);
+      }
+    }
+  }
+
+  /**
    * Set the [dependedOn] on which this result depends.
    */
   void _setDependedOnResults(ResultData thisData, TargetedResult thisResult,
@@ -804,8 +808,8 @@
   /**
    * The [StreamController] reporting [InvalidatedResult]s.
    */
-  final StreamController<InvalidatedResult> _onResultInvalidated =
-      new StreamController<InvalidatedResult>.broadcast(sync: true);
+  final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated =
+      new ReentrantSynchronousStream<InvalidatedResult>();
 
   /**
    * A table mapping the targets belonging to this partition to the information
@@ -840,12 +844,6 @@
   Map<AnalysisTarget, CacheEntry> get map => _targetMap;
 
   /**
-   * Return the stream that is notified when a value is invalidated.
-   */
-  Stream<InvalidatedResult> get onResultInvalidated =>
-      _onResultInvalidated.stream;
-
-  /**
    * Notifies the partition that the client is going to stop using it.
    */
   void dispose() {
@@ -1039,13 +1037,47 @@
    */
   final ResultDescriptor descriptor;
 
-  InvalidatedResult(this.entry, this.descriptor);
+  /**
+   * The value of the result which was invalidated.
+   */
+  final Object value;
+
+  InvalidatedResult(this.entry, this.descriptor, this.value);
 
   @override
   String toString() => '$descriptor of ${entry.target}';
 }
 
 /**
+ * A Stream-like interface, which broadcasts events synchronously.
+ * If a second event is fired while delivering a first event, then the second
+ * event will be delivered first, and then delivering of the first will be
+ * continued.
+ */
+class ReentrantSynchronousStream<T> {
+  final List<Function> listeners = <Function>[];
+
+  /**
+   * Send the given [event] to the stream.
+   */
+  void add(T event) {
+    List<Function> listeners = this.listeners.toList();
+    for (Function listener in listeners) {
+      listener(event);
+    }
+  }
+
+  /**
+   * Listen for the events in this stream.
+   * Note that if the [listener] fires a new event, then the [listener] will be
+   * invoked again before returning from the [add] invocation.
+   */
+  void listen(void listener(T event)) {
+    listeners.add(listener);
+  }
+}
+
+/**
  * The data about a single analysis result that is stored in a [CacheEntry].
  */
 // TODO(brianwilkerson) Consider making this a generic class so that the value
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index d90b091..c6a81da 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -252,6 +252,7 @@
         (this._options.hint && !options.hint) ||
         (this._options.lint && !options.lint) ||
         this._options.preserveComments != options.preserveComments ||
+        this._options.strongMode != options.strongMode ||
         this._options.enableStrictCallChecks !=
             options.enableStrictCallChecks ||
         this._options.enableSuperMixins != options.enableSuperMixins;
@@ -272,6 +273,7 @@
     this._options.incrementalValidation = options.incrementalValidation;
     this._options.lint = options.lint;
     this._options.preserveComments = options.preserveComments;
+    this._options.strongMode = options.strongMode;
     if (needsRecompute) {
       for (WorkManager workManager in workManagers) {
         workManager.onAnalysisOptionsChanged();
diff --git a/pkg/analyzer/lib/src/generated/ast.dart b/pkg/analyzer/lib/src/generated/ast.dart
index 0c5dfc2..6d47cf7 100644
--- a/pkg/analyzer/lib/src/generated/ast.dart
+++ b/pkg/analyzer/lib/src/generated/ast.dart
@@ -963,7 +963,8 @@
    * cloning AST nodes if [cloneTokens] is `true`.
    */
   AstCloner(
-      [this.cloneTokens = false]); // TODO(brianwilkerson) Change this to be a named parameter.
+      [this.cloneTokens =
+          false]); // TODO(brianwilkerson) Change this to be a named parameter.
 
   /**
    * Return a clone of the given [node].
@@ -1015,23 +1016,30 @@
 
   @override
   Annotation visitAnnotation(Annotation node) => new Annotation(
-      cloneToken(node.atSign), cloneNode(node.name), cloneToken(node.period),
-      cloneNode(node.constructorName), cloneNode(node.arguments));
+      cloneToken(node.atSign),
+      cloneNode(node.name),
+      cloneToken(node.period),
+      cloneNode(node.constructorName),
+      cloneNode(node.arguments));
 
   @override
   ArgumentList visitArgumentList(ArgumentList node) => new ArgumentList(
-      cloneToken(node.leftParenthesis), cloneNodeList(node.arguments),
+      cloneToken(node.leftParenthesis),
+      cloneNodeList(node.arguments),
       cloneToken(node.rightParenthesis));
 
   @override
   AsExpression visitAsExpression(AsExpression node) => new AsExpression(
-      cloneNode(node.expression), cloneToken(node.asOperator),
+      cloneNode(node.expression),
+      cloneToken(node.asOperator),
       cloneNode(node.type));
 
   @override
   AstNode visitAssertStatement(AssertStatement node) => new AssertStatement(
-      cloneToken(node.assertKeyword), cloneToken(node.leftParenthesis),
-      cloneNode(node.condition), cloneToken(node.rightParenthesis),
+      cloneToken(node.assertKeyword),
+      cloneToken(node.leftParenthesis),
+      cloneNode(node.condition),
+      cloneToken(node.rightParenthesis),
       cloneToken(node.semicolon));
 
   @override
@@ -1054,9 +1062,9 @@
       cloneNodeList(node.statements), cloneToken(node.rightBracket));
 
   @override
-  BlockFunctionBody visitBlockFunctionBody(
-      BlockFunctionBody node) => new BlockFunctionBody(
-      cloneToken(node.keyword), cloneToken(node.star), cloneNode(node.block));
+  BlockFunctionBody visitBlockFunctionBody(BlockFunctionBody node) =>
+      new BlockFunctionBody(cloneToken(node.keyword), cloneToken(node.star),
+          cloneNode(node.block));
 
   @override
   BooleanLiteral visitBooleanLiteral(BooleanLiteral node) =>
@@ -1064,7 +1072,8 @@
 
   @override
   BreakStatement visitBreakStatement(BreakStatement node) => new BreakStatement(
-      cloneToken(node.breakKeyword), cloneNode(node.label),
+      cloneToken(node.breakKeyword),
+      cloneNode(node.label),
       cloneToken(node.semicolon));
 
   @override
@@ -1074,32 +1083,47 @@
 
   @override
   CatchClause visitCatchClause(CatchClause node) => new CatchClause(
-      cloneToken(node.onKeyword), cloneNode(node.exceptionType),
-      cloneToken(node.catchKeyword), cloneToken(node.leftParenthesis),
-      cloneNode(node.exceptionParameter), cloneToken(node.comma),
-      cloneNode(node.stackTraceParameter), cloneToken(node.rightParenthesis),
+      cloneToken(node.onKeyword),
+      cloneNode(node.exceptionType),
+      cloneToken(node.catchKeyword),
+      cloneToken(node.leftParenthesis),
+      cloneNode(node.exceptionParameter),
+      cloneToken(node.comma),
+      cloneNode(node.stackTraceParameter),
+      cloneToken(node.rightParenthesis),
       cloneNode(node.body));
 
   @override
   ClassDeclaration visitClassDeclaration(ClassDeclaration node) {
     ClassDeclaration copy = new ClassDeclaration(
-        cloneNode(node.documentationComment), cloneNodeList(node.metadata),
-        cloneToken(node.abstractKeyword), cloneToken(node.classKeyword),
-        cloneNode(node.name), cloneNode(node.typeParameters),
-        cloneNode(node.extendsClause), cloneNode(node.withClause),
-        cloneNode(node.implementsClause), cloneToken(node.leftBracket),
-        cloneNodeList(node.members), cloneToken(node.rightBracket));
+        cloneNode(node.documentationComment),
+        cloneNodeList(node.metadata),
+        cloneToken(node.abstractKeyword),
+        cloneToken(node.classKeyword),
+        cloneNode(node.name),
+        cloneNode(node.typeParameters),
+        cloneNode(node.extendsClause),
+        cloneNode(node.withClause),
+        cloneNode(node.implementsClause),
+        cloneToken(node.leftBracket),
+        cloneNodeList(node.members),
+        cloneToken(node.rightBracket));
     copy.nativeClause = cloneNode(node.nativeClause);
     return copy;
   }
 
   @override
   ClassTypeAlias visitClassTypeAlias(ClassTypeAlias node) => new ClassTypeAlias(
-      cloneNode(node.documentationComment), cloneNodeList(node.metadata),
-      cloneToken(node.typedefKeyword), cloneNode(node.name),
-      cloneNode(node.typeParameters), cloneToken(node.equals),
-      cloneToken(node.abstractKeyword), cloneNode(node.superclass),
-      cloneNode(node.withClause), cloneNode(node.implementsClause),
+      cloneNode(node.documentationComment),
+      cloneNodeList(node.metadata),
+      cloneToken(node.typedefKeyword),
+      cloneNode(node.name),
+      cloneNode(node.typeParameters),
+      cloneToken(node.equals),
+      cloneToken(node.abstractKeyword),
+      cloneNode(node.superclass),
+      cloneNode(node.withClause),
+      cloneNode(node.implementsClause),
       cloneToken(node.semicolon));
 
   @override
@@ -1120,36 +1144,53 @@
 
   @override
   CompilationUnit visitCompilationUnit(CompilationUnit node) {
-    CompilationUnit clone = new CompilationUnit(cloneToken(node.beginToken),
-        cloneNode(node.scriptTag), cloneNodeList(node.directives),
-        cloneNodeList(node.declarations), cloneToken(node.endToken));
+    CompilationUnit clone = new CompilationUnit(
+        cloneToken(node.beginToken),
+        cloneNode(node.scriptTag),
+        cloneNodeList(node.directives),
+        cloneNodeList(node.declarations),
+        cloneToken(node.endToken));
     clone.lineInfo = node.lineInfo;
     return clone;
   }
 
   @override
   ConditionalExpression visitConditionalExpression(
-      ConditionalExpression node) => new ConditionalExpression(
-      cloneNode(node.condition), cloneToken(node.question),
-      cloneNode(node.thenExpression), cloneToken(node.colon),
-      cloneNode(node.elseExpression));
+          ConditionalExpression node) =>
+      new ConditionalExpression(
+          cloneNode(node.condition),
+          cloneToken(node.question),
+          cloneNode(node.thenExpression),
+          cloneToken(node.colon),
+          cloneNode(node.elseExpression));
 
   @override
   ConstructorDeclaration visitConstructorDeclaration(
-      ConstructorDeclaration node) => new ConstructorDeclaration(
-      cloneNode(node.documentationComment), cloneNodeList(node.metadata),
-      cloneToken(node.externalKeyword), cloneToken(node.constKeyword),
-      cloneToken(node.factoryKeyword), cloneNode(node.returnType),
-      cloneToken(node.period), cloneNode(node.name), cloneNode(node.parameters),
-      cloneToken(node.separator), cloneNodeList(node.initializers),
-      cloneNode(node.redirectedConstructor), cloneNode(node.body));
+          ConstructorDeclaration node) =>
+      new ConstructorDeclaration(
+          cloneNode(node.documentationComment),
+          cloneNodeList(node.metadata),
+          cloneToken(node.externalKeyword),
+          cloneToken(node.constKeyword),
+          cloneToken(node.factoryKeyword),
+          cloneNode(node.returnType),
+          cloneToken(node.period),
+          cloneNode(node.name),
+          cloneNode(node.parameters),
+          cloneToken(node.separator),
+          cloneNodeList(node.initializers),
+          cloneNode(node.redirectedConstructor),
+          cloneNode(node.body));
 
   @override
   ConstructorFieldInitializer visitConstructorFieldInitializer(
-      ConstructorFieldInitializer node) => new ConstructorFieldInitializer(
-      cloneToken(node.thisKeyword), cloneToken(node.period),
-      cloneNode(node.fieldName), cloneToken(node.equals),
-      cloneNode(node.expression));
+          ConstructorFieldInitializer node) =>
+      new ConstructorFieldInitializer(
+          cloneToken(node.thisKeyword),
+          cloneToken(node.period),
+          cloneNode(node.fieldName),
+          cloneToken(node.equals),
+          cloneNode(node.expression));
 
   @override
   ConstructorName visitConstructorName(ConstructorName node) =>
@@ -1163,21 +1204,27 @@
 
   @override
   DeclaredIdentifier visitDeclaredIdentifier(DeclaredIdentifier node) =>
-      new DeclaredIdentifier(cloneNode(node.documentationComment),
-          cloneNodeList(node.metadata), cloneToken(node.keyword),
-          cloneNode(node.type), cloneNode(node.identifier));
+      new DeclaredIdentifier(
+          cloneNode(node.documentationComment),
+          cloneNodeList(node.metadata),
+          cloneToken(node.keyword),
+          cloneNode(node.type),
+          cloneNode(node.identifier));
 
   @override
   DefaultFormalParameter visitDefaultFormalParameter(
-      DefaultFormalParameter node) => new DefaultFormalParameter(
-      cloneNode(node.parameter), node.kind, cloneToken(node.separator),
-      cloneNode(node.defaultValue));
+          DefaultFormalParameter node) =>
+      new DefaultFormalParameter(cloneNode(node.parameter), node.kind,
+          cloneToken(node.separator), cloneNode(node.defaultValue));
 
   @override
   DoStatement visitDoStatement(DoStatement node) => new DoStatement(
-      cloneToken(node.doKeyword), cloneNode(node.body),
-      cloneToken(node.whileKeyword), cloneToken(node.leftParenthesis),
-      cloneNode(node.condition), cloneToken(node.rightParenthesis),
+      cloneToken(node.doKeyword),
+      cloneNode(node.body),
+      cloneToken(node.whileKeyword),
+      cloneToken(node.leftParenthesis),
+      cloneNode(node.condition),
+      cloneToken(node.rightParenthesis),
       cloneToken(node.semicolon));
 
   @override
@@ -1199,17 +1246,24 @@
 
   @override
   EnumDeclaration visitEnumDeclaration(EnumDeclaration node) =>
-      new EnumDeclaration(cloneNode(node.documentationComment),
-          cloneNodeList(node.metadata), cloneToken(node.enumKeyword),
-          cloneNode(node.name), cloneToken(node.leftBracket),
-          cloneNodeList(node.constants), cloneToken(node.rightBracket));
+      new EnumDeclaration(
+          cloneNode(node.documentationComment),
+          cloneNodeList(node.metadata),
+          cloneToken(node.enumKeyword),
+          cloneNode(node.name),
+          cloneToken(node.leftBracket),
+          cloneNodeList(node.constants),
+          cloneToken(node.rightBracket));
 
   @override
   ExportDirective visitExportDirective(ExportDirective node) {
     ExportDirective directive = new ExportDirective(
-        cloneNode(node.documentationComment), cloneNodeList(node.metadata),
-        cloneToken(node.keyword), cloneNode(node.uri),
-        cloneNodeList(node.combinators), cloneToken(node.semicolon));
+        cloneNode(node.documentationComment),
+        cloneNodeList(node.metadata),
+        cloneToken(node.keyword),
+        cloneNode(node.uri),
+        cloneNodeList(node.combinators),
+        cloneToken(node.semicolon));
     directive.source = node.source;
     directive.uriContent = node.uriContent;
     return directive;
@@ -1217,9 +1271,12 @@
 
   @override
   ExpressionFunctionBody visitExpressionFunctionBody(
-      ExpressionFunctionBody node) => new ExpressionFunctionBody(
-      cloneToken(node.keyword), cloneToken(node.functionDefinition),
-      cloneNode(node.expression), cloneToken(node.semicolon));
+          ExpressionFunctionBody node) =>
+      new ExpressionFunctionBody(
+          cloneToken(node.keyword),
+          cloneToken(node.functionDefinition),
+          cloneNode(node.expression),
+          cloneToken(node.semicolon));
 
   @override
   ExpressionStatement visitExpressionStatement(ExpressionStatement node) =>
@@ -1232,55 +1289,83 @@
 
   @override
   FieldDeclaration visitFieldDeclaration(FieldDeclaration node) =>
-      new FieldDeclaration(cloneNode(node.documentationComment),
-          cloneNodeList(node.metadata), cloneToken(node.staticKeyword),
-          cloneNode(node.fields), cloneToken(node.semicolon));
+      new FieldDeclaration(
+          cloneNode(node.documentationComment),
+          cloneNodeList(node.metadata),
+          cloneToken(node.staticKeyword),
+          cloneNode(node.fields),
+          cloneToken(node.semicolon));
 
   @override
   FieldFormalParameter visitFieldFormalParameter(FieldFormalParameter node) =>
-      new FieldFormalParameter(cloneNode(node.documentationComment),
-          cloneNodeList(node.metadata), cloneToken(node.keyword),
-          cloneNode(node.type), cloneToken(node.thisKeyword),
-          cloneToken(node.period), cloneNode(node.identifier),
-          cloneNode(node.typeParameters), cloneNode(node.parameters));
+      new FieldFormalParameter(
+          cloneNode(node.documentationComment),
+          cloneNodeList(node.metadata),
+          cloneToken(node.keyword),
+          cloneNode(node.type),
+          cloneToken(node.thisKeyword),
+          cloneToken(node.period),
+          cloneNode(node.identifier),
+          cloneNode(node.typeParameters),
+          cloneNode(node.parameters));
 
   @override
   ForEachStatement visitForEachStatement(ForEachStatement node) {
     DeclaredIdentifier loopVariable = node.loopVariable;
     if (loopVariable == null) {
-      return new ForEachStatement.withReference(cloneToken(node.awaitKeyword),
-          cloneToken(node.forKeyword), cloneToken(node.leftParenthesis),
-          cloneNode(node.identifier), cloneToken(node.inKeyword),
-          cloneNode(node.iterable), cloneToken(node.rightParenthesis),
+      return new ForEachStatement.withReference(
+          cloneToken(node.awaitKeyword),
+          cloneToken(node.forKeyword),
+          cloneToken(node.leftParenthesis),
+          cloneNode(node.identifier),
+          cloneToken(node.inKeyword),
+          cloneNode(node.iterable),
+          cloneToken(node.rightParenthesis),
           cloneNode(node.body));
     }
-    return new ForEachStatement.withDeclaration(cloneToken(node.awaitKeyword),
-        cloneToken(node.forKeyword), cloneToken(node.leftParenthesis),
-        cloneNode(loopVariable), cloneToken(node.inKeyword),
-        cloneNode(node.iterable), cloneToken(node.rightParenthesis),
+    return new ForEachStatement.withDeclaration(
+        cloneToken(node.awaitKeyword),
+        cloneToken(node.forKeyword),
+        cloneToken(node.leftParenthesis),
+        cloneNode(loopVariable),
+        cloneToken(node.inKeyword),
+        cloneNode(node.iterable),
+        cloneToken(node.rightParenthesis),
         cloneNode(node.body));
   }
 
   @override
   FormalParameterList visitFormalParameterList(FormalParameterList node) =>
-      new FormalParameterList(cloneToken(node.leftParenthesis),
-          cloneNodeList(node.parameters), cloneToken(node.leftDelimiter),
-          cloneToken(node.rightDelimiter), cloneToken(node.rightParenthesis));
+      new FormalParameterList(
+          cloneToken(node.leftParenthesis),
+          cloneNodeList(node.parameters),
+          cloneToken(node.leftDelimiter),
+          cloneToken(node.rightDelimiter),
+          cloneToken(node.rightParenthesis));
 
   @override
   ForStatement visitForStatement(ForStatement node) => new ForStatement(
-      cloneToken(node.forKeyword), cloneToken(node.leftParenthesis),
-      cloneNode(node.variables), cloneNode(node.initialization),
-      cloneToken(node.leftSeparator), cloneNode(node.condition),
-      cloneToken(node.rightSeparator), cloneNodeList(node.updaters),
-      cloneToken(node.rightParenthesis), cloneNode(node.body));
+      cloneToken(node.forKeyword),
+      cloneToken(node.leftParenthesis),
+      cloneNode(node.variables),
+      cloneNode(node.initialization),
+      cloneToken(node.leftSeparator),
+      cloneNode(node.condition),
+      cloneToken(node.rightSeparator),
+      cloneNodeList(node.updaters),
+      cloneToken(node.rightParenthesis),
+      cloneNode(node.body));
 
   @override
   FunctionDeclaration visitFunctionDeclaration(FunctionDeclaration node) =>
-      new FunctionDeclaration(cloneNode(node.documentationComment),
-          cloneNodeList(node.metadata), cloneToken(node.externalKeyword),
-          cloneNode(node.returnType), cloneToken(node.propertyKeyword),
-          cloneNode(node.name), cloneNode(node.functionExpression));
+      new FunctionDeclaration(
+          cloneNode(node.documentationComment),
+          cloneNodeList(node.metadata),
+          cloneToken(node.externalKeyword),
+          cloneNode(node.returnType),
+          cloneToken(node.propertyKeyword),
+          cloneNode(node.name),
+          cloneNode(node.functionExpression));
 
   @override
   FunctionDeclarationStatement visitFunctionDeclarationStatement(
@@ -1294,24 +1379,32 @@
 
   @override
   FunctionExpressionInvocation visitFunctionExpressionInvocation(
-      FunctionExpressionInvocation node) => new FunctionExpressionInvocation(
-      cloneNode(node.function), cloneNode(node.typeArguments),
-      cloneNode(node.argumentList));
+          FunctionExpressionInvocation node) =>
+      new FunctionExpressionInvocation(cloneNode(node.function),
+          cloneNode(node.typeArguments), cloneNode(node.argumentList));
 
   @override
   FunctionTypeAlias visitFunctionTypeAlias(FunctionTypeAlias node) =>
-      new FunctionTypeAlias(cloneNode(node.documentationComment),
-          cloneNodeList(node.metadata), cloneToken(node.typedefKeyword),
-          cloneNode(node.returnType), cloneNode(node.name),
-          cloneNode(node.typeParameters), cloneNode(node.parameters),
+      new FunctionTypeAlias(
+          cloneNode(node.documentationComment),
+          cloneNodeList(node.metadata),
+          cloneToken(node.typedefKeyword),
+          cloneNode(node.returnType),
+          cloneNode(node.name),
+          cloneNode(node.typeParameters),
+          cloneNode(node.parameters),
           cloneToken(node.semicolon));
 
   @override
   FunctionTypedFormalParameter visitFunctionTypedFormalParameter(
-      FunctionTypedFormalParameter node) => new FunctionTypedFormalParameter(
-      cloneNode(node.documentationComment), cloneNodeList(node.metadata),
-      cloneNode(node.returnType), cloneNode(node.identifier),
-      cloneNode(node.typeParameters), cloneNode(node.parameters));
+          FunctionTypedFormalParameter node) =>
+      new FunctionTypedFormalParameter(
+          cloneNode(node.documentationComment),
+          cloneNodeList(node.metadata),
+          cloneNode(node.returnType),
+          cloneNode(node.identifier),
+          cloneNode(node.typeParameters),
+          cloneNode(node.parameters));
 
   @override
   HideCombinator visitHideCombinator(HideCombinator node) => new HideCombinator(
@@ -1319,9 +1412,12 @@
 
   @override
   IfStatement visitIfStatement(IfStatement node) => new IfStatement(
-      cloneToken(node.ifKeyword), cloneToken(node.leftParenthesis),
-      cloneNode(node.condition), cloneToken(node.rightParenthesis),
-      cloneNode(node.thenStatement), cloneToken(node.elseKeyword),
+      cloneToken(node.ifKeyword),
+      cloneToken(node.leftParenthesis),
+      cloneNode(node.condition),
+      cloneToken(node.rightParenthesis),
+      cloneNode(node.thenStatement),
+      cloneToken(node.elseKeyword),
       cloneNode(node.elseStatement));
 
   @override
@@ -1332,10 +1428,14 @@
   @override
   ImportDirective visitImportDirective(ImportDirective node) {
     ImportDirective directive = new ImportDirective(
-        cloneNode(node.documentationComment), cloneNodeList(node.metadata),
-        cloneToken(node.keyword), cloneNode(node.uri),
-        cloneToken(node.deferredKeyword), cloneToken(node.asKeyword),
-        cloneNode(node.prefix), cloneNodeList(node.combinators),
+        cloneNode(node.documentationComment),
+        cloneNodeList(node.metadata),
+        cloneToken(node.keyword),
+        cloneNode(node.uri),
+        cloneToken(node.deferredKeyword),
+        cloneToken(node.asKeyword),
+        cloneNode(node.prefix),
+        cloneNodeList(node.combinators),
         cloneToken(node.semicolon));
     directive.source = node.source;
     directive.uriContent = node.uriContent;
@@ -1346,21 +1446,25 @@
   IndexExpression visitIndexExpression(IndexExpression node) {
     Token period = node.period;
     if (period == null) {
-      return new IndexExpression.forTarget(cloneNode(node.target),
-          cloneToken(node.leftBracket), cloneNode(node.index),
+      return new IndexExpression.forTarget(
+          cloneNode(node.target),
+          cloneToken(node.leftBracket),
+          cloneNode(node.index),
           cloneToken(node.rightBracket));
     } else {
-      return new IndexExpression.forCascade(cloneToken(period),
-          cloneToken(node.leftBracket), cloneNode(node.index),
+      return new IndexExpression.forCascade(
+          cloneToken(period),
+          cloneToken(node.leftBracket),
+          cloneNode(node.index),
           cloneToken(node.rightBracket));
     }
   }
 
   @override
   InstanceCreationExpression visitInstanceCreationExpression(
-      InstanceCreationExpression node) => new InstanceCreationExpression(
-      cloneToken(node.keyword), cloneNode(node.constructorName),
-      cloneNode(node.argumentList));
+          InstanceCreationExpression node) =>
+      new InstanceCreationExpression(cloneToken(node.keyword),
+          cloneNode(node.constructorName), cloneNode(node.argumentList));
 
   @override
   IntegerLiteral visitIntegerLiteral(IntegerLiteral node) =>
@@ -1368,9 +1472,9 @@
 
   @override
   InterpolationExpression visitInterpolationExpression(
-      InterpolationExpression node) => new InterpolationExpression(
-      cloneToken(node.leftBracket), cloneNode(node.expression),
-      cloneToken(node.rightBracket));
+          InterpolationExpression node) =>
+      new InterpolationExpression(cloneToken(node.leftBracket),
+          cloneNode(node.expression), cloneToken(node.rightBracket));
 
   @override
   InterpolationString visitInterpolationString(InterpolationString node) =>
@@ -1378,8 +1482,10 @@
 
   @override
   IsExpression visitIsExpression(IsExpression node) => new IsExpression(
-      cloneNode(node.expression), cloneToken(node.isOperator),
-      cloneToken(node.notOperator), cloneNode(node.type));
+      cloneNode(node.expression),
+      cloneToken(node.isOperator),
+      cloneToken(node.notOperator),
+      cloneNode(node.type));
 
   @override
   Label visitLabel(Label node) =>
@@ -1392,9 +1498,12 @@
 
   @override
   LibraryDirective visitLibraryDirective(LibraryDirective node) =>
-      new LibraryDirective(cloneNode(node.documentationComment),
-          cloneNodeList(node.metadata), cloneToken(node.libraryKeyword),
-          cloneNode(node.name), cloneToken(node.semicolon));
+      new LibraryDirective(
+          cloneNode(node.documentationComment),
+          cloneNodeList(node.metadata),
+          cloneToken(node.libraryKeyword),
+          cloneNode(node.name),
+          cloneToken(node.semicolon));
 
   @override
   LibraryIdentifier visitLibraryIdentifier(LibraryIdentifier node) =>
@@ -1402,34 +1511,47 @@
 
   @override
   ListLiteral visitListLiteral(ListLiteral node) => new ListLiteral(
-      cloneToken(node.constKeyword), cloneNode(node.typeArguments),
-      cloneToken(node.leftBracket), cloneNodeList(node.elements),
+      cloneToken(node.constKeyword),
+      cloneNode(node.typeArguments),
+      cloneToken(node.leftBracket),
+      cloneNodeList(node.elements),
       cloneToken(node.rightBracket));
 
   @override
   MapLiteral visitMapLiteral(MapLiteral node) => new MapLiteral(
-      cloneToken(node.constKeyword), cloneNode(node.typeArguments),
-      cloneToken(node.leftBracket), cloneNodeList(node.entries),
+      cloneToken(node.constKeyword),
+      cloneNode(node.typeArguments),
+      cloneToken(node.leftBracket),
+      cloneNodeList(node.entries),
       cloneToken(node.rightBracket));
 
   @override
-  MapLiteralEntry visitMapLiteralEntry(
-      MapLiteralEntry node) => new MapLiteralEntry(
-      cloneNode(node.key), cloneToken(node.separator), cloneNode(node.value));
+  MapLiteralEntry visitMapLiteralEntry(MapLiteralEntry node) =>
+      new MapLiteralEntry(cloneNode(node.key), cloneToken(node.separator),
+          cloneNode(node.value));
 
   @override
   MethodDeclaration visitMethodDeclaration(MethodDeclaration node) =>
-      new MethodDeclaration(cloneNode(node.documentationComment),
-          cloneNodeList(node.metadata), cloneToken(node.externalKeyword),
-          cloneToken(node.modifierKeyword), cloneNode(node.returnType),
-          cloneToken(node.propertyKeyword), cloneToken(node.operatorKeyword),
-          cloneNode(node.name), cloneNode(node.typeParameters),
-          cloneNode(node.parameters), cloneNode(node.body));
+      new MethodDeclaration(
+          cloneNode(node.documentationComment),
+          cloneNodeList(node.metadata),
+          cloneToken(node.externalKeyword),
+          cloneToken(node.modifierKeyword),
+          cloneNode(node.returnType),
+          cloneToken(node.propertyKeyword),
+          cloneToken(node.operatorKeyword),
+          cloneNode(node.name),
+          cloneNode(node.typeParameters),
+          cloneNode(node.parameters),
+          cloneNode(node.body));
 
   @override
   MethodInvocation visitMethodInvocation(MethodInvocation node) =>
-      new MethodInvocation(cloneNode(node.target), cloneToken(node.operator),
-          cloneNode(node.methodName), cloneNode(node.typeArguments),
+      new MethodInvocation(
+          cloneNode(node.target),
+          cloneToken(node.operator),
+          cloneNode(node.methodName),
+          cloneNode(node.typeArguments),
           cloneNode(node.argumentList));
 
   @override
@@ -1451,15 +1573,17 @@
 
   @override
   ParenthesizedExpression visitParenthesizedExpression(
-      ParenthesizedExpression node) => new ParenthesizedExpression(
-      cloneToken(node.leftParenthesis), cloneNode(node.expression),
-      cloneToken(node.rightParenthesis));
+          ParenthesizedExpression node) =>
+      new ParenthesizedExpression(cloneToken(node.leftParenthesis),
+          cloneNode(node.expression), cloneToken(node.rightParenthesis));
 
   @override
   PartDirective visitPartDirective(PartDirective node) {
     PartDirective directive = new PartDirective(
-        cloneNode(node.documentationComment), cloneNodeList(node.metadata),
-        cloneToken(node.partKeyword), cloneNode(node.uri),
+        cloneNode(node.documentationComment),
+        cloneNodeList(node.metadata),
+        cloneToken(node.partKeyword),
+        cloneNode(node.uri),
         cloneToken(node.semicolon));
     directive.source = node.source;
     directive.uriContent = node.uriContent;
@@ -1468,9 +1592,12 @@
 
   @override
   PartOfDirective visitPartOfDirective(PartOfDirective node) =>
-      new PartOfDirective(cloneNode(node.documentationComment),
-          cloneNodeList(node.metadata), cloneToken(node.partKeyword),
-          cloneToken(node.ofKeyword), cloneNode(node.libraryName),
+      new PartOfDirective(
+          cloneNode(node.documentationComment),
+          cloneNodeList(node.metadata),
+          cloneToken(node.partKeyword),
+          cloneToken(node.ofKeyword),
+          cloneNode(node.libraryName),
           cloneToken(node.semicolon));
 
   @override
@@ -1488,14 +1615,17 @@
 
   @override
   PropertyAccess visitPropertyAccess(PropertyAccess node) => new PropertyAccess(
-      cloneNode(node.target), cloneToken(node.operator),
+      cloneNode(node.target),
+      cloneToken(node.operator),
       cloneNode(node.propertyName));
 
   @override
   RedirectingConstructorInvocation visitRedirectingConstructorInvocation(
           RedirectingConstructorInvocation node) =>
-      new RedirectingConstructorInvocation(cloneToken(node.thisKeyword),
-          cloneToken(node.period), cloneNode(node.constructorName),
+      new RedirectingConstructorInvocation(
+          cloneToken(node.thisKeyword),
+          cloneToken(node.period),
+          cloneNode(node.constructorName),
           cloneNode(node.argumentList));
 
   @override
@@ -1517,10 +1647,13 @@
 
   @override
   SimpleFormalParameter visitSimpleFormalParameter(
-      SimpleFormalParameter node) => new SimpleFormalParameter(
-      cloneNode(node.documentationComment), cloneNodeList(node.metadata),
-      cloneToken(node.keyword), cloneNode(node.type),
-      cloneNode(node.identifier));
+          SimpleFormalParameter node) =>
+      new SimpleFormalParameter(
+          cloneNode(node.documentationComment),
+          cloneNodeList(node.metadata),
+          cloneToken(node.keyword),
+          cloneNode(node.type),
+          cloneNode(node.identifier));
 
   @override
   SimpleIdentifier visitSimpleIdentifier(SimpleIdentifier node) =>
@@ -1536,9 +1669,12 @@
 
   @override
   SuperConstructorInvocation visitSuperConstructorInvocation(
-      SuperConstructorInvocation node) => new SuperConstructorInvocation(
-      cloneToken(node.superKeyword), cloneToken(node.period),
-      cloneNode(node.constructorName), cloneNode(node.argumentList));
+          SuperConstructorInvocation node) =>
+      new SuperConstructorInvocation(
+          cloneToken(node.superKeyword),
+          cloneToken(node.period),
+          cloneNode(node.constructorName),
+          cloneNode(node.argumentList));
 
   @override
   SuperExpression visitSuperExpression(SuperExpression node) =>
@@ -1546,21 +1682,29 @@
 
   @override
   SwitchCase visitSwitchCase(SwitchCase node) => new SwitchCase(
-      cloneNodeList(node.labels), cloneToken(node.keyword),
-      cloneNode(node.expression), cloneToken(node.colon),
+      cloneNodeList(node.labels),
+      cloneToken(node.keyword),
+      cloneNode(node.expression),
+      cloneToken(node.colon),
       cloneNodeList(node.statements));
 
   @override
   SwitchDefault visitSwitchDefault(SwitchDefault node) => new SwitchDefault(
-      cloneNodeList(node.labels), cloneToken(node.keyword),
-      cloneToken(node.colon), cloneNodeList(node.statements));
+      cloneNodeList(node.labels),
+      cloneToken(node.keyword),
+      cloneToken(node.colon),
+      cloneNodeList(node.statements));
 
   @override
   SwitchStatement visitSwitchStatement(SwitchStatement node) =>
-      new SwitchStatement(cloneToken(node.switchKeyword),
-          cloneToken(node.leftParenthesis), cloneNode(node.expression),
-          cloneToken(node.rightParenthesis), cloneToken(node.leftBracket),
-          cloneNodeList(node.members), cloneToken(node.rightBracket));
+      new SwitchStatement(
+          cloneToken(node.switchKeyword),
+          cloneToken(node.leftParenthesis),
+          cloneNode(node.expression),
+          cloneToken(node.rightParenthesis),
+          cloneToken(node.leftBracket),
+          cloneNodeList(node.members),
+          cloneToken(node.rightBracket));
 
   @override
   SymbolLiteral visitSymbolLiteral(SymbolLiteral node) => new SymbolLiteral(
@@ -1577,14 +1721,19 @@
 
   @override
   TopLevelVariableDeclaration visitTopLevelVariableDeclaration(
-      TopLevelVariableDeclaration node) => new TopLevelVariableDeclaration(
-      cloneNode(node.documentationComment), cloneNodeList(node.metadata),
-      cloneNode(node.variables), cloneToken(node.semicolon));
+          TopLevelVariableDeclaration node) =>
+      new TopLevelVariableDeclaration(
+          cloneNode(node.documentationComment),
+          cloneNodeList(node.metadata),
+          cloneNode(node.variables),
+          cloneToken(node.semicolon));
 
   @override
   TryStatement visitTryStatement(TryStatement node) => new TryStatement(
-      cloneToken(node.tryKeyword), cloneNode(node.body),
-      cloneNodeList(node.catchClauses), cloneToken(node.finallyKeyword),
+      cloneToken(node.tryKeyword),
+      cloneNode(node.body),
+      cloneNodeList(node.catchClauses),
+      cloneToken(node.finallyKeyword),
       cloneNode(node.finallyBlock));
 
   @override
@@ -1598,8 +1747,10 @@
 
   @override
   TypeParameter visitTypeParameter(TypeParameter node) => new TypeParameter(
-      cloneNode(node.documentationComment), cloneNodeList(node.metadata),
-      cloneNode(node.name), cloneToken(node.extendsKeyword),
+      cloneNode(node.documentationComment),
+      cloneNodeList(node.metadata),
+      cloneNode(node.name),
+      cloneToken(node.extendsKeyword),
       cloneNode(node.bound));
 
   @override
@@ -1614,20 +1765,26 @@
 
   @override
   VariableDeclarationList visitVariableDeclarationList(
-      VariableDeclarationList node) => new VariableDeclarationList(
-      cloneNode(node.documentationComment), cloneNodeList(node.metadata),
-      cloneToken(node.keyword), cloneNode(node.type),
-      cloneNodeList(node.variables));
+          VariableDeclarationList node) =>
+      new VariableDeclarationList(
+          cloneNode(node.documentationComment),
+          cloneNodeList(node.metadata),
+          cloneToken(node.keyword),
+          cloneNode(node.type),
+          cloneNodeList(node.variables));
 
   @override
   VariableDeclarationStatement visitVariableDeclarationStatement(
-      VariableDeclarationStatement node) => new VariableDeclarationStatement(
-      cloneNode(node.variables), cloneToken(node.semicolon));
+          VariableDeclarationStatement node) =>
+      new VariableDeclarationStatement(
+          cloneNode(node.variables), cloneToken(node.semicolon));
 
   @override
   WhileStatement visitWhileStatement(WhileStatement node) => new WhileStatement(
-      cloneToken(node.whileKeyword), cloneToken(node.leftParenthesis),
-      cloneNode(node.condition), cloneToken(node.rightParenthesis),
+      cloneToken(node.whileKeyword),
+      cloneToken(node.leftParenthesis),
+      cloneNode(node.condition),
+      cloneToken(node.rightParenthesis),
       cloneNode(node.body));
 
   @override
@@ -1636,8 +1793,10 @@
 
   @override
   YieldStatement visitYieldStatement(YieldStatement node) => new YieldStatement(
-      cloneToken(node.yieldKeyword), cloneToken(node.star),
-      cloneNode(node.expression), cloneToken(node.semicolon));
+      cloneToken(node.yieldKeyword),
+      cloneToken(node.star),
+      cloneNode(node.expression),
+      cloneToken(node.semicolon));
 
   /**
    * Return a clone of the given [node].
@@ -2726,8 +2885,8 @@
    * the same offset, and a positive value if the offset of the first node is
    * greater than the offset of the second node.
    */
-  static Comparator<AstNode> LEXICAL_ORDER =
-      (AstNode first, AstNode second) => first.offset - second.offset;
+  static Comparator<AstNode> LEXICAL_ORDER = (AstNode first, AstNode second) =>
+      first.offset - second.offset;
 
   /**
    * The parent of the node, or `null` if the node is the root of an AST
@@ -3851,9 +4010,16 @@
    * [comma] and [stackTraceParameter] can be `null` if the stack trace is not
    * referencable within the body.
    */
-  CatchClause(this.onKeyword, TypeName exceptionType, this.catchKeyword,
-      this.leftParenthesis, SimpleIdentifier exceptionParameter, this.comma,
-      SimpleIdentifier stackTraceParameter, this.rightParenthesis, Block body) {
+  CatchClause(
+      this.onKeyword,
+      TypeName exceptionType,
+      this.catchKeyword,
+      this.leftParenthesis,
+      SimpleIdentifier exceptionParameter,
+      this.comma,
+      SimpleIdentifier stackTraceParameter,
+      this.rightParenthesis,
+      Block body) {
     _exceptionType = _becomeParentOf(exceptionType);
     _exceptionParameter = _becomeParentOf(exceptionParameter);
     _stackTraceParameter = _becomeParentOf(stackTraceParameter);
@@ -4056,11 +4222,19 @@
    * corresponding clause. The list of [members] can be `null` if the class does
    * not have any members.
    */
-  ClassDeclaration(Comment comment, List<Annotation> metadata,
-      this.abstractKeyword, this.classKeyword, SimpleIdentifier name,
-      TypeParameterList typeParameters, ExtendsClause extendsClause,
-      WithClause withClause, ImplementsClause implementsClause,
-      this.leftBracket, List<ClassMember> members, this.rightBracket)
+  ClassDeclaration(
+      Comment comment,
+      List<Annotation> metadata,
+      this.abstractKeyword,
+      this.classKeyword,
+      SimpleIdentifier name,
+      TypeParameterList typeParameters,
+      ExtendsClause extendsClause,
+      WithClause withClause,
+      ImplementsClause implementsClause,
+      this.leftBracket,
+      List<ClassMember> members,
+      this.rightBracket)
       : super(comment, metadata, name) {
     _typeParameters = _becomeParentOf(typeParameters);
     _extendsClause = _becomeParentOf(extendsClause);
@@ -4312,10 +4486,18 @@
    * `null` if the class is not abstract. The [implementsClause] can be `null`
    * if the class does not implement any interfaces.
    */
-  ClassTypeAlias(Comment comment, List<Annotation> metadata, Token keyword,
-      SimpleIdentifier name, TypeParameterList typeParameters, this.equals,
-      this.abstractKeyword, TypeName superclass, WithClause withClause,
-      ImplementsClause implementsClause, Token semicolon)
+  ClassTypeAlias(
+      Comment comment,
+      List<Annotation> metadata,
+      Token keyword,
+      SimpleIdentifier name,
+      TypeParameterList typeParameters,
+      this.equals,
+      this.abstractKeyword,
+      TypeName superclass,
+      WithClause withClause,
+      ImplementsClause implementsClause,
+      Token semicolon)
       : super(comment, metadata, keyword, name, semicolon) {
     _typeParameters = _becomeParentOf(typeParameters);
     _superclass = _becomeParentOf(superclass);
@@ -4702,8 +4884,11 @@
    * are no directives in the compilation unit. The list of [declarations] can
    * be `null` if there are no declarations in the compilation unit.
    */
-  CompilationUnit(this.beginToken, ScriptTag scriptTag,
-      List<Directive> directives, List<CompilationUnitMember> declarations,
+  CompilationUnit(
+      this.beginToken,
+      ScriptTag scriptTag,
+      List<Directive> directives,
+      List<CompilationUnitMember> declarations,
       this.endToken) {
     _scriptTag = _becomeParentOf(scriptTag);
     _directives = new NodeList<Directive>(this, directives);
@@ -5374,12 +5559,20 @@
    * does not redirect to a different constructor. The [body] can be `null` if
    * the constructor does not have a body.
    */
-  ConstructorDeclaration(Comment comment, List<Annotation> metadata,
-      this.externalKeyword, this.constKeyword, this.factoryKeyword,
-      Identifier returnType, this.period, SimpleIdentifier name,
-      FormalParameterList parameters, this.separator,
+  ConstructorDeclaration(
+      Comment comment,
+      List<Annotation> metadata,
+      this.externalKeyword,
+      this.constKeyword,
+      this.factoryKeyword,
+      Identifier returnType,
+      this.period,
+      SimpleIdentifier name,
+      FormalParameterList parameters,
+      this.separator,
       List<ConstructorInitializer> initializers,
-      ConstructorName redirectedConstructor, FunctionBody body)
+      ConstructorName redirectedConstructor,
+      FunctionBody body)
       : super(comment, metadata) {
     _returnType = _becomeParentOf(returnType);
     _name = _becomeParentOf(name);
@@ -6160,8 +6353,13 @@
   /**
    * Initialize a newly created do loop.
    */
-  DoStatement(this.doKeyword, Statement body, this.whileKeyword,
-      this.leftParenthesis, Expression condition, this.rightParenthesis,
+  DoStatement(
+      this.doKeyword,
+      Statement body,
+      this.whileKeyword,
+      this.leftParenthesis,
+      Expression condition,
+      this.rightParenthesis,
       this.semicolon) {
     _body = _becomeParentOf(body);
     _condition = _becomeParentOf(condition);
@@ -6567,9 +6765,14 @@
    * corresponding attribute. The list of [constants] must contain at least one
    * value.
    */
-  EnumDeclaration(Comment comment, List<Annotation> metadata, this.enumKeyword,
-      SimpleIdentifier name, this.leftBracket,
-      List<EnumConstantDeclaration> constants, this.rightBracket)
+  EnumDeclaration(
+      Comment comment,
+      List<Annotation> metadata,
+      this.enumKeyword,
+      SimpleIdentifier name,
+      this.leftBracket,
+      List<EnumConstantDeclaration> constants,
+      this.rightBracket)
       : super(comment, metadata, name) {
     _constants = new NodeList<EnumConstantDeclaration>(this, constants);
   }
@@ -7184,9 +7387,16 @@
    * [parameters] can be `null` if this is not a function-typed field formal
    * parameter.
    */
-  FieldFormalParameter(Comment comment, List<Annotation> metadata, this.keyword,
-      TypeName type, this.thisKeyword, this.period, SimpleIdentifier identifier,
-      TypeParameterList typeParameters, FormalParameterList parameters)
+  FieldFormalParameter(
+      Comment comment,
+      List<Annotation> metadata,
+      this.keyword,
+      TypeName type,
+      this.thisKeyword,
+      this.period,
+      SimpleIdentifier identifier,
+      TypeParameterList typeParameters,
+      FormalParameterList parameters)
       : super(comment, metadata, identifier) {
     _type = _becomeParentOf(type);
     _typeParameters = _becomeParentOf(typeParameters);
@@ -7358,9 +7568,15 @@
    * `null` if this is not an asynchronous for loop.
    */
   @deprecated // Use new ForEachStatement.withDeclaration(...)
-  ForEachStatement.con1(this.awaitKeyword, this.forKeyword,
-      this.leftParenthesis, DeclaredIdentifier loopVariable, this.inKeyword,
-      Expression iterator, this.rightParenthesis, Statement body) {
+  ForEachStatement.con1(
+      this.awaitKeyword,
+      this.forKeyword,
+      this.leftParenthesis,
+      DeclaredIdentifier loopVariable,
+      this.inKeyword,
+      Expression iterator,
+      this.rightParenthesis,
+      Statement body) {
     _loopVariable = _becomeParentOf(loopVariable);
     _iterable = _becomeParentOf(iterator);
     _body = _becomeParentOf(body);
@@ -7371,9 +7587,15 @@
    * `null` if this is not an asynchronous for loop.
    */
   @deprecated // Use new ForEachStatement.withReference(...)
-  ForEachStatement.con2(this.awaitKeyword, this.forKeyword,
-      this.leftParenthesis, SimpleIdentifier identifier, this.inKeyword,
-      Expression iterator, this.rightParenthesis, Statement body) {
+  ForEachStatement.con2(
+      this.awaitKeyword,
+      this.forKeyword,
+      this.leftParenthesis,
+      SimpleIdentifier identifier,
+      this.inKeyword,
+      Expression iterator,
+      this.rightParenthesis,
+      Statement body) {
     _identifier = _becomeParentOf(identifier);
     _iterable = _becomeParentOf(iterator);
     _body = _becomeParentOf(body);
@@ -7384,9 +7606,15 @@
    * is declared internally (in the for-loop part). The [awaitKeyword] can be
    * `null` if this is not an asynchronous for loop.
    */
-  ForEachStatement.withDeclaration(this.awaitKeyword, this.forKeyword,
-      this.leftParenthesis, DeclaredIdentifier loopVariable, this.inKeyword,
-      Expression iterator, this.rightParenthesis, Statement body) {
+  ForEachStatement.withDeclaration(
+      this.awaitKeyword,
+      this.forKeyword,
+      this.leftParenthesis,
+      DeclaredIdentifier loopVariable,
+      this.inKeyword,
+      Expression iterator,
+      this.rightParenthesis,
+      Statement body) {
     _loopVariable = _becomeParentOf(loopVariable);
     _iterable = _becomeParentOf(iterator);
     _body = _becomeParentOf(body);
@@ -7397,9 +7625,15 @@
    * is declared outside the for loop. The [awaitKeyword] can be `null` if this
    * is not an asynchronous for loop.
    */
-  ForEachStatement.withReference(this.awaitKeyword, this.forKeyword,
-      this.leftParenthesis, SimpleIdentifier identifier, this.inKeyword,
-      Expression iterator, this.rightParenthesis, Statement body) {
+  ForEachStatement.withReference(
+      this.awaitKeyword,
+      this.forKeyword,
+      this.leftParenthesis,
+      SimpleIdentifier identifier,
+      this.inKeyword,
+      Expression iterator,
+      this.rightParenthesis,
+      Statement body) {
     _identifier = _becomeParentOf(identifier);
     _iterable = _becomeParentOf(iterator);
     _body = _becomeParentOf(body);
@@ -7730,10 +7964,17 @@
    * [updaters] can be `null` if the loop does not have the corresponding
    * attribute.
    */
-  ForStatement(this.forKeyword, this.leftParenthesis,
-      VariableDeclarationList variableList, Expression initialization,
-      this.leftSeparator, Expression condition, this.rightSeparator,
-      List<Expression> updaters, this.rightParenthesis, Statement body) {
+  ForStatement(
+      this.forKeyword,
+      this.leftParenthesis,
+      VariableDeclarationList variableList,
+      Expression initialization,
+      this.leftSeparator,
+      Expression condition,
+      this.rightSeparator,
+      List<Expression> updaters,
+      this.rightParenthesis,
+      Statement body) {
     _variableList = _becomeParentOf(variableList);
     _initialization = _becomeParentOf(initialization);
     _condition = _becomeParentOf(condition);
@@ -7908,9 +8149,14 @@
    * return type was specified. The [propertyKeyword] can be `null` if the
    * function is neither a getter or a setter.
    */
-  FunctionDeclaration(Comment comment, List<Annotation> metadata,
-      this.externalKeyword, TypeName returnType, this.propertyKeyword,
-      SimpleIdentifier name, FunctionExpression functionExpression)
+  FunctionDeclaration(
+      Comment comment,
+      List<Annotation> metadata,
+      this.externalKeyword,
+      TypeName returnType,
+      this.propertyKeyword,
+      SimpleIdentifier name,
+      FunctionExpression functionExpression)
       : super(comment, metadata, name) {
     _returnType = _becomeParentOf(returnType);
     _functionExpression = _becomeParentOf(functionExpression);
@@ -8326,9 +8572,14 @@
    * was specified. The [typeParameters] can be `null` if the function has no
    * type parameters.
    */
-  FunctionTypeAlias(Comment comment, List<Annotation> metadata, Token keyword,
-      TypeName returnType, SimpleIdentifier name,
-      TypeParameterList typeParameters, FormalParameterList parameters,
+  FunctionTypeAlias(
+      Comment comment,
+      List<Annotation> metadata,
+      Token keyword,
+      TypeName returnType,
+      SimpleIdentifier name,
+      TypeParameterList typeParameters,
+      FormalParameterList parameters,
       Token semicolon)
       : super(comment, metadata, keyword, name, semicolon) {
     _returnType = _becomeParentOf(returnType);
@@ -8433,9 +8684,13 @@
    * corresponding attribute. The [returnType] can be `null` if no return type
    * was specified.
    */
-  FunctionTypedFormalParameter(Comment comment, List<Annotation> metadata,
-      TypeName returnType, SimpleIdentifier identifier,
-      TypeParameterList typeParameters, FormalParameterList parameters)
+  FunctionTypedFormalParameter(
+      Comment comment,
+      List<Annotation> metadata,
+      TypeName returnType,
+      SimpleIdentifier identifier,
+      TypeParameterList typeParameters,
+      FormalParameterList parameters)
       : super(comment, metadata, identifier) {
     _returnType = _becomeParentOf(returnType);
     _typeParameters = _becomeParentOf(typeParameters);
@@ -9092,8 +9347,13 @@
    * Initialize a newly created if statement. The [elseKeyword] and
    * [elseStatement] can be `null` if there is no else clause.
    */
-  IfStatement(this.ifKeyword, this.leftParenthesis, Expression condition,
-      this.rightParenthesis, Statement thenStatement, this.elseKeyword,
+  IfStatement(
+      this.ifKeyword,
+      this.leftParenthesis,
+      Expression condition,
+      this.rightParenthesis,
+      Statement thenStatement,
+      this.elseKeyword,
       Statement elseStatement) {
     _condition = _becomeParentOf(condition);
     _thenStatement = _becomeParentOf(thenStatement);
@@ -9247,8 +9507,8 @@
  * >   | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier [Combinator]* ';'
  */
 class ImportDirective extends NamespaceDirective {
-  static Comparator<ImportDirective> COMPARATOR = (ImportDirective import1,
-      ImportDirective import2) {
+  static Comparator<ImportDirective> COMPARATOR =
+      (ImportDirective import1, ImportDirective import2) {
     //
     // uri
     //
@@ -9367,9 +9627,16 @@
    * does not specify a prefix. The list of [combinators] can be `null` if there
    * are no combinators.
    */
-  ImportDirective(Comment comment, List<Annotation> metadata, Token keyword,
-      StringLiteral libraryUri, this.deferredKeyword, this.asKeyword,
-      SimpleIdentifier prefix, List<Combinator> combinators, Token semicolon)
+  ImportDirective(
+      Comment comment,
+      List<Annotation> metadata,
+      Token keyword,
+      StringLiteral libraryUri,
+      this.deferredKeyword,
+      this.asKeyword,
+      SimpleIdentifier prefix,
+      List<Combinator> combinators,
+      Token semicolon)
       : super(comment, metadata, keyword, libraryUri, combinators, semicolon) {
     _prefix = _becomeParentOf(prefix);
   }
@@ -9484,16 +9751,20 @@
 
   @override
   Annotation visitAnnotation(Annotation node) {
-    Annotation copy = new Annotation(_mapToken(node.atSign),
-        _cloneNode(node.name), _mapToken(node.period),
-        _cloneNode(node.constructorName), _cloneNode(node.arguments));
+    Annotation copy = new Annotation(
+        _mapToken(node.atSign),
+        _cloneNode(node.name),
+        _mapToken(node.period),
+        _cloneNode(node.constructorName),
+        _cloneNode(node.arguments));
     copy.element = node.element;
     return copy;
   }
 
   @override
   ArgumentList visitArgumentList(ArgumentList node) => new ArgumentList(
-      _mapToken(node.leftParenthesis), _cloneNodeList(node.arguments),
+      _mapToken(node.leftParenthesis),
+      _cloneNodeList(node.arguments),
       _mapToken(node.rightParenthesis));
 
   @override
@@ -9507,14 +9778,17 @@
 
   @override
   AstNode visitAssertStatement(AssertStatement node) => new AssertStatement(
-      _mapToken(node.assertKeyword), _mapToken(node.leftParenthesis),
-      _cloneNode(node.condition), _mapToken(node.rightParenthesis),
+      _mapToken(node.assertKeyword),
+      _mapToken(node.leftParenthesis),
+      _cloneNode(node.condition),
+      _mapToken(node.rightParenthesis),
       _mapToken(node.semicolon));
 
   @override
   AssignmentExpression visitAssignmentExpression(AssignmentExpression node) {
     AssignmentExpression copy = new AssignmentExpression(
-        _cloneNode(node.leftHandSide), _mapToken(node.operator),
+        _cloneNode(node.leftHandSide),
+        _mapToken(node.operator),
         _cloneNode(node.rightHandSide));
     copy.propagatedElement = node.propagatedElement;
     copy.propagatedType = node.propagatedType;
@@ -9544,9 +9818,9 @@
       _cloneNodeList(node.statements), _mapToken(node.rightBracket));
 
   @override
-  BlockFunctionBody visitBlockFunctionBody(
-      BlockFunctionBody node) => new BlockFunctionBody(
-      _mapToken(node.keyword), _mapToken(node.star), _cloneNode(node.block));
+  BlockFunctionBody visitBlockFunctionBody(BlockFunctionBody node) =>
+      new BlockFunctionBody(_mapToken(node.keyword), _mapToken(node.star),
+          _cloneNode(node.block));
 
   @override
   BooleanLiteral visitBooleanLiteral(BooleanLiteral node) {
@@ -9559,7 +9833,8 @@
 
   @override
   BreakStatement visitBreakStatement(BreakStatement node) => new BreakStatement(
-      _mapToken(node.breakKeyword), _cloneNode(node.label),
+      _mapToken(node.breakKeyword),
+      _cloneNode(node.label),
       _mapToken(node.semicolon));
 
   @override
@@ -9573,32 +9848,47 @@
 
   @override
   CatchClause visitCatchClause(CatchClause node) => new CatchClause(
-      _mapToken(node.onKeyword), _cloneNode(node.exceptionType),
-      _mapToken(node.catchKeyword), _mapToken(node.leftParenthesis),
-      _cloneNode(node.exceptionParameter), _mapToken(node.comma),
-      _cloneNode(node.stackTraceParameter), _mapToken(node.rightParenthesis),
+      _mapToken(node.onKeyword),
+      _cloneNode(node.exceptionType),
+      _mapToken(node.catchKeyword),
+      _mapToken(node.leftParenthesis),
+      _cloneNode(node.exceptionParameter),
+      _mapToken(node.comma),
+      _cloneNode(node.stackTraceParameter),
+      _mapToken(node.rightParenthesis),
       _cloneNode(node.body));
 
   @override
   ClassDeclaration visitClassDeclaration(ClassDeclaration node) {
     ClassDeclaration copy = new ClassDeclaration(
-        _cloneNode(node.documentationComment), _cloneNodeList(node.metadata),
-        _mapToken(node.abstractKeyword), _mapToken(node.classKeyword),
-        _cloneNode(node.name), _cloneNode(node.typeParameters),
-        _cloneNode(node.extendsClause), _cloneNode(node.withClause),
-        _cloneNode(node.implementsClause), _mapToken(node.leftBracket),
-        _cloneNodeList(node.members), _mapToken(node.rightBracket));
+        _cloneNode(node.documentationComment),
+        _cloneNodeList(node.metadata),
+        _mapToken(node.abstractKeyword),
+        _mapToken(node.classKeyword),
+        _cloneNode(node.name),
+        _cloneNode(node.typeParameters),
+        _cloneNode(node.extendsClause),
+        _cloneNode(node.withClause),
+        _cloneNode(node.implementsClause),
+        _mapToken(node.leftBracket),
+        _cloneNodeList(node.members),
+        _mapToken(node.rightBracket));
     copy.nativeClause = _cloneNode(node.nativeClause);
     return copy;
   }
 
   @override
   ClassTypeAlias visitClassTypeAlias(ClassTypeAlias node) => new ClassTypeAlias(
-      _cloneNode(node.documentationComment), _cloneNodeList(node.metadata),
-      _mapToken(node.typedefKeyword), _cloneNode(node.name),
-      _cloneNode(node.typeParameters), _mapToken(node.equals),
-      _mapToken(node.abstractKeyword), _cloneNode(node.superclass),
-      _cloneNode(node.withClause), _cloneNode(node.implementsClause),
+      _cloneNode(node.documentationComment),
+      _cloneNodeList(node.metadata),
+      _mapToken(node.typedefKeyword),
+      _cloneNode(node.name),
+      _cloneNode(node.typeParameters),
+      _mapToken(node.equals),
+      _mapToken(node.abstractKeyword),
+      _cloneNode(node.superclass),
+      _cloneNode(node.withClause),
+      _cloneNode(node.implementsClause),
       _mapToken(node.semicolon));
 
   @override
@@ -9619,9 +9909,12 @@
 
   @override
   CompilationUnit visitCompilationUnit(CompilationUnit node) {
-    CompilationUnit copy = new CompilationUnit(_mapToken(node.beginToken),
-        _cloneNode(node.scriptTag), _cloneNodeList(node.directives),
-        _cloneNodeList(node.declarations), _mapToken(node.endToken));
+    CompilationUnit copy = new CompilationUnit(
+        _mapToken(node.beginToken),
+        _cloneNode(node.scriptTag),
+        _cloneNodeList(node.directives),
+        _cloneNodeList(node.declarations),
+        _mapToken(node.endToken));
     copy.lineInfo = node.lineInfo;
     copy.element = node.element;
     return copy;
@@ -9630,8 +9923,10 @@
   @override
   ConditionalExpression visitConditionalExpression(ConditionalExpression node) {
     ConditionalExpression copy = new ConditionalExpression(
-        _cloneNode(node.condition), _mapToken(node.question),
-        _cloneNode(node.thenExpression), _mapToken(node.colon),
+        _cloneNode(node.condition),
+        _mapToken(node.question),
+        _cloneNode(node.thenExpression),
+        _mapToken(node.colon),
         _cloneNode(node.elseExpression));
     copy.propagatedType = node.propagatedType;
     copy.staticType = node.staticType;
@@ -9642,23 +9937,32 @@
   ConstructorDeclaration visitConstructorDeclaration(
       ConstructorDeclaration node) {
     ConstructorDeclaration copy = new ConstructorDeclaration(
-        _cloneNode(node.documentationComment), _cloneNodeList(node.metadata),
-        _mapToken(node.externalKeyword), _mapToken(node.constKeyword),
-        _mapToken(node.factoryKeyword), _cloneNode(node.returnType),
-        _mapToken(node.period), _cloneNode(node.name),
-        _cloneNode(node.parameters), _mapToken(node.separator),
+        _cloneNode(node.documentationComment),
+        _cloneNodeList(node.metadata),
+        _mapToken(node.externalKeyword),
+        _mapToken(node.constKeyword),
+        _mapToken(node.factoryKeyword),
+        _cloneNode(node.returnType),
+        _mapToken(node.period),
+        _cloneNode(node.name),
+        _cloneNode(node.parameters),
+        _mapToken(node.separator),
         _cloneNodeList(node.initializers),
-        _cloneNode(node.redirectedConstructor), _cloneNode(node.body));
+        _cloneNode(node.redirectedConstructor),
+        _cloneNode(node.body));
     copy.element = node.element;
     return copy;
   }
 
   @override
   ConstructorFieldInitializer visitConstructorFieldInitializer(
-      ConstructorFieldInitializer node) => new ConstructorFieldInitializer(
-      _mapToken(node.thisKeyword), _mapToken(node.period),
-      _cloneNode(node.fieldName), _mapToken(node.equals),
-      _cloneNode(node.expression));
+          ConstructorFieldInitializer node) =>
+      new ConstructorFieldInitializer(
+          _mapToken(node.thisKeyword),
+          _mapToken(node.period),
+          _cloneNode(node.fieldName),
+          _mapToken(node.equals),
+          _cloneNode(node.expression));
 
   @override
   ConstructorName visitConstructorName(ConstructorName node) {
@@ -9675,21 +9979,27 @@
 
   @override
   DeclaredIdentifier visitDeclaredIdentifier(DeclaredIdentifier node) =>
-      new DeclaredIdentifier(_cloneNode(node.documentationComment),
-          _cloneNodeList(node.metadata), _mapToken(node.keyword),
-          _cloneNode(node.type), _cloneNode(node.identifier));
+      new DeclaredIdentifier(
+          _cloneNode(node.documentationComment),
+          _cloneNodeList(node.metadata),
+          _mapToken(node.keyword),
+          _cloneNode(node.type),
+          _cloneNode(node.identifier));
 
   @override
   DefaultFormalParameter visitDefaultFormalParameter(
-      DefaultFormalParameter node) => new DefaultFormalParameter(
-      _cloneNode(node.parameter), node.kind, _mapToken(node.separator),
-      _cloneNode(node.defaultValue));
+          DefaultFormalParameter node) =>
+      new DefaultFormalParameter(_cloneNode(node.parameter), node.kind,
+          _mapToken(node.separator), _cloneNode(node.defaultValue));
 
   @override
   DoStatement visitDoStatement(DoStatement node) => new DoStatement(
-      _mapToken(node.doKeyword), _cloneNode(node.body),
-      _mapToken(node.whileKeyword), _mapToken(node.leftParenthesis),
-      _cloneNode(node.condition), _mapToken(node.rightParenthesis),
+      _mapToken(node.doKeyword),
+      _cloneNode(node.body),
+      _mapToken(node.whileKeyword),
+      _mapToken(node.leftParenthesis),
+      _cloneNode(node.condition),
+      _mapToken(node.rightParenthesis),
       _mapToken(node.semicolon));
 
   @override
@@ -9715,26 +10025,35 @@
 
   @override
   AstNode visitEnumDeclaration(EnumDeclaration node) => new EnumDeclaration(
-      _cloneNode(node.documentationComment), _cloneNodeList(node.metadata),
-      _mapToken(node.enumKeyword), _cloneNode(node.name),
-      _mapToken(node.leftBracket), _cloneNodeList(node.constants),
+      _cloneNode(node.documentationComment),
+      _cloneNodeList(node.metadata),
+      _mapToken(node.enumKeyword),
+      _cloneNode(node.name),
+      _mapToken(node.leftBracket),
+      _cloneNodeList(node.constants),
       _mapToken(node.rightBracket));
 
   @override
   ExportDirective visitExportDirective(ExportDirective node) {
     ExportDirective copy = new ExportDirective(
-        _cloneNode(node.documentationComment), _cloneNodeList(node.metadata),
-        _mapToken(node.keyword), _cloneNode(node.uri),
-        _cloneNodeList(node.combinators), _mapToken(node.semicolon));
+        _cloneNode(node.documentationComment),
+        _cloneNodeList(node.metadata),
+        _mapToken(node.keyword),
+        _cloneNode(node.uri),
+        _cloneNodeList(node.combinators),
+        _mapToken(node.semicolon));
     copy.element = node.element;
     return copy;
   }
 
   @override
   ExpressionFunctionBody visitExpressionFunctionBody(
-      ExpressionFunctionBody node) => new ExpressionFunctionBody(
-      _mapToken(node.keyword), _mapToken(node.functionDefinition),
-      _cloneNode(node.expression), _mapToken(node.semicolon));
+          ExpressionFunctionBody node) =>
+      new ExpressionFunctionBody(
+          _mapToken(node.keyword),
+          _mapToken(node.functionDefinition),
+          _cloneNode(node.expression),
+          _mapToken(node.semicolon));
 
   @override
   ExpressionStatement visitExpressionStatement(ExpressionStatement node) =>
@@ -9747,55 +10066,83 @@
 
   @override
   FieldDeclaration visitFieldDeclaration(FieldDeclaration node) =>
-      new FieldDeclaration(_cloneNode(node.documentationComment),
-          _cloneNodeList(node.metadata), _mapToken(node.staticKeyword),
-          _cloneNode(node.fields), _mapToken(node.semicolon));
+      new FieldDeclaration(
+          _cloneNode(node.documentationComment),
+          _cloneNodeList(node.metadata),
+          _mapToken(node.staticKeyword),
+          _cloneNode(node.fields),
+          _mapToken(node.semicolon));
 
   @override
   FieldFormalParameter visitFieldFormalParameter(FieldFormalParameter node) =>
-      new FieldFormalParameter(_cloneNode(node.documentationComment),
-          _cloneNodeList(node.metadata), _mapToken(node.keyword),
-          _cloneNode(node.type), _mapToken(node.thisKeyword),
-          _mapToken(node.period), _cloneNode(node.identifier),
-          _cloneNode(node.typeParameters), _cloneNode(node.parameters));
+      new FieldFormalParameter(
+          _cloneNode(node.documentationComment),
+          _cloneNodeList(node.metadata),
+          _mapToken(node.keyword),
+          _cloneNode(node.type),
+          _mapToken(node.thisKeyword),
+          _mapToken(node.period),
+          _cloneNode(node.identifier),
+          _cloneNode(node.typeParameters),
+          _cloneNode(node.parameters));
 
   @override
   ForEachStatement visitForEachStatement(ForEachStatement node) {
     DeclaredIdentifier loopVariable = node.loopVariable;
     if (loopVariable == null) {
-      return new ForEachStatement.withReference(_mapToken(node.awaitKeyword),
-          _mapToken(node.forKeyword), _mapToken(node.leftParenthesis),
-          _cloneNode(node.identifier), _mapToken(node.inKeyword),
-          _cloneNode(node.iterable), _mapToken(node.rightParenthesis),
+      return new ForEachStatement.withReference(
+          _mapToken(node.awaitKeyword),
+          _mapToken(node.forKeyword),
+          _mapToken(node.leftParenthesis),
+          _cloneNode(node.identifier),
+          _mapToken(node.inKeyword),
+          _cloneNode(node.iterable),
+          _mapToken(node.rightParenthesis),
           _cloneNode(node.body));
     }
-    return new ForEachStatement.withDeclaration(_mapToken(node.awaitKeyword),
-        _mapToken(node.forKeyword), _mapToken(node.leftParenthesis),
-        _cloneNode(loopVariable), _mapToken(node.inKeyword),
-        _cloneNode(node.iterable), _mapToken(node.rightParenthesis),
+    return new ForEachStatement.withDeclaration(
+        _mapToken(node.awaitKeyword),
+        _mapToken(node.forKeyword),
+        _mapToken(node.leftParenthesis),
+        _cloneNode(loopVariable),
+        _mapToken(node.inKeyword),
+        _cloneNode(node.iterable),
+        _mapToken(node.rightParenthesis),
         _cloneNode(node.body));
   }
 
   @override
   FormalParameterList visitFormalParameterList(FormalParameterList node) =>
-      new FormalParameterList(_mapToken(node.leftParenthesis),
-          _cloneNodeList(node.parameters), _mapToken(node.leftDelimiter),
-          _mapToken(node.rightDelimiter), _mapToken(node.rightParenthesis));
+      new FormalParameterList(
+          _mapToken(node.leftParenthesis),
+          _cloneNodeList(node.parameters),
+          _mapToken(node.leftDelimiter),
+          _mapToken(node.rightDelimiter),
+          _mapToken(node.rightParenthesis));
 
   @override
   ForStatement visitForStatement(ForStatement node) => new ForStatement(
-      _mapToken(node.forKeyword), _mapToken(node.leftParenthesis),
-      _cloneNode(node.variables), _cloneNode(node.initialization),
-      _mapToken(node.leftSeparator), _cloneNode(node.condition),
-      _mapToken(node.rightSeparator), _cloneNodeList(node.updaters),
-      _mapToken(node.rightParenthesis), _cloneNode(node.body));
+      _mapToken(node.forKeyword),
+      _mapToken(node.leftParenthesis),
+      _cloneNode(node.variables),
+      _cloneNode(node.initialization),
+      _mapToken(node.leftSeparator),
+      _cloneNode(node.condition),
+      _mapToken(node.rightSeparator),
+      _cloneNodeList(node.updaters),
+      _mapToken(node.rightParenthesis),
+      _cloneNode(node.body));
 
   @override
   FunctionDeclaration visitFunctionDeclaration(FunctionDeclaration node) =>
-      new FunctionDeclaration(_cloneNode(node.documentationComment),
-          _cloneNodeList(node.metadata), _mapToken(node.externalKeyword),
-          _cloneNode(node.returnType), _mapToken(node.propertyKeyword),
-          _cloneNode(node.name), _cloneNode(node.functionExpression));
+      new FunctionDeclaration(
+          _cloneNode(node.documentationComment),
+          _cloneNodeList(node.metadata),
+          _mapToken(node.externalKeyword),
+          _cloneNode(node.returnType),
+          _mapToken(node.propertyKeyword),
+          _cloneNode(node.name),
+          _cloneNode(node.functionExpression));
 
   @override
   FunctionDeclarationStatement visitFunctionDeclarationStatement(
@@ -9805,7 +10152,8 @@
   @override
   FunctionExpression visitFunctionExpression(FunctionExpression node) {
     FunctionExpression copy = new FunctionExpression(
-        _cloneNode(node.typeParameters), _cloneNode(node.parameters),
+        _cloneNode(node.typeParameters),
+        _cloneNode(node.parameters),
         _cloneNode(node.body));
     copy.element = node.element;
     copy.propagatedType = node.propagatedType;
@@ -9817,7 +10165,8 @@
   FunctionExpressionInvocation visitFunctionExpressionInvocation(
       FunctionExpressionInvocation node) {
     FunctionExpressionInvocation copy = new FunctionExpressionInvocation(
-        _cloneNode(node.function), _cloneNode(node.typeArguments),
+        _cloneNode(node.function),
+        _cloneNode(node.typeArguments),
         _cloneNode(node.argumentList));
     copy.propagatedElement = node.propagatedElement;
     copy.propagatedType = node.propagatedType;
@@ -9828,18 +10177,26 @@
 
   @override
   FunctionTypeAlias visitFunctionTypeAlias(FunctionTypeAlias node) =>
-      new FunctionTypeAlias(_cloneNode(node.documentationComment),
-          _cloneNodeList(node.metadata), _mapToken(node.typedefKeyword),
-          _cloneNode(node.returnType), _cloneNode(node.name),
-          _cloneNode(node.typeParameters), _cloneNode(node.parameters),
+      new FunctionTypeAlias(
+          _cloneNode(node.documentationComment),
+          _cloneNodeList(node.metadata),
+          _mapToken(node.typedefKeyword),
+          _cloneNode(node.returnType),
+          _cloneNode(node.name),
+          _cloneNode(node.typeParameters),
+          _cloneNode(node.parameters),
           _mapToken(node.semicolon));
 
   @override
   FunctionTypedFormalParameter visitFunctionTypedFormalParameter(
-      FunctionTypedFormalParameter node) => new FunctionTypedFormalParameter(
-      _cloneNode(node.documentationComment), _cloneNodeList(node.metadata),
-      _cloneNode(node.returnType), _cloneNode(node.identifier),
-      _cloneNode(node.typeParameters), _cloneNode(node.parameters));
+          FunctionTypedFormalParameter node) =>
+      new FunctionTypedFormalParameter(
+          _cloneNode(node.documentationComment),
+          _cloneNodeList(node.metadata),
+          _cloneNode(node.returnType),
+          _cloneNode(node.identifier),
+          _cloneNode(node.typeParameters),
+          _cloneNode(node.parameters));
 
   @override
   HideCombinator visitHideCombinator(HideCombinator node) => new HideCombinator(
@@ -9847,9 +10204,12 @@
 
   @override
   IfStatement visitIfStatement(IfStatement node) => new IfStatement(
-      _mapToken(node.ifKeyword), _mapToken(node.leftParenthesis),
-      _cloneNode(node.condition), _mapToken(node.rightParenthesis),
-      _cloneNode(node.thenStatement), _mapToken(node.elseKeyword),
+      _mapToken(node.ifKeyword),
+      _mapToken(node.leftParenthesis),
+      _cloneNode(node.condition),
+      _mapToken(node.rightParenthesis),
+      _cloneNode(node.thenStatement),
+      _mapToken(node.elseKeyword),
       _cloneNode(node.elseStatement));
 
   @override
@@ -9859,19 +10219,26 @@
 
   @override
   ImportDirective visitImportDirective(ImportDirective node) =>
-      new ImportDirective(_cloneNode(node.documentationComment),
-          _cloneNodeList(node.metadata), _mapToken(node.keyword),
-          _cloneNode(node.uri), _mapToken(node.deferredKeyword),
-          _mapToken(node.asKeyword), _cloneNode(node.prefix),
-          _cloneNodeList(node.combinators), _mapToken(node.semicolon));
+      new ImportDirective(
+          _cloneNode(node.documentationComment),
+          _cloneNodeList(node.metadata),
+          _mapToken(node.keyword),
+          _cloneNode(node.uri),
+          _mapToken(node.deferredKeyword),
+          _mapToken(node.asKeyword),
+          _cloneNode(node.prefix),
+          _cloneNodeList(node.combinators),
+          _mapToken(node.semicolon));
 
   @override
   IndexExpression visitIndexExpression(IndexExpression node) {
     Token period = _mapToken(node.period);
     IndexExpression copy;
     if (period == null) {
-      copy = new IndexExpression.forTarget(_cloneNode(node.target),
-          _mapToken(node.leftBracket), _cloneNode(node.index),
+      copy = new IndexExpression.forTarget(
+          _cloneNode(node.target),
+          _mapToken(node.leftBracket),
+          _cloneNode(node.index),
           _mapToken(node.rightBracket));
     } else {
       copy = new IndexExpression.forCascade(period, _mapToken(node.leftBracket),
@@ -9889,7 +10256,8 @@
   InstanceCreationExpression visitInstanceCreationExpression(
       InstanceCreationExpression node) {
     InstanceCreationExpression copy = new InstanceCreationExpression(
-        _mapToken(node.keyword), _cloneNode(node.constructorName),
+        _mapToken(node.keyword),
+        _cloneNode(node.constructorName),
         _cloneNode(node.argumentList));
     copy.propagatedType = node.propagatedType;
     copy.staticElement = node.staticElement;
@@ -9908,9 +10276,9 @@
 
   @override
   InterpolationExpression visitInterpolationExpression(
-      InterpolationExpression node) => new InterpolationExpression(
-      _mapToken(node.leftBracket), _cloneNode(node.expression),
-      _mapToken(node.rightBracket));
+          InterpolationExpression node) =>
+      new InterpolationExpression(_mapToken(node.leftBracket),
+          _cloneNode(node.expression), _mapToken(node.rightBracket));
 
   @override
   InterpolationString visitInterpolationString(InterpolationString node) =>
@@ -9918,8 +10286,10 @@
 
   @override
   IsExpression visitIsExpression(IsExpression node) {
-    IsExpression copy = new IsExpression(_cloneNode(node.expression),
-        _mapToken(node.isOperator), _mapToken(node.notOperator),
+    IsExpression copy = new IsExpression(
+        _cloneNode(node.expression),
+        _mapToken(node.isOperator),
+        _mapToken(node.notOperator),
         _cloneNode(node.type));
     copy.propagatedType = node.propagatedType;
     copy.staticType = node.staticType;
@@ -9937,9 +10307,12 @@
 
   @override
   LibraryDirective visitLibraryDirective(LibraryDirective node) =>
-      new LibraryDirective(_cloneNode(node.documentationComment),
-          _cloneNodeList(node.metadata), _mapToken(node.libraryKeyword),
-          _cloneNode(node.name), _mapToken(node.semicolon));
+      new LibraryDirective(
+          _cloneNode(node.documentationComment),
+          _cloneNodeList(node.metadata),
+          _mapToken(node.libraryKeyword),
+          _cloneNode(node.name),
+          _mapToken(node.semicolon));
 
   @override
   LibraryIdentifier visitLibraryIdentifier(LibraryIdentifier node) {
@@ -9952,9 +10325,12 @@
 
   @override
   ListLiteral visitListLiteral(ListLiteral node) {
-    ListLiteral copy = new ListLiteral(_mapToken(node.constKeyword),
-        _cloneNode(node.typeArguments), _mapToken(node.leftBracket),
-        _cloneNodeList(node.elements), _mapToken(node.rightBracket));
+    ListLiteral copy = new ListLiteral(
+        _mapToken(node.constKeyword),
+        _cloneNode(node.typeArguments),
+        _mapToken(node.leftBracket),
+        _cloneNodeList(node.elements),
+        _mapToken(node.rightBracket));
     copy.propagatedType = node.propagatedType;
     copy.staticType = node.staticType;
     return copy;
@@ -9962,33 +10338,45 @@
 
   @override
   MapLiteral visitMapLiteral(MapLiteral node) {
-    MapLiteral copy = new MapLiteral(_mapToken(node.constKeyword),
-        _cloneNode(node.typeArguments), _mapToken(node.leftBracket),
-        _cloneNodeList(node.entries), _mapToken(node.rightBracket));
+    MapLiteral copy = new MapLiteral(
+        _mapToken(node.constKeyword),
+        _cloneNode(node.typeArguments),
+        _mapToken(node.leftBracket),
+        _cloneNodeList(node.entries),
+        _mapToken(node.rightBracket));
     copy.propagatedType = node.propagatedType;
     copy.staticType = node.staticType;
     return copy;
   }
 
   @override
-  MapLiteralEntry visitMapLiteralEntry(
-      MapLiteralEntry node) => new MapLiteralEntry(
-      _cloneNode(node.key), _mapToken(node.separator), _cloneNode(node.value));
+  MapLiteralEntry visitMapLiteralEntry(MapLiteralEntry node) =>
+      new MapLiteralEntry(_cloneNode(node.key), _mapToken(node.separator),
+          _cloneNode(node.value));
 
   @override
   MethodDeclaration visitMethodDeclaration(MethodDeclaration node) =>
-      new MethodDeclaration(_cloneNode(node.documentationComment),
-          _cloneNodeList(node.metadata), _mapToken(node.externalKeyword),
-          _mapToken(node.modifierKeyword), _cloneNode(node.returnType),
-          _mapToken(node.propertyKeyword), _mapToken(node.operatorKeyword),
-          _cloneNode(node.name), _cloneNode(node._typeParameters),
-          _cloneNode(node.parameters), _cloneNode(node.body));
+      new MethodDeclaration(
+          _cloneNode(node.documentationComment),
+          _cloneNodeList(node.metadata),
+          _mapToken(node.externalKeyword),
+          _mapToken(node.modifierKeyword),
+          _cloneNode(node.returnType),
+          _mapToken(node.propertyKeyword),
+          _mapToken(node.operatorKeyword),
+          _cloneNode(node.name),
+          _cloneNode(node._typeParameters),
+          _cloneNode(node.parameters),
+          _cloneNode(node.body));
 
   @override
   MethodInvocation visitMethodInvocation(MethodInvocation node) {
-    MethodInvocation copy = new MethodInvocation(_cloneNode(node.target),
-        _mapToken(node.operator), _cloneNode(node.methodName),
-        _cloneNode(node.typeArguments), _cloneNode(node.argumentList));
+    MethodInvocation copy = new MethodInvocation(
+        _cloneNode(node.target),
+        _mapToken(node.operator),
+        _cloneNode(node.methodName),
+        _cloneNode(node.typeArguments),
+        _cloneNode(node.argumentList));
     copy.propagatedType = node.propagatedType;
     copy.staticType = node.staticType;
     return copy;
@@ -10024,7 +10412,8 @@
   ParenthesizedExpression visitParenthesizedExpression(
       ParenthesizedExpression node) {
     ParenthesizedExpression copy = new ParenthesizedExpression(
-        _mapToken(node.leftParenthesis), _cloneNode(node.expression),
+        _mapToken(node.leftParenthesis),
+        _cloneNode(node.expression),
         _mapToken(node.rightParenthesis));
     copy.propagatedType = node.propagatedType;
     copy.staticType = node.staticType;
@@ -10034,8 +10423,10 @@
   @override
   PartDirective visitPartDirective(PartDirective node) {
     PartDirective copy = new PartDirective(
-        _cloneNode(node.documentationComment), _cloneNodeList(node.metadata),
-        _mapToken(node.partKeyword), _cloneNode(node.uri),
+        _cloneNode(node.documentationComment),
+        _cloneNodeList(node.metadata),
+        _mapToken(node.partKeyword),
+        _cloneNode(node.uri),
         _mapToken(node.semicolon));
     copy.element = node.element;
     return copy;
@@ -10044,9 +10435,12 @@
   @override
   PartOfDirective visitPartOfDirective(PartOfDirective node) {
     PartOfDirective copy = new PartOfDirective(
-        _cloneNode(node.documentationComment), _cloneNodeList(node.metadata),
-        _mapToken(node.partKeyword), _mapToken(node.ofKeyword),
-        _cloneNode(node.libraryName), _mapToken(node.semicolon));
+        _cloneNode(node.documentationComment),
+        _cloneNodeList(node.metadata),
+        _mapToken(node.partKeyword),
+        _mapToken(node.ofKeyword),
+        _cloneNode(node.libraryName),
+        _mapToken(node.semicolon));
     copy.element = node.element;
     return copy;
   }
@@ -10095,8 +10489,10 @@
   RedirectingConstructorInvocation visitRedirectingConstructorInvocation(
       RedirectingConstructorInvocation node) {
     RedirectingConstructorInvocation copy =
-        new RedirectingConstructorInvocation(_mapToken(node.thisKeyword),
-            _mapToken(node.period), _cloneNode(node.constructorName),
+        new RedirectingConstructorInvocation(
+            _mapToken(node.thisKeyword),
+            _mapToken(node.period),
+            _cloneNode(node.constructorName),
             _cloneNode(node.argumentList));
     copy.staticElement = node.staticElement;
     return copy;
@@ -10126,10 +10522,13 @@
 
   @override
   SimpleFormalParameter visitSimpleFormalParameter(
-      SimpleFormalParameter node) => new SimpleFormalParameter(
-      _cloneNode(node.documentationComment), _cloneNodeList(node.metadata),
-      _mapToken(node.keyword), _cloneNode(node.type),
-      _cloneNode(node.identifier));
+          SimpleFormalParameter node) =>
+      new SimpleFormalParameter(
+          _cloneNode(node.documentationComment),
+          _cloneNodeList(node.metadata),
+          _mapToken(node.keyword),
+          _cloneNode(node.type),
+          _cloneNode(node.identifier));
 
   @override
   SimpleIdentifier visitSimpleIdentifier(SimpleIdentifier node) {
@@ -10173,8 +10572,10 @@
   SuperConstructorInvocation visitSuperConstructorInvocation(
       SuperConstructorInvocation node) {
     SuperConstructorInvocation copy = new SuperConstructorInvocation(
-        _mapToken(node.superKeyword), _mapToken(node.period),
-        _cloneNode(node.constructorName), _cloneNode(node.argumentList));
+        _mapToken(node.superKeyword),
+        _mapToken(node.period),
+        _cloneNode(node.constructorName),
+        _cloneNode(node.argumentList));
     copy.staticElement = node.staticElement;
     return copy;
   }
@@ -10189,21 +10590,29 @@
 
   @override
   SwitchCase visitSwitchCase(SwitchCase node) => new SwitchCase(
-      _cloneNodeList(node.labels), _mapToken(node.keyword),
-      _cloneNode(node.expression), _mapToken(node.colon),
+      _cloneNodeList(node.labels),
+      _mapToken(node.keyword),
+      _cloneNode(node.expression),
+      _mapToken(node.colon),
       _cloneNodeList(node.statements));
 
   @override
   SwitchDefault visitSwitchDefault(SwitchDefault node) => new SwitchDefault(
-      _cloneNodeList(node.labels), _mapToken(node.keyword),
-      _mapToken(node.colon), _cloneNodeList(node.statements));
+      _cloneNodeList(node.labels),
+      _mapToken(node.keyword),
+      _mapToken(node.colon),
+      _cloneNodeList(node.statements));
 
   @override
   SwitchStatement visitSwitchStatement(SwitchStatement node) =>
-      new SwitchStatement(_mapToken(node.switchKeyword),
-          _mapToken(node.leftParenthesis), _cloneNode(node.expression),
-          _mapToken(node.rightParenthesis), _mapToken(node.leftBracket),
-          _cloneNodeList(node.members), _mapToken(node.rightBracket));
+      new SwitchStatement(
+          _mapToken(node.switchKeyword),
+          _mapToken(node.leftParenthesis),
+          _cloneNode(node.expression),
+          _mapToken(node.rightParenthesis),
+          _mapToken(node.leftBracket),
+          _cloneNodeList(node.members),
+          _mapToken(node.rightBracket));
 
   @override
   AstNode visitSymbolLiteral(SymbolLiteral node) {
@@ -10233,14 +10642,19 @@
 
   @override
   TopLevelVariableDeclaration visitTopLevelVariableDeclaration(
-      TopLevelVariableDeclaration node) => new TopLevelVariableDeclaration(
-      _cloneNode(node.documentationComment), _cloneNodeList(node.metadata),
-      _cloneNode(node.variables), _mapToken(node.semicolon));
+          TopLevelVariableDeclaration node) =>
+      new TopLevelVariableDeclaration(
+          _cloneNode(node.documentationComment),
+          _cloneNodeList(node.metadata),
+          _cloneNode(node.variables),
+          _mapToken(node.semicolon));
 
   @override
   TryStatement visitTryStatement(TryStatement node) => new TryStatement(
-      _mapToken(node.tryKeyword), _cloneNode(node.body),
-      _cloneNodeList(node.catchClauses), _mapToken(node.finallyKeyword),
+      _mapToken(node.tryKeyword),
+      _cloneNode(node.body),
+      _cloneNodeList(node.catchClauses),
+      _mapToken(node.finallyKeyword),
       _cloneNode(node.finallyBlock));
 
   @override
@@ -10258,8 +10672,10 @@
 
   @override
   TypeParameter visitTypeParameter(TypeParameter node) => new TypeParameter(
-      _cloneNode(node.documentationComment), _cloneNodeList(node.metadata),
-      _cloneNode(node.name), _mapToken(node.extendsKeyword),
+      _cloneNode(node.documentationComment),
+      _cloneNodeList(node.metadata),
+      _cloneNode(node.name),
+      _mapToken(node.extendsKeyword),
       _cloneNode(node.bound));
 
   @override
@@ -10274,19 +10690,26 @@
 
   @override
   VariableDeclarationList visitVariableDeclarationList(
-      VariableDeclarationList node) => new VariableDeclarationList(null,
-      _cloneNodeList(node.metadata), _mapToken(node.keyword),
-      _cloneNode(node.type), _cloneNodeList(node.variables));
+          VariableDeclarationList node) =>
+      new VariableDeclarationList(
+          null,
+          _cloneNodeList(node.metadata),
+          _mapToken(node.keyword),
+          _cloneNode(node.type),
+          _cloneNodeList(node.variables));
 
   @override
   VariableDeclarationStatement visitVariableDeclarationStatement(
-      VariableDeclarationStatement node) => new VariableDeclarationStatement(
-      _cloneNode(node.variables), _mapToken(node.semicolon));
+          VariableDeclarationStatement node) =>
+      new VariableDeclarationStatement(
+          _cloneNode(node.variables), _mapToken(node.semicolon));
 
   @override
   WhileStatement visitWhileStatement(WhileStatement node) => new WhileStatement(
-      _mapToken(node.whileKeyword), _mapToken(node.leftParenthesis),
-      _cloneNode(node.condition), _mapToken(node.rightParenthesis),
+      _mapToken(node.whileKeyword),
+      _mapToken(node.leftParenthesis),
+      _cloneNode(node.condition),
+      _mapToken(node.rightParenthesis),
       _cloneNode(node.body));
 
   @override
@@ -10295,8 +10718,10 @@
 
   @override
   YieldStatement visitYieldStatement(YieldStatement node) => new YieldStatement(
-      _mapToken(node.yieldKeyword), _mapToken(node.star),
-      _cloneNode(node.expression), _mapToken(node.semicolon));
+      _mapToken(node.yieldKeyword),
+      _mapToken(node.star),
+      _cloneNode(node.expression),
+      _mapToken(node.semicolon));
 
   AstNode _cloneNode(AstNode node) {
     if (node == null) {
@@ -11579,10 +12004,17 @@
    * method does not implement an operator. The [parameters] must be `null` if
    * this method declares a getter.
    */
-  MethodDeclaration(Comment comment, List<Annotation> metadata,
-      this.externalKeyword, this.modifierKeyword, TypeName returnType,
-      this.propertyKeyword, this.operatorKeyword, SimpleIdentifier name,
-      TypeParameterList typeParameters, FormalParameterList parameters,
+  MethodDeclaration(
+      Comment comment,
+      List<Annotation> metadata,
+      this.externalKeyword,
+      this.modifierKeyword,
+      TypeName returnType,
+      this.propertyKeyword,
+      this.operatorKeyword,
+      SimpleIdentifier name,
+      TypeParameterList typeParameters,
+      FormalParameterList parameters,
       FunctionBody body)
       : super(comment, metadata) {
     _returnType = _becomeParentOf(returnType);
@@ -11786,8 +12218,11 @@
    * Initialize a newly created method invocation. The [target] and [operator]
    * can be `null` if there is no target.
    */
-  MethodInvocation(Expression target, this.operator,
-      SimpleIdentifier methodName, TypeArgumentList typeArguments,
+  MethodInvocation(
+      Expression target,
+      this.operator,
+      SimpleIdentifier methodName,
+      TypeArgumentList typeArguments,
       ArgumentList argumentList) {
     _target = _becomeParentOf(target);
     _methodName = _becomeParentOf(methodName);
@@ -16014,7 +16449,8 @@
 
   @override
   R visitRedirectingConstructorInvocation(
-      RedirectingConstructorInvocation node) => null;
+          RedirectingConstructorInvocation node) =>
+      null;
 
   @override
   R visitRethrowExpression(RethrowExpression node) => null;
@@ -17235,9 +17671,14 @@
    * Initialize a newly created switch statement. The list of [members] can be
    * `null` if there are no switch members.
    */
-  SwitchStatement(this.switchKeyword, this.leftParenthesis,
-      Expression expression, this.rightParenthesis, this.leftBracket,
-      List<SwitchMember> members, this.rightBracket) {
+  SwitchStatement(
+      this.switchKeyword,
+      this.leftParenthesis,
+      Expression expression,
+      this.rightParenthesis,
+      this.leftBracket,
+      List<SwitchMember> members,
+      this.rightBracket) {
     _expression = _becomeParentOf(expression);
     _members = new NodeList<SwitchMember>(this, members);
   }
@@ -19458,7 +19899,8 @@
 
   @override
   R visitRedirectingConstructorInvocation(
-      RedirectingConstructorInvocation node) => visitNode(node);
+          RedirectingConstructorInvocation node) =>
+      visitNode(node);
 
   @override
   R visitRethrowExpression(RethrowExpression node) => visitNode(node);
diff --git a/pkg/analyzer/lib/src/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
index 999ae5b..93186c6 100644
--- a/pkg/analyzer/lib/src/generated/constant.dart
+++ b/pkg/analyzer/lib/src/generated/constant.dart
@@ -240,8 +240,8 @@
   ConstantEvaluationEngine(TypeProvider typeProvider, this._declaredVariables,
       {ConstantEvaluationValidator validator})
       : validator = validator != null
-          ? validator
-          : new ConstantEvaluationValidator_ForProduction(),
+            ? validator
+            : new ConstantEvaluationValidator_ForProduction(),
         typeSystem = new TypeSystemImpl(typeProvider);
 
   /**
@@ -258,7 +258,8 @@
    * "defaultValue" is always allowed to be null. Return `true` if the arguments
    * are correct, `false` if there is an error.
    */
-  bool checkFromEnvironmentArguments(NodeList<Expression> arguments,
+  bool checkFromEnvironmentArguments(
+      NodeList<Expression> arguments,
       List<DartObjectImpl> argumentValues,
       HashMap<String, DartObjectImpl> namedArgumentValues,
       InterfaceType expectedDefaultValueType) {
@@ -297,7 +298,8 @@
    * named arguments. Return `true` if the arguments are correct, `false` if
    * there is an error.
    */
-  bool checkSymbolArguments(NodeList<Expression> arguments,
+  bool checkSymbolArguments(
+      NodeList<Expression> arguments,
       List<DartObjectImpl> argumentValues,
       HashMap<String, DartObjectImpl> namedArgumentValues) {
     if (arguments.length != 1) {
@@ -349,7 +351,8 @@
           if (!runtimeTypeMatch(dartObject, constant.type)) {
             errorReporter.reportErrorForElement(
                 CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH,
-                constant, [dartObject.type, constant.type]);
+                constant,
+                [dartObject.type, constant.type]);
           }
         }
         (constant as VariableElementImpl).evaluationResult =
@@ -397,8 +400,11 @@
               errorListener, sourceCompilationUnit.element.source);
           ConstantVisitor constantVisitor =
               new ConstantVisitor(this, errorReporter);
-          DartObjectImpl result = evaluateConstructorCall(constNode,
-              constNode.arguments.arguments, element, constantVisitor,
+          DartObjectImpl result = evaluateConstructorCall(
+              constNode,
+              constNode.arguments.arguments,
+              element,
+              constantVisitor,
               errorReporter);
           elementAnnotation.evaluationResult =
               new EvaluationResultImpl(result, errorListener.errors);
@@ -543,7 +549,8 @@
    * fromEnvironment(). Return a [DartObjectImpl] object corresponding to the
    * evaluated result.
    */
-  DartObjectImpl computeValueFromEnvironment(DartObject environmentValue,
+  DartObjectImpl computeValueFromEnvironment(
+      DartObject environmentValue,
       DartObjectImpl builtInDefaultValue,
       HashMap<String, DartObjectImpl> namedArgumentValues) {
     DartObjectImpl value = environmentValue as DartObjectImpl;
@@ -570,9 +577,12 @@
     return value;
   }
 
-  DartObjectImpl evaluateConstructorCall(AstNode node,
-      NodeList<Expression> arguments, ConstructorElement constructor,
-      ConstantVisitor constantVisitor, ErrorReporter errorReporter) {
+  DartObjectImpl evaluateConstructorCall(
+      AstNode node,
+      NodeList<Expression> arguments,
+      ConstructorElement constructor,
+      ConstantVisitor constantVisitor,
+      ErrorReporter errorReporter) {
     if (!_getConstructorBase(constructor).isCycleFree) {
       // It's not safe to evaluate this constructor, so bail out.
       // TODO(paulberry): ensure that a reasonable error message is produced
@@ -621,21 +631,24 @@
           DartObject valueFromEnvironment;
           valueFromEnvironment =
               _declaredVariables.getBool(typeProvider, variableName);
-          return computeValueFromEnvironment(valueFromEnvironment,
+          return computeValueFromEnvironment(
+              valueFromEnvironment,
               new DartObjectImpl(typeProvider.boolType, BoolState.FALSE_STATE),
               namedArgumentValues);
         } else if (identical(definingClass, typeProvider.intType)) {
           DartObject valueFromEnvironment;
           valueFromEnvironment =
               _declaredVariables.getInt(typeProvider, variableName);
-          return computeValueFromEnvironment(valueFromEnvironment,
+          return computeValueFromEnvironment(
+              valueFromEnvironment,
               new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE),
               namedArgumentValues);
         } else if (identical(definingClass, typeProvider.stringType)) {
           DartObject valueFromEnvironment;
           valueFromEnvironment =
               _declaredVariables.getString(typeProvider, variableName);
-          return computeValueFromEnvironment(valueFromEnvironment,
+          return computeValueFromEnvironment(
+              valueFromEnvironment,
               new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE),
               namedArgumentValues);
         }
@@ -687,7 +700,8 @@
         if (fieldValue != null && !runtimeTypeMatch(fieldValue, fieldType)) {
           errorReporter.reportErrorForNode(
               CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH,
-              node, [fieldValue.type, field.name, fieldType]);
+              node,
+              [fieldValue.type, field.name, fieldType]);
         }
         fieldMap[field.name] = evaluationResult.value;
       }
@@ -734,7 +748,8 @@
         if (!runtimeTypeMatch(argumentValue, parameter.type)) {
           errorReporter.reportErrorForNode(
               CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH,
-              errorTarget, [argumentValue.type, parameter.type]);
+              errorTarget,
+              [argumentValue.type, parameter.type]);
         }
         if (baseParameter.isInitializingFormal) {
           FieldElement field = (parameter as FieldFormalParameterElement).field;
@@ -747,7 +762,8 @@
               if (!runtimeTypeMatch(argumentValue, fieldType)) {
                 errorReporter.reportErrorForNode(
                     CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH,
-                    errorTarget, [argumentValue.type, fieldType]);
+                    errorTarget,
+                    [argumentValue.type, fieldType]);
               }
             }
             String fieldName = field.name;
@@ -764,7 +780,8 @@
       }
     }
     ConstantVisitor initializerVisitor = new ConstantVisitor(
-        this, errorReporter, lexicalEnvironment: parameterMap);
+        this, errorReporter,
+        lexicalEnvironment: parameterMap);
     String superName = null;
     NodeList<Expression> superArguments = null;
     for (ConstructorInitializer initializer in initializers) {
@@ -787,7 +804,8 @@
             if (!runtimeTypeMatch(evaluationResult, field.type)) {
               errorReporter.reportErrorForNode(
                   CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH,
-                  node, [evaluationResult.type, fieldName, field.type]);
+                  node,
+                  [evaluationResult.type, fieldName, field.type]);
             }
           }
         }
@@ -803,9 +821,12 @@
         // it redirects to.
         ConstructorElement constructor = initializer.staticElement;
         if (constructor != null && constructor.isConst) {
-          return evaluateConstructorCall(node,
-              initializer.argumentList.arguments, constructor,
-              initializerVisitor, errorReporter);
+          return evaluateConstructorCall(
+              node,
+              initializer.argumentList.arguments,
+              constructor,
+              initializerVisitor,
+              errorReporter);
         }
       }
     }
@@ -825,10 +846,13 @@
     return new DartObjectImpl(definingClass, new GenericState(fieldMap));
   }
 
-  void evaluateSuperConstructorCall(AstNode node,
+  void evaluateSuperConstructorCall(
+      AstNode node,
       HashMap<String, DartObjectImpl> fieldMap,
-      ConstructorElement superConstructor, NodeList<Expression> superArguments,
-      ConstantVisitor initializerVisitor, ErrorReporter errorReporter) {
+      ConstructorElement superConstructor,
+      NodeList<Expression> superArguments,
+      ConstantVisitor initializerVisitor,
+      ErrorReporter errorReporter) {
     if (superConstructor != null && superConstructor.isConst) {
       DartObjectImpl evaluationResult = evaluateConstructorCall(node,
           superArguments, superConstructor, initializerVisitor, errorReporter);
@@ -1282,7 +1306,8 @@
       DeclaredVariables declaredVariables,
       [ConstantEvaluationValidator validator])
       : evaluationEngine = new ConstantEvaluationEngine(
-          typeProvider, declaredVariables, validator: validator);
+            typeProvider, declaredVariables,
+            validator: validator);
 
   /**
    * Add the constants in the given compilation [unit] to the list of constants
@@ -2590,9 +2615,10 @@
    * Throws an [EvaluationException] if the operator is not appropriate for an
    * object of this kind.
    */
-  DartObjectImpl greaterThanOrEqual(TypeProvider typeProvider,
-      DartObjectImpl rightOperand) => new DartObjectImpl(
-      typeProvider.boolType, _state.greaterThanOrEqual(rightOperand._state));
+  DartObjectImpl greaterThanOrEqual(
+          TypeProvider typeProvider, DartObjectImpl rightOperand) =>
+      new DartObjectImpl(typeProvider.boolType,
+          _state.greaterThanOrEqual(rightOperand._state));
 
   /**
    * Return the result of invoking the '~/' operator on this object with the
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 1e5794a..ab8fe91 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -161,20 +161,20 @@
             _lookUpMethod(leftHandSide, propagatedType, methodName);
         node.propagatedElement = propagatedMethod;
         if (_shouldReportMissingMember(staticType, staticMethod)) {
-          _recordUndefinedToken(staticType.element,
-              StaticTypeWarningCode.UNDEFINED_METHOD, operator, [
-            methodName,
-            staticType.displayName
-          ]);
+          _recordUndefinedToken(
+              staticType.element,
+              StaticTypeWarningCode.UNDEFINED_METHOD,
+              operator,
+              [methodName, staticType.displayName]);
         } else if (_enableHints &&
             _shouldReportMissingMember(propagatedType, propagatedMethod) &&
             !_memberFoundInSubclass(
                 propagatedType.element, methodName, true, false)) {
-          _recordUndefinedToken(propagatedType.element,
-              HintCode.UNDEFINED_METHOD, operator, [
-            methodName,
-            propagatedType.displayName
-          ]);
+          _recordUndefinedToken(
+              propagatedType.element,
+              HintCode.UNDEFINED_METHOD,
+              operator,
+              [methodName, propagatedType.displayName]);
         }
       }
     }
@@ -203,6 +203,7 @@
     setMetadata(node.element, node);
     return null;
   }
+
   @override
   Object visitClassTypeAlias(ClassTypeAlias node) {
     setMetadata(node.element, node);
@@ -494,8 +495,13 @@
       node.staticElement = setterStaticMethod;
       node.propagatedElement = setterPropagatedMethod;
       // generate undefined method warning
-      _checkForUndefinedIndexOperator(node, target, getterMethodName,
-          setterStaticMethod, setterPropagatedMethod, staticType,
+      _checkForUndefinedIndexOperator(
+          node,
+          target,
+          getterMethodName,
+          setterStaticMethod,
+          setterPropagatedMethod,
+          staticType,
           propagatedType);
       // lookup getter method
       MethodElement getterStaticMethod =
@@ -507,8 +513,13 @@
           new AuxiliaryElements(getterStaticMethod, getterPropagatedMethod);
       node.auxiliaryElements = auxiliaryElements;
       // generate undefined method warning
-      _checkForUndefinedIndexOperator(node, target, getterMethodName,
-          getterStaticMethod, getterPropagatedMethod, staticType,
+      _checkForUndefinedIndexOperator(
+          node,
+          target,
+          getterMethodName,
+          getterStaticMethod,
+          getterPropagatedMethod,
+          staticType,
           propagatedType);
     } else if (isInGetterContext) {
       // lookup getter method
@@ -592,7 +603,8 @@
         _isDeferredPrefix(target)) {
       if (node.operator.type == sc.TokenType.QUESTION_PERIOD) {
         _resolver.reportErrorForNode(
-            CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT, target,
+            CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
+            target,
             [(target as SimpleIdentifier).name]);
       }
       LibraryElement importedLibrary = _getImportedLibrary(target);
@@ -721,10 +733,8 @@
         ErrorCode proxyErrorCode = (generatedWithTypePropagation
             ? HintCode.UNDEFINED_METHOD
             : StaticTypeWarningCode.UNDEFINED_METHOD);
-        _recordUndefinedNode(targetType.element, proxyErrorCode, methodName, [
-          methodName.name,
-          targetTypeName
-        ]);
+        _recordUndefinedNode(targetType.element, proxyErrorCode, methodName,
+            [methodName.name, targetTypeName]);
       }
     } else if (identical(
         errorCode, StaticTypeWarningCode.UNDEFINED_SUPER_METHOD)) {
@@ -766,17 +776,17 @@
     node.propagatedElement = propagatedMethod;
     if (_shouldReportMissingMember(staticType, staticMethod)) {
       if (operand is SuperExpression) {
-        _recordUndefinedToken(staticType.element,
-            StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR, node.operator, [
-          methodName,
-          staticType.displayName
-        ]);
+        _recordUndefinedToken(
+            staticType.element,
+            StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR,
+            node.operator,
+            [methodName, staticType.displayName]);
       } else {
-        _recordUndefinedToken(staticType.element,
-            StaticTypeWarningCode.UNDEFINED_OPERATOR, node.operator, [
-          methodName,
-          staticType.displayName
-        ]);
+        _recordUndefinedToken(
+            staticType.element,
+            StaticTypeWarningCode.UNDEFINED_OPERATOR,
+            node.operator,
+            [methodName, staticType.displayName]);
       }
     } else if (_enableHints &&
         _shouldReportMissingMember(propagatedType, propagatedMethod) &&
@@ -879,27 +889,27 @@
       node.propagatedElement = propagatedMethod;
       if (_shouldReportMissingMember(staticType, staticMethod)) {
         if (operand is SuperExpression) {
-          _recordUndefinedToken(staticType.element,
-              StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR, operator, [
-            methodName,
-            staticType.displayName
-          ]);
+          _recordUndefinedToken(
+              staticType.element,
+              StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR,
+              operator,
+              [methodName, staticType.displayName]);
         } else {
-          _recordUndefinedToken(staticType.element,
-              StaticTypeWarningCode.UNDEFINED_OPERATOR, operator, [
-            methodName,
-            staticType.displayName
-          ]);
+          _recordUndefinedToken(
+              staticType.element,
+              StaticTypeWarningCode.UNDEFINED_OPERATOR,
+              operator,
+              [methodName, staticType.displayName]);
         }
       } else if (_enableHints &&
           _shouldReportMissingMember(propagatedType, propagatedMethod) &&
           !_memberFoundInSubclass(
               propagatedType.element, methodName, true, false)) {
-        _recordUndefinedToken(propagatedType.element,
-            HintCode.UNDEFINED_OPERATOR, operator, [
-          methodName,
-          propagatedType.displayName
-        ]);
+        _recordUndefinedToken(
+            propagatedType.element,
+            HintCode.UNDEFINED_OPERATOR,
+            operator,
+            [methodName, propagatedType.displayName]);
       }
     }
     return null;
@@ -1005,7 +1015,8 @@
             CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
       } else if (element is PrefixElement) {
         _resolver.reportErrorForNode(
-            CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT, node,
+            CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
+            node,
             [element.name]);
       } else {
         _recordUndefinedNode(_resolver.enclosingClass,
@@ -1052,14 +1063,14 @@
             !enclosingClass.isSuperConstructorAccessible(element))) {
       if (name != null) {
         _resolver.reportErrorForNode(
-            CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER, node, [
-          superType.displayName,
-          name
-        ]);
+            CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER,
+            node,
+            [superType.displayName, name]);
       } else {
         _resolver.reportErrorForNode(
             CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT,
-            node, [superType.displayName]);
+            node,
+            [superType.displayName]);
       }
       return null;
     } else {
@@ -1197,9 +1208,13 @@
    * the target of the expression. The [methodName] is the name of the operator
    * associated with the context of using of the given index expression.
    */
-  bool _checkForUndefinedIndexOperator(IndexExpression expression,
-      Expression target, String methodName, MethodElement staticMethod,
-      MethodElement propagatedMethod, DartType staticType,
+  bool _checkForUndefinedIndexOperator(
+      IndexExpression expression,
+      Expression target,
+      String methodName,
+      MethodElement staticMethod,
+      MethodElement propagatedMethod,
+      DartType staticType,
       DartType propagatedType) {
     bool shouldReportMissingMember_static =
         _shouldReportMissingMember(staticType, staticMethod);
@@ -1226,17 +1241,13 @@
       DartType type =
           shouldReportMissingMember_static ? staticType : propagatedType;
       if (leftBracket == null || rightBracket == null) {
-        _recordUndefinedNode(type.element, errorCode, expression, [
-          methodName,
-          type.displayName
-        ]);
+        _recordUndefinedNode(type.element, errorCode, expression,
+            [methodName, type.displayName]);
       } else {
         int offset = leftBracket.offset;
         int length = rightBracket.offset - offset + 1;
-        _recordUndefinedOffset(type.element, errorCode, offset, length, [
-          methodName,
-          type.displayName
-        ]);
+        _recordUndefinedOffset(type.element, errorCode, offset, length,
+            [methodName, type.displayName]);
       }
       return true;
     }
@@ -1581,8 +1592,10 @@
    * been examined, used to prevent infinite recursion and to optimize the
    * search.
    */
-  PropertyAccessorElement _lookUpGetterInInterfaces(InterfaceType targetType,
-      bool includeTargetType, String getterName,
+  PropertyAccessorElement _lookUpGetterInInterfaces(
+      InterfaceType targetType,
+      bool includeTargetType,
+      String getterName,
       HashSet<ClassElement> visitedInterfaces) {
     // TODO(brianwilkerson) This isn't correct. Section 8.1.1 of the
     // specification (titled "Inheritance and Overriding" under "Interfaces")
@@ -1655,8 +1668,10 @@
    * interfaces that have been examined, used to prevent infinite recursion and
    * to optimize the search.
    */
-  ExecutableElement _lookUpGetterOrMethodInInterfaces(InterfaceType targetType,
-      bool includeTargetType, String memberName,
+  ExecutableElement _lookUpGetterOrMethodInInterfaces(
+      InterfaceType targetType,
+      bool includeTargetType,
+      String memberName,
       HashSet<ClassElement> visitedInterfaces) {
     // TODO(brianwilkerson) This isn't correct. Section 8.1.1 of the
     // specification (titled "Inheritance and Overriding" under "Interfaces")
@@ -1736,8 +1751,10 @@
    * been examined, used to prevent infinite recursion and to optimize the
    * search.
    */
-  MethodElement _lookUpMethodInInterfaces(InterfaceType targetType,
-      bool includeTargetType, String methodName,
+  MethodElement _lookUpMethodInInterfaces(
+      InterfaceType targetType,
+      bool includeTargetType,
+      String methodName,
       HashSet<ClassElement> visitedInterfaces) {
     // TODO(brianwilkerson) This isn't correct. Section 8.1.1 of the
     // specification (titled "Inheritance and Overriding" under "Interfaces")
@@ -1814,8 +1831,10 @@
    * been examined, used to prevent infinite recursion and to optimize the
    * search.
    */
-  PropertyAccessorElement _lookUpSetterInInterfaces(InterfaceType targetType,
-      bool includeTargetType, String setterName,
+  PropertyAccessorElement _lookUpSetterInInterfaces(
+      InterfaceType targetType,
+      bool includeTargetType,
+      String setterName,
       HashSet<ClassElement> visitedInterfaces) {
     // TODO(brianwilkerson) This isn't correct. Section 8.1.1 of the
     // specification (titled "Inheritance and Overriding" under "Interfaces")
@@ -2011,8 +2030,8 @@
       // Class(args)
       if (element1 is ClassElement) {
         ClassElement classElement = element1;
-        constructor = new InterfaceTypeImpl(classElement).lookUpConstructor(
-            null, _definingLibrary);
+        constructor = new InterfaceTypeImpl(classElement)
+            .lookUpConstructor(null, _definingLibrary);
       }
     }
     //
@@ -2040,8 +2059,8 @@
       // Class.constructor(args)
       if (element1 is ClassElement) {
         ClassElement classElement = element1;
-        constructor = new InterfaceTypeImpl(classElement).lookUpConstructor(
-            nameNode2.name, _definingLibrary);
+        constructor = new InterfaceTypeImpl(classElement)
+            .lookUpConstructor(nameNode2.name, _definingLibrary);
         nameNode2.staticElement = constructor;
       }
     }
@@ -2064,8 +2083,8 @@
           return;
         }
         // prefix.Class.constructor(args)
-        constructor = new InterfaceTypeImpl(classElement).lookUpConstructor(
-            name3, _definingLibrary);
+        constructor = new InterfaceTypeImpl(classElement)
+            .lookUpConstructor(name3, _definingLibrary);
         nameNode3.staticElement = constructor;
       }
     }
@@ -2188,19 +2207,15 @@
       ErrorCode errorCode = (reportError
           ? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS
           : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS);
-      _resolver.reportErrorForNode(errorCode, argumentList, [
-        requiredParameters.length,
-        positionalArgumentCount
-      ]);
+      _resolver.reportErrorForNode(errorCode, argumentList,
+          [requiredParameters.length, positionalArgumentCount]);
     } else if (positionalArgumentCount > unnamedParameterCount &&
         noBlankArguments) {
       ErrorCode errorCode = (reportError
           ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS
           : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS);
-      _resolver.reportErrorForNode(errorCode, argumentList, [
-        unnamedParameterCount,
-        positionalArgumentCount
-      ]);
+      _resolver.reportErrorForNode(errorCode, argumentList,
+          [unnamedParameterCount, positionalArgumentCount]);
     }
     return resolvedParameters;
   }
@@ -2218,27 +2233,27 @@
       node.propagatedElement = propagatedMethod;
       if (_shouldReportMissingMember(staticType, staticMethod)) {
         if (leftOperand is SuperExpression) {
-          _recordUndefinedToken(staticType.element,
-              StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR, node.operator, [
-            methodName,
-            staticType.displayName
-          ]);
+          _recordUndefinedToken(
+              staticType.element,
+              StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR,
+              node.operator,
+              [methodName, staticType.displayName]);
         } else {
-          _recordUndefinedToken(staticType.element,
-              StaticTypeWarningCode.UNDEFINED_OPERATOR, node.operator, [
-            methodName,
-            staticType.displayName
-          ]);
+          _recordUndefinedToken(
+              staticType.element,
+              StaticTypeWarningCode.UNDEFINED_OPERATOR,
+              node.operator,
+              [methodName, staticType.displayName]);
         }
       } else if (_enableHints &&
           _shouldReportMissingMember(propagatedType, propagatedMethod) &&
           !_memberFoundInSubclass(
               propagatedType.element, methodName, true, false)) {
-        _recordUndefinedToken(propagatedType.element,
-            HintCode.UNDEFINED_OPERATOR, node.operator, [
-          methodName,
-          propagatedType.displayName
-        ]);
+        _recordUndefinedToken(
+            propagatedType.element,
+            HintCode.UNDEFINED_OPERATOR,
+            node.operator,
+            [methodName, propagatedType.displayName]);
       }
     }
   }
@@ -2371,7 +2386,8 @@
         if (isConditional) {
           _resolver.reportErrorForNode(
               CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
-              target, [target.name]);
+              target,
+              [target.name]);
         }
         //
         // Look to see whether the name of the method is really part of a
@@ -2480,7 +2496,8 @@
             return;
           } else if (classElement.isEnum && propertyName.name == "_name") {
             _resolver.reportErrorForNode(
-                CompileTimeErrorCode.ACCESS_PRIVATE_ENUM_FIELD, propertyName,
+                CompileTimeErrorCode.ACCESS_PRIVATE_ENUM_FIELD,
+                propertyName,
                 [propertyName.name]);
             return;
           }
@@ -2507,10 +2524,8 @@
         } else {
           errorCode = HintCode.UNDEFINED_SETTER;
         }
-        _recordUndefinedNode(declaringElement, errorCode, propertyName, [
-          propertyName.name,
-          displayType.displayName
-        ]);
+        _recordUndefinedNode(declaringElement, errorCode, propertyName,
+            [propertyName.name, displayType.displayName]);
       } else if (propertyName.inGetterContext()) {
         ErrorCode errorCode;
         if (shouldReportMissingMember_static) {
@@ -2530,13 +2545,13 @@
         } else {
           errorCode = HintCode.UNDEFINED_GETTER;
         }
-        _recordUndefinedNode(declaringElement, errorCode, propertyName, [
-          propertyName.name,
-          displayType.displayName
-        ]);
+        _recordUndefinedNode(declaringElement, errorCode, propertyName,
+            [propertyName.name, displayType.displayName]);
       } else {
-        _recordUndefinedNode(declaringElement,
-            StaticWarningCode.UNDEFINED_IDENTIFIER, propertyName,
+        _recordUndefinedNode(
+            declaringElement,
+            StaticWarningCode.UNDEFINED_IDENTIFIER,
+            propertyName,
             [propertyName.name]);
       }
     }
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 5eccbf7..c0e548c 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -10309,6 +10309,12 @@
  * used to visit that structure.
  */
 class ResolutionEraser extends GeneralizingAstVisitor<Object> {
+  /**
+   * A flag indicating whether the elements associated with declarations should
+   * be erased.
+   */
+  bool eraseDeclarations = true;
+
   @override
   Object visitAssignmentExpression(AssignmentExpression node) {
     node.staticElement = null;
@@ -10331,13 +10337,17 @@
 
   @override
   Object visitCompilationUnit(CompilationUnit node) {
-    node.element = null;
+    if (eraseDeclarations) {
+      node.element = null;
+    }
     return super.visitCompilationUnit(node);
   }
 
   @override
   Object visitConstructorDeclaration(ConstructorDeclaration node) {
-    node.element = null;
+    if (eraseDeclarations) {
+      node.element = null;
+    }
     return super.visitConstructorDeclaration(node);
   }
 
@@ -10355,7 +10365,9 @@
 
   @override
   Object visitDirective(Directive node) {
-    node.element = null;
+    if (eraseDeclarations) {
+      node.element = null;
+    }
     return super.visitDirective(node);
   }
 
@@ -10368,7 +10380,9 @@
 
   @override
   Object visitFunctionExpression(FunctionExpression node) {
-    node.element = null;
+    if (eraseDeclarations) {
+      node.element = null;
+    }
     return super.visitFunctionExpression(node);
   }
 
@@ -10415,7 +10429,9 @@
 
   @override
   Object visitSimpleIdentifier(SimpleIdentifier node) {
-    node.staticElement = null;
+    if (eraseDeclarations || !node.inDeclarationContext()) {
+      node.staticElement = null;
+    }
     node.propagatedElement = null;
     return super.visitSimpleIdentifier(node);
   }
@@ -10429,8 +10445,10 @@
   /**
    * Remove any resolution information from the given AST structure.
    */
-  static void erase(AstNode node) {
-    node.accept(new ResolutionEraser());
+  static void erase(AstNode node, {bool eraseDeclarations: true}) {
+    ResolutionEraser eraser = new ResolutionEraser();
+    eraser.eraseDeclarations = eraseDeclarations;
+    node.accept(eraser);
   }
 }
 
diff --git a/pkg/analyzer/lib/src/generated/error.dart b/pkg/analyzer/lib/src/generated/error.dart
index 93d1ce8..b8ea0bf 100644
--- a/pkg/analyzer/lib/src/generated/error.dart
+++ b/pkg/analyzer/lib/src/generated/error.dart
@@ -28,14 +28,15 @@
    * was found.
    */
   static Comparator<AnalysisError> FILE_COMPARATOR = (AnalysisError o1,
-      AnalysisError o2) => o1.source.shortName.compareTo(o2.source.shortName);
+          AnalysisError o2) =>
+      o1.source.shortName.compareTo(o2.source.shortName);
 
   /**
    * A [Comparator] that sorts error codes first by their severity (errors
    * first, warnings second), and then by the the error code type.
    */
-  static Comparator<AnalysisError> ERROR_CODE_COMPARATOR = (AnalysisError o1,
-      AnalysisError o2) {
+  static Comparator<AnalysisError> ERROR_CODE_COMPARATOR =
+      (AnalysisError o1, AnalysisError o2) {
     ErrorCode errorCode1 = o1.errorCode;
     ErrorCode errorCode2 = o2.errorCode;
     ErrorSeverity errorSeverity1 = errorCode1.errorSeverity;
@@ -1560,7 +1561,8 @@
    * 0: the name of the constant that is missing
    */
   static const CompileTimeErrorCode MISSING_ENUM_CONSTANT_IN_SWITCH =
-      const CompileTimeErrorCode('MISSING_ENUM_CONSTANT_IN_SWITCH',
+      const CompileTimeErrorCode(
+          'MISSING_ENUM_CONSTANT_IN_SWITCH',
           "Missing case clause for '{0}'",
           "Add a case clause for the missing constant or add a default clause.");
 
@@ -1596,7 +1598,8 @@
    * https://code.google.com/p/dart/issues/detail?id=15101#c4
    */
   static const CompileTimeErrorCode MIXIN_HAS_NO_CONSTRUCTORS =
-      const CompileTimeErrorCode('MIXIN_HAS_NO_CONSTRUCTORS',
+      const CompileTimeErrorCode(
+          'MIXIN_HAS_NO_CONSTRUCTORS',
           "This mixin application is invalid because all of the constructors "
           "in the base class '{0}' have optional parameters.");
 
@@ -2353,6 +2356,62 @@
 }
 
 /**
+ * An error listener that can be enabled or disabled while executing a function.
+ */
+class DisablableErrorListener implements AnalysisErrorListener {
+  /**
+   * The listener to which errors will be reported if this listener is enabled.
+   */
+  final AnalysisErrorListener baseListener;
+
+  /**
+   * A flag indicating whether this listener is currently enabled.
+   */
+  bool enabled = true;
+
+  /**
+   * Initialize a newly created listener to report errors to the given
+   * [baseListener].
+   */
+  DisablableErrorListener(this.baseListener);
+
+  /**
+   * Disable the processing of errors while evaluating the given [function].
+   * Return the value returned by the function.
+   */
+  dynamic disableWhile(dynamic function()) {
+    bool wasEnabled = enabled;
+    try {
+      enabled = false;
+      return function();
+    } finally {
+      enabled = wasEnabled;
+    }
+  }
+
+  /**
+   * Disable the processing of errors while evaluating the given [function].
+   * Return the value returned by the function.
+   */
+  dynamic enableWhile(dynamic function()) {
+    bool wasEnabled = enabled;
+    try {
+      enabled = true;
+      return function();
+    } finally {
+      enabled = wasEnabled;
+    }
+  }
+
+  @override
+  void onError(AnalysisError error) {
+    if (enabled) {
+      baseListener.onError(error);
+    }
+  }
+}
+
+/**
  * An error code associated with an [AnalysisError].
  *
  * Generally, we want to provide messages that consist of three sentences. From
@@ -2885,7 +2944,8 @@
    * Parameters:
    * 0: the name of the declared return type
    */
-  static const HintCode MISSING_RETURN = const HintCode('MISSING_RETURN',
+  static const HintCode MISSING_RETURN = const HintCode(
+      'MISSING_RETURN',
       "This function declares a return type of '{0}', but does not end with a return statement",
       "Either add a return statement or change the return type to 'void'");
 
@@ -3728,7 +3788,8 @@
    * 2: the name of the second library that the type is found
    */
   static const StaticWarningCode AMBIGUOUS_IMPORT = const StaticWarningCode(
-      'AMBIGUOUS_IMPORT', "The name '{0}' is defined in the libraries {1}",
+      'AMBIGUOUS_IMPORT',
+      "The name '{0}' is defined in the libraries {1}",
       "Consider using 'as prefix' for one of the import directives "
       "or hiding the name from all but one of the imports.");
 
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 9624115..4b47c67 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -1125,7 +1125,8 @@
     }
     // report problem
     _errorReporter.reportErrorForNode(
-        StaticTypeWarningCode.EXPECTED_TWO_MAP_TYPE_ARGUMENTS, typeArguments,
+        StaticTypeWarningCode.EXPECTED_TWO_MAP_TYPE_ARGUMENTS,
+        typeArguments,
         [num]);
     return true;
   }
@@ -1171,14 +1172,16 @@
           if (fieldElement.isFinal || fieldElement.isConst) {
             _errorReporter.reportErrorForNode(
                 StaticWarningCode.FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR,
-                formalParameter.identifier, [fieldElement.displayName]);
+                formalParameter.identifier,
+                [fieldElement.displayName]);
             foundError = true;
           }
         } else if (state == INIT_STATE.INIT_IN_FIELD_FORMAL) {
           if (fieldElement.isFinal || fieldElement.isConst) {
             _errorReporter.reportErrorForNode(
                 CompileTimeErrorCode.FINAL_INITIALIZED_MULTIPLE_TIMES,
-                formalParameter.identifier, [fieldElement.displayName]);
+                formalParameter.identifier,
+                [fieldElement.displayName]);
             foundError = true;
           }
         }
@@ -1215,7 +1218,8 @@
           } else if (state == INIT_STATE.INIT_IN_INITIALIZERS) {
             _errorReporter.reportErrorForNode(
                 CompileTimeErrorCode.FIELD_INITIALIZED_BY_MULTIPLE_INITIALIZERS,
-                fieldName, [fieldElement.displayName]);
+                fieldName,
+                [fieldElement.displayName]);
             foundError = true;
           }
         }
@@ -1237,7 +1241,8 @@
         if (fieldElement.isConst) {
           _errorReporter.reportErrorForNode(
               CompileTimeErrorCode.CONST_NOT_INITIALIZED,
-              constructor.returnType, [fieldElement.name]);
+              constructor.returnType,
+              [fieldElement.name]);
           foundError = true;
         }
       }
@@ -1248,14 +1253,13 @@
       if (notInitFinalFields.length == 1) {
         analysisError = _errorReporter.newErrorWithProperties(
             StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1,
-            constructor.returnType, [notInitFinalFields[0].name]);
+            constructor.returnType,
+            [notInitFinalFields[0].name]);
       } else if (notInitFinalFields.length == 2) {
         analysisError = _errorReporter.newErrorWithProperties(
             StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2,
-            constructor.returnType, [
-          notInitFinalFields[0].name,
-          notInitFinalFields[1].name
-        ]);
+            constructor.returnType,
+            [notInitFinalFields[0].name, notInitFinalFields[1].name]);
       } else {
         analysisError = _errorReporter.newErrorWithProperties(
             StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS,
@@ -1292,8 +1296,10 @@
    */
   bool _checkForAllInvalidOverrideErrorCodes(
       ExecutableElement executableElement,
-      ExecutableElement overriddenExecutable, List<ParameterElement> parameters,
-      List<AstNode> parameterLocations, SimpleIdentifier errorNameTarget) {
+      ExecutableElement overriddenExecutable,
+      List<ParameterElement> parameters,
+      List<AstNode> parameterLocations,
+      SimpleIdentifier errorNameTarget) {
     bool isGetter = false;
     bool isSetter = false;
     if (executableElement is PropertyAccessorElement) {
@@ -1355,10 +1361,12 @@
     // SWC.INVALID_METHOD_OVERRIDE_RETURN_TYPE
     if (overriddenFTReturnType != VoidTypeImpl.instance &&
         !overridingFTReturnType.isAssignableTo(overriddenFTReturnType)) {
-      _errorReporter.reportTypeErrorForNode(!isGetter
+      _errorReporter.reportTypeErrorForNode(
+          !isGetter
               ? StaticWarningCode.INVALID_METHOD_OVERRIDE_RETURN_TYPE
               : StaticWarningCode.INVALID_GETTER_OVERRIDE_RETURN_TYPE,
-          errorNameTarget, [
+          errorNameTarget,
+          [
         overridingFTReturnType,
         overriddenFTReturnType,
         overriddenExecutable.enclosingElement.displayName
@@ -1372,10 +1380,12 @@
     int parameterIndex = 0;
     for (int i = 0; i < overridingNormalPT.length; i++) {
       if (!overridingNormalPT[i].isAssignableTo(overriddenNormalPT[i])) {
-        _errorReporter.reportTypeErrorForNode(!isSetter
+        _errorReporter.reportTypeErrorForNode(
+            !isSetter
                 ? StaticWarningCode.INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE
                 : StaticWarningCode.INVALID_SETTER_OVERRIDE_NORMAL_PARAM_TYPE,
-            parameterLocations[parameterIndex], [
+            parameterLocations[parameterIndex],
+            [
           overridingNormalPT[i],
           overriddenNormalPT[i],
           overriddenExecutable.enclosingElement.displayName
@@ -1555,8 +1565,10 @@
    * to report problems on.
    */
   bool _checkForAllInvalidOverrideErrorCodesForExecutable(
-      ExecutableElement executableElement, List<ParameterElement> parameters,
-      List<AstNode> parameterLocations, SimpleIdentifier errorNameTarget) {
+      ExecutableElement executableElement,
+      List<ParameterElement> parameters,
+      List<AstNode> parameterLocations,
+      SimpleIdentifier errorNameTarget) {
     //
     // Compute the overridden executable from the InheritanceManager
     //
@@ -1721,10 +1733,8 @@
         ErrorCode errorCode = (declaration.constKeyword != null
             ? CompileTimeErrorCode.REDIRECT_TO_MISSING_CONSTRUCTOR
             : StaticWarningCode.REDIRECT_TO_MISSING_CONSTRUCTOR);
-        _errorReporter.reportErrorForNode(errorCode, redirectedConstructor, [
-          constructorStrName,
-          redirectedType.displayName
-        ]);
+        _errorReporter.reportErrorForNode(errorCode, redirectedConstructor,
+            [constructorStrName, redirectedType.displayName]);
         return true;
       }
       return false;
@@ -1739,7 +1749,8 @@
     if (!redirectedReturnType.isAssignableTo(constructorReturnType)) {
       _errorReporter.reportErrorForNode(
           StaticWarningCode.REDIRECT_TO_INVALID_RETURN_TYPE,
-          redirectedConstructor, [redirectedReturnType, constructorReturnType]);
+          redirectedConstructor,
+          [redirectedReturnType, constructorReturnType]);
       return true;
     }
     //
@@ -1748,7 +1759,8 @@
     if (!redirectedType.isSubtypeOf(constructorType)) {
       _errorReporter.reportErrorForNode(
           StaticWarningCode.REDIRECT_TO_INVALID_FUNCTION_TYPE,
-          redirectedConstructor, [redirectedType, constructorType]);
+          redirectedConstructor,
+          [redirectedType, constructorType]);
       return true;
     }
     return false;
@@ -1830,8 +1842,8 @@
       Element element = definedNames[name];
       Element prevElement = _exportedElements[name];
       if (element != null && prevElement != null && prevElement != element) {
-        _errorReporter.reportErrorForNode(CompileTimeErrorCode.AMBIGUOUS_EXPORT,
-            directive, [
+        _errorReporter.reportErrorForNode(
+            CompileTimeErrorCode.AMBIGUOUS_EXPORT, directive, [
           name,
           prevElement.library.definingCompilationUnit.displayName,
           element.library.definingCompilationUnit.displayName
@@ -1861,8 +1873,10 @@
    * [StaticWarningCode.MAP_KEY_TYPE_NOT_ASSIGNABLE], and
    * [StaticWarningCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE].
    */
-  bool _checkForArgumentTypeNotAssignable(Expression expression,
-      DartType expectedStaticType, DartType actualStaticType,
+  bool _checkForArgumentTypeNotAssignable(
+      Expression expression,
+      DartType expectedStaticType,
+      DartType actualStaticType,
       ErrorCode errorCode) {
     //
     // Warning case: test static type information
@@ -1913,8 +1927,10 @@
    * [StaticWarningCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE].
    */
   bool _checkForArgumentTypeNotAssignableWithExpectedTypes(
-      Expression expression, DartType expectedStaticType,
-      ErrorCode errorCode) => _checkForArgumentTypeNotAssignable(
+          Expression expression,
+          DartType expectedStaticType,
+          ErrorCode errorCode) =>
+      _checkForArgumentTypeNotAssignable(
           expression, expectedStaticType, getStaticType(expression), errorCode);
 
   /**
@@ -1999,7 +2015,8 @@
             element.setter == null &&
             element.isSynthetic) {
           _errorReporter.reportErrorForNode(
-              StaticWarningCode.ASSIGNMENT_TO_FINAL_NO_SETTER, highlightedNode,
+              StaticWarningCode.ASSIGNMENT_TO_FINAL_NO_SETTER,
+              highlightedNode,
               [element.name, element.enclosingElement.displayName]);
           return true;
         }
@@ -2134,10 +2151,9 @@
       }
       if (overriddenMember == null) {
         _errorReporter.reportErrorForNode(
-            StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER, nameNode, [
-          memberName,
-          _enclosingClass.displayName
-        ]);
+            StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER,
+            nameNode,
+            [memberName, _enclosingClass.displayName]);
         return true;
       }
     }
@@ -2172,7 +2188,8 @@
               CompileTimeErrorCode.DUPLICATE_CONSTRUCTOR_DEFAULT, constructor);
         } else {
           _errorReporter.reportErrorForNode(
-              CompileTimeErrorCode.DUPLICATE_CONSTRUCTOR_NAME, constructor,
+              CompileTimeErrorCode.DUPLICATE_CONSTRUCTOR_NAME,
+              constructor,
               [name]);
         }
         return true;
@@ -2187,7 +2204,8 @@
       if (field != null) {
         _errorReporter.reportErrorForNode(
             CompileTimeErrorCode.CONFLICTING_CONSTRUCTOR_NAME_AND_FIELD,
-            constructor, [name]);
+            constructor,
+            [name]);
         return true;
       }
       // methods
@@ -2195,7 +2213,8 @@
       if (method != null) {
         _errorReporter.reportErrorForNode(
             CompileTimeErrorCode.CONFLICTING_CONSTRUCTOR_NAME_AND_METHOD,
-            constructor, [name]);
+            constructor,
+            [name]);
         return true;
       }
     }
@@ -2226,7 +2245,8 @@
       // report problem
       hasProblem = true;
       _errorReporter.reportErrorForOffset(
-          CompileTimeErrorCode.CONFLICTING_GETTER_AND_METHOD, method.nameOffset,
+          CompileTimeErrorCode.CONFLICTING_GETTER_AND_METHOD,
+          method.nameOffset,
           name.length, [
         _enclosingClass.displayName,
         inherited.enclosingElement.displayName,
@@ -2249,7 +2269,8 @@
       hasProblem = true;
       _errorReporter.reportErrorForOffset(
           CompileTimeErrorCode.CONFLICTING_METHOD_AND_GETTER,
-          accessor.nameOffset, name.length, [
+          accessor.nameOffset,
+          name.length, [
         _enclosingClass.displayName,
         inherited.enclosingElement.displayName,
         name
@@ -2315,11 +2336,13 @@
       if (getter) {
         _errorReporter.reportErrorForElement(
             StaticWarningCode.CONFLICTING_INSTANCE_GETTER_AND_SUPERCLASS_MEMBER,
-            accessor, [superElementType.displayName]);
+            accessor,
+            [superElementType.displayName]);
       } else {
         _errorReporter.reportErrorForElement(
             StaticWarningCode.CONFLICTING_INSTANCE_SETTER_AND_SUPERCLASS_MEMBER,
-            accessor, [superElementType.displayName]);
+            accessor,
+            [superElementType.displayName]);
       }
     }
     // done
@@ -2401,10 +2424,9 @@
               !conflictingMethod.isGetter) {
             // report problem
             _errorReporter.reportErrorForNode(
-                StaticWarningCode.CONFLICTING_INSTANCE_METHOD_SETTER2, name, [
-              _enclosingClass.displayName,
-              name.name
-            ]);
+                StaticWarningCode.CONFLICTING_INSTANCE_METHOD_SETTER2,
+                name,
+                [_enclosingClass.displayName, name.name]);
             foundError = true;
             addThisMemberToTheMap = false;
           }
@@ -2460,7 +2482,8 @@
     // report problem
     _errorReporter.reportErrorForNode(
         StaticWarningCode.CONFLICTING_STATIC_GETTER_AND_INSTANCE_SETTER,
-        nameNode, [setterType.displayName]);
+        nameNode,
+        [setterType.displayName]);
     return true;
   }
 
@@ -2508,7 +2531,8 @@
     // report problem
     _errorReporter.reportErrorForNode(
         StaticWarningCode.CONFLICTING_STATIC_SETTER_AND_INSTANCE_MEMBER,
-        nameNode, [memberType.displayName]);
+        nameNode,
+        [memberType.displayName]);
     return true;
   }
 
@@ -2528,7 +2552,9 @@
       if (_enclosingClass.name == name) {
         _errorReporter.reportErrorForOffset(
             CompileTimeErrorCode.CONFLICTING_TYPE_VARIABLE_AND_CLASS,
-            typeParameter.nameOffset, name.length, [name]);
+            typeParameter.nameOffset,
+            name.length,
+            [name]);
         problemReported = true;
       }
       // check members
@@ -2537,7 +2563,9 @@
           _enclosingClass.getSetter(name) != null) {
         _errorReporter.reportErrorForOffset(
             CompileTimeErrorCode.CONFLICTING_TYPE_VARIABLE_AND_MEMBER,
-            typeParameter.nameOffset, name.length, [name]);
+            typeParameter.nameOffset,
+            name.length,
+            [name]);
         problemReported = true;
       }
     }
@@ -2576,7 +2604,8 @@
         }
         _errorReporter.reportErrorForNode(
             CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_NON_CONST_SUPER,
-            superInvocation, [element.enclosingElement.displayName]);
+            superInvocation,
+            [element.enclosingElement.displayName]);
         return true;
       }
     }
@@ -2599,7 +2628,8 @@
     // default constructor is not 'const', report problem
     _errorReporter.reportErrorForNode(
         CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_NON_CONST_SUPER,
-        constructor.returnType, [supertype.displayName]);
+        constructor.returnType,
+        [supertype.displayName]);
     return true;
   }
 
@@ -2640,7 +2670,8 @@
       ConstructorName constructorName, TypeName typeName) {
     if (typeName.isDeferred) {
       _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.CONST_DEFERRED_CLASS, constructorName,
+          CompileTimeErrorCode.CONST_DEFERRED_CLASS,
+          constructorName,
           [typeName.name.name]);
       return true;
     }
@@ -2687,7 +2718,8 @@
    * [StaticWarningCode.NEW_WITH_ABSTRACT_CLASS].
    */
   bool _checkForConstOrNewWithAbstractClass(
-      InstanceCreationExpression expression, TypeName typeName,
+      InstanceCreationExpression expression,
+      TypeName typeName,
       InterfaceType type) {
     if (type.element.isAbstract) {
       ConstructorElement element = expression.staticElement;
@@ -2791,7 +2823,8 @@
    * [CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT].
    */
   bool _checkForConstWithUndefinedConstructor(
-      InstanceCreationExpression expression, ConstructorName constructorName,
+      InstanceCreationExpression expression,
+      ConstructorName constructorName,
       TypeName typeName) {
     // OK if resolved
     if (expression.staticElement != null) {
@@ -2810,14 +2843,14 @@
     SimpleIdentifier name = constructorName.name;
     if (name != null) {
       _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR, name, [
-        className,
-        name
-      ]);
+          CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR,
+          name,
+          [className, name]);
     } else {
       _errorReporter.reportErrorForNode(
           CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT,
-          constructorName, [className]);
+          constructorName,
+          [className]);
     }
     return true;
   }
@@ -2968,7 +3001,9 @@
     // report problem
     _errorReporter.reportErrorForOffset(
         CompileTimeErrorCode.DUPLICATE_DEFINITION_INHERITANCE,
-        staticMember.nameOffset, name.length, [name, displayName]);
+        staticMember.nameOffset,
+        name.length,
+        [name, displayName]);
     return true;
   }
 
@@ -2987,7 +3022,8 @@
     }
     // report problem
     _errorReporter.reportErrorForNode(
-        StaticTypeWarningCode.EXPECTED_ONE_LIST_TYPE_ARGUMENTS, typeArguments,
+        StaticTypeWarningCode.EXPECTED_ONE_LIST_TYPE_ARGUMENTS,
+        typeArguments,
         [num]);
     return true;
   }
@@ -3053,7 +3089,8 @@
     }
     // report problem
     _errorReporter.reportErrorForNode(
-        CompileTimeErrorCode.EXPORT_INTERNAL_LIBRARY, directive,
+        CompileTimeErrorCode.EXPORT_INTERNAL_LIBRARY,
+        directive,
         [directive.uri]);
     return true;
   }
@@ -3222,13 +3259,13 @@
       // constant, not the static type.  See dartbug.com/21119.
       _errorReporter.reportTypeErrorForNode(
           CheckedModeCompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE,
-          expression, [staticType, fieldType]);
+          expression,
+          [staticType, fieldType]);
     }
     _errorReporter.reportTypeErrorForNode(
-        StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE, expression, [
-      staticType,
-      fieldType
-    ]);
+        StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE,
+        expression,
+        [staticType, fieldType]);
     return true;
     // TODO(brianwilkerson) Define a hint corresponding to these errors and
     // report it if appropriate.
@@ -3308,11 +3345,13 @@
         if (variable.initializer == null) {
           if (list.isConst) {
             _errorReporter.reportErrorForNode(
-                CompileTimeErrorCode.CONST_NOT_INITIALIZED, variable.name,
+                CompileTimeErrorCode.CONST_NOT_INITIALIZED,
+                variable.name,
                 [variable.name.name]);
           } else if (list.isFinal) {
             _errorReporter.reportErrorForNode(
-                StaticWarningCode.FINAL_NOT_INITIALIZED, variable.name,
+                StaticWarningCode.FINAL_NOT_INITIALIZED,
+                variable.name,
                 [variable.name.name]);
           }
           foundError = true;
@@ -3560,7 +3599,8 @@
     }
     // report problem
     _errorReporter.reportErrorForNode(
-        CompileTimeErrorCode.IMPORT_INTERNAL_LIBRARY, directive,
+        CompileTimeErrorCode.IMPORT_INTERNAL_LIBRARY,
+        directive,
         [directive.uri]);
     return true;
   }
@@ -3619,7 +3659,8 @@
     }
     // report problem
     _errorReporter.reportErrorForNode(
-        StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER, name,
+        StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
+        name,
         [name.name]);
     return true;
   }
@@ -3660,10 +3701,8 @@
           if (fieldElt.isStatic) {
             _errorReporter.reportErrorForNode(
                 StaticWarningCode.INSTANCE_METHOD_NAME_COLLIDES_WITH_SUPERCLASS_STATIC,
-                errorNameTarget, [
-              executableElementName,
-              fieldElt.enclosingElement.displayName
-            ]);
+                errorNameTarget,
+                [executableElementName, fieldElt.enclosingElement.displayName]);
             return true;
           }
         }
@@ -3751,10 +3790,9 @@
     DartType staticRightType = getStaticType(rhs);
     if (!staticRightType.isAssignableTo(leftType)) {
       _errorReporter.reportTypeErrorForNode(
-          StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [
-        staticRightType,
-        leftType
-      ]);
+          StaticTypeWarningCode.INVALID_ASSIGNMENT,
+          rhs,
+          [staticRightType, leftType]);
       return true;
     }
     return false;
@@ -3805,15 +3843,18 @@
       if (fieldElement.isSynthetic) {
         _errorReporter.reportErrorForNode(
             CompileTimeErrorCode.INITIALIZER_FOR_NON_EXISTENT_FIELD,
-            initializer, [fieldName]);
+            initializer,
+            [fieldName]);
       } else if (fieldElement.isStatic) {
         _errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.INITIALIZER_FOR_STATIC_FIELD, initializer,
+            CompileTimeErrorCode.INITIALIZER_FOR_STATIC_FIELD,
+            initializer,
             [fieldName]);
       }
     } else {
       _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.INITIALIZER_FOR_NON_EXISTENT_FIELD, initializer,
+          CompileTimeErrorCode.INITIALIZER_FOR_NON_EXISTENT_FIELD,
+          initializer,
           [fieldName]);
       return;
     }
@@ -3885,13 +3926,15 @@
       if (literal.constKeyword != null) {
         // TODO(paulberry): this error should be based on the actual type of the
         // list element, not the static type.  See dartbug.com/21119.
-        if (_checkForArgumentTypeNotAssignableWithExpectedTypes(element,
+        if (_checkForArgumentTypeNotAssignableWithExpectedTypes(
+            element,
             listElementType,
             CheckedModeCompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE)) {
           hasProblems = true;
         }
       }
-      if (_checkForArgumentTypeNotAssignableWithExpectedTypes(element,
+      if (_checkForArgumentTypeNotAssignableWithExpectedTypes(
+          element,
           listElementType,
           StaticWarningCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE)) {
         hasProblems = true;
@@ -3932,7 +3975,8 @@
             CheckedModeCompileTimeErrorCode.MAP_KEY_TYPE_NOT_ASSIGNABLE)) {
           hasProblems = true;
         }
-        if (_checkForArgumentTypeNotAssignableWithExpectedTypes(value,
+        if (_checkForArgumentTypeNotAssignableWithExpectedTypes(
+            value,
             valueType,
             CheckedModeCompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE)) {
           hasProblems = true;
@@ -3969,7 +4013,8 @@
     for (PropertyAccessorElement accessor in _enclosingClass.accessors) {
       if (className == accessor.name) {
         _errorReporter.reportErrorForOffset(
-            CompileTimeErrorCode.MEMBER_WITH_CLASS_NAME, accessor.nameOffset,
+            CompileTimeErrorCode.MEMBER_WITH_CLASS_NAME,
+            accessor.nameOffset,
             className.length);
         problemReported = true;
       }
@@ -4055,7 +4100,8 @@
       if (enclosingClassForCounterpart == null) {
         _errorReporter.reportTypeErrorForNode(
             StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES,
-            accessorDeclaration, [accessorTextName, setterType, getterType]);
+            accessorDeclaration,
+            [accessorTextName, setterType, getterType]);
         return true;
       } else {
         _errorReporter.reportTypeErrorForNode(
@@ -4121,8 +4167,10 @@
       int offset = statement.offset;
       int end = statement.rightParenthesis.end;
       _errorReporter.reportErrorForOffset(
-          CompileTimeErrorCode.MISSING_ENUM_CONSTANT_IN_SWITCH, offset,
-          end - offset, [constantNames[i]]);
+          CompileTimeErrorCode.MISSING_ENUM_CONSTANT_IN_SWITCH,
+          offset,
+          end - offset,
+          [constantNames[i]]);
     }
     return true;
   }
@@ -4165,7 +4213,8 @@
     for (ConstructorElement constructor in mixinElement.constructors) {
       if (!constructor.isSynthetic && !constructor.isFactory) {
         _errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR, mixinName,
+            CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR,
+            mixinName,
             [mixinElement.name]);
         return true;
       }
@@ -4199,7 +4248,8 @@
       if (!mixinSupertype.isObject ||
           !mixinElement.isMixinApplication && mixinElement.mixins.length != 0) {
         _errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, mixinName,
+            CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT,
+            mixinName,
             [mixinElement.name]);
         return true;
       }
@@ -4218,7 +4268,8 @@
       TypeName mixinName, ClassElement mixinElement) {
     if (!enableSuperMixins && mixinElement.hasReferenceToSuper) {
       _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.MIXIN_REFERENCES_SUPER, mixinName,
+          CompileTimeErrorCode.MIXIN_REFERENCES_SUPER,
+          mixinName,
           [mixinElement.name]);
     }
     return false;
@@ -4268,7 +4319,8 @@
    * See [StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR].
    */
   bool _checkForNewWithUndefinedConstructor(
-      InstanceCreationExpression expression, ConstructorName constructorName,
+      InstanceCreationExpression expression,
+      ConstructorName constructorName,
       TypeName typeName) {
     // OK if resolved
     if (expression.staticElement != null) {
@@ -4288,14 +4340,14 @@
     SimpleIdentifier name = constructorName.name;
     if (name != null) {
       _errorReporter.reportErrorForNode(
-          StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR, name, [
-        className,
-        name
-      ]);
+          StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR,
+          name,
+          [className, name]);
     } else {
       _errorReporter.reportErrorForNode(
           StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT,
-          constructorName, [className]);
+          constructorName,
+          [className]);
     }
     return true;
   }
@@ -4331,7 +4383,8 @@
     if (superUnnamedConstructor != null) {
       if (superUnnamedConstructor.isFactory) {
         _errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR, declaration.name,
+            CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR,
+            declaration.name,
             [superUnnamedConstructor]);
         return true;
       }
@@ -4344,7 +4397,8 @@
     // report problem
     _errorReporter.reportErrorForNode(
         CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_IMPLICIT,
-        declaration.name, [superType.displayName]);
+        declaration.name,
+        [superType.displayName]);
     return true;
   }
 
@@ -4486,11 +4540,13 @@
     if (stringMembersArray.length == 1) {
       analysisError = _errorReporter.newErrorWithProperties(
           StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE,
-          classNameNode, [stringMembersArray[0]]);
+          classNameNode,
+          [stringMembersArray[0]]);
     } else if (stringMembersArray.length == 2) {
       analysisError = _errorReporter.newErrorWithProperties(
           StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO,
-          classNameNode, [stringMembersArray[0], stringMembersArray[1]]);
+          classNameNode,
+          [stringMembersArray[0], stringMembersArray[1]]);
     } else if (stringMembersArray.length == 3) {
       analysisError = _errorReporter.newErrorWithProperties(
           StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE,
@@ -4826,7 +4882,8 @@
             }
             _errorReporter.reportErrorForNode(
                 CompileTimeErrorCode.REDIRECT_GENERATIVE_TO_MISSING_CONSTRUCTOR,
-                invocation, [constructorStrName, enclosingTypeName]);
+                invocation,
+                [constructorStrName, enclosingTypeName]);
           } else {
             if (redirectingElement.isFactory) {
               _errorReporter.reportErrorForNode(
@@ -4974,11 +5031,9 @@
       return false;
     }
     _errorReporter.reportTypeErrorForNode(
-        StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, returnExpression, [
-      staticReturnType,
-      expectedReturnType,
-      _enclosingFunction.displayName
-    ]);
+        StaticTypeWarningCode.RETURN_OF_INVALID_TYPE,
+        returnExpression,
+        [staticReturnType, expectedReturnType, _enclosingFunction.displayName]);
     return true;
     // TODO(brianwilkerson) Define a hint corresponding to the warning and
     // report it if appropriate.
@@ -5053,10 +5108,9 @@
       }
       // report problem
       _errorReporter.reportErrorForNode(
-          StaticWarningCode.SWITCH_EXPRESSION_NOT_ASSIGNABLE, expression, [
-        expressionType,
-        caseType
-      ]);
+          StaticWarningCode.SWITCH_EXPRESSION_NOT_ASSIGNABLE,
+          expression,
+          [expressionType, caseType]);
       return true;
     }
     return false;
@@ -5183,7 +5237,8 @@
     }
     // report problem
     _errorReporter.reportErrorForNode(
-        StaticTypeWarningCode.TYPE_PARAMETER_SUPERTYPE_OF_ITS_BOUND, parameter,
+        StaticTypeWarningCode.TYPE_PARAMETER_SUPERTYPE_OF_ITS_BOUND,
+        parameter,
         [element.displayName]);
     return true;
   }
@@ -5239,7 +5294,8 @@
       if (superUnnamedConstructor.isFactory) {
         _errorReporter.reportErrorForNode(
             CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR,
-            constructor.returnType, [superUnnamedConstructor]);
+            constructor.returnType,
+            [superUnnamedConstructor]);
         return true;
       }
       if (!superUnnamedConstructor.isDefaultConstructor ||
@@ -5254,14 +5310,17 @@
           length = (name != null ? name.end : returnType.end) - offset;
         }
         _errorReporter.reportErrorForOffset(
-            CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT, offset,
-            length, [superType.displayName]);
+            CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT,
+            offset,
+            length,
+            [superType.displayName]);
       }
       return false;
     }
     _errorReporter.reportErrorForNode(
         CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT,
-        constructor.returnType, [superElement.name]);
+        constructor.returnType,
+        [superElement.name]);
     return true;
   }
 
@@ -5290,7 +5349,8 @@
     }
     _errorReporter.reportErrorForNode(
         StaticTypeWarningCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER,
-        name, [name.name]);
+        name,
+        [name.name]);
     return true;
   }
 
@@ -5301,7 +5361,8 @@
       if (fieldElement == null || fieldElement.isSynthetic) {
         _errorReporter.reportErrorForNode(
             CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD,
-            parameter, [parameter.identifier.name]);
+            parameter,
+            [parameter.identifier.name]);
       } else {
         ParameterElement parameterElement = parameter.element;
         if (parameterElement is FieldFormalParameterElementImpl) {
@@ -5311,27 +5372,32 @@
           if (fieldElement.isSynthetic) {
             _errorReporter.reportErrorForNode(
                 CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD,
-                parameter, [parameter.identifier.name]);
+                parameter,
+                [parameter.identifier.name]);
           } else if (fieldElement.isStatic) {
             _errorReporter.reportErrorForNode(
                 CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD,
-                parameter, [parameter.identifier.name]);
+                parameter,
+                [parameter.identifier.name]);
           } else if (declaredType != null &&
               fieldType != null &&
               !declaredType.isAssignableTo(fieldType)) {
             _errorReporter.reportTypeErrorForNode(
                 StaticWarningCode.FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE,
-                parameter, [declaredType, fieldType]);
+                parameter,
+                [declaredType, fieldType]);
           }
         } else {
           if (fieldElement.isSynthetic) {
             _errorReporter.reportErrorForNode(
                 CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD,
-                parameter, [parameter.identifier.name]);
+                parameter,
+                [parameter.identifier.name]);
           } else if (fieldElement.isStatic) {
             _errorReporter.reportErrorForNode(
                 CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD,
-                parameter, [parameter.identifier.name]);
+                parameter,
+                [parameter.identifier.name]);
           }
         }
       }
@@ -5407,14 +5473,16 @@
     if (expected != -1 && numParameters != expected) {
       _errorReporter.reportErrorForNode(
           CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR,
-          nameNode, [name, expected, numParameters]);
+          nameNode,
+          [name, expected, numParameters]);
       return true;
     }
     // check for operator "-"
     if ("-" == name && numParameters > 1) {
       _errorReporter.reportErrorForNode(
           CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR_MINUS,
-          nameNode, [numParameters]);
+          nameNode,
+          [numParameters]);
       return true;
     }
     // OK
@@ -5476,10 +5544,9 @@
     }
     if (!impliedReturnType.isAssignableTo(declaredReturnType)) {
       _errorReporter.reportTypeErrorForNode(
-          StaticTypeWarningCode.YIELD_OF_INVALID_TYPE, yieldExpression, [
-        impliedReturnType,
-        declaredReturnType
-      ]);
+          StaticTypeWarningCode.YIELD_OF_INVALID_TYPE,
+          yieldExpression,
+          [impliedReturnType, declaredReturnType]);
       return true;
     }
     if (isYieldEach) {
@@ -5494,10 +5561,9 @@
       }
       if (!impliedReturnType.isAssignableTo(requiredReturnType)) {
         _errorReporter.reportTypeErrorForNode(
-            StaticTypeWarningCode.YIELD_OF_INVALID_TYPE, yieldExpression, [
-          impliedReturnType,
-          requiredReturnType
-        ]);
+            StaticTypeWarningCode.YIELD_OF_INVALID_TYPE,
+            yieldExpression,
+            [impliedReturnType, requiredReturnType]);
         return true;
       }
     }
@@ -5562,7 +5628,8 @@
       if (interfaceNode.type == superType) {
         hasProblem = true;
         _errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.IMPLEMENTS_SUPER_CLASS, interfaceNode,
+            CompileTimeErrorCode.IMPLEMENTS_SUPER_CLASS,
+            interfaceNode,
             [superType.displayName]);
       }
     }
@@ -5883,17 +5950,18 @@
         buffer.write(element.displayName);
         _errorReporter.reportErrorForOffset(
             CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE,
-            _enclosingClass.nameOffset, enclosingClassName.length, [
-          enclosingClassName,
-          buffer.toString()
-        ]);
+            _enclosingClass.nameOffset,
+            enclosingClassName.length,
+            [enclosingClassName, buffer.toString()]);
         return true;
       } else {
         // RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_EXTENDS or
         // RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_IMPLEMENTS or
         // RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_WITH
-        _errorReporter.reportErrorForOffset(_getBaseCaseErrorCode(element),
-            _enclosingClass.nameOffset, enclosingClassName.length,
+        _errorReporter.reportErrorForOffset(
+            _getBaseCaseErrorCode(element),
+            _enclosingClass.nameOffset,
+            enclosingClassName.length,
             [enclosingClassName]);
         return true;
       }
diff --git a/pkg/analyzer/lib/src/generated/html.dart b/pkg/analyzer/lib/src/generated/html.dart
index a72a1c8..c0012c5 100644
--- a/pkg/analyzer/lib/src/generated/html.dart
+++ b/pkg/analyzer/lib/src/generated/html.dart
@@ -401,9 +401,14 @@
       new XmlAttributeNode(name, equals, value);
 
   @override
-  XmlTagNode createTagNode(Token nodeStart, Token tag,
-      List<XmlAttributeNode> attributes, Token attributeEnd,
-      List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag,
+  XmlTagNode createTagNode(
+      Token nodeStart,
+      Token tag,
+      List<XmlAttributeNode> attributes,
+      Token attributeEnd,
+      List<XmlTagNode> tagNodes,
+      Token contentEnd,
+      Token closingTag,
       Token nodeEnd) {
     if (_isScriptNode(tag, attributes, tagNodes)) {
       HtmlScriptTagNode tagNode = new HtmlScriptTagNode(nodeStart, tag,
@@ -529,12 +534,17 @@
    * @param closingTag the name of the tag that occurs in the closing tag
    * @param nodeEnd the last token in the tag
    */
-  HtmlScriptTagNode(Token nodeStart, Token tag,
-      List<XmlAttributeNode> attributes, Token attributeEnd,
-      List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag,
+  HtmlScriptTagNode(
+      Token nodeStart,
+      Token tag,
+      List<XmlAttributeNode> attributes,
+      Token attributeEnd,
+      List<XmlTagNode> tagNodes,
+      Token contentEnd,
+      Token closingTag,
       Token nodeEnd)
       : super(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd,
-          closingTag, nodeEnd);
+            closingTag, nodeEnd);
 
   /**
    * Return the AST structure representing the Dart code within this tag, or `null` if this
@@ -1421,11 +1431,17 @@
    * @param nodeEnd the last token in the tag
    * @return the node that was created
    */
-  XmlTagNode createTagNode(Token nodeStart, Token tag,
-      List<XmlAttributeNode> attributes, Token attributeEnd,
-      List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag,
-      Token nodeEnd) => new XmlTagNode(nodeStart, tag, attributes, attributeEnd,
-      tagNodes, contentEnd, closingTag, nodeEnd);
+  XmlTagNode createTagNode(
+          Token nodeStart,
+          Token tag,
+          List<XmlAttributeNode> attributes,
+          Token attributeEnd,
+          List<XmlTagNode> tagNodes,
+          Token contentEnd,
+          Token closingTag,
+          Token nodeEnd) =>
+      new XmlTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes,
+          contentEnd, closingTag, nodeEnd);
 
   /**
    * Answer `true` if the specified tag is self closing and thus should never have content or
@@ -1736,9 +1752,15 @@
    * @param nodeEnd the ending [TokenType.GT] or [TokenType.SLASH_GT] token (not
    *          `null`)
    */
-  XmlTagNode(this.nodeStart, this._tag, List<XmlAttributeNode> attributes,
-      this.attributeEnd, List<XmlTagNode> tagNodes, this.contentEnd,
-      this.closingTag, this.nodeEnd) {
+  XmlTagNode(
+      this.nodeStart,
+      this._tag,
+      List<XmlAttributeNode> attributes,
+      this.attributeEnd,
+      List<XmlTagNode> tagNodes,
+      this.contentEnd,
+      this.closingTag,
+      this.nodeEnd) {
     this._attributes = becomeParentOfAll(attributes, ifEmpty: NO_ATTRIBUTES);
     this._tagNodes = becomeParentOfAll(tagNodes, ifEmpty: NO_TAG_NODES);
   }
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 5feaaa9..0341d59 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -8,30 +8,26 @@
 import 'dart:math' as math;
 
 import 'package:analyzer/src/context/cache.dart'
-    show CacheEntry, TargetedResult;
+    show CacheEntry, Delta, DeltaResult, TargetedResult;
 import 'package:analyzer/src/generated/constant.dart';
-import 'package:analyzer/src/task/dart.dart'
-    show
-        HINTS,
-        INFER_STATIC_VARIABLE_TYPES_ERRORS,
-        LIBRARY_UNIT_ERRORS,
-        PARSE_ERRORS,
-        PARTIALLY_RESOLVE_REFERENCES_ERRORS,
-        RESOLVE_FUNCTION_BODIES_ERRORS,
-        RESOLVE_TYPE_NAMES_ERRORS,
-        SCAN_ERRORS,
-        USED_IMPORTED_ELEMENTS,
-        USED_LOCAL_ELEMENTS,
-        VARIABLE_REFERENCE_ERRORS,
-        VERIFY_ERRORS;
-import 'package:analyzer/task/dart.dart'
-    show DART_ERRORS, LibrarySpecificUnit, PARSED_UNIT, TOKEN_STREAM;
+import 'package:analyzer/src/task/dart.dart';
+import 'package:analyzer/task/dart.dart';
 import 'package:analyzer/task/general.dart' show CONTENT, LINE_INFO;
-import 'package:analyzer/task/model.dart' show ResultDescriptor, TargetedResult;
+import 'package:analyzer/task/model.dart'
+    show AnalysisTarget, ResultDescriptor, TargetedResult, TaskDescriptor;
 
 import 'ast.dart';
 import 'element.dart';
-import 'engine.dart';
+import 'engine.dart'
+    show
+        AnalysisContext,
+        AnalysisOptions,
+        CacheState,
+        DartEntry,
+        DataDescriptor,
+        InternalAnalysisContext,
+        RecordingErrorListener,
+        SourceEntry;
 import 'error.dart';
 import 'error_verifier.dart';
 import 'incremental_logger.dart' show logger, LoggingTimer;
@@ -830,6 +826,74 @@
 }
 
 /**
+ * The [Delta] implementation used by incremental resolver.
+ * It keeps Dart results that are either don't change or are updated.
+ */
+class IncrementalBodyDelta extends Delta {
+  /**
+   * The offset of the changed contents.
+   */
+  final int updateOffset;
+
+  /**
+   * The end of the changed contents in the old unit.
+   */
+  final int updateEndOld;
+
+  /**
+   * The end of the changed contents in the new unit.
+   */
+  final int updateEndNew;
+
+  /**
+   * The delta between [updateEndNew] and [updateEndOld].
+   */
+  final int updateDelta;
+
+  IncrementalBodyDelta(Source source, this.updateOffset, this.updateEndOld,
+      this.updateEndNew, this.updateDelta)
+      : super(source);
+
+  @override
+  DeltaResult validate(InternalAnalysisContext context, AnalysisTarget target,
+      ResultDescriptor descriptor) {
+    // don't invalidate results of standard Dart tasks
+    bool isByTask(TaskDescriptor taskDescriptor) {
+      return taskDescriptor.results.contains(descriptor);
+    }
+    if (descriptor == CONTENT) {
+      return DeltaResult.KEEP_CONTINUE;
+    }
+    if (isByTask(BuildCompilationUnitElementTask.DESCRIPTOR) ||
+        isByTask(BuildDirectiveElementsTask.DESCRIPTOR) ||
+        isByTask(BuildEnumMemberElementsTask.DESCRIPTOR) ||
+        isByTask(BuildExportNamespaceTask.DESCRIPTOR) ||
+        isByTask(BuildLibraryElementTask.DESCRIPTOR) ||
+        isByTask(BuildPublicNamespaceTask.DESCRIPTOR) ||
+        isByTask(BuildSourceExportClosureTask.DESCRIPTOR) ||
+        isByTask(BuildSourceImportExportClosureTask.DESCRIPTOR) ||
+        isByTask(ComputeConstantDependenciesTask.DESCRIPTOR) ||
+        isByTask(ComputeConstantValueTask.DESCRIPTOR) ||
+        isByTask(EvaluateUnitConstantsTask.DESCRIPTOR) ||
+        isByTask(InferInstanceMembersInUnitTask.DESCRIPTOR) ||
+        isByTask(InferStaticVariableTypesInUnitTask.DESCRIPTOR) ||
+        isByTask(ParseDartTask.DESCRIPTOR) ||
+        isByTask(PartiallyResolveUnitReferencesTask.DESCRIPTOR) ||
+        isByTask(ScanDartTask.DESCRIPTOR) ||
+        isByTask(ResolveFunctionBodiesInUnitTask.DESCRIPTOR) ||
+        isByTask(ResolveLibraryReferencesTask.DESCRIPTOR) ||
+        isByTask(ResolveLibraryTypeNamesTask.DESCRIPTOR) ||
+        isByTask(ResolveUnitTypeNamesTask.DESCRIPTOR) ||
+        isByTask(ResolveVariableReferencesTask.DESCRIPTOR) ||
+        isByTask(VerifyUnitTask.DESCRIPTOR)) {
+      return DeltaResult.KEEP_CONTINUE;
+    }
+    // invalidate all the other results
+    return DeltaResult.INVALIDATE;
+  }
+}
+
+/**
  * Instances of the class [IncrementalResolver] resolve the smallest portion of
  * an AST structure that we currently know how to resolve.
  */
@@ -894,8 +958,16 @@
    */
   final int _updateEndNew;
 
+  /**
+   * The delta between [_updateEndNew] and [_updateEndOld].
+   */
   int _updateDelta;
 
+  /**
+   * The set of [AnalysisError]s that have been already shifted.
+   */
+  Set<AnalysisError> _alreadyShiftedErrors = new HashSet.identity();
+
   RecordingErrorListener errorListener = new RecordingErrorListener();
   ResolutionContext _resolutionContext;
 
@@ -935,6 +1007,7 @@
       AstNode rootNode = _findResolutionRoot(node);
       _prepareResolutionContext(rootNode);
       // update elements
+      _updateCache();
       _updateElementNameOffsets();
       _buildElements(rootNode);
       if (!_canBeIncrementallyResolved(rootNode)) {
@@ -1146,9 +1219,11 @@
 
   void _shiftErrors(List<AnalysisError> errors) {
     for (AnalysisError error in errors) {
-      int errorOffset = error.offset;
-      if (errorOffset > _updateOffset) {
-        error.offset += _updateDelta;
+      if (_alreadyShiftedErrors.add(error)) {
+        int errorOffset = error.offset;
+        if (errorOffset > _updateOffset) {
+          error.offset += _updateDelta;
+        }
       }
     }
   }
@@ -1164,6 +1239,14 @@
     _shiftErrors(errors);
   }
 
+  void _updateCache() {
+    if (newSourceEntry != null) {
+      newSourceEntry.setState(CONTENT, CacheState.INVALID,
+          delta: new IncrementalBodyDelta(_source, _updateOffset, _updateEndOld,
+              _updateEndNew, _updateDelta));
+    }
+  }
+
   void _updateElementNameOffsets() {
     LoggingTimer timer = logger.startTimer();
     try {
@@ -1367,6 +1450,7 @@
                   _updateOffset,
                   _updateEndOld,
                   _updateEndNew);
+              incrementalResolver._updateCache();
               incrementalResolver._updateElementNameOffsets();
               incrementalResolver._shiftEntryErrors();
             }
@@ -1534,6 +1618,7 @@
         _updateOffset,
         _updateEndOld,
         _updateEndNew);
+    incrementalResolver._updateCache();
     incrementalResolver._updateElementNameOffsets();
     incrementalResolver._shiftEntryErrors();
     _updateEntry();
@@ -1602,12 +1687,12 @@
   void _updateEntry_NEW() {
     _newSourceEntry.setState(DART_ERRORS, CacheState.INVALID);
     // scan results
-    _newSourceEntry.setState(SCAN_ERRORS, CacheState.INVALID);
     List<TargetedResult> scanDeps = <TargetedResult>[
       new TargetedResult(_unitSource, CONTENT)
     ];
-    _newSourceEntry.setValue(LINE_INFO, _newLineInfo, scanDeps);
+    _newSourceEntry.setState(SCAN_ERRORS, CacheState.INVALID);
     _newSourceEntry.setValue(SCAN_ERRORS, _newScanErrors, scanDeps);
+    _newSourceEntry.setValue(LINE_INFO, _newLineInfo, scanDeps);
     // parse results
     List<TargetedResult> parseDeps = <TargetedResult>[
       new TargetedResult(_unitSource, TOKEN_STREAM)
diff --git a/pkg/analyzer/lib/src/generated/java_core.dart b/pkg/analyzer/lib/src/generated/java_core.dart
index 9a0185a..8c96357 100644
--- a/pkg/analyzer/lib/src/generated/java_core.dart
+++ b/pkg/analyzer/lib/src/generated/java_core.dart
@@ -141,24 +141,31 @@
     }
     return -1;
   }
+
   static bool isDigit(int c) {
     return c >= 0x30 && c <= 0x39;
   }
+
   static bool isLetter(int c) {
     return c >= 0x41 && c <= 0x5A || c >= 0x61 && c <= 0x7A;
   }
+
   static bool isLetterOrDigit(int c) {
     return isLetter(c) || isDigit(c);
   }
+
   static bool isLowerCase(int c) {
     return c >= 0x61 && c <= 0x7A;
   }
+
   static bool isUpperCase(int c) {
     return c >= 0x41 && c <= 0x5A;
   }
+
   static bool isWhitespace(int c) {
     return c == 0x09 || c == 0x20 || c == 0x0A || c == 0x0D;
   }
+
   static String toChars(int codePoint) {
     if (codePoint < 0 || codePoint > MAX_CODE_POINT) {
       throw new IllegalArgumentException();
@@ -171,12 +178,14 @@
     int c1 = (offset & 0x3ff) + MIN_LOW_SURROGATE;
     return new String.fromCharCodes([c0, c1]);
   }
+
   static int toLowerCase(int c) {
     if (c >= 0x41 && c <= 0x5A) {
       return 0x61 + (c - 0x41);
     }
     return c;
   }
+
   static int toUpperCase(int c) {
     if (c >= 0x61 && c <= 0x7A) {
       return 0x41 + (c - 0x61);
@@ -188,6 +197,7 @@
 abstract class Enum<E extends Enum> implements Comparable<E> {
   /// The name of this enum constant, as declared in the enum declaration.
   final String name;
+
   /// The position in the enum declaration.
   final int ordinal;
   const Enum(this.name, this.ordinal);
@@ -221,6 +231,7 @@
     }
     return true;
   }
+
   static int makeHashCode(List a) {
     if (a == null) {
       return 0;
@@ -259,6 +270,7 @@
     _match = _matches.current;
     return true;
   }
+
   String group(int i) => _match[i];
   bool matches() => find();
   int start() => _match.start;
@@ -270,11 +282,13 @@
     if (fromIndex < 0) fromIndex = 0;
     return target.indexOf(str, fromIndex);
   }
+
   static int lastIndexOf(String target, String str, int fromIndex) {
     if (fromIndex > target.length) return -1;
     if (fromIndex < 0) fromIndex = 0;
     return target.lastIndexOf(str, fromIndex);
   }
+
   static bool startsWithBefore(String s, String other, int start) {
     return s.indexOf(other, start) != -1;
   }
diff --git a/pkg/analyzer/lib/src/generated/java_engine.dart b/pkg/analyzer/lib/src/generated/java_engine.dart
index 98ff8e4..d0fb62b 100644
--- a/pkg/analyzer/lib/src/generated/java_engine.dart
+++ b/pkg/analyzer/lib/src/generated/java_engine.dart
@@ -128,10 +128,12 @@
         str.codeUnitAt(length - 2) == c2 &&
         str.codeUnitAt(length - 1) == c3;
   }
+
   static endsWithChar(String str, int c) {
     int length = str.length;
     return length > 0 && str.codeUnitAt(length - 1) == c;
   }
+
   static int indexOf1(String str, int start, int c) {
     int index = start;
     int last = str.length;
@@ -143,6 +145,7 @@
     }
     return -1;
   }
+
   static int indexOf2(String str, int start, int c1, int c2) {
     int index = start;
     int last = str.length - 1;
@@ -154,6 +157,7 @@
     }
     return -1;
   }
+
   static int indexOf4(
       String string, int start, int c1, int c2, int c3, int c4) {
     int index = start;
@@ -169,6 +173,7 @@
     }
     return -1;
   }
+
   static int indexOf5(
       String str, int start, int c1, int c2, int c3, int c4, int c5) {
     int index = start;
@@ -203,10 +208,12 @@
     }
     return last;
   }
+
   static String intern(String string) => INTERNER.intern(string);
   static bool isEmpty(String s) {
     return s == null || s.isEmpty;
   }
+
   static bool isTagName(String s) {
     if (s == null || s.length == 0) {
       return false;
@@ -225,6 +232,7 @@
     }
     return true;
   }
+
   /**
    * Produce a string containing all of the names in the given array, surrounded by single quotes,
    * and separated by commas. The list must contain at least two elements.
@@ -255,17 +263,20 @@
     buffer.write("'");
     return buffer.toString();
   }
+
   static startsWith2(String str, int start, int c1, int c2) {
     return str.length - start >= 2 &&
         str.codeUnitAt(start) == c1 &&
         str.codeUnitAt(start + 1) == c2;
   }
+
   static startsWith3(String str, int start, int c1, int c2, int c3) {
     return str.length - start >= 3 &&
         str.codeUnitAt(start) == c1 &&
         str.codeUnitAt(start + 1) == c2 &&
         str.codeUnitAt(start + 2) == c3;
   }
+
   static startsWith4(String str, int start, int c1, int c2, int c3, int c4) {
     return str.length - start >= 4 &&
         str.codeUnitAt(start) == c1 &&
@@ -273,6 +284,7 @@
         str.codeUnitAt(start + 2) == c3 &&
         str.codeUnitAt(start + 3) == c4;
   }
+
   static startsWith5(
       String str, int start, int c1, int c2, int c3, int c4, int c5) {
     return str.length - start >= 5 &&
@@ -282,6 +294,7 @@
         str.codeUnitAt(start + 3) == c4 &&
         str.codeUnitAt(start + 4) == c5;
   }
+
   static startsWith6(
       String str, int start, int c1, int c2, int c3, int c4, int c5, int c6) {
     return str.length - start >= 6 &&
@@ -292,6 +305,7 @@
         str.codeUnitAt(start + 4) == c5 &&
         str.codeUnitAt(start + 5) == c6;
   }
+
   static startsWithChar(String str, int c) {
     return str.length != 0 && str.codeUnitAt(0) == c;
   }
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 47a4bc1..113da91 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -89,11 +89,14 @@
   'parseWithClause_0':
       new MethodTrampoline(0, (Parser target) => target.parseWithClause()),
   'advance_0': new MethodTrampoline(0, (Parser target) => target._advance()),
-  'appendScalarValue_5': new MethodTrampoline(5, (Parser target, arg0, arg1,
-      arg2, arg3,
-      arg4) => target._appendScalarValue(arg0, arg1, arg2, arg3, arg4)),
-  'computeStringValue_3': new MethodTrampoline(3, (Parser target, arg0, arg1,
-      arg2) => target._computeStringValue(arg0, arg1, arg2)),
+  'appendScalarValue_5': new MethodTrampoline(
+      5,
+      (Parser target, arg0, arg1, arg2, arg3, arg4) =>
+          target._appendScalarValue(arg0, arg1, arg2, arg3, arg4)),
+  'computeStringValue_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._computeStringValue(arg0, arg1, arg2)),
   'convertToFunctionDeclaration_1': new MethodTrampoline(
       1, (Parser target, arg0) => target._convertToFunctionDeclaration(arg0)),
   'couldBeStartOfCompilationUnitMember_0': new MethodTrampoline(
@@ -159,8 +162,10 @@
       0, (Parser target) => target._parseAssertStatement()),
   'parseAssignableExpression_1': new MethodTrampoline(
       1, (Parser target, arg0) => target._parseAssignableExpression(arg0)),
-  'parseAssignableSelector_2': new MethodTrampoline(2, (Parser target, arg0,
-      arg1) => target._parseAssignableSelector(arg0, arg1)),
+  'parseAssignableSelector_2': new MethodTrampoline(
+      2,
+      (Parser target, arg0, arg1) =>
+          target._parseAssignableSelector(arg0, arg1)),
   'parseAwaitExpression_0': new MethodTrampoline(
       0, (Parser target) => target._parseAwaitExpression()),
   'parseBitwiseAndExpression_0': new MethodTrampoline(
@@ -175,8 +180,10 @@
       (Parser target, arg0, arg1) => target._parseClassDeclaration(arg0, arg1)),
   'parseClassMembers_2': new MethodTrampoline(
       2, (Parser target, arg0, arg1) => target._parseClassMembers(arg0, arg1)),
-  'parseClassTypeAlias_3': new MethodTrampoline(3, (Parser target, arg0, arg1,
-      arg2) => target._parseClassTypeAlias(arg0, arg1, arg2)),
+  'parseClassTypeAlias_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._parseClassTypeAlias(arg0, arg1, arg2)),
   'parseCombinator_0':
       new MethodTrampoline(0, (Parser target) => target.parseCombinator()),
   'parseCombinators_0':
@@ -191,9 +198,10 @@
       1, (Parser target, arg0) => target._parseCompilationUnitMember(arg0)),
   'parseConstExpression_0': new MethodTrampoline(
       0, (Parser target) => target._parseConstExpression()),
-  'parseConstructor_8': new MethodTrampoline(8, (Parser target, arg0, arg1,
-          arg2, arg3, arg4, arg5, arg6, arg7) =>
-      target._parseConstructor(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)),
+  'parseConstructor_8': new MethodTrampoline(
+      8,
+      (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) => target
+          ._parseConstructor(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)),
   'parseConstructorFieldInitializer_0': new MethodTrampoline(
       0, (Parser target) => target._parseConstructorFieldInitializer()),
   'parseContinueStatement_0': new MethodTrampoline(
@@ -224,26 +232,36 @@
       1, (Parser target, arg0) => target._parseFormalParameter(arg0)),
   'parseForStatement_0':
       new MethodTrampoline(0, (Parser target) => target._parseForStatement()),
-  'parseFunctionBody_3': new MethodTrampoline(3, (Parser target, arg0, arg1,
-      arg2) => target._parseFunctionBody(arg0, arg1, arg2)),
-  'parseFunctionDeclaration_3': new MethodTrampoline(3, (Parser target, arg0,
-      arg1, arg2) => target._parseFunctionDeclaration(arg0, arg1, arg2)),
+  'parseFunctionBody_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._parseFunctionBody(arg0, arg1, arg2)),
+  'parseFunctionDeclaration_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._parseFunctionDeclaration(arg0, arg1, arg2)),
   'parseFunctionDeclarationStatement_0': new MethodTrampoline(
       0, (Parser target) => target._parseFunctionDeclarationStatement()),
-  'parseFunctionDeclarationStatementAfterReturnType_2': new MethodTrampoline(2,
+  'parseFunctionDeclarationStatementAfterReturnType_2': new MethodTrampoline(
+      2,
       (Parser target, arg0, arg1) =>
           target._parseFunctionDeclarationStatementAfterReturnType(arg0, arg1)),
-  'parseFunctionTypeAlias_2': new MethodTrampoline(2, (Parser target, arg0,
-      arg1) => target._parseFunctionTypeAlias(arg0, arg1)),
-  'parseGetter_4': new MethodTrampoline(4, (Parser target, arg0, arg1, arg2,
-      arg3) => target._parseGetter(arg0, arg1, arg2, arg3)),
+  'parseFunctionTypeAlias_2': new MethodTrampoline(
+      2,
+      (Parser target, arg0, arg1) =>
+          target._parseFunctionTypeAlias(arg0, arg1)),
+  'parseGetter_4': new MethodTrampoline(
+      4,
+      (Parser target, arg0, arg1, arg2, arg3) =>
+          target._parseGetter(arg0, arg1, arg2, arg3)),
   'parseIdentifierList_0':
       new MethodTrampoline(0, (Parser target) => target._parseIdentifierList()),
   'parseIfStatement_0':
       new MethodTrampoline(0, (Parser target) => target._parseIfStatement()),
   'parseImportDirective_1': new MethodTrampoline(
       1, (Parser target, arg0) => target._parseImportDirective(arg0)),
-  'parseInitializedIdentifierList_4': new MethodTrampoline(4,
+  'parseInitializedIdentifierList_4': new MethodTrampoline(
+      4,
       (Parser target, arg0, arg1, arg2, arg3) =>
           target._parseInitializedIdentifierList(arg0, arg1, arg2, arg3)),
   'parseInstanceCreationExpression_1': new MethodTrampoline(1,
@@ -260,11 +278,13 @@
       0, (Parser target) => target._parseLogicalAndExpression()),
   'parseMapLiteral_2': new MethodTrampoline(
       2, (Parser target, arg0, arg1) => target._parseMapLiteral(arg0, arg1)),
-  'parseMethodDeclarationAfterParameters_7': new MethodTrampoline(7,
-      (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6) => target
-          ._parseMethodDeclarationAfterParameters(
+  'parseMethodDeclarationAfterParameters_7': new MethodTrampoline(
+      7,
+      (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6) =>
+          target._parseMethodDeclarationAfterParameters(
               arg0, arg1, arg2, arg3, arg4, arg5, arg6)),
-  'parseMethodDeclarationAfterReturnType_4': new MethodTrampoline(4,
+  'parseMethodDeclarationAfterReturnType_4': new MethodTrampoline(
+      4,
       (Parser target, arg0, arg1, arg2, arg3) => target
           ._parseMethodDeclarationAfterReturnType(arg0, arg1, arg2, arg3)),
   'parseModifiers_0':
@@ -277,8 +297,10 @@
       new MethodTrampoline(0, (Parser target) => target._parseNewExpression()),
   'parseNonLabeledStatement_0': new MethodTrampoline(
       0, (Parser target) => target._parseNonLabeledStatement()),
-  'parseOperator_3': new MethodTrampoline(3, (Parser target, arg0, arg1,
-      arg2) => target._parseOperator(arg0, arg1, arg2)),
+  'parseOperator_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._parseOperator(arg0, arg1, arg2)),
   'parseOptionalReturnType_0': new MethodTrampoline(
       0, (Parser target) => target._parseOptionalReturnType()),
   'parsePartDirective_1': new MethodTrampoline(
@@ -295,8 +317,10 @@
       0, (Parser target) => target._parseRethrowExpression()),
   'parseReturnStatement_0': new MethodTrampoline(
       0, (Parser target) => target._parseReturnStatement()),
-  'parseSetter_4': new MethodTrampoline(4, (Parser target, arg0, arg1, arg2,
-      arg3) => target._parseSetter(arg0, arg1, arg2, arg3)),
+  'parseSetter_4': new MethodTrampoline(
+      4,
+      (Parser target, arg0, arg1, arg2, arg3) =>
+          target._parseSetter(arg0, arg1, arg2, arg3)),
   'parseShiftExpression_0': new MethodTrampoline(
       0, (Parser target) => target._parseShiftExpression()),
   'parseStatementList_0':
@@ -321,16 +345,20 @@
       0, (Parser target) => target._parseUnaryExpression()),
   'parseVariableDeclaration_0': new MethodTrampoline(
       0, (Parser target) => target._parseVariableDeclaration()),
-  'parseVariableDeclarationListAfterMetadata_1': new MethodTrampoline(1,
+  'parseVariableDeclarationListAfterMetadata_1': new MethodTrampoline(
+      1,
       (Parser target, arg0) =>
           target._parseVariableDeclarationListAfterMetadata(arg0)),
-  'parseVariableDeclarationListAfterType_3': new MethodTrampoline(3,
+  'parseVariableDeclarationListAfterType_3': new MethodTrampoline(
+      3,
       (Parser target, arg0, arg1, arg2) =>
           target._parseVariableDeclarationListAfterType(arg0, arg1, arg2)),
-  'parseVariableDeclarationStatementAfterMetadata_1': new MethodTrampoline(1,
+  'parseVariableDeclarationStatementAfterMetadata_1': new MethodTrampoline(
+      1,
       (Parser target, arg0) =>
           target._parseVariableDeclarationStatementAfterMetadata(arg0)),
-  'parseVariableDeclarationStatementAfterType_3': new MethodTrampoline(3,
+  'parseVariableDeclarationStatementAfterType_3': new MethodTrampoline(
+      3,
       (Parser target, arg0, arg1, arg2) =>
           target._parseVariableDeclarationStatementAfterType(arg0, arg1, arg2)),
   'parseWhileStatement_0':
@@ -342,12 +370,18 @@
       new MethodTrampoline(1, (Parser target, arg0) => target._peekAt(arg0)),
   'reportError_1': new MethodTrampoline(
       1, (Parser target, arg0) => target._reportError(arg0)),
-  'reportErrorForCurrentToken_2': new MethodTrampoline(2, (Parser target, arg0,
-      arg1) => target._reportErrorForCurrentToken(arg0, arg1)),
-  'reportErrorForNode_3': new MethodTrampoline(3, (Parser target, arg0, arg1,
-      arg2) => target._reportErrorForNode(arg0, arg1, arg2)),
-  'reportErrorForToken_3': new MethodTrampoline(3, (Parser target, arg0, arg1,
-      arg2) => target._reportErrorForToken(arg0, arg1, arg2)),
+  'reportErrorForCurrentToken_2': new MethodTrampoline(
+      2,
+      (Parser target, arg0, arg1) =>
+          target._reportErrorForCurrentToken(arg0, arg1)),
+  'reportErrorForNode_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._reportErrorForNode(arg0, arg1, arg2)),
+  'reportErrorForToken_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._reportErrorForToken(arg0, arg1, arg2)),
   'skipBlock_0':
       new MethodTrampoline(0, (Parser target) => target._skipBlock()),
   'skipFinalConstVarOrType_1': new MethodTrampoline(
@@ -380,8 +414,10 @@
       (Parser target, arg0, arg1) => target._tokenMatchesKeyword(arg0, arg1)),
   'tokenMatchesString_2': new MethodTrampoline(
       2, (Parser target, arg0, arg1) => target._tokenMatchesString(arg0, arg1)),
-  'translateCharacter_3': new MethodTrampoline(3, (Parser target, arg0, arg1,
-      arg2) => target._translateCharacter(arg0, arg1, arg2)),
+  'translateCharacter_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._translateCharacter(arg0, arg1, arg2)),
   'unlockErrorListener_0':
       new MethodTrampoline(0, (Parser target) => target._unlockErrorListener()),
   'validateFormalParameterList_1': new MethodTrampoline(
@@ -394,21 +430,26 @@
       1, (Parser target, arg0) => target._validateModifiersForEnum(arg0)),
   'validateModifiersForField_1': new MethodTrampoline(
       1, (Parser target, arg0) => target._validateModifiersForField(arg0)),
-  'validateModifiersForFunctionDeclarationStatement_1': new MethodTrampoline(1,
+  'validateModifiersForFunctionDeclarationStatement_1': new MethodTrampoline(
+      1,
       (Parser target, arg0) =>
           target._validateModifiersForFunctionDeclarationStatement(arg0)),
-  'validateModifiersForGetterOrSetterOrMethod_1': new MethodTrampoline(1,
+  'validateModifiersForGetterOrSetterOrMethod_1': new MethodTrampoline(
+      1,
       (Parser target, arg0) =>
           target._validateModifiersForGetterOrSetterOrMethod(arg0)),
   'validateModifiersForOperator_1': new MethodTrampoline(
       1, (Parser target, arg0) => target._validateModifiersForOperator(arg0)),
-  'validateModifiersForTopLevelDeclaration_1': new MethodTrampoline(1,
+  'validateModifiersForTopLevelDeclaration_1': new MethodTrampoline(
+      1,
       (Parser target, arg0) =>
           target._validateModifiersForTopLevelDeclaration(arg0)),
-  'validateModifiersForTopLevelFunction_1': new MethodTrampoline(1,
+  'validateModifiersForTopLevelFunction_1': new MethodTrampoline(
+      1,
       (Parser target, arg0) =>
           target._validateModifiersForTopLevelFunction(arg0)),
-  'validateModifiersForTopLevelVariable_1': new MethodTrampoline(1,
+  'validateModifiersForTopLevelVariable_1': new MethodTrampoline(
+      1,
       (Parser target, arg0) =>
           target._validateModifiersForTopLevelVariable(arg0)),
   'validateModifiersForTypedef_1': new MethodTrampoline(
@@ -2328,11 +2369,11 @@
             commentAndMetadata, modifiers.externalKeyword, returnType);
       } else if (_matchesIdentifier() &&
           _peek().matchesAny([
-        TokenType.OPEN_PAREN,
-        TokenType.OPEN_CURLY_BRACKET,
-        TokenType.FUNCTION,
-        TokenType.LT
-      ])) {
+            TokenType.OPEN_PAREN,
+            TokenType.OPEN_CURLY_BRACKET,
+            TokenType.FUNCTION,
+            TokenType.LT
+          ])) {
         _validateModifiersForGetterOrSetterOrMethod(modifiers);
         return _parseMethodDeclarationAfterReturnType(commentAndMetadata,
             modifiers.externalKeyword, modifiers.staticKeyword, returnType);
@@ -2347,8 +2388,10 @@
             // We appear to have a variable declaration with a type of "void".
             //
             _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType);
-            return _parseInitializedIdentifierList(commentAndMetadata,
-                modifiers.staticKeyword, _validateModifiersForField(modifiers),
+            return _parseInitializedIdentifierList(
+                commentAndMetadata,
+                modifiers.staticKeyword,
+                _validateModifiersForField(modifiers),
                 returnType);
           }
         }
@@ -2426,8 +2469,10 @@
         List<VariableDeclaration> variables = new List<VariableDeclaration>();
         variables.add(
             new VariableDeclaration(_createSyntheticIdentifier(), null, null));
-        return new FieldDeclaration(commentAndMetadata.comment,
-            commentAndMetadata.metadata, null,
+        return new FieldDeclaration(
+            commentAndMetadata.comment,
+            commentAndMetadata.metadata,
+            null,
             new VariableDeclarationList(null, null, keyword, null, variables),
             _expectSemicolon());
       }
@@ -2441,9 +2486,17 @@
         // to loose, so we'll treat it as a method declaration with a missing
         // name, parameters and empty body.
         //
-        return new MethodDeclaration(commentAndMetadata.comment,
-            commentAndMetadata.metadata, null, null, null, null, null,
-            _createSyntheticIdentifier(), null, new FormalParameterList(
+        return new MethodDeclaration(
+            commentAndMetadata.comment,
+            commentAndMetadata.metadata,
+            null,
+            null,
+            null,
+            null,
+            null,
+            _createSyntheticIdentifier(),
+            null,
+            new FormalParameterList(
                 null, new List<FormalParameter>(), null, null, null),
             new EmptyFunctionBody(_createSyntheticToken(TokenType.SEMICOLON)));
       }
@@ -2451,9 +2504,14 @@
     } else if (_tokenMatches(_peek(), TokenType.PERIOD) &&
         _tokenMatchesIdentifier(_peekAt(2)) &&
         _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) {
-      return _parseConstructor(commentAndMetadata, modifiers.externalKeyword,
-          _validateModifiersForConstructor(modifiers), modifiers.factoryKeyword,
-          parseSimpleIdentifier(), getAndAdvance(), parseSimpleIdentifier(),
+      return _parseConstructor(
+          commentAndMetadata,
+          modifiers.externalKeyword,
+          _validateModifiersForConstructor(modifiers),
+          modifiers.factoryKeyword,
+          parseSimpleIdentifier(),
+          getAndAdvance(),
+          parseSimpleIdentifier(),
           parseFormalParameterList());
     } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
       SimpleIdentifier methodName = parseSimpleIdentifier();
@@ -2461,15 +2519,26 @@
       if (_matches(TokenType.COLON) ||
           modifiers.factoryKeyword != null ||
           methodName.name == className) {
-        return _parseConstructor(commentAndMetadata, modifiers.externalKeyword,
+        return _parseConstructor(
+            commentAndMetadata,
+            modifiers.externalKeyword,
             _validateModifiersForConstructor(modifiers),
-            modifiers.factoryKeyword, methodName, null, null, parameters);
+            modifiers.factoryKeyword,
+            methodName,
+            null,
+            null,
+            parameters);
       }
       _validateModifiersForGetterOrSetterOrMethod(modifiers);
       _validateFormalParameterList(parameters);
-      return _parseMethodDeclarationAfterParameters(commentAndMetadata,
-          modifiers.externalKeyword, modifiers.staticKeyword, null, methodName,
-          null, parameters);
+      return _parseMethodDeclarationAfterParameters(
+          commentAndMetadata,
+          modifiers.externalKeyword,
+          modifiers.staticKeyword,
+          null,
+          methodName,
+          null,
+          parameters);
     } else if (_peek()
         .matchesAny([TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
       if (modifiers.constKeyword == null &&
@@ -2514,8 +2583,10 @@
         // class. 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.
         //
-        return _parseInitializedIdentifierList(commentAndMetadata,
-            modifiers.staticKeyword, _validateModifiersForField(modifiers),
+        return _parseInitializedIdentifierList(
+            commentAndMetadata,
+            modifiers.staticKeyword,
+            _validateModifiersForField(modifiers),
             type);
       }
       if (_isOperator(_currentToken)) {
@@ -2536,8 +2607,10 @@
           ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken);
       try {
         _lockErrorListener();
-        return _parseInitializedIdentifierList(commentAndMetadata,
-            modifiers.staticKeyword, _validateModifiersForField(modifiers),
+        return _parseInitializedIdentifierList(
+            commentAndMetadata,
+            modifiers.staticKeyword,
+            _validateModifiersForField(modifiers),
             type);
       } finally {
         _unlockErrorListener();
@@ -2547,15 +2620,26 @@
       FormalParameterList parameters = parseFormalParameterList();
       if (methodName.name == className) {
         _reportErrorForNode(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, type);
-        return _parseConstructor(commentAndMetadata, modifiers.externalKeyword,
+        return _parseConstructor(
+            commentAndMetadata,
+            modifiers.externalKeyword,
             _validateModifiersForConstructor(modifiers),
-            modifiers.factoryKeyword, methodName, null, null, parameters);
+            modifiers.factoryKeyword,
+            methodName,
+            null,
+            null,
+            parameters);
       }
       _validateModifiersForGetterOrSetterOrMethod(modifiers);
       _validateFormalParameterList(parameters);
-      return _parseMethodDeclarationAfterParameters(commentAndMetadata,
-          modifiers.externalKeyword, modifiers.staticKeyword, type, methodName,
-          null, parameters);
+      return _parseMethodDeclarationAfterParameters(
+          commentAndMetadata,
+          modifiers.externalKeyword,
+          modifiers.staticKeyword,
+          type,
+          methodName,
+          null,
+          parameters);
     } else if (parseGenericMethods && _tokenMatches(_peek(), TokenType.LT)) {
       return _parseMethodDeclarationAfterReturnType(commentAndMetadata,
           modifiers.externalKeyword, modifiers.staticKeyword, type);
@@ -3192,13 +3276,24 @@
           _reportErrorForToken(
               ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword);
         }
-        return new FunctionTypedFormalParameter(commentAndMetadata.comment,
-            commentAndMetadata.metadata, holder.type, identifier,
-            typeParameters, parameters);
+        return new FunctionTypedFormalParameter(
+            commentAndMetadata.comment,
+            commentAndMetadata.metadata,
+            holder.type,
+            identifier,
+            typeParameters,
+            parameters);
       } else {
-        return new FieldFormalParameter(commentAndMetadata.comment,
-            commentAndMetadata.metadata, holder.keyword, holder.type,
-            thisKeyword, period, identifier, typeParameters, parameters);
+        return new FieldFormalParameter(
+            commentAndMetadata.comment,
+            commentAndMetadata.metadata,
+            holder.keyword,
+            holder.type,
+            thisKeyword,
+            period,
+            identifier,
+            typeParameters,
+            parameters);
       }
     } else if (typeParameters != null) {
       // TODO(brianwilkerson) Report an error. It looks like a function-typed
@@ -3219,9 +3314,16 @@
       // TODO(brianwilkerson) If there are type parameters but no parameters,
       // should we create a synthetic empty parameter list here so we can
       // capture the type parameters?
-      return new FieldFormalParameter(commentAndMetadata.comment,
-          commentAndMetadata.metadata, holder.keyword, holder.type, thisKeyword,
-          period, identifier, null, null);
+      return new FieldFormalParameter(
+          commentAndMetadata.comment,
+          commentAndMetadata.metadata,
+          holder.keyword,
+          holder.type,
+          thisKeyword,
+          period,
+          identifier,
+          null,
+          null);
     }
     return new SimpleFormalParameter(commentAndMetadata.comment,
         commentAndMetadata.metadata, holder.keyword, holder.type, identifier);
@@ -3508,9 +3610,14 @@
    * captures the components of the given method declaration).
    */
   FunctionDeclaration _convertToFunctionDeclaration(MethodDeclaration method) =>
-      new FunctionDeclaration(method.documentationComment, method.metadata,
-          method.externalKeyword, method.returnType, method.propertyKeyword,
-          method.name, new FunctionExpression(
+      new FunctionDeclaration(
+          method.documentationComment,
+          method.metadata,
+          method.externalKeyword,
+          method.returnType,
+          method.propertyKeyword,
+          method.name,
+          new FunctionExpression(
               method.typeParameters, method.parameters, method.body));
 
   /**
@@ -4212,7 +4319,8 @@
   Expression _parseAssignableExpression(bool primaryAllowed) {
     if (_matchesKeyword(Keyword.SUPER)) {
       return _parseAssignableSelector(
-          new SuperExpression(getAndAdvance()), false, allowConditional: false);
+          new SuperExpression(getAndAdvance()), false,
+          allowConditional: false);
     }
     //
     // A primary expression can start with an identifier. We resolve the
@@ -4233,8 +4341,11 @@
               expression as SimpleIdentifier, typeArguments, argumentList);
         } else if (expression is PrefixedIdentifier) {
           PrefixedIdentifier identifier = expression as PrefixedIdentifier;
-          expression = new MethodInvocation(identifier.prefix,
-              identifier.period, identifier.identifier, typeArguments,
+          expression = new MethodInvocation(
+              identifier.prefix,
+              identifier.period,
+              identifier.identifier,
+              typeArguments,
               argumentList);
         } else if (expression is PropertyAccess) {
           PropertyAccess access = expression as PropertyAccess;
@@ -4469,9 +4580,12 @@
           }
           if (expression is PropertyAccess) {
             PropertyAccess propertyAccess = expression as PropertyAccess;
-            expression = new MethodInvocation(propertyAccess.target,
-                propertyAccess.operator, propertyAccess.propertyName,
-                typeArguments, parseArgumentList());
+            expression = new MethodInvocation(
+                propertyAccess.target,
+                propertyAccess.operator,
+                propertyAccess.propertyName,
+                typeArguments,
+                parseArgumentList());
           } else {
             expression = new FunctionExpressionInvocation(
                 expression, typeArguments, parseArgumentList());
@@ -4600,9 +4714,18 @@
       _reportErrorForCurrentToken(ParserErrorCode.MISSING_CLASS_BODY);
     }
     ClassDeclaration classDeclaration = new ClassDeclaration(
-        commentAndMetadata.comment, commentAndMetadata.metadata,
-        abstractKeyword, keyword, name, typeParameters, extendsClause,
-        withClause, implementsClause, leftBracket, members, rightBracket);
+        commentAndMetadata.comment,
+        commentAndMetadata.metadata,
+        abstractKeyword,
+        keyword,
+        name,
+        typeParameters,
+        extendsClause,
+        withClause,
+        implementsClause,
+        leftBracket,
+        members,
+        rightBracket);
     classDeclaration.nativeClause = nativeClause;
     return classDeclaration;
   }
@@ -4692,9 +4815,17 @@
       }
       semicolon = _createSyntheticToken(TokenType.SEMICOLON);
     }
-    return new ClassTypeAlias(commentAndMetadata.comment,
-        commentAndMetadata.metadata, classKeyword, className, typeParameters,
-        equals, abstractKeyword, superclass, withClause, implementsClause,
+    return new ClassTypeAlias(
+        commentAndMetadata.comment,
+        commentAndMetadata.metadata,
+        classKeyword,
+        className,
+        typeParameters,
+        equals,
+        abstractKeyword,
+        superclass,
+        withClause,
+        implementsClause,
         semicolon);
   }
 
@@ -4924,10 +5055,10 @@
             commentAndMetadata, modifiers.externalKeyword, returnType));
       } else if (_matchesIdentifier() &&
           _peek().matchesAny([
-        TokenType.OPEN_PAREN,
-        TokenType.OPEN_CURLY_BRACKET,
-        TokenType.FUNCTION
-      ])) {
+            TokenType.OPEN_PAREN,
+            TokenType.OPEN_CURLY_BRACKET,
+            TokenType.FUNCTION
+          ])) {
         _validateModifiersForTopLevelFunction(modifiers);
         return _parseFunctionDeclaration(
             commentAndMetadata, modifiers.externalKeyword, returnType);
@@ -4942,7 +5073,8 @@
             // We appear to have a variable declaration with a type of "void".
             //
             _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType);
-            return new TopLevelVariableDeclaration(commentAndMetadata.comment,
+            return new TopLevelVariableDeclaration(
+                commentAndMetadata.comment,
                 commentAndMetadata.metadata,
                 _parseVariableDeclarationListAfterType(null,
                     _validateModifiersForTopLevelVariable(modifiers), null),
@@ -4978,7 +5110,8 @@
         List<VariableDeclaration> variables = new List<VariableDeclaration>();
         variables.add(
             new VariableDeclaration(_createSyntheticIdentifier(), null, null));
-        return new TopLevelVariableDeclaration(commentAndMetadata.comment,
+        return new TopLevelVariableDeclaration(
+            commentAndMetadata.comment,
             commentAndMetadata.metadata,
             new VariableDeclarationList(null, null, keyword, null, variables),
             _expectSemicolon());
@@ -4997,8 +5130,10 @@
         _reportErrorForCurrentToken(
             ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
       }
-      return new TopLevelVariableDeclaration(commentAndMetadata.comment,
-          commentAndMetadata.metadata, _parseVariableDeclarationListAfterType(
+      return new TopLevelVariableDeclaration(
+          commentAndMetadata.comment,
+          commentAndMetadata.metadata,
+          _parseVariableDeclarationListAfterType(
               null, _validateModifiersForTopLevelVariable(modifiers), null),
           _expect(TokenType.SEMICOLON));
     }
@@ -5013,10 +5148,12 @@
       return _convertToFunctionDeclaration(_parseOperator(
           commentAndMetadata, modifiers.externalKeyword, returnType));
     } else if (_matches(TokenType.AT)) {
-      return new TopLevelVariableDeclaration(commentAndMetadata.comment,
-          commentAndMetadata.metadata, _parseVariableDeclarationListAfterType(
-              null, _validateModifiersForTopLevelVariable(modifiers),
-              returnType), _expect(TokenType.SEMICOLON));
+      return new TopLevelVariableDeclaration(
+          commentAndMetadata.comment,
+          commentAndMetadata.metadata,
+          _parseVariableDeclarationListAfterType(null,
+              _validateModifiersForTopLevelVariable(modifiers), returnType),
+          _expect(TokenType.SEMICOLON));
     } else if (!_matchesIdentifier()) {
       // TODO(brianwilkerson) Generalize this error. We could also be parsing a
       // top-level variable at this point.
@@ -5030,7 +5167,8 @@
       List<VariableDeclaration> variables = new List<VariableDeclaration>();
       variables.add(
           new VariableDeclaration(_createSyntheticIdentifier(), null, null));
-      return new TopLevelVariableDeclaration(commentAndMetadata.comment,
+      return new TopLevelVariableDeclaration(
+          commentAndMetadata.comment,
           commentAndMetadata.metadata,
           new VariableDeclarationList(null, null, null, returnType, variables),
           semicolon);
@@ -5044,8 +5182,10 @@
       return _parseFunctionDeclaration(
           commentAndMetadata, modifiers.externalKeyword, returnType);
     }
-    return new TopLevelVariableDeclaration(commentAndMetadata.comment,
-        commentAndMetadata.metadata, _parseVariableDeclarationListAfterType(
+    return new TopLevelVariableDeclaration(
+        commentAndMetadata.comment,
+        commentAndMetadata.metadata,
+        _parseVariableDeclarationListAfterType(
             null, _validateModifiersForTopLevelVariable(modifiers), returnType),
         _expect(TokenType.SEMICOLON));
   }
@@ -5071,9 +5211,14 @@
   }
 
   ConstructorDeclaration _parseConstructor(
-      CommentAndMetadata commentAndMetadata, Token externalKeyword,
-      Token constKeyword, Token factoryKeyword, SimpleIdentifier returnType,
-      Token period, SimpleIdentifier name, FormalParameterList parameters) {
+      CommentAndMetadata commentAndMetadata,
+      Token externalKeyword,
+      Token constKeyword,
+      Token factoryKeyword,
+      SimpleIdentifier returnType,
+      Token period,
+      SimpleIdentifier name,
+      FormalParameterList parameters) {
     bool bodyAllowed = externalKeyword == null;
     Token separator = null;
     List<ConstructorInitializer> initializers = null;
@@ -5141,10 +5286,20 @@
         }
       }
     }
-    return new ConstructorDeclaration(commentAndMetadata.comment,
-        commentAndMetadata.metadata, externalKeyword, constKeyword,
-        factoryKeyword, returnType, period, name, parameters, separator,
-        initializers, redirectedConstructor, body);
+    return new ConstructorDeclaration(
+        commentAndMetadata.comment,
+        commentAndMetadata.metadata,
+        externalKeyword,
+        constKeyword,
+        factoryKeyword,
+        returnType,
+        period,
+        name,
+        parameters,
+        separator,
+        initializers,
+        redirectedConstructor,
+        body);
   }
 
   /**
@@ -5412,8 +5567,13 @@
       rightBracket = _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET);
       _reportErrorForCurrentToken(ParserErrorCode.MISSING_ENUM_BODY);
     }
-    return new EnumDeclaration(commentAndMetadata.comment,
-        commentAndMetadata.metadata, keyword, name, leftBracket, constants,
+    return new EnumDeclaration(
+        commentAndMetadata.comment,
+        commentAndMetadata.metadata,
+        keyword,
+        name,
+        leftBracket,
+        constants,
         rightBracket);
   }
 
@@ -5459,8 +5619,12 @@
     StringLiteral libraryUri = _parseUri();
     List<Combinator> combinators = _parseCombinators();
     Token semicolon = _expectSemicolon();
-    return new ExportDirective(commentAndMetadata.comment,
-        commentAndMetadata.metadata, exportKeyword, libraryUri, combinators,
+    return new ExportDirective(
+        commentAndMetadata.comment,
+        commentAndMetadata.metadata,
+        exportKeyword,
+        libraryUri,
+        combinators,
         semicolon);
   }
 
@@ -5640,13 +5804,25 @@
           Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
           Statement body = parseStatement2();
           if (loopVariable == null) {
-            return new ForEachStatement.withReference(awaitKeyword, forKeyword,
-                leftParenthesis, identifier, inKeyword, iterator,
-                rightParenthesis, body);
+            return new ForEachStatement.withReference(
+                awaitKeyword,
+                forKeyword,
+                leftParenthesis,
+                identifier,
+                inKeyword,
+                iterator,
+                rightParenthesis,
+                body);
           }
-          return new ForEachStatement.withDeclaration(awaitKeyword, forKeyword,
-              leftParenthesis, loopVariable, inKeyword, iterator,
-              rightParenthesis, body);
+          return new ForEachStatement.withDeclaration(
+              awaitKeyword,
+              forKeyword,
+              leftParenthesis,
+              loopVariable,
+              inKeyword,
+              iterator,
+              rightParenthesis,
+              body);
         }
       }
       if (awaitKeyword != null) {
@@ -5665,9 +5841,17 @@
       }
       Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
       Statement body = parseStatement2();
-      return new ForStatement(forKeyword, leftParenthesis, variableList,
-          initialization, leftSeparator, condition, rightSeparator, updaters,
-          rightParenthesis, body);
+      return new ForStatement(
+          forKeyword,
+          leftParenthesis,
+          variableList,
+          initialization,
+          leftSeparator,
+          condition,
+          rightSeparator,
+          updaters,
+          rightParenthesis,
+          body);
     } finally {
       _inLoop = wasInLoop;
     }
@@ -5797,7 +5981,8 @@
    *       | returnType? getOrSet identifier formalParameterList functionBody
    */
   FunctionDeclaration _parseFunctionDeclaration(
-      CommentAndMetadata commentAndMetadata, Token externalKeyword,
+      CommentAndMetadata commentAndMetadata,
+      Token externalKeyword,
       TypeName returnType) {
     Token keyword = null;
     bool isGetter = false;
@@ -5823,7 +6008,10 @@
         _reportErrorForCurrentToken(
             ParserErrorCode.MISSING_FUNCTION_PARAMETERS);
         parameters = new FormalParameterList(
-            _createSyntheticToken(TokenType.OPEN_PAREN), null, null, null,
+            _createSyntheticToken(TokenType.OPEN_PAREN),
+            null,
+            null,
+            null,
             _createSyntheticToken(TokenType.CLOSE_PAREN));
       }
     } else if (_matches(TokenType.OPEN_PAREN)) {
@@ -5842,8 +6030,13 @@
 //          reportError(ParserErrorCode.UNEXPECTED_TOKEN, currentToken.getLexeme());
 //          advance();
 //        }
-    return new FunctionDeclaration(commentAndMetadata.comment,
-        commentAndMetadata.metadata, externalKeyword, returnType, keyword, name,
+    return new FunctionDeclaration(
+        commentAndMetadata.comment,
+        commentAndMetadata.metadata,
+        externalKeyword,
+        returnType,
+        keyword,
+        name,
         new FunctionExpression(typeParameters, parameters, body));
   }
 
@@ -5912,31 +6105,50 @@
     if (_matches(TokenType.SEMICOLON) || _matches(TokenType.EOF)) {
       _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS);
       FormalParameterList parameters = new FormalParameterList(
-          _createSyntheticToken(TokenType.OPEN_PAREN), null, null, null,
+          _createSyntheticToken(TokenType.OPEN_PAREN),
+          null,
+          null,
+          null,
           _createSyntheticToken(TokenType.CLOSE_PAREN));
       Token semicolon = _expect(TokenType.SEMICOLON);
-      return new FunctionTypeAlias(commentAndMetadata.comment,
-          commentAndMetadata.metadata, keyword, returnType, name,
-          typeParameters, parameters, semicolon);
+      return new FunctionTypeAlias(
+          commentAndMetadata.comment,
+          commentAndMetadata.metadata,
+          keyword,
+          returnType,
+          name,
+          typeParameters,
+          parameters,
+          semicolon);
     } else if (!_matches(TokenType.OPEN_PAREN)) {
       _reportErrorForCurrentToken(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.
-      return new FunctionTypeAlias(commentAndMetadata.comment,
-          commentAndMetadata.metadata, keyword, returnType, name,
-          typeParameters, new FormalParameterList(
-              _createSyntheticToken(TokenType.OPEN_PAREN), null, null, null,
-              _createSyntheticToken(TokenType.CLOSE_PAREN)),
+      return new FunctionTypeAlias(
+          commentAndMetadata.comment,
+          commentAndMetadata.metadata,
+          keyword,
+          returnType,
+          name,
+          typeParameters,
+          new FormalParameterList(_createSyntheticToken(TokenType.OPEN_PAREN),
+              null, null, null, _createSyntheticToken(TokenType.CLOSE_PAREN)),
           _createSyntheticToken(TokenType.SEMICOLON));
     }
     FormalParameterList parameters = parseFormalParameterList();
     _validateFormalParameterList(parameters);
     Token semicolon = _expect(TokenType.SEMICOLON);
-    return new FunctionTypeAlias(commentAndMetadata.comment,
-        commentAndMetadata.metadata, keyword, returnType, name, typeParameters,
-        parameters, semicolon);
+    return new FunctionTypeAlias(
+        commentAndMetadata.comment,
+        commentAndMetadata.metadata,
+        keyword,
+        returnType,
+        name,
+        typeParameters,
+        parameters,
+        semicolon);
   }
 
   /**
@@ -5965,13 +6177,23 @@
     }
     FunctionBody body = _parseFunctionBody(
         externalKeyword != null || staticKeyword == null,
-        ParserErrorCode.STATIC_GETTER_WITHOUT_BODY, false);
+        ParserErrorCode.STATIC_GETTER_WITHOUT_BODY,
+        false);
     if (externalKeyword != null && body is! EmptyFunctionBody) {
       _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_GETTER_WITH_BODY);
     }
-    return new MethodDeclaration(commentAndMetadata.comment,
-        commentAndMetadata.metadata, externalKeyword, staticKeyword, returnType,
-        propertyKeyword, null, name, null, null, body);
+    return new MethodDeclaration(
+        commentAndMetadata.comment,
+        commentAndMetadata.metadata,
+        externalKeyword,
+        staticKeyword,
+        returnType,
+        propertyKeyword,
+        null,
+        name,
+        null,
+        null,
+        body);
   }
 
   /**
@@ -6053,9 +6275,16 @@
     }
     List<Combinator> combinators = _parseCombinators();
     Token semicolon = _expectSemicolon();
-    return new ImportDirective(commentAndMetadata.comment,
-        commentAndMetadata.metadata, importKeyword, libraryUri, deferredToken,
-        asToken, prefix, combinators, semicolon);
+    return new ImportDirective(
+        commentAndMetadata.comment,
+        commentAndMetadata.metadata,
+        importKeyword,
+        libraryUri,
+        deferredToken,
+        asToken,
+        prefix,
+        combinators,
+        semicolon);
   }
 
   /**
@@ -6078,12 +6307,17 @@
    *         identifier ('=' expression)?
    */
   FieldDeclaration _parseInitializedIdentifierList(
-      CommentAndMetadata commentAndMetadata, Token staticKeyword, Token keyword,
+      CommentAndMetadata commentAndMetadata,
+      Token staticKeyword,
+      Token keyword,
       TypeName type) {
     VariableDeclarationList fieldList =
         _parseVariableDeclarationListAfterType(null, keyword, type);
-    return new FieldDeclaration(commentAndMetadata.comment,
-        commentAndMetadata.metadata, staticKeyword, fieldList,
+    return new FieldDeclaration(
+        commentAndMetadata.comment,
+        commentAndMetadata.metadata,
+        staticKeyword,
+        fieldList,
         _expect(TokenType.SEMICOLON));
   }
 
@@ -6161,7 +6395,8 @@
     // may be empty list literal
     if (_matches(TokenType.INDEX)) {
       BeginToken leftBracket = _createToken(
-          _currentToken, TokenType.OPEN_SQUARE_BRACKET, isBegin: true);
+          _currentToken, TokenType.OPEN_SQUARE_BRACKET,
+          isBegin: true);
       Token rightBracket =
           new Token(TokenType.CLOSE_SQUARE_BRACKET, _currentToken.offset + 1);
       leftBracket.endToken = rightBracket;
@@ -6219,8 +6454,11 @@
       return _parseListLiteral(modifier, typeArguments);
     }
     _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL);
-    return new ListLiteral(modifier, typeArguments,
-        _createSyntheticToken(TokenType.OPEN_SQUARE_BRACKET), null,
+    return new ListLiteral(
+        modifier,
+        typeArguments,
+        _createSyntheticToken(TokenType.OPEN_SQUARE_BRACKET),
+        null,
         _createSyntheticToken(TokenType.CLOSE_SQUARE_BRACKET));
   }
 
@@ -6290,12 +6528,17 @@
    *       | 'external'? functionSignature ';'
    */
   MethodDeclaration _parseMethodDeclarationAfterParameters(
-      CommentAndMetadata commentAndMetadata, Token externalKeyword,
-      Token staticKeyword, TypeName returnType, SimpleIdentifier name,
-      TypeParameterList typeParameters, FormalParameterList parameters) {
+      CommentAndMetadata commentAndMetadata,
+      Token externalKeyword,
+      Token staticKeyword,
+      TypeName returnType,
+      SimpleIdentifier name,
+      TypeParameterList typeParameters,
+      FormalParameterList parameters) {
     FunctionBody body = _parseFunctionBody(
         externalKeyword != null || staticKeyword == null,
-        ParserErrorCode.MISSING_FUNCTION_BODY, false);
+        ParserErrorCode.MISSING_FUNCTION_BODY,
+        false);
     if (externalKeyword != null) {
       if (body is! EmptyFunctionBody) {
         _reportErrorForNode(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, body);
@@ -6305,9 +6548,18 @@
         _reportErrorForNode(ParserErrorCode.ABSTRACT_STATIC_METHOD, body);
       }
     }
-    return new MethodDeclaration(commentAndMetadata.comment,
-        commentAndMetadata.metadata, externalKeyword, staticKeyword, returnType,
-        null, null, name, typeParameters, parameters, body);
+    return new MethodDeclaration(
+        commentAndMetadata.comment,
+        commentAndMetadata.metadata,
+        externalKeyword,
+        staticKeyword,
+        returnType,
+        null,
+        null,
+        name,
+        typeParameters,
+        parameters,
+        body);
   }
 
   /**
@@ -6323,8 +6575,10 @@
    *       | 'external'? functionSignature ';'
    */
   MethodDeclaration _parseMethodDeclarationAfterReturnType(
-      CommentAndMetadata commentAndMetadata, Token externalKeyword,
-      Token staticKeyword, TypeName returnType) {
+      CommentAndMetadata commentAndMetadata,
+      Token externalKeyword,
+      Token staticKeyword,
+      TypeName returnType) {
     SimpleIdentifier methodName = parseSimpleIdentifier();
     TypeParameterList typeParameters = null;
     if (parseGenericMethods && _matches(TokenType.LT)) {
@@ -6337,14 +6591,22 @@
       _reportErrorForToken(
           ParserErrorCode.MISSING_METHOD_PARAMETERS, _currentToken.previous);
       parameters = new FormalParameterList(
-          _createSyntheticToken(TokenType.OPEN_PAREN), null, null, null,
+          _createSyntheticToken(TokenType.OPEN_PAREN),
+          null,
+          null,
+          null,
           _createSyntheticToken(TokenType.CLOSE_PAREN));
     } else {
       parameters = parseFormalParameterList();
     }
     _validateFormalParameterList(parameters);
-    return _parseMethodDeclarationAfterParameters(commentAndMetadata,
-        externalKeyword, staticKeyword, returnType, methodName, typeParameters,
+    return _parseMethodDeclarationAfterParameters(
+        commentAndMetadata,
+        externalKeyword,
+        staticKeyword,
+        returnType,
+        methodName,
+        typeParameters,
         parameters);
   }
 
@@ -6552,10 +6814,10 @@
         TypeName returnType = parseReturnType();
         if (_matchesIdentifier() &&
             _peek().matchesAny([
-          TokenType.OPEN_PAREN,
-          TokenType.OPEN_CURLY_BRACKET,
-          TokenType.FUNCTION
-        ])) {
+              TokenType.OPEN_PAREN,
+              TokenType.OPEN_CURLY_BRACKET,
+              TokenType.FUNCTION
+            ])) {
           return _parseFunctionDeclarationStatementAfterReturnType(
               commentAndMetadata, returnType);
         } else {
@@ -6699,9 +6961,18 @@
     if (externalKeyword != null && body is! EmptyFunctionBody) {
       _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_OPERATOR_WITH_BODY);
     }
-    return new MethodDeclaration(commentAndMetadata.comment,
-        commentAndMetadata.metadata, externalKeyword, null, returnType, null,
-        operatorKeyword, name, null, parameters, body);
+    return new MethodDeclaration(
+        commentAndMetadata.comment,
+        commentAndMetadata.metadata,
+        externalKeyword,
+        null,
+        returnType,
+        null,
+        operatorKeyword,
+        name,
+        null,
+        parameters,
+        body);
   }
 
   /**
@@ -6746,8 +7017,12 @@
       LibraryIdentifier libraryName = _parseLibraryName(
           ParserErrorCode.MISSING_NAME_IN_PART_OF_DIRECTIVE, ofKeyword);
       Token semicolon = _expect(TokenType.SEMICOLON);
-      return new PartOfDirective(commentAndMetadata.comment,
-          commentAndMetadata.metadata, partKeyword, ofKeyword, libraryName,
+      return new PartOfDirective(
+          commentAndMetadata.comment,
+          commentAndMetadata.metadata,
+          partKeyword,
+          ofKeyword,
+          libraryName,
           semicolon);
     }
     StringLiteral partUri = _parseUri();
@@ -6836,7 +7111,8 @@
       // TODO(paulberry): verify with Gilad that "super" must be followed by
       // unconditionalAssignableSelector in this case.
       return _parseAssignableSelector(
-          new SuperExpression(getAndAdvance()), false, allowConditional: false);
+          new SuperExpression(getAndAdvance()), false,
+          allowConditional: false);
     } else if (_matchesKeyword(Keyword.NULL)) {
       return new NullLiteral(getAndAdvance());
     } else if (_matchesKeyword(Keyword.FALSE)) {
@@ -7039,13 +7315,23 @@
     _validateFormalParameterList(parameters);
     FunctionBody body = _parseFunctionBody(
         externalKeyword != null || staticKeyword == null,
-        ParserErrorCode.STATIC_SETTER_WITHOUT_BODY, false);
+        ParserErrorCode.STATIC_SETTER_WITHOUT_BODY,
+        false);
     if (externalKeyword != null && body is! EmptyFunctionBody) {
       _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY);
     }
-    return new MethodDeclaration(commentAndMetadata.comment,
-        commentAndMetadata.metadata, externalKeyword, staticKeyword, returnType,
-        propertyKeyword, null, name, null, parameters, body);
+    return new MethodDeclaration(
+        commentAndMetadata.comment,
+        commentAndMetadata.metadata,
+        externalKeyword,
+        staticKeyword,
+        returnType,
+        propertyKeyword,
+        null,
+        name,
+        null,
+        parameters,
+        body);
   }
 
   /**
@@ -7195,7 +7481,8 @@
           if (definedLabels.contains(label)) {
             _reportErrorForToken(
                 ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT,
-                identifier.token, [label]);
+                identifier.token,
+                [label]);
           } else {
             definedLabels.add(label);
           }
@@ -7353,9 +7640,16 @@
         rightParenthesis = _expect(TokenType.CLOSE_PAREN);
       }
       Block catchBody = parseBlock();
-      catchClauses.add(new CatchClause(onKeyword, exceptionType, catchKeyword,
-          leftParenthesis, exceptionParameter, comma, stackTraceParameter,
-          rightParenthesis, catchBody));
+      catchClauses.add(new CatchClause(
+          onKeyword,
+          exceptionType,
+          catchKeyword,
+          leftParenthesis,
+          exceptionParameter,
+          comma,
+          stackTraceParameter,
+          rightParenthesis,
+          catchBody));
     }
     Token finallyKeyword = null;
     if (_matchesKeyword(Keyword.FINALLY)) {
@@ -7468,8 +7762,10 @@
           secondOperator.setNext(_currentToken);
           firstOperator.setNext(secondOperator);
           operator.previous.setNext(firstOperator);
-          return new PrefixExpression(firstOperator, new PrefixExpression(
-              secondOperator, new SuperExpression(getAndAdvance())));
+          return new PrefixExpression(
+              firstOperator,
+              new PrefixExpression(
+                  secondOperator, new SuperExpression(getAndAdvance())));
         } else {
           // Invalid operator before 'super'
           _reportErrorForCurrentToken(
@@ -7608,7 +7904,9 @@
     return new VariableDeclarationList(
         commentAndMetadata != null ? commentAndMetadata.comment : null,
         commentAndMetadata != null ? commentAndMetadata.metadata : null,
-        keyword, type, variables);
+        keyword,
+        type,
+        variables);
   }
 
   /**
@@ -7867,10 +8165,10 @@
     // that should only occur at the beginning of a parameter list.
     //
     if (next.matchesAny([
-      TokenType.AT,
-      TokenType.OPEN_SQUARE_BRACKET,
-      TokenType.OPEN_CURLY_BRACKET
-    ]) ||
+          TokenType.AT,
+          TokenType.OPEN_SQUARE_BRACKET,
+          TokenType.OPEN_CURLY_BRACKET
+        ]) ||
         _tokenMatchesKeyword(next, Keyword.VOID) ||
         (_tokenMatchesIdentifier(next) &&
             (next.next.matchesAny([TokenType.COMMA, TokenType.CLOSE_PAREN])))) {
@@ -8350,20 +8648,15 @@
         } else {
           _appendScalarValue(
               buffer,
-              lexeme
-                  .substring(
-                      index,
-                      currentIndex + 1),
+              lexeme.substring(index, currentIndex + 1),
               (((((Character.digit(firstDigit, 16) << 4) +
                                   Character.digit(secondDigit, 16)) <<
                               4) +
                           Character.digit(thirdDigit, 16)) <<
                       4) +
-                  Character
-                      .digit(fourthDigit, 16),
+                  Character.digit(fourthDigit, 16),
               index,
-              currentIndex +
-                  3);
+              currentIndex + 3);
         }
         return currentIndex + 4;
       }
@@ -8705,6 +8998,7 @@
     }
   }
 }
+
 /**
  * A synthetic keyword token.
  */
@@ -8933,7 +9227,8 @@
           "Top-level declarations cannot be declared to be 'factory'");
 
   static const ParserErrorCode FACTORY_WITH_INITIALIZERS =
-      const ParserErrorCode('FACTORY_WITH_INITIALIZERS',
+      const ParserErrorCode(
+          'FACTORY_WITH_INITIALIZERS',
           "A 'factory' constructor cannot have initializers",
           "Either remove the 'factory' keyword to make this a generative "
           "constructor or remove the initializers.");
@@ -9202,7 +9497,8 @@
           "The part-of directive must be the only directive in a part");
 
   static const ParserErrorCode NON_STRING_LITERAL_AS_URI =
-      const ParserErrorCode('NON_STRING_LITERAL_AS_URI',
+      const ParserErrorCode(
+          'NON_STRING_LITERAL_AS_URI',
           "The URI must be a string literal",
           "Enclose the URI in either single or double quotes.");
 
@@ -9365,7 +9661,8 @@
   @override
   bool visitAnnotation(Annotation node) {
     Annotation toNode = this._toNode as Annotation;
-    if (_and(_isEqualTokens(node.atSign, toNode.atSign),
+    if (_and(
+        _isEqualTokens(node.atSign, toNode.atSign),
         _isEqualNodes(node.name, toNode.name),
         _isEqualTokens(node.period, toNode.period),
         _isEqualNodes(node.constructorName, toNode.constructorName),
@@ -9379,7 +9676,8 @@
   @override
   bool visitArgumentList(ArgumentList node) {
     ArgumentList toNode = this._toNode as ArgumentList;
-    return _and(_isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
+    return _and(
+        _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
         _isEqualNodeLists(node.arguments, toNode.arguments),
         _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis));
   }
@@ -9387,7 +9685,8 @@
   @override
   bool visitAsExpression(AsExpression node) {
     AsExpression toNode = this._toNode as AsExpression;
-    if (_and(_isEqualNodes(node.expression, toNode.expression),
+    if (_and(
+        _isEqualNodes(node.expression, toNode.expression),
         _isEqualTokens(node.asOperator, toNode.asOperator),
         _isEqualNodes(node.type, toNode.type))) {
       toNode.propagatedType = node.propagatedType;
@@ -9400,7 +9699,8 @@
   @override
   bool visitAssertStatement(AssertStatement node) {
     AssertStatement toNode = this._toNode as AssertStatement;
-    return _and(_isEqualTokens(node.assertKeyword, toNode.assertKeyword),
+    return _and(
+        _isEqualTokens(node.assertKeyword, toNode.assertKeyword),
         _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
         _isEqualNodes(node.condition, toNode.condition),
         _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
@@ -9410,7 +9710,8 @@
   @override
   bool visitAssignmentExpression(AssignmentExpression node) {
     AssignmentExpression toNode = this._toNode as AssignmentExpression;
-    if (_and(_isEqualNodes(node.leftHandSide, toNode.leftHandSide),
+    if (_and(
+        _isEqualNodes(node.leftHandSide, toNode.leftHandSide),
         _isEqualTokens(node.operator, toNode.operator),
         _isEqualNodes(node.rightHandSide, toNode.rightHandSide))) {
       toNode.propagatedElement = node.propagatedElement;
@@ -9437,7 +9738,8 @@
   @override
   bool visitBinaryExpression(BinaryExpression node) {
     BinaryExpression toNode = this._toNode as BinaryExpression;
-    if (_and(_isEqualNodes(node.leftOperand, toNode.leftOperand),
+    if (_and(
+        _isEqualNodes(node.leftOperand, toNode.leftOperand),
         _isEqualTokens(node.operator, toNode.operator),
         _isEqualNodes(node.rightOperand, toNode.rightOperand))) {
       toNode.propagatedElement = node.propagatedElement;
@@ -9452,7 +9754,8 @@
   @override
   bool visitBlock(Block node) {
     Block toNode = this._toNode as Block;
-    return _and(_isEqualTokens(node.leftBracket, toNode.leftBracket),
+    return _and(
+        _isEqualTokens(node.leftBracket, toNode.leftBracket),
         _isEqualNodeLists(node.statements, toNode.statements),
         _isEqualTokens(node.rightBracket, toNode.rightBracket));
   }
@@ -9478,7 +9781,8 @@
   @override
   bool visitBreakStatement(BreakStatement node) {
     BreakStatement toNode = this._toNode as BreakStatement;
-    if (_and(_isEqualTokens(node.breakKeyword, toNode.breakKeyword),
+    if (_and(
+        _isEqualTokens(node.breakKeyword, toNode.breakKeyword),
         _isEqualNodes(node.label, toNode.label),
         _isEqualTokens(node.semicolon, toNode.semicolon))) {
       // TODO(paulberry): map node.target to toNode.target.
@@ -9502,7 +9806,8 @@
   @override
   bool visitCatchClause(CatchClause node) {
     CatchClause toNode = this._toNode as CatchClause;
-    return _and(_isEqualTokens(node.onKeyword, toNode.onKeyword),
+    return _and(
+        _isEqualTokens(node.onKeyword, toNode.onKeyword),
         _isEqualNodes(node.exceptionType, toNode.exceptionType),
         _isEqualTokens(node.catchKeyword, toNode.catchKeyword),
         _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
@@ -9564,7 +9869,8 @@
   @override
   bool visitCompilationUnit(CompilationUnit node) {
     CompilationUnit toNode = this._toNode as CompilationUnit;
-    if (_and(_isEqualTokens(node.beginToken, toNode.beginToken),
+    if (_and(
+        _isEqualTokens(node.beginToken, toNode.beginToken),
         _isEqualNodes(node.scriptTag, toNode.scriptTag),
         _isEqualNodeLists(node.directives, toNode.directives),
         _isEqualNodeLists(node.declarations, toNode.declarations),
@@ -9578,7 +9884,8 @@
   @override
   bool visitConditionalExpression(ConditionalExpression node) {
     ConditionalExpression toNode = this._toNode as ConditionalExpression;
-    if (_and(_isEqualNodes(node.condition, toNode.condition),
+    if (_and(
+        _isEqualNodes(node.condition, toNode.condition),
         _isEqualTokens(node.question, toNode.question),
         _isEqualNodes(node.thenExpression, toNode.thenExpression),
         _isEqualTokens(node.colon, toNode.colon),
@@ -9617,7 +9924,8 @@
   bool visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
     ConstructorFieldInitializer toNode =
         this._toNode as ConstructorFieldInitializer;
-    return _and(_isEqualTokens(node.thisKeyword, toNode.thisKeyword),
+    return _and(
+        _isEqualTokens(node.thisKeyword, toNode.thisKeyword),
         _isEqualTokens(node.period, toNode.period),
         _isEqualNodes(node.fieldName, toNode.fieldName),
         _isEqualTokens(node.equals, toNode.equals),
@@ -9627,7 +9935,8 @@
   @override
   bool visitConstructorName(ConstructorName node) {
     ConstructorName toNode = this._toNode as ConstructorName;
-    if (_and(_isEqualNodes(node.type, toNode.type),
+    if (_and(
+        _isEqualNodes(node.type, toNode.type),
         _isEqualTokens(node.period, toNode.period),
         _isEqualNodes(node.name, toNode.name))) {
       toNode.staticElement = node.staticElement;
@@ -9639,7 +9948,8 @@
   @override
   bool visitContinueStatement(ContinueStatement node) {
     ContinueStatement toNode = this._toNode as ContinueStatement;
-    if (_and(_isEqualTokens(node.continueKeyword, toNode.continueKeyword),
+    if (_and(
+        _isEqualTokens(node.continueKeyword, toNode.continueKeyword),
         _isEqualNodes(node.label, toNode.label),
         _isEqualTokens(node.semicolon, toNode.semicolon))) {
       // TODO(paulberry): map node.target to toNode.target.
@@ -9662,7 +9972,8 @@
   @override
   bool visitDefaultFormalParameter(DefaultFormalParameter node) {
     DefaultFormalParameter toNode = this._toNode as DefaultFormalParameter;
-    return _and(_isEqualNodes(node.parameter, toNode.parameter),
+    return _and(
+        _isEqualNodes(node.parameter, toNode.parameter),
         node.kind == toNode.kind,
         _isEqualTokens(node.separator, toNode.separator),
         _isEqualNodes(node.defaultValue, toNode.defaultValue));
@@ -9671,7 +9982,8 @@
   @override
   bool visitDoStatement(DoStatement node) {
     DoStatement toNode = this._toNode as DoStatement;
-    return _and(_isEqualTokens(node.doKeyword, toNode.doKeyword),
+    return _and(
+        _isEqualTokens(node.doKeyword, toNode.doKeyword),
         _isEqualNodes(node.body, toNode.body),
         _isEqualTokens(node.whileKeyword, toNode.whileKeyword),
         _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
@@ -9792,7 +10104,8 @@
   @override
   bool visitForEachStatement(ForEachStatement node) {
     ForEachStatement toNode = this._toNode as ForEachStatement;
-    return _and(_isEqualTokens(node.forKeyword, toNode.forKeyword),
+    return _and(
+        _isEqualTokens(node.forKeyword, toNode.forKeyword),
         _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
         _isEqualNodes(node.loopVariable, toNode.loopVariable),
         _isEqualTokens(node.inKeyword, toNode.inKeyword),
@@ -9804,7 +10117,8 @@
   @override
   bool visitFormalParameterList(FormalParameterList node) {
     FormalParameterList toNode = this._toNode as FormalParameterList;
-    return _and(_isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
+    return _and(
+        _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
         _isEqualNodeLists(node.parameters, toNode.parameters),
         _isEqualTokens(node.leftDelimiter, toNode.leftDelimiter),
         _isEqualTokens(node.rightDelimiter, toNode.rightDelimiter),
@@ -9814,7 +10128,8 @@
   @override
   bool visitForStatement(ForStatement node) {
     ForStatement toNode = this._toNode as ForStatement;
-    return _and(_isEqualTokens(node.forKeyword, toNode.forKeyword),
+    return _and(
+        _isEqualTokens(node.forKeyword, toNode.forKeyword),
         _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
         _isEqualNodes(node.variables, toNode.variables),
         _isEqualNodes(node.initialization, toNode.initialization),
@@ -9910,7 +10225,8 @@
   @override
   bool visitIfStatement(IfStatement node) {
     IfStatement toNode = this._toNode as IfStatement;
-    return _and(_isEqualTokens(node.ifKeyword, toNode.ifKeyword),
+    return _and(
+        _isEqualTokens(node.ifKeyword, toNode.ifKeyword),
         _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
         _isEqualNodes(node.condition, toNode.condition),
         _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
@@ -9948,7 +10264,8 @@
   @override
   bool visitIndexExpression(IndexExpression node) {
     IndexExpression toNode = this._toNode as IndexExpression;
-    if (_and(_isEqualNodes(node.target, toNode.target),
+    if (_and(
+        _isEqualNodes(node.target, toNode.target),
         _isEqualTokens(node.leftBracket, toNode.leftBracket),
         _isEqualNodes(node.index, toNode.index),
         _isEqualTokens(node.rightBracket, toNode.rightBracket))) {
@@ -9966,7 +10283,8 @@
   bool visitInstanceCreationExpression(InstanceCreationExpression node) {
     InstanceCreationExpression toNode =
         this._toNode as InstanceCreationExpression;
-    if (_and(_isEqualTokens(node.keyword, toNode.keyword),
+    if (_and(
+        _isEqualTokens(node.keyword, toNode.keyword),
         _isEqualNodes(node.constructorName, toNode.constructorName),
         _isEqualNodes(node.argumentList, toNode.argumentList))) {
       toNode.propagatedType = node.propagatedType;
@@ -9992,7 +10310,8 @@
   @override
   bool visitInterpolationExpression(InterpolationExpression node) {
     InterpolationExpression toNode = this._toNode as InterpolationExpression;
-    return _and(_isEqualTokens(node.leftBracket, toNode.leftBracket),
+    return _and(
+        _isEqualTokens(node.leftBracket, toNode.leftBracket),
         _isEqualNodes(node.expression, toNode.expression),
         _isEqualTokens(node.rightBracket, toNode.rightBracket));
   }
@@ -10007,7 +10326,8 @@
   @override
   bool visitIsExpression(IsExpression node) {
     IsExpression toNode = this._toNode as IsExpression;
-    if (_and(_isEqualNodes(node.expression, toNode.expression),
+    if (_and(
+        _isEqualNodes(node.expression, toNode.expression),
         _isEqualTokens(node.isOperator, toNode.isOperator),
         _isEqualTokens(node.notOperator, toNode.notOperator),
         _isEqualNodes(node.type, toNode.type))) {
@@ -10061,7 +10381,8 @@
   @override
   bool visitListLiteral(ListLiteral node) {
     ListLiteral toNode = this._toNode as ListLiteral;
-    if (_and(_isEqualTokens(node.constKeyword, toNode.constKeyword),
+    if (_and(
+        _isEqualTokens(node.constKeyword, toNode.constKeyword),
         _isEqualNodes(node.typeArguments, toNode.typeArguments),
         _isEqualTokens(node.leftBracket, toNode.leftBracket),
         _isEqualNodeLists(node.elements, toNode.elements),
@@ -10076,7 +10397,8 @@
   @override
   bool visitMapLiteral(MapLiteral node) {
     MapLiteral toNode = this._toNode as MapLiteral;
-    if (_and(_isEqualTokens(node.constKeyword, toNode.constKeyword),
+    if (_and(
+        _isEqualTokens(node.constKeyword, toNode.constKeyword),
         _isEqualNodes(node.typeArguments, toNode.typeArguments),
         _isEqualTokens(node.leftBracket, toNode.leftBracket),
         _isEqualNodeLists(node.entries, toNode.entries),
@@ -10091,7 +10413,8 @@
   @override
   bool visitMapLiteralEntry(MapLiteralEntry node) {
     MapLiteralEntry toNode = this._toNode as MapLiteralEntry;
-    return _and(_isEqualNodes(node.key, toNode.key),
+    return _and(
+        _isEqualNodes(node.key, toNode.key),
         _isEqualTokens(node.separator, toNode.separator),
         _isEqualNodes(node.value, toNode.value));
   }
@@ -10115,7 +10438,8 @@
   @override
   bool visitMethodInvocation(MethodInvocation node) {
     MethodInvocation toNode = this._toNode as MethodInvocation;
-    if (_and(_isEqualNodes(node.target, toNode.target),
+    if (_and(
+        _isEqualNodes(node.target, toNode.target),
         _isEqualTokens(node.operator, toNode.operator),
         _isEqualNodes(node.methodName, toNode.methodName),
         _isEqualNodes(node.argumentList, toNode.argumentList))) {
@@ -10148,7 +10472,8 @@
   @override
   bool visitNativeFunctionBody(NativeFunctionBody node) {
     NativeFunctionBody toNode = this._toNode as NativeFunctionBody;
-    return _and(_isEqualTokens(node.nativeKeyword, toNode.nativeKeyword),
+    return _and(
+        _isEqualTokens(node.nativeKeyword, toNode.nativeKeyword),
         _isEqualNodes(node.stringLiteral, toNode.stringLiteral),
         _isEqualTokens(node.semicolon, toNode.semicolon));
   }
@@ -10167,7 +10492,8 @@
   @override
   bool visitParenthesizedExpression(ParenthesizedExpression node) {
     ParenthesizedExpression toNode = this._toNode as ParenthesizedExpression;
-    if (_and(_isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
+    if (_and(
+        _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
         _isEqualNodes(node.expression, toNode.expression),
         _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis))) {
       toNode.propagatedType = node.propagatedType;
@@ -10225,7 +10551,8 @@
   @override
   bool visitPrefixedIdentifier(PrefixedIdentifier node) {
     PrefixedIdentifier toNode = this._toNode as PrefixedIdentifier;
-    if (_and(_isEqualNodes(node.prefix, toNode.prefix),
+    if (_and(
+        _isEqualNodes(node.prefix, toNode.prefix),
         _isEqualTokens(node.period, toNode.period),
         _isEqualNodes(node.identifier, toNode.identifier))) {
       toNode.propagatedType = node.propagatedType;
@@ -10252,7 +10579,8 @@
   @override
   bool visitPropertyAccess(PropertyAccess node) {
     PropertyAccess toNode = this._toNode as PropertyAccess;
-    if (_and(_isEqualNodes(node.target, toNode.target),
+    if (_and(
+        _isEqualNodes(node.target, toNode.target),
         _isEqualTokens(node.operator, toNode.operator),
         _isEqualNodes(node.propertyName, toNode.propertyName))) {
       toNode.propagatedType = node.propagatedType;
@@ -10267,7 +10595,8 @@
       RedirectingConstructorInvocation node) {
     RedirectingConstructorInvocation toNode =
         this._toNode as RedirectingConstructorInvocation;
-    if (_and(_isEqualTokens(node.thisKeyword, toNode.thisKeyword),
+    if (_and(
+        _isEqualTokens(node.thisKeyword, toNode.thisKeyword),
         _isEqualTokens(node.period, toNode.period),
         _isEqualNodes(node.constructorName, toNode.constructorName),
         _isEqualNodes(node.argumentList, toNode.argumentList))) {
@@ -10291,7 +10620,8 @@
   @override
   bool visitReturnStatement(ReturnStatement node) {
     ReturnStatement toNode = this._toNode as ReturnStatement;
-    return _and(_isEqualTokens(node.returnKeyword, toNode.returnKeyword),
+    return _and(
+        _isEqualTokens(node.returnKeyword, toNode.returnKeyword),
         _isEqualNodes(node.expression, toNode.expression),
         _isEqualTokens(node.semicolon, toNode.semicolon));
   }
@@ -10361,7 +10691,8 @@
   bool visitSuperConstructorInvocation(SuperConstructorInvocation node) {
     SuperConstructorInvocation toNode =
         this._toNode as SuperConstructorInvocation;
-    if (_and(_isEqualTokens(node.superKeyword, toNode.superKeyword),
+    if (_and(
+        _isEqualTokens(node.superKeyword, toNode.superKeyword),
         _isEqualTokens(node.period, toNode.period),
         _isEqualNodes(node.constructorName, toNode.constructorName),
         _isEqualNodes(node.argumentList, toNode.argumentList))) {
@@ -10385,7 +10716,8 @@
   @override
   bool visitSwitchCase(SwitchCase node) {
     SwitchCase toNode = this._toNode as SwitchCase;
-    return _and(_isEqualNodeLists(node.labels, toNode.labels),
+    return _and(
+        _isEqualNodeLists(node.labels, toNode.labels),
         _isEqualTokens(node.keyword, toNode.keyword),
         _isEqualNodes(node.expression, toNode.expression),
         _isEqualTokens(node.colon, toNode.colon),
@@ -10395,7 +10727,8 @@
   @override
   bool visitSwitchDefault(SwitchDefault node) {
     SwitchDefault toNode = this._toNode as SwitchDefault;
-    return _and(_isEqualNodeLists(node.labels, toNode.labels),
+    return _and(
+        _isEqualNodeLists(node.labels, toNode.labels),
         _isEqualTokens(node.keyword, toNode.keyword),
         _isEqualTokens(node.colon, toNode.colon),
         _isEqualNodeLists(node.statements, toNode.statements));
@@ -10404,7 +10737,8 @@
   @override
   bool visitSwitchStatement(SwitchStatement node) {
     SwitchStatement toNode = this._toNode as SwitchStatement;
-    return _and(_isEqualTokens(node.switchKeyword, toNode.switchKeyword),
+    return _and(
+        _isEqualTokens(node.switchKeyword, toNode.switchKeyword),
         _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
         _isEqualNodes(node.expression, toNode.expression),
         _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
@@ -10462,7 +10796,8 @@
   @override
   bool visitTryStatement(TryStatement node) {
     TryStatement toNode = this._toNode as TryStatement;
-    return _and(_isEqualTokens(node.tryKeyword, toNode.tryKeyword),
+    return _and(
+        _isEqualTokens(node.tryKeyword, toNode.tryKeyword),
         _isEqualNodes(node.body, toNode.body),
         _isEqualNodeLists(node.catchClauses, toNode.catchClauses),
         _isEqualTokens(node.finallyKeyword, toNode.finallyKeyword),
@@ -10472,7 +10807,8 @@
   @override
   bool visitTypeArgumentList(TypeArgumentList node) {
     TypeArgumentList toNode = this._toNode as TypeArgumentList;
-    return _and(_isEqualTokens(node.leftBracket, toNode.leftBracket),
+    return _and(
+        _isEqualTokens(node.leftBracket, toNode.leftBracket),
         _isEqualNodeLists(node.arguments, toNode.arguments),
         _isEqualTokens(node.rightBracket, toNode.rightBracket));
   }
@@ -10502,7 +10838,8 @@
   @override
   bool visitTypeParameterList(TypeParameterList node) {
     TypeParameterList toNode = this._toNode as TypeParameterList;
-    return _and(_isEqualTokens(node.leftBracket, toNode.leftBracket),
+    return _and(
+        _isEqualTokens(node.leftBracket, toNode.leftBracket),
         _isEqualNodeLists(node.typeParameters, toNode.typeParameters),
         _isEqualTokens(node.rightBracket, toNode.rightBracket));
   }
@@ -10540,7 +10877,8 @@
   @override
   bool visitWhileStatement(WhileStatement node) {
     WhileStatement toNode = this._toNode as WhileStatement;
-    return _and(_isEqualTokens(node.whileKeyword, toNode.whileKeyword),
+    return _and(
+        _isEqualTokens(node.whileKeyword, toNode.whileKeyword),
         _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
         _isEqualNodes(node.condition, toNode.condition),
         _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
@@ -10557,7 +10895,8 @@
   @override
   bool visitYieldStatement(YieldStatement node) {
     YieldStatement toNode = this._toNode as YieldStatement;
-    return _and(_isEqualTokens(node.yieldKeyword, toNode.yieldKeyword),
+    return _and(
+        _isEqualTokens(node.yieldKeyword, toNode.yieldKeyword),
         _isEqualNodes(node.expression, toNode.expression),
         _isEqualTokens(node.semicolon, toNode.semicolon));
   }
@@ -10565,9 +10904,18 @@
   /**
    * Return `true` if all of the parameters are `true`.
    */
-  bool _and(bool b1, bool b2, [bool b3 = true, bool b4 = true, bool b5 = true,
-      bool b6 = true, bool b7 = true, bool b8 = true, bool b9 = true,
-      bool b10 = true, bool b11 = true, bool b12 = true, bool b13 = true]) {
+  bool _and(bool b1, bool b2,
+      [bool b3 = true,
+      bool b4 = true,
+      bool b5 = true,
+      bool b6 = true,
+      bool b7 = true,
+      bool b8 = true,
+      bool b9 = true,
+      bool b10 = true,
+      bool b11 = true,
+      bool b12 = true,
+      bool b13 = true]) {
     // TODO(brianwilkerson) Inline this method.
     return b1 &&
         b2 &&
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 4a17411..36d68f9 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -9547,6 +9547,154 @@
 }
 
 /**
+ * An AST visitor that is used to resolve the some of the nodes within a single
+ * compilation unit. The nodes that are skipped are those that are within
+ * function bodies.
+ */
+class PartialResolverVisitor extends ResolverVisitor {
+  /**
+   * A flag indicating whether the resolver is being run in strong mode.
+   */
+  final bool strongMode;
+
+  /**
+   * The static variables that have an initializer. These are the variables that
+   * need to be re-resolved after static variables have their types inferred. A
+   * subset of these variables are those whose types should be inferred. The
+   * list will be empty unless the resolver is being run in strong mode.
+   */
+  final List<VariableElement> staticVariables = <VariableElement>[];
+
+  /**
+   * A flag indicating whether we should discard errors while resolving the
+   * initializer for variable declarations. We do this for top-level variables
+   * and fields because their initializer will be re-resolved at a later time.
+   */
+  bool discardErrorsInInitializer = false;
+
+  /**
+   * Initialize a newly created visitor to resolve the nodes in an AST node.
+   *
+   * The [definingLibrary] is the element for the library containing the node
+   * being visited. The [source] is the source representing the compilation unit
+   * containing the node being visited. The [typeProvider] is the object used to
+   * access the types from the core library. The [errorListener] is the error
+   * listener that will be informed of any errors that are found during
+   * resolution. The [nameScope] is the scope used to resolve identifiers in the
+   * node that will first be visited.  If `null` or unspecified, a new
+   * [LibraryScope] will be created based on [definingLibrary] and
+   * [typeProvider]. The [inheritanceManager] is used to perform inheritance
+   * lookups.  If `null` or unspecified, a new [InheritanceManager] will be
+   * created based on [definingLibrary]. The [typeAnalyzerFactory] is used to
+   * create the type analyzer.  If `null` or unspecified, a type analyzer of
+   * type [StaticTypeAnalyzer] will be created.
+   */
+  PartialResolverVisitor(LibraryElement definingLibrary, Source source,
+      TypeProvider typeProvider, AnalysisErrorListener errorListener,
+      {Scope nameScope,
+      InheritanceManager inheritanceManager,
+      StaticTypeAnalyzerFactory typeAnalyzerFactory})
+      : strongMode = definingLibrary.context.analysisOptions.strongMode,
+        super(definingLibrary, source, typeProvider,
+            new DisablableErrorListener(errorListener));
+
+  @override
+  Object visitBlockFunctionBody(BlockFunctionBody node) {
+    if (_shouldBeSkipped(node)) {
+      return null;
+    }
+    return super.visitBlockFunctionBody(node);
+  }
+
+  @override
+  Object visitExpressionFunctionBody(ExpressionFunctionBody node) {
+    if (_shouldBeSkipped(node)) {
+      return null;
+    }
+    return super.visitExpressionFunctionBody(node);
+  }
+
+  @override
+  Object visitFieldDeclaration(FieldDeclaration node) {
+    if (strongMode && node.isStatic) {
+      _addStaticVariables(node.fields.variables);
+      bool wasDiscarding = discardErrorsInInitializer;
+      discardErrorsInInitializer = true;
+      try {
+        return super.visitFieldDeclaration(node);
+      } finally {
+        discardErrorsInInitializer = wasDiscarding;
+      }
+    }
+    return super.visitFieldDeclaration(node);
+  }
+
+  @override
+  Object visitNode(AstNode node) {
+    if (discardErrorsInInitializer) {
+      AstNode parent = node.parent;
+      if (parent is VariableDeclaration && parent.initializer == node) {
+        DisablableErrorListener listener = errorListener;
+        return listener.disableWhile(() => super.visitNode(node));
+      }
+    }
+    return super.visitNode(node);
+  }
+
+  @override
+  Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
+    if (strongMode) {
+      _addStaticVariables(node.variables.variables);
+      bool wasDiscarding = discardErrorsInInitializer;
+      discardErrorsInInitializer = true;
+      try {
+        return super.visitTopLevelVariableDeclaration(node);
+      } finally {
+        discardErrorsInInitializer = wasDiscarding;
+      }
+    }
+    return super.visitTopLevelVariableDeclaration(node);
+  }
+
+  /**
+   * Add all of the [variables] with initializers to the list of variables whose
+   * type can be inferred. Technically, we only infer the types of variables
+   * that do not have a static type, but all variables with initializers
+   * potentially need to be re-resolved after inference because they might
+   * refer to a field whose type was inferred.
+   */
+  void _addStaticVariables(NodeList<VariableDeclaration> variables) {
+    for (VariableDeclaration variable in variables) {
+      if (variable.initializer != null) {
+        staticVariables.add(variable.element);
+      }
+    }
+  }
+
+  /**
+   * Return `true` if the given function body should be skipped because it is
+   * the body of a top-level function, method or constructor.
+   */
+  bool _shouldBeSkipped(FunctionBody body) {
+    AstNode parent = body.parent;
+    if (parent is MethodDeclaration) {
+      return parent.body == body;
+    }
+    if (parent is ConstructorDeclaration) {
+      return parent.body == body;
+    }
+    if (parent is FunctionExpression) {
+      AstNode parent2 = parent.parent;
+      if (parent2 is FunctionDeclaration &&
+          parent2.parent is! FunctionDeclarationStatement) {
+        return parent.body == body;
+      }
+    }
+    return false;
+  }
+}
+
+/**
  * Instances of the class `PubVerifier` traverse an AST structure looking for deviations from
  * pub best practices.
  */
@@ -10132,21 +10280,19 @@
   /**
    * Initialize a newly created visitor to resolve the nodes in an AST node.
    *
-   * [definingLibrary] is the element for the library containing the node being
-   * visited.
-   * [source] is the source representing the compilation unit containing the
-   * node being visited.
-   * [typeProvider] the object used to access the types from the core library.
-   * [errorListener] the error listener that will be informed of any errors
-   * that are found during resolution.
-   * [nameScope] is the scope used to resolve identifiers in the node that will
-   * first be visited.  If `null` or unspecified, a new [LibraryScope] will be
-   * created based on [definingLibrary] and [typeProvider].
-   * [inheritanceManager] is used to perform inheritance lookups.  If `null` or
-   * unspecified, a new [InheritanceManager] will be created based on
-   * [definingLibrary].
-   * [typeAnalyzerFactory] is used to create the type analyzer.  If `null` or
-   * unspecified, a type analyzer of type [StaticTypeAnalyzer] will be created.
+   * The [definingLibrary] is the element for the library containing the node
+   * being visited. The [source] is the source representing the compilation unit
+   * containing the node being visited. The [typeProvider] is the object used to
+   * access the types from the core library. The [errorListener] is the error
+   * listener that will be informed of any errors that are found during
+   * resolution. The [nameScope] is the scope used to resolve identifiers in the
+   * node that will first be visited.  If `null` or unspecified, a new
+   * [LibraryScope] will be created based on [definingLibrary] and
+   * [typeProvider]. The [inheritanceManager] is used to perform inheritance
+   * lookups.  If `null` or unspecified, a new [InheritanceManager] will be
+   * created based on [definingLibrary]. The [typeAnalyzerFactory] is used to
+   * create the type analyzer.  If `null` or unspecified, a type analyzer of
+   * type [StaticTypeAnalyzer] will be created.
    */
   ResolverVisitor(LibraryElement definingLibrary, Source source,
       TypeProvider typeProvider, AnalysisErrorListener errorListener,
@@ -10285,7 +10431,14 @@
   /**
    * Prepares this [ResolverVisitor] to using it for incremental resolution.
    */
-  void initForIncrementalResolution() {
+  void initForIncrementalResolution([Declaration declaration = null]) {
+    if (declaration != null) {
+      Element element = declaration.element;
+      if (element is ExecutableElement) {
+        _enclosingFunction = element;
+      }
+      _commentBeforeFunction = declaration.documentationComment;
+    }
     _overrideManager.enterScope();
   }
 
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index e6d7a54..31bd28a 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -602,8 +602,8 @@
   SourceFactory(this._resolvers,
       [this._packages, ResourceProvider resourceProvider])
       : _resourceProvider = resourceProvider != null
-          ? resourceProvider
-          : PhysicalResourceProvider.INSTANCE;
+            ? resourceProvider
+            : PhysicalResourceProvider.INSTANCE;
 
   /**
    * Return the [DartSdk] associated with this [SourceFactory], or `null` if there
@@ -639,16 +639,17 @@
       Map<String, List<Folder>> packageMap = <String, List<Folder>>{};
       _packages.asMap().forEach((String name, Uri uri) {
         if (uri.scheme == 'file' || uri.scheme == '' /* unspecified */) {
-          packageMap[name] =
-              <Folder>[_resourceProvider.getFolder(uri.toFilePath())];
+          packageMap[name] = <Folder>[
+            _resourceProvider.getFolder(uri.toFilePath())
+          ];
         }
       });
       return packageMap;
     }
 
     // Default to the PackageMapUriResolver.
-    PackageMapUriResolver resolver = _resolvers.firstWhere(
-        (r) => r is PackageMapUriResolver, orElse: () => null);
+    PackageMapUriResolver resolver = _resolvers
+        .firstWhere((r) => r is PackageMapUriResolver, orElse: () => null);
     return resolver != null ? resolver.packageMap : null;
   }
 
diff --git a/pkg/analyzer/lib/src/generated/source_io.dart b/pkg/analyzer/lib/src/generated/source_io.dart
index 76d3396..4708aa0 100644
--- a/pkg/analyzer/lib/src/generated/source_io.dart
+++ b/pkg/analyzer/lib/src/generated/source_io.dart
@@ -415,8 +415,10 @@
             new CaughtException(exception, stackTrace));
       }
     }
-    return new JavaFile.relative(pkgDir, relPath.replaceAll(
-        '/', new String.fromCharCode(JavaFile.separatorChar)));
+    return new JavaFile.relative(
+        pkgDir,
+        relPath.replaceAll(
+            '/', new String.fromCharCode(JavaFile.separatorChar)));
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index bffeaad..3da6e37 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -328,7 +328,9 @@
         node.element as ExecutableElementImpl;
     functionElement.returnType =
         _computeStaticReturnTypeOfFunctionDeclaration(node);
-    _recordPropagatedTypeOfFunction(functionElement, function.body);
+    if (node.parent is FunctionDeclarationStatement) {
+      _recordPropagatedTypeOfFunction(functionElement, function.body);
+    }
     _recordStaticType(function, functionElement.type);
     return null;
   }
diff --git a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
index d0d9c00..5b5204a 100644
--- a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
+++ b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
@@ -337,13 +337,13 @@
 
   @override
   List<InterfaceType> get nonSubtypableTypes => <InterfaceType>[
-    nullType,
-    numType,
-    intType,
-    doubleType,
-    boolType,
-    stringType
-  ];
+        nullType,
+        numType,
+        intType,
+        doubleType,
+        boolType,
+        stringType
+      ];
 
   @override
   DartObjectImpl get nullObject {
diff --git a/pkg/analyzer/lib/src/generated/visitors.dart b/pkg/analyzer/lib/src/generated/visitors.dart
index defb317..59e644f 100644
--- a/pkg/analyzer/lib/src/generated/visitors.dart
+++ b/pkg/analyzer/lib/src/generated/visitors.dart
@@ -303,6 +303,7 @@
     node.visitChildren(this);
     return null;
   }
+
   @override
   T visitFunctionDeclaration(FunctionDeclaration node) {
     _delegates.forEach((delegate) => delegate.visitFunctionDeclaration(node));
@@ -475,6 +476,7 @@
     node.visitChildren(this);
     return null;
   }
+
   @override
   T visitMethodInvocation(MethodInvocation node) {
     _delegates.forEach((delegate) => delegate.visitMethodInvocation(node));
@@ -545,6 +547,7 @@
     node.visitChildren(this);
     return null;
   }
+
   @override
   T visitPrefixedIdentifier(PrefixedIdentifier node) {
     _delegates.forEach((delegate) => delegate.visitPrefixedIdentifier(node));
diff --git a/pkg/analyzer/lib/src/plugin/engine_plugin.dart b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
index 65ead96..75debaa 100644
--- a/pkg/analyzer/lib/src/plugin/engine_plugin.dart
+++ b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
@@ -7,6 +7,7 @@
 import 'package:analyzer/plugin/task.dart';
 import 'package:analyzer/src/generated/engine.dart'
     show InternalAnalysisContext;
+import 'package:analyzer/src/generated/error.dart' show AnalysisError;
 import 'package:analyzer/src/task/dart.dart';
 import 'package:analyzer/src/task/dart_work_manager.dart';
 import 'package:analyzer/src/task/general.dart';
@@ -22,6 +23,27 @@
 class EnginePlugin implements Plugin {
   /**
    * The simple identifier of the extension point that allows plugins to
+   * register new analysis error results to compute for a Dart source.
+   */
+  static const String DART_ERRORS_FOR_SOURCE_EXTENSION_POINT =
+      'dartErrorsForSource';
+
+  /**
+   * The simple identifier of the extension point that allows plugins to
+   * register new analysis error results to compute for a Dart library
+   * specific unit.
+   */
+  static const String DART_ERRORS_FOR_UNIT_EXTENSION_POINT =
+      'dartErrorsForUnit';
+
+  /**
+   * The simple identifier of the extension point that allows plugins to
+   * register new analysis error results to compute for an HTML source.
+   */
+  static const String HTML_ERRORS_EXTENSION_POINT = 'htmlErrors';
+
+  /**
+   * The simple identifier of the extension point that allows plugins to
    * register new analysis tasks with the analysis engine.
    */
   static const String TASK_EXTENSION_POINT = 'task';
@@ -39,6 +61,24 @@
   static const String UNIQUE_IDENTIFIER = 'analysis_engine.core';
 
   /**
+   * The extension point that allows plugins to register new analysis error
+   * results for a Dart source.
+   */
+  ExtensionPoint dartErrorsForSourceExtensionPoint;
+
+  /**
+   * The extension point that allows plugins to register new analysis error
+   * results for a Dart library specific unit.
+   */
+  ExtensionPoint dartErrorsForUnitExtensionPoint;
+
+  /**
+   * The extension point that allows plugins to register new analysis error
+   * results for an HTML source.
+   */
+  ExtensionPoint htmlErrorsExtensionPoint;
+
+  /**
    * The extension point that allows plugins to register new analysis tasks with
    * the analysis engine.
    */
@@ -56,6 +96,26 @@
   EnginePlugin();
 
   /**
+   * Return a list containing all of the contributed analysis error result
+   * descriptors for Dart sources.
+   */
+  List<TaskDescriptor> get dartErrorsForSource =>
+      dartErrorsForSourceExtensionPoint.extensions;
+
+  /**
+   * Return a list containing all of the contributed analysis error result
+   * descriptors for Dart library specific units.
+   */
+  List<TaskDescriptor> get dartErrorsForUnit =>
+      dartErrorsForUnitExtensionPoint.extensions;
+
+  /**
+   * Return a list containing all of the contributed analysis error result
+   * descriptors for HTML sources.
+   */
+  List<TaskDescriptor> get htmlErrors => htmlErrorsExtensionPoint.extensions;
+
+  /**
    * Return a list containing all of the task descriptors that were contributed.
    */
   List<TaskDescriptor> get taskDescriptors => taskExtensionPoint.extensions;
@@ -72,6 +132,15 @@
 
   @override
   void registerExtensionPoints(RegisterExtensionPoint registerExtensionPoint) {
+    dartErrorsForSourceExtensionPoint = registerExtensionPoint(
+        DART_ERRORS_FOR_SOURCE_EXTENSION_POINT,
+        _validateAnalysisErrorListResultDescriptor);
+    dartErrorsForUnitExtensionPoint = registerExtensionPoint(
+        DART_ERRORS_FOR_UNIT_EXTENSION_POINT,
+        _validateAnalysisErrorListResultDescriptor);
+    htmlErrorsExtensionPoint = registerExtensionPoint(
+        HTML_ERRORS_EXTENSION_POINT,
+        _validateAnalysisErrorListResultDescriptor);
     taskExtensionPoint =
         registerExtensionPoint(TASK_EXTENSION_POINT, _validateTaskExtension);
     workManagerFactoryExtensionPoint = registerExtensionPoint(
@@ -83,6 +152,27 @@
   void registerExtensions(RegisterExtension registerExtension) {
     _registerTaskExtensions(registerExtension);
     _registerWorkManagerFactoryExtensions(registerExtension);
+    _registerDartErrorsForSource(registerExtension);
+    _registerDartErrorsForUnit(registerExtension);
+    _registerHtmlErrors(registerExtension);
+  }
+
+  void _registerDartErrorsForSource(RegisterExtension registerExtension) {
+    String id = DART_ERRORS_FOR_SOURCE_EXTENSION_POINT_ID;
+    registerExtension(id, BUILD_DIRECTIVES_ERRORS);
+    registerExtension(id, BUILD_LIBRARY_ERRORS);
+    registerExtension(id, PARSE_ERRORS);
+    registerExtension(id, SCAN_ERRORS);
+  }
+
+  void _registerDartErrorsForUnit(RegisterExtension registerExtension) {
+    String id = DART_ERRORS_FOR_UNIT_EXTENSION_POINT_ID;
+    registerExtension(id, LIBRARY_UNIT_ERRORS);
+  }
+
+  void _registerHtmlErrors(RegisterExtension registerExtension) {
+    String id = HTML_ERRORS_EXTENSION_POINT_ID;
+    registerExtension(id, HTML_DOCUMENT_ERRORS);
   }
 
   void _registerTaskExtensions(RegisterExtension registerExtension) {
@@ -145,8 +235,20 @@
   }
 
   /**
-   * Validate the given extension by throwing an [ExtensionError] if it is not a
-   * valid domain.
+   * Validate the given extension by throwing an [ExtensionError] if it is not
+   * a [ListResultDescriptor] of [AnalysisError]s.
+   */
+  void _validateAnalysisErrorListResultDescriptor(Object extension) {
+    if (extension is! ListResultDescriptor<AnalysisError>) {
+      String id = taskExtensionPoint.uniqueIdentifier;
+      throw new ExtensionError(
+          'Extensions to $id must be a ListResultDescriptor<AnalysisError>');
+    }
+  }
+
+  /**
+   * Validate the given extension by throwing an [ExtensionError] if it is not
+   * a [TaskDescriptor].
    */
   void _validateTaskExtension(Object extension) {
     if (extension is! TaskDescriptor) {
@@ -156,8 +258,8 @@
   }
 
   /**
-   * Validate the given extension by throwing an [ExtensionError] if it is not a
-   * valid domain.
+   * Validate the given extension by throwing an [ExtensionError] if it is not
+   * a [WorkManagerFactory].
    */
   void _validateWorkManagerFactoryExtension(Object extension) {
     if (extension is! WorkManagerFactory) {
diff --git a/pkg/analyzer/lib/src/plugin/options_plugin.dart b/pkg/analyzer/lib/src/plugin/options_plugin.dart
index 1dea284..fc82910 100644
--- a/pkg/analyzer/lib/src/plugin/options_plugin.dart
+++ b/pkg/analyzer/lib/src/plugin/options_plugin.dart
@@ -11,7 +11,6 @@
 /// by applications that want to consume options defined in the analysis
 /// options file.
 class OptionsPlugin implements Plugin {
-
   /// The simple identifier of the extension point that allows plugins to
   /// register new options processors.
   static const String OPTIONS_PROCESSOR_EXTENSION_POINT = 'optionsProcessor';
diff --git a/pkg/analyzer/lib/src/services/lint.dart b/pkg/analyzer/lib/src/services/lint.dart
index 9dd51a0..5601c4a 100644
--- a/pkg/analyzer/lib/src/services/lint.dart
+++ b/pkg/analyzer/lib/src/services/lint.dart
@@ -27,7 +27,6 @@
 ///
 /// See [LintCode].
 class LintGenerator {
-
   /// A global container for contributed linters.
   static final List<Linter> LINTERS = <Linter>[];
 
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index e81545c..88a5637 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -21,6 +21,7 @@
 import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/plugin/engine_plugin.dart';
 import 'package:analyzer/src/task/driver.dart';
 import 'package:analyzer/src/task/general.dart';
 import 'package:analyzer/src/task/html.dart';
@@ -72,16 +73,6 @@
         'BUILD_LIBRARY_ERRORS', AnalysisError.NO_ERRORS);
 
 /**
- * A list of the [ClassElement]s representing the classes defined in a
- * compilation unit.
- *
- * The result is only available for [LibrarySpecificUnit]s, and only when strong
- * mode is enabled.
- */
-final ListResultDescriptor<ClassElement> CLASSES_IN_UNIT =
-    new ListResultDescriptor<ClassElement>('CLASSES_IN_UNIT', null);
-
-/**
  * A list of the [ConstantEvaluationTarget]s defined in a unit.  This includes
  * constants defined at top level, statically inside classes, and local to
  * functions, as well as constant constructors, annotations, and default values
@@ -1932,31 +1923,6 @@
  */
 class DartErrorsTask extends SourceBasedAnalysisTask {
   /**
-   * The name of the [BUILD_DIRECTIVES_ERRORS] input.
-   */
-  static const String BUILD_DIRECTIVES_ERRORS_INPUT = 'BUILD_DIRECTIVES_ERRORS';
-
-  /**
-   * The name of the [BUILD_LIBRARY_ERRORS] input.
-   */
-  static const String BUILD_LIBRARY_ERRORS_INPUT = 'BUILD_LIBRARY_ERRORS';
-
-  /**
-   * The name of the [LIBRARY_UNIT_ERRORS] input.
-   */
-  static const String LIBRARY_UNIT_ERRORS_INPUT = 'LIBRARY_UNIT_ERRORS';
-
-  /**
-   * The name of the [PARSE_ERRORS] input.
-   */
-  static const String PARSE_ERRORS_INPUT = 'PARSE_ERRORS';
-
-  /**
-   * The name of the [SCAN_ERRORS] input.
-   */
-  static const String SCAN_ERRORS_INPUT = 'SCAN_ERRORS';
-
-  /**
    * The task descriptor describing this kind of task.
    */
   static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('DartErrorsTask',
@@ -1970,18 +1936,21 @@
 
   @override
   void internalPerform() {
+    List<List<AnalysisError>> errorLists = <List<AnalysisError>>[];
     //
     // Prepare inputs.
     //
-    List<List<AnalysisError>> errorLists = <List<AnalysisError>>[];
-    errorLists.add(getRequiredInput(BUILD_DIRECTIVES_ERRORS_INPUT));
-    errorLists.add(getRequiredInput(BUILD_LIBRARY_ERRORS_INPUT));
-    errorLists.add(getRequiredInput(PARSE_ERRORS_INPUT));
-    errorLists.add(getRequiredInput(SCAN_ERRORS_INPUT));
-    Map<Source, List<AnalysisError>> unitErrors =
-        getRequiredInput(LIBRARY_UNIT_ERRORS_INPUT);
-    for (List<AnalysisError> errors in unitErrors.values) {
-      errorLists.add(errors);
+    EnginePlugin enginePlugin = AnalysisEngine.instance.enginePlugin;
+    for (ResultDescriptor result in enginePlugin.dartErrorsForSource) {
+      String inputName = result.name + '_input';
+      errorLists.add(getRequiredInput(inputName));
+    }
+    for (ResultDescriptor result in enginePlugin.dartErrorsForUnit) {
+      String inputName = result.name + '_input';
+      Map<Source, List<AnalysisError>> errorMap = getRequiredInput(inputName);
+      for (List<AnalysisError> errors in errorMap.values) {
+        errorLists.add(errors);
+      }
     }
     //
     // Record outputs.
@@ -1996,17 +1965,23 @@
    */
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
     Source source = target;
-    return <String, TaskInput>{
-      BUILD_DIRECTIVES_ERRORS_INPUT: BUILD_DIRECTIVES_ERRORS.of(source),
-      BUILD_LIBRARY_ERRORS_INPUT: BUILD_LIBRARY_ERRORS.of(source),
-      PARSE_ERRORS_INPUT: PARSE_ERRORS.of(source),
-      SCAN_ERRORS_INPUT: SCAN_ERRORS.of(source),
-      LIBRARY_UNIT_ERRORS_INPUT:
+    Map<String, TaskInput> inputs = <String, TaskInput>{};
+    EnginePlugin enginePlugin = AnalysisEngine.instance.enginePlugin;
+    // for Source
+    for (ResultDescriptor result in enginePlugin.dartErrorsForSource) {
+      String inputName = result.name + '_input';
+      inputs[inputName] = result.of(source);
+    }
+    // for LibrarySpecificUnit
+    for (ResultDescriptor result in enginePlugin.dartErrorsForUnit) {
+      String inputName = result.name + '_input';
+      inputs[inputName] =
           CONTAINING_LIBRARIES.of(source).toMap((Source library) {
         LibrarySpecificUnit unit = new LibrarySpecificUnit(library, source);
-        return LIBRARY_UNIT_ERRORS.of(unit);
-      })
-    };
+        return result.of(unit);
+      });
+    }
+    return inputs;
   }
 
   /**
@@ -2703,6 +2678,7 @@
             "NodeLocator failed to find a variable's declaration");
       }
       Expression initializer = declaration.initializer;
+      ResolutionEraser.erase(initializer, eraseDeclarations: false);
       ResolutionContext resolutionContext =
           ResolutionContextBuilder.contextFor(initializer, errorListener);
       ResolverVisitor visitor = new ResolverVisitor(
@@ -2725,7 +2701,9 @@
       (variable.initializer as ExecutableElementImpl).returnType = newType;
       if (variable is PropertyInducingElementImpl) {
         setReturnType(variable.getter, newType);
-        setParameterType(variable.setter, newType);
+        if (!variable.isFinal && !variable.isConst) {
+          setParameterType(variable.setter, newType);
+        }
       }
     } else {
       // TODO(brianwilkerson) For now we simply don't infer any type for
@@ -3141,7 +3119,6 @@
       'PartiallyResolveUnitReferencesTask',
       createTask,
       buildInputs, <ResultDescriptor>[
-    CLASSES_IN_UNIT,
     INFERABLE_STATIC_VARIABLES_IN_UNIT,
     PARTIALLY_RESOLVE_REFERENCES_ERRORS,
     RESOLVED_UNIT5
@@ -3169,29 +3146,14 @@
     //
     InheritanceManager inheritanceManager =
         new InheritanceManager(libraryElement);
-    // TODO(brianwilkerson) Improve performance by not resolving anything inside
-    // function bodies. Function bodies will be resolved later so this is wasted
-    // effort.
-    AstVisitor visitor = new ResolverVisitor(
+    PartialResolverVisitor visitor = new PartialResolverVisitor(
         libraryElement, unitElement.source, typeProvider, errorListener,
         inheritanceManager: inheritanceManager);
     unit.accept(visitor);
     //
-    // Prepare targets for inference.
-    //
-    List<VariableElement> staticVariables = <VariableElement>[];
-    List<ClassElement> classes = <ClassElement>[];
-    if (context.analysisOptions.strongMode) {
-      InferrenceFinder inferrenceFinder = new InferrenceFinder();
-      unit.accept(inferrenceFinder);
-      staticVariables = inferrenceFinder.staticVariables;
-      classes = inferrenceFinder.classes;
-    }
-    //
     // Record outputs.
     //
-    outputs[CLASSES_IN_UNIT] = classes;
-    outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT] = staticVariables;
+    outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT] = visitor.staticVariables;
     outputs[PARTIALLY_RESOLVE_REFERENCES_ERRORS] =
         removeDuplicateErrors(errorListener.errors);
     outputs[RESOLVED_UNIT5] = unit;
@@ -3438,8 +3400,18 @@
       visitor.prepareToResolveMembersInClass(
           resolutionContext.enclosingClassDeclaration);
     }
-    visitor.initForIncrementalResolution();
+    Declaration declaration = functionBody.getAncestor((AstNode node) =>
+        node is ConstructorDeclaration ||
+            node is FunctionDeclaration ||
+            node is MethodDeclaration);
+    visitor.initForIncrementalResolution(declaration);
     functionBody.accept(visitor);
+    if (declaration is FunctionDeclaration) {
+      // This is in the wrong place. The propagated return type is stored
+      // locally in the resolver, not in the declaration (or element). Hence,
+      // this needs to happen later.
+      declaration.accept(visitor.typeAnalyzer);
+    }
   }
 
   /**
diff --git a/pkg/analyzer/lib/src/task/driver.dart b/pkg/analyzer/lib/src/task/driver.dart
index e4210d5..8daa5cf 100644
--- a/pkg/analyzer/lib/src/task/driver.dart
+++ b/pkg/analyzer/lib/src/task/driver.dart
@@ -102,7 +102,12 @@
       WorkOrder workOrder = createWorkOrderForResult(target, result);
       if (workOrder != null) {
         while (workOrder.moveNext()) {
+//          AnalysisTask previousTask = task;
+//          String message = workOrder.current.toString();
           task = performWorkItem(workOrder.current);
+//          if (task == null) {
+//            throw new AnalysisException(message, previousTask.caughtException);
+//          }
         }
       }
       return task;
diff --git a/pkg/analyzer/lib/src/task/html.dart b/pkg/analyzer/lib/src/task/html.dart
index 0722ed4..d169560 100644
--- a/pkg/analyzer/lib/src/task/html.dart
+++ b/pkg/analyzer/lib/src/task/html.dart
@@ -6,9 +6,13 @@
 
 import 'dart:collection';
 
+import 'package:analyzer/src/context/cache.dart';
 import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask;
 import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/plugin/engine_plugin.dart';
 import 'package:analyzer/src/task/dart.dart';
 import 'package:analyzer/src/task/general.dart';
 import 'package:analyzer/task/dart.dart';
@@ -18,9 +22,6 @@
 import 'package:html/dom.dart';
 import 'package:html/parser.dart';
 import 'package:source_span/source_span.dart';
-import 'package:analyzer/src/context/cache.dart';
-import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 
 /**
  * The Dart scripts that are embedded in an HTML file.
@@ -107,11 +108,11 @@
   /**
    * The task descriptor describing this kind of task.
    */
-  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('DartScriptsTask',
-      createTask, buildInputs, <ResultDescriptor>[
-    DART_SCRIPTS,
-    REFERENCED_LIBRARIES
-  ]);
+  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+      'DartScriptsTask',
+      createTask,
+      buildInputs,
+      <ResultDescriptor>[DART_SCRIPTS, REFERENCED_LIBRARIES]);
 
   DartScriptsTask(InternalAnalysisContext context, AnalysisTarget target)
       : super(context, target);
@@ -190,17 +191,17 @@
  */
 class HtmlErrorsTask extends SourceBasedAnalysisTask {
   /**
+   * The suffix to add to the names of contributed error results.
+   */
+  static const String INPUT_SUFFIX = '_input';
+
+  /**
    * The name of the input that is a list of errors from each of the embedded
    * Dart scripts.
    */
   static const String DART_ERRORS_INPUT = 'DART_ERRORS';
 
   /**
-   * The name of the [HTML_DOCUMENT_ERRORS] input.
-   */
-  static const String DOCUMENT_ERRORS_INPUT = 'DOCUMENT_ERRORS';
-
-  /**
    * The task descriptor describing this kind of task.
    */
   static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('HtmlErrorsTask',
@@ -214,24 +215,26 @@
 
   @override
   void internalPerform() {
+    EnginePlugin enginePlugin = AnalysisEngine.instance.enginePlugin;
     //
     // Prepare inputs.
     //
     List<List<AnalysisError>> dartErrors = getRequiredInput(DART_ERRORS_INPUT);
-    List<AnalysisError> documentErrors =
-        getRequiredInput(DOCUMENT_ERRORS_INPUT);
+    List<List<AnalysisError>> htmlErrors = <List<AnalysisError>>[];
+    for (ResultDescriptor result in enginePlugin.htmlErrors) {
+      String inputName = result.name + INPUT_SUFFIX;
+      htmlErrors.add(getRequiredInput(inputName));
+    }
     //
     // Compute the error list.
     //
-    List<AnalysisError> errors = <AnalysisError>[];
-    errors.addAll(documentErrors);
-    for (List<AnalysisError> scriptErrors in dartErrors) {
-      errors.addAll(scriptErrors);
-    }
+    List<List<AnalysisError>> errorLists = <List<AnalysisError>>[];
+    errorLists.addAll(dartErrors);
+    errorLists.addAll(htmlErrors);
     //
     // Record outputs.
     //
-    outputs[HTML_ERRORS] = removeDuplicateErrors(errors);
+    outputs[HTML_ERRORS] = AnalysisError.mergeLists(errorLists);
   }
 
   /**
@@ -240,10 +243,15 @@
    * given [target].
    */
   static Map<String, TaskInput> buildInputs(Source target) {
-    return <String, TaskInput>{
-      DOCUMENT_ERRORS_INPUT: HTML_DOCUMENT_ERRORS.of(target),
+    EnginePlugin enginePlugin = AnalysisEngine.instance.enginePlugin;
+    Map<String, TaskInput> inputs = <String, TaskInput>{
       DART_ERRORS_INPUT: DART_SCRIPTS.of(target).toListOf(DART_ERRORS)
     };
+    for (ResultDescriptor result in enginePlugin.htmlErrors) {
+      String inputName = result.name + INPUT_SUFFIX;
+      inputs[inputName] = result.of(target);
+    }
+    return inputs;
   }
 
   /**
@@ -268,11 +276,11 @@
   /**
    * The task descriptor describing this kind of task.
    */
-  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('ParseHtmlTask',
-      createTask, buildInputs, <ResultDescriptor>[
-    HTML_DOCUMENT,
-    HTML_DOCUMENT_ERRORS
-  ]);
+  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+      'ParseHtmlTask',
+      createTask,
+      buildInputs,
+      <ResultDescriptor>[HTML_DOCUMENT, HTML_DOCUMENT_ERRORS]);
 
   /**
    * Initialize a newly created task to access the content of the source
@@ -291,7 +299,8 @@
     if (context.getModificationStamp(target.source) < 0) {
       String message = 'Content could not be read';
       if (context is InternalAnalysisContext) {
-        CacheEntry entry = (context as InternalAnalysisContext).getCacheEntry(target);
+        CacheEntry entry =
+            (context as InternalAnalysisContext).getCacheEntry(target);
         CaughtException exception = entry.exception;
         if (exception != null) {
           message = exception.toString();
@@ -299,8 +308,10 @@
       }
 
       outputs[HTML_DOCUMENT] = new Document();
-      outputs[HTML_DOCUMENT_ERRORS] = <AnalysisError>[new AnalysisError(
-          target.source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [message])];
+      outputs[HTML_DOCUMENT_ERRORS] = <AnalysisError>[
+        new AnalysisError(
+            target.source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [message])
+      ];
     } else {
       HtmlParser parser = new HtmlParser(content, generateSpans: true);
       parser.compatMode = 'quirks';
diff --git a/pkg/analyzer/lib/src/task/incremental_element_builder.dart b/pkg/analyzer/lib/src/task/incremental_element_builder.dart
index bc562a7..d6a0c14 100644
--- a/pkg/analyzer/lib/src/task/incremental_element_builder.dart
+++ b/pkg/analyzer/lib/src/task/incremental_element_builder.dart
@@ -69,8 +69,8 @@
    * Fills [unitDelta] with added/remove elements.
    */
   void build() {
-    new CompilationUnitBuilder().buildCompilationUnit(
-        unitSource, newUnit, librarySource);
+    new CompilationUnitBuilder()
+        .buildCompilationUnit(unitSource, newUnit, librarySource);
     _processDirectives();
     _processUnitMembers();
     newUnit.element = unitElement;
diff --git a/pkg/analyzer/lib/src/task/inputs.dart b/pkg/analyzer/lib/src/task/inputs.dart
index 308b06a..c93a127 100644
--- a/pkg/analyzer/lib/src/task/inputs.dart
+++ b/pkg/analyzer/lib/src/task/inputs.dart
@@ -25,7 +25,8 @@
  * defined on a single target.
  */
 class ListTaskInputImpl<E> extends SimpleTaskInput<List<E>>
-    with ListTaskInputMixin<E> implements ListTaskInput<E> {
+    with ListTaskInputMixin<E>
+    implements ListTaskInput<E> {
   /**
    * Initialize a newly created task input that computes the input by accessing
    * the given [result] associated with the given [target].
@@ -168,7 +169,8 @@
 abstract class MapTaskInputMixin<K, V> implements MapTaskInput<K, V> {
   TaskInput<List /*<E>*/ > toFlattenList(
       BinaryFunction<K, dynamic /*element of V*/, dynamic /*<E>*/ > mapper) {
-    return new MapToFlattenListTaskInput<K, dynamic /*element of V*/, dynamic /*E*/ >(
+    return new MapToFlattenListTaskInput<K, dynamic /*element of V*/,
+        dynamic /*E*/ >(
         this as MapTaskInput<K, List /*<element of V>*/ >, mapper);
   }
 }
@@ -301,7 +303,8 @@
  * An input to an [AnalysisTask] that is computed by mapping the value of
  * another task input to a list of values.
  */
-class ObjectToListTaskInput<E> extends TaskInputImpl<List<E>> with ListTaskInputMixin<E>
+class ObjectToListTaskInput<E> extends TaskInputImpl<List<E>>
+    with ListTaskInputMixin<E>
     implements ListTaskInput<E> {
   /**
    * The input used to compute the value to be mapped.
diff --git a/pkg/analyzer/lib/src/task/strong_mode.dart b/pkg/analyzer/lib/src/task/strong_mode.dart
index 3d13146..a78d590 100644
--- a/pkg/analyzer/lib/src/task/strong_mode.dart
+++ b/pkg/analyzer/lib/src/task/strong_mode.dart
@@ -83,83 +83,6 @@
 typedef bool VariableFilter(VariableElement element);
 
 /**
- * An object used to find static variables whose types should be inferred and
- * classes whose members should have types inferred. Clients are expected to
- * visit a [CompilationUnit].
- */
-class InferrenceFinder extends SimpleAstVisitor {
-  /**
-   * The static variables that should have types inferred for them.
-   */
-  final List<VariableElement> staticVariables = <VariableElement>[];
-
-  /**
-   * The classes defined in the unit.
-   *
-   * TODO(brianwilkerson) We don't currently remove classes whose members do not
-   * need to be processed, but we potentially could.
-   */
-  final List<ClassElement> classes = <ClassElement>[];
-
-  /**
-   * Initialize a newly created finder.
-   */
-  InferrenceFinder();
-
-  @override
-  void visitClassDeclaration(ClassDeclaration node) {
-    classes.add(node.element);
-    for (ClassMember member in node.members) {
-      member.accept(this);
-    }
-  }
-
-  @override
-  void visitClassTypeAlias(ClassTypeAlias node) {
-    classes.add(node.element);
-  }
-
-  @override
-  void visitCompilationUnit(CompilationUnit node) {
-    for (CompilationUnitMember declaration in node.declarations) {
-      declaration.accept(this);
-    }
-  }
-
-  @override
-  void visitFieldDeclaration(FieldDeclaration node) {
-    if (node.isStatic && node.fields.type == null) {
-      _addVariables(node.fields.variables);
-    }
-  }
-
-  @override
-  void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
-    if (node.variables.type == null) {
-      _addVariables(node.variables.variables);
-    }
-  }
-
-  /**
-   * Add all of the [variables] with initializers to the list of variables whose
-   * type can be inferred. Technically, we only infer the types of variables
-   * that do not have a static type, but all variables with initializers
-   * potentially need to be re-resolved after inference because they might
-   * refer to fields whose type was inferred.
-   */
-  void _addVariables(NodeList<VariableDeclaration> variables) {
-    for (VariableDeclaration variable in variables) {
-      if (variable.initializer != null) {
-        VariableElement element = variable.element;
-        if (element.hasImplicitType) {
-          staticVariables.add(element);
-        }
-      }
-    }
-  }
-}
-
-/**
  * An object used to infer the type of instance fields and the return types of
  * instance methods within a single compilation unit.
  */
@@ -416,7 +339,7 @@
       (fieldElement as FieldElementImpl).type = newType;
       setReturnType(fieldElement.getter, newType);
       if (!fieldElement.isFinal && !fieldElement.isConst) {
-         setParameterType(fieldElement.setter, newType);
+        setParameterType(fieldElement.setter, newType);
       }
     }
   }
diff --git a/pkg/analyzer/lib/task/dart.dart b/pkg/analyzer/lib/task/dart.dart
index a0e309e..644ab24 100644
--- a/pkg/analyzer/lib/task/dart.dart
+++ b/pkg/analyzer/lib/task/dart.dart
@@ -128,7 +128,8 @@
  * The result is only available for [Source]s representing a compilation unit.
  */
 final ResultDescriptor<Token> TOKEN_STREAM = new ResultDescriptor<Token>(
-    'TOKEN_STREAM', null, cachingPolicy: TOKEN_STREAM_CACHING_POLICY);
+    'TOKEN_STREAM', null,
+    cachingPolicy: TOKEN_STREAM_CACHING_POLICY);
 
 /**
  * The sources of the Dart files that a library consists of.
diff --git a/pkg/analyzer/lib/task/model.dart b/pkg/analyzer/lib/task/model.dart
index 9375576..833a6d3 100644
--- a/pkg/analyzer/lib/task/model.dart
+++ b/pkg/analyzer/lib/task/model.dart
@@ -198,8 +198,8 @@
       _safelyPerform();
     } on AnalysisException catch (exception, stackTrace) {
       caughtException = new CaughtException(exception, stackTrace);
-      AnalysisEngine.instance.logger.logInformation(
-          "Task failed: ${description}", caughtException);
+      AnalysisEngine.instance.logger
+          .logInformation("Task failed: ${description}", caughtException);
     }
   }
 
@@ -221,8 +221,8 @@
       if (contextName == null) {
         contextName = 'unnamed';
       }
-      AnalysisEngine.instance.instrumentationService.logAnalysisTask(
-          contextName, this);
+      AnalysisEngine.instance.instrumentationService
+          .logAnalysisTask(contextName, this);
       //
       // Gather statistics on the performance of the task.
       //
@@ -268,7 +268,8 @@
    * values associated with this result will remain in the cache.
    */
   factory ListResultDescriptor(String name, List<E> defaultValue,
-      {ResultCachingPolicy<List<E>> cachingPolicy}) = ListResultDescriptorImpl<E>;
+      {ResultCachingPolicy<List<E>> cachingPolicy}) = ListResultDescriptorImpl<
+      E>;
 
   @override
   ListTaskInput<E> of(AnalysisTarget target);
@@ -443,7 +444,9 @@
    * and produces the given [results]. The [buildTask] will be used to create
    * the instance of [AnalysisTask] thusly described.
    */
-  factory TaskDescriptor(String name, BuildTask buildTask,
+  factory TaskDescriptor(
+      String name,
+      BuildTask buildTask,
       CreateTaskInputs inputBuilder,
       List<ResultDescriptor> results) = TaskDescriptorImpl;
 
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index a08ede7..a60941b 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -38,11 +38,64 @@
 void initializeTestEnvironment() {}
 
 void _assertEqualError(AnalysisError incrError, AnalysisError fullError) {
-  expect(incrError.errorCode, same(fullError.errorCode));
-  expect(incrError.source, fullError.source);
-  expect(incrError.offset, fullError.offset);
-  expect(incrError.length, fullError.length);
-  expect(incrError.message, fullError.message);
+  if (incrError.errorCode != fullError.errorCode ||
+      incrError.source != fullError.source ||
+      incrError.offset != fullError.offset ||
+      incrError.length != fullError.length ||
+      incrError.message != fullError.message) {
+    StringBuffer buffer = new StringBuffer();
+    buffer.writeln('Found error does not match expected error:');
+    if (incrError.errorCode == fullError.errorCode) {
+      buffer.write('  errorCode = ');
+      buffer.write(fullError.errorCode.uniqueName);
+    } else {
+      buffer.write('  Expected errorCode = ');
+      buffer.write(fullError.errorCode.uniqueName);
+      buffer.write(' found ');
+      buffer.write(incrError.errorCode.uniqueName);
+    }
+    buffer.writeln();
+    if (incrError.source == fullError.source) {
+      buffer.write('  source = ');
+      buffer.write(fullError.source);
+    } else {
+      buffer.write('  Expected source = ');
+      buffer.write(fullError.source);
+      buffer.write(' found ');
+      buffer.write(incrError.source);
+    }
+    buffer.writeln();
+    if (incrError.offset == fullError.offset) {
+      buffer.write('  offset = ');
+      buffer.write(fullError.offset);
+    } else {
+      buffer.write('  Expected offset = ');
+      buffer.write(fullError.offset);
+      buffer.write(' found ');
+      buffer.write(incrError.offset);
+    }
+    buffer.writeln();
+    if (incrError.length == fullError.length) {
+      buffer.write('  length = ');
+      buffer.write(fullError.length);
+    } else {
+      buffer.write('  Expected length = ');
+      buffer.write(fullError.length);
+      buffer.write(' found ');
+      buffer.write(incrError.length);
+    }
+    buffer.writeln();
+    if (incrError.message == fullError.message) {
+      buffer.write('  message = ');
+      buffer.write(fullError.message);
+    } else {
+      buffer.write('  Expected message = ');
+      buffer.write(fullError.message);
+      buffer.write(' found ');
+      buffer.write(incrError.message);
+    }
+    fail(buffer.toString());
+  }
 }
 
 void _assertEqualErrors(
@@ -4425,8 +4478,7 @@
     // Resolve "newCode" from scratch.
     if (compareWithFull) {
       _resetWithIncremental(false);
-      source = addSource(newCode + ' ');
-      source = addSource(newCode);
+      changeSource(source, newCode);
       _runTasks();
       LibraryElement library = resolve2(source);
       CompilationUnit fullNewUnit = resolveCompilationUnit(source, library);
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 6463a7b..f5153cf 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -7974,6 +7974,16 @@
   }
 
   /**
+   * Change the contents of the given [source] to the given [contents].
+   */
+  void changeSource(Source source, String contents) {
+    analysisContext2.setContents(source, contents);
+    ChangeSet changeSet = new ChangeSet();
+    changeSet.changedSource(source);
+    analysisContext2.applyChanges(changeSet);
+  }
+
+  /**
    * Computes errors for the given [librarySource].
    * This assumes that the given [librarySource] and its parts have already
    * been added to the content provider using the method [addNamedSource].
@@ -8054,75 +8064,6 @@
   }
 
   /**
-   * @param code the code that iterates using variable "v". We check that
-   *          "v" has expected static and propagated type.
-   */
-  void _assertPropagatedIterationType(String code, DartType expectedStaticType,
-      DartType expectedPropagatedType) {
-    SimpleIdentifier identifier = _findMarkedIdentifier(code, "v in ");
-    expect(identifier.staticType, same(expectedStaticType));
-    expect(identifier.propagatedType, same(expectedPropagatedType));
-  }
-
-  /**
-   * @param code the code that assigns the value to the variable "v", no matter how. We check that
-   *          "v" has expected static and propagated type.
-   */
-  void _assertPropagatedAssignedType(String code, DartType expectedStaticType,
-      DartType expectedPropagatedType) {
-    SimpleIdentifier identifier = _findMarkedIdentifier(code, "v = ");
-    expect(identifier.staticType, same(expectedStaticType));
-    expect(identifier.propagatedType, same(expectedPropagatedType));
-  }
-
-  /**
-   * Check the static and propagated types of the expression marked with "; // marker" comment.
-   *
-   * @param code source code to analyze, with the expression to check marked with "// marker".
-   * @param expectedStaticType if non-null, check actual static type is equal to this.
-   * @param expectedPropagatedType if non-null, check actual static type is equal to this.
-   * @throws Exception
-   */
-  void _assertTypeOfMarkedExpression(String code, DartType expectedStaticType,
-      DartType expectedPropagatedType) {
-    SimpleIdentifier identifier = _findMarkedIdentifier(code, "; // marker");
-    if (expectedStaticType != null) {
-      expect(identifier.staticType, expectedStaticType);
-    }
-    expect(identifier.propagatedType, expectedPropagatedType);
-  }
-
-  /**
-   * Return the `SimpleIdentifier` marked by `marker`. The source code must have no
-   * errors and be verifiable.
-   *
-   * @param code source code to analyze.
-   * @param marker marker identifying sought after expression in source code.
-   * @return expression marked by the marker.
-   * @throws Exception
-   */
-  SimpleIdentifier _findMarkedIdentifier(String code, String marker) {
-    try {
-      Source source = addSource(code);
-      LibraryElement library = resolve2(source);
-      assertNoErrors(source);
-      verify([source]);
-      CompilationUnit unit = resolveCompilationUnit(source, library);
-      // Could generalize this further by making [SimpleIdentifier.class] a
-      // parameter.
-      return EngineTestCase.findNode(
-          unit, code, marker, (node) => node is SimpleIdentifier);
-    } catch (exception) {
-      // Is there a better exception to throw here? The point is that an
-      // assertion failure here should be a failure, in both "test_*" and
-      // "fail_*" tests. However, an assertion failure is success for the
-      // purpose of "fail_*" tests, so without catching them here "fail_*" tests
-      // can succeed by failing for the wrong reason.
-      throw new JavaException("Unexexpected assertion failure: $exception");
-    }
-  }
-
-  /**
    * In the rare cases we want to group several tests into single "test_" method, so need a way to
    * reset test instance to reuse it.
    */
@@ -8241,6 +8182,45 @@
   }
 
   /**
+   * @param code the code that assigns the value to the variable "v", no matter how. We check that
+   *          "v" has expected static and propagated type.
+   */
+  void _assertPropagatedAssignedType(String code, DartType expectedStaticType,
+      DartType expectedPropagatedType) {
+    SimpleIdentifier identifier = _findMarkedIdentifier(code, "v = ");
+    expect(identifier.staticType, same(expectedStaticType));
+    expect(identifier.propagatedType, same(expectedPropagatedType));
+  }
+
+  /**
+   * @param code the code that iterates using variable "v". We check that
+   *          "v" has expected static and propagated type.
+   */
+  void _assertPropagatedIterationType(String code, DartType expectedStaticType,
+      DartType expectedPropagatedType) {
+    SimpleIdentifier identifier = _findMarkedIdentifier(code, "v in ");
+    expect(identifier.staticType, same(expectedStaticType));
+    expect(identifier.propagatedType, same(expectedPropagatedType));
+  }
+
+  /**
+   * Check the static and propagated types of the expression marked with "; // marker" comment.
+   *
+   * @param code source code to analyze, with the expression to check marked with "// marker".
+   * @param expectedStaticType if non-null, check actual static type is equal to this.
+   * @param expectedPropagatedType if non-null, check actual static type is equal to this.
+   * @throws Exception
+   */
+  void _assertTypeOfMarkedExpression(String code, DartType expectedStaticType,
+      DartType expectedPropagatedType) {
+    SimpleIdentifier identifier = _findMarkedIdentifier(code, "; // marker");
+    if (expectedStaticType != null) {
+      expect(identifier.staticType, expectedStaticType);
+    }
+    expect(identifier.propagatedType, expectedPropagatedType);
+  }
+
+  /**
    * Create a source object representing a file with the given [fileName] and
    * give it an empty content. Return the source that was created.
    */
@@ -8250,6 +8230,36 @@
     analysisContext2.setContents(source, "");
     return source;
   }
+
+  /**
+   * Return the `SimpleIdentifier` marked by `marker`. The source code must have no
+   * errors and be verifiable.
+   *
+   * @param code source code to analyze.
+   * @param marker marker identifying sought after expression in source code.
+   * @return expression marked by the marker.
+   * @throws Exception
+   */
+  SimpleIdentifier _findMarkedIdentifier(String code, String marker) {
+    try {
+      Source source = addSource(code);
+      LibraryElement library = resolve2(source);
+      assertNoErrors(source);
+      verify([source]);
+      CompilationUnit unit = resolveCompilationUnit(source, library);
+      // Could generalize this further by making [SimpleIdentifier.class] a
+      // parameter.
+      return EngineTestCase.findNode(
+          unit, code, marker, (node) => node is SimpleIdentifier);
+    } catch (exception) {
+      // Is there a better exception to throw here? The point is that an
+      // assertion failure here should be a failure, in both "test_*" and
+      // "fail_*" tests. However, an assertion failure is success for the
+      // purpose of "fail_*" tests, so without catching them here "fail_*" tests
+      // can succeed by failing for the wrong reason.
+      throw new JavaException("Unexexpected assertion failure: $exception");
+    }
+  }
 }
 
 class Scope_EnclosedScopeTest_test_define_duplicate extends Scope {
@@ -11870,6 +11880,273 @@
 }
 
 @reflectiveTest
+class StrongModeTypePropagationTest extends ResolverTestCase {
+  @override
+  void setUp() {
+    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+    options.strongMode = true;
+    resetWithOptions(options);
+  }
+
+  void test_foreachInference_dynamic_disabled() {
+    String code = r'''
+main() {
+  var list = <int>[];
+  for (dynamic v in list) {
+    v; // marker
+  }
+}''';
+    _assertPropagatedIterationType(
+        code, typeProvider.dynamicType, typeProvider.intType);
+    _assertTypeOfMarkedExpression(
+        code, typeProvider.dynamicType, typeProvider.intType);
+  }
+
+  void test_foreachInference_reusedVar_disabled() {
+    String code = r'''
+main() {
+  var list = <int>[];
+  var v;
+  for (v in list) {
+    v; // marker
+  }
+}''';
+    _assertPropagatedIterationType(
+        code, typeProvider.dynamicType, typeProvider.intType);
+    _assertTypeOfMarkedExpression(
+        code, typeProvider.dynamicType, typeProvider.intType);
+  }
+
+  void test_foreachInference_var() {
+    String code = r'''
+main() {
+  var list = <int>[];
+  for (var v in list) {
+    v; // marker
+  }
+}''';
+    _assertPropagatedIterationType(code, typeProvider.intType, null);
+    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+  }
+
+  void test_foreachInference_var_iterable() {
+    String code = r'''
+main() {
+  Iterable<int> list = <int>[];
+  for (var v in list) {
+    v; // marker
+  }
+}''';
+    _assertPropagatedIterationType(code, typeProvider.intType, null);
+    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+  }
+
+  void test_foreachInference_var_stream() {
+    String code = r'''
+import 'dart:async';
+main() async {
+  Stream<int> stream = null;
+  await for (var v in stream) {
+    v; // marker
+  }
+}''';
+    _assertPropagatedIterationType(code, typeProvider.intType, null);
+    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+  }
+
+  void test_localVariableInference_bottom_disabled() {
+    String code = r'''
+main() {
+  var v = null;
+  return v; // marker
+}''';
+    _assertPropagatedAssignedType(code, typeProvider.dynamicType, null);
+    _assertTypeOfMarkedExpression(code, typeProvider.dynamicType, null);
+  }
+
+  void test_localVariableInference_constant() {
+    String code = r'''
+main() {
+  var v = 3;
+  return v; // marker
+}''';
+    _assertPropagatedAssignedType(code, typeProvider.intType, null);
+    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+  }
+
+  void test_localVariableInference_declaredType_disabled() {
+    String code = r'''
+main() {
+  dynamic v = 3;
+  return v; // marker
+}''';
+    _assertPropagatedAssignedType(
+        code, typeProvider.dynamicType, typeProvider.intType);
+    _assertTypeOfMarkedExpression(
+        code, typeProvider.dynamicType, typeProvider.intType);
+  }
+
+  void test_localVariableInference_noInitializer_disabled() {
+    String code = r'''
+main() {
+  var v;
+  v = 3;
+  return v; // marker
+}''';
+    _assertPropagatedAssignedType(
+        code, typeProvider.dynamicType, typeProvider.intType);
+    _assertTypeOfMarkedExpression(
+        code, typeProvider.dynamicType, typeProvider.intType);
+  }
+
+  void test_localVariableInference_transitive_field_inferred_lexical() {
+    if (!AnalysisEngine.instance.useTaskModel) {
+      return;
+    }
+    String code = r'''
+class A {
+  final x = 3;
+  f() {
+    var v = x;
+    return v; // marker
+  }
+}
+main() {
+}
+''';
+    _assertPropagatedAssignedType(code, typeProvider.intType, null);
+    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+  }
+
+  void test_localVariableInference_transitive_field_inferred_reversed() {
+    if (!AnalysisEngine.instance.useTaskModel) {
+      return;
+    }
+    String code = r'''
+class A {
+  f() {
+    var v = x;
+    return v; // marker
+  }
+  final x = 3;
+}
+main() {
+}
+''';
+    _assertPropagatedAssignedType(code, typeProvider.intType, null);
+    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+  }
+
+  void test_localVariableInference_transitive_field_lexical() {
+    String code = r'''
+class A {
+  int x = 3;
+  f() {
+    var v = x;
+    return v; // marker
+  }
+}
+main() {
+}
+''';
+    _assertPropagatedAssignedType(code, typeProvider.intType, null);
+    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+  }
+
+  void test_localVariableInference_transitive_field_reversed() {
+    String code = r'''
+class A {
+  f() {
+    var v = x;
+    return v; // marker
+  }
+  int x = 3;
+}
+main() {
+}
+''';
+    _assertPropagatedAssignedType(code, typeProvider.intType, null);
+    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+  }
+
+  void test_localVariableInference_transitive_list_local() {
+    String code = r'''
+main() {
+  var x = <int>[3];
+  var v = x[0];
+  return v; // marker
+}''';
+    _assertPropagatedAssignedType(code, typeProvider.intType, null);
+    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+  }
+
+  void test_localVariableInference_transitive_local() {
+    String code = r'''
+main() {
+  var x = 3;
+  var v = x;
+  return v; // marker
+}''';
+    _assertPropagatedAssignedType(code, typeProvider.intType, null);
+    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+  }
+
+  void test_localVariableInference_transitive_toplevel_inferred_lexical() {
+    if (!AnalysisEngine.instance.useTaskModel) {
+      return;
+    }
+    String code = r'''
+final x = 3;
+main() {
+  var v = x;
+  return v; // marker
+}
+''';
+    _assertPropagatedAssignedType(code, typeProvider.intType, null);
+    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+  }
+
+  void test_localVariableInference_transitive_toplevel_inferred_reversed() {
+    if (!AnalysisEngine.instance.useTaskModel) {
+      return;
+    }
+    String code = r'''
+main() {
+  var v = x;
+  return v; // marker
+}
+final x = 3;
+''';
+    _assertPropagatedAssignedType(code, typeProvider.intType, null);
+    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+  }
+
+  void test_localVariableInference_transitive_toplevel_lexical() {
+    String code = r'''
+int x = 3;
+main() {
+  var v = x;
+  return v; // marker
+}
+''';
+    _assertPropagatedAssignedType(code, typeProvider.intType, null);
+    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+  }
+
+  void test_localVariableInference_transitive_toplevel_reversed() {
+    String code = r'''
+main() {
+  var v = x;
+  return v; // marker
+}
+int x = 3;
+''';
+    _assertPropagatedAssignedType(code, typeProvider.intType, null);
+    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+  }
+}
+
+@reflectiveTest
 class SubtypeManagerTest extends EngineTestCase {
   /**
    * The inheritance manager being tested.
@@ -13443,72 +13720,6 @@
         typeProvider.stringType);
   }
 
-  void test_propagatedReturnType_function_hasReturnType_returnsNull() {
-    String code = r'''
-String f() => null;
-main() {
-  var v = f();
-}''';
-    _assertPropagatedAssignedType(
-        code, typeProvider.dynamicType, typeProvider.stringType);
-  }
-
-  void test_propagatedReturnType_function_lessSpecificStaticReturnType() {
-    String code = r'''
-Object f() => 42;
-main() {
-  var v = f();
-}''';
-    _assertPropagatedAssignedType(
-        code, typeProvider.dynamicType, typeProvider.intType);
-  }
-
-  void test_propagatedReturnType_function_moreSpecificStaticReturnType() {
-    String code = r'''
-int f(v) => (v as num);
-main() {
-  var v = f(3);
-}''';
-    _assertPropagatedAssignedType(
-        code, typeProvider.dynamicType, typeProvider.intType);
-  }
-
-  void test_propagatedReturnType_function_noReturnTypeName_blockBody_multipleReturns() {
-    String code = r'''
-f() {
-  if (true) return 0;
-  return 1.0;
-}
-main() {
-  var v = f();
-}''';
-    _assertPropagatedAssignedType(
-        code, typeProvider.dynamicType, typeProvider.numType);
-  }
-
-  void test_propagatedReturnType_function_noReturnTypeName_blockBody_oneReturn() {
-    String code = r'''
-f() {
-  var z = 42;
-  return z;
-}
-main() {
-  var v = f();
-}''';
-    _assertPropagatedAssignedType(
-        code, typeProvider.dynamicType, typeProvider.intType);
-  }
-
-  void test_propagatedReturnType_function_noReturnTypeName_expressionBody() {
-    String code = r'''
-f() => 42;
-main() {
-  var v = f();
-}''';
-    _assertPropagatedAssignedType(
-        code, typeProvider.dynamicType, typeProvider.intType);
-  }
-
   void test_propagatedReturnType_localFunction() {
     String code = r'''
 main() {
@@ -13563,261 +13774,6 @@
 }
 
 @reflectiveTest
-class StrongModeTypePropagationTest extends ResolverTestCase {
-  @override
-  void setUp() {
-    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
-    options.strongMode = true;
-    resetWithOptions(options);
-  }
-
-  void test_localVariableInference_constant() {
-    String code = r'''
-main() {
-  var v = 3;
-  return v; // marker
-}''';
-    _assertPropagatedAssignedType(code, typeProvider.intType, null);
-    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
-  }
-
-  void test_localVariableInference_transitive_local() {
-    String code = r'''
-main() {
-  var x = 3;
-  var v = x;
-  return v; // marker
-}''';
-    _assertPropagatedAssignedType(code, typeProvider.intType, null);
-    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
-  }
-
-  void test_localVariableInference_transitive_list_local() {
-    String code = r'''
-main() {
-  var x = <int>[3];
-  var v = x[0];
-  return v; // marker
-}''';
-    _assertPropagatedAssignedType(code, typeProvider.intType, null);
-    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
-  }
-
-  void test_localVariableInference_transitive_toplevel_lexical() {
-    String code = r'''
-int x = 3;
-main() {
-  var v = x;
-  return v; // marker
-}
-''';
-    _assertPropagatedAssignedType(code, typeProvider.intType, null);
-    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
-  }
-
-  void test_localVariableInference_transitive_toplevel_reversed() {
-    String code = r'''
-main() {
-  var v = x;
-  return v; // marker
-}
-int x = 3;
-''';
-    _assertPropagatedAssignedType(code, typeProvider.intType, null);
-    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
-  }
-
-  void fail_localVariableInference_transitive_toplevel_inferred_lexical() {
-    String code = r'''
-final x = 3;
-main() {
-  var v = x;
-  return v; // marker
-}
-''';
-    _assertPropagatedAssignedType(code, typeProvider.intType, null);
-    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
-  }
-
-  void fail_localVariableInference_transitive_toplevel_inferred_reversed() {
-    String code = r'''
-main() {
-  var v = x;
-  return v; // marker
-}
-final x = 3;
-''';
-    _assertPropagatedAssignedType(code, typeProvider.intType, null);
-    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
-  }
-
-  void test_localVariableInference_transitive_field_lexical() {
-    String code = r'''
-class A {
-  int x = 3;
-  f() {
-    var v = x;
-    return v; // marker
-  }
-}
-main() {
-}
-''';
-    _assertPropagatedAssignedType(code, typeProvider.intType, null);
-    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
-  }
-
-  void test_localVariableInference_transitive_field_reversed() {
-    String code = r'''
-class A {
-  f() {
-    var v = x;
-    return v; // marker
-  }
-  int x = 3;
-}
-main() {
-}
-''';
-    _assertPropagatedAssignedType(code, typeProvider.intType, null);
-    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
-  }
-
-  void fail_localVariableInference_transitive_field_inferred_lexical() {
-    String code = r'''
-class A {
-  final x = 3;
-  f() {
-    var v = x;
-    return v; // marker
-  }
-}
-main() {
-}
-''';
-    _assertPropagatedAssignedType(code, typeProvider.intType, null);
-    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
-  }
-
-  void fail_localVariableInference_transitive_field_inferred_reversed() {
-    String code = r'''
-class A {
-  f() {
-    var v = x;
-    return v; // marker
-  }
-  final x = 3;
-}
-main() {
-}
-''';
-    _assertPropagatedAssignedType(code, typeProvider.intType, null);
-    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
-  }
-
-  void test_localVariableInference_declaredType_disabled() {
-    String code = r'''
-main() {
-  dynamic v = 3;
-  return v; // marker
-}''';
-    _assertPropagatedAssignedType(
-        code, typeProvider.dynamicType, typeProvider.intType);
-    _assertTypeOfMarkedExpression(
-        code, typeProvider.dynamicType, typeProvider.intType);
-  }
-
-  void test_localVariableInference_bottom_disabled() {
-    String code = r'''
-main() {
-  var v = null;
-  return v; // marker
-}''';
-    _assertPropagatedAssignedType(code, typeProvider.dynamicType, null);
-    _assertTypeOfMarkedExpression(code, typeProvider.dynamicType, null);
-  }
-
-  void test_localVariableInference_noInitializer_disabled() {
-    String code = r'''
-main() {
-  var v;
-  v = 3;
-  return v; // marker
-}''';
-    _assertPropagatedAssignedType(
-        code, typeProvider.dynamicType, typeProvider.intType);
-    _assertTypeOfMarkedExpression(
-        code, typeProvider.dynamicType, typeProvider.intType);
-  }
-
-  void test_foreachInference_var() {
-    String code = r'''
-main() {
-  var list = <int>[];
-  for (var v in list) {
-    v; // marker
-  }
-}''';
-    _assertPropagatedIterationType(code, typeProvider.intType, null);
-    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
-  }
-
-  void test_foreachInference_var_iterable() {
-    String code = r'''
-main() {
-  Iterable<int> list = <int>[];
-  for (var v in list) {
-    v; // marker
-  }
-}''';
-    _assertPropagatedIterationType(code, typeProvider.intType, null);
-    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
-  }
-
-  void test_foreachInference_var_stream() {
-    String code = r'''
-import 'dart:async';
-main() async {
-  Stream<int> stream = null;
-  await for (var v in stream) {
-    v; // marker
-  }
-}''';
-    _assertPropagatedIterationType(code, typeProvider.intType, null);
-    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
-  }
-
-  void test_foreachInference_dynamic_disabled() {
-    String code = r'''
-main() {
-  var list = <int>[];
-  for (dynamic v in list) {
-    v; // marker
-  }
-}''';
-    _assertPropagatedIterationType(
-        code, typeProvider.dynamicType, typeProvider.intType);
-    _assertTypeOfMarkedExpression(
-        code, typeProvider.dynamicType, typeProvider.intType);
-  }
-
-  void test_foreachInference_reusedVar_disabled() {
-    String code = r'''
-main() {
-  var list = <int>[];
-  var v;
-  for (v in list) {
-    v; // marker
-  }
-}''';
-    _assertPropagatedIterationType(
-        code, typeProvider.dynamicType, typeProvider.intType);
-    _assertTypeOfMarkedExpression(
-        code, typeProvider.dynamicType, typeProvider.intType);
-  }
-}
-
-@reflectiveTest
 class TypeProviderImplTest extends EngineTestCase {
   void test_creation() {
     //
diff --git a/pkg/analyzer/test/generated/test_support.dart b/pkg/analyzer/test/generated/test_support.dart
index 6c1b066..20cc0e2 100644
--- a/pkg/analyzer/test/generated/test_support.dart
+++ b/pkg/analyzer/test/generated/test_support.dart
@@ -558,7 +558,8 @@
   bool generateExceptionOnRead = false;
 
   @override
-  int get modificationStamp => generateExceptionOnRead ? -1 : _modificationStamp;
+  int get modificationStamp =>
+      generateExceptionOnRead ? -1 : _modificationStamp;
 
   /**
    * The number of times that the contents of this source have been requested.
@@ -575,46 +576,58 @@
     }
     return new TimestampedData<String>(0, _contents);
   }
+
   String get encoding {
     throw new UnsupportedOperationException();
   }
+
   String get fullName {
     return _name;
   }
+
   int get hashCode => 0;
   bool get isInSystemLibrary {
     return false;
   }
+
   String get shortName {
     return _name;
   }
+
   Uri get uri {
     throw new UnsupportedOperationException();
   }
+
   UriKind get uriKind {
     throw new UnsupportedOperationException();
   }
+
   bool operator ==(Object other) {
     if (other is TestSource) {
       return other._name == _name;
     }
     return false;
   }
+
   bool exists() => exists2;
   void getContentsToReceiver(Source_ContentReceiver receiver) {
     throw new UnsupportedOperationException();
   }
+
   Source resolve(String uri) {
     throw new UnsupportedOperationException();
   }
+
   Uri resolveRelativeUri(Uri uri) {
     return new Uri(scheme: 'file', path: _name).resolveUri(uri);
   }
+
   void setContents(String value) {
     generateExceptionOnRead = false;
     _modificationStamp = new DateTime.now().millisecondsSinceEpoch;
     _contents = value;
   }
+
   @override
   String toString() => '$_name';
 }
diff --git a/pkg/analyzer/test/instrumentation/instrumentation_test.dart b/pkg/analyzer/test/instrumentation/instrumentation_test.dart
index e23fd9a..290b71a 100644
--- a/pkg/analyzer/test/instrumentation/instrumentation_test.dart
+++ b/pkg/analyzer/test/instrumentation/instrumentation_test.dart
@@ -111,8 +111,10 @@
     service.logVersion('myUuid', 'someClientId', 'someClientVersion',
         'aServerVersion', 'anSdkVersion');
     expect(server.normalChannel.toString(), '');
-    expect(server.priorityChannel.toString(), endsWith(
-        ':myUuid:someClientId:someClientVersion:aServerVersion:anSdkVersion\n'));
+    expect(
+        server.priorityChannel.toString(),
+        endsWith(
+            ':myUuid:someClientId:someClientVersion:aServerVersion:anSdkVersion\n'));
   }
 }
 
diff --git a/pkg/analyzer/test/src/context/cache_test.dart b/pkg/analyzer/test/src/context/cache_test.dart
index b9f3608..21432ed 100644
--- a/pkg/analyzer/test/src/context/cache_test.dart
+++ b/pkg/analyzer/test/src/context/cache_test.dart
@@ -622,6 +622,38 @@
     expect(cache.get(target2), isNull);
   }
 
+  test_setState_invalid_withDelta_keepDependency() {
+    Source target = new TestSource('/test.dart');
+    CacheEntry entry = new CacheEntry(target);
+    cache.put(entry);
+    ResultDescriptor result1 = new ResultDescriptor('result1', -1);
+    ResultDescriptor result2 = new ResultDescriptor('result2', -2);
+    ResultDescriptor result3 = new ResultDescriptor('result3', -3);
+    // set results, all of them are VALID
+    entry.setValue(result1, 111, TargetedResult.EMPTY_LIST);
+    entry.setValue(result2, 222, [new TargetedResult(target, result1)]);
+    entry.setValue(result3, 333, [new TargetedResult(target, result2)]);
+    expect(entry.getState(result1), CacheState.VALID);
+    expect(entry.getState(result2), CacheState.VALID);
+    expect(entry.getState(result3), CacheState.VALID);
+    // result2 depends on result1
+    expect(entry.getResultData(result1).dependentResults,
+        unorderedEquals([new TargetedResult(target, result2)]));
+    expect(entry.getResultData(result2).dependedOnResults,
+        unorderedEquals([new TargetedResult(target, result1)]));
+    // invalidate result2 with Delta: keep result2, invalidate result3
+    entry.setState(result2, CacheState.INVALID,
+        delta: new _KeepContinueDelta(target, result2));
+    expect(entry.getState(result1), CacheState.VALID);
+    expect(entry.getState(result2), CacheState.VALID);
+    expect(entry.getState(result3), CacheState.INVALID);
+    // result2 still depends on result1
+    expect(entry.getResultData(result1).dependentResults,
+        unorderedEquals([new TargetedResult(target, result2)]));
+    expect(entry.getResultData(result2).dependedOnResults,
+        unorderedEquals([new TargetedResult(target, result1)]));
+  }
+
   test_setState_valid() {
     AnalysisTarget target = new TestSource();
     ResultDescriptor result = new ResultDescriptor('test', null);
@@ -713,6 +745,8 @@
     expect(entry.getValue(result1), 111);
     expect(entry.getValue(result2), 2222);
     expect(entry.getValue(result3), -3);
+    expect(entry.getResultData(result1).dependentResults,
+        unorderedEquals([new TargetedResult(target, result2)]));
     expect(entry.getResultData(result2).dependedOnResults,
         unorderedEquals([new TargetedResult(target, result1)]));
   }
@@ -1057,6 +1091,25 @@
   noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 }
 
+/**
+ * Keep the given [keepDescriptor], invalidate all the other results.
+ */
+class _KeepContinueDelta implements Delta {
+  final Source source;
+  final ResultDescriptor keepDescriptor;
+
+  _KeepContinueDelta(this.source, this.keepDescriptor);
+
+  @override
+  DeltaResult validate(InternalAnalysisContext context, AnalysisTarget target,
+      ResultDescriptor descriptor) {
+    if (descriptor == keepDescriptor) {
+      return DeltaResult.KEEP_CONTINUE;
+    }
+    return DeltaResult.INVALIDATE;
+  }
+}
+
 class _TestAnalysisTarget implements AnalysisTarget {
   @override
   Source get source => null;
diff --git a/pkg/analyzer/test/src/context/context_test.dart b/pkg/analyzer/test/src/context/context_test.dart
index bad2cc6..acfb596 100644
--- a/pkg/analyzer/test/src/context/context_test.dart
+++ b/pkg/analyzer/test/src/context/context_test.dart
@@ -2239,7 +2239,7 @@
 }
 ''');
     _assertInvalid(sourceA, LIBRARY_ERRORS_READY);
-    _assertValid(sourceB, LIBRARY_ERRORS_READY);
+    _assertValid(sourceB, LIBRARY_ELEMENT);
     // The a.dart's unit and element are updated incrementally.
     // They are the same instances as initially.
     // So, all the references from other units are still valid.
@@ -2275,7 +2275,7 @@
 }
 ''');
     _assertInvalid(sourceA, LIBRARY_ERRORS_READY);
-    _assertInvalid(sourceB, LIBRARY_ERRORS_READY);
+    _assertInvalid(sourceB, LIBRARY_ELEMENT);
     // The a.dart's unit and element are the same.
     {
       LibrarySpecificUnit target = new LibrarySpecificUnit(sourceA, sourceA);
diff --git a/pkg/analyzer/test/src/context/mock_sdk.dart b/pkg/analyzer/test/src/context/mock_sdk.dart
index e5b7bcb..25de8b3 100644
--- a/pkg/analyzer/test/src/context/mock_sdk.dart
+++ b/pkg/analyzer/test/src/context/mock_sdk.dart
@@ -14,8 +14,10 @@
 import 'package:analyzer/src/generated/source.dart';
 
 class MockSdk implements DartSdk {
-  static const _MockSdkLibrary LIB_CORE = const _MockSdkLibrary('dart:core',
-      '/lib/core/core.dart', '''
+  static const _MockSdkLibrary LIB_CORE = const _MockSdkLibrary(
+      'dart:core',
+      '/lib/core/core.dart',
+      '''
 library dart.core;
 
 import 'dart:async';
@@ -108,8 +110,10 @@
 const Object override = const _Override();
 ''');
 
-  static const _MockSdkLibrary LIB_ASYNC = const _MockSdkLibrary('dart:async',
-      '/lib/async/async.dart', '''
+  static const _MockSdkLibrary LIB_ASYNC = const _MockSdkLibrary(
+      'dart:async',
+      '/lib/async/async.dart',
+      '''
 library dart.async;
 
 import 'dart:math';
@@ -125,14 +129,18 @@
 ''');
 
   static const _MockSdkLibrary LIB_COLLECTION = const _MockSdkLibrary(
-      'dart:collection', '/lib/collection/collection.dart', '''
+      'dart:collection',
+      '/lib/collection/collection.dart',
+      '''
 library dart.collection;
 
 abstract class HashMap<K, V> implements Map<K, V> {}
 ''');
 
   static const _MockSdkLibrary LIB_CONVERT = const _MockSdkLibrary(
-      'dart:convert', '/lib/convert/convert.dart', '''
+      'dart:convert',
+      '/lib/convert/convert.dart',
+      '''
 library dart.convert;
 
 import 'dart:async';
@@ -141,8 +149,10 @@
 class JsonDecoder extends Converter<String, Object> {}
 ''');
 
-  static const _MockSdkLibrary LIB_MATH = const _MockSdkLibrary('dart:math',
-      '/lib/math/math.dart', '''
+  static const _MockSdkLibrary LIB_MATH = const _MockSdkLibrary(
+      'dart:math',
+      '/lib/math/math.dart',
+      '''
 library dart.math;
 const double E = 2.718281828459045;
 const double PI = 3.1415926535897932;
@@ -159,8 +169,10 @@
 }
 ''');
 
-  static const _MockSdkLibrary LIB_HTML = const _MockSdkLibrary('dart:html',
-      '/lib/html/dartium/html_dartium.dart', '''
+  static const _MockSdkLibrary LIB_HTML = const _MockSdkLibrary(
+      'dart:html',
+      '/lib/html/dartium/html_dartium.dart',
+      '''
 library dart.html;
 class HtmlElement {}
 ''');
diff --git a/pkg/analyzer/test/src/mock_sdk.dart b/pkg/analyzer/test/src/mock_sdk.dart
index 1487f4a..d4f6ac1 100644
--- a/pkg/analyzer/test/src/mock_sdk.dart
+++ b/pkg/analyzer/test/src/mock_sdk.dart
@@ -12,8 +12,10 @@
 import 'package:analyzer/src/generated/source.dart';
 
 class MockSdk implements DartSdk {
-  static const _MockSdkLibrary LIB_CORE = const _MockSdkLibrary('dart:core',
-      '/lib/core/core.dart', '''
+  static const _MockSdkLibrary LIB_CORE = const _MockSdkLibrary(
+      'dart:core',
+      '/lib/core/core.dart',
+      '''
 library dart.core;
 
 import 'dart:async';
@@ -106,8 +108,10 @@
 const Object override = const _Override();
 ''');
 
-  static const _MockSdkLibrary LIB_ASYNC = const _MockSdkLibrary('dart:async',
-      '/lib/async/async.dart', '''
+  static const _MockSdkLibrary LIB_ASYNC = const _MockSdkLibrary(
+      'dart:async',
+      '/lib/async/async.dart',
+      '''
 library dart.async;
 
 import 'dart:math';
@@ -123,14 +127,18 @@
 ''');
 
   static const _MockSdkLibrary LIB_COLLECTION = const _MockSdkLibrary(
-      'dart:collection', '/lib/collection/collection.dart', '''
+      'dart:collection',
+      '/lib/collection/collection.dart',
+      '''
 library dart.collection;
 
 abstract class HashMap<K, V> implements Map<K, V> {}
 ''');
 
   static const _MockSdkLibrary LIB_CONVERT = const _MockSdkLibrary(
-      'dart:convert', '/lib/convert/convert.dart', '''
+      'dart:convert',
+      '/lib/convert/convert.dart',
+      '''
 library dart.convert;
 
 import 'dart:async';
@@ -139,8 +147,10 @@
 class JsonDecoder extends Converter<String, Object> {}
 ''');
 
-  static const _MockSdkLibrary LIB_MATH = const _MockSdkLibrary('dart:math',
-      '/lib/math/math.dart', '''
+  static const _MockSdkLibrary LIB_MATH = const _MockSdkLibrary(
+      'dart:math',
+      '/lib/math/math.dart',
+      '''
 library dart.math;
 const double E = 2.718281828459045;
 const double PI = 3.1415926535897932;
@@ -157,8 +167,10 @@
 }
 ''');
 
-  static const _MockSdkLibrary LIB_HTML = const _MockSdkLibrary('dart:html',
-      '/lib/html/dartium/html_dartium.dart', '''
+  static const _MockSdkLibrary LIB_HTML = const _MockSdkLibrary(
+      'dart:html',
+      '/lib/html/dartium/html_dartium.dart',
+      '''
 library dart.html;
 class HtmlElement {}
 ''');
diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart
index 95a9ff5..3667038 100644
--- a/pkg/analyzer/test/src/task/dart_test.dart
+++ b/pkg/analyzer/test/src/task/dart_test.dart
@@ -57,7 +57,6 @@
   runReflectiveTests(PartiallyResolveUnitReferencesTaskTest);
   runReflectiveTests(ResolveFunctionBodiesInUnitTaskTest);
   runReflectiveTests(ResolveLibraryTypeNamesTaskTest);
-//  runReflectiveTests(ResolveUnitReferencesTaskTest);
   runReflectiveTests(ResolveUnitTypeNamesTaskTest);
   runReflectiveTests(ResolveVariableReferencesTaskTest);
   runReflectiveTests(ScanDartTaskTest);
@@ -1911,7 +1910,22 @@
 
 @reflectiveTest
 class InferStaticVariableTypesInUnitTaskTest extends _AbstractDartTaskTest {
-  void test_perform() {
+  void test_perform_nestedDeclarations() {
+    enableStrongMode();
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+var f = (int x) {
+  int squared(int value) => value * value;
+  var xSquared = squared(x);
+  return xSquared;
+};
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6,
+        matcher: isInferStaticVariableTypesInUnitTask);
+  }
+
+  void test_perform_recursive() {
     enableStrongMode();
     AnalysisTarget firstSource = newSource(
         '/first.dart',
@@ -1949,6 +1963,30 @@
     expect(variableC.element.type, typeM);
     expect(variableC.initializer.staticType, typeM);
   }
+
+  void test_perform_simple() {
+    enableStrongMode();
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+var X = 1;
+
+var Y = () {
+  return 1 + X;
+};
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6,
+        matcher: isInferStaticVariableTypesInUnitTask);
+    CompilationUnit unit = outputs[RESOLVED_UNIT6];
+    TopLevelVariableDeclaration declaration = unit.declarations[1];
+    FunctionExpression function =
+        declaration.variables.variables[0].initializer;
+    BlockFunctionBody body = function.body;
+    ReturnStatement statement = body.block.statements[0];
+    Expression expression = statement.expression;
+    InterfaceType intType = context.typeProvider.intType;
+    expect(expression.staticType, intType);
+  }
 }
 
 @reflectiveTest
@@ -2269,8 +2307,7 @@
     computeResult(target, RESOLVED_UNIT5,
         matcher: isPartiallyResolveUnitReferencesTask);
     // Test the outputs
-    expect(outputs[CLASSES_IN_UNIT], hasLength(2));
-    expect(outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT], hasLength(2));
+    expect(outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT], hasLength(4));
     CompilationUnit unit = outputs[RESOLVED_UNIT5];
     expect(unit, same(outputs[RESOLVED_UNIT5]));
     // Test the state of the AST
@@ -2280,8 +2317,7 @@
     expect(initializer.staticElement, isNotNull);
     // Test the error generation
     _fillErrorListener(PARTIALLY_RESOLVE_REFERENCES_ERRORS);
-    errorListener.assertErrorsWithCodes(
-        <ErrorCode>[StaticWarningCode.UNDEFINED_IDENTIFIER]);
+    errorListener.assertNoErrors();
   }
 
   test_perform_importExport() {
@@ -2311,20 +2347,83 @@
     computeResult(new LibrarySpecificUnit(sourceC, sourceC), RESOLVED_UNIT5,
         matcher: isPartiallyResolveUnitReferencesTask);
     // validate
-    expect(outputs[CLASSES_IN_UNIT], hasLength(0));
     expect(outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT], hasLength(0));
     CompilationUnit unit = outputs[RESOLVED_UNIT5];
     expect(unit, isNotNull);
 
-    FunctionDeclaration functionDeclaration = unit.declarations[0];
-    BlockFunctionBody body = functionDeclaration.functionExpression.body;
+    FunctionDeclaration mainFunction = unit.declarations[0];
+    expect(mainFunction.element, isNotNull);
+    BlockFunctionBody body = mainFunction.functionExpression.body;
     List<Statement> statements = body.block.statements;
     ExpressionStatement statement = statements[0];
     MethodInvocation invocation = statement.expression;
     MethodElement methodElement = invocation.methodName.staticElement;
-    expect(methodElement, isNotNull);
-    expect(methodElement.type, isNotNull);
-    expect(methodElement.returnType.toString(), 'int');
+    expect(methodElement, isNull);
+  }
+
+  test_perform_notResolved() {
+    enableStrongMode();
+    Source source = newSource(
+        '/test.dart',
+        '''
+int A;
+f1() {
+  A;
+}
+var f2 = () {
+  A;
+  void f3() {
+    A;
+  }
+}
+class C {
+  C() {
+    A;
+  }
+  m() {
+    A;
+  }
+}
+''');
+    LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+    computeResult(target, RESOLVED_UNIT5,
+        matcher: isPartiallyResolveUnitReferencesTask);
+    CompilationUnit unit = outputs[RESOLVED_UNIT5];
+    NodeList<CompilationUnitMember> declarations = unit.declarations;
+
+    void expectReference(BlockFunctionBody body, bool isResolved) {
+      ExpressionStatement statement = body.block.statements[0];
+      SimpleIdentifier reference = statement.expression;
+      expect(reference.staticElement, isResolved ? isNotNull : isNull);
+    }
+    //
+    // The reference to 'A' in 'f1' should not be resolved.
+    //
+    FunctionDeclaration f1 = declarations[1];
+    expectReference(f1.functionExpression.body, false);
+    //
+    // The references to 'A' in 'f2' should be resolved.
+    //
+    TopLevelVariableDeclaration f2 = declarations[2];
+    FunctionExpression expression2 = f2.variables.variables[0].initializer;
+    BlockFunctionBody body2 = expression2.body;
+    expectReference(body2, true);
+
+    FunctionDeclarationStatement statement2 = body2.block.statements[1];
+    BlockFunctionBody innerBody =
+        statement2.functionDeclaration.functionExpression.body;
+    expectReference(innerBody, true);
+    //
+    // The references to 'A' in 'C' should not be resolved.
+    //
+    ClassDeclaration c = declarations[3];
+    NodeList<ClassMember> members = c.members;
+
+    ConstructorDeclaration constructor = members[0];
+    expectReference(constructor.body, false);
+
+    MethodDeclaration method = members[1];
+    expectReference(method.body, false);
   }
 }
 
diff --git a/pkg/analyzer/test/src/task/html_test.dart b/pkg/analyzer/test/src/task/html_test.dart
index ec78be1..a07dc75 100644
--- a/pkg/analyzer/test/src/task/html_test.dart
+++ b/pkg/analyzer/test/src/task/html_test.dart
@@ -175,18 +175,6 @@
 
 @reflectiveTest
 class HtmlErrorsTaskTest extends AbstractContextTest {
-  test_buildInputs() {
-    Source source = newSource('/test.html');
-    Map<String, TaskInput> inputs = HtmlErrorsTask.buildInputs(source);
-    expect(inputs, isNotNull);
-    expect(
-        inputs.keys,
-        unorderedEquals([
-          HtmlErrorsTask.DART_ERRORS_INPUT,
-          HtmlErrorsTask.DOCUMENT_ERRORS_INPUT
-        ]));
-  }
-
   test_constructor() {
     Source source = newSource('/test.html');
     HtmlErrorsTask task = new HtmlErrorsTask(context, source);
diff --git a/pkg/analyzer/test/src/task/strong_mode_test.dart b/pkg/analyzer/test/src/task/strong_mode_test.dart
index 6d9b3f9..7b719ab 100644
--- a/pkg/analyzer/test/src/task/strong_mode_test.dart
+++ b/pkg/analyzer/test/src/task/strong_mode_test.dart
@@ -18,55 +18,11 @@
 
 main() {
   initializeTestEnvironment();
-  runReflectiveTests(InferrenceFinderTest);
   runReflectiveTests(InstanceMemberInferrerTest);
   runReflectiveTests(VariableGathererTest);
 }
 
 @reflectiveTest
-class InferrenceFinderTest extends AbstractContextTest {
-  void test_creation() {
-    InferrenceFinder finder = new InferrenceFinder();
-    expect(finder, isNotNull);
-    expect(finder.classes, isEmpty);
-    expect(finder.staticVariables, isEmpty);
-  }
-
-  void test_visit() {
-    Source source = addSource(
-        '/test.dart',
-        r'''
-const c = 1;
-final f = '';
-var v = const A();
-int i;
-class A {
-  static final fa = 0;
-  static int fi;
-  const A();
-}
-class B extends A {
-  static const cb = 1;
-  static vb = 0;
-  const ci = 2;
-  final fi = '';
-  var vi;
-}
-class C = Object with A;
-typedef int F(int x);
-''');
-    LibrarySpecificUnit librarySpecificUnit =
-        new LibrarySpecificUnit(source, source);
-    computeResult(librarySpecificUnit, RESOLVED_UNIT5);
-    CompilationUnit unit = outputs[RESOLVED_UNIT5];
-    InferrenceFinder finder = new InferrenceFinder();
-    unit.accept(finder);
-    expect(finder.classes, hasLength(3));
-    expect(finder.staticVariables, hasLength(6));
-  }
-}
-
-@reflectiveTest
 class InstanceMemberInferrerTest extends AbstractContextTest {
   InstanceMemberInferrer get createInferrer =>
       new InstanceMemberInferrer(context.typeProvider);
diff --git a/pkg/analyzer/test/src/task/test_support.dart b/pkg/analyzer/test/src/task/test_support.dart
index 2173ba2..e68952b 100644
--- a/pkg/analyzer/test/src/task/test_support.dart
+++ b/pkg/analyzer/test/src/task/test_support.dart
@@ -36,8 +36,11 @@
   final bool handlesDependencyCycles;
 
   TestAnalysisTask(AnalysisContext context, AnalysisTarget target,
-      {this.descriptor, this.exception, this.handlesDependencyCycles: false,
-      this.results, this.value: 1})
+      {this.descriptor,
+      this.exception,
+      this.handlesDependencyCycles: false,
+      this.results,
+      this.value: 1})
       : super(context, target);
 
   @override
diff --git a/pkg/analyzer/tool/task_dependency_graph.dart b/pkg/analyzer/tool/task_dependency_graph.dart
index 4625b42..5da2976 100644
--- a/pkg/analyzer/tool/task_dependency_graph.dart
+++ b/pkg/analyzer/tool/task_dependency_graph.dart
@@ -94,7 +94,9 @@
     CompilationUnitElement modelElement = getUnit(modelSource).element;
     InterfaceType analysisTaskType = modelElement.getType('AnalysisTask').type;
     DartType dynamicType = context.typeProvider.dynamicType;
-    resultDescriptorType = modelElement.getType('ResultDescriptor').type
+    resultDescriptorType = modelElement
+        .getType('ResultDescriptor')
+        .type
         .substitute4([dynamicType]);
     CompilationUnit taskUnit = getUnit(taskSource);
     CompilationUnitElement taskUnitElement = taskUnit.element;
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index d2849d2..b9e48ed 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -19,6 +19,7 @@
     LIBRARIES;
 
 import '../compiler_new.dart' as api;
+import 'commandline_options.dart';
 import 'common/tasks.dart' show
     GenericTask;
 import 'compiler.dart' as leg;
@@ -66,59 +67,60 @@
         this.allowedLibraryCategories = getAllowedLibraryCategories(options),
         super(
             outputProvider: outputProvider,
-            enableTypeAssertions: hasOption(options, '--enable-checked-mode'),
-            enableUserAssertions: hasOption(options, '--enable-checked-mode'),
+            enableTypeAssertions: hasOption(options, Flags.enableCheckedMode),
+            enableUserAssertions: hasOption(options, Flags.enableCheckedMode),
             trustTypeAnnotations:
-                hasOption(options, '--trust-type-annotations'),
+                hasOption(options, Flags.trustTypeAnnotations),
             trustPrimitives:
-                hasOption(options, '--trust-primitives'),
-            enableMinification: hasOption(options, '--minify'),
+                hasOption(options, Flags.trustPrimitives),
+            enableMinification: hasOption(options, Flags.minify),
             useFrequencyNamer:
-                !hasOption(options, "--no-frequency-based-minification"),
-            preserveUris: hasOption(options, '--preserve-uris'),
+                !hasOption(options, Flags.noFrequencyBasedMinification),
+            preserveUris: hasOption(options, Flags.preserveUris),
             enableNativeLiveTypeAnalysis:
-                !hasOption(options, '--disable-native-live-type-analysis'),
+                !hasOption(options, Flags.disableNativeLiveTypeAnalysis),
             emitJavaScript: !(hasOption(options, '--output-type=dart') ||
                               hasOption(options, '--output-type=dart-multi')),
             dart2dartMultiFile: hasOption(options, '--output-type=dart-multi'),
-            generateSourceMap: !hasOption(options, '--no-source-maps'),
-            analyzeAllFlag: hasOption(options, '--analyze-all'),
-            analyzeOnly: hasOption(options, '--analyze-only'),
-            analyzeMain: hasOption(options, '--analyze-main'),
+            generateSourceMap: !hasOption(options, Flags.noSourceMaps),
+            analyzeAllFlag: hasOption(options, Flags.analyzeAll),
+            analyzeOnly: hasOption(options, Flags.analyzeOnly),
+            analyzeMain: hasOption(options, Flags.analyzeMain),
             analyzeSignaturesOnly:
-                hasOption(options, '--analyze-signatures-only'),
+                hasOption(options, Flags.analyzeSignaturesOnly),
             strips: extractCsvOption(options, '--force-strip='),
             enableConcreteTypeInference:
-                hasOption(options, '--enable-concrete-type-inference'),
+                hasOption(options, Flags.enableConcreteTypeInference),
             disableTypeInferenceFlag:
-                hasOption(options, '--disable-type-inference'),
-            preserveComments: hasOption(options, '--preserve-comments'),
-            useCpsIr: hasOption(options, '--use-cps-ir'),
-            verbose: hasOption(options, '--verbose'),
+                hasOption(options, Flags.disableTypeInference),
+            preserveComments: hasOption(options, Flags.preserveComments),
+            useCpsIr: hasOption(options, Flags.useCpsIr),
+            verbose: hasOption(options, Flags.verbose),
             sourceMapUri: extractUriOption(options, '--source-map='),
             outputUri: extractUriOption(options, '--out='),
-            terseDiagnostics: hasOption(options, '--terse'),
+            terseDiagnostics: hasOption(options, Flags.terse),
             deferredMapUri: extractUriOption(options, '--deferred-map='),
-            dumpInfo: hasOption(options, '--dump-info'),
+            dumpInfo: hasOption(options, Flags.dumpInfo),
             buildId: extractStringOption(
                 options, '--build-id=',
                 "build number could not be determined"),
             showPackageWarnings:
-                hasOption(options, '--show-package-warnings'),
-            useContentSecurityPolicy: hasOption(options, '--csp'),
-            useStartupEmitter: hasOption(options, '--fast-startup'),
+                hasOption(options, Flags.showPackageWarnings),
+            useContentSecurityPolicy:
+              hasOption(options, Flags.useContentSecurityPolicy),
+            useStartupEmitter: hasOption(options, Flags.fastStartup),
             hasIncrementalSupport:
                 forceIncrementalSupport ||
-                hasOption(options, '--incremental-support'),
-            suppressWarnings: hasOption(options, '--suppress-warnings'),
-            fatalWarnings: hasOption(options, '--fatal-warnings'),
+                hasOption(options, Flags.incrementalSupport),
+            suppressWarnings: hasOption(options, Flags.suppressWarnings),
+            fatalWarnings: hasOption(options, Flags.fatalWarnings),
             enableExperimentalMirrors:
-                hasOption(options, '--enable-experimental-mirrors'),
+                hasOption(options, Flags.enableExperimentalMirrors),
             generateCodeWithCompileTimeErrors:
-                hasOption(options, '--generate-code-with-compile-time-errors'),
-            testMode: hasOption(options, '--test-mode'),
+                hasOption(options, Flags.generateCodeWithCompileTimeErrors),
+            testMode: hasOption(options, Flags.testMode),
             allowNativeExtensions:
-                hasOption(options, '--allow-native-extensions')) {
+                hasOption(options, Flags.allowNativeExtensions)) {
     tasks.addAll([
         userHandlerTask = new GenericTask('Diagnostic handler', this),
         userProviderTask = new GenericTask('Input provider', this),
@@ -141,8 +143,8 @@
     if (!analyzeOnly) {
       if (allowNativeExtensions) {
         throw new ArgumentError(
-            "--allow-native-extensions is only supported in combination with "
-            "--analyze-only");
+            "${Flags.allowNativeExtensions} is only supported in combination "
+            "with ${Flags.analyzeOnly}");
       }
     }
   }
@@ -189,10 +191,13 @@
 
   // TODO(johnniwinther): Merge better with [translateDartUri] when
   // [scanBuiltinLibrary] is removed.
-  String lookupLibraryPath(LibraryInfo info) {
+  String lookupLibraryPath(Uri uri, LibraryInfo info) {
     if (info == null) return null;
     if (!info.isDart2jsLibrary) return null;
-    if (!allowedLibraryCategories.contains(info.category)) return null;
+    if (!allowedLibraryCategories.contains(info.category)) {
+      registerDisallowedLibraryUse(uri);
+      return null;
+    }
     String path = info.dart2jsPath;
     if (path == null) {
       path = info.path;
@@ -216,9 +221,9 @@
 
   /// See [leg.Compiler.translateResolvedUri].
   Uri translateResolvedUri(elements.LibraryElement importingLibrary,
-                           Uri resolvedUri, tree.Node node) {
+                           Uri resolvedUri, Spannable spannable) {
     if (resolvedUri.scheme == 'dart') {
-      return translateDartUri(importingLibrary, resolvedUri, node);
+      return translateDartUri(importingLibrary, resolvedUri, spannable);
     }
     return resolvedUri;
   }
@@ -312,9 +317,9 @@
   }
 
   Uri translateDartUri(elements.LibraryElement importingLibrary,
-                       Uri resolvedUri, tree.Node node) {
+                       Uri resolvedUri, Spannable spannable) {
     LibraryInfo libraryInfo = lookupLibraryInfo(resolvedUri.path);
-    String path = lookupLibraryPath(libraryInfo);
+    String path = lookupLibraryPath(resolvedUri, libraryInfo);
     if (libraryInfo != null &&
         libraryInfo.category == "Internal") {
       bool allowInternalLibraryAccess = false;
@@ -329,21 +334,28 @@
       if (!allowInternalLibraryAccess) {
         if (importingLibrary != null) {
           reportError(
-              node,
+              spannable,
               MessageKind.INTERNAL_LIBRARY_FROM,
               {'resolvedUri': resolvedUri,
                'importingUri': importingLibrary.canonicalUri});
         } else {
           reportError(
-              node,
+              spannable,
               MessageKind.INTERNAL_LIBRARY,
               {'resolvedUri': resolvedUri});
         }
       }
     }
     if (path == null) {
-      reportError(node, MessageKind.LIBRARY_NOT_FOUND,
-                  {'resolvedUri': resolvedUri});
+      if (libraryInfo == null) {
+        reportError(spannable, MessageKind.LIBRARY_NOT_FOUND,
+                    {'resolvedUri': resolvedUri});
+      } else {
+        reportError(spannable, MessageKind.LIBRARY_NOT_SUPPORTED,
+                    {'resolvedUri': resolvedUri});
+      }
+      // TODO(johnniwinther): Support signaling the error through the returned
+      // value.
       return null;
     }
     if (resolvedUri.path == 'html' ||
@@ -472,7 +484,7 @@
 
   bool get isMockCompilation {
     return mockableLibraryUsed
-      && (options.indexOf('--allow-mock-compilation') != -1);
+      && (options.indexOf(Flags.allowMockCompilation) != -1);
   }
 
   void callUserHandler(Message message, Uri uri, int begin, int end,
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
new file mode 100644
index 0000000..4cd99ed
--- /dev/null
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2015, 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.cmdline.options;
+
+/// Commandline flags used in `dart2js.dart` and/or `apiimpl.dart`.
+class Flags {
+  static const String allowMockCompilation = '--allow-mock-compilation';
+  static const String allowNativeExtensions = '--allow-native-extensions';
+  static const String analyzeAll = '--analyze-all';
+  static const String analyzeMain = '--analyze-main';
+  static const String analyzeOnly = '--analyze-only';
+  static const String analyzeSignaturesOnly = '--analyze-signatures-only';
+  static const String disableDiagnosticColors = '--disable-diagnostic-colors';
+  static const String disableNativeLiveTypeAnalysis =
+      '--disable-native-live-type-analysis';
+  static const String disableTypeInference = '--disable-type-inference';
+  static const String dumpInfo = '--dump-info';
+  static const String enableCheckedMode = '--enable-checked-mode';
+  static const String enableConcreteTypeInference =
+      '--enable-concrete-type-inference';
+  static const String enableDiagnosticColors = '--enable-diagnostic-colors';
+  static const String enableExperimentalMirrors =
+      '--enable-experimental-mirrors';
+  static const String fastStartup = '--fast-startup';
+  static const String fatalWarnings = '--fatal-warnings';
+  static const String generateCodeWithCompileTimeErrors =
+      '--generate-code-with-compile-time-errors';
+  static const String incrementalSupport = '--incremental-support';
+  static const String minify = '--minify';
+  static const String noFrequencyBasedMinification =
+      '--no-frequency-based-minification';
+  static const String noSourceMaps = '--no-source-maps';
+  static const String preserveComments = '--preserve-comments';
+  static const String preserveUris = '--preserve-uris';
+  static const String showPackageWarnings = '--show-package-warnings';
+  static const String suppressHints = '--suppress-hints';
+  static const String suppressWarnings = '--suppress-warnings';
+  static const String terse = '--terse';
+  static const String testMode = '--test-mode';
+  static const String trustPrimitives = '--trust-primitives';
+  static const String trustTypeAnnotations = '--trust-type-annotations';
+  static const String useContentSecurityPolicy = '--csp';
+  static const String useCpsIr = '--use-cps-ir';
+  static const String verbose = '--verbose';
+  static const String version = '--version';
+}
diff --git a/pkg/compiler/lib/src/common/backend_api.dart b/pkg/compiler/lib/src/common/backend_api.dart
index 42ad090..7af8750 100644
--- a/pkg/compiler/lib/src/common/backend_api.dart
+++ b/pkg/compiler/lib/src/common/backend_api.dart
@@ -212,7 +212,6 @@
   void enableIsolateSupport(Enqueuer enqueuer) {}
 
   void registerRequiredType(DartType type, Element enclosingElement) {}
-  void registerClassUsingVariableExpression(ClassElement cls) {}
 
   void registerConstSymbol(String name, Registry registry) {}
   void registerNewSymbol(Registry registry) {}
diff --git a/pkg/compiler/lib/src/common/names.dart b/pkg/compiler/lib/src/common/names.dart
index 7051ffe..5d104ef 100644
--- a/pkg/compiler/lib/src/common/names.dart
+++ b/pkg/compiler/lib/src/common/names.dart
@@ -18,10 +18,17 @@
   /// The name of the call operator.
   static const String call = 'call';
 
+  /// The name of the current element property used on iterators in for-each
+  /// loops.
+  static const String current = 'current';
+
   /// The name of the from environment constructors on 'int', 'bool' and
   /// 'String'.
   static const String fromEnvironment = 'fromEnvironment';
 
+  /// The name of the iterator property used in for-each loops.
+  static const String iterator = 'iterator';
+
   /// The name of the main method.
   static const String main = 'main';
 
@@ -39,13 +46,13 @@
 
   /// The name of the current element property used on iterators in for-each
   /// loops.
-  static const Name current = const PublicName('current');
+  static const Name current = const PublicName(Identifiers.current);
 
   /// The name of the dynamic type.
   static const Name dynamic_ = const PublicName('dynamic');
 
   /// The name of the iterator property used in for-each loops.
-  static const Name iterator = const PublicName('iterator');
+  static const Name iterator = const PublicName(Identifiers.iterator);
 
   /// The name of the move next method used on iterators in for-each loops.
   static const Name moveNext = const PublicName('moveNext');
diff --git a/pkg/compiler/lib/src/common/resolution.dart b/pkg/compiler/lib/src/common/resolution.dart
index 2f9b828..e43cf14 100644
--- a/pkg/compiler/lib/src/common/resolution.dart
+++ b/pkg/compiler/lib/src/common/resolution.dart
@@ -10,7 +10,8 @@
     DartType;
 import '../elements/elements.dart' show
     AstElement,
-    ErroneousElement;
+    ErroneousElement,
+    TypeVariableElement;
 import '../enqueue.dart' show
     ResolutionEnqueuer,
     WorldImpact;
@@ -66,7 +67,8 @@
 
   /// Called during resolution to notify to the backend that the
   /// program uses a type variable as an expression.
-  void onTypeVariableExpression(Registry registry) {}
+  void onTypeVariableExpression(Registry registry,
+                                TypeVariableElement variable) {}
 
   /// Called during resolution to notify to the backend that the
   /// program uses a type literal.
@@ -114,4 +116,7 @@
 
   /// Called when resolving the `Symbol` constructor.
   void onSymbolConstructor(Registry registry) {}
+
+  /// Called when resolving a prefix or postfix expression.
+  void onIncDecOperation(Registry registry) {}
 }
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index db180aa..747dc38 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -133,7 +133,8 @@
     Selector,
     Universe;
 import 'util/util.dart' show
-    Link;
+    Link,
+    Setlet;
 import 'world.dart' show
     World;
 
@@ -275,6 +276,11 @@
 
   List<Uri> librariesToAnalyzeWhenRun;
 
+  /// The set of platform libraries reported as unsupported.
+  ///
+  /// For instance when importing 'dart:io' without '--categories=Server'.
+  Set<Uri> disallowedLibraryUris = new Setlet<Uri>();
+
   Tracer tracer;
 
   CompilerTask measuredTask;
@@ -770,6 +776,72 @@
     return backend.onLibraryScanned(library, loader);
   }
 
+  /// Compute the set of distinct import chains to the library at [uri] within
+  /// [loadedLibraries].
+  ///
+  /// The chains are strings of the form
+  ///
+  ///       <main-uri> => <intermediate-uri1> => <intermediate-uri2> => <uri>
+  ///
+  Set<String> computeImportChainsFor(LoadedLibraries loadedLibraries, Uri uri) {
+    // TODO(johnniwinther): Move computation of dependencies to the library
+    // loader.
+    Uri rootUri = loadedLibraries.rootUri;
+    Set<String> importChains = new Set<String>();
+    // The maximum number of full imports chains to process.
+    final int chainLimit = 10000;
+    // The maximum number of imports chains to show.
+    final int compactChainLimit = verbose ? 20 : 10;
+    int chainCount = 0;
+    loadedLibraries.forEachImportChain(uri,
+        callback: (Link<Uri> importChainReversed) {
+      Link<CodeLocation> compactImportChain = const Link<CodeLocation>();
+      CodeLocation currentCodeLocation =
+          new UriLocation(importChainReversed.head);
+      compactImportChain = compactImportChain.prepend(currentCodeLocation);
+      for (Link<Uri> link = importChainReversed.tail;
+           !link.isEmpty;
+           link = link.tail) {
+        Uri uri = link.head;
+        if (!currentCodeLocation.inSameLocation(uri)) {
+          currentCodeLocation =
+              verbose ? new UriLocation(uri) : new CodeLocation(uri);
+          compactImportChain =
+              compactImportChain.prepend(currentCodeLocation);
+        }
+      }
+      String importChain =
+          compactImportChain.map((CodeLocation codeLocation) {
+            return codeLocation.relativize(rootUri);
+          }).join(' => ');
+
+      if (!importChains.contains(importChain)) {
+        if (importChains.length > compactChainLimit) {
+          importChains.add('...');
+          return false;
+        } else {
+          importChains.add(importChain);
+        }
+      }
+
+      chainCount++;
+      if (chainCount > chainLimit) {
+        // Assume there are more import chains.
+        importChains.add('...');
+        return false;
+      }
+      return true;
+    });
+    return importChains;
+  }
+
+  /// Register that [uri] was recognized but disallowed as a dependency.
+  ///
+  /// For instance import of 'dart:io' without '--categories=Server'.
+  void registerDisallowedLibraryUse(Uri uri) {
+    disallowedLibraryUris.add(uri);
+  }
+
   /// This method is called when all new libraries loaded through
   /// [LibraryLoader.loadLibrary] has been loaded and their imports/exports
   /// have been computed.
@@ -780,60 +852,26 @@
   /// libraries.
   Future onLibrariesLoaded(LoadedLibraries loadedLibraries) {
     return new Future.sync(() {
+      for (Uri uri in disallowedLibraryUris) {
+        if (loadedLibraries.containsLibrary(uri)) {
+          Set<String> importChains =
+              computeImportChainsFor(loadedLibraries, Uri.parse('dart:io'));
+          reportInfo(NO_LOCATION_SPANNABLE,
+             MessageKind.DISALLOWED_LIBRARY_IMPORT,
+              {'uri': uri,
+               'importChain': importChains.join(
+                   MessageTemplate.DISALLOWED_LIBRARY_IMPORT_PADDING)});
+        }
+      }
+
       if (!loadedLibraries.containsLibrary(Uris.dart_core)) {
         return null;
       }
+
       if (!enableExperimentalMirrors &&
           loadedLibraries.containsLibrary(Uris.dart_mirrors)) {
-        // TODO(johnniwinther): Move computation of dependencies to the library
-        // loader.
-        Uri rootUri = loadedLibraries.rootUri;
-        Set<String> importChains = new Set<String>();
-        // The maximum number of full imports chains to process.
-        final int chainLimit = 10000;
-        // The maximum number of imports chains to show.
-        final int compactChainLimit = verbose ? 20 : 10;
-        int chainCount = 0;
-        loadedLibraries.forEachImportChain(Uris.dart_mirrors,
-            callback: (Link<Uri> importChainReversed) {
-          Link<CodeLocation> compactImportChain = const Link<CodeLocation>();
-          CodeLocation currentCodeLocation =
-              new UriLocation(importChainReversed.head);
-          compactImportChain = compactImportChain.prepend(currentCodeLocation);
-          for (Link<Uri> link = importChainReversed.tail;
-               !link.isEmpty;
-               link = link.tail) {
-            Uri uri = link.head;
-            if (!currentCodeLocation.inSameLocation(uri)) {
-              currentCodeLocation =
-                  verbose ? new UriLocation(uri) : new CodeLocation(uri);
-              compactImportChain =
-                  compactImportChain.prepend(currentCodeLocation);
-            }
-          }
-          String importChain =
-              compactImportChain.map((CodeLocation codeLocation) {
-                return codeLocation.relativize(rootUri);
-              }).join(' => ');
-
-          if (!importChains.contains(importChain)) {
-            if (importChains.length > compactChainLimit) {
-              importChains.add('...');
-              return false;
-            } else {
-              importChains.add(importChain);
-            }
-          }
-
-          chainCount++;
-          if (chainCount > chainLimit) {
-            // Assume there are more import chains.
-            importChains.add('...');
-            return false;
-          }
-          return true;
-        });
-
+        Set<String> importChains =
+            computeImportChainsFor(loadedLibraries, Uris.dart_mirrors);
         if (!backend.supportsReflection) {
           reportError(NO_LOCATION_SPANNABLE,
                       MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND);
@@ -848,11 +886,6 @@
       functionClass.ensureResolved(this);
       functionApplyMethod = functionClass.lookupLocalMember('apply');
 
-      proxyConstant =
-          constants.getConstantValue(
-              resolver.constantCompiler.compileConstant(
-                  coreLibrary.find('proxy')));
-
       if (preserveComments) {
         return libraryLoader.loadLibrary(Uris.dart_mirrors)
             .then((LibraryElement libraryElement) {
@@ -862,6 +895,18 @@
     }).then((_) => backend.onLibrariesLoaded(loadedLibraries));
   }
 
+  bool isProxyConstant(ConstantValue value) {
+    FieldElement field = coreLibrary.find('proxy');
+    if (field == null) return false;
+    if (!enqueuer.resolution.hasBeenResolved(field)) return false;
+    if (proxyConstant == null) {
+      proxyConstant =
+          constants.getConstantValue(
+              resolver.constantCompiler.compileConstant(field));
+    }
+    return proxyConstant == value;
+  }
+
   Element findRequiredElement(LibraryElement library, String name) {
     var element = library.find(name);
     if (element == null) {
@@ -1492,7 +1537,7 @@
    * See [LibraryLoader] for terminology on URIs.
    */
   Uri translateResolvedUri(LibraryElement importingLibrary,
-                           Uri resolvedUri, Node node) {
+                           Uri resolvedUri, Spannable spannable) {
     unimplemented(importingLibrary, 'Compiler.translateResolvedUri');
     return null;
   }
diff --git a/pkg/compiler/lib/src/constants/expressions.dart b/pkg/compiler/lib/src/constants/expressions.dart
index 7311912..fd0f68a 100644
--- a/pkg/compiler/lib/src/constants/expressions.dart
+++ b/pkg/compiler/lib/src/constants/expressions.dart
@@ -1563,7 +1563,7 @@
 
   @override
   void visitDeferred(DeferredConstantExpression exp, context) {
-    sb.write(exp.prefix.deferredImport.prefix.source);
+    sb.write(exp.prefix.name);
     sb.write('.');
     write(exp, exp.expression);
   }
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
index d93de7b..070aa60 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
@@ -161,7 +161,7 @@
 /// The subclass describes how to compute the value.
 ///
 /// All primitives except [Parameter] must be bound by a [LetPrim].
-abstract class Primitive extends Definition<Primitive> {
+abstract class Primitive extends Variable<Primitive> {
   /// The [VariableElement] or [ParameterElement] from which the primitive
   /// binding originated.
   Entity hint;
@@ -405,6 +405,17 @@
   final Reference<Continuation> continuation;
   final SourceInformation sourceInformation;
 
+  /// If true, the [receiver] is intercepted and the actual receiver is in
+  /// the first argument. Otherwise, the [receiver] is the actual receiver.
+  ///
+  /// This flag is always false for non-intercepted selectors, but it may also
+  /// be false for intercepted selectors after dummy receiver optimization
+  /// (in this case the first argument is a dummy value).
+  ///
+  /// It is always false before the unsugaring pass, where interceptors have
+  /// not yet been introduced.
+  bool receiverIsIntercepted = false;
+
   /// If true, it is known that the receiver cannot be `null`.
   bool receiverIsNotNull = false;
 
@@ -484,14 +495,14 @@
 /// Note that [InvokeConstructor] does it itself allocate an object.
 /// The invoked constructor will do that using [CreateInstance].
 class InvokeConstructor extends CallExpression {
-  final DartType type;
+  final DartType dartType;
   final ConstructorElement target;
   final List<Reference<Primitive>> arguments;
   final Reference<Continuation> continuation;
   final Selector selector;
   final SourceInformation sourceInformation;
 
-  InvokeConstructor(this.type,
+  InvokeConstructor(this.dartType,
                     this.target,
                     this.selector,
                     List<Primitive> args,
@@ -512,9 +523,9 @@
 /// to the same primitive).
 class Refinement extends Primitive {
   Reference<Primitive> value;
-  final TypeMask type;
+  final TypeMask refineType;
 
-  Refinement(Primitive value, this.type)
+  Refinement(Primitive value, this.refineType)
     : value = new Reference<Primitive>(value);
 
   bool get isSafeForElimination => true;
@@ -534,7 +545,7 @@
 /// to simplify code generation for type tests.
 class TypeTest extends Primitive {
   Reference<Primitive> value;
-  final DartType type;
+  final DartType dartType;
 
   /// If [type] is an [InterfaceType], this holds the internal representation of
   /// the type arguments to [type]. Since these may reference type variables
@@ -550,7 +561,7 @@
   final List<Reference<Primitive>> typeArguments;
 
   TypeTest(Primitive value,
-           this.type,
+           this.dartType,
            List<Primitive> typeArguments)
   : this.value = new Reference<Primitive>(value),
     this.typeArguments = _referenceList(typeArguments);
@@ -573,14 +584,14 @@
 /// continuation parameter without needing flow-sensitive analysis.
 class TypeCast extends CallExpression {
   Reference<Primitive> value;
-  final DartType type;
+  final DartType dartType;
 
   /// See the corresponding field on [TypeTest].
   final List<Reference<Primitive>> typeArguments;
   final Reference<Continuation> continuation;
 
   TypeCast(Primitive value,
-           this.type,
+           this.dartType,
            List<Primitive> typeArguments,
            Continuation cont)
       : this.value = new Reference<Primitive>(value),
@@ -1036,10 +1047,10 @@
 
 class LiteralList extends Primitive {
   /// The List type being created; this is not the type argument.
-  final InterfaceType type;
+  final InterfaceType dartType;
   final List<Reference<Primitive>> values;
 
-  LiteralList(this.type, List<Primitive> values)
+  LiteralList(this.dartType, List<Primitive> values)
       : this.values = _referenceList(values);
 
   accept(Visitor visitor) => visitor.visitLiteralList(this);
@@ -1058,10 +1069,10 @@
 }
 
 class LiteralMap extends Primitive {
-  final InterfaceType type;
+  final InterfaceType dartType;
   final List<LiteralMapEntry> entries;
 
-  LiteralMap(this.type, this.entries);
+  LiteralMap(this.dartType, this.entries);
 
   accept(Visitor visitor) => visitor.visitLiteralMap(this);
 
@@ -1135,8 +1146,16 @@
   accept(Visitor visitor) => visitor.visitContinuation(this);
 }
 
+/// Common interface for [Primitive] and [MutableVariable].
+abstract class Variable<T extends Variable<T>> extends Definition<T> {
+  /// Type of value held in the variable.
+  ///
+  /// Is `null` until initialized by type propagation.
+  TypeMask type;
+}
+
 /// Identifies a mutable variable.
-class MutableVariable extends Definition {
+class MutableVariable extends Variable<MutableVariable> {
   Entity hint;
 
   MutableVariable(this.hint);
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
index 1131ce8..631e909 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
@@ -159,8 +159,8 @@
     // constructor calls in the DartBackend, we get an element with no enclosing
     // class.  Clean this up by introducing a name field to the node and
     // removing [ErroneousElement]s from the IR.
-    if (node.type != null) {
-      className = node.type.toString();
+    if (node.dartType != null) {
+      className = node.dartType.toString();
     } else {
       className = node.target.enclosingClass.name;
     }
@@ -232,13 +232,14 @@
     String value = access(node.value);
     String cont = access(node.continuation);
     String typeArguments = node.typeArguments.map(access).join(' ');
-    return '$indentation(TypeCast $value ${node.type} ($typeArguments) $cont)';
+    return '$indentation(TypeCast $value ${node.dartType}'
+                         ' ($typeArguments) $cont)';
   }
 
   String visitTypeTest(TypeTest node) {
     String value = access(node.value);
     String typeArguments = node.typeArguments.map(access).join(' ');
-    return '(TypeTest $value ${node.type} ($typeArguments))';
+    return '(TypeTest $value ${node.dartType} ($typeArguments))';
   }
 
   String visitLiteralList(LiteralList node) {
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
index 6b56330..5240db9 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
@@ -82,7 +82,10 @@
       });
       tag("HIR", () {
         if (entryPointParameters != null) {
-          String params = entryPointParameters.map(names.name).join(', ');
+          String formatParameter(cps_ir.Parameter param) {
+            return '${names.name(param)} ${param.type}';
+          }
+          String params = entryPointParameters.map(formatParameter).join(', ');
           printStmt('x0', 'Entry ($params)');
         }
         for (cps_ir.Parameter param in block.parameters) {
@@ -103,7 +106,8 @@
 
   visitLetPrim(cps_ir.LetPrim node) {
     String id = names.name(node.primitive);
-    printStmt(id, "LetPrim $id = ${formatPrimitive(node.primitive)}");
+    String primitive = visit(node.primitive);
+    printStmt(id, "LetPrim $id = $primitive [type=${node.primitive.type}]");
     visit(node.body);
   }
 
@@ -215,7 +219,7 @@
     String value = formatReference(node.value);
     String args = node.typeArguments.map(formatReference).join(', ');
     String kont = formatReference(node.continuation);
-    printStmt(dummy, "TypeCast ($value ${node.type} ($args)) $kont");
+    printStmt(dummy, "TypeCast ($value ${node.dartType} ($args)) $kont");
   }
 
   visitInvokeContinuation(cps_ir.InvokeContinuation node) {
@@ -249,8 +253,6 @@
     }
   }
 
-  String formatPrimitive(cps_ir.Primitive p) => visit(p);
-
   visitConstant(cps_ir.Constant node) {
     return "Constant ${node.value.toStructuredString()}";
   }
@@ -344,7 +346,7 @@
   visitTypeTest(cps_ir.TypeTest node) {
     String value = formatReference(node.value);
     String args = node.typeArguments.map(formatReference).join(', ');
-    return "TypeTest ($value ${node.type} ($args))";
+    return "TypeTest ($value ${node.dartType} ($args))";
   }
 
   visitApplyBuiltinOperator(cps_ir.ApplyBuiltinOperator node) {
diff --git a/pkg/compiler/lib/src/cps_ir/insert_refinements.dart b/pkg/compiler/lib/src/cps_ir/insert_refinements.dart
index 03cafdf..ec12543 100644
--- a/pkg/compiler/lib/src/cps_ir/insert_refinements.dart
+++ b/pkg/compiler/lib/src/cps_ir/insert_refinements.dart
@@ -7,13 +7,13 @@
 import 'optimizers.dart' show Pass;
 import 'shrinking_reductions.dart' show ParentVisitor;
 import 'cps_ir_nodes.dart';
-import '../types/types.dart';
 import '../types/constants.dart';
 import '../constants/values.dart';
-import '../world.dart';
 import '../common/names.dart';
 import '../universe/universe.dart';
 import '../elements/elements.dart';
+import '../types/types.dart' show TypeMask;
+import 'type_mask_system.dart';
 
 /// Inserts [Refinement] nodes in the IR to allow for sparse path-sensitive
 /// type analysis in the [TypePropagator] pass.
@@ -26,18 +26,12 @@
 class InsertRefinements extends RecursiveVisitor implements Pass {
   String get passName => 'Insert refinement nodes';
 
-  final TypesTask types;
-  final World world;
-  final TypeMask nonNullType;
-  final TypeMask nullType;
+  final TypeMaskSystem types;
 
   /// Maps unrefined primitives to its refinement currently in scope (if any).
   final Map<Primitive, Refinement> refinementFor = <Primitive, Refinement>{};
 
-  InsertRefinements(this.types, World world)
-    : this.world = world,
-      nonNullType = new TypeMask.nonNullSubtype(world.objectClass, world),
-      nullType = new TypeMask.empty();
+  InsertRefinements(this.types);
 
   void rewrite(FunctionDefinition node) {
     new ParentVisitor().visit(node);
@@ -134,7 +128,7 @@
       push(cont);
     } else {
       // Filter away receivers that throw on this selector.
-      TypeMask type = world.allFunctions.receiverType(node.selector, node.mask);
+      TypeMask type = types.receiverTypeFor(node.selector, node.mask);
       pushRefinement(cont, new Refinement(receiver, type));
     }
   }
@@ -153,10 +147,6 @@
     return prim is Constant && prim.value.isTrue;
   }
 
-  TypeMask getTypeOf(ConstantValue constant) {
-    return computeTypeMask(types.compiler, constant);
-  }
-
   void visitBranch(Branch node) {
     processReference(node.condition);
     Primitive condition = node.condition.definition;
@@ -171,10 +161,9 @@
     sinkContinuationToUse(falseCont, node);
 
     // If the condition is an 'is' check, promote the checked value.
-    if (condition is TypeTest && condition.type.element is ClassElement) {
+    if (condition is TypeTest) {
       Primitive value = condition.value.definition;
-      ClassElement classElement = condition.type.element;
-      TypeMask type = new TypeMask.nonNullSubtype(classElement, world);
+      TypeMask type = types.subtypesOf(condition.dartType);
       Primitive refinedValue = new Refinement(value, type);
       pushRefinement(trueCont, refinedValue);
       push(falseCont);
@@ -190,13 +179,13 @@
                         Continuation trueCont,
                         Continuation falseCont) {
       if (second is Constant && second.value.isNull) {
-        Refinement refinedTrue = new Refinement(first, nullType);
-        Refinement refinedFalse = new Refinement(first, nonNullType);
+        Refinement refinedTrue = new Refinement(first, types.nullType);
+        Refinement refinedFalse = new Refinement(first, types.nonNullType);
         pushRefinement(trueCont, refinedTrue);
         pushRefinement(falseCont, refinedFalse);
       } else if (first is Constant && first.value.isNull) {
-        Refinement refinedTrue = new Refinement(second, nullType);
-        Refinement refinedFalse = new Refinement(second, nonNullType);
+        Refinement refinedTrue = new Refinement(second, types.nullType);
+        Refinement refinedFalse = new Refinement(second, types.nonNullType);
         pushRefinement(trueCont, refinedTrue);
         pushRefinement(falseCont, refinedFalse);
       } else {
diff --git a/pkg/compiler/lib/src/cps_ir/loop_invariant_code_motion.dart b/pkg/compiler/lib/src/cps_ir/loop_invariant_code_motion.dart
index 4471019..877f4ac 100644
--- a/pkg/compiler/lib/src/cps_ir/loop_invariant_code_motion.dart
+++ b/pkg/compiler/lib/src/cps_ir/loop_invariant_code_motion.dart
@@ -126,9 +126,15 @@
   }
 
   bool shouldLift(Primitive prim) {
-    // Interceptors are safe and almost always profitable for lifting
+    // Interceptors are generally safe and almost always profitable for lifting
     // out of loops. Several other primitive could be lifted too, but it's not
     // always profitable to do so.
+
+    // Note that the type of the interceptor is technically not sound after
+    // lifting because its current type might have been computed based on a
+    // refinement node (which has since been removed). As a whole, it still
+    // works out because all uses of the interceptor must occur in a context
+    // where it indeed has the type it claims to have.
     return prim is Interceptor;
   }
 }
diff --git a/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart b/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
index d01c3f5..3dea17c 100644
--- a/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
+++ b/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
@@ -191,6 +191,7 @@
               <MutableVariable, Primitive>{};
           for (MutableVariable variable in mutableVariables) {
             Parameter phi = new Parameter(variable.hint);
+            phi.type = variable.type;
             cont.parameters.add(phi);
             phi.parent = cont;
             environment[variable] = phi;
diff --git a/pkg/compiler/lib/src/cps_ir/optimizers.dart b/pkg/compiler/lib/src/cps_ir/optimizers.dart
index d10823a..1ffe526 100644
--- a/pkg/compiler/lib/src/cps_ir/optimizers.dart
+++ b/pkg/compiler/lib/src/cps_ir/optimizers.dart
@@ -37,3 +37,11 @@
       value.isNaN ||
       value is StringConstantValue && value.primitiveValue.isEmpty;
 }
+
+/// Returns true if [value] satisfies a branching condition with the
+/// given strictness.
+///
+/// For non-strict, this is the opposite of [isFalsyConstant].
+bool isTruthyConstant(ConstantValue value, {bool strict: false}) {
+  return strict ? value.isTrue : !isFalsyConstant(value);
+}
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_join.dart b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
index 4acb2ef..747e701 100644
--- a/pkg/compiler/lib/src/cps_ir/redundant_join.dart
+++ b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
@@ -109,12 +109,12 @@
       Primitive argument = invoke.arguments[parameterIndex].definition;
       if (argument is! Constant) return; // Branching condition is unknown.
       Constant constant = argument;
-      if (isFalsyConstant(constant.value)) {
-        ++falseHits;
-        falseCall = invoke;
-      } else {
+      if (isTruthyConstant(constant.value, strict: branch.isStrictCheck)) {
         ++trueHits;
         trueCall = invoke;
+      } else {
+        ++falseHits;
+        falseCall = invoke;
       }
     }
 
@@ -182,10 +182,10 @@
       Reference reference = branchCont.firstRef;
       InvokeContinuation invoke = branchCont.firstRef.parent;
       Constant condition = invoke.arguments[parameterIndex].definition;
-      if (isFalsyConstant(condition.value)) {
-        invoke.continuation.changeTo(falseCont);
-      } else {
+      if (isTruthyConstant(condition.value, strict: branch.isStrictCheck)) {
         invoke.continuation.changeTo(trueCont);
+      } else {
+        invoke.continuation.changeTo(falseCont);
       }
       assert(branchCont.firstRef != reference);
     }
@@ -248,6 +248,7 @@
       // create a new parameter object for this continuation.
       if (param.parent != cont) {
         Parameter newParam = new Parameter(param.hint);
+        newParam.type = param.type;
         renaming[param] = newParam;
         cont.parameters[i] = newParam;
         newParam.parent = cont;
diff --git a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
index 81df956..fb6b539 100644
--- a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
+++ b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
@@ -40,16 +40,18 @@
   String get passName => 'Scalar replacement';
 
   final dart2js.InternalErrorFunction _internalError;
+  final World _classWorld;
 
   ScalarReplacer(dart2js.Compiler compiler)
-      : _internalError = compiler.internalError;
+      : _internalError = compiler.internalError,
+        _classWorld = compiler.world;
 
   @override
   void rewrite(FunctionDefinition root) {
     // Set all parent pointers.
     new ParentVisitor().visit(root);
     ScalarReplacementVisitor analyzer =
-        new ScalarReplacementVisitor(_internalError);
+        new ScalarReplacementVisitor(_internalError, _classWorld);
     analyzer.analyze(root);
     analyzer.process();
   }
@@ -62,13 +64,14 @@
 class ScalarReplacementVisitor extends RecursiveVisitor {
 
   final dart2js.InternalErrorFunction internalError;
+  final World classWorld;
   ScalarReplacementRemovalVisitor removalVisitor;
 
   Primitive _current = null;
   Set<Primitive> _allocations = new Set<Primitive>();
   Queue<Primitive> _queue = new Queue<Primitive>();
 
-  ScalarReplacementVisitor(this.internalError) {
+  ScalarReplacementVisitor(this.internalError, this.classWorld) {
     removalVisitor = new ScalarReplacementRemovalVisitor(this);
   }
 
@@ -130,6 +133,7 @@
     InteriorNode insertionPoint = allocation.parent;  // LetPrim
     for (FieldElement field in writes) {
       MutableVariable variable = new MutableVariable(field);
+      variable.type = new TypeMask.nonNullEmpty();
       cells[field] = variable;
       Primitive initialValue = fieldInitialValues[field];
       if (initialValue == null) {
@@ -153,6 +157,7 @@
         MutableVariable variable = cells[getField.field];
         if (variable != null) {
           GetMutable getter = new GetMutable(variable);
+          getter.type = getField.type;
           getter.variable.parent = getter;
           getter.substituteFor(getField);
           replacePrimitive(getField, getter);
@@ -166,6 +171,7 @@
         SetField setField = use;
         MutableVariable variable = cells[setField.field];
         Primitive value = setField.value.definition;
+        variable.type = variable.type.union(value.type, classWorld);
         SetMutable setter = new SetMutable(variable, value);
         setter.variable.parent = setter;
         setter.value.parent = setter;
diff --git a/pkg/compiler/lib/src/cps_ir/share_interceptors.dart b/pkg/compiler/lib/src/cps_ir/share_interceptors.dart
index 27afeb5..67aa417 100644
--- a/pkg/compiler/lib/src/cps_ir/share_interceptors.dart
+++ b/pkg/compiler/lib/src/cps_ir/share_interceptors.dart
@@ -6,9 +6,15 @@
 
 import 'cps_ir_nodes.dart';
 import 'optimizers.dart';
+import 'type_mask_system.dart';
+import '../elements/elements.dart';
 import '../constants/values.dart';
 
-/// Merges calls to `getInterceptor` when one call dominates the other.
+/// Merges calls to `getInterceptor` when one call is in scope of the other.
+///
+/// Also replaces `getInterceptor` calls with an interceptor constant when
+/// the result is known statically, and there is no interceptor already in
+/// scope.
 /// 
 /// Should run after [LoopInvariantCodeMotion] so interceptors lifted out from
 /// loops can be merged.
diff --git a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
new file mode 100644
index 0000000..e05db65
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
@@ -0,0 +1,336 @@
+// Copyright (c) 2015, 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.type_mask_system;
+
+import '../closure.dart' show ClosureClassElement, Identifiers;
+import '../common/names.dart' show Selectors, Identifiers;
+import '../compiler.dart' as dart2js show Compiler;
+import '../constants/constant_system.dart';
+import '../constants/values.dart';
+import '../dart_types.dart' as types;
+import '../elements/elements.dart';
+import '../io/source_information.dart' show SourceInformation;
+import '../js_backend/js_backend.dart' show JavaScriptBackend;
+import '../types/types.dart';
+import '../types/constants.dart' show computeTypeMask;
+import '../universe/universe.dart';
+import '../world.dart' show World;
+
+enum AbstractBool {
+  True, False, Maybe, Nothing
+}
+
+class TypeMaskSystem {
+  final TypesTask inferrer;
+  final World classWorld;
+  final JavaScriptBackend backend;
+
+  TypeMask get dynamicType => inferrer.dynamicType;
+  TypeMask get typeType => inferrer.typeType;
+  TypeMask get functionType => inferrer.functionType;
+  TypeMask get boolType => inferrer.boolType;
+  TypeMask get intType => inferrer.intType;
+  TypeMask get doubleType => inferrer.doubleType;
+  TypeMask get numType => inferrer.numType;
+  TypeMask get stringType => inferrer.stringType;
+  TypeMask get listType => inferrer.listType;
+  TypeMask get mapType => inferrer.mapType;
+  TypeMask get nonNullType => inferrer.nonNullType;
+  TypeMask get nullType => inferrer.nullType;
+  TypeMask get extendableNativeListType => backend.extendableArrayType;
+
+  TypeMask numStringBoolType;
+
+  ClassElement get jsNullClass => backend.jsNullClass;
+
+  // TODO(karlklose): remove compiler here.
+  TypeMaskSystem(dart2js.Compiler compiler)
+      : inferrer = compiler.typesTask,
+        classWorld = compiler.world,
+        backend = compiler.backend {
+
+    // Build the number+string+bool type. To make containment tests more
+    // inclusive, we use the num, String, bool types for this, not
+    // the JSNumber, JSString, JSBool subclasses.
+    TypeMask anyNum =
+        new TypeMask.nonNullSubtype(classWorld.numClass, classWorld);
+    TypeMask anyString =
+        new TypeMask.nonNullSubtype(classWorld.stringClass, classWorld);
+    TypeMask anyBool =
+        new TypeMask.nonNullSubtype(classWorld.boolClass, classWorld);
+    numStringBoolType =
+        new TypeMask.unionOf(<TypeMask>[anyNum, anyString, anyBool],
+            classWorld);
+  }
+
+  bool methodUsesReceiverArgument(FunctionElement function) {
+    assert(backend.isInterceptedMethod(function));
+    ClassElement clazz = function.enclosingClass.declaration;
+    return clazz.isSubclassOf(backend.jsInterceptorClass) ||
+           classWorld.isUsedAsMixin(clazz);
+  }
+
+  Element locateSingleElement(TypeMask mask, Selector selector) {
+    return mask.locateSingleElement(selector, mask, classWorld.compiler);
+  }
+
+  ClassElement singleClass(TypeMask mask) {
+    return mask.singleClass(classWorld);
+  }
+
+  bool needsNoSuchMethodHandling(TypeMask mask, Selector selector) {
+    return mask.needsNoSuchMethodHandling(selector, classWorld);
+  }
+
+  TypeMask getReceiverType(MethodElement method) {
+    assert(method.isInstanceMember);
+    if (classWorld.isUsedAsMixin(method.enclosingClass.declaration)) {
+      // If used as a mixin, the receiver could be any of the classes that mix
+      // in the class, and these are not considered subclasses.
+      // TODO(asgerf): Exclude the subtypes that only `implement` the class.
+      return nonNullSubtype(method.enclosingClass);
+    } else {
+      return nonNullSubclass(method.enclosingClass);
+    }
+  }
+
+  TypeMask getParameterType(ParameterElement parameter) {
+    return inferrer.getGuaranteedTypeOfElement(parameter);
+  }
+
+  TypeMask getReturnType(FunctionElement function) {
+    return inferrer.getGuaranteedReturnTypeOfElement(function);
+  }
+
+  TypeMask getInvokeReturnType(Selector selector, TypeMask mask) {
+    TypeMask result = inferrer.getGuaranteedTypeOfSelector(selector, mask);
+    // Tearing off .call from a function returns the function itself.
+    if (selector.isGetter &&
+        selector.name == Identifiers.call &&
+        !areDisjoint(functionType, mask)) {
+      result = join(result, functionType);
+    }
+    return result;
+  }
+
+  TypeMask getFieldType(FieldElement field) {
+    return inferrer.getGuaranteedTypeOfElement(field);
+  }
+
+  TypeMask join(TypeMask a, TypeMask b) {
+    return a.union(b, classWorld);
+  }
+
+  TypeMask getTypeOf(ConstantValue constant) {
+    return computeTypeMask(inferrer.compiler, constant);
+  }
+
+  TypeMask nonNullExact(ClassElement element) {
+    // The class world does not know about classes created by
+    // closure conversion, so just treat those as a subtypes of Function.
+    // TODO(asgerf): Maybe closure conversion should create a new ClassWorld?
+    if (element.isClosure) return functionType;
+    return new TypeMask.nonNullExact(element.declaration, classWorld);
+  }
+
+  TypeMask nonNullSubclass(ClassElement element) {
+    if (element.isClosure) return functionType;
+    return new TypeMask.nonNullSubclass(element.declaration, classWorld);
+  }
+
+  TypeMask nonNullSubtype(ClassElement element) {
+    if (element.isClosure) return functionType;
+    return new TypeMask.nonNullSubtype(element.declaration, classWorld);
+  }
+
+  bool isDefinitelyBool(TypeMask t, {bool allowNull: false}) {
+    if (!allowNull && t.isNullable) return false;
+    return t.nonNullable().containsOnlyBool(classWorld);
+  }
+
+  bool isDefinitelyNum(TypeMask t, {bool allowNull: false}) {
+    if (!allowNull && t.isNullable) return false;
+    return t.nonNullable().containsOnlyNum(classWorld);
+  }
+
+  bool isDefinitelyString(TypeMask t, {bool allowNull: false}) {
+    if (!allowNull && t.isNullable) return false;
+    return t.nonNullable().containsOnlyString(classWorld);
+  }
+
+  bool isDefinitelyNumStringBool(TypeMask t, {bool allowNull: false}) {
+    if (!allowNull && t.isNullable) return false;
+    return numStringBoolType.containsMask(t.nonNullable(), classWorld);
+  }
+
+  bool isDefinitelyNotNumStringBool(TypeMask t) {
+    return areDisjoint(t, numStringBoolType);
+  }
+
+  /// True if all values of [t] are either integers or not numbers at all.
+  ///
+  /// This does not imply that the value is an integer, since most other values
+  /// such as null are also not a non-integer double.
+  bool isDefinitelyNotNonIntegerDouble(TypeMask t) {
+    // Even though int is a subclass of double in the JS type system, we can
+    // still check this with disjointness, because [doubleType] is the *exact*
+    // double class, so this excludes things that are known to be instances of a
+    // more specific class.
+    // We currently exploit that there are no subclasses of double that are
+    // not integers (e.g. there is no UnsignedDouble class or whatever).
+    return areDisjoint(t, doubleType);
+  }
+
+  bool isDefinitelyInt(TypeMask t, {bool allowNull: false}) {
+    if (!allowNull && t.isNullable) return false;
+    return t.satisfies(backend.jsIntClass, classWorld);
+  }
+
+  bool isDefinitelyNativeList(TypeMask t, {bool allowNull: false}) {
+    if (!allowNull && t.isNullable) return false;
+    return t.nonNullable().satisfies(backend.jsArrayClass, classWorld);
+  }
+
+  bool isDefinitelyMutableNativeList(TypeMask t, {bool allowNull: false}) {
+    if (!allowNull && t.isNullable) return false;
+    return t.nonNullable().satisfies(backend.jsMutableArrayClass, classWorld);
+  }
+
+  bool isDefinitelyFixedNativeList(TypeMask t, {bool allowNull: false}) {
+    if (!allowNull && t.isNullable) return false;
+    return t.nonNullable().satisfies(backend.jsFixedArrayClass, classWorld);
+  }
+
+  bool isDefinitelyExtendableNativeList(TypeMask t, {bool allowNull: false}) {
+    if (!allowNull && t.isNullable) return false;
+    return t.nonNullable().satisfies(backend.jsExtendableArrayClass,
+                                     classWorld);
+  }
+
+  bool isDefinitelyIndexable(TypeMask t, {bool allowNull: false}) {
+    if (!allowNull && t.isNullable) return false;
+    return t.nonNullable().satisfies(backend.jsIndexableClass, classWorld);
+  }
+
+  bool areDisjoint(TypeMask leftType, TypeMask rightType) {
+    TypeMask intersection = leftType.intersection(rightType, classWorld);
+    return intersection.isEmpty && !intersection.isNullable;
+  }
+
+  AbstractBool isSubtypeOf(TypeMask value,
+                           types.DartType type,
+                           {bool allowNull}) {
+    assert(allowNull != null);
+    if (type is types.DynamicType) {
+      return AbstractBool.True;
+    }
+    if (type is types.InterfaceType) {
+      TypeMask typeAsMask = allowNull
+      ? new TypeMask.subtype(type.element, classWorld)
+      : new TypeMask.nonNullSubtype(type.element, classWorld);
+      if (areDisjoint(value, typeAsMask)) {
+        // Disprove the subtype relation based on the class alone.
+        return AbstractBool.False;
+      }
+      if (!type.treatAsRaw) {
+        // If there are type arguments, we cannot prove the subtype relation,
+        // because the type arguments are unknown on both the value and type.
+        return AbstractBool.Maybe;
+      }
+      if (typeAsMask.containsMask(value, classWorld)) {
+        // All possible values are contained in the set of allowed values.
+        // Note that we exploit the fact that [typeAsMask] is an exact
+        // representation of [type], not an approximation.
+        return AbstractBool.True;
+      }
+      // The value is neither contained in the type, nor disjoint from the type.
+      return AbstractBool.Maybe;
+    }
+    // TODO(asgerf): Support function types, and what else might be missing.
+    return AbstractBool.Maybe;
+  }
+
+  /// Returns whether [type] is one of the falsy values: false, 0, -0, NaN,
+  /// the empty string, or null.
+  AbstractBool boolify(TypeMask type) {
+    if (isDefinitelyNotNumStringBool(type) && !type.isNullable) {
+      return AbstractBool.True;
+    }
+    return AbstractBool.Maybe;
+  }
+
+  AbstractBool strictBoolify(TypeMask type) {
+    if (areDisjoint(type, boolType)) return AbstractBool.False;
+    return AbstractBool.Maybe;
+  }
+
+  /// Create a type mask containing at least all subtypes of [type].
+  TypeMask subtypesOf(types.DartType type) {
+    if (type is types.InterfaceType) {
+      ClassElement element = type.element;
+      if (element.isObject) {
+        return dynamicType;
+      }
+      if (element == classWorld.nullClass) {
+        return nullType;
+      }
+      if (element == classWorld.stringClass) {
+        return stringType;
+      }
+      if (element == classWorld.numClass ||
+          element == classWorld.doubleClass) {
+        return numType;
+      }
+      if (element == classWorld.intClass) {
+        return intType;
+      }
+      if (element == classWorld.boolClass) {
+        return boolType;
+      }
+      return new TypeMask.nonNullSubtype(element, classWorld);
+    }
+    if (type is types.FunctionType) {
+      return functionType;
+    }
+    return dynamicType;
+  }
+
+  /// Returns a subset of [mask] containing at least the types
+  /// that can respond to [selector] without throwing.
+  TypeMask receiverTypeFor(Selector selector, TypeMask mask) {
+    return classWorld.allFunctions.receiverType(selector, mask);
+  }
+
+  /// The result of an index operation on something of [type], or the dynamic
+  /// type if unknown.
+  TypeMask elementTypeOfIndexable(TypeMask type) {
+    if (type is UnionTypeMask) {
+      return new TypeMask.unionOf(
+          type.disjointMasks.map(elementTypeOfIndexable), classWorld);
+    }
+    if (type is ContainerTypeMask) {
+      return type.elementType;
+    }
+    if (isDefinitelyString(type)) {
+      return stringType;
+    }
+    if (type.satisfies(backend.typedArrayClass, classWorld)) {
+      if (type.satisfies(backend.typedArrayOfIntClass, classWorld)) {
+        return intType;
+      }
+      return numType;
+    }
+    return dynamicType;
+  }
+
+  /// The length of something of [type], or `null` if unknown.
+  int getContainerLength(TypeMask type) {
+    if (type is ContainerTypeMask) {
+      return type.length;
+    } else {
+      return null;
+    }
+  }
+}
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index 5ef491b..631aaf2 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -30,248 +30,7 @@
 import '../world.dart' show World;
 import 'cps_fragment.dart';
 import 'cps_ir_nodes.dart';
-import 'cps_ir_nodes_sexpr.dart' show SExpressionStringifier;
-
-enum AbstractBool {
-  True, False, Maybe, Nothing
-}
-
-class TypeMaskSystem {
-  final TypesTask inferrer;
-  final World classWorld;
-  final JavaScriptBackend backend;
-
-  TypeMask get dynamicType => inferrer.dynamicType;
-  TypeMask get typeType => inferrer.typeType;
-  TypeMask get functionType => inferrer.functionType;
-  TypeMask get boolType => inferrer.boolType;
-  TypeMask get intType => inferrer.intType;
-  TypeMask get doubleType => inferrer.doubleType;
-  TypeMask get numType => inferrer.numType;
-  TypeMask get stringType => inferrer.stringType;
-  TypeMask get listType => inferrer.listType;
-  TypeMask get mapType => inferrer.mapType;
-  TypeMask get nonNullType => inferrer.nonNullType;
-  TypeMask get extendableNativeListType => backend.extendableArrayType;
-
-  TypeMask numStringBoolType;
-
-  ClassElement get jsNullClass => backend.jsNullClass;
-
-  // TODO(karlklose): remove compiler here.
-  TypeMaskSystem(dart2js.Compiler compiler)
-    : inferrer = compiler.typesTask,
-      classWorld = compiler.world,
-      backend = compiler.backend {
-
-    // Build the number+string+bool type. To make containment tests more
-    // inclusive, we use the num, String, bool types for this, not
-    // the JSNumber, JSString, JSBool subclasses.
-    TypeMask anyNum =
-        new TypeMask.nonNullSubtype(classWorld.numClass, classWorld);
-    TypeMask anyString =
-        new TypeMask.nonNullSubtype(classWorld.stringClass, classWorld);
-    TypeMask anyBool =
-        new TypeMask.nonNullSubtype(classWorld.boolClass, classWorld);
-    numStringBoolType =
-      new TypeMask.unionOf(<TypeMask>[anyNum, anyString, anyBool],
-                           classWorld);
-  }
-
-  bool methodUsesReceiverArgument(FunctionElement function) {
-    assert(backend.isInterceptedMethod(function));
-    ClassElement clazz = function.enclosingClass.declaration;
-    return clazz.isSubclassOf(backend.jsInterceptorClass) ||
-           classWorld.isUsedAsMixin(clazz);
-  }
-
-  Element locateSingleElement(TypeMask mask, Selector selector) {
-    return mask.locateSingleElement(selector, mask, classWorld.compiler);
-  }
-
-  ClassElement singleClass(TypeMask mask) {
-    return mask.singleClass(classWorld);
-  }
-
-  bool needsNoSuchMethodHandling(TypeMask mask, Selector selector) {
-    return mask.needsNoSuchMethodHandling(selector, classWorld);
-  }
-
-  TypeMask getReceiverType(MethodElement method) {
-    assert(method.isInstanceMember);
-    if (classWorld.isUsedAsMixin(method.enclosingClass.declaration)) {
-      // If used as a mixin, the receiver could be any of the classes that mix
-      // in the class, and these are not considered subclasses.
-      // TODO(asgerf): Exclude the subtypes that only `implement` the class.
-      return nonNullSubtype(method.enclosingClass);
-    } else {
-      return nonNullSubclass(method.enclosingClass);
-    }
-  }
-
-  TypeMask getParameterType(ParameterElement parameter) {
-    return inferrer.getGuaranteedTypeOfElement(parameter);
-  }
-
-  TypeMask getReturnType(FunctionElement function) {
-    return inferrer.getGuaranteedReturnTypeOfElement(function);
-  }
-
-  TypeMask getInvokeReturnType(Selector selector, TypeMask mask) {
-    return inferrer.getGuaranteedTypeOfSelector(selector, mask);
-  }
-
-  TypeMask getFieldType(FieldElement field) {
-    return inferrer.getGuaranteedTypeOfElement(field);
-  }
-
-  TypeMask join(TypeMask a, TypeMask b) {
-    return a.union(b, classWorld);
-  }
-
-  TypeMask getTypeOf(ConstantValue constant) {
-    return computeTypeMask(inferrer.compiler, constant);
-  }
-
-  TypeMask nonNullExact(ClassElement element) {
-    // The class world does not know about classes created by
-    // closure conversion, so just treat those as a subtypes of Function.
-    // TODO(asgerf): Maybe closure conversion should create a new ClassWorld?
-    if (element.isClosure) return functionType;
-    return new TypeMask.nonNullExact(element.declaration, classWorld);
-  }
-
-  TypeMask nonNullSubclass(ClassElement element) {
-    if (element.isClosure) return functionType;
-    return new TypeMask.nonNullSubclass(element.declaration, classWorld);
-  }
-
-  TypeMask nonNullSubtype(ClassElement element) {
-    if (element.isClosure) return functionType;
-    return new TypeMask.nonNullSubtype(element.declaration, classWorld);
-  }
-
-  bool isDefinitelyBool(TypeMask t, {bool allowNull: false}) {
-    if (!allowNull && t.isNullable) return false;
-    return t.nonNullable().containsOnlyBool(classWorld);
-  }
-
-  bool isDefinitelyNum(TypeMask t, {bool allowNull: false}) {
-    if (!allowNull && t.isNullable) return false;
-    return t.nonNullable().containsOnlyNum(classWorld);
-  }
-
-  bool isDefinitelyString(TypeMask t, {bool allowNull: false}) {
-    if (!allowNull && t.isNullable) return false;
-    return t.nonNullable().containsOnlyString(classWorld);
-  }
-
-  bool isDefinitelyNumStringBool(TypeMask t, {bool allowNull: false}) {
-    if (!allowNull && t.isNullable) return false;
-    return numStringBoolType.containsMask(t.nonNullable(), classWorld);
-  }
-
-  bool isDefinitelyNotNumStringBool(TypeMask t) {
-    return areDisjoint(t, numStringBoolType);
-  }
-
-  /// True if all values of [t] are either integers or not numbers at all.
-  ///
-  /// This does not imply that the value is an integer, since most other values
-  /// such as null are also not a non-integer double.
-  bool isDefinitelyNotNonIntegerDouble(TypeMask t) {
-    // Even though int is a subclass of double in the JS type system, we can
-    // still check this with disjointness, because [doubleType] is the *exact*
-    // double class, so this excludes things that are known to be instances of a
-    // more specific class.
-    // We currently exploit that there are no subclasses of double that are
-    // not integers (e.g. there is no UnsignedDouble class or whatever).
-    return areDisjoint(t, doubleType);
-  }
-
-  bool isDefinitelyInt(TypeMask t, {bool allowNull: false}) {
-    if (!allowNull && t.isNullable) return false;
-    return t.satisfies(backend.jsIntClass, classWorld);
-  }
-
-  bool isDefinitelyNativeList(TypeMask t, {bool allowNull: false}) {
-    if (!allowNull && t.isNullable) return false;
-    return t.nonNullable().satisfies(backend.jsArrayClass, classWorld);
-  }
-
-  bool isDefinitelyMutableNativeList(TypeMask t, {bool allowNull: false}) {
-    if (!allowNull && t.isNullable) return false;
-    return t.nonNullable().satisfies(backend.jsMutableArrayClass, classWorld);
-  }
-
-  bool isDefinitelyFixedNativeList(TypeMask t, {bool allowNull: false}) {
-    if (!allowNull && t.isNullable) return false;
-    return t.nonNullable().satisfies(backend.jsFixedArrayClass, classWorld);
-  }
-
-  bool isDefinitelyExtendableNativeList(TypeMask t, {bool allowNull: false}) {
-    if (!allowNull && t.isNullable) return false;
-    return t.nonNullable().satisfies(backend.jsExtendableArrayClass,
-        classWorld);
-  }
-
-  bool isDefinitelyIndexable(TypeMask t, {bool allowNull: false}) {
-    if (!allowNull && t.isNullable) return false;
-    return t.nonNullable().satisfies(backend.jsIndexableClass, classWorld);
-  }
-
-  bool areDisjoint(TypeMask leftType, TypeMask rightType) {
-    TypeMask intersection = leftType.intersection(rightType, classWorld);
-    return intersection.isEmpty && !intersection.isNullable;
-  }
-
-  AbstractBool isSubtypeOf(TypeMask value,
-                           types.DartType type,
-                           {bool allowNull}) {
-    assert(allowNull != null);
-    if (type is types.DynamicType) {
-      return AbstractBool.True;
-    }
-    if (type is types.InterfaceType) {
-      TypeMask typeAsMask = allowNull
-          ? new TypeMask.subtype(type.element, classWorld)
-          : new TypeMask.nonNullSubtype(type.element, classWorld);
-      if (areDisjoint(value, typeAsMask)) {
-        // Disprove the subtype relation based on the class alone.
-        return AbstractBool.False;
-      }
-      if (!type.treatAsRaw) {
-        // If there are type arguments, we cannot prove the subtype relation,
-        // because the type arguments are unknown on both the value and type.
-        return AbstractBool.Maybe;
-      }
-      if (typeAsMask.containsMask(value, classWorld)) {
-        // All possible values are contained in the set of allowed values.
-        // Note that we exploit the fact that [typeAsMask] is an exact
-        // representation of [type], not an approximation.
-        return AbstractBool.True;
-      }
-      // The value is neither contained in the type, nor disjoint from the type.
-      return AbstractBool.Maybe;
-    }
-    // TODO(asgerf): Support function types, and what else might be missing.
-    return AbstractBool.Maybe;
-  }
-
-  /// Returns whether [type] is one of the falsy values: false, 0, -0, NaN,
-  /// the empty string, or null.
-  AbstractBool boolify(TypeMask type) {
-    if (isDefinitelyNotNumStringBool(type) && !type.isNullable) {
-      return AbstractBool.True;
-    }
-    return AbstractBool.Maybe;
-  }
-
-  AbstractBool strictBoolify(TypeMask type) {
-    if (areDisjoint(type, boolType)) return AbstractBool.False;
-    return AbstractBool.Maybe;
-  }
-}
+import 'type_mask_system.dart';
 
 class ConstantPropagationLattice {
   final TypeMaskSystem typeSystem;
@@ -575,17 +334,19 @@
 
   final dart2js.Compiler _compiler;
   final CpsFunctionCompiler _functionCompiler;
-  // The constant system is used for evaluation of expressions with constant
-  // arguments.
   final ConstantPropagationLattice _lattice;
   final dart2js.InternalErrorFunction _internalError;
-  final Map<Definition, AbstractValue> _values = <Definition, AbstractValue>{};
+  final Map<Variable, ConstantValue> _values = <Variable, ConstantValue>{};
+  final TypeMaskSystem _typeSystem;
 
-  TypePropagator(dart2js.Compiler compiler, this._functionCompiler)
+  TypePropagator(dart2js.Compiler compiler,
+                 TypeMaskSystem typeSystem,
+                 this._functionCompiler)
       : _compiler = compiler,
         _internalError = compiler.internalError,
+        _typeSystem = typeSystem,
         _lattice = new ConstantPropagationLattice(
-            new TypeMaskSystem(compiler),
+            typeSystem,
             compiler.backend.constantSystem,
             compiler.types);
 
@@ -650,7 +411,7 @@
   JavaScriptBackend get backend => compiler.backend;
   TypeMaskSystem get typeSystem => lattice.typeSystem;
   types.DartTypes get dartTypes => lattice.dartTypes;
-  Map<Node, AbstractValue> get values => analyzer.values;
+  Map<Variable, ConstantValue> get values => analyzer.values;
 
   final dart2js.InternalErrorFunction internalError;
 
@@ -734,6 +495,9 @@
 
   void visitContinuation(Continuation node) {
     if (node.isReturnContinuation) return;
+    if (!analyzer.reachableContinuations.contains(node)) {
+      replaceSubtree(node.body, new Unreachable());
+    }
     // Process the continuation body.
     // Note that the continuation body may have changed since the continuation
     // was put on the stack (e.g. [visitInvokeContinuation] may do this).
@@ -809,8 +573,8 @@
   /// Make a constant primitive for [constant] and set its entry in [values].
   Constant makeConstantPrimitive(ConstantValue constant) {
     Constant primitive = new Constant(constant);
-    values[primitive] = new AbstractValue.constantValue(constant,
-        typeSystem.getTypeOf(constant));
+    primitive.type = typeSystem.getTypeOf(constant);
+    values[primitive] = constant;
     return primitive;
   }
 
@@ -960,10 +724,8 @@
     }
 
     if (node.selector.isOperator && node.arguments.length == 2) {
-      // The operators we specialize are are intercepted calls, so the operands
-      // are in the argument list.
-      Primitive leftArg = node.arguments[0].definition;
-      Primitive rightArg = node.arguments[1].definition;
+      Primitive leftArg = getDartReceiver(node);
+      Primitive rightArg = getDartArgument(node, 0);
       AbstractValue left = getValue(leftArg);
       AbstractValue right = getValue(rightArg);
 
@@ -1035,7 +797,7 @@
   }
 
   Primitive getDartReceiver(InvokeMethod node) {
-    if (isInterceptedSelector(node.selector)) {
+    if (node.receiverIsIntercepted) {
       return node.arguments[0].definition;
     } else {
       return node.receiver.definition;
@@ -1230,6 +992,14 @@
         }
         if (!isExtendable) return false;
         CpsFragment cps = new CpsFragment(sourceInfo);
+        Primitive length = cps.letPrim(new GetLength(list));
+        Primitive isEmpty = cps.applyBuiltin(
+            BuiltinOperator.StrictEq,
+            [length, cps.makeZero()]);
+        CpsFragment fail = cps.ifTruthy(isEmpty);
+        fail.invokeStaticThrower(
+            backend.getThrowIndexOutOfBoundsError(),
+            [list, fail.makeConstant(new IntConstantValue(-1))]);
         Primitive removedItem = cps.invokeBuiltin(BuiltinMethod.Pop,
             list,
             <Primitive>[],
@@ -1708,7 +1478,7 @@
     AbstractValue receiver = getValue(node.receiver.definition);
     node.receiverIsNotNull = receiver.isDefinitelyNotNull;
 
-    if (isInterceptedSelector(node.selector) &&
+    if (node.receiverIsIntercepted &&
         node.receiver.definition.sameValue(node.arguments[0].definition)) {
       // The receiver and first argument are the same; that means we already
       // determined in visitInterceptor that we are targeting a non-interceptor.
@@ -1731,6 +1501,7 @@
         insertLetPrim(node, dummy);
         node.arguments[0].unlink();
         node.arguments[0] = new Reference<Primitive>(dummy);
+        node.receiverIsIntercepted = false;
       }
     }
   }
@@ -1739,7 +1510,7 @@
     Continuation cont = node.continuation.definition;
 
     AbstractValue value = getValue(node.value.definition);
-    switch (lattice.isSubtypeOf(value, node.type, allowNull: true)) {
+    switch (lattice.isSubtypeOf(value, node.dartType, allowNull: true)) {
       case AbstractBool.Maybe:
       case AbstractBool.Nothing:
         break;
@@ -1892,9 +1663,15 @@
     if (inlineInvokeStatic(node)) return;
   }
 
-  AbstractValue getValue(Primitive primitive) {
-    AbstractValue value = values[primitive];
-    return value == null ? new AbstractValue.nothing() : value;
+  AbstractValue getValue(Variable node) {
+    ConstantValue constant = values[node];
+    if (constant != null) {
+      return new AbstractValue.constantValue(constant, node.type);
+    }
+    if (node.type != null) {
+      return new AbstractValue.nonConstant(node.type);
+    }
+    return lattice.nothing;
   }
 
 
@@ -2024,7 +1801,7 @@
   Primitive visitTypeTest(TypeTest node) {
     Primitive prim = node.value.definition;
     AbstractValue value = getValue(prim);
-    if (node.type == dartTypes.coreTypes.intType) {
+    if (node.dartType == dartTypes.coreTypes.intType) {
       // Compile as typeof x === 'number' && Math.floor(x) === x
       if (lattice.isDefinitelyNum(value, allowNull: true)) {
         // If value is null or a number, we can skip the typeof test.
@@ -2046,8 +1823,8 @@
           <Primitive>[prim, prim, prim],
           node.sourceInformation);
     }
-    if (node.type == dartTypes.coreTypes.numType ||
-        node.type == dartTypes.coreTypes.doubleType) {
+    if (node.dartType == dartTypes.coreTypes.numType ||
+        node.dartType == dartTypes.coreTypes.doubleType) {
       return new ApplyBuiltinOperator(
           BuiltinOperator.IsNumber,
           <Primitive>[prim],
@@ -2141,7 +1918,7 @@
 
   // Stores the current lattice value for primitives and mutable variables.
   // Access through [getValue] and [setValue].
-  final Map<Definition, AbstractValue> values;
+  final Map<Variable, ConstantValue> values;
 
   /// Expressions that invoke their call continuation with a constant value
   /// and without any side effects. These can be replaced by the constant.
@@ -2205,17 +1982,24 @@
   /// Returns the lattice value corresponding to [node], defaulting to nothing.
   ///
   /// Never returns null.
-  AbstractValue getValue(Definition node) {
-    AbstractValue value = values[node];
-    return (value == null) ? nothing : value;
+  AbstractValue getValue(Variable node) {
+    ConstantValue constant = values[node];
+    if (constant != null) {
+      return new AbstractValue.constantValue(constant, node.type);
+    }
+    if (node.type != null) {
+      return new AbstractValue.nonConstant(node.type);
+    }
+    return lattice.nothing;
   }
 
   /// Joins the passed lattice [updateValue] to the current value of [node],
   /// and adds it to the definition work set if it has changed and [node] is
   /// a definition.
-  void setValue(Definition node, AbstractValue updateValue) {
+  void setValue(Variable node, AbstractValue updateValue) {
     AbstractValue oldValue = getValue(node);
     AbstractValue newValue = lattice.join(oldValue, updateValue);
+    node.type = newValue.type; // Ensure type is initialized even if bottom.
     if (oldValue == newValue) {
       return;
     }
@@ -2223,10 +2007,48 @@
     // Values may only move in the direction NOTHING -> CONSTANT -> NONCONST.
     assert(newValue.kind >= oldValue.kind);
 
-    values[node] = newValue;
+    values[node] = newValue.isConstant ? newValue.constant : null;
     defWorklist.add(node);
   }
 
+  /// Updates the value of a [CallExpression]'s continuation parameter.
+  void setResult(CallExpression call,
+                 AbstractValue updateValue,
+                 {bool canReplace: false}) {
+    Continuation cont = call.continuation.definition;
+    setValue(cont.parameters.single, updateValue);
+    if (!updateValue.isNothing) {
+      setReachable(cont);
+
+      if (updateValue.isConstant && canReplace) {
+        replacements[call] = updateValue.constant;
+      } else {
+        // A replacement might have been set in a previous iteration.
+        replacements.remove(call);
+      }
+    }
+  }
+
+  bool isInterceptedSelector(Selector selector) {
+    return backend.isInterceptedSelector(selector);
+  }
+
+  Primitive getDartReceiver(InvokeMethod node) {
+    if (node.receiverIsIntercepted) {
+      return node.arguments[0].definition;
+    } else {
+      return node.receiver.definition;
+    }
+  }
+
+  Primitive getDartArgument(InvokeMethod node, int n) {
+    if (isInterceptedSelector(node.selector)) {
+      return node.arguments[n+1].definition;
+    } else {
+      return node.arguments[n].definition;
+    }
+  }
+
   // -------------------------- Visitor overrides ------------------------------
   void visit(Node node) { node.accept(this); }
 
@@ -2289,35 +2111,17 @@
   }
 
   void visitInvokeStatic(InvokeStatic node) {
-    Continuation cont = node.continuation.definition;
-    setReachable(cont);
-
-    assert(cont.parameters.length == 1);
-    Parameter returnValue = cont.parameters[0];
-
-    /// Sets the value of the target continuation parameter, and possibly
-    /// try to replace the whole invocation with a constant.
-    void setResult(AbstractValue updateValue, {bool canReplace: false}) {
-      setValue(returnValue, updateValue);
-      if (canReplace && updateValue.isConstant) {
-        replacements[node] = updateValue.constant;
-      } else {
-        // A previous iteration might have tried to replace this.
-        replacements.remove(node);
-      }
-    }
-
     if (node.target.library.isInternalLibrary) {
       switch (node.target.name) {
         case InternalMethod.Stringify:
           AbstractValue argValue = getValue(node.arguments[0].definition);
-          setResult(lattice.stringify(argValue), canReplace: true);
+          setResult(node, lattice.stringify(argValue), canReplace: true);
           return;
       }
     }
 
     TypeMask returnType = typeSystem.getReturnType(node.target);
-    setResult(nonConstant(returnType));
+    setResult(node, nonConstant(returnType));
   }
 
   void visitInvokeContinuation(InvokeContinuation node) {
@@ -2327,45 +2131,28 @@
     // Forward the constant status of all continuation invokes to the
     // continuation. Note that this is effectively a phi node in SSA terms.
     for (int i = 0; i < node.arguments.length; i++) {
-      Definition def = node.arguments[i].definition;
+      Primitive def = node.arguments[i].definition;
       AbstractValue cell = getValue(def);
       setValue(cont.parameters[i], cell);
     }
   }
 
   void visitInvokeMethod(InvokeMethod node) {
-    Continuation cont = node.continuation.definition;
-    setReachable(cont);
-
-    /// Sets the value of the target continuation parameter, and possibly
-    /// try to replace the whole invocation with a constant.
-    void setResult(AbstractValue updateValue, {bool canReplace: false}) {
-      Parameter returnValue = cont.parameters[0];
-      setValue(returnValue, updateValue);
-      if (canReplace && updateValue.isConstant) {
-        replacements[node] = updateValue.constant;
-      } else {
-        // A previous iteration might have tried to replace this.
-        replacements.remove(node);
-      }
-    }
-
     AbstractValue receiver = getValue(node.receiver.definition);
     if (receiver.isNothing) {
       return;  // And come back later.
     }
     if (!node.selector.isOperator) {
       // TODO(jgruber): Handle known methods on constants such as String.length.
-      setResult(lattice.getInvokeReturnType(node.selector, node.mask));
+      setResult(node, lattice.getInvokeReturnType(node.selector, node.mask));
       return;
     }
 
     // Calculate the resulting constant if possible.
-    // Operators are intercepted, so the operands are in the argument list.
     AbstractValue result;
     String opname = node.selector.name;
     if (node.arguments.length == 1) {
-      AbstractValue argument = getValue(node.arguments[0].definition);
+      AbstractValue argument = getValue(getDartReceiver(node));
       // Unary operator.
       if (opname == "unary-") {
         opname = "-";
@@ -2374,8 +2161,8 @@
       result = lattice.unaryOp(operator, argument);
     } else if (node.arguments.length == 2) {
       // Binary operator.
-      AbstractValue left = getValue(node.arguments[0].definition);
-      AbstractValue right = getValue(node.arguments[1].definition);
+      AbstractValue left = getValue(getDartReceiver(node));
+      AbstractValue right = getValue(getDartArgument(node, 0));
       BinaryOperator operator = BinaryOperator.parse(opname);
       result = lattice.binaryOp(operator, left, right);
     }
@@ -2383,9 +2170,9 @@
     // Update value of the continuation parameter. Again, this is effectively
     // a phi.
     if (result == null) {
-      setResult(lattice.getInvokeReturnType(node.selector, node.mask));
+      setResult(node, lattice.getInvokeReturnType(node.selector, node.mask));
     } else {
-      setResult(result, canReplace: true);
+      setResult(node, result, canReplace: true);
     }
   }
 
@@ -2481,27 +2268,22 @@
   }
 
   void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
-    // TODO(asgerf): For pop(), use the container type from the TypeMask.
-    setValue(node, nonConstant());
+    AbstractValue receiver = getValue(node.receiver.definition);
+    if (node.method == BuiltinMethod.Pop) {
+      setValue(node, nonConstant(
+          typeSystem.elementTypeOfIndexable(receiver.type)));
+    } else {
+      setValue(node, nonConstant());
+    }
   }
 
   void visitInvokeMethodDirectly(InvokeMethodDirectly node) {
-    Continuation cont = node.continuation.definition;
-    setReachable(cont);
-
-    assert(cont.parameters.length == 1);
-    Parameter returnValue = cont.parameters[0];
     // TODO(karlklose): lookup the function and get ites return type.
-    setValue(returnValue, nonConstant());
+    setResult(node, nonConstant());
   }
 
   void visitInvokeConstructor(InvokeConstructor node) {
-    Continuation cont = node.continuation.definition;
-    setReachable(cont);
-
-    assert(cont.parameters.length == 1);
-    Parameter returnValue = cont.parameters[0];
-    setValue(returnValue, nonConstant(typeSystem.getReturnType(node.target)));
+    setResult(node, nonConstant(typeSystem.getReturnType(node.target)));
   }
 
   void visitThrow(Throw node) {
@@ -2537,7 +2319,7 @@
   void visitTypeTest(TypeTest node) {
     AbstractValue input = getValue(node.value.definition);
     TypeMask boolType = typeSystem.boolType;
-    switch(lattice.isSubtypeOf(input, node.type, allowNull: false)) {
+    switch(lattice.isSubtypeOf(input, node.dartType, allowNull: false)) {
       case AbstractBool.Nothing:
         break; // And come back later.
 
@@ -2558,7 +2340,7 @@
   void visitTypeCast(TypeCast node) {
     Continuation cont = node.continuation.definition;
     AbstractValue input = getValue(node.value.definition);
-    switch (lattice.isSubtypeOf(input, node.type, allowNull: true)) {
+    switch (lattice.isSubtypeOf(input, node.dartType, allowNull: true)) {
       case AbstractBool.Nothing:
         break; // And come back later.
 
@@ -2572,13 +2354,10 @@
 
       case AbstractBool.Maybe:
         setReachable(cont);
-        TypeMask type = input.type;
-        if (node.type.element is ClassElement) {
-          // Narrow type of output to those that survive the cast.
-          type = type.intersection(
-              new TypeMask.subtype(node.type.element, classWorld),
-              classWorld);
-        }
+        // Narrow type of output to those that survive the cast.
+        TypeMask type = input.type.intersection(
+            typeSystem.subtypesOf(node.dartType),
+            classWorld);
         setValue(cont.parameters.single, nonConstant(type));
         break;
     }
@@ -2643,12 +2422,7 @@
   void visitSetStatic(SetStatic node) {}
 
   void visitGetLazyStatic(GetLazyStatic node) {
-    Continuation cont = node.continuation.definition;
-    setReachable(cont);
-
-    assert(cont.parameters.length == 1);
-    Parameter returnValue = cont.parameters[0];
-    setValue(returnValue, nonConstant(typeSystem.getFieldType(node.element)));
+    setResult(node, nonConstant(typeSystem.getFieldType(node.element)));
   }
 
   void visitInterceptor(Interceptor node) {
@@ -2707,23 +2481,27 @@
   @override
   void visitForeignCode(ForeignCode node) {
     if (node.continuation != null) {
-      Continuation continuation = node.continuation.definition;
-      setReachable(continuation);
-
-      assert(continuation.parameters.length == 1);
-      Parameter returnValue = continuation.parameters.first;
-      setValue(returnValue, nonConstant(node.type));
+      setResult(node, nonConstant(node.type));
     }
   }
 
   @override
   void visitGetLength(GetLength node) {
-    setValue(node, nonConstant(typeSystem.intType));
+    AbstractValue input = getValue(node.object.definition);
+    int length = typeSystem.getContainerLength(input.type);
+    if (length != null) {
+      // TODO(asgerf): Constant-folding the length might degrade the VM's
+      // own bounds-check elimination?
+      setValue(node, constantValue(new IntConstantValue(length)));
+    } else {
+      setValue(node, nonConstant(typeSystem.intType));
+    }
   }
 
   @override
   void visitGetIndex(GetIndex node) {
-    setValue(node, nonConstant());
+    AbstractValue input = getValue(node.object.definition);
+    setValue(node, nonConstant(typeSystem.elementTypeOfIndexable(input.type)));
   }
 
   @override
@@ -2740,13 +2518,14 @@
   @override
   void visitRefinement(Refinement node) {
     AbstractValue value = getValue(node.value.definition);
-    if (value.isNothing || typeSystem.areDisjoint(value.type, node.type)) {
+    if (value.isNothing ||
+        typeSystem.areDisjoint(value.type, node.refineType)) {
       setValue(node, nothing);
     } else if (value.isConstant) {
       setValue(node, value);
     } else {
       setValue(node,
-          nonConstant(value.type.intersection(node.type, classWorld)));
+          nonConstant(value.type.intersection(node.refineType, classWorld)));
     }
   }
 }
@@ -2850,7 +2629,7 @@
 
 class ResetAnalysisInfo extends RecursiveVisitor {
   Set<Continuation> reachableContinuations;
-  Map<Definition, AbstractValue> values;
+  Map<Variable, ConstantValue> values;
 
   ResetAnalysisInfo(this.reachableContinuations, this.values);
 
@@ -2860,10 +2639,12 @@
   }
 
   processLetPrim(LetPrim node) {
-    values.remove(node.primitive);
+    node.primitive.type = null;
+    values[node.primitive] = null;
   }
 
   processLetMutable(LetMutable node) {
-    values.remove(node.variable);
+    node.variable.type = null;
+    values[node.variable] = null;
   }
 }
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index a2f98b7..31c62c7 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -12,6 +12,7 @@
          stdin, stderr;
 
 import '../compiler.dart' as api;
+import 'commandline_options.dart';
 import 'io/source_file.dart';
 import 'source_file_provider.dart';
 import 'filenames.dart';
@@ -286,10 +287,10 @@
           wantHelp = true;
           break;
         case 'c':
-          setCheckedMode('--enable-checked-mode');
+          setCheckedMode(Flags.enableCheckedMode);
           break;
         case 'm':
-          implyCompilation('--minify');
+          implyCompilation(Flags.minify);
           break;
         default:
           throw 'Internal error: "$shortOption" did not match';
@@ -301,60 +302,60 @@
   List<OptionHandler> handlers = <OptionHandler>[
     new OptionHandler('-[chvm?]+', handleShortOptions),
     new OptionHandler('--throw-on-error(?:=[0-9]+)?', handleThrowOnError),
-    new OptionHandler('--suppress-warnings', (_) {
+    new OptionHandler(Flags.suppressWarnings, (_) {
       diagnosticHandler.showWarnings = false;
-      passThrough('--suppress-warnings');
+      passThrough(Flags.suppressWarnings);
     }),
-    new OptionHandler('--fatal-warnings', passThrough),
-    new OptionHandler('--suppress-hints',
+    new OptionHandler(Flags.fatalWarnings, passThrough),
+    new OptionHandler(Flags.suppressHints,
                       (_) => diagnosticHandler.showHints = false),
     new OptionHandler(
         '--output-type=dart|--output-type=dart-multi|--output-type=js',
         setOutputType),
-    new OptionHandler('--use-cps-ir', passThrough),
-    new OptionHandler('--no-frequency-based-minification', passThrough),
-    new OptionHandler('--verbose', setVerbose),
-    new OptionHandler('--version', (_) => wantVersion = true),
+    new OptionHandler(Flags.useCpsIr, passThrough),
+    new OptionHandler(Flags.noFrequencyBasedMinification, passThrough),
+    new OptionHandler(Flags.verbose, setVerbose),
+    new OptionHandler(Flags.version, (_) => wantVersion = true),
     new OptionHandler('--library-root=.+', setLibraryRoot),
     new OptionHandler('--out=.+|-o.*', setOutput, multipleArguments: true),
-    new OptionHandler('--allow-mock-compilation', passThrough),
-    new OptionHandler('--fast-startup', passThrough),
-    new OptionHandler('--minify|-m', implyCompilation),
-    new OptionHandler('--preserve-uris', passThrough),
+    new OptionHandler(Flags.allowMockCompilation, passThrough),
+    new OptionHandler(Flags.fastStartup, passThrough),
+    new OptionHandler('${Flags.minify}|-m', implyCompilation),
+    new OptionHandler(Flags.preserveUris, passThrough),
     new OptionHandler('--force-strip=.*', setStrip),
-    new OptionHandler('--disable-diagnostic-colors',
+    new OptionHandler(Flags.disableDiagnosticColors,
                       (_) => diagnosticHandler.enableColors = false),
-    new OptionHandler('--enable-diagnostic-colors',
+    new OptionHandler(Flags.enableDiagnosticColors,
                       (_) => diagnosticHandler.enableColors = true),
     new OptionHandler('--enable[_-]checked[_-]mode|--checked',
-                      (_) => setCheckedMode('--enable-checked-mode')),
-    new OptionHandler('--enable-concrete-type-inference',
+                      (_) => setCheckedMode(Flags.enableCheckedMode)),
+    new OptionHandler(Flags.enableConcreteTypeInference,
                       (_) => implyCompilation(
-                          '--enable-concrete-type-inference')),
-    new OptionHandler('--trust-type-annotations',
+                          Flags.enableConcreteTypeInference)),
+    new OptionHandler(Flags.trustTypeAnnotations,
                       (_) => setTrustTypeAnnotations(
-                          '--trust-type-annotations')),
-    new OptionHandler('--trust-primitives',
+                          Flags.trustTypeAnnotations)),
+    new OptionHandler(Flags.trustPrimitives,
                       (_) => setTrustPrimitives(
-                          '--trust-primitives')),
+                          Flags.trustPrimitives)),
     new OptionHandler(r'--help|/\?|/h', (_) => wantHelp = true),
     new OptionHandler('--packages=.+', setPackageConfig),
     new OptionHandler('--package-root=.+|-p.+', setPackageRoot),
-    new OptionHandler('--analyze-all', setAnalyzeAll),
-    new OptionHandler('--analyze-only', setAnalyzeOnly),
-    new OptionHandler('--no-source-maps', passThrough),
-    new OptionHandler('--analyze-signatures-only', setAnalyzeOnly),
-    new OptionHandler('--disable-native-live-type-analysis', passThrough),
+    new OptionHandler(Flags.analyzeAll, setAnalyzeAll),
+    new OptionHandler(Flags.analyzeOnly, setAnalyzeOnly),
+    new OptionHandler(Flags.noSourceMaps, passThrough),
+    new OptionHandler(Flags.analyzeSignaturesOnly, setAnalyzeOnly),
+    new OptionHandler(Flags.disableNativeLiveTypeAnalysis, passThrough),
     new OptionHandler('--categories=.*', setCategories),
-    new OptionHandler('--disable-type-inference', implyCompilation),
-    new OptionHandler('--terse', passThrough),
+    new OptionHandler(Flags.disableTypeInference, implyCompilation),
+    new OptionHandler(Flags.terse, passThrough),
     new OptionHandler('--deferred-map=.+', implyCompilation),
-    new OptionHandler('--dump-info', setDumpInfo),
+    new OptionHandler(Flags.dumpInfo, setDumpInfo),
     new OptionHandler('--disallow-unsafe-eval',
                       (_) => hasDisallowUnsafeEval = true),
-    new OptionHandler('--show-package-warnings', passThrough),
-    new OptionHandler('--csp', passThrough),
-    new OptionHandler('--enable-experimental-mirrors', passThrough),
+    new OptionHandler(Flags.showPackageWarnings, passThrough),
+    new OptionHandler(Flags.useContentSecurityPolicy, passThrough),
+    new OptionHandler(Flags.enableExperimentalMirrors, passThrough),
     new OptionHandler('--enable-async', (_) {
       diagnosticHandler.info(
           "Option '--enable-async' is no longer needed. "
@@ -373,9 +374,9 @@
           "Enums are supported by default.",
           api.Diagnostic.HINT);
     }),
-    new OptionHandler('--allow-native-extensions', setAllowNativeExtensions),
-    new OptionHandler('--generate-code-with-compile-time-errors', passThrough),
-    new OptionHandler('--test-mode', passThrough),
+    new OptionHandler(Flags.allowNativeExtensions, setAllowNativeExtensions),
+    new OptionHandler(Flags.generateCodeWithCompileTimeErrors, passThrough),
+    new OptionHandler(Flags.testMode, passThrough),
 
     // The following three options must come last.
     new OptionHandler('-D.+=.*', addInEnvironment),
@@ -415,7 +416,7 @@
   }
 
   if (checkedMode && trustTypeAnnotations) {
-    helpAndFail("Option '--trust-type-annotations' may not be used in "
+    helpAndFail("Option '${Flags.trustTypeAnnotations}' may not be used in "
                 "checked mode.");
   }
 
@@ -426,23 +427,23 @@
   if ((analyzeOnly || analyzeAll) && !optionsImplyCompilation.isEmpty) {
     if (!analyzeOnly) {
       diagnosticHandler.info(
-          "Option '--analyze-all' implies '--analyze-only'.",
+          "Option '${Flags.analyzeAll}' implies '${Flags.analyzeOnly}'.",
           api.Diagnostic.INFO);
     }
     diagnosticHandler.info(
         "Options $optionsImplyCompilation indicate that output is expected, "
-        "but compilation is turned off by the option '--analyze-only'.",
+        "but compilation is turned off by the option '${Flags.analyzeOnly}'.",
         api.Diagnostic.INFO);
   }
   if (analyzeAll) analyzeOnly = true;
   if (!analyzeOnly) {
     if (allowNativeExtensions) {
-      helpAndFail("Option '--allow-native-extensions' is only supported in "
-                  "combination with the '--analyze-only' option.");
+      helpAndFail("Option '${Flags.allowNativeExtensions}' is only supported "
+                  "in combination with the '${Flags.analyzeOnly}' option.");
     }
   }
   if (dumpInfo && outputLanguage == OUTPUT_LANGUAGE_DART) {
-    helpAndFail("Option '--dump-info' is not supported in "
+    helpAndFail("Option '${Flags.dumpInfo}' is not supported in "
                 "combination with the '--output-type=dart' option.");
   }
 
diff --git a/pkg/compiler/lib/src/dart_backend/outputter.dart b/pkg/compiler/lib/src/dart_backend/outputter.dart
index 07d5a4e..82e5170 100644
--- a/pkg/compiler/lib/src/dart_backend/outputter.dart
+++ b/pkg/compiler/lib/src/dart_backend/outputter.dart
@@ -267,7 +267,7 @@
         fixedStaticNames.add(element.name);
       });
 
-      for (Element export in library.exports) {
+      library.forEachExport((Element export) {
         if (!library.isInternalLibrary &&
             export.library.isInternalLibrary) {
           // If an element of an internal library is reexported by a platform
@@ -276,7 +276,7 @@
           // implementation detail of dart2js.
           reexportingLibraries[export] = library;
         }
-      }
+      });
     }
 
     // Map to keep track of names of enum classes. Since these cannot be renamed
@@ -526,23 +526,22 @@
             stripTypes: forceStripTypes,
             minify: enableMinification);
         unparsers[outputLibrary] = unparser;
-        LibraryName libraryName = outputLibrary.libraryTag;
-        if (libraryName != null) {
-          unparser.visitLibraryName(libraryName);
+        if (outputLibrary.hasLibraryName) {
+          unparser.unparseLibraryName(outputLibrary.libraryName);
         }
-        for (LibraryTag tag in outputLibrary.tags) {
-          if (tag is! LibraryDependency) continue;
-          LibraryDependency dependency = tag;
-          LibraryElement libraryElement =
-              outputLibrary.getLibraryFromTag(dependency);
+        for (ImportElement import in outputLibrary.imports) {
+          LibraryElement libraryElement = import.importedLibrary;
           String uri = outputPaths.containsKey(libraryElement)
               ? "${outputPaths[libraryElement]}.dart"
               : libraryElement.canonicalUri.toString();
-          if (dependency is Import) {
-            unparser.unparseImportTag(uri);
-          } else {
-            unparser.unparseExportTag(uri);
-          }
+          unparser.unparseImportTag(uri);
+        }
+        for (ExportElement export in outputLibrary.exports) {
+          LibraryElement libraryElement = export.exportedLibrary;
+          String uri = outputPaths.containsKey(libraryElement)
+              ? "${outputPaths[libraryElement]}.dart"
+              : libraryElement.canonicalUri.toString();
+          unparser.unparseExportTag(uri);
         }
       }
     } else {
diff --git a/pkg/compiler/lib/src/dart_types.dart b/pkg/compiler/lib/src/dart_types.dart
index 23e87a8..1686c5a 100644
--- a/pkg/compiler/lib/src/dart_types.dart
+++ b/pkg/compiler/lib/src/dart_types.dart
@@ -12,7 +12,8 @@
 import 'diagnostics/invariant.dart' show
     invariant;
 import 'diagnostics/spannable.dart' show
-    CURRENT_ELEMENT_SPANNABLE;
+    CURRENT_ELEMENT_SPANNABLE,
+    NO_LOCATION_SPANNABLE;
 import 'elements/modelx.dart' show
     LibraryElementX,
     TypeDeclarationElementX,
@@ -1663,6 +1664,88 @@
     }
     return const DynamicType();
   }
+
+  /// Computes the unaliased type of the first non type variable bound of
+  /// [type].
+  ///
+  /// This is used to normalize malformed types, type variables and typedef
+  /// before use in typechecking.
+  ///
+  /// Malformed types are normalized to `dynamic`. Typedefs are normalized to
+  /// their alias, or `dynamic` if cyclic. Type variables are normalized to the
+  /// normalized type of their bound, or `Object` if cyclic.
+  ///
+  /// For instance for these types:
+  ///
+  ///     class Foo<T extends Bar, S extends T, U extends Baz> {}
+  ///     class Bar<X extends Y, Y extends X> {}
+  ///     typedef Baz();
+  ///
+  /// the unaliased bounds types are:
+  ///
+  ///     unaliasedBound(Foo) = Foo
+  ///     unaliasedBound(Bar) = Bar
+  ///     unaliasedBound(Unresolved) = `dynamic`
+  ///     unaliasedBound(Baz) = ()->dynamic
+  ///     unaliasedBound(T) = Bar
+  ///     unaliasedBound(S) = unaliasedBound(T) = Bar
+  ///     unaliasedBound(U) = unaliasedBound(Baz) = ()->dynamic
+  ///     unaliasedBound(X) = unaliasedBound(Y) = `Object`
+  ///
+  static DartType computeUnaliasedBound(Compiler compiler, DartType type) {
+    DartType originalType = type;
+    while (type.isTypeVariable) {
+      TypeVariableType variable = type;
+      type = variable.element.bound;
+      if (type == originalType) {
+        type = compiler.objectClass.rawType;
+      }
+    }
+    if (type.isMalformed) {
+      return const DynamicType();
+    }
+    return type.unalias(compiler);
+  }
+
+  /// Computes the interface type of [type], which is the type that defines
+  /// the property of [type].
+  ///
+  /// For an interface type it is the type itself, for a type variable it is the
+  /// interface type of the bound, for function types and typedefs it is the
+  /// `Function` type. For other types, like `dynamic`, `void` and malformed
+  /// types, there is no interface type and `null` is returned.
+  ///
+  /// For instance for these types:
+  ///
+  ///     class Foo<T extends Bar, S extends T, U extends Baz> {}
+  ///     class Bar {}
+  ///     typedef Baz();
+  ///
+  /// the interface types are:
+  ///
+  ///     interfaceType(Foo) = Foo
+  ///     interfaceType(Bar) = Bar
+  ///     interfaceType(Baz) = interfaceType(()->dynamic) = Function
+  ///     interfaceType(T) = interfaceType(Bar) = Bar
+  ///     interfaceType(S) = interfaceType(T) = interfaceType(Bar) = Bar
+  ///     interfaceType(U) = interfaceType(Baz)
+  ///                      = intefaceType(()->dynamic) = Function
+  ///
+  /// When typechecking `o.foo` the interface type of the static type of `o` is
+  /// used to lookup the existence and type of `foo`.
+  ///
+  static InterfaceType computeInterfaceType(Compiler compiler, DartType type) {
+    type = computeUnaliasedBound(compiler, type);
+    if (type.treatAsDynamic) {
+      return null;
+    }
+    if (type.isFunctionType) {
+      type = compiler.functionClass.rawType;
+    }
+    assert(invariant(NO_LOCATION_SPANNABLE, type.isInterfaceType,
+        message: "unexpected type kind ${type.kind}."));
+    return type;
+  }
 }
 
 /**
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 378710d8..949a37b 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -18,6 +18,8 @@
 import 'dart_types.dart';
 import 'diagnostics/messages.dart' show
     MessageKind;
+import 'diagnostics/spannable.dart' show
+    Spannable;
 import 'elements/elements.dart' show
     AccessorElement,
     AstElement,
@@ -25,7 +27,9 @@
     Element,
     ElementKind,
     Elements,
+    ExportElement,
     FunctionElement,
+    ImportElement,
     LibraryElement,
     MetadataAnnotation,
     PrefixElement,
@@ -66,7 +70,7 @@
 class OutputUnit {
   /// The deferred imports that will load this output unit when one of them is
   /// loaded.
-  final Setlet<Import> imports = new Setlet<Import>();
+  final Setlet<_DeferredImport> imports = new Setlet<_DeferredImport>();
 
   /// `true` if this output unit is for the main output file.
   final bool isMainOutput;
@@ -86,7 +90,7 @@
 
   int get hashCode {
     int sum = 0;
-    for (Import import in imports) {
+    for (_DeferredImport import in imports) {
       sum = (sum + import.hashCode) & 0x3FFFFFFF;  // Stay in 30 bit range.
     }
     return sum;
@@ -105,8 +109,7 @@
 
   /// A synthetic [Import] representing the loading of the main
   /// program.
-  final Import _fakeMainImport = new Import(null, new LiteralString(null,
-      new LiteralDartString("main")), null, null, null);
+  final _DeferredImport _fakeMainImport = const _DeferredImport();
 
   /// The OutputUnit that will be loaded when the program starts.
   final OutputUnit mainOutputUnit = new OutputUnit(isMainOutput: true);
@@ -127,7 +130,8 @@
   /// can be loaded in parallel. And finally lib1 can be loaded.
   final Map<String, List<OutputUnit>> hunksToLoad =
       new Map<String, List<OutputUnit>>();
-  final Map<Import, String> importDeferName = new Map<Import, String>();
+  final Map<_DeferredImport, String> _importDeferName =
+      <_DeferredImport, String>{};
 
   /// A mapping from elements and constants to their output unit. Query this via
   /// [outputUnitForElement]
@@ -142,17 +146,18 @@
   /// All the imports with a [DeferredLibrary] annotation, mapped to the
   /// [LibraryElement] they import.
   /// The main library is included in this set for convenience.
-  final Map<Import, LibraryElement> _allDeferredImports =
-      new Map<Import, LibraryElement>();
+  final Map<_DeferredImport, LibraryElement> _allDeferredImports =
+      new Map<_DeferredImport, LibraryElement>();
 
   /// Because the token-stream is forgotten later in the program, we cache a
   /// description of each deferred import.
-  final _deferredImportDescriptions = new Map<Import, ImportDescription>();
+  final Map<_DeferredImport, ImportDescription>_deferredImportDescriptions =
+      <_DeferredImport, ImportDescription>{};
 
   // For each deferred import we want to know exactly what elements have to
   // be loaded.
-  Map<Import, Set<Element>> _importedDeferredBy = null;
-  Map<Import, Set<ConstantValue>> _constantsDeferredBy = null;
+  Map<_DeferredImport, Set<Element>> _importedDeferredBy = null;
+  Map<_DeferredImport, Set<ConstantValue>> _constantsDeferredBy = null;
 
   Set<Element> _mainElements = new Set<Element>();
 
@@ -192,6 +197,16 @@
     return outputUnitForElement(element) != mainOutputUnit;
   }
 
+  /// Returns the unique name for the deferred import of [prefix].
+  String getImportDeferName(Spannable node, PrefixElement prefix) {
+    String name =
+        _importDeferName[new _DeclaredDeferredImport(prefix.deferredImport)];
+    if (name == null) {
+      compiler.internalError(node, "No deferred name for $prefix.");
+    }
+    return name;
+  }
+
   /// Returns `true` if element [to] is reachable from element [from] without
   /// crossing a deferred import.
   ///
@@ -207,14 +222,14 @@
   void registerConstantDeferredUse(DeferredConstantValue constant,
                                    PrefixElement prefix) {
     OutputUnit outputUnit = new OutputUnit();
-    outputUnit.imports.add(prefix.deferredImport);
+    outputUnit.imports.add(new _DeclaredDeferredImport(prefix.deferredImport));
     _constantToOutputUnit[constant] = outputUnit;
   }
 
   /// Answers whether [element] is explicitly deferred when referred to from
   /// [library].
   bool _isExplicitlyDeferred(Element element, LibraryElement library) {
-    Link<Import> imports = _getImports(element, library);
+    Iterable<ImportElement> imports = _getImports(element, library);
     // If the element is not imported explicitly, it is implicitly imported
     // not deferred.
     if (imports.isEmpty) return false;
@@ -222,11 +237,11 @@
     // is explicitly deferred, we say the element is explicitly deferred.
     // TODO(sigurdm): We might want to give a warning if the imports do not
     // agree.
-    return imports.every((Import import) => import.isDeferred);
+    return imports.every((ImportElement import) => import.isDeferred);
   }
 
   /// Returns a [Link] of every [Import] that imports [element] into [library].
-  Link<Import> _getImports(Element element, LibraryElement library) {
+  Iterable<ImportElement> _getImports(Element element, LibraryElement library) {
     if (element.isClassMember) {
       element = element.enclosingClass;
     }
@@ -246,6 +261,11 @@
       Set<ConstantValue> constants,
       isMirrorUsage) {
 
+    if (element.isErroneous) {
+      // Erroneous elements are ignored.
+      return;
+    }
+
     /// Recursively collects all the dependencies of [type].
     void collectTypeDependencies(DartType type) {
       if (type is GenericType) {
@@ -379,14 +399,16 @@
       iterateTags(LibraryElement library) {
         // TODO(sigurdm): Make helper getLibraryDependencyTags when tags is
         // changed to be a List instead of a Link.
-        for (LibraryTag tag in library.tags) {
-          if (tag is! LibraryDependency) continue;
-          LibraryDependency libraryDependency = tag;
-          if (!(libraryDependency is Import && libraryDependency.isDeferred)) {
-            LibraryElement importedLibrary = library.getLibraryFromTag(tag);
+        for (ImportElement import in library.imports) {
+          if (!import.isDeferred) {
+            LibraryElement importedLibrary = import.importedLibrary;
             traverseLibrary(importedLibrary);
           }
         }
+        for (ExportElement export in library.exports) {
+          LibraryElement exportedLibrary = export.exportedLibrary;
+          traverseLibrary(exportedLibrary);
+        }
       }
 
       iterateTags(library);
@@ -400,7 +422,8 @@
   }
 
   /// Add all dependencies of [constant] to the mapping of [import].
-  void _mapConstantDependencies(ConstantValue constant, Import import) {
+  void _mapConstantDependencies(ConstantValue constant,
+                                _DeferredImport import) {
     Set<ConstantValue> constants = _constantsDeferredBy.putIfAbsent(import,
         () => new Set<ConstantValue>());
     if (constants.contains(constant)) return;
@@ -418,7 +441,7 @@
   /// sets [_importedDeferredBy] and [_constantsDeferredBy].
   /// Only one of [element] and [constant] should be given.
   void _mapDependencies({Element element,
-                         Import import,
+                         _DeferredImport import,
                          isMirrorUsage: false}) {
 
     Set<Element> elements = _importedDeferredBy.putIfAbsent(import,
@@ -449,8 +472,9 @@
 
     for (Element dependency in dependentElements) {
       if (_isExplicitlyDeferred(dependency, library)) {
-        for (Import deferredImport in _getImports(dependency, library)) {
-          _mapDependencies(element: dependency, import: deferredImport);
+        for (ImportElement deferredImport in _getImports(dependency, library)) {
+          _mapDependencies(element: dependency,
+              import: new _DeclaredDeferredImport(deferredImport));
         }
       } else {
         _mapDependencies(element: dependency, import: import);
@@ -460,7 +484,7 @@
     for (ConstantValue dependency in dependentConstants) {
       if (dependency is DeferredConstantValue) {
         _mapConstantDependencies(dependency,
-                                 dependency.prefix.deferredImport);
+            new _DeclaredDeferredImport(dependency.prefix.deferredImport));
       } else {
         _mapConstantDependencies(dependency, import);
       }
@@ -471,7 +495,8 @@
   ///
   /// The elements are added with [_mapDependencies].
   void _addMirrorElements() {
-    void mapDependenciesIfResolved(Element element, Import deferredImport) {
+    void mapDependenciesIfResolved(Element element,
+                                   _DeferredImport deferredImport) {
       // If an element is the target of a MirrorsUsed annotation but never used
       // It will not be resolved, and we should not call isNeededForReflection.
       // TODO(sigurdm): Unresolved elements should just answer false when
@@ -479,27 +504,20 @@
       // So we have to filter them out here.
       if (element is AnalyzableElementX && !element.hasTreeElements) return;
       if (compiler.backend.isAccessibleByReflection(element)) {
-        _mapDependencies(element: element, import: deferredImport,
-                         isMirrorUsage: true);
+        _mapDependencies(
+            element: element, import: deferredImport, isMirrorUsage: true);
       }
     }
 
     // For each deferred import we analyze all elements reachable from the
     // imported library through non-deferred imports.
-    handleLibrary(LibraryElement library, Import deferredImport) {
+    void handleLibrary(LibraryElement library, _DeferredImport deferredImport) {
       library.implementation.forEachLocalMember((Element element) {
         mapDependenciesIfResolved(element, deferredImport);
       });
 
-      for (MetadataAnnotation metadata in library.metadata) {
-        ConstantValue constant =
-            backend.constants.getConstantValueForMetadata(metadata);
-        if (constant != null) {
-          _mapConstantDependencies(constant, deferredImport);
-        }
-      }
-      for (LibraryTag tag in library.tags) {
-        for (MetadataAnnotation metadata in tag.metadata) {
+      void processMetadata(Element element) {
+        for (MetadataAnnotation metadata in element.metadata) {
           ConstantValue constant =
               backend.constants.getConstantValueForMetadata(metadata);
           if (constant != null) {
@@ -507,9 +525,13 @@
           }
         }
       }
+
+      processMetadata(library);
+      library.imports.forEach(processMetadata);
+      library.exports.forEach(processMetadata);
     }
 
-    for (Import deferredImport in _allDeferredImports.keys) {
+    for (_DeferredImport deferredImport in _allDeferredImports.keys) {
       LibraryElement deferredLibrary = _allDeferredImports[deferredImport];
       for (LibraryElement library in
           _nonDeferredReachableLibraries(deferredLibrary)) {
@@ -524,36 +546,15 @@
   void _assignNamesToOutputUnits(Set<OutputUnit> allOutputUnits) {
     Set<String> usedImportNames = new Set<String>();
 
-    // Finds the first argument to the [DeferredLibrary] annotation
-    void computeImportDeferName(Import import) {
-      String result;
-      if (import == _fakeMainImport) {
-        result = "main";
-      } else if (import.isDeferred) {
-        result = import.prefix.toString();
-      } else {
-        Link<MetadataAnnotation> metadatas = import.metadata;
-        assert(metadatas != null);
-        for (MetadataAnnotation metadata in metadatas) {
-          metadata.ensureResolved(compiler);
-          ConstantValue value =
-              compiler.constants.getConstantValue(metadata.constant);
-          Element element = value.getType(compiler.coreTypes).element;
-          if (element == deferredLibraryClass) {
-            ConstructedConstantValue constant = value;
-            StringConstantValue s = constant.fields.values.single;
-            result = s.primitiveValue.slowToString();
-            break;
-          }
-        }
-      }
+    void computeImportDeferName(_DeferredImport import) {
+      String result = import.computeImportDeferName(compiler);
       assert(result != null);
-      importDeferName[import] = makeUnique(result, usedImportNames);;
+      _importDeferName[import] = makeUnique(result, usedImportNames);
     }
 
     int counter = 1;
 
-    for (Import import in _allDeferredImports.keys) {
+    for (_DeferredImport import in _allDeferredImports.keys) {
       computeImportDeferName(import);
     }
 
@@ -582,13 +583,13 @@
     sortedOutputUnits.sort((a, b) => b.imports.length - a.imports.length);
 
     // For each deferred import we find out which outputUnits to load.
-    for (Import import in _allDeferredImports.keys) {
+    for (_DeferredImport import in _allDeferredImports.keys) {
       if (import == _fakeMainImport) continue;
-      hunksToLoad[importDeferName[import]] = new List<OutputUnit>();
+      hunksToLoad[_importDeferName[import]] = new List<OutputUnit>();
       for (OutputUnit outputUnit in sortedOutputUnits) {
         if (outputUnit == mainOutputUnit) continue;
         if (outputUnit.imports.contains(import)) {
-          hunksToLoad[importDeferName[import]].add(outputUnit);
+          hunksToLoad[_importDeferName[import]].add(outputUnit);
         }
       }
     }
@@ -601,8 +602,8 @@
     }
     if (main == null) return;
     LibraryElement mainLibrary = main.library;
-    _importedDeferredBy = new Map<Import, Set<Element>>();
-    _constantsDeferredBy = new Map<Import, Set<ConstantValue>>();
+    _importedDeferredBy = new Map<_DeferredImport, Set<Element>>();
+    _constantsDeferredBy = new Map<_DeferredImport, Set<ConstantValue>>();
     _importedDeferredBy[_fakeMainImport] = _mainElements;
 
     measureElement(mainLibrary, () {
@@ -631,7 +632,7 @@
 
       // Reverse the mappings. For each element record an OutputUnit collecting
       // all deferred imports mapped to this element. Same for constants.
-      for (Import import in _importedDeferredBy.keys) {
+      for (_DeferredImport import in _importedDeferredBy.keys) {
         for (Element element in _importedDeferredBy[import]) {
           // Only one file should be loaded when the program starts, so make
           // sure that only one OutputUnit is created for [fakeMainImport].
@@ -644,7 +645,7 @@
           }
         }
       }
-      for (Import import in _constantsDeferredBy.keys) {
+      for (_DeferredImport import in _constantsDeferredBy.keys) {
         for (ConstantValue constant in _constantsDeferredBy[import]) {
           // Only one file should be loaded when the program starts, so make
           // sure that only one OutputUnit is created for [fakeMainImport].
@@ -711,19 +712,17 @@
     // The prefixes that have been used by any imports in this library.
     Setlet<String> usedPrefixes = new Setlet<String>();
     // The last deferred import we saw with a given prefix (if any).
-    Map<String, Import> prefixDeferredImport = new Map<String, Import>();
+    Map<String, ImportElement> prefixDeferredImport =
+        new Map<String, ImportElement>();
     for (LibraryElement library in compiler.libraryLoader.libraries) {
       compiler.withCurrentElement(library, () {
         prefixDeferredImport.clear();
         usedPrefixes.clear();
         // TODO(sigurdm): Make helper getLibraryImportTags when tags is a List
         // instead of a Link.
-        for (LibraryTag tag in library.tags) {
-          if (tag is! Import) continue;
-          Import import = tag;
-
+        for (ImportElement import in library.imports) {
           /// Give an error if the old annotation-based syntax has been used.
-          Link<MetadataAnnotation> metadataList = import.metadata;
+          List<MetadataAnnotation> metadataList = import.metadata;
           if (metadataList != null) {
             for (MetadataAnnotation metadata in metadataList) {
               metadata.ensureResolved(compiler);
@@ -738,20 +737,21 @@
           }
 
           String prefix = (import.prefix != null)
-              ? import.prefix.toString()
+              ? import.prefix.name
               : null;
           // The last import we saw with the same prefix.
-          Import previousDeferredImport = prefixDeferredImport[prefix];
+          ImportElement previousDeferredImport = prefixDeferredImport[prefix];
           if (import.isDeferred) {
-            LibraryElement importedLibrary = library.getLibraryFromTag(import);
-            _allDeferredImports[import] = importedLibrary;
+            _DeferredImport key = new _DeclaredDeferredImport(import);
+            LibraryElement importedLibrary = import.importedLibrary;
+            _allDeferredImports[key] = importedLibrary;
 
             if (prefix == null) {
               compiler.reportError(import,
                   MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX);
             } else {
               prefixDeferredImport[prefix] = import;
-              _deferredImportDescriptions[import] =
+              _deferredImportDescriptions[key] =
                   new ImportDescription(import, library, compiler);
             }
             isProgramSplit = true;
@@ -760,7 +760,7 @@
           if (prefix != null) {
             if (previousDeferredImport != null ||
                 (import.isDeferred && usedPrefixes.contains(prefix))) {
-              Import failingImport = (previousDeferredImport != null)
+              ImportElement failingImport = (previousDeferredImport != null)
                   ? previousDeferredImport
                   : import;
               compiler.reportError(failingImport.prefix,
@@ -850,8 +850,8 @@
     JavaScriptBackend backend = compiler.backend;
     Map<String, Map<String, dynamic>> mapping =
         new Map<String, Map<String, dynamic>>();
-    _deferredImportDescriptions.keys.forEach((ast.Import import) {
-      List<OutputUnit> outputUnits = hunksToLoad[importDeferName[import]];
+    _deferredImportDescriptions.keys.forEach((_DeferredImport import) {
+      List<OutputUnit> outputUnits = hunksToLoad[_importDeferName[import]];
       ImportDescription description = _deferredImportDescriptions[import];
       Map<String, dynamic> libraryMap =
           mapping.putIfAbsent(description.importingUri,
@@ -874,20 +874,73 @@
   final String prefix;
   final LibraryElement _importingLibrary;
 
-  ImportDescription(Import import,
+  ImportDescription(ImportElement import,
                     LibraryElement importingLibrary,
                     Compiler compiler)
       : importingUri = uri_extras.relativize(
           compiler.mainApp.canonicalUri,
           importingLibrary.canonicalUri, false),
-        prefix = import.prefix.source,
+        prefix = import.prefix.name,
         _importingLibrary = importingLibrary;
 
   String get importingLibraryName {
-    String libraryName = _importingLibrary.getLibraryName();
-    return libraryName == ""
-      ? "<unnamed>"
-      : libraryName;
+    return _importingLibrary.hasLibraryName
+        ? _importingLibrary.libraryName : "<unnamed>";
+  }
+}
+
+/// A node in the deferred import graph.
+///
+/// This class serves as the root node; the 'import' of the main library.
+class _DeferredImport {
+  const _DeferredImport();
+
+  /// Computes a suggestive name for this import.
+  String computeImportDeferName(Compiler compiler) => 'main';
+}
+
+/// A node in the deferred import graph defined by a deferred import directive.
+class _DeclaredDeferredImport implements _DeferredImport {
+  final ImportElement declaration;
+
+  _DeclaredDeferredImport(this.declaration);
+
+  @override
+  String computeImportDeferName(Compiler compiler) {
+    String result;
+    if (declaration.isDeferred) {
+      if (declaration.prefix != null) {
+        result = declaration.prefix.name;
+      } else {
+        // This happens when the deferred import isn't declared with a prefix.
+        assert(compiler.compilationFailed);
+        result = '';
+      }
+    } else {
+      // Finds the first argument to the [DeferredLibrary] annotation
+      List<MetadataAnnotation> metadatas = declaration.metadata;
+      assert(metadatas != null);
+      for (MetadataAnnotation metadata in metadatas) {
+        metadata.ensureResolved(compiler);
+        ConstantValue value =
+            compiler.constants.getConstantValue(metadata.constant);
+        Element element = value.getType(compiler.coreTypes).element;
+        if (element == compiler.deferredLibraryClass) {
+          ConstructedConstantValue constant = value;
+          StringConstantValue s = constant.fields.values.single;
+          result = s.primitiveValue.slowToString();
+          break;
+        }
+      }
+    }
+    assert(result != null);
+    return result;
   }
 
+  bool operator ==(other) {
+    if (other is! _DeclaredDeferredImport) return false;
+    return declaration == other.declaration;
+  }
+
+  int get hashCode => declaration.hashCode * 17;
 }
diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart
index b812fd3..8fabdf8 100644
--- a/pkg/compiler/lib/src/diagnostics/messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/messages.dart
@@ -166,6 +166,7 @@
   DEFERRED_TYPE_ANNOTATION,
   DEPRECATED_TYPEDEF_MIXIN_SYNTAX,
   DIRECTLY_THROWING_NSM,
+  DISALLOWED_LIBRARY_IMPORT,
   DUPLICATE_DEFINITION,
   DUPLICATE_EXPORT,
   DUPLICATE_EXPORT_CONT,
@@ -197,6 +198,7 @@
   FACTORY_REDIRECTION_IN_NON_FACTORY,
   FINAL_FUNCTION_TYPE_PARAMETER,
   FINAL_WITHOUT_INITIALIZER,
+  FORIN_NOT_ASSIGNABLE,
   FORMAL_DECLARED_CONST,
   FORMAL_DECLARED_STATIC,
   FUNCTION_TYPE_FORMAL_WITH_DEFAULT,
@@ -272,6 +274,7 @@
   INVALID_USE_OF_SUPER,
   LIBRARY_NAME_MISMATCH,
   LIBRARY_NOT_FOUND,
+  LIBRARY_NOT_SUPPORTED,
   LIBRARY_TAG_MUST_BE_FIRST,
   MAIN_NOT_A_FUNCTION,
   MAIN_WITH_EXTRA_PARAMETER,
@@ -309,6 +312,7 @@
   NATIVE_NOT_SUPPORTED,
   NO_BREAK_TARGET,
   NO_CATCH_NOR_FINALLY,
+  NO_COMMON_SUBTYPES,
   NO_CONTINUE_TARGET,
   NO_INSTANCE_AVAILABLE,
   NO_MATCHING_CONSTRUCTOR,
@@ -492,6 +496,11 @@
         const MessageTemplate(MessageKind.NOT_ASSIGNABLE,
           "'#{fromType}' is not assignable to '#{toType}'."),
 
+      MessageKind.FORIN_NOT_ASSIGNABLE:
+        const MessageTemplate(MessageKind.FORIN_NOT_ASSIGNABLE,
+          "The element type '#{currentType}' of '#{expressionType}' "
+          "is not assignable to '#{elementType}'."),
+
       MessageKind.VOID_EXPRESSION:
         const MessageTemplate(MessageKind.VOID_EXPRESSION,
           "Expression does not yield a value."),
@@ -2088,6 +2097,20 @@
         const MessageTemplate(MessageKind.LIBRARY_NOT_FOUND,
           "Library not found '#{resolvedUri}'."),
 
+      MessageKind.LIBRARY_NOT_SUPPORTED:
+        const MessageTemplate(MessageKind.LIBRARY_NOT_SUPPORTED,
+          "Library not supported '#{resolvedUri}'.",
+          howToFix: "Try removing the dependency or enabling support using "
+                    "the '--categories' option.",
+          examples: const [/*
+              """
+              import 'dart:io';
+              main() {}
+              """
+          */]),
+          // TODO(johnniwinther): Enable example when message_kind_test.dart
+          // supports library loader callbacks.
+
       MessageKind.UNSUPPORTED_EQ_EQ_EQ:
         const MessageTemplate(MessageKind.UNSUPPORTED_EQ_EQ_EQ,
           "'===' is not an operator. "
@@ -2894,6 +2917,10 @@
           howToFix:
             "Try replacing '#{shownType}' with '#{shownTypeSuggestion}'."),
 
+      MessageKind.NO_COMMON_SUBTYPES:
+        const MessageTemplate(MessageKind.NO_COMMON_SUBTYPES,
+           "Types '#{left}' and '#{right}' have no common subtypes."),
+
       MessageKind.HIDDEN_WARNINGS_HINTS:
         const MessageTemplate(MessageKind.HIDDEN_WARNINGS_HINTS,
           "#{warnings} warning(s) and #{hints} hint(s) suppressed in #{uri}."),
@@ -3263,6 +3290,14 @@
 ****************************************************************
 '''),
 
+      MessageKind.DISALLOWED_LIBRARY_IMPORT:
+        const MessageTemplate(MessageKind.DISALLOWED_LIBRARY_IMPORT, '''
+Your app imports the unsupported library '#{uri}' via:
+''''''
+$DISALLOWED_LIBRARY_IMPORT_PADDING#{importChain}
+
+Use the --categories option to support import of '#{uri}'.
+'''),
 
       MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND:
         const MessageTemplate(
@@ -3303,8 +3338,14 @@
 
   }; // End of TEMPLATES.
 
+  /// Padding used before and between import chains in the message for
+  /// [MessageKind.IMPORT_EXPERIMENTAL_MIRRORS].
   static const String IMPORT_EXPERIMENTAL_MIRRORS_PADDING = '\n*   ';
 
+  /// Padding used before and between import chains in the message for
+  /// [MessageKind.DISALLOWED_LIBRARY_IMPORT].
+  static const String DISALLOWED_LIBRARY_IMPORT_PADDING = '\n  ';
+
   toString() => template;
 
   Message message([Map arguments = const {}, bool terse = false]) {
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 4ba2073..adf558d 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -82,8 +82,7 @@
   }
 
   LibraryInfo visitLibraryElement(LibraryElement element, _) {
-    String libname = element.getLibraryName();
-    libname = libname == "" ? "<unnamed>" : libname;
+    String libname = element.hasLibraryName ? element.libraryName : "<unnamed>";
     int size = compiler.dumpInfoTask.sizeOf(element);
     LibraryInfo info =
       new LibraryInfo(libname, element.canonicalUri, null, size);
diff --git a/pkg/compiler/lib/src/elements/common.dart b/pkg/compiler/lib/src/elements/common.dart
index 5320fcb..6c4352a 100644
--- a/pkg/compiler/lib/src/elements/common.dart
+++ b/pkg/compiler/lib/src/elements/common.dart
@@ -133,9 +133,9 @@
   bool get isInternalLibrary =>
       isPlatformLibrary && canonicalUri.path.startsWith('_');
 
-  String getLibraryOrScriptName() {
-    if (hasLibraryName()) {
-      return getLibraryName();
+  String get libraryOrScriptName {
+    if (hasLibraryName) {
+      return libraryName;
     } else {
       // Use the file name as script name.
       String path = canonicalUri.path;
@@ -145,7 +145,7 @@
 
   int compareTo(LibraryElement other) {
     if (this == other) return 0;
-    return getLibraryOrScriptName().compareTo(other.getLibraryOrScriptName());
+    return libraryOrScriptName.compareTo(other.libraryOrScriptName);
   }
 }
 
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index 219349b..7c538b5 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -106,6 +106,10 @@
       const ElementKind('abstract_field', ElementCategory.VARIABLE);
   static const ElementKind LIBRARY =
       const ElementKind('library', ElementCategory.NONE);
+  static const ElementKind IMPORT =
+      const ElementKind('import', ElementCategory.NONE);
+  static const ElementKind EXPORT =
+      const ElementKind('export', ElementCategory.NONE);
   static const ElementKind PREFIX =
       const ElementKind('prefix', ElementCategory.PREFIX);
   static const ElementKind TYPEDEF =
@@ -182,11 +186,17 @@
   String get name;
   ElementKind get kind;
   Element get enclosingElement;
-  Link<MetadataAnnotation> get metadata;
+  Iterable<MetadataAnnotation> get metadata;
 
   /// `true` if this element is a library.
   bool get isLibrary;
 
+  /// `true` if this element is an import declaration.
+  bool get isImport => kind == ElementKind.IMPORT;
+
+  /// `true` if this element is an export declaration.
+  bool get isExport => kind == ElementKind.EXPORT;
+
   /// `true` if this element is a compilation unit.
   bool get isCompilationUnit;
 
@@ -832,6 +842,22 @@
   int compareTo(CompilationUnitElement other);
 }
 
+abstract class ImportElement extends Element {
+  Uri get uri;
+  LibraryElement get importedLibrary;
+  bool get isDeferred;
+  PrefixElement get prefix;
+  // TODO(johnniwinther): Remove this when no longer needed in source mirrors.
+  Import get node;
+}
+
+abstract class ExportElement extends Element {
+  Uri get uri;
+  LibraryElement get exportedLibrary;
+  // TODO(johnniwinther): Remove this when no longer needed in source mirrors.
+  Export get node;
+}
+
 abstract class LibraryElement extends Element
     implements ScopeContainerElement, AnalyzableElement {
   /**
@@ -847,9 +873,13 @@
 
   CompilationUnitElement get entryCompilationUnit;
   Link<CompilationUnitElement> get compilationUnits;
-  Iterable<LibraryTag> get tags;
-  LibraryName get libraryTag;
-  Link<Element> get exports;
+
+  /// The import declarations in this library, including the implicit import of
+  /// 'dart:core', if present.
+  Iterable<ImportElement> get imports;
+
+  /// The export declarations in this library.
+  Iterable<ExportElement> get exports;
 
   /**
    * [:true:] if this library is part of the platform, that is, its canonical
@@ -874,9 +904,6 @@
 
   LibraryElement get implementation;
 
-  /// Return the library element corresponding to an import or export.
-  LibraryElement getLibraryFromTag(LibraryDependency tag);
-
   Element find(String elementName);
   Element findLocal(String elementName);
   Element findExported(String elementName);
@@ -886,32 +913,35 @@
   void forEachImport(f(Element element));
 
   /// Returns the imports that import element into this library.
-  Link<Import> getImportsFor(Element element);
+  Iterable<ImportElement> getImportsFor(Element element);
 
-  bool hasLibraryName();
-  String getLibraryName();
+  /// `true` if this library has name as given through a library tag.
+  bool get hasLibraryName;
 
-  /**
-   * Returns the library name (as defined by the library tag) or for script
-   * (which have no library tag) the script file name. The latter case is used
-   * to provide a 'library name' for scripts to use for instance in dartdoc.
-   *
-   * Note: the returned filename is still escaped ("a%20b.dart" instead of
-   * "a b.dart").
-   */
-  String getLibraryOrScriptName();
+  /// The library name, which is either the name given in the library tag
+  /// or the empty string if there is no library tag.
+  String get libraryName;
+
+  /// Returns the library name (as defined by the library tag) or for script
+  /// (which have no library tag) the script file name. The latter case is used
+  /// to provide a 'library name' for scripts to use for instance in dartdoc.
+  ///
+  /// Note: the returned filename is still escaped ("a%20b.dart" instead of
+  /// "a b.dart").
+  String get libraryOrScriptName;
 
   int compareTo(LibraryElement other);
 }
 
 /// The implicit scope defined by a import declaration with a prefix clause.
 abstract class PrefixElement extends Element {
-  void addImport(Element element, Import import, DiagnosticListener listener);
   Element lookupLocalMember(String memberName);
+
   /// Is true if this prefix belongs to a deferred import.
   bool get isDeferred;
-  void markAsDeferred(Import import);
-  Import get deferredImport;
+
+  /// Import that declared this deferred prefix.
+  ImportElement get deferredImport;
 }
 
 /// A type alias definition.
diff --git a/pkg/compiler/lib/src/elements/modelx.dart b/pkg/compiler/lib/src/elements/modelx.dart
index 6574231..de3c11f 100644
--- a/pkg/compiler/lib/src/elements/modelx.dart
+++ b/pkg/compiler/lib/src/elements/modelx.dart
@@ -59,7 +59,7 @@
   final ElementKind kind;
   final Element enclosingElement;
   final int hashCode = ++elementHashCode;
-  Link<MetadataAnnotation> metadata = const Link<MetadataAnnotation>();
+  List<MetadataAnnotation> metadataInternal;
 
   ElementX(this.name, this.kind, this.enclosingElement) {
     assert(isErroneous || implementationLibrary != null);
@@ -73,14 +73,27 @@
     return null;
   }
 
-  void addMetadata(MetadataAnnotationX annotation) {
-    assert(annotation.annotatedElement == null);
-    annotation.annotatedElement = this;
-    addMetadataInternal(annotation);
+  void set metadata(List<MetadataAnnotation> metadata) {
+    assert(metadataInternal == null);
+    for (MetadataAnnotationX annotation in metadata) {
+      assert(annotation.annotatedElement == null);
+      annotation.annotatedElement = this;
+    }
+    metadataInternal = metadata;
   }
 
-  void addMetadataInternal(MetadataAnnotation annotation) {
-    metadata = metadata.prepend(annotation);
+  Iterable<MetadataAnnotation> get metadata {
+    if (isPatch && metadataInternal != null) {
+      if (origin.metadata.isEmpty) {
+        return metadataInternal;
+      } else {
+        return <MetadataAnnotation>[]
+            ..addAll(origin.metadata)
+            ..addAll(metadataInternal);
+      }
+    }
+    return metadataInternal != null
+        ? metadataInternal : const <MetadataAnnotation>[];
   }
 
   bool get isClosure => false;
@@ -280,7 +293,7 @@
   }
 
   get asyncMarker => AsyncMarker.SYNC;
-  Link<MetadataAnnotation> get metadata => unsupported();
+  Iterable<MetadataAnnotation> get metadata => unsupported();
   bool get hasNode => false;
   get node => unsupported();
   get hasResolvedAst => false;
@@ -547,11 +560,10 @@
     for (Element element in ambiguousElements) {
       var arguments = {'name': element.name};
       listener.reportInfo(element, code, arguments);
-      Link<Import> importers = importer.importers.getImports(element);
       listener.withCurrentElement(importer, () {
-        for (; !importers.isEmpty; importers = importers.tail) {
+        for (ImportElement import in importer.importers.getImports(element)) {
           listener.reportInfo(
-              importers.head, MessageKind.IMPORTED_HERE, arguments);
+              import, MessageKind.IMPORTED_HERE, arguments);
         }
       });
     }
@@ -678,6 +690,19 @@
   @override
   LibraryElementX get library => enclosingElement.declaration;
 
+  void set metadata(List<MetadataAnnotation> metadata) {
+    for (MetadataAnnotationX annotation in metadata) {
+      assert(annotation.annotatedElement == null);
+      annotation.annotatedElement = this;
+    }
+    // TODO(johnniwinther): Remove this work-around when import, export,
+    // part, and part-of declarations are elements.
+    if (metadataInternal == null) {
+      metadataInternal = <MetadataAnnotation>[];
+    }
+    metadataInternal.addAll(metadata);
+  }
+
   void forEachLocalMember(f(Element element)) {
     localMembers.forEach(f);
   }
@@ -736,22 +761,26 @@
   }
 }
 
+/// Map from [Element] to the [ImportElement]s throught which it was imported.
+///
+/// This is used for error reporting and deferred loading.
 class Importers {
-  Map<Element, Link<Import>> importers = new Map<Element, Link<Import>>();
+  Map<Element, List<ImportElement>> importers =
+      new Map<Element, List<ImportElement>>();
 
-  Link<Import> getImports(Element element) {
-    Link<Import> imports = importers[element];
-    return imports != null ? imports : const Link<Import>();
+  /// Returns the the list of [ImportElement]s through which [element] was
+  /// imported.
+  List<ImportElement> getImports(Element element) {
+    List<ImportElement> imports = importers[element];
+    return imports != null ? imports : const <ImportElement>[];
   }
 
-  Import getImport(Element element) => getImports(element).head;
+  /// Returns the first [ImportElement] through which [element] was imported.
+  ImportElement getImport(Element element) => getImports(element).first;
 
-  void registerImport(Element element, Import import) {
-    if (import == null) return;
-
-    importers[element] =
-        importers.putIfAbsent(element, () => const Link<Import>())
-          .prepend(import);
+  /// Register [element] as imported through [import];
+  void registerImport(Element element, ImportElement import) {
+    importers.putIfAbsent(element, () => <ImportElement>[]).add(import);
   }
 }
 
@@ -774,7 +803,7 @@
    */
   void addImport(Element enclosingElement,
                  Element element,
-                 Import import,
+                 ImportElement import,
                  DiagnosticListener listener) {
     LibraryElementX library = enclosingElement.library;
     Importers importers = library.importers;
@@ -789,7 +818,7 @@
     Element existing = importScope.putIfAbsent(name, () => element);
     importers.registerImport(element, import);
 
-    void registerWarnOnUseElement(Import import,
+    void registerWarnOnUseElement(ImportElement import,
                                   MessageKind messageKind,
                                   Element hidingElement,
                                   Element hiddenElement) {
@@ -810,7 +839,7 @@
     }
 
     if (existing != element) {
-      Import existingImport = importers.getImport(existing);
+      ImportElement existingImport = importers.getImport(existing);
       if (existing.library.isPlatformLibrary &&
           !element.library.isPlatformLibrary) {
         // [existing] is implicitly hidden.
@@ -819,7 +848,7 @@
       } else if (!existing.library.isPlatformLibrary &&
                  element.library.isPlatformLibrary) {
         // [element] is implicitly hidden.
-        if (import == null) {
+        if (import.isSynthesized) {
           // [element] is imported implicitly (probably through dart:core).
           registerWarnOnUseElement(
               existingImport, MessageKind.HIDDEN_IMPLICIT_IMPORT,
@@ -840,6 +869,94 @@
   }
 
   Element operator [](String name) => importScope[name];
+
+  void forEach(f(Element element)) => importScope.values.forEach(f);
+}
+
+abstract class LibraryDependencyElementX extends ElementX {
+  final LibraryDependency node;
+  final Uri uri;
+  LibraryElement libraryDependency;
+
+  LibraryDependencyElementX(CompilationUnitElement enclosingElement,
+                            ElementKind kind,
+                            this.node,
+                            this.uri)
+      : super('', kind, enclosingElement);
+
+  @override
+  List<MetadataAnnotation> get metadata => node.metadata;
+
+  void set metadata(value) {
+    // The metadata is stored on [libraryDependency].
+    throw new SpannableAssertionFailure(
+        this, 'Cannot set metadata on a import/export.');
+  }
+
+  @override
+  Token get position => node.getBeginToken();
+
+  SourceSpan get sourcePosition {
+    return new SourceSpan.fromNode(compilationUnit.script.resourceUri, node);
+  }
+
+  String toString() => '$kind($uri)';
+}
+
+class ImportElementX extends LibraryDependencyElementX
+    implements ImportElement {
+  PrefixElementX prefix;
+
+  ImportElementX(CompilationUnitElement enclosingElement, Import node, Uri uri)
+      : super(enclosingElement, ElementKind.IMPORT, node, uri);
+
+  @override
+  Import get node => super.node;
+
+  @override
+  LibraryElement get importedLibrary => libraryDependency;
+
+  @override
+  accept(ElementVisitor visitor, arg) => visitor.visitImportElement(this, arg);
+
+  @override
+  bool get isDeferred => node.isDeferred;
+}
+
+class SyntheticImportElement extends ImportElementX {
+  SyntheticImportElement(CompilationUnitElement enclosingElement, Uri uri)
+      : super(enclosingElement, null, uri);
+
+  @override
+  Token get position => library.position;
+
+  @override
+  bool get isSynthesized => true;
+
+  @override
+  bool get isDeferred => false;
+
+  @override
+  List<MetadataAnnotation> get metadata => const <MetadataAnnotation>[];
+
+  @override
+  SourceSpan get sourcePosition => library.sourcePosition;
+}
+
+
+class ExportElementX extends LibraryDependencyElementX
+    implements ExportElement {
+
+  ExportElementX(CompilationUnitElement enclosingElement, Export node, Uri uri)
+      : super(enclosingElement, ElementKind.EXPORT, node, uri);
+
+  Export get node => super.node;
+
+  @override
+  LibraryElement get exportedLibrary => libraryDependency;
+
+  @override
+  accept(ElementVisitor visitor, arg) => visitor.visitExportElement(this, arg);
 }
 
 class LibraryElementX
@@ -877,6 +994,9 @@
    */
   Link<Element> slotForExports;
 
+  List<ImportElement> _imports = <ImportElement>[];
+  List<ExportElement> _exports = <ExportElement>[];
+
   final Map<LibraryDependency, LibraryElement> tagMapping =
       new Map<LibraryDependency, LibraryElement>();
 
@@ -892,11 +1012,14 @@
     }
   }
 
-  Link<MetadataAnnotation> get metadata {
-    return (libraryTag == null) ? super.metadata : libraryTag.metadata;
+  Iterable<MetadataAnnotation> get metadata {
+    if (libraryTag != null) {
+      return libraryTag.metadata;
+    }
+    return const <MetadataAnnotation>[];
   }
 
-  set metadata(value) {
+  void set metadata(value) {
     // The metadata is stored on [libraryTag].
     throw new SpannableAssertionFailure(this, 'Cannot set metadata on Library');
   }
@@ -925,13 +1048,17 @@
     return tagsCache;
   }
 
-  /// Record which element an import or export tag resolved to.
-  void recordResolvedTag(LibraryDependency tag, LibraryElement library) {
-    assert(tagMapping[tag] == null);
-    tagMapping[tag] = library;
+  void addImportDeclaration(ImportElement import) {
+    _imports.add(import);
   }
 
-  LibraryElement getLibraryFromTag(LibraryDependency tag) => tagMapping[tag];
+  Iterable<ImportElement> get imports => _imports;
+
+  void addExportDeclaration(ExportElement export) {
+    _exports.add(export);
+  }
+
+  Iterable<ExportElement> get exports => _exports;
 
   /**
    * Adds [element] to the import scope of this library.
@@ -940,7 +1067,9 @@
    * [ErroneousElement] will be put in the imported scope, allowing for
    * detection of ambiguous uses of imported names.
    */
-  void addImport(Element element, Import import, DiagnosticListener listener) {
+  void addImport(Element element,
+                 ImportElement import,
+                 DiagnosticListener listener) {
     importScope.addImport(this, element, import, listener);
   }
 
@@ -967,12 +1096,6 @@
    */
   bool get exportsHandled => slotForExports != null;
 
-  Link<Element> get exports {
-    assert(invariant(this, exportsHandled,
-                     message: 'Exports not handled on $this'));
-    return slotForExports;
-  }
-
   /**
    * Sets the export scope of this library. This method can only be called once.
    */
@@ -1024,7 +1147,9 @@
   }
 
   Element findExported(String elementName) {
-    for (Link link = exports; !link.isEmpty; link = link.tail) {
+    assert(invariant(this, exportsHandled,
+                     message: 'Exports not handled on $this'));
+    for (Link link = slotForExports; !link.isEmpty; link = link.tail) {
       Element element = link.head;
       if (element.name == elementName) return element;
     }
@@ -1032,16 +1157,17 @@
   }
 
   void forEachExport(f(Element element)) {
-    exports.forEach((Element e) => f(e));
+    assert(invariant(this, exportsHandled,
+                     message: 'Exports not handled on $this'));
+    slotForExports.forEach((Element e) => f(e));
   }
 
-  Link<Import> getImportsFor(Element element) => importers.getImports(element);
-
-  @override
-  void forEachImport(f(Element element)) {
-    importScope.importScope.values.forEach(f);
+  Iterable<ImportElement> getImportsFor(Element element) {
+    return importers.getImports(element);
   }
 
+  void forEachImport(f(Element element)) => importScope.forEach(f);
+
   void forEachLocalMember(f(Element element)) {
     if (isPatch) {
       // Patch libraries traverse both origin and injected members.
@@ -1067,17 +1193,23 @@
     });
   }
 
-  bool hasLibraryName() => libraryTag != null;
+  bool get hasLibraryName => libraryTag != null;
 
-  /**
-   * Returns the library name, which is either the name given in the library tag
-   * or the empty string if there is no library tag.
-   */
-  String getLibraryName() {
+  String get libraryName {
     if (libraryTag == null) return '';
     return libraryTag.name.toString();
   }
 
+  String get libraryOrScriptName {
+    if (libraryTag != null) {
+      return libraryTag.name.toString();
+    } else {
+      // Use the file name as script name.
+      String path = canonicalUri.path;
+      return path.substring(path.lastIndexOf('/') + 1);
+    }
+  }
+
   Scope buildScope() => new LibraryScope(this);
 
   String toString() {
@@ -1104,13 +1236,15 @@
 
   final ImportScope importScope = new ImportScope();
 
-  bool get isDeferred => _deferredImport != null;
+  bool get isDeferred => deferredImport != null;
 
   // Only needed for deferred imports.
-  Import _deferredImport;
-  Import get deferredImport => _deferredImport;
+  final ImportElement deferredImport;
 
-  PrefixElementX(String prefix, Element enclosing, this.firstPosition)
+  PrefixElementX(String prefix,
+                 Element enclosing,
+                 this.firstPosition,
+                 this.deferredImport)
       : super(prefix, ElementKind.PREFIX, enclosing);
 
   bool get isTopLevel => false;
@@ -1121,7 +1255,9 @@
 
   Token get position => firstPosition;
 
-  void addImport(Element element, Import import, DiagnosticListener listener) {
+  void addImport(Element element,
+                 ImportElement import,
+                 DiagnosticListener listener) {
     importScope.addImport(this, element, import, listener);
   }
 
@@ -1129,10 +1265,6 @@
     return visitor.visitPrefixElement(this, arg);
   }
 
-  void markAsDeferred(Import deferredImport) {
-    _deferredImport = deferredImport;
-  }
-
   String toString() => '$kind($name)';
 }
 
@@ -1218,7 +1350,7 @@
   VariableDefinitions definitions;
   DartType type;
   final Modifiers modifiers;
-  Link<MetadataAnnotation> metadata = const Link<MetadataAnnotation>();
+  List<MetadataAnnotation> metadataInternal;
 
   VariableList(Modifiers this.modifiers);
 
@@ -1228,6 +1360,25 @@
     assert(modifiers != null);
   }
 
+  Iterable<MetadataAnnotation> get metadata {
+    return metadataInternal != null
+        ? metadataInternal : const <MetadataAnnotation>[];
+  }
+
+  void set metadata(List<MetadataAnnotation> metadata) {
+    if (metadata.isEmpty) {
+      // For a multi declaration like:
+      //
+      //    @foo @bar var a, b, c
+      //
+      // the metadata list is reported through the declaration of `a`, and `b`
+      // and `c` report an empty list of metadata.
+      return;
+    }
+    assert(metadataInternal == null);
+    metadataInternal = metadata;
+  }
+
   VariableDefinitions parseNode(Element element, DiagnosticListener listener) {
     return definitions;
   }
@@ -1284,10 +1435,14 @@
 
   // TODO(johnniwinther): Ensure that the [TreeElements] for this variable hold
   // the mappings for all its metadata.
-  Link<MetadataAnnotation> get metadata => variables.metadata;
+  Iterable<MetadataAnnotation> get metadata => variables.metadata;
 
-  void addMetadataInternal(MetadataAnnotation annotation) {
-    variables.metadata = variables.metadata.prepend(annotation);
+  void set metadata(List<MetadataAnnotation> metadata) {
+    for (MetadataAnnotationX annotation in metadata) {
+      assert(annotation.annotatedElement == null);
+      annotation.annotatedElement = this;
+    }
+    variables.metadata = metadata;
   }
 
   // A variable cannot be patched therefore defines itself.
@@ -2097,7 +2252,7 @@
 
   FunctionExpression get node => constructor.node;
 
-  Link<MetadataAnnotation> get metadata => constructor.metadata;
+  List<MetadataAnnotation> get metadata => constructor.metadata;
 
   bool get isInstanceMember => true;
 
@@ -2363,6 +2518,7 @@
   void ensureResolved(Compiler compiler) {
     if (resolutionState == STATE_NOT_STARTED) {
       compiler.resolver.resolveClass(this);
+      compiler.world.registerClass(this);
     }
   }
 
@@ -2617,7 +2773,7 @@
   final Node node;
   final Modifiers modifiers;
 
-  Link<FunctionElement> constructors = new Link<FunctionElement>();
+  Link<ConstructorElement> constructors = new Link<ConstructorElement>();
 
   InterfaceType mixinType;
 
diff --git a/pkg/compiler/lib/src/elements/names.dart b/pkg/compiler/lib/src/elements/names.dart
index 514729c..314a94b 100644
--- a/pkg/compiler/lib/src/elements/names.dart
+++ b/pkg/compiler/lib/src/elements/names.dart
@@ -110,5 +110,5 @@
     return super==(other) && library == other.library;
   }
 
-  String toString() => '${library.getLibraryName()}#${super.toString()}';
+  String toString() => '${library.libraryName}#${super.toString()}';
 }
diff --git a/pkg/compiler/lib/src/elements/visitor.dart b/pkg/compiler/lib/src/elements/visitor.dart
index 7769226..23d5263 100644
--- a/pkg/compiler/lib/src/elements/visitor.dart
+++ b/pkg/compiler/lib/src/elements/visitor.dart
@@ -20,6 +20,8 @@
   R visitAmbiguousElement(AmbiguousElement e, A arg) => null;
   R visitCompilationUnitElement(CompilationUnitElement e, A arg) => null;
   R visitLibraryElement(LibraryElement e, A arg) => null;
+  R visitImportElement(ImportElement e, A arg) => null;
+  R visitExportElement(ExportElement e, A arg) => null;
   R visitPrefixElement(PrefixElement e, A arg) => null;
   R visitTypedefElement(TypedefElement e, A arg) => null;
   R visitVariableElement(VariableElement e, A arg) => null;
@@ -76,6 +78,16 @@
   }
 
   @override
+  R visitImportElement(ImportElement e, A arg) {
+    return visitElement(e, arg);
+  }
+
+  @override
+  R visitExportElement(ExportElement e, A arg) {
+    return visitElement(e, arg);
+  }
+
+  @override
   R visitPrefixElement(PrefixElement e, A arg) {
     return visitElement(e, arg);
   }
diff --git a/pkg/compiler/lib/src/helpers/stats.dart b/pkg/compiler/lib/src/helpers/stats.dart
index 13897c7..d7f6b5d 100644
--- a/pkg/compiler/lib/src/helpers/stats.dart
+++ b/pkg/compiler/lib/src/helpers/stats.dart
@@ -458,7 +458,7 @@
     indentation = ''.padLeft(countText.length, ' ');
     if (commonPrefix != null) {
       int index = 0;
-      for (String line in commonPrefix) {
+      for (StackTraceLine line in commonPrefix) {
         sb.write(indentation);
         if (index > 1) {
           sb.write('...\n');
diff --git a/pkg/compiler/lib/src/helpers/trace.dart b/pkg/compiler/lib/src/helpers/trace.dart
index f19b0d0..b928bb6 100644
--- a/pkg/compiler/lib/src/helpers/trace.dart
+++ b/pkg/compiler/lib/src/helpers/trace.dart
@@ -131,8 +131,9 @@
     // Dart VM are:
     //    #n     <method-name> (<uri>:<line-no>:<column-no>)
     //    #n     <method-name> (<uri>:<line-no>)
+    //    #n     <method-name> (<uri>)
     // in which '<anonymous closure>' is the name used for an (unnamed) function
-    // expression.
+    // expression. The last case is used for async bodies.
     for (String line in stackTrace.split('\n')) {
       try {
         index++;
@@ -154,16 +155,33 @@
           lineNo = line.substring(nextToLastColon+1, lastColon);
           columnNo = line.substring(lastColon+1, rightParenPos);
           try {
-            int.parse(lineNo);
+            int.parse(columnNo);
+            try {
+              int.parse(lineNo);
+            } on FormatException {
+              // Only line number.
+              lineNo = columnNo;
+              columnNo = '';
+              nextToLastColon = lastColon;
+            }
           } on FormatException {
-            lineNo = columnNo;
+            // No column number nor line number.
+            lineNo = '';
             columnNo = '';
-            nextToLastColon = lastColon;
+            nextToLastColon = rightParenPos;
           }
         } else {
           lineNo = line.substring(lastColon+1, rightParenPos);
           columnNo = '';
-          nextToLastColon = lastColon;
+          try {
+            int.parse(lineNo);
+            nextToLastColon = lastColon;
+          } on FormatException {
+            // No column number nor line number.
+            lineNo = columnNo;
+            columnNo = '';
+            nextToLastColon = rightParenPos;
+          }
         }
 
         if (lineNo.length > maxLineNoLength) {
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index e031100..bb88478 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -332,6 +332,9 @@
 
   ClassElement jsInvocationMirrorClass;
 
+  ClassElement typedArrayClass;
+  ClassElement typedArrayOfIntClass;
+
   /// If [true], the compiler will emit code that logs whenever a method is
   /// called. When TRACE_METHOD is 'console' this will be logged
   /// directly in the JavaScript console. When TRACE_METHOD is 'post' the
@@ -1369,10 +1372,6 @@
     }
   }
 
-  void registerClassUsingVariableExpression(ClassElement cls) {
-    rti.classesUsingTypeVariableExpression.add(cls);
-  }
-
   bool classNeedsRti(ClassElement cls) {
     return rti.classesNeedingRti.contains(cls.declaration) ||
         compiler.enabledRuntimeType;
@@ -1501,16 +1500,8 @@
    *
    * Invariant: [element] must be a declaration element.
    */
-  String assembleCode(Element element) {
+  String getGeneratedCode(Element element) {
     assert(invariant(element, element.isDeclaration));
-    var code = generatedCode[element];
-    if (namer is jsAst.TokenFinalizer) {
-      jsAst.TokenCounter counter = new jsAst.TokenCounter();
-      counter.countTokens(code);
-      // Avoid a warning.
-      var finalizer = namer;
-      finalizer.finalizeTokens();
-    }
     return jsAst.prettyPrint(generatedCode[element], compiler).getText();
   }
 
@@ -1528,17 +1519,15 @@
            'percentage': percentage.round()});
       for (LibraryElement library in compiler.libraryLoader.libraries) {
         if (library.isInternalLibrary) continue;
-        for (LibraryTag tag in library.tags) {
-          Import importTag = tag.asImport();
-          if (importTag == null) continue;
-          LibraryElement importedLibrary = library.getLibraryFromTag(tag);
+        for (ImportElement import in library.imports) {
+          LibraryElement importedLibrary = import.importedLibrary;
           if (importedLibrary != compiler.mirrorsLibrary) continue;
           MessageKind kind =
               compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(library)
               ? MessageKind.MIRROR_IMPORT
               : MessageKind.MIRROR_IMPORT_NO_USAGE;
           compiler.withCurrentElement(library, () {
-            compiler.reportInfo(importTag, kind);
+            compiler.reportInfo(import, kind);
           });
         }
       }
@@ -2085,7 +2074,10 @@
 
   Future onLibraryScanned(LibraryElement library, LibraryLoader loader) {
     return super.onLibraryScanned(library, loader).then((_) {
-      if (library.isPlatformLibrary && !library.isPatched) {
+      if (library.isPlatformLibrary &&
+          // Don't patch library currently disallowed.
+          !library.isSynthesized &&
+          !library.isPatched) {
         // Apply patch, if any.
         Uri patchUri = compiler.resolvePatchUri(library.canonicalUri.path);
         if (patchUri != null) {
@@ -2160,6 +2152,9 @@
         htmlLibraryIsLoaded = true;
       } else if (uri == PACKAGE_LOOKUP_MAP) {
         lookupMapAnalysis.init(library);
+      } else if (uri == Uris.dart__native_typed_data) {
+        typedArrayClass = findClass('NativeTypedArray');
+        typedArrayOfIntClass = findClass('NativeTypedArrayOfInt');
       }
       annotations.onLibraryScanned(library);
     });
@@ -2313,8 +2308,7 @@
    */
   bool matchesMirrorsMetaTarget(Element element) {
     if (metaTargetsUsed.isEmpty) return false;
-    for (Link link = element.metadata; !link.isEmpty; link = link.tail) {
-      MetadataAnnotation metadata = link.head;
+    for (MetadataAnnotation metadata in element.metadata) {
       // TODO(kasperl): It would be nice if we didn't have to resolve
       // all metadata but only stuff that potentially would match one
       // of the used meta targets.
@@ -2625,7 +2619,7 @@
     bool hasForceInline = false;
     bool hasNoThrows = false;
     bool hasNoSideEffects = false;
-    for (MetadataAnnotation metadata in element.metadata) {
+    for (MetadataAnnotation metadata in element.implementation.metadata) {
       metadata.ensureResolved(compiler);
       ConstantValue constantValue =
           compiler.constants.getConstantValue(metadata.constant);
@@ -2894,19 +2888,21 @@
   /// Returns `true` if [element] is annotated with [annotationClass].
   bool _hasAnnotation(Element element, ClassElement annotationClass) {
     if (annotationClass == null) return false;
-    for (Link<MetadataAnnotation> link = element.metadata;
-         !link.isEmpty;
-         link = link.tail) {
-      ConstantValue value =
-          compiler.constants.getConstantValue(link.head.constant);
-      if (value.isConstructedObject) {
-        ConstructedConstantValue constructedConstant = value;
-        if (constructedConstant.type.element == annotationClass) {
-          return true;
+    return compiler.withCurrentElement(element, () {
+      for (MetadataAnnotation metadata in element.metadata) {
+        assert(invariant(metadata, metadata.constant != null,
+            message: "Unevaluated metadata constant."));
+        ConstantValue value =
+            compiler.constants.getConstantValue(metadata.constant);
+        if (value.isConstructedObject) {
+          ConstructedConstantValue constructedConstant = value;
+          if (constructedConstant.type.element == annotationClass) {
+            return true;
+          }
         }
       }
-    }
-    return false;
+      return false;
+    });
   }
 }
 
@@ -2990,7 +2986,8 @@
         backend.getCheckConcurrentModificationError(), registry);
   }
 
-  void onTypeVariableExpression(Registry registry) {
+  void onTypeVariableExpression(Registry registry,
+                                TypeVariableElement variable) {
     assert(registry.isForResolution);
     registerBackendStaticInvocation(backend.getSetRuntimeTypeInfo(), registry);
     registerBackendStaticInvocation(backend.getGetRuntimeTypeInfo(), registry);
@@ -2998,6 +2995,9 @@
     registerBackendInstantiation(backend.compiler.listClass, registry);
     registerBackendStaticInvocation(backend.getRuntimeTypeToString(), registry);
     registerBackendStaticInvocation(backend.getCreateRuntimeType(), registry);
+    needsInt(registry, 'Needed for accessing a type variable literal on this.');
+    ClassElement cls = variable.enclosingClass;
+    backend.rti.classesUsingTypeVariableExpression.add(cls);
   }
 
   // TODO(johnniwinther): Maybe split this into [onAssertType] and [onTestType].
@@ -3058,7 +3058,7 @@
     registerBackendStaticInvocation(
         backend.getThrowAbstractClassInstantiationError(), registry);
     // Also register the types of the arguments passed to this method.
-    registerBackendInstantiation(backend.compiler.stringClass, registry);
+    needsString(registry, '// Needed to encode the message.');
   }
 
   void onFallThroughError(Registry registry) {
@@ -3075,8 +3075,10 @@
     assert(registry.isForResolution);
     registerBackendStaticInvocation(backend.getThrowNoSuchMethod(), registry);
     // Also register the types of the arguments passed to this method.
-    registerBackendInstantiation(backend.compiler.listClass, registry);
-    registerBackendInstantiation(backend.compiler.stringClass, registry);
+    needsList(registry,
+        'Needed to encode the arguments for throw NoSuchMethodError.');
+    needsString(registry,
+        'Needed to encode the name for throw NoSuchMethodError.');
   }
 
   void onThrowRuntimeError(Registry registry) {
@@ -3101,8 +3103,12 @@
         backend.compiler.objectClass.lookupLocalMember(
             Identifiers.noSuchMethod_),
         registry);
-    registerBackendInstantiation(backend.compiler.listClass, registry);
-    registerBackendInstantiation(backend.compiler.stringClass, registry);
+    needsInt(registry,
+        'Needed to encode the invocation kind of super.noSuchMethod.');
+    needsList(registry,
+        'Needed to encode the arguments of super.noSuchMethod.');
+    needsString(registry,
+        'Needed to encode the name of super.noSuchMethod.');
   }
 
   void onMapLiteral(ResolutionRegistry registry,
@@ -3132,6 +3138,29 @@
     registerBackendStaticInvocation(
         backend.compiler.symbolValidatedConstructor, registry);
   }
+
+  /// Called when resolving a prefix or postfix expression.
+  void onIncDecOperation(Registry registry) {
+    needsInt(registry, 'Needed for the `+ 1` or `- 1` operation of ++/--.');
+  }
+
+  /// Helper for registering that `int` is needed.
+  void needsInt(Registry registry, String reason) {
+    // TODO(johnniwinther): Register [reason] for use in dump-info.
+    registerBackendInstantiation(backend.compiler.intClass, registry);
+  }
+
+  /// Helper for registering that `List` is needed.
+  void needsList(Registry registry, String reason) {
+    // TODO(johnniwinther): Register [reason] for use in dump-info.
+    registerBackendInstantiation(backend.compiler.listClass, registry);
+  }
+
+  /// Helper for registering that `String` is needed.
+  void needsString(Registry registry, String reason) {
+    // TODO(johnniwinther): Register [reason] for use in dump-info.
+    registerBackendInstantiation(backend.compiler.stringClass, registry);
+  }
 }
 
 /// Records that [constant] is used by the element behind [registry].
diff --git a/pkg/compiler/lib/src/js_backend/codegen/task.dart b/pkg/compiler/lib/src/js_backend/codegen/task.dart
index 93a2320..16093d3 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/task.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/task.dart
@@ -38,6 +38,7 @@
 import '../../tree_ir/optimization/optimization.dart' as tree_opt;
 import '../../tree_ir/tree_ir_integrity.dart';
 import '../../cps_ir/cps_ir_nodes_sexpr.dart';
+import '../../cps_ir/type_mask_system.dart';
 
 class CpsFunctionCompiler implements FunctionCompiler {
   final ConstantSystem constantSystem;
@@ -48,6 +49,7 @@
 
   // TODO(karlklose,sigurdm): remove and update dart-doc of [compile].
   final FunctionCompiler fallbackCompiler;
+  TypeMaskSystem typeSystem;
 
   Tracer get tracer => compiler.tracer;
 
@@ -69,8 +71,8 @@
   /// Generates JavaScript code for `work.element`.
   js.Fun compile(CodegenWorkItem work) {
     AstElement element = work.element;
-    JavaScriptBackend backend = compiler.backend;
     return compiler.withCurrentElement(element, () {
+      typeSystem = new TypeMaskSystem(compiler);
       try {
         // TODO(karlklose): remove this fallback when we do not need it for
         // testing anymore.
@@ -170,10 +172,13 @@
       assert(checkCpsIntegrity(cpsNode));
     }
 
+    TypeMaskSystem typeSystem = new TypeMaskSystem(compiler);
+
     applyCpsPass(new RedundantJoinEliminator());
     applyCpsPass(new RedundantPhiEliminator());
-    applyCpsPass(new InsertRefinements(compiler.typesTask, compiler.world));
-    TypePropagator typePropagator = new TypePropagator(compiler, this);
+    applyCpsPass(new InsertRefinements(typeSystem));
+    TypePropagator typePropagator =
+        new TypePropagator(compiler, typeSystem, this);
     applyCpsPass(typePropagator);
     dumpTypedIR(cpsNode, typePropagator);
     applyCpsPass(new RemoveRefinements());
diff --git a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart b/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
index 4fa59bb..6209cda 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
@@ -250,6 +250,7 @@
     }
     node.arguments.insert(0, node.receiver);
     node.receiver = new Reference<Primitive>(newReceiver);
+    node.receiverIsIntercepted = true;
   }
 
   processInvokeMethodDirectly(InvokeMethodDirectly node) {
diff --git a/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart b/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
index 9bc3a86..5d0183a 100644
--- a/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
@@ -261,7 +261,7 @@
   const ForgetConstantElementVisitor();
 
   void visitElement(Element e, JavaScriptConstantCompiler constants) {
-    for (MetadataAnnotation data in e.metadata) {
+    for (MetadataAnnotation data in e.implementation.metadata) {
       constants.metadataConstantMap.remove(data);
       if (data.hasNode) {
         data.node.accept(new ForgetConstantNodeVisitor(constants));
diff --git a/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart b/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
index 7be572b..4f372c3 100644
--- a/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
@@ -28,6 +28,7 @@
 import '../enqueue.dart' show Enqueuer;
 import 'js_backend.dart' show JavaScriptBackend;
 import '../dart_types.dart' show DynamicType, InterfaceType;
+import 'package:pub_semver/pub_semver.dart';
 
 /// An analysis and optimization to remove unused entries from a `LookupMap`.
 ///
@@ -162,8 +163,12 @@
 
     // TODO(sigmund): add proper version resolution using the pub_semver package
     // when we introduce the next version.
-    String version = value.primitiveValue.slowToString();
-    if (version != '0.0.1') {
+    Version version;
+    try {
+      version = new Version.parse(value.primitiveValue.slowToString());
+    } catch (e) {}
+
+    if (version == null || !_validLookupMapVersionConstraint.allows(version)) {
       backend.compiler.reportInfo(lookupMapVersionVariable,
           MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP);
       return;
@@ -430,3 +435,6 @@
     }
   }
 }
+
+final _validLookupMapVersionConstraint =
+    new VersionConstraint.parse('^0.0.1');
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 6156b27..541aa7b 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -1144,12 +1144,12 @@
       LibraryElement library = element;
       name = libraryLongNames[library];
       if (name != null) return name;
-      name = library.getLibraryOrScriptName();
+      name = library.libraryOrScriptName;
       if (name.contains('.')) {
         // For libraries that have a library tag, we use the last part
         // of the fully qualified name as their base name. For all other
         // libraries, we use the first part of their filename.
-        name = library.hasLibraryName()
+        name = library.hasLibraryName
             ? name.substring(name.lastIndexOf('.') + 1)
             : name.substring(0, name.indexOf('.'));
       }
@@ -1346,7 +1346,7 @@
       return 'P';
     }
     return userGlobalObjects[
-        library.getLibraryOrScriptName().hashCode % userGlobalObjects.length];
+        library.libraryOrScriptName.hashCode % userGlobalObjects.length];
   }
 
   jsAst.Name deriveLazyInitializerName(jsAst.Name name) {
@@ -1988,4 +1988,4 @@
   global,
   instance,
   constant
-}
\ No newline at end of file
+}
diff --git a/pkg/compiler/lib/src/js_backend/namer_names.dart b/pkg/compiler/lib/src/js_backend/namer_names.dart
index 5d6eae3..60e1597 100644
--- a/pkg/compiler/lib/src/js_backend/namer_names.dart
+++ b/pkg/compiler/lib/src/js_backend/namer_names.dart
@@ -193,7 +193,8 @@
   int get hashCode => super.hashCode;
 
   finalize() {
-    assert(!isFinalized);
+    assert(invariant(NO_LOCATION_SPANNABLE, !isFinalized,
+        message: "TokenName($key)=$_name has already been finalized."));
     _name = _scope.getNextName();
   }
 }
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
index 6a5716b..d6748b9 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
@@ -1089,7 +1089,7 @@
 
     String libraryName =
         (!compiler.enableMinification || backend.mustRetainLibraryNames) ?
-        library.getLibraryName() :
+        library.libraryName :
         "";
 
     jsAst.Fun metadata = task.metadataCollector.buildMetadataFunction(library);
@@ -1982,10 +1982,6 @@
           ..add(js.statement('${typesAccess}.push.apply(${typesAccess}, '
                              '${namer.deferredTypesName});'));
 
-      // Sets the static state variable to the state of the current isolate
-      // (which is provided as second argument).
-      body.add(js.statement("${namer.staticStateHolder} = arguments[1];"));
-
       body.add(buildCompileTimeConstants(fragment.constants,
                                          isMainFragment: false));
       body.add(buildStaticNonFinalFieldInitializations(outputUnit));
@@ -1995,7 +1991,7 @@
       statements
           ..add(buildGeneratedBy())
           ..add(js.statement('${deferredInitializers}.current = '
-                             """function (#) {
+                             """function (#, ${namer.staticStateHolder}) {
                                   #
                                 }
                              """, [globalsHolder, body]));
diff --git a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
index 8ffda24..af55455 100644
--- a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
+++ b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
@@ -161,18 +161,13 @@
     if (!_mustEmitMetadataFor(element)) return null;
     return _compiler.withCurrentElement(element, () {
       List<jsAst.Expression> metadata = <jsAst.Expression>[];
-      Link link = element.metadata;
-      // TODO(ahe): Why is metadata sometimes null?
-      if (link != null) {
-        for (; !link.isEmpty; link = link.tail) {
-          MetadataAnnotation annotation = link.head;
-          ConstantValue constant =
-              _backend.constants.getConstantValueForMetadata(annotation);
-          if (constant == null) {
-            _compiler.internalError(annotation, 'Annotation value is null.');
-          } else {
-            metadata.add(_emitter.constantReference(constant));
-          }
+      for (MetadataAnnotation annotation in element.metadata) {
+        ConstantValue constant =
+            _backend.constants.getConstantValueForMetadata(annotation);
+        if (constant == null) {
+          _compiler.internalError(annotation, 'Annotation value is null.');
+        } else {
+          metadata.add(_emitter.constantReference(constant));
         }
       }
       if (metadata.isEmpty) return null;
@@ -289,12 +284,8 @@
     return _compiler.withCurrentElement(element, () {
       if (!_mustEmitMetadataFor(element)) return const <jsAst.DeferredNumber>[];
       List<jsAst.DeferredNumber> metadata = <jsAst.DeferredNumber>[];
-      Link link = element.metadata;
-      // TODO(ahe): Why is metadata sometimes null?
-      if (link != null) {
-        for (; !link.isEmpty; link = link.tail) {
-          metadata.add(reifyMetadata(link.head));
-        }
+      for (MetadataAnnotation annotation in element.metadata) {
+        metadata.add(reifyMetadata(annotation));
       }
       return metadata;
     });
diff --git a/pkg/compiler/lib/src/library_loader.dart b/pkg/compiler/lib/src/library_loader.dart
index 62ad6c6..9984f05d 100644
--- a/pkg/compiler/lib/src/library_loader.dart
+++ b/pkg/compiler/lib/src/library_loader.dart
@@ -17,17 +17,26 @@
     invariant;
 import 'diagnostics/messages.dart' show
     MessageKind;
+import 'diagnostics/spannable.dart' show
+    Spannable;
 import 'elements/elements.dart' show
     CompilationUnitElement,
     Element,
+    ImportElement,
+    ExportElement,
     LibraryElement,
     PrefixElement;
 import 'elements/modelx.dart' show
     CompilationUnitElementX,
     DeferredLoaderGetterElementX,
     ErroneousElementX,
+    ExportElementX,
+    ImportElementX,
     LibraryElementX,
-    PrefixElementX;
+    LibraryDependencyElementX,
+    PrefixElementX,
+    SyntheticImportElement;
+
 import 'native/native.dart' as native;
 import 'script.dart';
 import 'tree/tree.dart';
@@ -337,7 +346,7 @@
     Uri resourceUri = library.entryCompilationUnit.script.resourceUri;
     libraryResourceUriMap[resourceUri] = library;
 
-    String name = library.getLibraryOrScriptName();
+    String name = library.libraryOrScriptName;
     libraryNames[name] = library;
   }
 
@@ -374,21 +383,52 @@
     TagState tagState = new TagState();
 
     bool importsDartCore = false;
-    var libraryDependencies = new LinkBuilder<LibraryDependency>();
+    LinkBuilder<LibraryDependencyElementX> libraryDependencies =
+        new LinkBuilder<LibraryDependencyElementX>();
     Uri base = library.entryCompilationUnit.script.readableUri;
 
     return Future.forEach(library.tags, (LibraryTag tag) {
       return compiler.withCurrentElement(library, () {
+
+        Uri computeUri(LibraryDependency node) {
+          String tagUriString = node.uri.dartString.slowToString();
+          try {
+            return Uri.parse(tagUriString);
+          } on FormatException {
+            compiler.reportError(
+                node.uri,
+                MessageKind.INVALID_URI, {'uri': tagUriString});
+            return null;
+          }
+        }
+
         if (tag.isImport) {
-          Import import = tag;
-          tagState.checkTag(TagState.IMPORT_OR_EXPORT, import, compiler);
-          if (import.uri.dartString.slowToString() == 'dart:core') {
+          Uri uri = computeUri(tag);
+          if (uri == null) {
+            // Skip this erroneous import.
+            return new Future.value();
+          }
+          // TODO(johnniwinther): Create imports during parsing.
+          ImportElementX import =
+              new ImportElementX(library.entryCompilationUnit, tag, uri);
+          tagState.checkTag(TagState.IMPORT_OR_EXPORT, import.node, compiler);
+          if (import.uri == Uris.dart_core) {
             importsDartCore = true;
           }
+          library.addImportDeclaration(import);
           libraryDependencies.addLast(import);
         } else if (tag.isExport) {
-          tagState.checkTag(TagState.IMPORT_OR_EXPORT, tag, compiler);
-          libraryDependencies.addLast(tag);
+          Uri uri = computeUri(tag);
+          if (uri == null) {
+            // Skip this erroneous export.
+            return new Future.value();
+          }
+          // TODO(johnniwinther): Create exports during parsing.
+          ExportElementX export =
+              new ExportElementX(library.entryCompilationUnit, tag, uri);
+          tagState.checkTag(TagState.IMPORT_OR_EXPORT, export.node, compiler);
+          library.addExportDeclaration(export);
+          libraryDependencies.addLast(export);
         } else if (tag.isLibraryName) {
           tagState.checkTag(TagState.LIBRARY, tag, compiler);
           if (library.libraryTag == null) {
@@ -416,14 +456,19 @@
         if (!importsDartCore && library.canonicalUri != Uris.dart_core) {
           return createLibrary(handler, null, Uris.dart_core)
               .then((LibraryElement coreLibrary) {
-            handler.registerDependency(library, null, coreLibrary);
+            handler.registerDependency(library,
+                new SyntheticImportElement(
+                    library.entryCompilationUnit, Uris.dart_core),
+                coreLibrary);
           });
         }
       });
     }).then((_) {
-      return Future.forEach(libraryDependencies.toList(), (tag) {
+      return Future.forEach(libraryDependencies.toList(),
+          (LibraryDependencyElementX libraryDependency) {
         return compiler.withCurrentElement(library, () {
-          return registerLibraryFromTag(handler, library, tag);
+          return registerLibraryFromImportExport(
+              handler, library, libraryDependency);
         });
       });
     });
@@ -432,15 +477,14 @@
   void checkDuplicatedLibraryName(LibraryElement library) {
     if (library.isInternalLibrary) return;
     Uri resourceUri = library.entryCompilationUnit.script.resourceUri;
-    LibraryName tag = library.libraryTag;
     LibraryElement existing =
         libraryResourceUriMap.putIfAbsent(resourceUri, () => library);
     if (!identical(existing, library)) {
-      if (tag != null) {
+      if (library.hasLibraryName) {
         compiler.withCurrentElement(library, () {
-          compiler.reportWarning(tag.name,
+          compiler.reportWarning(library,
               MessageKind.DUPLICATED_LIBRARY_RESOURCE,
-              {'libraryName': tag.name,
+              {'libraryName': library.libraryName,
                'resourceUri': resourceUri,
                'canonicalUri1': library.canonicalUri,
                'canonicalUri2': existing.canonicalUri});
@@ -452,17 +496,17 @@
              'canonicalUri1': library.canonicalUri,
              'canonicalUri2': existing.canonicalUri});
       }
-    } else if (tag != null) {
-      String name = library.getLibraryOrScriptName();
+    } else if (library.hasLibraryName) {
+      String name = library.libraryOrScriptName;
       existing = libraryNames.putIfAbsent(name, () => library);
       if (!identical(existing, library)) {
         compiler.withCurrentElement(library, () {
-          compiler.reportWarning(tag.name,
+          compiler.reportWarning(library,
               MessageKind.DUPLICATED_LIBRARY_NAME,
               {'libraryName': name});
         });
         compiler.withCurrentElement(existing, () {
-          compiler.reportWarning(existing.libraryTag.name,
+          compiler.reportWarning(existing,
               MessageKind.DUPLICATED_LIBRARY_NAME,
               {'libraryName': name});
         });
@@ -501,25 +545,19 @@
    * export scope. If the tag does not contain a valid URI, then its dependency
    * is not registered in [handler].
    */
-  Future<Null> registerLibraryFromTag(LibraryDependencyHandler handler,
-                                      LibraryElement library,
-                                      LibraryDependency tag) {
+  Future<Null> registerLibraryFromImportExport(
+      LibraryDependencyHandler handler,
+      LibraryElement library,
+      LibraryDependencyElementX libraryDependency) {
     Uri base = library.canonicalUri;
-    String tagUriString = tag.uri.dartString.slowToString();
-    Uri resolvedUri;
-    try {
-      resolvedUri = base.resolve(tagUriString);
-    } on FormatException {
-      compiler.reportError(
-          tag.uri, MessageKind.INVALID_URI, {'uri': tagUriString});
-      // 'reportError' does not stop necessarily stop compilation
-      return new Future.value();
-    }
-    return createLibrary(handler, library, resolvedUri, tag.uri)
+    Uri resolvedUri = base.resolveUri(libraryDependency.uri);
+    return createLibrary(handler, library, resolvedUri, libraryDependency)
         .then((LibraryElement loadedLibrary) {
           if (loadedLibrary == null) return;
           compiler.withCurrentElement(library, () {
-            handler.registerDependency(library, tag, loadedLibrary);
+            libraryDependency.libraryDependency = loadedLibrary;
+            handler.registerDependency(
+                library, libraryDependency, loadedLibrary);
           });
         });
   }
@@ -534,10 +572,13 @@
     compiler.onLibraryCreated(library);
     libraryCanonicalUriMap[library.canonicalUri] = library;
     return compiler.onLibraryScanned(library, handler).then((_) {
-      return Future.forEach(library.tags, (LibraryTag tag) {
-        LibraryElement dependency = library.getLibraryFromTag(tag);
-        return createLibrary(handler, library, dependency.canonicalUri);
-      }).then((_) => library);
+      return Future.forEach(library.imports, (ImportElement import) {
+        return createLibrary(handler, library, import.uri);
+      }).then((_) {
+        return Future.forEach(library.exports, (ExportElement export) {
+          return createLibrary(handler, library, export.uri);
+        }).then((_) => library);
+      });
     });
   }
 
@@ -550,7 +591,7 @@
   Future<LibraryElement> createLibrary(LibraryDependencyHandler handler,
                                        LibraryElement importingLibrary,
                                        Uri resolvedUri,
-                                       [Node node]) {
+                                       [Spannable node]) {
     Uri readableUri =
         compiler.translateResolvedUri(importingLibrary, resolvedUri, node);
     LibraryElement library = libraryCanonicalUriMap[resolvedUri];
@@ -671,7 +712,7 @@
  * An [import] tag and the [importedLibrary] imported through [import].
  */
 class ImportLink {
-  final Import import;
+  final ImportElementX import;
   final LibraryElement importedLibrary;
 
   ImportLink(this.import, this.importedLibrary);
@@ -683,14 +724,19 @@
     assert(invariant(importingLibrary,
                      importedLibrary.exportsHandled,
                      message: 'Exports not handled on $importedLibrary'));
-    var combinatorFilter = new CombinatorFilter.fromTag(import);
-    if (import != null && import.prefix != null) {
-      String prefix = import.prefix.source;
+    Import tag = import.node;
+    CombinatorFilter combinatorFilter =
+        new CombinatorFilter.fromTag(tag);
+    if (tag != null && tag.prefix != null) {
+      String prefix = tag.prefix.source;
       Element existingElement = importingLibrary.find(prefix);
-      PrefixElement prefixElement;
+      PrefixElementX prefixElement;
       if (existingElement == null || !existingElement.isPrefix) {
-        prefixElement = new PrefixElementX(prefix,
-            importingLibrary.entryCompilationUnit, import.getBeginToken());
+        prefixElement = new PrefixElementX(
+            prefix,
+            importingLibrary.entryCompilationUnit,
+            tag.getBeginToken(),
+            tag.isDeferred ? import : null);
       } else {
         prefixElement = existingElement;
       }
@@ -699,14 +745,11 @@
         if (combinatorFilter.exclude(element)) return;
         prefixElement.addImport(element, import, compiler);
       });
-      if (import.isDeferred) {
+      import.prefix = prefixElement;
+      if (prefixElement.isDeferred) {
         prefixElement.addImport(
             new DeferredLoaderGetterElementX(prefixElement),
             import, compiler);
-        // TODO(sigurdm): When we remove support for the annotation based
-        // syntax the [PrefixElement] constructor should receive this
-        // information.
-        prefixElement.markAsDeferred(import);
       }
     } else {
       importedLibrary.forEachExport((Element element) {
@@ -725,13 +768,13 @@
  * the library dependency graph.
  */
 class ExportLink {
-  final Export export;
+  final ExportElementX export;
   final CombinatorFilter combinatorFilter;
   final LibraryDependencyNode exportNode;
 
-  ExportLink(Export export, LibraryDependencyNode this.exportNode)
+  ExportLink(ExportElementX export, LibraryDependencyNode this.exportNode)
       : this.export = export,
-        this.combinatorFilter = new CombinatorFilter.fromTag(export);
+        this.combinatorFilter = new CombinatorFilter.fromTag(export.node);
 
   /**
    * Exports [element] to the dependent library unless [element] is filtered by
@@ -780,11 +823,11 @@
    * The export scope for [library] which is gradually computed by the work-list
    * computation in [LibraryDependencyHandler.computeExports].
    */
-  Map<String, Element> exportScope =
-      new Map<String, Element>();
+  Map<String, Element> exportScope = <String, Element>{};
 
   /// Map from exported elements to the export directives that exported them.
-  Map<Element, Link<Export>> exporters = new Map<Element, Link<Export>>();
+  Map<Element, Link<ExportElement>> exporters =
+      <Element, Link<ExportElement>>{};
 
   /**
    * The set of exported elements that need to be propageted to dependent
@@ -792,8 +835,8 @@
    * [LibraryDependencyHandler.computeExports]. Each export element is mapped
    * to a list of exports directives that export it.
    */
-  Map<Element, Link<Export>> pendingExportMap =
-      new Map<Element, Link<Export>>();
+  Map<Element, Link<ExportElement>> pendingExportMap =
+      <Element, Link<ExportElement>>{};
 
   LibraryDependencyNode(this.library);
 
@@ -801,7 +844,7 @@
    * Registers that the library of this node imports [importLibrary] through the
    * [import] tag.
    */
-  void registerImportDependency(Import import,
+  void registerImportDependency(ImportElementX import,
                                 LibraryElement importedLibrary) {
     imports = imports.prepend(new ImportLink(import, importedLibrary));
   }
@@ -810,7 +853,7 @@
    * Registers that the library of this node is exported by
    * [exportingLibraryNode] through the [export] tag.
    */
-  void registerExportDependency(Export export,
+  void registerExportDependency(ExportElementX export,
                                 LibraryDependencyNode exportingLibraryNode) {
     // Register the exported library in the exporting library node.
     exportingLibraryNode.exports =
@@ -827,22 +870,22 @@
    */
   void registerInitialExports() {
     for (Element element in library.getNonPrivateElementsInScope()) {
-      pendingExportMap[element] = const Link<Export>();
+      pendingExportMap[element] = const Link<ExportElement>();
     }
   }
 
   void registerHandledExports(LibraryElement exportedLibraryElement,
-                              Export export,
+                              ExportElementX export,
                               CombinatorFilter filter) {
     assert(invariant(library, exportedLibraryElement.exportsHandled));
-    for (Element exportedElement in exportedLibraryElement.exports) {
+    exportedLibraryElement.forEachExport((Element exportedElement) {
       if (!filter.exclude(exportedElement)) {
-        Link<Export> exports =
+        Link<ExportElement> exports =
             pendingExportMap.putIfAbsent(exportedElement,
-                                         () => const Link<Export>());
+                                         () => const Link<ExportElement>());
         pendingExportMap[exportedElement] = exports.prepend(export);
       }
-    }
+    });
   }
 
   /**
@@ -864,9 +907,9 @@
   /**
    * Copies and clears pending export set for this node.
    */
-  Map<Element, Link<Export>> pullPendingExports() {
-    Map<Element, Link<Export>> pendingExports =
-        new Map<Element, Link<Export>>.from(pendingExportMap);
+  Map<Element, Link<ExportElement>> pullPendingExports() {
+    Map<Element, Link<ExportElement>> pendingExports =
+        new Map<Element, Link<ExportElement>>.from(pendingExportMap);
     pendingExportMap.clear();
     return pendingExports;
   }
@@ -876,17 +919,17 @@
    * is a duplicate, an error element is inserted into the export scope.
    */
   Element addElementToExportScope(Compiler compiler, Element element,
-                                  Link<Export> exports) {
+                                  Link<ExportElement> exports) {
     String name = element.name;
 
     void reportDuplicateExport(Element duplicate,
-                               Link<Export> duplicateExports,
+                               Link<ExportElement> duplicateExports,
                                {bool reportError: true}) {
       assert(invariant(library, !duplicateExports.isEmpty,
           message: "No export for $duplicate from ${duplicate.library} "
                    "in $library."));
       compiler.withCurrentElement(library, () {
-        for (Export export in duplicateExports) {
+        for (ExportElement export in duplicateExports) {
           if (reportError) {
             compiler.reportError(export,
                 MessageKind.DUPLICATE_EXPORT, {'name': name});
@@ -900,7 +943,7 @@
     }
 
     void reportDuplicateExportDecl(Element duplicate,
-                                   Link<Export> duplicateExports) {
+                                   Link<ExportElement> duplicateExports) {
       assert(invariant(library, !duplicateExports.isEmpty,
           message: "No export for $duplicate from ${duplicate.library} "
                    "in $library."));
@@ -922,7 +965,7 @@
         exporters[element] = exports;
       } else {
         // Declared elements hide exported elements.
-        Link<Export> existingExports = exporters[existingElement];
+        Link<ExportElement> existingExports = exporters[existingElement];
         reportDuplicateExport(existingElement, existingExports);
         reportDuplicateExport(element, exports, reportError: false);
         reportDuplicateExportDecl(existingElement, existingExports);
@@ -957,12 +1000,12 @@
    * the pending export set was modified. The combinators of [export] are used
    * to filter the element.
    */
-  bool addElementToPendingExports(Element element, Export export) {
+  bool addElementToPendingExports(Element element, ExportElement export) {
     bool changed = false;
     if (!identical(exportScope[element.name], element)) {
-      Link<Export> exports = pendingExportMap.putIfAbsent(element, () {
+      Link<ExportElement> exports = pendingExportMap.putIfAbsent(element, () {
         changed = true;
-        return const Link<Export>();
+        return const Link<ExportElement>();
       });
       pendingExportMap[element] = exports.prepend(export);
     }
@@ -1006,8 +1049,8 @@
     bool changed = true;
     while (changed) {
       changed = false;
-      Map<LibraryDependencyNode, Map<Element, Link<Export>>> tasks =
-          new Map<LibraryDependencyNode, Map<Element, Link<Export>>>();
+      Map<LibraryDependencyNode, Map<Element, Link<ExportElement>>> tasks =
+          new Map<LibraryDependencyNode, Map<Element, Link<ExportElement>>>();
 
       // Locally defined elements take precedence over exported
       // elements.  So we must propagate local elements first.  We
@@ -1015,12 +1058,13 @@
       // propagating.  This enforces that we handle exports
       // breadth-first, with locally defined elements being level 0.
       nodeMap.forEach((_, LibraryDependencyNode node) {
-        Map<Element, Link<Export>> pendingExports = node.pullPendingExports();
+        Map<Element, Link<ExportElement>> pendingExports =
+            node.pullPendingExports();
         tasks[node] = pendingExports;
       });
       tasks.forEach((LibraryDependencyNode node,
-                     Map<Element, Link<Export>> pendingExports) {
-        pendingExports.forEach((Element element, Link<Export> exports) {
+                     Map<Element, Link<ExportElement>> pendingExports) {
+        pendingExports.forEach((Element element, Link<ExportElement> exports) {
           element = node.addElementToExportScope(compiler, element, exports);
           if (node.propagateElement(element)) {
             changed = true;
@@ -1042,23 +1086,20 @@
     });
   }
 
-  /**
-   * Registers that [library] depends on [loadedLibrary] through [tag].
-   */
+  /// Registers that [library] depends on [loadedLibrary] through
+  /// [libraryDependency].
   void registerDependency(LibraryElementX library,
-                          LibraryDependency tag,
+                          LibraryDependencyElementX libraryDependency,
                           LibraryElement loadedLibrary) {
-    if (tag != null) {
-      library.recordResolvedTag(tag, loadedLibrary);
-    }
-    if (tag is Export) {
+    if (libraryDependency.isExport) {
       // [loadedLibrary] is exported by [library].
       LibraryDependencyNode exportingNode = nodeMap[library];
       if (loadedLibrary.exportsHandled) {
         // Export scope already computed on [loadedLibrary].
-        var combinatorFilter = new CombinatorFilter.fromTag(tag);
+        CombinatorFilter combinatorFilter =
+            new CombinatorFilter.fromTag(libraryDependency.node);
         exportingNode.registerHandledExports(
-            loadedLibrary, tag, combinatorFilter);
+            loadedLibrary, libraryDependency, combinatorFilter);
         return;
       }
       LibraryDependencyNode exportedNode = nodeMap[loadedLibrary];
@@ -1066,13 +1107,13 @@
           message: "$loadedLibrary has not been registered"));
       assert(invariant(library, exportingNode != null,
           message: "$library has not been registered"));
-      exportedNode.registerExportDependency(tag, exportingNode);
-    } else if (tag == null || tag is Import) {
+      exportedNode.registerExportDependency(libraryDependency, exportingNode);
+    } else if (libraryDependency == null || libraryDependency.isImport) {
       // [loadedLibrary] is imported by [library].
       LibraryDependencyNode importingNode = nodeMap[library];
       assert(invariant(library, importingNode != null,
           message: "$library has not been registered"));
-      importingNode.registerImportDependency(tag, loadedLibrary);
+      importingNode.registerImportDependency(libraryDependency, loadedLibrary);
     }
   }
 
diff --git a/pkg/compiler/lib/src/mirrors/dart2js_library_mirror.dart b/pkg/compiler/lib/src/mirrors/dart2js_library_mirror.dart
index 38925b5..2d43e7d 100644
--- a/pkg/compiler/lib/src/mirrors/dart2js_library_mirror.dart
+++ b/pkg/compiler/lib/src/mirrors/dart2js_library_mirror.dart
@@ -4,7 +4,6 @@
 
 part of dart2js.mirrors;
 
-
 class Dart2JsLibraryMirror
     extends Dart2JsElementMirror
     with ObjectMirrorMixin, ContainerMixin
@@ -18,7 +17,8 @@
     throw new UnsupportedError('LibraryMirror.operator [] unsupported.');
   }
 
-  LibraryElement get _element => super._element;
+  // TODO(johnniwinther): Avoid the need for [LibraryElementX].
+  LibraryElementX get _element => super._element;
 
   Uri get uri => _element.canonicalUri;
 
@@ -33,7 +33,7 @@
    * 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 => _element.getLibraryOrScriptName();
+  String get _simpleNameString => _element.libraryOrScriptName;
 
   Symbol get qualifiedName => simpleName;
 
@@ -75,17 +75,33 @@
 
   void _ensureLibraryDependenciesAnalyzed() {
     if (_libraryDependencies == null) {
+      // TODO(johnniwinther): Support order of declarations on [LibraryElement].
+      Map<LibraryDependency, Dart2JsLibraryDependencyMirror> mirrorMap =
+          <LibraryDependency, Dart2JsLibraryDependencyMirror>{};
+
+      void addLibraryDependency(LibraryDependency libraryDependency,
+                                LibraryElement targetLibraryElement) {
+        assert(targetLibraryElement != null);
+        LibraryMirror targetLibrary =
+            mirrorSystem._getLibrary(targetLibraryElement);
+        mirrorMap[libraryDependency] = new Dart2JsLibraryDependencyMirror(
+            libraryDependency, this, targetLibrary);
+      }
+      for (ImportElement import in _element.imports) {
+        addLibraryDependency(import.node, import.importedLibrary);
+      }
+      for (ExportElement export in _element.exports) {
+        addLibraryDependency(export.node, export.exportedLibrary);
+      }
+
       _libraryDependencies = <LibraryDependencySourceMirror>[];
+
       for (LibraryTag node in _element.tags) {
         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));
+          Dart2JsLibraryDependencyMirror mirror = mirrorMap[libraryDependency];
+          assert(mirror != null);
+          _libraryDependencies.add(mirror);
         }
       }
     }
diff --git a/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart b/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart
index c35fd8b..3834728 100644
--- a/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart
+++ b/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart
@@ -18,6 +18,8 @@
 import '../diagnostics/spannable.dart' show
     NO_LOCATION_SPANNABLE;
 import '../elements/elements.dart';
+import '../elements/modelx.dart' show
+    LibraryElementX;
 import '../resolution/scope.dart' show
     Scope;
 import '../script.dart';
diff --git a/pkg/compiler/lib/src/mirrors_used.dart b/pkg/compiler/lib/src/mirrors_used.dart
index fac0234..553f9cc 100644
--- a/pkg/compiler/lib/src/mirrors_used.dart
+++ b/pkg/compiler/lib/src/mirrors_used.dart
@@ -28,6 +28,7 @@
 import 'elements/elements.dart' show
     ClassElement,
     Element,
+    ImportElement,
     LibraryElement,
     MetadataAnnotation,
     ScopeContainerElement,
@@ -199,12 +200,10 @@
         new Map<LibraryElement, List<MirrorUsage>>();
     for (LibraryElement library in compiler.libraryLoader.libraries) {
       if (library.isInternalLibrary) continue;
-      for (LibraryTag tag in library.tags) {
-        Import importTag = tag.asImport();
-        if (importTag == null) continue;
+      for (ImportElement import in library.imports) {
         compiler.withCurrentElement(library, () {
           List<MirrorUsage> usages =
-              mirrorsUsedOnLibraryTag(library, importTag);
+              mirrorsUsedOnLibraryTag(library, import);
           if (usages != null) {
             List<MirrorUsage> existing = result[library];
             if (existing != null) {
@@ -255,13 +254,13 @@
   /// Find @MirrorsUsed annotations on the given import [tag] in [library]. The
   /// annotations are represented as [MirrorUsage].
   List<MirrorUsage> mirrorsUsedOnLibraryTag(LibraryElement library,
-                                            Import tag) {
-    LibraryElement importedLibrary = library.getLibraryFromTag(tag);
+                                            ImportElement import) {
+    LibraryElement importedLibrary = import.importedLibrary;
     if (importedLibrary != compiler.mirrorsLibrary) {
       return null;
     }
     List<MirrorUsage> result = <MirrorUsage>[];
-    for (MetadataAnnotation metadata in tag.metadata) {
+    for (MetadataAnnotation metadata in import.metadata) {
       metadata.ensureResolved(compiler);
       ConstantValue value =
           compiler.constants.getConstantValue(metadata.constant);
@@ -476,8 +475,8 @@
         LibraryElement libraryCandiate;
         String libraryNameCandiate;
         for (LibraryElement l in compiler.libraryLoader.libraries) {
-          if (l.hasLibraryName()) {
-            String libraryName = l.getLibraryOrScriptName();
+          if (l.hasLibraryName) {
+            String libraryName = l.libraryOrScriptName;
             if (string == libraryName) {
               // Found an exact match.
               libraryCandiate = l;
@@ -535,7 +534,7 @@
           compiler.reportHint(
               spannable, MessageKind.MIRRORS_CANNOT_RESOLVE_IN_LIBRARY,
               {'name': identifiers[0],
-               'library': library.getLibraryOrScriptName()});
+               'library': library.libraryOrScriptName});
         } else {
           compiler.reportHint(
               spannable, MessageKind.MIRRORS_CANNOT_FIND_IN_ELEMENT,
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index edbefd1..23bf702 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -652,7 +652,7 @@
   }
 
   void _overrideWithAnnotations(Element element, Compiler compiler) {
-    if (element.metadata.isEmpty) return;
+    if (element.implementation.metadata.isEmpty) return;
 
     DartType lookup(String name) {
       Element e = element.buildScope().lookup(name);
@@ -685,10 +685,8 @@
   static _collect(Element element, Compiler compiler, Element annotationClass,
                   lookup(str)) {
     var types = null;
-    for (Link<MetadataAnnotation> link = element.metadata;
-         !link.isEmpty;
-         link = link.tail) {
-      MetadataAnnotation annotation = link.head.ensureResolved(compiler);
+    for (MetadataAnnotation annotation in element.implementation.metadata) {
+      annotation.ensureResolved(compiler);
       ConstantValue value =
           compiler.constants.getConstantValue(annotation.constant);
       if (!value.isConstructedObject) continue;
diff --git a/pkg/compiler/lib/src/native/enqueue.dart b/pkg/compiler/lib/src/native/enqueue.dart
index 1f9b47b..3de82e0 100644
--- a/pkg/compiler/lib/src/native/enqueue.dart
+++ b/pkg/compiler/lib/src/native/enqueue.dart
@@ -314,10 +314,8 @@
   String findJsNameFromAnnotation(Element element) {
     String name = null;
     ClassElement annotationClass = annotationJsNameClass;
-    for (Link<MetadataAnnotation> link = element.metadata;
-         !link.isEmpty;
-         link = link.tail) {
-      MetadataAnnotation annotation = link.head.ensureResolved(compiler);
+    for (MetadataAnnotation annotation in element.implementation.metadata) {
+      annotation.ensureResolved(compiler);
       ConstantValue value =
           compiler.constants.getConstantValue(annotation.constant);
       if (!value.isConstructedObject) continue;
diff --git a/pkg/compiler/lib/src/parser/element_listener.dart b/pkg/compiler/lib/src/parser/element_listener.dart
index 00ec535..8473d03 100644
--- a/pkg/compiler/lib/src/parser/element_listener.dart
+++ b/pkg/compiler/lib/src/parser/element_listener.dart
@@ -37,7 +37,8 @@
     EOF_TOKEN;
 import '../tree/tree.dart';
 import '../util/util.dart' show
-    Link;
+    Link,
+    LinkBuilder;
 
 import 'partial_elements.dart' show
     PartialClassElement,
@@ -69,7 +70,8 @@
 
   Link<Node> nodes = const Link<Node>();
 
-  Link<MetadataAnnotation> metadata = const Link<MetadataAnnotation>();
+  LinkBuilder<MetadataAnnotation> metadata =
+      new LinkBuilder<MetadataAnnotation>();
 
   /// Records a stack of booleans for each member parsed (a stack is used to
   /// support nested members which isn't currently possible, but it also serves
@@ -212,9 +214,9 @@
 
   void endTopLevelDeclaration(Token token) {
     if (!metadata.isEmpty) {
-      recoverableError(metadata.head.beginToken,
+      recoverableError(metadata.first.beginToken,
                        'Metadata not supported here.');
-      metadata = const Link<MetadataAnnotation>();
+      metadata.clear();
     }
   }
 
@@ -595,19 +597,15 @@
     compilationUnitElement.addMember(element, listener);
   }
 
-  Link<MetadataAnnotation> popMetadata(ElementX element) {
-    var result = const Link<MetadataAnnotation>();
-    for (Link link = metadata; !link.isEmpty; link = link.tail) {
-      element.addMetadata(link.head);
-      // Reverse the list as is implicitly done by addMetadata.
-      result = result.prepend(link.head);
-    }
-    metadata = const Link<MetadataAnnotation>();
+  List<MetadataAnnotation> popMetadata(ElementX element) {
+    List<MetadataAnnotation> result = metadata.toList();
+    element.metadata = result;
+    metadata.clear();
     return result;
   }
 
   void pushMetadata(MetadataAnnotation annotation) {
-    metadata = metadata.prepend(annotation);
+    metadata.addLast(annotation);
   }
 
   void addLibraryTag(LibraryTag tag) {
diff --git a/pkg/compiler/lib/src/parser/member_listener.dart b/pkg/compiler/lib/src/parser/member_listener.dart
index 08656d3..c9cbd48 100644
--- a/pkg/compiler/lib/src/parser/member_listener.dart
+++ b/pkg/compiler/lib/src/parser/member_listener.dart
@@ -153,10 +153,7 @@
   }
 
   void addMetadata(ElementX memberElement) {
-    for (Link link = metadata; !link.isEmpty; link = link.tail) {
-      memberElement.addMetadata(link.head);
-    }
-    metadata = const Link<MetadataAnnotation>();
+    memberElement.metadata = metadata.toList();
   }
 
   void addMember(ElementX memberElement) {
diff --git a/pkg/compiler/lib/src/patch_parser.dart b/pkg/compiler/lib/src/patch_parser.dart
index 0f30084..ee2995f 100644
--- a/pkg/compiler/lib/src/patch_parser.dart
+++ b/pkg/compiler/lib/src/patch_parser.dart
@@ -386,10 +386,7 @@
   static checkAnnotation(Compiler compiler,
                          Element element,
                          EagerAnnotationHandler handler) {
-    for (Link<MetadataAnnotation> link = element.metadata;
-         !link.isEmpty;
-         link = link.tail) {
-      MetadataAnnotation annotation = link.head;
+    for (MetadataAnnotation annotation in element.implementation.metadata) {
       var result = handler.apply(compiler, element, annotation);
       if (result != null) {
         // TODO(johnniwinther): Perform this check in
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index dbfdd13..9d8b71e 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -1846,7 +1846,7 @@
     registry.registerThrowNoSuchMethod();
     ErroneousElement error = reportAndCreateErroneousElement(
         node, name.text, MessageKind.PRIVATE_ACCESS,
-        {'libraryName': member.library.getLibraryOrScriptName(),
+        {'libraryName': member.library.libraryOrScriptName,
          'name': name});
     // TODO(johnniwinther): Add an [AccessSemantics] for unresolved static
     // member access.
@@ -1862,7 +1862,7 @@
     registry.registerThrowNoSuchMethod();
     ErroneousElement error = reportAndCreateErroneousElement(
         node, name.text, MessageKind.PRIVATE_ACCESS,
-        {'libraryName': member.library.getLibraryOrScriptName(),
+        {'libraryName': member.library.libraryOrScriptName,
          'name': name});
     // TODO(johnniwinther): Add an [AccessSemantics] for unresolved static
     // member access.
@@ -1953,8 +1953,7 @@
     } else {
       semantics = new StaticAccess.typeParameterTypeLiteral(element);
     }
-    registry.registerClassUsingVariableExpression(element.enclosingClass);
-    registry.registerTypeVariableExpression();
+    registry.registerTypeVariableExpression(element);
 
     registry.useElement(node, element);
     registry.registerTypeLiteral(node, element.type);
@@ -2007,6 +2006,11 @@
             MessageKind.ASSIGNING_TYPE, const {});
       }
 
+      if (node.isComplex) {
+        // We read the type variable before trying write to it.
+        registry.registerTypeVariableExpression(element);
+      }
+
       // TODO(23998): Remove this when all information goes through
       // the [SendStructure].
       registry.useElement(node, error);
@@ -3422,6 +3426,7 @@
           ? new PrefixStructure(semantics, operator)
           : new PostfixStructure(semantics, operator);
       registry.registerSendStructure(node, sendStructure);
+      registry.registerIncDecOperation();
     } else {
       Node rhs = node.arguments.head;
       visitExpression(rhs);
@@ -3783,7 +3788,7 @@
       }
     }
     if (node.metadata != null) {
-      variables.metadata =
+      variables.metadataInternal =
           compiler.resolver.resolveMetadata(enclosingElement, node);
     }
     visitor.visit(node.definitions);
@@ -3892,6 +3897,21 @@
     }
     if (node.isConst) {
       analyzeConstantDeferred(node);
+
+      // TODO(johnniwinther): Compute this in the [ConstructorResolver].
+      // Check that the constructor is not deferred.
+      Send send = node.send.selector.asSend();
+      if (send != null) {
+        // Of the form `const a.b(...)`.
+        if (compiler.deferredLoadTask.deferredPrefixElement(
+                send, registry.mapping) != null) {
+          // `a` is a deferred prefix.
+          isValidAsConstant = false;
+          // TODO(johnniwinther): Create an [ErroneousConstantExpression] here
+          // when constants are only created during resolution.
+        }
+      }
+
       if (isValidAsConstant &&
           constructor.isConst &&
           argumentsResult.isValidAsConstant) {
diff --git a/pkg/compiler/lib/src/resolution/registry.dart b/pkg/compiler/lib/src/resolution/registry.dart
index 6a40754..625f8f0 100644
--- a/pkg/compiler/lib/src/resolution/registry.dart
+++ b/pkg/compiler/lib/src/resolution/registry.dart
@@ -455,12 +455,8 @@
     backend.resolutionCallbacks.onSuperNoSuchMethod(this);
   }
 
-  void registerClassUsingVariableExpression(ClassElement element) {
-    backend.registerClassUsingVariableExpression(element);
-  }
-
-  void registerTypeVariableExpression() {
-    backend.resolutionCallbacks.onTypeVariableExpression(this);
+  void registerTypeVariableExpression(TypeVariableElement element) {
+    backend.resolutionCallbacks.onTypeVariableExpression(this, element);
   }
 
   void registerTypeLiteral(Send node, DartType type) {
@@ -610,6 +606,10 @@
     backend.resolutionCallbacks.onAsyncForIn(node, this);
   }
 
+  void registerIncDecOperation() {
+    backend.resolutionCallbacks.onIncDecOperation(this);
+  }
+
   void registerTryStatement() {
     mapping.containsTryStatement = true;
   }
diff --git a/pkg/compiler/lib/src/resolution/resolution.dart b/pkg/compiler/lib/src/resolution/resolution.dart
index 5874251..a137493 100644
--- a/pkg/compiler/lib/src/resolution/resolution.dart
+++ b/pkg/compiler/lib/src/resolution/resolution.dart
@@ -78,7 +78,7 @@
       }
 
       WorldImpact processMetadata([WorldImpact result]) {
-        for (MetadataAnnotation metadata in element.metadata) {
+        for (MetadataAnnotation metadata in element.implementation.metadata) {
           metadata.ensureResolved(compiler);
         }
         return result;
@@ -594,11 +594,11 @@
   }
 
   void _postProcessClassElement(BaseClassElementX element) {
-    for (MetadataAnnotation metadata in element.metadata) {
+    for (MetadataAnnotation metadata in element.implementation.metadata) {
       metadata.ensureResolved(compiler);
       ConstantValue value =
           compiler.constants.getConstantValue(metadata.constant);
-      if (!element.isProxy && value == compiler.proxyConstant) {
+      if (!element.isProxy && compiler.isProxyConstant(value)) {
         element.isProxy = true;
       }
     }
@@ -611,7 +611,7 @@
     element.forEachMember((_, Element member) {
       if (!member.isInstanceMember) {
         compiler.withCurrentElement(member, () {
-          for (MetadataAnnotation metadata in member.metadata) {
+          for (MetadataAnnotation metadata in member.implementation.metadata) {
             metadata.ensureResolved(compiler);
           }
         });
@@ -996,6 +996,7 @@
       // [compileMetadata].
       annotation.constant =
           constantCompiler.compileMetadata(annotation, node, registry.mapping);
+      constantCompiler.evaluate(annotation.constant);
       // TODO(johnniwinther): Register the relation between the annotation
       // and the annotated element instead. This will allow the backend to
       // retrieve the backend constant and only register metadata on the
@@ -1009,17 +1010,16 @@
     compiler.reportError(node, kind, arguments);
   }
 
-  Link<MetadataAnnotation> resolveMetadata(Element element,
+  List<MetadataAnnotation> resolveMetadata(Element element,
                                            VariableDefinitions node) {
-    LinkBuilder<MetadataAnnotation> metadata =
-        new LinkBuilder<MetadataAnnotation>();
+    List<MetadataAnnotation> metadata = <MetadataAnnotation>[];
     for (Metadata annotation in node.metadata.nodes) {
       ParameterMetadataAnnotation metadataAnnotation =
           new ParameterMetadataAnnotation(annotation);
       metadataAnnotation.annotatedElement = element;
-      metadata.addLast(metadataAnnotation.ensureResolved(compiler));
+      metadata.add(metadataAnnotation.ensureResolved(compiler));
     }
-    return metadata.toLink();
+    return metadata;
   }
 }
 
diff --git a/pkg/compiler/lib/src/resolution/signatures.dart b/pkg/compiler/lib/src/resolution/signatures.dart
index 4dfd954..2a6aa6d 100644
--- a/pkg/compiler/lib/src/resolution/signatures.dart
+++ b/pkg/compiler/lib/src/resolution/signatures.dart
@@ -102,7 +102,8 @@
     currentDefinitions = node;
     FormalElementX element = definition.accept(this);
     if (currentDefinitions.metadata != null) {
-      element.metadata = compiler.resolver.resolveMetadata(element, node);
+      element.metadataInternal =
+          compiler.resolver.resolveMetadata(element, node);
     }
     currentDefinitions = null;
     return element;
diff --git a/pkg/compiler/lib/src/serialization/element_serialization.dart b/pkg/compiler/lib/src/serialization/element_serialization.dart
index c72f916..9ef5187 100644
--- a/pkg/compiler/lib/src/serialization/element_serialization.dart
+++ b/pkg/compiler/lib/src/serialization/element_serialization.dart
@@ -39,6 +39,9 @@
   TYPEVARIABLE,
   PARAMETER,
   INITIALIZING_FORMAL,
+  IMPORT,
+  EXPORT,
+  PREFIX,
 }
 
 /// Set of serializers used to serialize different kinds of elements by
@@ -58,6 +61,9 @@
     const TypedefSerializer(),
     const TypeVariableSerializer(),
     const ParameterSerializer(),
+    const ImportSerializer(),
+    const ExportSerializer(),
+    const PrefixSerializer(),
 ];
 
 /// Interface for a function that can serialize a set of element kinds.
@@ -150,32 +156,22 @@
                  SerializedElementKind kind) {
     encoder.setUri(
         Key.CANONICAL_URI, element.canonicalUri, element.canonicalUri);
-    encoder.setString(Key.LIBRARY_NAME, element.getLibraryName());
+    encoder.setString(Key.LIBRARY_NAME, element.libraryName);
     SerializerUtil.serializeMembers(element, encoder);
     encoder.setElement(Key.COMPILATION_UNIT, element.entryCompilationUnit);
     encoder.setElements(
         Key.COMPILATION_UNITS, element.compilationUnits.toList());
-    ListEncoder tags = encoder.createList(Key.TAGS);
+    encoder.setElements(Key.IMPORTS, element.imports);
+    encoder.setElements(Key.EXPORTS, element.exports);
 
-    for (LibraryTag tag in element.tags) {
-      if (tag is Import) {
-        ObjectEncoder importTag = tags.createObject();
-        importTag.setString(Key.KIND, 'import');
-        importTag.setElement(Key.LIBRARY, element.getLibraryFromTag(tag));
-      } else if (tag is Export) {
-        ObjectEncoder exportTag = tags.createObject();
-        exportTag.setString(Key.KIND, 'export');
-        exportTag.setElement(Key.LIBRARY, element.getLibraryFromTag(tag));
-      }
-    }
+    List<Element> importedElements = <Element>[];
+    element.forEachImport(SerializerUtil.flattenElements(importedElements));
+    encoder.setElements(Key.IMPORT_SCOPE, importedElements);
 
-    List<Element> imports = <Element>[];
-    element.forEachImport(SerializerUtil.flattenElements(imports));
-    encoder.setElements(Key.IMPORTS, imports);
+    List<Element> exportedElements = <Element>[];
+    element.forEachExport(SerializerUtil.flattenElements(exportedElements));
+    encoder.setElements(Key.EXPORT_SCOPE, exportedElements);
 
-    List<Element> exports = <Element>[];
-    element.forEachExport(SerializerUtil.flattenElements(exports));
-    encoder.setElements(Key.EXPORTS, exports);
   }
 }
 
@@ -425,6 +421,75 @@
   }
 }
 
+class ImportSerializer implements ElementSerializer {
+  const ImportSerializer();
+
+  SerializedElementKind getSerializedKind(Element element) {
+    if (element.isImport) {
+      return SerializedElementKind.IMPORT;
+    }
+    return null;
+  }
+
+  void serialize(ImportElement element,
+                 ObjectEncoder encoder,
+                 SerializedElementKind kind) {
+    encoder.setElement(Key.LIBRARY, element.library);
+    encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
+    encoder.setElement(Key.LIBRARY_DEPENDENCY, element.importedLibrary);
+    if (element.prefix != null) {
+      encoder.setElement(Key.PREFIX, element.prefix);
+    }
+    encoder.setBool(Key.IS_DEFERRED, element.isDeferred);
+    // TODO(johnniwinther): What is the base for the URI?
+    encoder.setUri(Key.URI, element.uri, element.uri);
+  }
+}
+
+class ExportSerializer implements ElementSerializer {
+  const ExportSerializer();
+
+  SerializedElementKind getSerializedKind(Element element) {
+    if (element.isExport) {
+      return SerializedElementKind.EXPORT;
+    }
+    return null;
+  }
+
+  void serialize(ExportElement element,
+                 ObjectEncoder encoder,
+                 SerializedElementKind kind) {
+    encoder.setElement(Key.LIBRARY, element.library);
+    encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
+    encoder.setElement(Key.LIBRARY_DEPENDENCY, element.exportedLibrary);
+    // TODO(johnniwinther): What is the base for the URI?
+    encoder.setUri(Key.URI, element.uri, element.uri);
+  }
+}
+
+class PrefixSerializer implements ElementSerializer {
+  const PrefixSerializer();
+
+  SerializedElementKind getSerializedKind(Element element) {
+    if (element.isPrefix) {
+      return SerializedElementKind.PREFIX;
+    }
+    return null;
+  }
+
+  void serialize(PrefixElement element,
+                 ObjectEncoder encoder,
+                 SerializedElementKind kind) {
+    encoder.setString(Key.NAME, element.name);
+    encoder.setElement(Key.LIBRARY, element.library);
+    encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
+    if (element.deferredImport != null) {
+      encoder.setElement(Key.IMPORT, element.deferredImport);
+    }
+    encoder.setBool(Key.IS_DEFERRED, element.isDeferred);
+  }
+}
+
 /// Utility class for deserializing [Element]s.
 ///
 /// This is used by the [Deserializer].
@@ -482,6 +547,12 @@
         return new ParameterElementZ(decoder);
       case SerializedElementKind.INITIALIZING_FORMAL:
         return new InitializingFormalElementZ(decoder);
+      case SerializedElementKind.IMPORT:
+        return new ImportElementZ(decoder);
+      case SerializedElementKind.EXPORT:
+        return new ExportElementZ(decoder);
+      case SerializedElementKind.PREFIX:
+        return new PrefixElementZ(decoder);
     }
     throw new UnsupportedError("Unexpected element kind '${elementKind}.");
   }
diff --git a/pkg/compiler/lib/src/serialization/keys.dart b/pkg/compiler/lib/src/serialization/keys.dart
index a3c276e..de1af42 100644
--- a/pkg/compiler/lib/src/serialization/keys.dart
+++ b/pkg/compiler/lib/src/serialization/keys.dart
@@ -23,17 +23,21 @@
   static const Key ELEMENT = const Key('element');
   static const Key ELEMENTS = const Key('elements');
   static const Key EXPORTS = const Key('exports');
+  static const Key EXPORT_SCOPE = const Key('export-scope');
   static const Key EXPRESSION = const Key('expression');
   static const Key FALSE = const Key('false');
   static const Key FIELD = const Key('field');
   static const Key FIELDS = const Key('fields');
   static const Key FUNCTION = const Key('function');
   static const Key ID = const Key('id');
+  static const Key IMPORT = const Key('import');
   static const Key IMPORTS = const Key('imports');
+  static const Key IMPORT_SCOPE = const Key('import-scope');
   static const Key INTERFACES = const Key('interfaces');
   static const Key INDEX = const Key('index');
   static const Key IS_ABSTRACT = const Key('isAbstract');
   static const Key IS_CONST = const Key('isConst');
+  static const Key IS_DEFERRED = const Key('isDeferred');
   static const Key IS_EXTERNAL = const Key('isExternal');
   static const Key IS_FINAL = const Key('isFinal');
   static const Key IS_NAMED = const Key('isNamed');
@@ -44,6 +48,7 @@
   static const Key LEFT = const Key('left');
   static const Key LENGTH = const Key('length');
   static const Key LIBRARY = const Key('library');
+  static const Key LIBRARY_DEPENDENCY = const Key('library-dependency');
   static const Key LIBRARY_NAME = const Key('library-name');
   static const Key MEMBERS = const Key('members');
   static const Key NAME = const Key('name');
@@ -57,6 +62,7 @@
       const Key('optional-parameter-types');
   static const Key PARAMETERS = const Key('parameters');
   static const Key PARAMETER_TYPES = const Key('parameter-types');
+  static const Key PREFIX = const Key('prefix');
   static const Key RETURN_TYPE = const Key('return-type');
   static const Key RIGHT = const Key('right');
   static const Key SUPERTYPE = const Key('supertype');
diff --git a/pkg/compiler/lib/src/serialization/modelz.dart b/pkg/compiler/lib/src/serialization/modelz.dart
index a0ba0a8..f246736 100644
--- a/pkg/compiler/lib/src/serialization/modelz.dart
+++ b/pkg/compiler/lib/src/serialization/modelz.dart
@@ -27,16 +27,12 @@
 import '../io/source_file.dart';
 import '../ordered_typeset.dart';
 import '../resolution/class_members.dart' as class_members;
-import '../resolution/enum_creator.dart' show
-    AstBuilder;
 import '../resolution/tree_elements.dart' show
     TreeElements;
 import '../resolution/scope.dart' show
     Scope;
 import '../script.dart';
 import '../serialization/constant_serialization.dart';
-import '../tokens/precedence_constants.dart' as Precedence show
-    SEMICOLON_INFO;
 import '../tokens/token.dart' show
     Token;
 import '../tree/tree.dart';
@@ -159,7 +155,7 @@
 
   // TODO(johnniwinther): Support metadata.
   @override
-  Link<MetadataAnnotation> get metadata => const Link<MetadataAnnotation>();
+  Iterable<MetadataAnnotation> get metadata => const <MetadataAnnotation>[];
 
   @override
   Element get outermostEnclosingMemberOrTopLevel {
@@ -375,7 +371,8 @@
   Uri _canonicalUri;
   CompilationUnitElement _entryCompilationUnit;
   Link<CompilationUnitElement> _compilationUnits;
-  Link<Element> _exports;
+  List<ImportElement> _imports;
+  List<ExportElement> _exports;
   ListedContainer _exportsMap;
   ListedContainer _importsMap;
   Map<LibraryTag, LibraryElement> _libraryDependencies;
@@ -426,12 +423,12 @@
   }
 
   @override
-  bool hasLibraryName() {
-    return getLibraryName() != '';
+  bool get hasLibraryName {
+    return libraryName != '';
   }
 
   @override
-  String getLibraryName() {
+  String get libraryName {
     return _decoder.getString(Key.LIBRARY_NAME);
   }
 
@@ -439,20 +436,15 @@
   bool get exportsHandled => true;
 
   void _ensureExports() {
-    if (_exports == null) {
-      _exportsMap = new ListedContainer(_decoder.getElements(Key.EXPORTS));
-      _exports = toLink(_exportsMap.values);
+    if (_exportsMap == null) {
+      _exportsMap = new ListedContainer(_decoder.getElements(Key.EXPORT_SCOPE));
     }
   }
 
-  Link<Element> get exports {
-    _ensureExports();
-    return _exports;
-  }
-
   @override
   void forEachExport(f(Element element)) {
-    exports.forEach(f);
+    _ensureExports();
+    _exportsMap.forEach(f);
   }
 
   @override
@@ -470,53 +462,6 @@
     return localLookup(elementName);
   }
 
-  void _ensureLibraryDependencies() {
-    if (_libraryDependencies == null) {
-      _libraryDependencies = <LibraryTag, LibraryElement>{};
-      ListDecoder tags = _decoder.getList(Key.TAGS);
-      AstBuilder builder = new AstBuilder(0);
-      for (int i = 0; i < tags.length; i++) {
-        ObjectDecoder dependency = tags.getObject(i);
-        String kind = dependency.getString(Key.KIND);
-        LibraryElement library = dependency.getElement(Key.LIBRARY);
-        // TODO(johnniwinther): Add `ImportElement` and `ExportElement` to the
-        // element model to avoid hacking up nodes.
-        if (kind == 'import') {
-          Import tag = new Import(
-              builder.keywordToken('import'),
-              builder.literalString(library.canonicalUri.toString())
-                  ..getEndToken().next =
-                      builder.symbolToken(Precedence.SEMICOLON_INFO),
-              null, // prefix
-              null, // combinators
-              null, // metadata
-              isDeferred: false);
-          _libraryDependencies[tag] = library;
-        } else if (kind == 'export') {
-          Export tag = new Export(
-              builder.keywordToken('export'),
-              builder.literalString(library.canonicalUri.toString())
-                  ..getEndToken().next =
-                      builder.symbolToken(Precedence.SEMICOLON_INFO),
-              null,  // combinators
-              null); // metadata
-          _libraryDependencies[tag] = library;
-        }
-      }
-    }
-  }
-
-  @override
-  Iterable<LibraryTag> get tags {
-    _ensureLibraryDependencies();
-    return _libraryDependencies.keys;
-  }
-
-  LibraryElement getLibraryFromTag(LibraryDependency tag) {
-    _ensureLibraryDependencies();
-    return _libraryDependencies[tag];
-  }
-
   @override
   bool get canUseNative => false;
 
@@ -525,7 +470,7 @@
 
   void _ensureImports() {
     if (_importsMap == null) {
-      _importsMap = new ListedContainer(_decoder.getElements(Key.IMPORTS));
+      _importsMap = new ListedContainer(_decoder.getElements(Key.IMPORT_SCOPE));
     }
   }
 
@@ -536,14 +481,29 @@
   }
 
   @override
-  Link<Import> getImportsFor(Element element) => _unsupported('getImportsFor');
-
-  @override
-  LibraryName get libraryTag => _unsupported('libraryTag');
+  Iterable<ImportElement> getImportsFor(Element element) {
+    return _unsupported('getImportsFor');
+  }
 
   String toString() {
     return 'Zlibrary(${canonicalUri})';
   }
+
+  @override
+  Iterable<ExportElement> get exports {
+    if (_exports == null) {
+      _exports = _decoder.getElements(Key.EXPORTS, isOptional: true);
+    }
+    return _exports;
+  }
+
+  @override
+  Iterable<ImportElement> get imports {
+    if (_imports == null) {
+      _imports = _decoder.getElements(Key.IMPORTS, isOptional: true);
+    }
+    return _imports;
+  }
 }
 
 class ScriptZ implements Script {
@@ -940,6 +900,11 @@
 
   @override
   ClassElement get superclass => supertype != null ? supertype.element : null;
+
+  @override
+  void ensureResolved(Compiler compiler) {
+    compiler.world.registerClass(this);
+  }
 }
 
 abstract class ConstructorElementZ extends DeserializedElementZ
@@ -1280,9 +1245,6 @@
 
   @override
   bool get isResolved => true;
-
-  @override
-  void ensureResolved(Compiler compiler) {}
 }
 
 class TypedefElementZ extends DeserializedElementZ
@@ -1318,6 +1280,9 @@
   }
 
   @override
+  void ensureResolved(Compiler compiler) {}
+
+  @override
   void checkCyclicReference(Compiler compiler) {}
 }
 
@@ -1451,7 +1416,6 @@
   MemberElement get memberContext => executableContext.memberContext;
 }
 
-
 class InitializingFormalElementZ extends ParameterElementZ
     implements InitializingFormalElement {
   FieldElement _fieldElement;
@@ -1474,5 +1438,142 @@
 
   @override
   ElementKind get kind => ElementKind.INITIALIZING_FORMAL;
+}
 
+class ImportElementZ extends DeserializedElementZ
+    with LibraryMemberMixin implements ImportElement {
+  bool _isDeferred;
+  PrefixElement _prefix;
+  LibraryElement _importedLibrary;
+  Uri _uri;
+
+  ImportElementZ(ObjectDecoder decoder)
+      : super(decoder);
+
+  @override
+  String get name => '';
+
+  @override
+  accept(ElementVisitor visitor, arg) => visitor.visitImportElement(this, arg);
+
+  @override
+  ElementKind get kind => ElementKind.IMPORT;
+
+  @override
+  LibraryElement get importedLibrary {
+    if (_importedLibrary == null) {
+      _importedLibrary = _decoder.getElement(Key.LIBRARY_DEPENDENCY);
+    }
+    return _importedLibrary;
+  }
+
+  void _ensurePrefixResolved() {
+    if (_isDeferred == null) {
+      _isDeferred = _decoder.getBool(Key.IS_DEFERRED);
+      _prefix = _decoder.getElement(Key.PREFIX, isOptional: true);
+    }
+  }
+
+  @override
+  bool get isDeferred {
+    _ensurePrefixResolved();
+    return _isDeferred;
+  }
+
+  @override
+  PrefixElement get prefix {
+    _ensurePrefixResolved();
+    return _prefix;
+  }
+
+  @override
+  Uri get uri {
+    if (_uri == null) {
+      _uri = _decoder.getUri(Key.URI);
+    }
+    return _uri;
+  }
+
+  @override
+  Import get node => _unsupported('node');
+
+  String toString() => 'Z$kind($uri)';
+}
+
+class ExportElementZ extends DeserializedElementZ
+    with LibraryMemberMixin implements ExportElement {
+  LibraryElement _exportedLibrary;
+  Uri _uri;
+
+  ExportElementZ(ObjectDecoder decoder)
+      : super(decoder);
+
+  @override
+  String get name => '';
+
+  @override
+  accept(ElementVisitor visitor, arg) => visitor.visitExportElement(this, arg);
+
+  @override
+  ElementKind get kind => ElementKind.EXPORT;
+
+  @override
+  LibraryElement get exportedLibrary {
+    if (_exportedLibrary == null) {
+      _exportedLibrary = _decoder.getElement(Key.LIBRARY_DEPENDENCY);
+    }
+    return _exportedLibrary;
+  }
+
+  @override
+  Uri get uri {
+    if (_uri == null) {
+      _uri = _decoder.getUri(Key.URI);
+    }
+    return _uri;
+  }
+
+  @override
+  Export get node => _unsupported('node');
+
+  String toString() => 'Z$kind($uri)';
+}
+
+class PrefixElementZ extends DeserializedElementZ
+    with LibraryMemberMixin implements PrefixElement {
+  bool _isDeferred;
+  ImportElement _deferredImport;
+
+  PrefixElementZ(ObjectDecoder decoder)
+      : super(decoder);
+
+  @override
+  accept(ElementVisitor visitor, arg) => visitor.visitPrefixElement(this, arg);
+
+  void _ensureDeferred() {
+    if (_isDeferred == null) {
+      _isDeferred = _decoder.getBool(Key.IS_DEFERRED);
+      _deferredImport = _decoder.getElement(Key.IMPORT, isOptional: true);
+    }
+  }
+
+  @override
+  ImportElement get deferredImport {
+    _ensureDeferred();
+    return _deferredImport;
+  }
+
+  @override
+  bool get isDeferred {
+    _ensureDeferred();
+    return _isDeferred;
+  }
+
+  @override
+  ElementKind get kind => ElementKind.PREFIX;
+
+  @override
+  Element lookupLocalMember(String memberName) {
+    return _unsupported('lookupLocalMember');
+  }
 }
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 209e151..bf19f70 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -1097,6 +1097,7 @@
       this.work = work,
       this.rti = backend.rti,
       this.elements = work.resolutionTree {
+    graph.element = work.element;
     localsHandler = new LocalsHandler(this, work.element, null);
     sourceElementStack.add(work.element);
     sourceInformationBuilder =
@@ -3338,9 +3339,9 @@
                                              ast.Node location) {
     if (prefixElement == null) return;
     String loadId =
-        compiler.deferredLoadTask.importDeferName[prefixElement.deferredImport];
+        compiler.deferredLoadTask.getImportDeferName(location, prefixElement);
     HInstruction loadIdConstant = addConstantString(loadId);
-    String uri = prefixElement.deferredImport.uri.dartString.slowToString();
+    String uri = prefixElement.deferredImport.uri.toString();
     HInstruction uriConstant = addConstantString(uri);
     Element helper = backend.getCheckDeferredIsLoaded();
     pushInvokeStatic(location, helper, [loadIdConstant, uriConstant]);
@@ -4413,8 +4414,8 @@
     invariant(node, deferredLoader.isDeferredLoaderGetter);
     Element loadFunction = compiler.loadLibraryFunction;
     PrefixElement prefixElement = deferredLoader.enclosingElement;
-    String loadId = compiler.deferredLoadTask
-        .importDeferName[prefixElement.deferredImport];
+    String loadId =
+        compiler.deferredLoadTask.getImportDeferName(node, prefixElement);
     var inputs = [graph.addConstantString(
         new ast.DartString.literal(loadId), compiler)];
     push(new HInvokeStatic(loadFunction, inputs, backend.nonNullType,
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 6a2002c..3e25aa9 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -2122,7 +2122,7 @@
       js.Statement thenBody = new js.Block.empty();
       js.Block oldContainer = currentContainer;
       currentContainer = thenBody;
-      generateThrowWithHelper('ioore', [node.array, node.index]);
+      generateThrowWithHelper('ioore', [node.array, node.reportedIndex]);
       currentContainer = oldContainer;
       thenBody = unwrapStatement(thenBody);
       pushStatement(new js.If.noElse(underOver, thenBody)
@@ -2694,7 +2694,7 @@
       checkString(input, '!==', input.sourceInformation);
       return pop();
     }
-    compiler.internalError(input, 'Unexpected check.');
+    compiler.internalError(input, 'Unexpected check: $checkedType.');
     return null;
   }
 
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index b23f32d..8943e70 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -130,6 +130,7 @@
 }
 
 class HGraph {
+  Element element;  // Used for debug printing.
   HBasicBlock entry;
   HBasicBlock exit;
   HThis thisInstruction;
@@ -137,15 +138,13 @@
   HParameterValue explicitReceiverParameter;
   bool isRecursiveMethod = false;
   bool calledInLoop = false;
-  final List<HBasicBlock> blocks;
+  final List<HBasicBlock> blocks = <HBasicBlock>[];
 
   // We canonicalize all constants used within a graph so we do not
   // have to worry about them for global value numbering.
-  Map<ConstantValue, HConstant> constants;
+  Map<ConstantValue, HConstant> constants = new Map<ConstantValue, HConstant>();
 
-  HGraph()
-      : blocks = new List<HBasicBlock>(),
-        constants = new Map<ConstantValue, HConstant>() {
+  HGraph() {
     entry = addNewBlock();
     // The exit block will be added later, so it has an id that is
     // after all others in the system.
@@ -262,6 +261,8 @@
     validator.visitGraph(this);
     return validator.isValid;
   }
+
+  toString() => 'HGraph($element)';
 }
 
 class HBaseVisitor extends HGraphVisitor implements HVisitor {
@@ -882,6 +883,32 @@
     return instructionType.isEmpty && !instructionType.isNullable;
   }
 
+  /// Returns `true` if [typeMask] contains [cls].
+  static bool containsType(
+      TypeMask typeMask,
+      ClassElement cls,
+      ClassWorld classWorld) {
+    return classWorld.isInstantiated(cls) && typeMask.contains(cls, classWorld);
+  }
+
+  /// Returns `true` if [typeMask] contains only [cls].
+  static bool containsOnlyType(
+      TypeMask typeMask,
+      ClassElement cls,
+      ClassWorld classWorld) {
+    return classWorld.isInstantiated(cls) &&
+        typeMask.containsOnly(cls);
+  }
+
+  /// Returns `true` if [typeMask] is an instance of [cls].
+  static bool isInstanceOf(
+      TypeMask typeMask,
+      ClassElement cls,
+      ClassWorld classWorld) {
+    return classWorld.isInstantiated(cls) &&
+        typeMask.satisfies(cls, classWorld);
+  }
+
   bool canBePrimitive(Compiler compiler) {
     return canBePrimitiveNumber(compiler)
         || canBePrimitiveArray(compiler)
@@ -895,27 +922,28 @@
     JavaScriptBackend backend = compiler.backend;
     // TODO(sra): It should be possible to test only jsDoubleClass and
     // jsUInt31Class, since all others are superclasses of these two.
-    return instructionType.contains(backend.jsNumberClass, classWorld)
-        || instructionType.contains(backend.jsIntClass, classWorld)
-        || instructionType.contains(backend.jsPositiveIntClass, classWorld)
-        || instructionType.contains(backend.jsUInt32Class, classWorld)
-        || instructionType.contains(backend.jsUInt31Class, classWorld)
-        || instructionType.contains(backend.jsDoubleClass, classWorld);
+    return containsType(instructionType, backend.jsNumberClass, classWorld)
+        || containsType(instructionType, backend.jsIntClass, classWorld)
+        || containsType(instructionType, backend.jsPositiveIntClass, classWorld)
+        || containsType(instructionType, backend.jsUInt32Class, classWorld)
+        || containsType(instructionType, backend.jsUInt31Class, classWorld)
+        || containsType(instructionType, backend.jsDoubleClass, classWorld);
   }
 
   bool canBePrimitiveBoolean(Compiler compiler) {
     ClassWorld classWorld = compiler.world;
     JavaScriptBackend backend = compiler.backend;
-    return instructionType.contains(backend.jsBoolClass, classWorld);
+    return containsType(instructionType, backend.jsBoolClass, classWorld);
   }
 
   bool canBePrimitiveArray(Compiler compiler) {
     ClassWorld classWorld = compiler.world;
     JavaScriptBackend backend = compiler.backend;
-    return instructionType.contains(backend.jsArrayClass, classWorld)
-        || instructionType.contains(backend.jsFixedArrayClass, classWorld)
-        || instructionType.contains(backend.jsExtendableArrayClass, classWorld)
-        || instructionType.contains(
+    return containsType(instructionType, backend.jsArrayClass, classWorld)
+        || containsType(instructionType, backend.jsFixedArrayClass, classWorld)
+        || containsType(
+            instructionType, backend.jsExtendableArrayClass, classWorld)
+        || containsType(instructionType,
             backend.jsUnmodifiableArrayClass, classWorld);
   }
 
@@ -923,37 +951,43 @@
     ClassWorld classWorld = compiler.world;
     JavaScriptBackend backend = compiler.backend;
     return instructionType.containsOnlyString(classWorld)
-        || instructionType.satisfies(backend.jsIndexableClass, classWorld);
+        || isInstanceOf(instructionType, backend.jsIndexableClass, classWorld);
   }
 
   bool isFixedArray(Compiler compiler) {
+    ClassWorld classWorld = compiler.world;
     JavaScriptBackend backend = compiler.backend;
     // TODO(sra): Recognize the union of these types as well.
-    return instructionType.containsOnly(backend.jsFixedArrayClass)
-        || instructionType.containsOnly(backend.jsUnmodifiableArrayClass);
+    return containsOnlyType(
+            instructionType, backend.jsFixedArrayClass, classWorld)
+        || containsOnlyType(
+            instructionType, backend.jsUnmodifiableArrayClass, classWorld);
   }
 
   bool isExtendableArray(Compiler compiler) {
+    ClassWorld classWorld = compiler.world;
     JavaScriptBackend backend = compiler.backend;
-    return instructionType.containsOnly(backend.jsExtendableArrayClass);
+    return containsOnlyType(
+        instructionType, backend.jsExtendableArrayClass, classWorld);
   }
 
   bool isMutableArray(Compiler compiler) {
     ClassWorld classWorld = compiler.world;
     JavaScriptBackend backend = compiler.backend;
-    return instructionType.satisfies(backend.jsMutableArrayClass, classWorld);
+    return isInstanceOf(
+        instructionType, backend.jsMutableArrayClass, classWorld);
   }
 
   bool isReadableArray(Compiler compiler) {
     ClassWorld classWorld = compiler.world;
     JavaScriptBackend backend = compiler.backend;
-    return instructionType.satisfies(backend.jsArrayClass, classWorld);
+    return isInstanceOf(instructionType, backend.jsArrayClass, classWorld);
   }
 
   bool isMutableIndexable(Compiler compiler) {
     ClassWorld classWorld = compiler.world;
     JavaScriptBackend backend = compiler.backend;
-    return instructionType.satisfies(
+    return isInstanceOf(instructionType,
         backend.jsMutableIndexableClass, classWorld);
   }
 
@@ -962,7 +996,7 @@
   bool canBePrimitiveString(Compiler compiler) {
     ClassWorld classWorld = compiler.world;
     JavaScriptBackend backend = compiler.backend;
-    return instructionType.contains(backend.jsStringClass, classWorld);
+    return containsType(instructionType, backend.jsStringClass, classWorld);
   }
 
   bool isInteger(Compiler compiler) {
@@ -975,27 +1009,28 @@
     ClassWorld classWorld = compiler.world;
     JavaScriptBackend backend = compiler.backend;
     return !instructionType.isNullable
-        && instructionType.satisfies(backend.jsUInt32Class, classWorld);
+        && isInstanceOf(instructionType, backend.jsUInt32Class, classWorld);
   }
 
   bool isUInt31(Compiler compiler) {
     ClassWorld classWorld = compiler.world;
     JavaScriptBackend backend = compiler.backend;
     return !instructionType.isNullable
-        && instructionType.satisfies(backend.jsUInt31Class, classWorld);
+        && isInstanceOf(instructionType, backend.jsUInt31Class, classWorld);
   }
 
   bool isPositiveInteger(Compiler compiler) {
     ClassWorld classWorld = compiler.world;
     JavaScriptBackend backend = compiler.backend;
-    return !instructionType.isNullable
-        && instructionType.satisfies(backend.jsPositiveIntClass, classWorld);
+    return !instructionType.isNullable &&
+        isInstanceOf(instructionType, backend.jsPositiveIntClass, classWorld);
   }
 
   bool isPositiveIntegerOrNull(Compiler compiler) {
     ClassWorld classWorld = compiler.world;
     JavaScriptBackend backend = compiler.backend;
-    return instructionType.satisfies(backend.jsPositiveIntClass, classWorld);
+    return isInstanceOf(
+        instructionType, backend.jsPositiveIntClass, classWorld);
   }
 
   bool isIntegerOrNull(Compiler compiler) {
@@ -1393,6 +1428,9 @@
   HInstruction get length => inputs[1];
   HInstruction get index => inputs[0];
   HInstruction get array => inputs[2];
+  // There can be an additional fourth input which is the index to report to
+  // [ioore]. This is used by the expansion of [JSArray.removeLast].
+  HInstruction get reportedIndex => inputs.length > 3 ? inputs[3] : index;
   bool isControlFlow() => true;
 
   accept(HVisitor visitor) => visitor.visitBoundsCheck(this);
@@ -1846,6 +1884,8 @@
   accept(HVisitor visitor) => visitor.visitForeignNew(this);
 
   bool get isAllocation => true;
+
+  String toString() => 'HForeignNew($element)';
 }
 
 abstract class HInvokeBinary extends HInstruction {
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 977900c..cb03183 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -268,9 +268,11 @@
       ClassWorld classWorld = compiler.world;
       TypeMask resultType = backend.positiveIntType;
       // If we already have computed a more specific type, keep that type.
-      if (actualType.satisfies(backend.jsUInt31Class, classWorld)) {
+      if (HInstruction.isInstanceOf(
+              actualType, backend.jsUInt31Class, classWorld)) {
         resultType = backend.uint31Type;
-      } else if (actualType.satisfies(backend.jsUInt32Class, classWorld)) {
+      } else if (HInstruction.isInstanceOf(
+              actualType, backend.jsUInt32Class, classWorld)) {
         resultType = backend.uint32Type;
       }
       HFieldGet result = new HFieldGet(
@@ -1029,8 +1031,13 @@
     if (node.isInterceptedCall) return;
     if (element != backend.jsArrayRemoveLast) return;
     if (boundsChecked.contains(node)) return;
-    insertBoundsCheck(
+    // `0` is the index we want to check, but we want to report `-1`, as if we
+    // executed `a[a.length-1]`
+    HBoundsCheck check = insertBoundsCheck(
         node, node.receiver, graph.addConstantInt(0, backend.compiler));
+    HInstruction minusOne = graph.addConstantInt(-1, backend.compiler);
+    check.inputs.add(minusOne);
+    minusOne.usedBy.add(check);
   }
 }
 
@@ -1954,17 +1961,57 @@
 
   void visitForeignNew(HForeignNew instruction) {
     memorySet.registerAllocation(instruction);
-    int argumentIndex = 0;
-    instruction.element.forEachInstanceField((_, Element member) {
-      if (compiler.elementHasCompileTimeError(member)) return;
-      memorySet.registerFieldValue(
-          member, instruction, instruction.inputs[argumentIndex++]);
-    }, includeSuperAndInjectedMembers: true);
+    if (shouldTrackInitialValues(instruction)) {
+      int argumentIndex = 0;
+      instruction.element.forEachInstanceField((_, Element member) {
+        if (compiler.elementHasCompileTimeError(member)) return;
+        memorySet.registerFieldValue(
+            member, instruction, instruction.inputs[argumentIndex++]);
+      }, includeSuperAndInjectedMembers: true);
+    }
     // In case this instruction has as input non-escaping objects, we
     // need to mark these objects as escaping.
     memorySet.killAffectedBy(instruction);
   }
 
+  bool shouldTrackInitialValues(HForeignNew instruction) {
+    // Don't track initial field values of an allocation that are
+    // unprofitable. We search the chain of single uses in allocations for a
+    // limited depth.
+
+    const MAX_HEAP_DEPTH = 5;
+
+    bool interestingUse(HInstruction instruction, int heapDepth) {
+      // Heuristic: if the allocation is too deep in heap it is unlikely we will
+      // recover a field by load-elimination.
+      // TODO(sra): We can measure this depth by looking at load chains.
+      if (heapDepth == MAX_HEAP_DEPTH) return false;
+      // There are multiple uses so do the full store analysis.
+      if (instruction.usedBy.length != 1) return true;
+      HInstruction use = instruction.usedBy.single;
+      // When the only use is an allocation, the allocation becomes the only
+      // heap alias for the current instruction.
+      if (use is HForeignNew) return interestingUse(use, heapDepth + 1);
+      if (use is HLiteralList) return interestingUse(use, heapDepth + 1);
+      if (use is HInvokeStatic) {
+        // Assume the argument escapes. All we do with our initial allocation is
+        // have it escape or store it into an object that escapes.
+        return false;
+        // TODO(sra): Handle more functions. `setRuntimeTypeInfo` does not
+        // actually kill it's input, but we don't make use of that elsewhere so
+        // there is not point in checking here.
+      }
+      if (use is HPhi) {
+        // The initial allocation (it's only alias) gets merged out of the model
+        // of the heap before load.
+        return false;
+      }
+      return true;
+    }
+
+    return interestingUse(instruction, 0);
+  }
+
   void visitInstruction(HInstruction instruction) {
     if (instruction.isAllocation) {
       memorySet.registerAllocation(instruction);
diff --git a/pkg/compiler/lib/src/tree/nodes.dart b/pkg/compiler/lib/src/tree/nodes.dart
index 56f1f26..6c4516b 100644
--- a/pkg/compiler/lib/src/tree/nodes.dart
+++ b/pkg/compiler/lib/src/tree/nodes.dart
@@ -1897,7 +1897,7 @@
 }
 
 abstract class LibraryTag extends Node {
-  final Link<MetadataAnnotation> metadata;
+  final List<MetadataAnnotation> metadata;
 
   LibraryTag(this.metadata);
 
@@ -1915,7 +1915,7 @@
 
   LibraryName(this.libraryKeyword,
               this.name,
-              Link<MetadataAnnotation> metadata)
+              List<MetadataAnnotation> metadata)
     : super(metadata);
 
   bool get isLibraryName => true;
@@ -1942,7 +1942,7 @@
 
   LibraryDependency(this.uri,
                     this.combinators,
-                    Link<MetadataAnnotation> metadata)
+                    List<MetadataAnnotation> metadata)
     : super(metadata);
 
   LibraryDependency asLibraryDependency() => this;
@@ -1962,7 +1962,7 @@
 
   Import(this.importKeyword, StringNode uri,
          this.prefix, NodeList combinators,
-         Link<MetadataAnnotation> metadata,
+         List<MetadataAnnotation> metadata,
          {this.isDeferred})
       : super(uri, combinators, metadata);
 
@@ -2027,7 +2027,7 @@
   Export(this.exportKeyword,
          StringNode uri,
          NodeList combinators,
-         Link<MetadataAnnotation> metadata)
+         List<MetadataAnnotation> metadata)
       : super(uri, combinators, metadata);
 
   bool get isExport => true;
@@ -2054,7 +2054,7 @@
 
   final Token partKeyword;
 
-  Part(this.partKeyword, this.uri, Link<MetadataAnnotation> metadata)
+  Part(this.partKeyword, this.uri, List<MetadataAnnotation> metadata)
     : super(metadata);
 
   bool get isPart => true;
@@ -2075,7 +2075,7 @@
 
   final Token partKeyword;
 
-  final Link<MetadataAnnotation> metadata;
+  final List<MetadataAnnotation> metadata;
 
   PartOf(this.partKeyword, this.name, this.metadata);
 
diff --git a/pkg/compiler/lib/src/tree/unparser.dart b/pkg/compiler/lib/src/tree/unparser.dart
index fd00ba3..a0156be 100644
--- a/pkg/compiler/lib/src/tree/unparser.dart
+++ b/pkg/compiler/lib/src/tree/unparser.dart
@@ -698,6 +698,11 @@
     indentLess();
   }
 
+  unparseLibraryName(String libraryName) {
+    write('library $libraryName;');
+    newline();
+  }
+
   unparseImportTag(String uri, {String prefix,
                                 List<String> shows: const <String>[],
                                 bool isDeferred: false}) {
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
index 9ad632c..c4b993b 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
@@ -392,14 +392,14 @@
     Expression value = getVariableUse(node.value);
     List<Expression> typeArgs = translateArguments(node.typeArguments);
     Expression expression =
-        new TypeOperator(value, node.type, typeArgs, isTypeTest: false);
+        new TypeOperator(value, node.dartType, typeArgs, isTypeTest: false);
     return makeCallExpression(node, expression);
   }
 
   NodeCallback visitInvokeConstructor(cps_ir.InvokeConstructor node) {
     List<Expression> arguments = translateArguments(node.arguments);
     Expression invoke = new InvokeConstructor(
-        node.type,
+        node.dartType,
         node.target,
         node.selector,
         arguments,
@@ -580,13 +580,13 @@
 
   Expression visitLiteralList(cps_ir.LiteralList node) {
     return new LiteralList(
-            node.type,
+            node.dartType,
             translateArguments(node.values));
   }
 
   Expression visitLiteralMap(cps_ir.LiteralMap node) {
     return new LiteralMap(
-        node.type,
+        node.dartType,
         new List<LiteralMapEntry>.generate(node.entries.length, (int index) {
           return new LiteralMapEntry(
               getVariableUse(node.entries[index].key),
@@ -625,7 +625,7 @@
   Expression visitTypeTest(cps_ir.TypeTest node) {
     Expression value = getVariableUse(node.value);
     List<Expression> typeArgs = translateArguments(node.typeArguments);
-    return new TypeOperator(value, node.type, typeArgs, isTypeTest: true);
+    return new TypeOperator(value, node.dartType, typeArgs, isTypeTest: true);
   }
 
   Expression visitGetStatic(cps_ir.GetStatic node) {
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart
index fa33492..3a1a0bc 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart
@@ -85,7 +85,7 @@
     label2declaration[label] = target;
     labelUses[label] = 0;
     visitStatement(target.body);
-    label2declaration.remove(target);
+    label2declaration.remove(label);
 
     if (labelUses[label] != label.useCount) {
       error('Label $label has ${labelUses[label]} uses '
diff --git a/pkg/compiler/lib/src/typechecker.dart b/pkg/compiler/lib/src/typechecker.dart
index 74b9659..cb64d9b 100644
--- a/pkg/compiler/lib/src/typechecker.dart
+++ b/pkg/compiler/lib/src/typechecker.dart
@@ -4,6 +4,8 @@
 
 library dart2js.typechecker;
 
+import 'common/names.dart' show
+    Identifiers;
 import 'common/tasks.dart' show
     CompilerTask;
 import 'compiler.dart' show
@@ -62,7 +64,7 @@
     if (element.isClass) return;
     if (element.isTypedef) return;
     ResolvedAst resolvedAst = element.resolvedAst;
-    compiler.withCurrentElement(element, () {
+    compiler.withCurrentElement(element.implementation, () {
       measure(() {
         TypeCheckerVisitor visitor = new TypeCheckerVisitor(
             compiler, resolvedAst.elements, compiler.types);
@@ -420,6 +422,16 @@
     compiler.reportWarning(spannable, kind, arguments);
   }
 
+  reportMessage(Spannable spannable, MessageKind kind,
+                Map arguments,
+                {bool isHint: false}) {
+    if (isHint) {
+      compiler.reportHint(spannable, kind, arguments);
+    } else {
+      compiler.reportWarning(spannable, kind, arguments);
+    }
+  }
+
   reportTypeInfo(Spannable spannable, MessageKind kind,
                  [Map arguments = const {}]) {
     compiler.reportInfo(spannable, kind, arguments);
@@ -726,14 +738,15 @@
           node,
           MessageKind.PRIVATE_ACCESS,
           {'name': name,
-           'libraryName': element.library.getLibraryOrScriptName()});
+           'libraryName': element.library.libraryOrScriptName});
     }
 
   }
 
   ElementAccess lookupMember(Node node, DartType receiverType, String name,
                              MemberKind memberKind, Element receiverElement,
-                             {bool lookupClassMember: false}) {
+                             {bool lookupClassMember: false,
+                              bool isHint: false}) {
     if (receiverType.treatAsDynamic) {
       return const DynamicAccess();
     }
@@ -741,35 +754,6 @@
     Name memberName = new Name(name, currentLibrary,
         isSetter: memberKind == MemberKind.SETTER);
 
-    // Compute the unaliased type of the first non type variable bound of
-    // [type].
-    DartType computeUnaliasedBound(DartType type) {
-      DartType originalType = type;
-      while (identical(type.kind, TypeKind.TYPE_VARIABLE)) {
-        TypeVariableType variable = type;
-        type = variable.element.bound;
-        if (type == originalType) {
-          type = compiler.objectClass.rawType;
-        }
-      }
-      if (type.isMalformed) {
-        return const DynamicType();
-      }
-      return type.unalias(compiler);
-    }
-
-    // Compute the interface type of [type]. For type variable it is the
-    // interface type of the bound, for function types and typedefs it is the
-    // `Function` type.
-    InterfaceType computeInterfaceType(DartType type) {
-      if (type.isFunctionType) {
-         type = compiler.functionClass.rawType;
-      }
-      assert(invariant(node, type.isInterfaceType,
-          message: "unexpected type kind ${type.kind}."));
-      return type;
-    }
-
     // Lookup the class or interface member [name] in [interface].
     MemberSignature lookupMemberSignature(Name name, InterfaceType interface) {
       MembersCreator.computeClassMembersByName(
@@ -802,11 +786,13 @@
       return null;
     }
 
-    DartType unaliasedBound = computeUnaliasedBound(receiverType);
+    DartType unaliasedBound =
+        Types.computeUnaliasedBound(compiler, receiverType);
     if (unaliasedBound.treatAsDynamic) {
       return new DynamicAccess();
     }
-    InterfaceType interface = computeInterfaceType(unaliasedBound);
+    InterfaceType interface =
+        Types.computeInterfaceType(compiler, unaliasedBound);
     ElementAccess access = getAccess(memberName, unaliasedBound, interface);
     if (access != null) {
       return access;
@@ -818,9 +804,11 @@
         while (!typePromotions.isEmpty) {
           TypePromotion typePromotion = typePromotions.head;
           if (!typePromotion.isValid) {
-            DartType unaliasedBound = computeUnaliasedBound(typePromotion.type);
+            DartType unaliasedBound =
+                Types.computeUnaliasedBound(compiler, typePromotion.type);
             if (!unaliasedBound.treatAsDynamic) {
-              InterfaceType interface = computeInterfaceType(unaliasedBound);
+              InterfaceType interface =
+                  Types.computeInterfaceType(compiler, unaliasedBound);
               if (getAccess(memberName, unaliasedBound, interface) != null) {
                 reportTypePromotionHint(typePromotion);
               }
@@ -840,11 +828,12 @@
         void findPrivateMember(MemberSignature member) {
           if (memberName.isSimilarTo(member.name)) {
             PrivateName privateName = member.name;
-            reportTypeWarning(
+            reportMessage(
                  node,
                  MessageKind.PRIVATE_ACCESS,
                  {'name': name,
-                  'libraryName': privateName.library.getLibraryOrScriptName()});
+                  'libraryName': privateName.library.libraryOrScriptName},
+                 isHint: isHint);
             foundPrivateMember = true;
           }
         }
@@ -860,19 +849,22 @@
       if (!foundPrivateMember) {
         switch (memberKind) {
           case MemberKind.METHOD:
-            reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND,
-                {'className': receiverType.name, 'memberName': name});
+            reportMessage(node, MessageKind.METHOD_NOT_FOUND,
+                {'className': receiverType.name, 'memberName': name},
+                isHint: isHint);
             break;
           case MemberKind.OPERATOR:
-            reportTypeWarning(node, MessageKind.OPERATOR_NOT_FOUND,
-                {'className': receiverType.name, 'memberName': name});
+            reportMessage(node, MessageKind.OPERATOR_NOT_FOUND,
+                {'className': receiverType.name, 'memberName': name},
+                isHint: isHint);
             break;
           case MemberKind.GETTER:
             if (lookupMemberSignature(memberName.setter, interface) != null) {
               // A setter is present so warn explicitly about the missing
               // getter.
-              reportTypeWarning(node, MessageKind.GETTER_NOT_FOUND,
-                  {'className': receiverType.name, 'memberName': name});
+              reportMessage(node, MessageKind.GETTER_NOT_FOUND,
+                  {'className': receiverType.name, 'memberName': name},
+                  isHint: isHint);
             } else if (name == 'await') {
               Map arguments = {'className': receiverType.name};
               String functionName = executableContext.name;
@@ -883,15 +875,17 @@
                 kind = MessageKind.AWAIT_MEMBER_NOT_FOUND;
                 arguments['functionName'] = functionName;
               }
-              reportTypeWarning(node, kind, arguments);
+              reportMessage(node, kind, arguments, isHint: isHint);
             } else {
-              reportTypeWarning(node, MessageKind.MEMBER_NOT_FOUND,
-                  {'className': receiverType.name, 'memberName': name});
+              reportMessage(node, MessageKind.MEMBER_NOT_FOUND,
+                  {'className': receiverType.name, 'memberName': name},
+                  isHint: isHint);
             }
             break;
           case MemberKind.SETTER:
-            reportTypeWarning(node, MessageKind.SETTER_NOT_FOUND,
-                {'className': receiverType.name, 'memberName': name});
+            reportMessage(node, MessageKind.SETTER_NOT_FOUND,
+                {'className': receiverType.name, 'memberName': name},
+                isHint: isHint);
             break;
         }
       }
@@ -900,8 +894,9 @@
   }
 
   DartType lookupMemberType(Node node, DartType type, String name,
-                            MemberKind memberKind) {
-    return lookupMember(node, type, name, memberKind, null)
+                            MemberKind memberKind,
+                            {bool isHint: false}) {
+    return lookupMember(node, type, name, memberKind, null, isHint: isHint)
         .computeType(compiler);
   }
 
@@ -1797,14 +1792,67 @@
     return const StatementType();
   }
 
+  DartType computeForInElementType(ForIn node) {
+    VariableDefinitions declaredIdentifier =
+        node.declaredIdentifier.asVariableDefinitions();
+    if (declaredIdentifier != null) {
+      return
+          analyzeWithDefault(declaredIdentifier.type, const DynamicType());
+    } else {
+      return analyze(node.declaredIdentifier);
+    }
+  }
+
   visitAsyncForIn(AsyncForIn node) {
-    analyze(node.expression);
+    DartType elementType = computeForInElementType(node);
+    DartType expressionType = analyze(node.expression);
+    // TODO(johnniwinther): Move this to _CompilerCoreTypes.
+    compiler.streamClass.ensureResolved(compiler);
+    DartType streamOfDynamic = coreTypes.streamType();
+    if (!types.isAssignable(expressionType, streamOfDynamic)) {
+      reportMessage(node.expression,
+          MessageKind.NOT_ASSIGNABLE,
+          {'fromType': expressionType, 'toType': streamOfDynamic},
+          isHint: true);
+    } else {
+      InterfaceType interfaceType =
+          Types.computeInterfaceType(compiler, expressionType);
+      if (interfaceType != null) {
+        InterfaceType streamType =
+            interfaceType.asInstanceOf(compiler.streamClass);
+        if (streamType != null) {
+          DartType streamElementType = streamType.typeArguments.first;
+          if (!types.isAssignable(streamElementType, elementType)) {
+            reportMessage(node.expression,
+                MessageKind.FORIN_NOT_ASSIGNABLE,
+                {'currentType': streamElementType,
+                 'expressionType': expressionType,
+                 'elementType': elementType},
+                isHint: true);
+          }
+        }
+      }
+    }
     analyze(node.body);
     return const StatementType();
   }
 
   visitSyncForIn(SyncForIn node) {
-    analyze(node.expression);
+    DartType elementType = computeForInElementType(node);
+    DartType expressionType = analyze(node.expression);
+    DartType iteratorType = lookupMemberType(node.expression,
+        expressionType, Identifiers.iterator, MemberKind.GETTER);
+    DartType currentType = lookupMemberType(node.expression,
+              iteratorType, Identifiers.current, MemberKind.GETTER,
+              isHint: true);
+    if (!types.isAssignable(currentType, elementType)) {
+      reportMessage(node.expression,
+          MessageKind.FORIN_NOT_ASSIGNABLE,
+          {'currentType': currentType,
+           'expressionType': expressionType,
+           'elementType': elementType},
+          isHint: true);
+    }
     analyze(node.body);
     return const StatementType();
   }
diff --git a/pkg/compiler/lib/src/universe/call_structure.dart b/pkg/compiler/lib/src/universe/call_structure.dart
new file mode 100644
index 0000000..12e4fd8
--- /dev/null
+++ b/pkg/compiler/lib/src/universe/call_structure.dart
@@ -0,0 +1,282 @@
+// Copyright (c) 2015, 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 universe;
+
+/// The structure of the arguments at a call-site.
+// TODO(johnniwinther): Should these be cached?
+// TODO(johnniwinther): Should isGetter/isSetter be part of the call structure
+// instead of the selector?
+class CallStructure {
+  static const CallStructure NO_ARGS = const CallStructure.unnamed(0);
+  static const CallStructure ONE_ARG = const CallStructure.unnamed(1);
+  static const CallStructure TWO_ARGS = const CallStructure.unnamed(2);
+
+  /// The numbers of arguments of the call. Includes named arguments.
+  final int argumentCount;
+
+  /// The number of named arguments of the call.
+  int get namedArgumentCount => 0;
+
+  /// The number of positional argument of the call.
+  int get positionalArgumentCount => argumentCount;
+
+  const CallStructure.unnamed(this.argumentCount);
+
+  factory CallStructure(int argumentCount, [List<String> namedArguments]) {
+    if (namedArguments == null || namedArguments.isEmpty) {
+      return new CallStructure.unnamed(argumentCount);
+    }
+    return new NamedCallStructure(argumentCount, namedArguments);
+  }
+
+  /// `true` if this call has named arguments.
+  bool get isNamed => false;
+
+  /// `true` if this call has no named arguments.
+  bool get isUnnamed => true;
+
+  /// The names of the named arguments in call-site order.
+  List<String> get namedArguments => const <String>[];
+
+  /// The names of the named arguments in canonicalized order.
+  List<String> getOrderedNamedArguments() => const <String>[];
+
+  /// A description of the argument structure.
+  String structureToString() => 'arity=$argumentCount';
+
+  String toString() => 'CallStructure(${structureToString()})';
+
+  Selector get callSelector {
+    return new Selector(SelectorKind.CALL, Selector.CALL_NAME, this);
+  }
+
+  bool match(CallStructure other) {
+    if (identical(this, other)) return true;
+    return this.argumentCount == other.argumentCount
+        && this.namedArgumentCount == other.namedArgumentCount
+        && sameNames(this.namedArguments, other.namedArguments);
+  }
+
+  // TODO(johnniwinther): Cache hash code?
+  int get hashCode {
+    return Hashing.listHash(namedArguments,
+        Hashing.objectHash(argumentCount, namedArguments.length));
+  }
+
+  bool operator ==(other) {
+    if (other is! CallStructure) return false;
+    return match(other);
+  }
+
+  bool signatureApplies(FunctionSignature parameters) {
+    if (argumentCount > parameters.parameterCount) return false;
+    int requiredParameterCount = parameters.requiredParameterCount;
+    int optionalParameterCount = parameters.optionalParameterCount;
+    if (positionalArgumentCount < requiredParameterCount) return false;
+
+    if (!parameters.optionalParametersAreNamed) {
+      // We have already checked that the number of arguments are
+      // not greater than the number of parameters. Therefore the
+      // number of positional arguments are not greater than the
+      // number of parameters.
+      assert(positionalArgumentCount <= parameters.parameterCount);
+      return namedArguments.isEmpty;
+    } else {
+      if (positionalArgumentCount > requiredParameterCount) return false;
+      assert(positionalArgumentCount == requiredParameterCount);
+      if (namedArgumentCount > optionalParameterCount) return false;
+      Set<String> nameSet = new Set<String>();
+      parameters.optionalParameters.forEach((Element element) {
+        nameSet.add(element.name);
+      });
+      for (String name in namedArguments) {
+        if (!nameSet.contains(name)) return false;
+        // TODO(5213): By removing from the set we are checking
+        // that we are not passing the name twice. We should have this
+        // check in the resolver also.
+        nameSet.remove(name);
+      }
+      return true;
+    }
+  }
+
+  /**
+   * Returns a `List` with the evaluated arguments in the normalized order.
+   *
+   * [compileDefaultValue] is a function that returns a compiled constant
+   * of an optional argument that is not in [compiledArguments].
+   *
+   * Precondition: `this.applies(element, world)`.
+   *
+   * Invariant: [element] must be the implementation element.
+   */
+  /*<T>*/ List/*<T>*/ makeArgumentsList(
+      Link<Node> arguments,
+      FunctionElement element,
+      /*T*/ compileArgument(Node argument),
+      /*T*/ compileDefaultValue(ParameterElement element)) {
+    assert(invariant(element, element.isImplementation));
+    List/*<T>*/ result = new List();
+
+    FunctionSignature parameters = element.functionSignature;
+    parameters.forEachRequiredParameter((ParameterElement element) {
+      result.add(compileArgument(arguments.head));
+      arguments = arguments.tail;
+    });
+
+    if (!parameters.optionalParametersAreNamed) {
+      parameters.forEachOptionalParameter((ParameterElement element) {
+        if (!arguments.isEmpty) {
+          result.add(compileArgument(arguments.head));
+          arguments = arguments.tail;
+        } else {
+          result.add(compileDefaultValue(element));
+        }
+      });
+    } else {
+      // Visit named arguments and add them into a temporary list.
+      List compiledNamedArguments = [];
+      for (; !arguments.isEmpty; arguments = arguments.tail) {
+        NamedArgument namedArgument = arguments.head;
+        compiledNamedArguments.add(compileArgument(namedArgument.expression));
+      }
+      // Iterate over the optional parameters of the signature, and try to
+      // find them in [compiledNamedArguments]. If found, we use the
+      // value in the temporary list, otherwise the default value.
+      parameters.orderedOptionalParameters.forEach((ParameterElement element) {
+        int foundIndex = namedArguments.indexOf(element.name);
+        if (foundIndex != -1) {
+          result.add(compiledNamedArguments[foundIndex]);
+        } else {
+          result.add(compileDefaultValue(element));
+        }
+      });
+    }
+    return result;
+  }
+
+  /**
+   * Fills [list] with the arguments in the order expected by
+   * [callee], and where [caller] is a synthesized element
+   *
+   * [compileArgument] is a function that returns a compiled version
+   * of a parameter of [callee].
+   *
+   * [compileConstant] is a function that returns a compiled constant
+   * of an optional argument that is not in the parameters of [callee].
+   *
+   * Returns [:true:] if the signature of the [caller] matches the
+   * signature of the [callee], [:false:] otherwise.
+   */
+  static /*<T>*/ bool addForwardingElementArgumentsToList(
+      ConstructorElement caller,
+      List/*<T>*/ list,
+      ConstructorElement callee,
+      /*T*/ compileArgument(ParameterElement element),
+      /*T*/ compileConstant(ParameterElement element)) {
+    assert(invariant(caller, !callee.isErroneous,
+        message: "Cannot compute arguments to erroneous constructor: "
+                 "$caller calling $callee."));
+
+    FunctionSignature signature = caller.functionSignature;
+    Map<Node, ParameterElement> mapping = <Node, ParameterElement>{};
+
+    // TODO(ngeoffray): This is a hack that fakes up AST nodes, so
+    // that we can call [addArgumentsToList].
+    Link<Node> computeCallNodesFromParameters() {
+      LinkBuilder<Node> builder = new LinkBuilder<Node>();
+      signature.forEachRequiredParameter((ParameterElement element) {
+        Node node = element.node;
+        mapping[node] = element;
+        builder.addLast(node);
+      });
+      if (signature.optionalParametersAreNamed) {
+        signature.forEachOptionalParameter((ParameterElement element) {
+          mapping[element.initializer] = element;
+          builder.addLast(new NamedArgument(null, null, element.initializer));
+        });
+      } else {
+        signature.forEachOptionalParameter((ParameterElement element) {
+          Node node = element.node;
+          mapping[node] = element;
+          builder.addLast(node);
+        });
+      }
+      return builder.toLink();
+    }
+
+    /*T*/ internalCompileArgument(Node node) {
+      return compileArgument(mapping[node]);
+    }
+
+    Link<Node> nodes = computeCallNodesFromParameters();
+
+    // Synthesize a structure for the call.
+    // TODO(ngeoffray): Should the resolver do it instead?
+    List<String> namedParameters;
+    if (signature.optionalParametersAreNamed) {
+      namedParameters =
+          signature.optionalParameters.map((e) => e.name).toList();
+    }
+    CallStructure callStructure =
+        new CallStructure(signature.parameterCount, namedParameters);
+    if (!callStructure.signatureApplies(signature)) {
+      return false;
+    }
+    list.addAll(callStructure.makeArgumentsList(
+        nodes,
+        callee,
+        internalCompileArgument,
+        compileConstant));
+
+    return true;
+  }
+
+  static bool sameNames(List<String> first, List<String> second) {
+    for (int i = 0; i < first.length; i++) {
+      if (first[i] != second[i]) return false;
+    }
+    return true;
+  }
+}
+
+///
+class NamedCallStructure extends CallStructure {
+  final List<String> namedArguments;
+  final List<String> _orderedNamedArguments = <String>[];
+
+  NamedCallStructure(int argumentCount, this.namedArguments)
+      : super.unnamed(argumentCount) {
+    assert(namedArguments.isNotEmpty);
+  }
+
+  @override
+  bool get isNamed => true;
+
+  @override
+  bool get isUnnamed => false;
+
+  @override
+  int get namedArgumentCount => namedArguments.length;
+
+  @override
+  int get positionalArgumentCount => argumentCount - namedArgumentCount;
+
+  @override
+  List<String> getOrderedNamedArguments() {
+    if (!_orderedNamedArguments.isEmpty) return _orderedNamedArguments;
+
+    _orderedNamedArguments.addAll(namedArguments);
+    _orderedNamedArguments.sort((String first, String second) {
+      return first.compareTo(second);
+    });
+    return _orderedNamedArguments;
+  }
+
+  @override
+  String structureToString() {
+    return 'arity=$argumentCount, named=[${namedArguments.join(', ')}]';
+  }
+}
diff --git a/pkg/compiler/lib/src/universe/class_set.dart b/pkg/compiler/lib/src/universe/class_set.dart
index 11d9e09..d19b2c1 100644
--- a/pkg/compiler/lib/src/universe/class_set.dart
+++ b/pkg/compiler/lib/src/universe/class_set.dart
@@ -12,7 +12,27 @@
 ///
 /// This is used by the [ClassWorld] to perform queries on subclass and subtype
 /// relations.
-// TODO(johnniwinther): Use this for `ClassWorld.subtypesOf`.
+///
+/// For this class hierarchy:
+///
+///     class A {}
+///     class B extends A {}
+///     class C extends A {}
+///     class D extends B {}
+///     class E extends D {}
+///
+/// the [ClassHierarchyNode]s form this subclass tree:
+///
+///       Object
+///         |
+///         A
+///        / \
+///       B   C
+///       |
+///       D
+///       |
+///       E
+///
 class ClassHierarchyNode {
   final ClassElement cls;
 
@@ -47,39 +67,240 @@
     _directSubclasses = _directSubclasses.prepend(subclass);
   }
 
+  /// Returns `true` if [other] is contained in the subtree of this node.
+  ///
+  /// This means that [other] is a subclass of [cls].
+  bool contains(ClassElement other) {
+    while (other != null) {
+      if (cls == other) return true;
+      if (cls.hierarchyDepth >= other.hierarchyDepth) return false;
+      other = other.superclass;
+    }
+    return false;
+  }
+
   /// `true` if [cls] has been directly or indirectly instantiated.
   bool get isInstantiated => isDirectlyInstantiated || isIndirectlyInstantiated;
 
   /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
-  /// If [directlyInstantiated] is `true`, the iterable only returns the
-  /// directly instantiated subclasses of [cls].
-  Iterable<ClassElement> subclasses({bool directlyInstantiated: true}) {
+  ///
+  /// The directly instantiated, indirectly instantiated and uninstantiated
+  /// subclasses of [cls] are returned if [includeDirectlyInstantiated],
+  /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`,
+  /// respectively. If [strict] is `true`, [cls] itself is _not_ returned.
+  Iterable<ClassElement> subclasses(
+      {bool includeDirectlyInstantiated: true,
+       bool includeIndirectlyInstantiated: true,
+       bool includeUninstantiated: true,
+       bool strict: false}) {
     return new ClassHierarchyNodeIterable(
-        this, directlyInstantiatedOnly: directlyInstantiated);
+        this,
+        includeRoot: !strict,
+        includeDirectlyInstantiated: includeDirectlyInstantiated,
+        includeIndirectlyInstantiated: includeIndirectlyInstantiated,
+        includeUninstantiated: includeUninstantiated);
   }
 
-  /// Returns an [Iterable] of the strict subclasses of [cls] _not_ including
-  /// [cls] itself. If [directlyInstantiated] is `true`, the iterable only
-  /// returns the directly instantiated subclasses of [cls].
-  Iterable<ClassElement> strictSubclasses(
-      {bool directlyInstantiated: true}) {
-    return new ClassHierarchyNodeIterable(this,
-        includeRoot: false, directlyInstantiatedOnly: directlyInstantiated);
+  void dump(StringBuffer sb, String indentation) {
+    sb.write('$indentation$cls:[');
+    if (_directSubclasses.isEmpty) {
+      sb.write(']');
+    } else {
+      sb.write('\n');
+      bool needsComma = false;
+      for (Link<ClassHierarchyNode> link = _directSubclasses;
+           !link.isEmpty;
+           link = link.tail) {
+        if (needsComma) {
+          sb.write(',\n');
+        }
+        link.head.dump(sb, '$indentation  ');
+        needsComma = true;
+      }
+      sb.write('\n');
+      sb.write('$indentation]');
+    }
   }
 
   String toString() => cls.toString();
 }
 
+/// Object holding the subclass and subtype relation for a single
+/// [ClassElement].
+///
+/// The subclass relation for a class `C` is modelled through a reference to
+/// the [ClassHierarchyNode] for `C` in the global [ClassHierarchyNode] tree
+/// computed in [World].
+///
+/// The subtype relation for a class `C` is modelled through a collection of
+/// disjoint [ClassHierarchyNode] subtrees. The subclasses of `C`, modelled
+/// through the aforementioned [ClassHierarchyNode] pointer, are extended with
+/// the subtypes that do not extend `C` through a list of additional
+/// [ClassHierarchyNode] nodes. This list is normalized to contain only the
+/// nodes for the topmost subtypes and is furthermore ordered in increasing
+/// hierarchy depth order.
+///
+/// For this class hierarchy:
+///
+///     class A {}
+///     class B extends A {}
+///     class C implements B {}
+///     class D implements A {}
+///     class E extends D {}
+///     class F implements D {}
+///
+/// the [ClassHierarchyNode] tree is
+///
+///       Object
+///      / |  | \
+///     A  C  D  F
+///     |     |
+///     B     E
+///
+/// and the [ClassSet] for `A` holds these [ClassHierarchyNode] nodes:
+///
+///      A  ->  [C, D, F]
+///
+/// The subtypes `B` and `E` are not directly modeled because they are implied
+/// by their subclass relation to `A` and `D`, repectively. This can be seen
+/// if we expand the subclass subtrees:
+///
+///      A  ->  [C, D, F]
+///      |          |
+///      B          E
+///
+class ClassSet {
+  final ClassHierarchyNode node;
+
+  List<ClassHierarchyNode> _directSubtypes;
+
+  ClassSet(this.node);
+
+  ClassElement get cls => node.cls;
+
+  /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
+  ///
+  /// The directly instantiated, indirectly instantiated and uninstantiated
+  /// subclasses of [cls] are returned if [includeDirectlyInstantiated],
+  /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`,
+  /// respectively. If [strict] is `true`, [cls] itself is _not_ returned.
+  Iterable<ClassElement> subclasses(
+      {bool includeDirectlyInstantiated: true,
+       bool includeIndirectlyInstantiated: true,
+       bool includeUninstantiated: true,
+       bool strict: false}) {
+    return node.subclasses(
+        strict: strict,
+        includeDirectlyInstantiated: includeDirectlyInstantiated,
+        includeIndirectlyInstantiated: includeIndirectlyInstantiated,
+        includeUninstantiated: includeUninstantiated);
+  }
+
+  /// Returns an [Iterable] of the subtypes of [cls] possibly including [cls].
+  ///
+  /// The directly instantiated, indirectly instantiated and uninstantiated
+  /// subtypes of [cls] are returned if [includeDirectlyInstantiated],
+  /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`,
+  /// respectively. If [strict] is `true`, [cls] itself is _not_ returned.
+  Iterable<ClassElement> subtypes(
+      {bool includeDirectlyInstantiated: true,
+       bool includeIndirectlyInstantiated: true,
+       bool includeUninstantiated: true,
+       bool strict: false}) {
+    if (_directSubtypes == null) {
+      return node.subclasses(
+          strict: strict,
+          includeDirectlyInstantiated: includeDirectlyInstantiated,
+          includeIndirectlyInstantiated: includeIndirectlyInstantiated,
+          includeUninstantiated: includeUninstantiated);
+    }
+    return new SubtypesIterable.SubtypesIterator(this,
+        includeRoot: !strict,
+        includeDirectlyInstantiated: includeDirectlyInstantiated,
+        includeIndirectlyInstantiated: includeIndirectlyInstantiated,
+        includeUninstantiated: includeUninstantiated);
+  }
+
+  /// Adds [subtype] as a subtype of [cls].
+  void addSubtype(ClassHierarchyNode subtype) {
+    if (node.contains(subtype.cls)) {
+      return;
+    }
+    if (_directSubtypes == null) {
+      _directSubtypes = <ClassHierarchyNode>[subtype];
+    } else {
+      int hierarchyDepth = subtype.cls.hierarchyDepth;
+      List<ClassHierarchyNode> newSubtypes = <ClassHierarchyNode>[];
+      bool added = false;
+      for (ClassHierarchyNode otherSubtype in _directSubtypes) {
+        int otherHierarchyDepth = otherSubtype.cls.hierarchyDepth;
+        if (hierarchyDepth == otherHierarchyDepth) {
+          if (subtype == otherSubtype) {
+            return;
+          } else {
+            // [otherSubtype] is unrelated to [subtype].
+            newSubtypes.add(otherSubtype);
+          }
+        } else if (hierarchyDepth > otherSubtype.cls.hierarchyDepth) {
+          // [otherSubtype] could be a superclass of [subtype].
+          if (otherSubtype.contains(subtype.cls)) {
+            // [subtype] is already in this set.
+            return;
+          } else {
+            // [otherSubtype] is unrelated to [subtype].
+            newSubtypes.add(otherSubtype);
+          }
+        } else {
+          if (!added) {
+            // Insert [subtype] before other subtypes of higher hierarchy depth.
+            newSubtypes.add(subtype);
+            added = true;
+          }
+          // [subtype] could be a superclass of [otherSubtype].
+          if (subtype.contains(otherSubtype.cls)) {
+            // Replace [otherSubtype].
+          } else {
+            newSubtypes.add(otherSubtype);
+          }
+        }
+      }
+      if (!added) {
+        newSubtypes.add(subtype);
+      }
+      _directSubtypes = newSubtypes;
+    }
+  }
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.write('[\n');
+    node.dump(sb, '  ');
+    sb.write('\n');
+    if (_directSubtypes != null) {
+      for (ClassHierarchyNode node in _directSubtypes) {
+        node.dump(sb, '  ');
+        sb.write('\n');
+      }
+    }
+    sb.write(']');
+    return sb.toString();
+  }
+}
+
 /// Iterable for subclasses of a [ClassHierarchyNode].
 class ClassHierarchyNodeIterable extends IterableBase<ClassElement> {
   final ClassHierarchyNode root;
   final bool includeRoot;
-  final bool directlyInstantiatedOnly;
+  final bool includeDirectlyInstantiated;
+  final bool includeIndirectlyInstantiated;
+  final bool includeUninstantiated;
 
   ClassHierarchyNodeIterable(
       this.root,
       {this.includeRoot: true,
-       this.directlyInstantiatedOnly: false}) {
+       this.includeDirectlyInstantiated: true,
+       this.includeIndirectlyInstantiated: true,
+       this.includeUninstantiated: true}) {
     if (root == null) throw new StateError("No root for iterable.");
   }
 
@@ -112,7 +333,13 @@
 
   bool get includeRoot => iterable.includeRoot;
 
-  bool get directlyInstantiatedOnly => iterable.directlyInstantiatedOnly;
+  bool get includeDirectlyInstantiated => iterable.includeDirectlyInstantiated;
+
+  bool get includeIndirectlyInstantiated {
+    return iterable.includeIndirectlyInstantiated;
+  }
+
+  bool get includeUninstantiated => iterable.includeUninstantiated;
 
   @override
   ClassElement get current {
@@ -143,6 +370,11 @@
       }
       currentNode = stack.head;
       stack = stack.tail;
+      if (!includeUninstantiated && !currentNode.isInstantiated) {
+        // We're only iterating instantiated classes so there is no use in
+        // visiting the current node and its subtree.
+        continue;
+      }
       for (Link<ClassHierarchyNode> link = currentNode._directSubclasses;
            !link.isEmpty;
            link = link.tail) {
@@ -157,9 +389,90 @@
   /// Returns `true` if the class of [node] is a valid result for this iterator.
   bool _isValid(ClassHierarchyNode node) {
     if (!includeRoot && node == root) return false;
-    if (directlyInstantiatedOnly && !node.isDirectlyInstantiated) return false;
-    return true;
+    if (includeDirectlyInstantiated && node.isDirectlyInstantiated) {
+      return true;
+    }
+    if (includeIndirectlyInstantiated && node.isIndirectlyInstantiated) {
+      return true;
+    }
+    if (includeUninstantiated && !node.isInstantiated) {
+      return true;
+    }
+    return false;
   }
 }
 
+/// Iterable for the subtypes in a [ClassSet].
+class SubtypesIterable extends IterableBase<ClassElement> {
+  final ClassSet subtypeSet;
+  final bool includeRoot;
+  final bool includeDirectlyInstantiated;
+  final bool includeIndirectlyInstantiated;
+  final bool includeUninstantiated;
 
+  SubtypesIterable.SubtypesIterator(
+      this.subtypeSet,
+      {this.includeRoot: true,
+       this.includeDirectlyInstantiated: true,
+       this.includeIndirectlyInstantiated: true,
+       this.includeUninstantiated: true});
+
+  @override
+  Iterator<ClassElement> get iterator => new SubtypesIterator(this);
+}
+
+/// Iterator for the subtypes in a [ClassSet].
+class SubtypesIterator extends Iterator<ClassElement> {
+  final SubtypesIterable iterable;
+  Iterator<ClassElement> elements;
+  Iterator<ClassHierarchyNode> hierarchyNodes;
+
+  SubtypesIterator(this.iterable);
+
+  bool get includeRoot => iterable.includeRoot;
+
+  bool get includeDirectlyInstantiated => iterable.includeDirectlyInstantiated;
+
+  bool get includeIndirectlyInstantiated {
+    return iterable.includeIndirectlyInstantiated;
+  }
+
+  bool get includeUninstantiated => iterable.includeUninstantiated;
+
+  @override
+  ClassElement get current {
+    if (elements != null) {
+      return elements.current;
+    }
+    return null;
+  }
+
+  @override
+  bool moveNext() {
+    if (elements == null && hierarchyNodes == null) {
+      // Initial state. Iterate through subclasses.
+      elements = iterable.subtypeSet.node.subclasses(
+          strict: !includeRoot,
+          includeDirectlyInstantiated: includeDirectlyInstantiated,
+          includeIndirectlyInstantiated: includeIndirectlyInstantiated,
+          includeUninstantiated: includeUninstantiated).iterator;
+    }
+    if (elements != null && elements.moveNext()) {
+      return true;
+    }
+    if (hierarchyNodes == null) {
+      // Start iterating through subtypes.
+      hierarchyNodes = iterable.subtypeSet._directSubtypes.iterator;
+    }
+    while (hierarchyNodes.moveNext()) {
+      elements = hierarchyNodes.current.subclasses(
+          includeDirectlyInstantiated: includeDirectlyInstantiated,
+          includeIndirectlyInstantiated: includeIndirectlyInstantiated,
+          includeUninstantiated: includeUninstantiated).iterator;
+      if (elements.moveNext()) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
diff --git a/pkg/compiler/lib/src/universe/selector.dart b/pkg/compiler/lib/src/universe/selector.dart
new file mode 100644
index 0000000..94fa6b4
--- /dev/null
+++ b/pkg/compiler/lib/src/universe/selector.dart
@@ -0,0 +1,271 @@
+// Copyright (c) 2015, 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 universe;
+
+class SelectorKind {
+  final String name;
+  final int hashCode;
+  const SelectorKind(this.name, this.hashCode);
+
+  static const SelectorKind GETTER = const SelectorKind('getter', 0);
+  static const SelectorKind SETTER = const SelectorKind('setter', 1);
+  static const SelectorKind CALL = const SelectorKind('call', 2);
+  static const SelectorKind OPERATOR = const SelectorKind('operator', 3);
+  static const SelectorKind INDEX = const SelectorKind('index', 4);
+
+  String toString() => name;
+}
+
+class Selector {
+  final SelectorKind kind;
+  final Name memberName;
+  final CallStructure callStructure;
+
+  final int hashCode;
+
+  int get argumentCount => callStructure.argumentCount;
+  int get namedArgumentCount => callStructure.namedArgumentCount;
+  int get positionalArgumentCount => callStructure.positionalArgumentCount;
+  List<String> get namedArguments => callStructure.namedArguments;
+
+  String get name => memberName.text;
+
+  LibraryElement get library => memberName.library;
+
+  static const Name INDEX_NAME = const PublicName("[]");
+  static const Name INDEX_SET_NAME = const PublicName("[]=");
+  static const Name CALL_NAME = Names.call;
+
+  Selector.internal(this.kind,
+                    this.memberName,
+                    this.callStructure,
+                    this.hashCode) {
+    assert(kind == SelectorKind.INDEX ||
+           (memberName != INDEX_NAME && memberName != INDEX_SET_NAME));
+    assert(kind == SelectorKind.OPERATOR ||
+           kind == SelectorKind.INDEX ||
+           !Elements.isOperatorName(memberName.text) ||
+           identical(memberName.text, '??'));
+    assert(kind == SelectorKind.CALL ||
+           kind == SelectorKind.GETTER ||
+           kind == SelectorKind.SETTER ||
+           Elements.isOperatorName(memberName.text) ||
+           identical(memberName.text, '??'));
+  }
+
+  // TODO(johnniwinther): Extract caching.
+  static Map<int, List<Selector>> canonicalizedValues =
+      new Map<int, List<Selector>>();
+
+  factory Selector(SelectorKind kind,
+                   Name name,
+                   CallStructure callStructure) {
+    // TODO(johnniwinther): Maybe use equality instead of implicit hashing.
+    int hashCode = computeHashCode(kind, name, callStructure);
+    List<Selector> list = canonicalizedValues.putIfAbsent(hashCode,
+        () => <Selector>[]);
+    for (int i = 0; i < list.length; i++) {
+      Selector existing = list[i];
+      if (existing.match(kind, name, callStructure)) {
+        assert(existing.hashCode == hashCode);
+        return existing;
+      }
+    }
+    Selector result = new Selector.internal(
+        kind, name, callStructure, hashCode);
+    list.add(result);
+    return result;
+  }
+
+  factory Selector.fromElement(Element element) {
+    Name name = new Name(element.name, element.library);
+    if (element.isFunction) {
+      if (name == INDEX_NAME) {
+        return new Selector.index();
+      } else if (name == INDEX_SET_NAME) {
+        return new Selector.indexSet();
+      }
+      FunctionSignature signature =
+          element.asFunctionElement().functionSignature;
+      int arity = signature.parameterCount;
+      List<String> namedArguments = null;
+      if (signature.optionalParametersAreNamed) {
+        namedArguments =
+            signature.orderedOptionalParameters.map((e) => e.name).toList();
+      }
+      if (element.isOperator) {
+        // Operators cannot have named arguments, however, that doesn't prevent
+        // a user from declaring such an operator.
+        return new Selector(
+            SelectorKind.OPERATOR,
+            name,
+            new CallStructure(arity, namedArguments));
+      } else {
+        return new Selector.call(
+            name, new CallStructure(arity, namedArguments));
+      }
+    } else if (element.isSetter) {
+      return new Selector.setter(name);
+    } else if (element.isGetter) {
+      return new Selector.getter(name);
+    } else if (element.isField) {
+      return new Selector.getter(name);
+    } else if (element.isConstructor) {
+      return new Selector.callConstructor(name);
+    } else {
+      throw new SpannableAssertionFailure(
+          element, "Can't get selector from $element");
+    }
+  }
+
+  factory Selector.getter(Name name)
+      => new Selector(SelectorKind.GETTER,
+                      name.getter,
+                      CallStructure.NO_ARGS);
+
+  factory Selector.setter(Name name)
+      => new Selector(SelectorKind.SETTER,
+                      name.setter,
+                      CallStructure.ONE_ARG);
+
+  factory Selector.unaryOperator(String name) => new Selector(
+      SelectorKind.OPERATOR,
+      new PublicName(Elements.constructOperatorName(name, true)),
+      CallStructure.NO_ARGS);
+
+  factory Selector.binaryOperator(String name) => new Selector(
+      SelectorKind.OPERATOR,
+      new PublicName(Elements.constructOperatorName(name, false)),
+      CallStructure.ONE_ARG);
+
+  factory Selector.index()
+      => new Selector(SelectorKind.INDEX, INDEX_NAME,
+                      CallStructure.ONE_ARG);
+
+  factory Selector.indexSet()
+      => new Selector(SelectorKind.INDEX, INDEX_SET_NAME,
+                      CallStructure.TWO_ARGS);
+
+  factory Selector.call(Name name, CallStructure callStructure)
+      => new Selector(SelectorKind.CALL, name, callStructure);
+
+  factory Selector.callClosure(int arity, [List<String> namedArguments])
+      => new Selector(SelectorKind.CALL, CALL_NAME,
+                      new CallStructure(arity, namedArguments));
+
+  factory Selector.callClosureFrom(Selector selector)
+      => new Selector(SelectorKind.CALL, CALL_NAME, selector.callStructure);
+
+  factory Selector.callConstructor(Name name,
+                                   [int arity = 0,
+                                    List<String> namedArguments])
+      => new Selector(SelectorKind.CALL, name,
+                      new CallStructure(arity, namedArguments));
+
+  factory Selector.callDefaultConstructor()
+      => new Selector(
+          SelectorKind.CALL,
+          const PublicName(''),
+          CallStructure.NO_ARGS);
+
+  bool get isGetter => kind == SelectorKind.GETTER;
+  bool get isSetter => kind == SelectorKind.SETTER;
+  bool get isCall => kind == SelectorKind.CALL;
+  bool get isClosureCall => isCall && memberName == CALL_NAME;
+
+  bool get isIndex => kind == SelectorKind.INDEX && argumentCount == 1;
+  bool get isIndexSet => kind == SelectorKind.INDEX && argumentCount == 2;
+
+  bool get isOperator => kind == SelectorKind.OPERATOR;
+  bool get isUnaryOperator => isOperator && argumentCount == 0;
+
+  /** Check whether this is a call to 'assert'. */
+  bool get isAssert => isCall && identical(name, "assert");
+
+  /**
+   * The member name for invocation mirrors created from this selector.
+   */
+  String get invocationMirrorMemberName =>
+      isSetter ? '$name=' : name;
+
+  int get invocationMirrorKind {
+    const int METHOD = 0;
+    const int GETTER = 1;
+    const int SETTER = 2;
+    int kind = METHOD;
+    if (isGetter) {
+      kind = GETTER;
+    } else if (isSetter) {
+      kind = SETTER;
+    }
+    return kind;
+  }
+
+  bool appliesUnnamed(Element element, World world) {
+    assert(sameNameHack(element, world));
+    return appliesUntyped(element, world);
+  }
+
+  bool appliesUntyped(Element element, World world) {
+    assert(sameNameHack(element, world));
+    if (Elements.isUnresolved(element)) return false;
+    if (memberName.isPrivate && memberName.library != element.library) {
+      // TODO(johnniwinther): Maybe this should be
+      // `memberName != element.memberName`.
+      return false;
+    }
+    if (world.isForeign(element)) return true;
+    if (element.isSetter) return isSetter;
+    if (element.isGetter) return isGetter || isCall;
+    if (element.isField) {
+      return isSetter
+          ? !element.isFinal && !element.isConst
+          : isGetter || isCall;
+    }
+    if (isGetter) return true;
+    if (isSetter) return false;
+    return signatureApplies(element);
+  }
+
+  bool signatureApplies(FunctionElement function) {
+    if (Elements.isUnresolved(function)) return false;
+    return callStructure.signatureApplies(function.functionSignature);
+  }
+
+  bool sameNameHack(Element element, World world) {
+    // TODO(ngeoffray): Remove workaround checks.
+    return element.isConstructor ||
+           name == element.name ||
+           name == 'assert' && world.isAssertMethod(element);
+  }
+
+  bool applies(Element element, World world) {
+    if (!sameNameHack(element, world)) return false;
+    return appliesUnnamed(element, world);
+  }
+
+  bool match(SelectorKind kind,
+             Name memberName,
+             CallStructure callStructure) {
+    return this.kind == kind
+        && this.memberName == memberName
+        && this.callStructure.match(callStructure);
+  }
+
+  static int computeHashCode(SelectorKind kind,
+                             Name name,
+                             CallStructure callStructure) {
+    // Add bits from name and kind.
+    int hash = Hashing.mixHashCodeBits(name.hashCode, kind.hashCode);
+    // Add bits from the call structure.
+    return Hashing.mixHashCodeBits(hash, callStructure.hashCode);
+  }
+
+  String toString() {
+    return 'Selector($kind, $name, ${callStructure.structureToString()})';
+  }
+
+  Selector toCallSelector() => new Selector.callClosureFrom(this);
+}
diff --git a/pkg/compiler/lib/src/universe/universe.dart b/pkg/compiler/lib/src/universe/universe.dart
index 4530400..5268be3 100644
--- a/pkg/compiler/lib/src/universe/universe.dart
+++ b/pkg/compiler/lib/src/universe/universe.dart
@@ -25,7 +25,9 @@
     ClassWorld,
     World;
 
+part 'call_structure.dart';
 part 'function_set.dart';
+part 'selector.dart';
 part 'side_effects.dart';
 
 class UniverseSelector {
@@ -371,546 +373,3 @@
         }));
   }
 }
-
-class SelectorKind {
-  final String name;
-  final int hashCode;
-  const SelectorKind(this.name, this.hashCode);
-
-  static const SelectorKind GETTER = const SelectorKind('getter', 0);
-  static const SelectorKind SETTER = const SelectorKind('setter', 1);
-  static const SelectorKind CALL = const SelectorKind('call', 2);
-  static const SelectorKind OPERATOR = const SelectorKind('operator', 3);
-  static const SelectorKind INDEX = const SelectorKind('index', 4);
-
-  String toString() => name;
-}
-
-/// The structure of the arguments at a call-site.
-// TODO(johnniwinther): Should these be cached?
-// TODO(johnniwinther): Should isGetter/isSetter be part of the call structure
-// instead of the selector?
-class CallStructure {
-  static const CallStructure NO_ARGS = const CallStructure.unnamed(0);
-  static const CallStructure ONE_ARG = const CallStructure.unnamed(1);
-  static const CallStructure TWO_ARGS = const CallStructure.unnamed(2);
-
-  /// The numbers of arguments of the call. Includes named arguments.
-  final int argumentCount;
-
-  /// The number of named arguments of the call.
-  int get namedArgumentCount => 0;
-
-  /// The number of positional argument of the call.
-  int get positionalArgumentCount => argumentCount;
-
-  const CallStructure.unnamed(this.argumentCount);
-
-  factory CallStructure(int argumentCount, [List<String> namedArguments]) {
-    if (namedArguments == null || namedArguments.isEmpty) {
-      return new CallStructure.unnamed(argumentCount);
-    }
-    return new NamedCallStructure(argumentCount, namedArguments);
-  }
-
-  /// `true` if this call has named arguments.
-  bool get isNamed => false;
-
-  /// `true` if this call has no named arguments.
-  bool get isUnnamed => true;
-
-  /// The names of the named arguments in call-site order.
-  List<String> get namedArguments => const <String>[];
-
-  /// The names of the named arguments in canonicalized order.
-  List<String> getOrderedNamedArguments() => const <String>[];
-
-  /// A description of the argument structure.
-  String structureToString() => 'arity=$argumentCount';
-
-  String toString() => 'CallStructure(${structureToString()})';
-
-  Selector get callSelector {
-    return new Selector(SelectorKind.CALL, Selector.CALL_NAME, this);
-  }
-
-  bool match(CallStructure other) {
-    if (identical(this, other)) return true;
-    return this.argumentCount == other.argumentCount
-        && this.namedArgumentCount == other.namedArgumentCount
-        && sameNames(this.namedArguments, other.namedArguments);
-  }
-
-  // TODO(johnniwinther): Cache hash code?
-  int get hashCode {
-    return Hashing.listHash(namedArguments,
-        Hashing.objectHash(argumentCount, namedArguments.length));
-  }
-
-  bool operator ==(other) {
-    if (other is! CallStructure) return false;
-    return match(other);
-  }
-
-  bool signatureApplies(FunctionSignature parameters) {
-    if (argumentCount > parameters.parameterCount) return false;
-    int requiredParameterCount = parameters.requiredParameterCount;
-    int optionalParameterCount = parameters.optionalParameterCount;
-    if (positionalArgumentCount < requiredParameterCount) return false;
-
-    if (!parameters.optionalParametersAreNamed) {
-      // We have already checked that the number of arguments are
-      // not greater than the number of parameters. Therefore the
-      // number of positional arguments are not greater than the
-      // number of parameters.
-      assert(positionalArgumentCount <= parameters.parameterCount);
-      return namedArguments.isEmpty;
-    } else {
-      if (positionalArgumentCount > requiredParameterCount) return false;
-      assert(positionalArgumentCount == requiredParameterCount);
-      if (namedArgumentCount > optionalParameterCount) return false;
-      Set<String> nameSet = new Set<String>();
-      parameters.optionalParameters.forEach((Element element) {
-        nameSet.add(element.name);
-      });
-      for (String name in namedArguments) {
-        if (!nameSet.contains(name)) return false;
-        // TODO(5213): By removing from the set we are checking
-        // that we are not passing the name twice. We should have this
-        // check in the resolver also.
-        nameSet.remove(name);
-      }
-      return true;
-    }
-  }
-
-  /**
-   * Returns a `List` with the evaluated arguments in the normalized order.
-   *
-   * [compileDefaultValue] is a function that returns a compiled constant
-   * of an optional argument that is not in [compiledArguments].
-   *
-   * Precondition: `this.applies(element, world)`.
-   *
-   * Invariant: [element] must be the implementation element.
-   */
-  /*<T>*/ List/*<T>*/ makeArgumentsList(
-      Link<Node> arguments,
-      FunctionElement element,
-      /*T*/ compileArgument(Node argument),
-      /*T*/ compileDefaultValue(ParameterElement element)) {
-    assert(invariant(element, element.isImplementation));
-    List/*<T>*/ result = new List();
-
-    FunctionSignature parameters = element.functionSignature;
-    parameters.forEachRequiredParameter((ParameterElement element) {
-      result.add(compileArgument(arguments.head));
-      arguments = arguments.tail;
-    });
-
-    if (!parameters.optionalParametersAreNamed) {
-      parameters.forEachOptionalParameter((ParameterElement element) {
-        if (!arguments.isEmpty) {
-          result.add(compileArgument(arguments.head));
-          arguments = arguments.tail;
-        } else {
-          result.add(compileDefaultValue(element));
-        }
-      });
-    } else {
-      // Visit named arguments and add them into a temporary list.
-      List compiledNamedArguments = [];
-      for (; !arguments.isEmpty; arguments = arguments.tail) {
-        NamedArgument namedArgument = arguments.head;
-        compiledNamedArguments.add(compileArgument(namedArgument.expression));
-      }
-      // Iterate over the optional parameters of the signature, and try to
-      // find them in [compiledNamedArguments]. If found, we use the
-      // value in the temporary list, otherwise the default value.
-      parameters.orderedOptionalParameters.forEach((ParameterElement element) {
-        int foundIndex = namedArguments.indexOf(element.name);
-        if (foundIndex != -1) {
-          result.add(compiledNamedArguments[foundIndex]);
-        } else {
-          result.add(compileDefaultValue(element));
-        }
-      });
-    }
-    return result;
-  }
-
-  /**
-   * Fills [list] with the arguments in the order expected by
-   * [callee], and where [caller] is a synthesized element
-   *
-   * [compileArgument] is a function that returns a compiled version
-   * of a parameter of [callee].
-   *
-   * [compileConstant] is a function that returns a compiled constant
-   * of an optional argument that is not in the parameters of [callee].
-   *
-   * Returns [:true:] if the signature of the [caller] matches the
-   * signature of the [callee], [:false:] otherwise.
-   */
-  static /*<T>*/ bool addForwardingElementArgumentsToList(
-      ConstructorElement caller,
-      List/*<T>*/ list,
-      ConstructorElement callee,
-      /*T*/ compileArgument(ParameterElement element),
-      /*T*/ compileConstant(ParameterElement element)) {
-    assert(invariant(caller, !callee.isErroneous,
-        message: "Cannot compute arguments to erroneous constructor: "
-                 "$caller calling $callee."));
-
-    FunctionSignature signature = caller.functionSignature;
-    Map<Node, ParameterElement> mapping = <Node, ParameterElement>{};
-
-    // TODO(ngeoffray): This is a hack that fakes up AST nodes, so
-    // that we can call [addArgumentsToList].
-    Link<Node> computeCallNodesFromParameters() {
-      LinkBuilder<Node> builder = new LinkBuilder<Node>();
-      signature.forEachRequiredParameter((ParameterElement element) {
-        Node node = element.node;
-        mapping[node] = element;
-        builder.addLast(node);
-      });
-      if (signature.optionalParametersAreNamed) {
-        signature.forEachOptionalParameter((ParameterElement element) {
-          mapping[element.initializer] = element;
-          builder.addLast(new NamedArgument(null, null, element.initializer));
-        });
-      } else {
-        signature.forEachOptionalParameter((ParameterElement element) {
-          Node node = element.node;
-          mapping[node] = element;
-          builder.addLast(node);
-        });
-      }
-      return builder.toLink();
-    }
-
-    /*T*/ internalCompileArgument(Node node) {
-      return compileArgument(mapping[node]);
-    }
-
-    Link<Node> nodes = computeCallNodesFromParameters();
-
-    // Synthesize a structure for the call.
-    // TODO(ngeoffray): Should the resolver do it instead?
-    List<String> namedParameters;
-    if (signature.optionalParametersAreNamed) {
-      namedParameters =
-          signature.optionalParameters.map((e) => e.name).toList();
-    }
-    CallStructure callStructure =
-        new CallStructure(signature.parameterCount, namedParameters);
-    if (!callStructure.signatureApplies(signature)) {
-      return false;
-    }
-    list.addAll(callStructure.makeArgumentsList(
-        nodes,
-        callee,
-        internalCompileArgument,
-        compileConstant));
-
-    return true;
-  }
-
-  static bool sameNames(List<String> first, List<String> second) {
-    for (int i = 0; i < first.length; i++) {
-      if (first[i] != second[i]) return false;
-    }
-    return true;
-  }
-}
-
-///
-class NamedCallStructure extends CallStructure {
-  final List<String> namedArguments;
-  final List<String> _orderedNamedArguments = <String>[];
-
-  NamedCallStructure(int argumentCount, this.namedArguments)
-      : super.unnamed(argumentCount) {
-    assert(namedArguments.isNotEmpty);
-  }
-
-  @override
-  bool get isNamed => true;
-
-  @override
-  bool get isUnnamed => false;
-
-  @override
-  int get namedArgumentCount => namedArguments.length;
-
-  @override
-  int get positionalArgumentCount => argumentCount - namedArgumentCount;
-
-  @override
-  List<String> getOrderedNamedArguments() {
-    if (!_orderedNamedArguments.isEmpty) return _orderedNamedArguments;
-
-    _orderedNamedArguments.addAll(namedArguments);
-    _orderedNamedArguments.sort((String first, String second) {
-      return first.compareTo(second);
-    });
-    return _orderedNamedArguments;
-  }
-
-  @override
-  String structureToString() {
-    return 'arity=$argumentCount, named=[${namedArguments.join(', ')}]';
-  }
-}
-
-class Selector {
-  final SelectorKind kind;
-  final Name memberName;
-  final CallStructure callStructure;
-
-  final int hashCode;
-
-  int get argumentCount => callStructure.argumentCount;
-  int get namedArgumentCount => callStructure.namedArgumentCount;
-  int get positionalArgumentCount => callStructure.positionalArgumentCount;
-  List<String> get namedArguments => callStructure.namedArguments;
-
-  String get name => memberName.text;
-
-  LibraryElement get library => memberName.library;
-
-  static const Name INDEX_NAME = const PublicName("[]");
-  static const Name INDEX_SET_NAME = const PublicName("[]=");
-  static const Name CALL_NAME = Names.call;
-
-  Selector.internal(this.kind,
-                    this.memberName,
-                    this.callStructure,
-                    this.hashCode) {
-    assert(kind == SelectorKind.INDEX ||
-           (memberName != INDEX_NAME && memberName != INDEX_SET_NAME));
-    assert(kind == SelectorKind.OPERATOR ||
-           kind == SelectorKind.INDEX ||
-           !Elements.isOperatorName(memberName.text) ||
-           identical(memberName.text, '??'));
-    assert(kind == SelectorKind.CALL ||
-           kind == SelectorKind.GETTER ||
-           kind == SelectorKind.SETTER ||
-           Elements.isOperatorName(memberName.text) ||
-           identical(memberName.text, '??'));
-  }
-
-  // TODO(johnniwinther): Extract caching.
-  static Map<int, List<Selector>> canonicalizedValues =
-      new Map<int, List<Selector>>();
-
-  factory Selector(SelectorKind kind,
-                   Name name,
-                   CallStructure callStructure) {
-    // TODO(johnniwinther): Maybe use equality instead of implicit hashing.
-    int hashCode = computeHashCode(kind, name, callStructure);
-    List<Selector> list = canonicalizedValues.putIfAbsent(hashCode,
-        () => <Selector>[]);
-    for (int i = 0; i < list.length; i++) {
-      Selector existing = list[i];
-      if (existing.match(kind, name, callStructure)) {
-        assert(existing.hashCode == hashCode);
-        return existing;
-      }
-    }
-    Selector result = new Selector.internal(
-        kind, name, callStructure, hashCode);
-    list.add(result);
-    return result;
-  }
-
-  factory Selector.fromElement(Element element) {
-    Name name = new Name(element.name, element.library);
-    if (element.isFunction) {
-      if (name == INDEX_NAME) {
-        return new Selector.index();
-      } else if (name == INDEX_SET_NAME) {
-        return new Selector.indexSet();
-      }
-      FunctionSignature signature =
-          element.asFunctionElement().functionSignature;
-      int arity = signature.parameterCount;
-      List<String> namedArguments = null;
-      if (signature.optionalParametersAreNamed) {
-        namedArguments =
-            signature.orderedOptionalParameters.map((e) => e.name).toList();
-      }
-      if (element.isOperator) {
-        // Operators cannot have named arguments, however, that doesn't prevent
-        // a user from declaring such an operator.
-        return new Selector(
-            SelectorKind.OPERATOR,
-            name,
-            new CallStructure(arity, namedArguments));
-      } else {
-        return new Selector.call(
-            name, new CallStructure(arity, namedArguments));
-      }
-    } else if (element.isSetter) {
-      return new Selector.setter(name);
-    } else if (element.isGetter) {
-      return new Selector.getter(name);
-    } else if (element.isField) {
-      return new Selector.getter(name);
-    } else if (element.isConstructor) {
-      return new Selector.callConstructor(name);
-    } else {
-      throw new SpannableAssertionFailure(
-          element, "Can't get selector from $element");
-    }
-  }
-
-  factory Selector.getter(Name name)
-      => new Selector(SelectorKind.GETTER,
-                      name.getter,
-                      CallStructure.NO_ARGS);
-
-  factory Selector.setter(Name name)
-      => new Selector(SelectorKind.SETTER,
-                      name.setter,
-                      CallStructure.ONE_ARG);
-
-  factory Selector.unaryOperator(String name) => new Selector(
-      SelectorKind.OPERATOR,
-      new PublicName(Elements.constructOperatorName(name, true)),
-      CallStructure.NO_ARGS);
-
-  factory Selector.binaryOperator(String name) => new Selector(
-      SelectorKind.OPERATOR,
-      new PublicName(Elements.constructOperatorName(name, false)),
-      CallStructure.ONE_ARG);
-
-  factory Selector.index()
-      => new Selector(SelectorKind.INDEX, INDEX_NAME,
-                      CallStructure.ONE_ARG);
-
-  factory Selector.indexSet()
-      => new Selector(SelectorKind.INDEX, INDEX_SET_NAME,
-                      CallStructure.TWO_ARGS);
-
-  factory Selector.call(Name name, CallStructure callStructure)
-      => new Selector(SelectorKind.CALL, name, callStructure);
-
-  factory Selector.callClosure(int arity, [List<String> namedArguments])
-      => new Selector(SelectorKind.CALL, CALL_NAME,
-                      new CallStructure(arity, namedArguments));
-
-  factory Selector.callClosureFrom(Selector selector)
-      => new Selector(SelectorKind.CALL, CALL_NAME, selector.callStructure);
-
-  factory Selector.callConstructor(Name name,
-                                   [int arity = 0,
-                                    List<String> namedArguments])
-      => new Selector(SelectorKind.CALL, name,
-                      new CallStructure(arity, namedArguments));
-
-  factory Selector.callDefaultConstructor()
-      => new Selector(
-          SelectorKind.CALL,
-          const PublicName(''),
-          CallStructure.NO_ARGS);
-
-  bool get isGetter => kind == SelectorKind.GETTER;
-  bool get isSetter => kind == SelectorKind.SETTER;
-  bool get isCall => kind == SelectorKind.CALL;
-  bool get isClosureCall => isCall && memberName == CALL_NAME;
-
-  bool get isIndex => kind == SelectorKind.INDEX && argumentCount == 1;
-  bool get isIndexSet => kind == SelectorKind.INDEX && argumentCount == 2;
-
-  bool get isOperator => kind == SelectorKind.OPERATOR;
-  bool get isUnaryOperator => isOperator && argumentCount == 0;
-
-  /** Check whether this is a call to 'assert'. */
-  bool get isAssert => isCall && identical(name, "assert");
-
-  /**
-   * The member name for invocation mirrors created from this selector.
-   */
-  String get invocationMirrorMemberName =>
-      isSetter ? '$name=' : name;
-
-  int get invocationMirrorKind {
-    const int METHOD = 0;
-    const int GETTER = 1;
-    const int SETTER = 2;
-    int kind = METHOD;
-    if (isGetter) {
-      kind = GETTER;
-    } else if (isSetter) {
-      kind = SETTER;
-    }
-    return kind;
-  }
-
-  bool appliesUnnamed(Element element, World world) {
-    assert(sameNameHack(element, world));
-    return appliesUntyped(element, world);
-  }
-
-  bool appliesUntyped(Element element, World world) {
-    assert(sameNameHack(element, world));
-    if (Elements.isUnresolved(element)) return false;
-    if (memberName.isPrivate && memberName.library != element.library) {
-      // TODO(johnniwinther): Maybe this should be
-      // `memberName != element.memberName`.
-      return false;
-    }
-    if (world.isForeign(element)) return true;
-    if (element.isSetter) return isSetter;
-    if (element.isGetter) return isGetter || isCall;
-    if (element.isField) {
-      return isSetter
-          ? !element.isFinal && !element.isConst
-          : isGetter || isCall;
-    }
-    if (isGetter) return true;
-    if (isSetter) return false;
-    return signatureApplies(element);
-  }
-
-  bool signatureApplies(FunctionElement function) {
-    if (Elements.isUnresolved(function)) return false;
-    return callStructure.signatureApplies(function.functionSignature);
-  }
-
-  bool sameNameHack(Element element, World world) {
-    // TODO(ngeoffray): Remove workaround checks.
-    return element.isConstructor ||
-           name == element.name ||
-           name == 'assert' && world.isAssertMethod(element);
-  }
-
-  bool applies(Element element, World world) {
-    if (!sameNameHack(element, world)) return false;
-    return appliesUnnamed(element, world);
-  }
-
-  bool match(SelectorKind kind,
-             Name memberName,
-             CallStructure callStructure) {
-    return this.kind == kind
-        && this.memberName == memberName
-        && this.callStructure.match(callStructure);
-  }
-
-  static int computeHashCode(SelectorKind kind,
-                             Name name,
-                             CallStructure callStructure) {
-    // Add bits from name and kind.
-    int hash = Hashing.mixHashCodeBits(name.hashCode, kind.hashCode);
-    // Add bits from the call structure.
-    return Hashing.mixHashCodeBits(hash, callStructure.hashCode);
-  }
-
-  String toString() {
-    return 'Selector($kind, $name, ${callStructure.structureToString()})';
-  }
-
-  Selector toCallSelector() => new Selector.callClosureFrom(this);
-}
diff --git a/pkg/compiler/lib/src/use_unused_api.dart b/pkg/compiler/lib/src/use_unused_api.dart
index bdb0acf..d2e8648 100644
--- a/pkg/compiler/lib/src/use_unused_api.dart
+++ b/pkg/compiler/lib/src/use_unused_api.dart
@@ -144,6 +144,7 @@
     ..asFor()
     ..asFunctionDeclaration()
     ..asIf()
+    ..asImport()
     ..asLabeledStatement()
     ..asLibraryDependency()
     ..asLibraryName()
@@ -226,7 +227,7 @@
 }
 
 useJsBackend(js_backend.JavaScriptBackend backend) {
-  backend.assembleCode(null);
+  backend.getGeneratedCode(null);
 }
 
 useConcreteTypesInferrer(concrete_types_inferrer.ConcreteTypesInferrer c) {
@@ -270,7 +271,9 @@
   sourceFileProvider.getSourceFile(null);
   world.hasAnyUserDefinedGetter(null, null);
   world.subclassesOf(null);
-  world.classHierarchyNode(null);
+  world.getClassHierarchyNode(null);
+  world.getClassSet(null);
+  world.haveAnyCommonSubtypes(null, null);
   typeGraphInferrer.getCallersOf(null);
   dart_types.Types.sorted(null);
   new dart_types.Types(compiler).copy(compiler);
diff --git a/pkg/compiler/lib/src/util/link.dart b/pkg/compiler/lib/src/util/link.dart
index d09639c..3a9c133 100644
--- a/pkg/compiler/lib/src/util/link.dart
+++ b/pkg/compiler/lib/src/util/link.dart
@@ -122,19 +122,31 @@
   Link copyWithout(e) => this;
 }
 
+/// Builder object for creating linked lists using [Link] or fixed-length [List]
+/// objects.
 abstract class LinkBuilder<T> {
   factory LinkBuilder() = LinkBuilderImplementation;
 
-  /**
-   * Prepends all elements added to the builder to [tail]. The resulting list is
-   * returned and the builder is cleared.
-   */
+  /// Prepends all elements added to the builder to [tail]. The resulting list
+  /// is returned and the builder is cleared.
   Link<T> toLink([Link<T> tail = const Link()]);
 
+  /// Creates a new fixed length containing all added elements. The
+  /// resulting list is returned and the builder is cleared.
   List<T> toList();
 
+  /// Adds the element [t] to the end of the list being built.
   Link<T> addLast(T t);
 
+  /// Returns the first element in the list being built.
+  T get first;
+
+  /// Returns the number of elements in the list being built.
   final int length;
+
+  /// Returns `true` if the list being built is empty.
   final bool isEmpty;
+
+  /// Removes all added elements and resets the builder.
+  void clear();
 }
diff --git a/pkg/compiler/lib/src/util/link_implementation.dart b/pkg/compiler/lib/src/util/link_implementation.dart
index 74d9f23..973ef50 100644
--- a/pkg/compiler/lib/src/util/link_implementation.dart
+++ b/pkg/compiler/lib/src/util/link_implementation.dart
@@ -169,6 +169,7 @@
     Link<T> link = head;
     lastLink = null;
     head = null;
+    length = 0;
     return link;
   }
 
@@ -184,6 +185,7 @@
     }
     lastLink = null;
     head = null;
+    length = 0;
     return list;
   }
 
@@ -200,4 +202,17 @@
   }
 
   bool get isEmpty => length == 0;
+
+  T get first {
+    if (head != null) {
+      return head.head;
+    }
+    throw new StateError("no elements");
+  }
+
+  void clear() {
+    head = null;
+    lastLink = null;
+    length = 0;
+  }
 }
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index e8c9b13..6cfa45f 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -89,6 +89,9 @@
   /// including [cls] if it is live.
   Iterable<ClassElement> strictSubtypesOf(ClassElement cls);
 
+  /// Returns `true` if [a] and [b] have any known common subtypes.
+  bool haveAnyCommonSubtypes(ClassElement a, ClassElement b);
+
   /// Returns `true` if any live class other than [cls] extends [cls].
   bool hasAnyStrictSubclass(ClassElement cls);
 
@@ -131,6 +134,7 @@
   ClassElement get intClass => compiler.intClass;
   ClassElement get doubleClass => compiler.doubleClass;
   ClassElement get stringClass => compiler.stringClass;
+  ClassElement get nullClass => compiler.nullClass;
 
   /// Cache of [ti.FlatTypeMask]s grouped by the 8 possible values of the
   /// [ti.FlatTypeMask.flags] property.
@@ -185,9 +189,9 @@
   Iterable<ClassElement> subclassesOf(ClassElement cls) {
     ClassHierarchyNode hierarchy = _classHierarchyNodes[cls.declaration];
     if (hierarchy == null) return const <ClassElement>[];
-    assert(invariant(cls, isInstantiated(cls.declaration),
-        message: 'Class $cls has not been instantiated.'));
-    return hierarchy.subclasses();
+    return hierarchy.subclasses(
+        includeIndirectlyInstantiated: false,
+        includeUninstantiated: false);
   }
 
   /// Returns an iterable over the directly instantiated classes that extend
@@ -195,16 +199,39 @@
   Iterable<ClassElement> strictSubclassesOf(ClassElement cls) {
     ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration];
     if (subclasses == null) return const <ClassElement>[];
-    assert(invariant(cls, isInstantiated(cls.declaration),
-        message: 'Class $cls has not been instantiated.'));
-    return subclasses.strictSubclasses();
+    return subclasses.subclasses(
+        strict: true,
+        includeIndirectlyInstantiated: false,
+        includeUninstantiated: false);
   }
 
   /// Returns an iterable over the directly instantiated that implement [cls]
   /// _not_ including [cls].
   Iterable<ClassElement> strictSubtypesOf(ClassElement cls) {
-    Set<ClassElement> subtypes = _subtypes[cls.declaration];
-    return subtypes != null ? subtypes : const <ClassElement>[];
+    ClassSet classSet = _classSets[cls.declaration];
+    if (classSet == null) {
+      return const <ClassElement>[];
+    } else {
+      return classSet.subtypes(
+          strict: true,
+          includeIndirectlyInstantiated: false,
+          includeUninstantiated: false);
+    }
+  }
+
+  /// Returns `true` if [a] and [b] have any known common subtypes.
+  bool haveAnyCommonSubtypes(ClassElement a, ClassElement b) {
+    ClassSet classSetA = _classSets[a.declaration];
+    ClassSet classSetB = _classSets[b.declaration];
+    if (classSetA == null || classSetB == null) return false;
+    // TODO(johnniwinther): Implement an optimized query on [ClassSet].
+    Set<ClassElement> subtypesOfB = classSetB.subtypes().toSet();
+    for (ClassElement subtypeOfA in classSetA.subtypes()) {
+      if (subtypesOfB.contains(subtypeOfA)) {
+        return true;
+      }
+    }
+    return false;
   }
 
   /// Returns `true` if any directly instantiated class other than [cls] extends
@@ -212,8 +239,6 @@
   bool hasAnyStrictSubclass(ClassElement cls) {
     ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration];
     if (subclasses == null) return false;
-    assert(invariant(cls, isInstantiated(cls.declaration),
-        message: 'Class $cls has not been instantiated.'));
     return subclasses.isIndirectlyInstantiated;
   }
 
@@ -338,8 +363,8 @@
   // distinct sets to make class hierarchy analysis faster.
   final Map<ClassElement, ClassHierarchyNode> _classHierarchyNodes =
       <ClassElement, ClassHierarchyNode>{};
-  final Map<ClassElement, Set<ClassElement>> _subtypes =
-      new Map<ClassElement, Set<ClassElement>>();
+  final Map<ClassElement, ClassSet> _classSets =
+        <ClassElement, ClassSet>{};
 
   final Set<Element> sideEffectsFreeElements = new Set<Element>();
 
@@ -371,38 +396,81 @@
         this.compiler = compiler,
         alreadyPopulated = compiler.cacheStrategy.newSet();
 
-  ClassHierarchyNode classHierarchyNode(ClassElement cls) {
-    return _classHierarchyNodes[cls];
+  /// Called to add [cls] to the set of known classes.
+  ///
+  /// This ensures that class hierarchy queries can be performed on [cls] and
+  /// classes that extend or implement it.
+  void registerClass(ClassElement cls) {
+    _ensureClassSet(cls);
+  }
+
+  /// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies
+  /// of known classes.
+  ///
+  /// This method is only provided for testing. For queries on classes, use the
+  /// methods defined in [ClassWorld].
+  ClassHierarchyNode getClassHierarchyNode(ClassElement cls) {
+    return _classHierarchyNodes[cls.declaration];
+  }
+
+  ClassHierarchyNode _ensureClassHierarchyNode(ClassElement cls) {
+    cls = cls.declaration;
+    return _classHierarchyNodes.putIfAbsent(cls, () {
+      ClassHierarchyNode node = new ClassHierarchyNode(cls);
+      if (cls.superclass != null) {
+        _ensureClassHierarchyNode(cls.superclass).addDirectSubclass(node);
+      }
+      return node;
+    });
+  }
+
+  /// Returns [ClassSet] for [cls] used to model the extends and implements
+  /// relations of known classes.
+  ///
+  /// This method is only provided for testing. For queries on classes, use the
+  /// methods defined in [ClassWorld].
+  ClassSet getClassSet(ClassElement cls) {
+    return _classSets[cls.declaration];
+  }
+
+  ClassSet _ensureClassSet(ClassElement cls) {
+    cls = cls.declaration;
+    return _classSets.putIfAbsent(cls, () {
+      ClassHierarchyNode node = _ensureClassHierarchyNode(cls);
+      ClassSet classSet = new ClassSet(node);
+
+      for (InterfaceType type in cls.allSupertypes) {
+        // TODO(johnniwinther): Optimization: Avoid adding [cls] to
+        // superclasses.
+        ClassSet subtypeSet = _ensureClassSet(type.element);
+        subtypeSet.addSubtype(node);
+      }
+      return classSet;
+    });
   }
 
   void populate() {
-
-    /// Ensure that a [ClassHierarchyNode] exists for [cls]. Updates the
-    /// `isDirectlyInstantiated` and `isIndirectlyInstantiated` property of the
-    /// node according the provided arguments and returns the node.
-    ClassHierarchyNode createClassHierarchyNodeForClass(
+    /// Updates the `isDirectlyInstantiated` and `isIndirectlyInstantiated`
+    /// properties of the [ClassHierarchyNode] for [cls].
+    void updateClassHierarchyNodeForClass(
         ClassElement cls,
         {bool directlyInstantiated: false,
          bool indirectlyInstantiated: false}) {
-      assert(isInstantiated(cls));
-
-      ClassHierarchyNode node = _classHierarchyNodes.putIfAbsent(cls, () {
-        ClassHierarchyNode node = new ClassHierarchyNode(cls);
-        if (cls.superclass != null) {
-          createClassHierarchyNodeForClass(cls.superclass,
-              indirectlyInstantiated:
-                directlyInstantiated || indirectlyInstantiated)
-              .addDirectSubclass(node);
-        }
-        return node;
-      });
-      if (directlyInstantiated) {
+      assert(!directlyInstantiated || isInstantiated(cls));
+      ClassHierarchyNode node = getClassHierarchyNode(cls);
+      bool changed = false;
+      if (directlyInstantiated && !node.isDirectlyInstantiated) {
         node.isDirectlyInstantiated = true;
+        changed = true;
       }
-      if (indirectlyInstantiated) {
+      if (indirectlyInstantiated && !node.isIndirectlyInstantiated) {
         node.isIndirectlyInstantiated = true;
+        changed = true;
       }
-      return node;
+      if (changed && cls.superclass != null) {
+        updateClassHierarchyNodeForClass(
+            cls.superclass, indirectlyInstantiated: true);
+      }
     }
 
     void addSubtypes(ClassElement cls) {
@@ -414,13 +482,7 @@
         compiler.internalError(cls, 'Class "${cls.name}" is not resolved.');
       }
 
-      createClassHierarchyNodeForClass(cls, directlyInstantiated: true);
-
-      for (DartType type in cls.allSupertypes) {
-        Set<Element> subtypesOfSupertype =
-            _subtypes.putIfAbsent(type.element, () => new Set<ClassElement>());
-        subtypesOfSupertype.add(cls);
-      }
+      updateClassHierarchyNodeForClass(cls, directlyInstantiated: true);
 
       // Walk through the superclasses, and record the types
       // implemented by that type on the superclasses.
diff --git a/pkg/compiler/pubspec.yaml b/pkg/compiler/pubspec.yaml
index fe774b2..8e74b36 100644
--- a/pkg/compiler/pubspec.yaml
+++ b/pkg/compiler/pubspec.yaml
@@ -4,6 +4,7 @@
 #version: do-not-upload
 dependencies:
   package_config: ^0.1.1
+  pub_semver: ^1.2.1
   js_ast:
     path: ../js_ast
   js_runtime:
diff --git a/pkg/js_ast/lib/src/printer.dart b/pkg/js_ast/lib/src/printer.dart
index 8523916..7a1124f 100644
--- a/pkg/js_ast/lib/src/printer.dart
+++ b/pkg/js_ast/lib/src/printer.dart
@@ -136,7 +136,7 @@
 
   int get lastCharCode {
     if (lastAddedString == null) return 0;
-    assert(lastAddedString.length != "");
+    assert(lastAddedString.length != 0);
     return lastAddedString.codeUnitAt(lastAddedString.length - 1);
   }
 
diff --git a/pkg/lookup_map/CHANGELOG.md b/pkg/lookup_map/CHANGELOG.md
index cbe7954a..beb0eb0 100644
--- a/pkg/lookup_map/CHANGELOG.md
+++ b/pkg/lookup_map/CHANGELOG.md
@@ -1,4 +1,7 @@
 # Changelog
 
+## 0.0.1+1
+- Fix minor typo in readme.
+
 ## 0.0.1
 - Initial version of `LookupMap`
diff --git a/pkg/lookup_map/README.md b/pkg/lookup_map/README.md
index ecab6b5..a333791 100644
--- a/pkg/lookup_map/README.md
+++ b/pkg/lookup_map/README.md
@@ -2,7 +2,7 @@
 
 This package contains the definition of `LookupMap`: a simple, but very
 restricted map. The map can only hold constant keys and the only way to use the
-map is to retrieve values with a key you already have.  Expect for lookup, any
+map is to retrieve values with a key you already have.  Except for lookup, any
 other operation in `Map` (like forEach, keys, values, length, etc) is not
 available.
 
diff --git a/pkg/lookup_map/lib/lookup_map.dart b/pkg/lookup_map/lib/lookup_map.dart
index 0c03094..65ac754 100644
--- a/pkg/lookup_map/lib/lookup_map.dart
+++ b/pkg/lookup_map/lib/lookup_map.dart
@@ -7,7 +7,7 @@
 
 /// [LookupMap] is a simple, but very restricted map.  The map can only hold
 /// constant keys and the only way to use the map is to retrieve values with a
-/// key you already have.  Expect for lookup, any other operation in [Map] (like
+/// key you already have.  Except for lookup, any other operation in [Map] (like
 /// forEach, keys, values, length, etc) is not available.
 ///
 /// Constant [LookupMap]s are understood by dart2js and can be tree-shaken
@@ -97,4 +97,4 @@
 /// this code.
 // Note: this needs to be kept in sync with the pubspec, otherwise
 // test/version_check_test would fail.
-final _version = '0.0.1';
+final _version = '0.0.1+1';
diff --git a/pkg/lookup_map/pubspec.yaml b/pkg/lookup_map/pubspec.yaml
index 8c420d0..adaee09e 100644
--- a/pkg/lookup_map/pubspec.yaml
+++ b/pkg/lookup_map/pubspec.yaml
@@ -2,7 +2,7 @@
 description: a lookup-only map that can be tree-shaken by dart2js
 # Note: the version needs to be kept in sync with the string in
 # lib/lookup_map.dart, otherwise test/version_check_test would fail.
-version: 0.0.1
+version: 0.0.1+1
 author: "Dart Team <misc@dartlang.org>"
 homepage: https://github.com/dart-lang/sdk/blob/master/pkg/lookup_map/README.md
 dev_dependencies:
diff --git a/pkg/lookup_map/test/version_check_test.dart b/pkg/lookup_map/test/version_check_test.dart
index 2da0873..2bee1a6 100644
--- a/pkg/lookup_map/test/version_check_test.dart
+++ b/pkg/lookup_map/test/version_check_test.dart
@@ -11,8 +11,8 @@
 /// This dartdoc helps remove a warning for the unused import on [LookupMap].
 main() {
   test('validate version number matches', () {
-    var pubspecPath = Platform.script.resolve('../pubspec.yaml').path;
-    var yaml = loadYaml(new File(pubspecPath).readAsStringSync());
+    var pubspec = Platform.script.resolve('../pubspec.yaml');
+    var yaml = loadYaml(new File.fromUri(pubspec).readAsStringSync());
     var version1 = yaml['version'];
     var library = currentMirrorSystem().findLibrary(#lookup_map);
     var version2 = library.getField(new Symbol('_version')).reflectee;
diff --git a/pkg/pkgbuild.status b/pkg/pkgbuild.status
index aa7e83e..3cf95f1 100644
--- a/pkg/pkgbuild.status
+++ b/pkg/pkgbuild.status
@@ -8,7 +8,6 @@
 
 [ $use_repository_packages ]
 pkg/analyzer: PubGetError
-third_party/pkg/shelf: PubGetError # either shelf needs to be updated, or dart2js_info needs to be downgraded.
 samples/third_party/angular_todo: Fail # angular needs to be updated
 samples/third_party/todomvc_performance: Skip # dependencies are not in the repo
 
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index bbc4d3e..253d8d7 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -175,7 +175,7 @@
 }
 
 
-static_library("libdart_embedder_noio") {
+source_set("libdart_embedder_noio") {
   configs += ["..:dart_config",]
   deps = [
     "..:libdart",
diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index dfe9a74..78a71e7 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -295,7 +295,7 @@
       'conditions': [
         ['dart_io_support==1', {
           'dependencies': [
-            'bin/net/zlib.gyp:zlib_dart',
+            'bin/zlib.gyp:zlib_dart',
           ],
         }],
         ['dart_io_support==1 and dart_io_secure_socket==1', {
diff --git a/runtime/bin/builtin.h b/runtime/bin/builtin.h
index a943dc8..ab871af 100644
--- a/runtime/bin/builtin.h
+++ b/runtime/bin/builtin.h
@@ -49,7 +49,7 @@
   // load it.
   static Dart_Handle LoadAndCheckLibrary(BuiltinLibraryId id);
 
-  static void SetLoadPort(Dart_Port port);
+  static Dart_Handle SetLoadPort(Dart_Port port);
 
  private:
   // Map specified URI to an actual file name from 'source_paths' and read
diff --git a/runtime/bin/builtin_common.cc b/runtime/bin/builtin_common.cc
index da754a5..678e48b 100644
--- a/runtime/bin/builtin_common.cc
+++ b/runtime/bin/builtin_common.cc
@@ -10,27 +10,37 @@
 #include "bin/dartutils.h"
 #include "bin/platform.h"
 
+// Return the error from the containing function if handle is in error handle.
+#define RETURN_IF_ERROR(handle)                                                \
+  {                                                                            \
+    Dart_Handle __handle = handle;                                             \
+    if (Dart_IsError((__handle))) {                                            \
+      return __handle;                                                         \
+    }                                                                          \
+  }
+
 namespace dart {
 namespace bin {
 
-void Builtin::SetLoadPort(Dart_Port port) {
+Dart_Handle Builtin::SetLoadPort(Dart_Port port) {
   load_port_ = port;
   ASSERT(load_port_ != ILLEGAL_PORT);
   Dart_Handle field_name = DartUtils::NewString("_loadPort");
-  ASSERT(!Dart_IsError(field_name));
+  RETURN_IF_ERROR(field_name);
   Dart_Handle builtin_lib =
       Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
-  ASSERT(!Dart_IsError(builtin_lib));
+  RETURN_IF_ERROR(builtin_lib);
   Dart_Handle send_port = Dart_GetField(builtin_lib, field_name);
-  ASSERT(!Dart_IsError(send_port));
+  RETURN_IF_ERROR(send_port);
   if (!Dart_IsNull(send_port)) {
     // Already created and set.
-    return;
+    return Dart_True();
   }
   send_port = Dart_NewSendPort(load_port_);
-  ASSERT(!Dart_IsError(send_port));
+  RETURN_IF_ERROR(send_port);
   Dart_Handle result = Dart_SetField(builtin_lib, field_name, send_port);
-  ASSERT(!Dart_IsError(result));
+  RETURN_IF_ERROR(result);
+  return Dart_True();
 }
 
 }  // namespace bin
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index 1c77820..a4fc2e2 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -21,6 +21,15 @@
 #include "bin/socket.h"
 #include "bin/utils.h"
 
+// Return the error from the containing function if handle is in error handle.
+#define RETURN_IF_ERROR(handle)                                                \
+  {                                                                            \
+    Dart_Handle __handle = handle;                                             \
+    if (Dart_IsError((__handle))) {                                            \
+      return __handle;                                                         \
+    }                                                                          \
+  }
+
 namespace dart {
 namespace bin {
 
@@ -126,21 +135,17 @@
 }
 
 
-void DartUtils::SetIntegerField(Dart_Handle handle,
-                                const char* name,
-                                int64_t val) {
-  Dart_Handle result = Dart_SetField(handle,
-                                     NewString(name),
-                                     Dart_NewInteger(val));
-  if (Dart_IsError(result)) Dart_PropagateError(result);
+Dart_Handle DartUtils::SetIntegerField(Dart_Handle handle,
+                                       const char* name,
+                                       int64_t val) {
+  return Dart_SetField(handle, NewString(name), Dart_NewInteger(val));
 }
 
 
-void DartUtils::SetStringField(Dart_Handle handle,
+Dart_Handle DartUtils::SetStringField(Dart_Handle handle,
                                const char* name,
                                const char* val) {
-  Dart_Handle result = Dart_SetField(handle, NewString(name), NewString(val));
-  if (Dart_IsError(result)) Dart_PropagateError(result);
+  return Dart_SetField(handle, NewString(name), NewString(val));
 }
 
 
@@ -383,7 +388,7 @@
     // Resolve the url within the context of the library's URL.
     Dart_Handle builtin_lib =
         Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
-    DART_CHECK_VALID(builtin_lib);
+    RETURN_IF_ERROR(builtin_lib);
     return ResolveUri(library_url, url, builtin_lib);
   }
 
@@ -423,7 +428,7 @@
 
   Dart_Handle builtin_lib =
       Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
-  DART_CHECK_VALID(builtin_lib);
+  RETURN_IF_ERROR(builtin_lib);
   if (DartUtils::IsDartExtensionSchemeURL(url_string)) {
     // Load a native code shared library to use in a native extension
     if (tag != Dart_kImportTag) {
@@ -569,7 +574,9 @@
       } else {
         ASSERT(tag == Dart_kSourceTag);
         Dart_Handle library = Dart_LookupLibrary(library_uri);
-        DART_CHECK_VALID(library);
+        if (Dart_IsError(library)) {
+          Dart_PropagateError(library);
+        }
         result = Dart_LoadSource(library, resolved_script_uri, source, 0, 0);
       }
     }
@@ -630,37 +637,38 @@
   // Setup the internal library's 'internalPrint' function.
   Dart_Handle print = Dart_Invoke(
       builtin_lib, NewString("_getPrintClosure"), 0, NULL);
-  DART_CHECK_VALID(print);
+  RETURN_IF_ERROR(print);
   Dart_Handle result =
       Dart_SetField(internal_lib, NewString("_printClosure"), print);
-  DART_CHECK_VALID(result);
+  RETURN_IF_ERROR(result);
 
   if (!is_service_isolate) {
     if (IsWindowsHost()) {
       result = Dart_SetField(builtin_lib, NewString("_isWindows"), Dart_True());
-      DART_CHECK_VALID(result);
+      RETURN_IF_ERROR(result);
     }
     if (trace_loading) {
       result = Dart_SetField(builtin_lib,
                              NewString("_traceLoading"), Dart_True());
-      DART_CHECK_VALID(result);
+      RETURN_IF_ERROR(result);
     }
     // Set current working directory.
     result = SetWorkingDirectory(builtin_lib);
-    DART_CHECK_VALID(result);
+    RETURN_IF_ERROR(result);
     // Wait for the service isolate to initialize the load port.
     Dart_Port load_port = Dart_ServiceWaitForLoadPort();
     if (load_port == ILLEGAL_PORT) {
       return NewDartUnsupportedError("Service did not return load port.");
     }
-    Builtin::SetLoadPort(load_port);
+    result = Builtin::SetLoadPort(load_port);
+    RETURN_IF_ERROR(result);
   }
 
   // Set up package root if specified.
   if (package_root != NULL) {
     ASSERT(packages_file == NULL);
     result = NewString(package_root);
-    DART_CHECK_VALID(result);
+    RETURN_IF_ERROR(result);
     const int kNumArgs = 1;
     Dart_Handle dart_args[kNumArgs];
     dart_args[0] = result;
@@ -668,10 +676,10 @@
                          NewString("_setPackageRoot"),
                          kNumArgs,
                          dart_args);
-    DART_CHECK_VALID(result);
+    RETURN_IF_ERROR(result);
   } else if (packages_file != NULL) {
     result = NewString(packages_file);
-    DART_CHECK_VALID(result);
+    RETURN_IF_ERROR(result);
     const int kNumArgs = 1;
     Dart_Handle dart_args[kNumArgs];
     dart_args[0] = result;
@@ -679,47 +687,49 @@
                          NewString("_loadPackagesMap"),
                          kNumArgs,
                          dart_args);
-    DART_CHECK_VALID(result);
+    RETURN_IF_ERROR(result);
   }
   return Dart_True();
 }
 
 
-void DartUtils::PrepareCoreLibrary(Dart_Handle core_lib,
-                                   Dart_Handle builtin_lib,
-                                   bool is_service_isolate) {
+Dart_Handle DartUtils::PrepareCoreLibrary(Dart_Handle core_lib,
+                                          Dart_Handle builtin_lib,
+                                          bool is_service_isolate) {
   if (!is_service_isolate) {
     // Setup the 'Uri.base' getter in dart:core.
     Dart_Handle uri_base = Dart_Invoke(
         builtin_lib, NewString("_getUriBaseClosure"), 0, NULL);
-    DART_CHECK_VALID(uri_base);
+    RETURN_IF_ERROR(uri_base);
     Dart_Handle result = Dart_SetField(core_lib,
                                        NewString("_uriBaseClosure"),
                                        uri_base);
-    DART_CHECK_VALID(result);
+    RETURN_IF_ERROR(result);
   }
+  return Dart_True();
 }
 
 
-void DartUtils::PrepareAsyncLibrary(Dart_Handle async_lib,
-                                    Dart_Handle isolate_lib) {
+Dart_Handle DartUtils::PrepareAsyncLibrary(Dart_Handle async_lib,
+                                           Dart_Handle isolate_lib) {
   Dart_Handle schedule_immediate_closure =
       Dart_Invoke(isolate_lib, NewString("_getIsolateScheduleImmediateClosure"),
                   0, NULL);
+  RETURN_IF_ERROR(schedule_immediate_closure);
   Dart_Handle args[1];
   args[0] = schedule_immediate_closure;
-  DART_CHECK_VALID(Dart_Invoke(
-      async_lib, NewString("_setScheduleImmediateClosure"), 1, args));
+  return Dart_Invoke(
+      async_lib, NewString("_setScheduleImmediateClosure"), 1, args);
 }
 
 
-void DartUtils::PrepareIOLibrary(Dart_Handle io_lib) {
-  DART_CHECK_VALID(Dart_Invoke(io_lib, NewString("_setupHooks"), 0, NULL));
+Dart_Handle DartUtils::PrepareIOLibrary(Dart_Handle io_lib) {
+  return Dart_Invoke(io_lib, NewString("_setupHooks"), 0, NULL);
 }
 
 
-void DartUtils::PrepareIsolateLibrary(Dart_Handle isolate_lib) {
-  DART_CHECK_VALID(Dart_Invoke(isolate_lib, NewString("_setupHooks"), 0, NULL));
+Dart_Handle DartUtils::PrepareIsolateLibrary(Dart_Handle isolate_lib) {
+  return Dart_Invoke(isolate_lib, NewString("_setupHooks"), 0, NULL);
 }
 
 
@@ -730,28 +740,28 @@
                                                Dart_Handle builtin_lib) {
   // First ensure all required libraries are available.
   Dart_Handle url = NewString(kCoreLibURL);
-  DART_CHECK_VALID(url);
+  RETURN_IF_ERROR(url);
   Dart_Handle core_lib = Dart_LookupLibrary(url);
-  DART_CHECK_VALID(core_lib);
+  RETURN_IF_ERROR(core_lib);
   url = NewString(kAsyncLibURL);
-  DART_CHECK_VALID(url);
+  RETURN_IF_ERROR(url);
   Dart_Handle async_lib = Dart_LookupLibrary(url);
-  DART_CHECK_VALID(async_lib);
+  RETURN_IF_ERROR(async_lib);
   url = NewString(kIsolateLibURL);
-  DART_CHECK_VALID(url);
+  RETURN_IF_ERROR(url);
   Dart_Handle isolate_lib = Dart_LookupLibrary(url);
-  DART_CHECK_VALID(isolate_lib);
+  RETURN_IF_ERROR(isolate_lib);
   url = NewString(kInternalLibURL);
-  DART_CHECK_VALID(url);
+  RETURN_IF_ERROR(url);
   Dart_Handle internal_lib = Dart_LookupLibrary(url);
-  DART_CHECK_VALID(internal_lib);
+  RETURN_IF_ERROR(internal_lib);
   Dart_Handle io_lib = Builtin::LoadAndCheckLibrary(Builtin::kIOLibrary);
-  DART_CHECK_VALID(io_lib);
+  RETURN_IF_ERROR(io_lib);
 
   // We need to ensure that all the scripts loaded so far are finalized
   // as we are about to invoke some Dart code below to setup closures.
   Dart_Handle result = Dart_FinalizeLoading(false);
-  DART_CHECK_VALID(result);
+  RETURN_IF_ERROR(result);
 
   result = PrepareBuiltinLibrary(builtin_lib,
                                  internal_lib,
@@ -759,30 +769,32 @@
                                  trace_loading,
                                  package_root,
                                  packages_file);
-  DART_CHECK_VALID(result);
+  RETURN_IF_ERROR(result);
 
-  PrepareAsyncLibrary(async_lib, isolate_lib);
-  PrepareCoreLibrary(core_lib, builtin_lib, is_service_isolate);
-  PrepareIsolateLibrary(isolate_lib);
-  PrepareIOLibrary(io_lib);
+  RETURN_IF_ERROR(PrepareAsyncLibrary(async_lib, isolate_lib));
+  RETURN_IF_ERROR(PrepareCoreLibrary(
+      core_lib, builtin_lib, is_service_isolate));
+  RETURN_IF_ERROR(PrepareIsolateLibrary(isolate_lib));
+  RETURN_IF_ERROR(PrepareIOLibrary(io_lib));
   return result;
 }
 
 
-void DartUtils::SetupIOLibrary(const char* script_uri) {
+Dart_Handle DartUtils::SetupIOLibrary(const char* script_uri) {
   Dart_Handle io_lib_url = NewString(kIOLibURL);
-  DART_CHECK_VALID(io_lib_url);
+  RETURN_IF_ERROR(io_lib_url);
   Dart_Handle io_lib = Dart_LookupLibrary(io_lib_url);
-  DART_CHECK_VALID(io_lib);
+  RETURN_IF_ERROR(io_lib);
   Dart_Handle platform_type = GetDartType(DartUtils::kIOLibURL, "_Platform");
-  DART_CHECK_VALID(platform_type);
+  RETURN_IF_ERROR(platform_type);
   Dart_Handle script_name = NewString("_nativeScript");
-  DART_CHECK_VALID(script_name);
+  RETURN_IF_ERROR(script_name);
   Dart_Handle dart_script = NewString(script_uri);
-  DART_CHECK_VALID(dart_script);
+  RETURN_IF_ERROR(dart_script);
   Dart_Handle set_script_name =
       Dart_SetField(platform_type, script_name, dart_script);
-  DART_CHECK_VALID(set_script_name);
+  RETURN_IF_ERROR(set_script_name);
+  return Dart_Null();
 }
 
 
diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h
index 8a9c953..3118950 100644
--- a/runtime/bin/dartutils.h
+++ b/runtime/bin/dartutils.h
@@ -102,12 +102,12 @@
   // a boolean value an API error is propagated.
   static bool GetBooleanValue(Dart_Handle bool_obj);
 
-  static void SetIntegerField(Dart_Handle handle,
-                              const char* name,
-                              int64_t val);
-  static void SetStringField(Dart_Handle handle,
-                             const char* name,
-                             const char* val);
+  static Dart_Handle SetIntegerField(Dart_Handle handle,
+                                     const char* name,
+                                     int64_t val);
+  static Dart_Handle SetStringField(Dart_Handle handle,
+                                    const char* name,
+                                    const char* val);
   static bool IsDartSchemeURL(const char* url_name);
   static bool IsDartExtensionSchemeURL(const char* url_name);
   static bool IsDartIOLibURL(const char* url_name);
@@ -130,19 +130,19 @@
                                            bool trace_loading,
                                            const char* package_root,
                                            const char* packages_file);
-  static void PrepareCoreLibrary(Dart_Handle core_lib,
+  static Dart_Handle PrepareCoreLibrary(Dart_Handle core_lib,
                                  Dart_Handle builtin_lib,
                                  bool is_service_isolate);
-  static void PrepareAsyncLibrary(Dart_Handle async_lib,
+  static Dart_Handle PrepareAsyncLibrary(Dart_Handle async_lib,
                                   Dart_Handle isolate_lib);
-  static void PrepareIOLibrary(Dart_Handle io_lib);
-  static void PrepareIsolateLibrary(Dart_Handle isolate_lib);
+  static Dart_Handle PrepareIOLibrary(Dart_Handle io_lib);
+  static Dart_Handle PrepareIsolateLibrary(Dart_Handle isolate_lib);
   static Dart_Handle PrepareForScriptLoading(const char* package_root,
                                              const char* packages_file,
                                              bool is_service_isolate,
                                              bool trace_loading,
                                              Dart_Handle builtin_lib);
-  static void SetupIOLibrary(const char* script_uri);
+  static Dart_Handle SetupIOLibrary(const char* script_uri);
 
   static bool PostNull(Dart_Port port_id);
   static bool PostInt32(Dart_Port port_id, int32_t value);
diff --git a/runtime/bin/dbg_message.cc b/runtime/bin/dbg_message.cc
index a635880..0a3038a 100644
--- a/runtime/bin/dbg_message.cc
+++ b/runtime/bin/dbg_message.cc
@@ -1402,14 +1402,17 @@
 
 void DbgMsgQueueList::IsolateEventHandler(Dart_IsolateId isolate_id,
                                           Dart_IsolateEvent kind) {
-  DebuggerConnectionHandler::WaitForConnection();
-  Dart_EnterScope();
   if (kind == kCreated) {
+    DebuggerConnectionHandler::WaitForConnection();
+    Dart_EnterScope();
     DbgMsgQueue* msg_queue = AddIsolateMsgQueue(isolate_id);
     msg_queue->SendIsolateEvent(isolate_id, kind);
+    Dart_ExitScope();
   } else {
     DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id);
     if (msg_queue != NULL) {
+      DebuggerConnectionHandler::WaitForConnection();
+      Dart_EnterScope();
       msg_queue->SendQueuedMsgs();
       msg_queue->SendIsolateEvent(isolate_id, kind);
       if (kind == kInterrupted) {
@@ -1418,9 +1421,11 @@
         ASSERT(kind == kShutdown);
         RemoveIsolateMsgQueue(isolate_id);
       }
+      Dart_ExitScope();
     }
+    // If there is no receive message queue, do not wait for a connection, and
+    // ignore the message.
   }
-  Dart_ExitScope();
 }
 
 }  // namespace bin
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 4c18137..7c6c798 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -544,18 +544,19 @@
   // Initialize the Dart VM.
   // Note: We don't expect isolates to be created from dart code during
   // snapshot generation.
-  if (!Dart_Initialize(NULL, NULL,
-                       NULL, NULL, NULL, NULL,
-                       DartUtils::OpenFile,
-                       DartUtils::ReadFile,
-                       DartUtils::WriteFile,
-                       DartUtils::CloseFile,
-                       DartUtils::EntropySource)) {
-    Log::PrintErr("VM initialization failed\n");
+  char* error = Dart_Initialize(NULL, NULL,
+      NULL, NULL, NULL, NULL,
+      DartUtils::OpenFile,
+      DartUtils::ReadFile,
+      DartUtils::WriteFile,
+      DartUtils::CloseFile,
+      DartUtils::EntropySource);
+  if (error != NULL) {
+    Log::PrintErr("VM initialization failed: %s\n", error);
+    free(error);
     return 255;
   }
 
-  char* error;
   Dart_Isolate isolate = Dart_CreateIsolate(
       NULL, NULL, NULL, NULL, NULL, &error);
   if (isolate == NULL) {
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index ee7b80d..702a8a2 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -110,6 +110,7 @@
 // Exit code indicating an unhandled error that is not a compilation error.
 static const int kErrorExitCode = 255;
 
+extern bool do_vm_shutdown;  // Defined in bin/process.cc
 static void ErrorExit(int exit_code, const char* format, ...) {
   va_list arguments;
   va_start(arguments, format);
@@ -120,11 +121,19 @@
   Dart_ExitScope();
   Dart_ShutdownIsolate();
 
-  Dart_Cleanup();
+  // Terminate process exit-code handler.
+  Process::TerminateExitCodeHandler();
 
-  DebuggerConnectionHandler::StopHandler();
-  // TODO(zra): Stop the EventHandler once thread shutdown is enabled.
-  // EventHandler::Stop();
+  char* error = Dart_Cleanup();
+  if (error != NULL) {
+    Log::PrintErr("VM cleanup failed: %s\n", error);
+    free(error);
+  }
+
+  if (do_vm_shutdown) {
+    DebuggerConnectionHandler::StopHandler();
+    EventHandler::Stop();
+  }
   exit(exit_code);
 }
 
@@ -430,30 +439,60 @@
 }
 
 
+
+static bool ProcessShutdownOption(const char* arg,
+                                  CommandLineOptions* vm_options) {
+  ASSERT(arg != NULL);
+  if (*arg == '\0') {
+    do_vm_shutdown = true;
+    vm_options->AddArgument("--shutdown");
+    return true;
+  }
+
+  if ((*arg != '=') && (*arg != ':')) {
+    return false;
+  }
+
+  if (strcmp(arg + 1, "true") == 0) {
+    do_vm_shutdown = true;
+    vm_options->AddArgument("--shutdown");
+    return true;
+  } else if (strcmp(arg + 1, "false") == 0) {
+    do_vm_shutdown = false;
+    vm_options->AddArgument("--no-shutdown");
+    return true;
+  }
+
+  return false;
+}
+
+
 static struct {
   const char* option_name;
   bool (*process)(const char* option, CommandLineOptions* vm_options);
 } main_options[] = {
   // Standard options shared with dart2js.
-  { "--version", ProcessVersionOption },
-  { "--help", ProcessHelpOption },
-  { "-h", ProcessHelpOption },
-  { "--verbose", ProcessVerboseOption },
-  { "-v", ProcessVerboseOption },
-  { "--package-root=", ProcessPackageRootOption },
-  { "--packages=", ProcessPackagesOption },
   { "-D", ProcessEnvironmentOption },
+  { "-h", ProcessHelpOption },
+  { "--help", ProcessHelpOption },
+  { "--packages=", ProcessPackagesOption },
+  { "--package-root=", ProcessPackageRootOption },
+  { "-v", ProcessVerboseOption },
+  { "--verbose", ProcessVerboseOption },
+  { "--version", ProcessVersionOption },
+
   // VM specific options to the standalone dart program.
   { "--break-at=", ProcessBreakpointOption },
   { "--compile_all", ProcessCompileAllOption },
-  { "--gen-precompiled-snapshot", ProcessGenPrecompiledSnapshotOption },
-  { "--run-precompiled-snapshot", ProcessRunPrecompiledSnapshotOption },
   { "--debug", ProcessDebugOption },
-  { "--snapshot=", ProcessGenScriptSnapshotOption },
   { "--enable-vm-service", ProcessEnableVmServiceOption },
+  { "--gen-precompiled-snapshot", ProcessGenPrecompiledSnapshotOption },
   { "--observe", ProcessObserveOption },
+  { "--run-precompiled-snapshot", ProcessRunPrecompiledSnapshotOption },
+  { "--shutdown", ProcessShutdownOption },
+  { "--snapshot=", ProcessGenScriptSnapshotOption },
   { "--trace-debug-protocol", ProcessTraceDebugProtocolOption },
-  { "--trace-loading", ProcessTraceLoadingOption},
+  { "--trace-loading", ProcessTraceLoadingOption },
   { NULL, NULL }
 };
 
@@ -660,6 +699,7 @@
                                error);
 
   if (isolate == NULL) {
+    delete isolate_data;
     return NULL;
   }
 
@@ -681,10 +721,7 @@
       *error = strdup(VmService::GetErrorMessage());
       return NULL;
     }
-    if (has_gen_precompiled_snapshot) {
-      result = Dart_Precompile();
-      CHECK_RESULT(result);
-    } else if (has_compile_all) {
+    if (has_compile_all) {
       result = Dart_CompileAll();
       CHECK_RESULT(result);
     }
@@ -728,7 +765,8 @@
 
   Platform::SetPackageRoot(package_root);
 
-  DartUtils::SetupIOLibrary(script_uri);
+  result = DartUtils::SetupIOLibrary(script_uri);
+  CHECK_RESULT(result);
 
   // Make the isolate runnable so that it is ready to handle messages.
   Dart_ExitScope();
@@ -1001,7 +1039,9 @@
   File* file = File::Open(filename, File::kWriteTruncate);
   ASSERT(file != NULL);
   if (!file->WriteFully(buffer, size)) {
-    Log::PrintErr("Error: Failed to write snapshot file.\n\n");
+    ErrorExit(kErrorExitCode,
+              "Unable to open file %s for writing snapshot\n",
+              filename);
   }
   delete file;
 }
@@ -1011,14 +1051,14 @@
                              const uint8_t** buffer) {
   void* file = DartUtils::OpenFile(filename, false);
   if (file == NULL) {
-    Log::PrintErr("Error: Failed to open '%s'.\n\n", filename);
-    exit(kErrorExitCode);
+    ErrorExit(kErrorExitCode,
+              "Error: Unable to open file %s for reading snapshot\n", filename);
   }
   intptr_t len = -1;
   DartUtils::ReadFile(buffer, &len, file);
   if (*buffer == NULL || len == -1) {
-    Log::PrintErr("Error: Failed to read '%s'.\n\n", filename);
-    exit(kErrorExitCode);
+    ErrorExit(kErrorExitCode,
+              "Error: Unable to read snapshot file %s\n", filename);
   }
   DartUtils::CloseFile(file);
 }
@@ -1027,13 +1067,13 @@
 static void* LoadLibrarySymbol(const char* libname, const char* symname) {
   void* library = Extensions::LoadExtensionLibrary(libname);
   if (library == NULL) {
-    Log::PrintErr("Error: Failed to load library '%s'.\n\n", libname);
-    exit(kErrorExitCode);
+    ErrorExit(kErrorExitCode,
+              "Error: Failed to load library '%s'\n", libname);
   }
   void* symbol = Extensions::ResolveSymbol(library, symname);
   if (symbol == NULL) {
-    Log::PrintErr("Failed to load symbol '%s'\n", symname);
-    exit(kErrorExitCode);
+    ErrorExit(kErrorExitCode,
+              "Error: Failed to load symbol '%s'\n", symname);
   }
   return symbol;
 }
@@ -1121,18 +1161,22 @@
   }
 
   // Initialize the Dart VM.
-  if (!Dart_Initialize(vm_isolate_snapshot_buffer, instructions_snapshot,
-                       CreateIsolateAndSetup, NULL, NULL, ShutdownIsolate,
-                       DartUtils::OpenFile,
-                       DartUtils::ReadFile,
-                       DartUtils::WriteFile,
-                       DartUtils::CloseFile,
-                       DartUtils::EntropySource)) {
-    fprintf(stderr, "%s", "VM initialization failed\n");
+  char* error = Dart_Initialize(
+      vm_isolate_snapshot_buffer, instructions_snapshot,
+      CreateIsolateAndSetup, NULL, NULL, ShutdownIsolate,
+      DartUtils::OpenFile,
+      DartUtils::ReadFile,
+      DartUtils::WriteFile,
+      DartUtils::CloseFile,
+      DartUtils::EntropySource);
+  if (error != NULL) {
+    if (do_vm_shutdown) {
+      DebuggerConnectionHandler::StopHandler();
+      EventHandler::Stop();
+    }
+    fprintf(stderr, "VM initialization failed: %s\n", error);
     fflush(stderr);
-    DebuggerConnectionHandler::StopHandler();
-    // TODO(zra): Stop the EventHandler once thread shutdown is enabled.
-    // EventHandler::Stop();
+    free(error);
     exit(kErrorExitCode);
   }
 
@@ -1143,7 +1187,6 @@
 
   // Call CreateIsolateAndSetup which creates an isolate and loads up
   // the specified application script.
-  char* error = NULL;
   int exit_code = 0;
   char* isolate_name = BuildIsolateName(script_name, "main");
   Dart_Isolate isolate = CreateIsolateAndSetupHelper(script_name,
@@ -1156,10 +1199,18 @@
   if (isolate == NULL) {
     Log::PrintErr("%s\n", error);
     free(error);
+    error = NULL;
     delete [] isolate_name;
-    DebuggerConnectionHandler::StopHandler();
-    // TODO(zra): Stop the EventHandler once thread shutdown is enabled.
-    // EventHandler::Stop();
+    Process::TerminateExitCodeHandler();
+    error = Dart_Cleanup();
+    if (error != NULL) {
+      Log::PrintErr("VM cleanup failed: %s\n", error);
+      free(error);
+    }
+    if (do_vm_shutdown) {
+      DebuggerConnectionHandler::StopHandler();
+      EventHandler::Stop();
+    }
     exit((exit_code != 0) ? exit_code : kErrorExitCode);
   }
   delete [] isolate_name;
@@ -1231,53 +1282,55 @@
       WriteSnapshotFile(kPrecompiledInstructionsName,
                         instructions_buffer,
                         instructions_size);
-    } else if (has_compile_all) {
-      result = Dart_CompileAll();
+    } else {
+      if (has_compile_all) {
+        result = Dart_CompileAll();
+        DartExitOnError(result);
+      }
+
+      if (Dart_IsNull(root_lib)) {
+        ErrorExit(kErrorExitCode,
+                  "Unable to find root library for '%s'\n",
+                  script_name);
+      }
+
+      // The helper function _getMainClosure creates a closure for the main
+      // entry point which is either explicitly or implictly exported from the
+      // root library.
+      Dart_Handle main_closure = Dart_Invoke(builtin_lib,
+          Dart_NewStringFromCString("_getMainClosure"), 0, NULL);
+      DartExitOnError(main_closure);
+
+      // Set debug breakpoint if specified on the command line before calling
+      // the main function.
+      if (breakpoint_at != NULL) {
+        result = SetBreakpoint(breakpoint_at, root_lib);
+        if (Dart_IsError(result)) {
+          ErrorExit(kErrorExitCode,
+                    "Error setting breakpoint at '%s': %s\n",
+                    breakpoint_at,
+                    Dart_GetError(result));
+        }
+      }
+
+      // Call _startIsolate in the isolate library to enable dispatching the
+      // initial startup message.
+      const intptr_t kNumIsolateArgs = 2;
+      Dart_Handle isolate_args[kNumIsolateArgs];
+      isolate_args[0] = main_closure;                         // entryPoint
+      isolate_args[1] = CreateRuntimeOptions(&dart_options);  // args
+
+      Dart_Handle isolate_lib =
+          Dart_LookupLibrary(Dart_NewStringFromCString("dart:isolate"));
+      result = Dart_Invoke(isolate_lib,
+                           Dart_NewStringFromCString("_startMainIsolate"),
+                           kNumIsolateArgs, isolate_args);
+      DartExitOnError(result);
+
+      // Keep handling messages until the last active receive port is closed.
+      result = Dart_RunLoop();
       DartExitOnError(result);
     }
-
-    if (Dart_IsNull(root_lib)) {
-      ErrorExit(kErrorExitCode,
-                "Unable to find root library for '%s'\n",
-                script_name);
-    }
-
-    // The helper function _getMainClosure creates a closure for the main
-    // entry point which is either explicitly or implictly exported from the
-    // root library.
-    Dart_Handle main_closure = Dart_Invoke(
-        builtin_lib, Dart_NewStringFromCString("_getMainClosure"), 0, NULL);
-    DartExitOnError(main_closure);
-
-    // Set debug breakpoint if specified on the command line before calling
-    // the main function.
-    if (breakpoint_at != NULL) {
-      result = SetBreakpoint(breakpoint_at, root_lib);
-      if (Dart_IsError(result)) {
-        ErrorExit(kErrorExitCode,
-                  "Error setting breakpoint at '%s': %s\n",
-                  breakpoint_at,
-                  Dart_GetError(result));
-      }
-    }
-
-    // Call _startIsolate in the isolate library to enable dispatching the
-    // initial startup message.
-    const intptr_t kNumIsolateArgs = 2;
-    Dart_Handle isolate_args[kNumIsolateArgs];
-    isolate_args[0] = main_closure;                         // entryPoint
-    isolate_args[1] = CreateRuntimeOptions(&dart_options);  // args
-
-    Dart_Handle isolate_lib = Dart_LookupLibrary(
-        Dart_NewStringFromCString("dart:isolate"));
-    result = Dart_Invoke(isolate_lib,
-                         Dart_NewStringFromCString("_startMainIsolate"),
-                         kNumIsolateArgs, isolate_args);
-    DartExitOnError(result);
-
-    // Keep handling messages until the last active receive port is closed.
-    result = Dart_RunLoop();
-    DartExitOnError(result);
   }
 
   Dart_ExitScope();
@@ -1286,11 +1339,15 @@
   // Terminate process exit-code handler.
   Process::TerminateExitCodeHandler();
 
-  Dart_Cleanup();
-
-  DebuggerConnectionHandler::StopHandler();
-  // TODO(zra): Stop the EventHandler once thread shutdown is enabled.
-  // EventHandler::Stop();
+  error = Dart_Cleanup();
+  if (error != NULL) {
+    Log::PrintErr("VM cleanup failed: %s\n", error);
+    free(error);
+  }
+  if (do_vm_shutdown) {
+    DebuggerConnectionHandler::StopHandler();
+    EventHandler::Stop();
+  }
 
   // Free copied argument strings if converted.
   if (argv_converted) {
diff --git a/runtime/bin/net/.gitignore b/runtime/bin/net/.gitignore
deleted file mode 100644
index 3ca2cc5..0000000
--- a/runtime/bin/net/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-/*.Makefile
-/*.sln
-/*.target.mk
-/*.vcproj
-/*.vcxproj
-/*.vcxproj.filters
-/*.vcxproj.user
-/*.xcodeproj
diff --git a/runtime/bin/process.cc b/runtime/bin/process.cc
index 242ef1c..3c345b7 100644
--- a/runtime/bin/process.cc
+++ b/runtime/bin/process.cc
@@ -6,6 +6,7 @@
 #include "bin/dbg_connection.h"
 #include "bin/eventhandler.h"
 #include "bin/io_buffer.h"
+#include "bin/log.h"
 #include "bin/platform.h"
 #include "bin/process.h"
 #include "bin/socket.h"
@@ -16,6 +17,10 @@
 namespace dart {
 namespace bin {
 
+// Global flag that is used to indicate that the VM should do a clean
+// shutdown.
+bool do_vm_shutdown = true;
+
 static const int kProcessIdNativeField = 0;
 
 int Process::global_exit_code_ = 0;
@@ -36,9 +41,15 @@
   // Protect against user-defined list implementations that can have
   // arbitrary length.
   if (len < 0 || len > kMaxArgumentListLength) {
-    DartUtils::SetIntegerField(status_handle, "_errorCode", 0);
-    DartUtils::SetStringField(
+    result = DartUtils::SetIntegerField(status_handle, "_errorCode", 0);
+    if (Dart_IsError(result)) {
+      Dart_PropagateError(result);
+    }
+    result = DartUtils::SetStringField(
         status_handle, "_errorMessage", "Max argument list length exceeded");
+    if (Dart_IsError(result)) {
+      Dart_PropagateError(result);
+    }
     return NULL;
   }
   *length = len;
@@ -50,9 +61,15 @@
       Dart_PropagateError(arg);
     }
     if (!Dart_IsString(arg)) {
-      DartUtils::SetIntegerField(status_handle, "_errorCode", 0);
-      DartUtils::SetStringField(
+      result = DartUtils::SetIntegerField(status_handle, "_errorCode", 0);
+      if (Dart_IsError(result)) {
+        Dart_PropagateError(result);
+      }
+      result = DartUtils::SetStringField(
           status_handle, "_errorMessage", error_msg);
+      if (Dart_IsError(result)) {
+        Dart_PropagateError(result);
+      }
       delete[] string_args;
       return NULL;
     }
@@ -67,15 +84,22 @@
   intptr_t process_stdout;
   intptr_t process_stderr;
   intptr_t exit_event;
+  Dart_Handle result;
   Dart_Handle status_handle = Dart_GetNativeArgument(args, 10);
   Dart_Handle path_handle = Dart_GetNativeArgument(args, 1);
   // The Dart code verifies that the path implements the String
   // interface. However, only builtin Strings are handled by
   // GetStringValue.
   if (!Dart_IsString(path_handle)) {
-    DartUtils::SetIntegerField(status_handle, "_errorCode", 0);
-    DartUtils::SetStringField(
+    result = DartUtils::SetIntegerField(status_handle, "_errorCode", 0);
+    if (Dart_IsError(result)) {
+      Dart_PropagateError(result);
+    }
+    result = DartUtils::SetStringField(
         status_handle, "_errorMessage", "Path must be a builtin string");
+    if (Dart_IsError(result)) {
+      Dart_PropagateError(result);
+    }
     Dart_SetReturnValue(args, Dart_NewBoolean(false));
     return;
   }
@@ -98,10 +122,16 @@
     working_directory = DartUtils::GetStringValue(working_directory_handle);
   } else if (!Dart_IsNull(working_directory_handle)) {
     delete[] string_args;
-    DartUtils::SetIntegerField(status_handle, "_errorCode", 0);
-    DartUtils::SetStringField(
+    result = DartUtils::SetIntegerField(status_handle, "_errorCode", 0);
+    if (Dart_IsError(result)) {
+      Dart_PropagateError(result);
+    }
+    result = DartUtils::SetStringField(
         status_handle, "_errorMessage",
         "WorkingDirectory must be a builtin string");
+    if (Dart_IsError(result)) {
+      Dart_PropagateError(result);
+    }
     Dart_SetReturnValue(args, Dart_NewBoolean(false));
     return;
   }
@@ -153,13 +183,19 @@
     }
     Process::SetProcessIdNativeField(process, pid);
   } else {
-    DartUtils::SetIntegerField(
+    result = DartUtils::SetIntegerField(
         status_handle, "_errorCode", error_code);
-    DartUtils::SetStringField(
+    if (Dart_IsError(result)) {
+      Dart_PropagateError(result);
+    }
+    result = DartUtils::SetStringField(
         status_handle,
         "_errorMessage",
         os_error_message != NULL ? os_error_message
                                  : "Cannot get error message");
+    if (Dart_IsError(result)) {
+      Dart_PropagateError(result);
+    }
   }
   delete[] string_args;
   delete[] string_environment;
@@ -218,11 +254,17 @@
   int64_t status = 0;
   // Ignore result if passing invalid argument and just exit 0.
   DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 0), &status);
-  Dart_ExitIsolate();
-  Dart_Cleanup();
-  DebuggerConnectionHandler::StopHandler();
-  // TODO(zra): Stop the EventHandler once thread shutdown is enabled.
-  // EventHandler::Stop();
+  Dart_ShutdownIsolate();
+  Process::TerminateExitCodeHandler();
+  char* error = Dart_Cleanup();
+  if (error != NULL) {
+    Log::PrintErr("VM cleanup failed: %s\n", error);
+    free(error);
+  }
+  if (do_vm_shutdown) {
+    DebuggerConnectionHandler::StopHandler();
+    EventHandler::Stop();
+  }
   exit(static_cast<int>(status));
 }
 
diff --git a/runtime/bin/process_patch.dart b/runtime/bin/process_patch.dart
index b6d40ee..1917b46 100644
--- a/runtime/bin/process_patch.dart
+++ b/runtime/bin/process_patch.dart
@@ -176,10 +176,9 @@
 // implicit constructor.
 class _ProcessImplNativeWrapper extends NativeFieldWrapperClass1 {}
 
-class _ProcessImpl extends _ProcessImplNativeWrapper with _ServiceObject
-    implements Process {
-  // Use default Map so we keep order.
-  static Map<int, _ProcessImpl> _processes = new Map<int, _ProcessImpl>();
+class _ProcessImpl extends _ProcessImplNativeWrapper implements Process {
+  _ProcessResourceInfo _resourceInfo;
+  static bool connectedResourceHandler = false;
 
   _ProcessImpl(String path,
                List<String> arguments,
@@ -188,7 +187,14 @@
                bool includeParentEnvironment,
                bool runInShell,
                ProcessStartMode mode) : super() {
-    _processes[_serviceId] = this;
+    if (!connectedResourceHandler) {
+      registerExtension('__getProcesses',
+                        _ProcessResourceInfo.getStartedProcesses);
+      registerExtension('__getProcessById',
+                        _ProcessResourceInfo.getProcessInfoMapById);
+      connectedResourceHandler = true;
+    }
+
     if (runInShell) {
       arguments = _getShellArguments(path, arguments);
       path = _getShellCommand();
@@ -267,38 +273,6 @@
     _started = false;
   }
 
-  String get _serviceTypePath => 'io/processes';
-  String get _serviceTypeName => 'Process';
-
-  Map _toJSON(bool ref) {
-    var r = {
-      'id': _servicePath,
-      'type': _serviceType(ref),
-      'name': '$_path',
-      'user_name': '$_path',
-      'pid': '$pid',
-      'arguments': _arguments.join(' '),
-    };
-    if (ref) {
-      return r;
-    }
-    r['started'] = _started;
-    r['ended'] = _ended;
-    r['path'] = _path;
-    r['environment'] = _environment;
-    r['workingDirectory'] = _workingDirectory == null ? '.' : _workingDirectory;
-    if (_stdin._sink._nativeSocket.owner != null) {
-      r['stdin'] = _stdin._sink._nativeSocket._toJSON(true);
-    }
-    if (_stdout._stream._nativeSocket.owner != null) {
-      r['stdout'] = _stdout._stream._nativeSocket._toJSON(true);
-    }
-    if (_stderr._stream._nativeSocket.owner != null) {
-      r['stderr'] = _stderr._stream._nativeSocket._toJSON(true);
-    }
-    return r;
-  }
-
   static String _getShellCommand() {
     if (Platform.isWindows) {
       return 'cmd.exe';
@@ -418,6 +392,7 @@
       }
 
       _started = true;
+      _resourceInfo = new _ProcessResourceInfo(this);
 
       // Setup an exit handler to handle internal cleanup and possible
       // callback when a process terminates.
@@ -439,7 +414,7 @@
             _exitCode.complete(exitCode(exitDataBuffer));
             // Kill stdin, helping hand if the user forgot to do it.
             _stdin._sink.destroy();
-            _processes.remove(_serviceId);
+            _resourceInfo.stopped();
           }
 
           exitDataBuffer.setRange(
@@ -477,6 +452,8 @@
                                  status._errorCode);
     }
 
+    _resourceInfo = new _ProcessResourceInfo(this);
+
     var result = _wait(
         _stdin._sink._nativeSocket,
         _stdout._stream._nativeSocket,
@@ -488,7 +465,7 @@
       return encoding.decode(output);
     }
 
-    _processes.remove(_serviceId);
+    _resourceInfo.stopped();
 
     return new ProcessResult(
         result[0],
diff --git a/runtime/bin/run_vm_tests.cc b/runtime/bin/run_vm_tests.cc
index e821cc2..c45a2a0 100644
--- a/runtime/bin/run_vm_tests.cc
+++ b/runtime/bin/run_vm_tests.cc
@@ -114,6 +114,12 @@
   TestCaseBase::RunAll();
   // Apply the filter to all registered benchmarks.
   Benchmark::RunAll(argv[0]);
+
+  if (Flags::IsSet("shutdown")) {
+    err_msg = Dart::Cleanup();
+    ASSERT(err_msg == NULL);
+  }
+
   // Print a warning message if no tests or benchmarks were matched.
   if (run_matches == 0) {
     fprintf(stderr, "No tests matched: %s\n", run_filter);
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index be459ba..47e5f44 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -313,8 +313,6 @@
   bool writeEventIssued = false;
   bool writeAvailable = false;
 
-  static final Stopwatch sw = new Stopwatch()..start();
-
   static bool connectedResourceHandler = false;
   _ReadWriteResourceInfo resourceInfo;
 
@@ -584,8 +582,7 @@
     // TODO(ricow): Remove when we track internal and pipe uses.
     assert(resourceInfo != null || isPipe || isInternal);
     if (resourceInfo != null) {
-      resourceInfo.readCount++;
-      resourceInfo.lastRead = timestamp;
+      resourceInfo.didRead();
     }
     return result;
   }
@@ -612,8 +609,7 @@
     // TODO(ricow): Remove when we track internal and pipe uses.
     assert(resourceInfo != null || isPipe || isInternal);
     if (resourceInfo != null) {
-      resourceInfo.readCount++;
-      resourceInfo.lastRead = timestamp;
+      resourceInfo.didRead();
     }
     return result;
   }
@@ -656,9 +652,7 @@
     // TODO(ricow): Remove when we track internal and pipe uses.
     assert(resourceInfo != null || isPipe || isInternal);
     if (resourceInfo != null) {
-      resourceInfo.totalWritten += result;
-      resourceInfo.writeCount++;
-      resourceInfo.lastWrite = timestamp;
+      resourceInfo.addWrite(result);
     }
     return result;
   }
@@ -679,9 +673,7 @@
     // TODO(ricow): Remove when we track internal and pipe uses.
     assert(resourceInfo != null || isPipe || isInternal);
     if (resourceInfo != null) {
-      resourceInfo.totalWritten += result;
-      resourceInfo.writeCount++;
-      resourceInfo.lastWrite = timestamp;
+      resourceInfo.addWrite(result);
     }
     return result;
   }
@@ -701,8 +693,8 @@
     // TODO(ricow): Remove when we track internal and pipe uses.
     assert(resourceInfo != null || isPipe || isInternal);
     if (resourceInfo != null) {
-      resourceInfo.totalRead += 1;
-      resourceInfo.lastRead = timestamp;
+      // We track this as read one byte.
+      resourceInfo.addRead(1);
     }
     return socket;
   }
diff --git a/runtime/bin/utils.h b/runtime/bin/utils.h
index bb55a76..2c3f1fc 100644
--- a/runtime/bin/utils.h
+++ b/runtime/bin/utils.h
@@ -11,7 +11,6 @@
 #include "include/dart_api.h"
 #include "platform/globals.h"
 
-
 namespace dart {
 namespace bin {
 
diff --git a/runtime/bin/vmservice/server.dart b/runtime/bin/vmservice/server.dart
index a672bf2..34d5715 100644
--- a/runtime/bin/vmservice/server.dart
+++ b/runtime/bin/vmservice/server.dart
@@ -16,6 +16,12 @@
     socket.done.then((_) => close());
   }
 
+  disconnect() {
+    if (socket != null) {
+      socket.close();
+    }
+  }
+
   void onWebSocketMessage(message) {
     if (message is String) {
       var map;
@@ -68,6 +74,11 @@
   HttpRequestClient(this.request, VMService service)
       : super(service, sendEvents:false);
 
+  disconnect() {
+    request.response.close();
+    close();
+  }
+
   void post(String result) {
     if (result == null) {
       close();
diff --git a/runtime/bin/vmservice/vmservice_io.dart b/runtime/bin/vmservice/vmservice_io.dart
index 409bc59..d9b0c75 100644
--- a/runtime/bin/vmservice/vmservice_io.dart
+++ b/runtime/bin/vmservice/vmservice_io.dart
@@ -89,6 +89,15 @@
     // scheduled microtasks.
     Timer.run(() {});
   }
+  // TODO(johnmccutchan, turnidge) Creating a VMService object here causes
+  // strange behavior from the legacy debug protocol and coverage tool.
+  // Enable this code, and remove the call to Isolate::KillIsolate() from
+  // service_isolate.cc when the strange behavior is solved.
+  // See: https://github.com/dart-lang/sdk/issues/23977
+  // else {
+  //   var service = new VMService();
+  //   service.onShutdown = _onShutdown;
+  // }
   scriptLoadPort.handler = _processLoadRequest;
   // Register signal handler after a small delay to avoid stalling main
   // isolate startup.
diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc
index 3037ad6..553093f 100644
--- a/runtime/bin/vmservice_impl.cc
+++ b/runtime/bin/vmservice_impl.cc
@@ -159,6 +159,7 @@
 char VmService::server_ip_[kServerIpStringBufferSize];
 intptr_t VmService::server_port_ = 0;
 
+
 bool VmService::Setup(const char* server_ip, intptr_t server_port) {
   Dart_Isolate isolate = Dart_CurrentIsolate();
   ASSERT(isolate != NULL);
@@ -203,7 +204,8 @@
   SHUTDOWN_ON_ERROR(library);
 
   // Set HTTP server state.
-  DartUtils::SetStringField(library, "_ip", server_ip);
+  result = DartUtils::SetStringField(library, "_ip", server_ip);
+  SHUTDOWN_ON_ERROR(result);
   // If we have a port specified, start the server immediately.
   bool auto_start = server_port >= 0;
   if (server_port < 0) {
@@ -211,7 +213,8 @@
     // port when the HTTP server is started.
     server_port = 0;
   }
-  DartUtils::SetIntegerField(library, "_port", server_port);
+  result = DartUtils::SetIntegerField(library, "_port", server_port);
+  SHUTDOWN_ON_ERROR(result);
   result = Dart_SetField(library,
                          DartUtils::NewString("_autoStart"),
                          Dart_NewBoolean(auto_start));
diff --git a/runtime/bin/net/zlib.gyp b/runtime/bin/zlib.gyp
similarity index 87%
rename from runtime/bin/net/zlib.gyp
rename to runtime/bin/zlib.gyp
index 8aa920d..6f2f913 100644
--- a/runtime/bin/net/zlib.gyp
+++ b/runtime/bin/zlib.gyp
@@ -6,17 +6,18 @@
 # 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 a modified copy of src/third_party/zlib/zlib.gyp from Chromium.
-# Revision 291806 (this should agree with "nss_rev" in DEPS).
+# This file is a modified copy of
+# https://chromium.googlesource.com/chromium/src/third_party/zlib/zlib.gyp
+# at revision c3d0a6190f2f8c924a05ab6cc97b8f975bddd33f.
 {
   # Added by Dart. All Dart comments refer to the following block or line.
   'includes': [
-    '../../tools/gyp/runtime-configurations.gypi',
-    '../../tools/gyp/nss_configurations.gypi',
+    '../tools/gyp/runtime-configurations.gypi',
+    '../tools/gyp/nss_configurations.gypi',
   ],
   'variables': {
     # Added by Dart.
-    'zlib_path': '../../../third_party/zlib',
+    'zlib_path': '../../third_party/zlib',
   },
   # Added by Dart.  We do not indent, so diffs with the original are clearer.
   'conditions': [[ 'dart_io_support==1', {
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 15114a6..9042eff 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -368,7 +368,6 @@
     }                                                                          \
   }                                                                            \
 
-
 /**
  * Converts an object to a string.
  *
@@ -863,9 +862,10 @@
  * \param shutdown A function to be called when an isolate is shutdown.
  *   See Dart_IsolateShutdownCallback.
  *
- * \return True if initialization is successful.
+ * \return NULL if initialization is successful. Returns an error message
+ *   otherwise. The caller is responsible for freeing the error message.
  */
-DART_EXPORT bool Dart_Initialize(
+DART_EXPORT char* Dart_Initialize(
     const uint8_t* vm_isolate_snapshot,
     const uint8_t* instructions_snapshot,
     Dart_IsolateCreateCallback create,
@@ -881,9 +881,10 @@
 /**
  * Cleanup state in the VM before process termination.
  *
- * \return True if cleanup is successful.
+ * \return NULL if cleanup is successful. Returns an error message otherwise.
+ *   The caller is responsible for freeing the error message.
  */
-DART_EXPORT bool Dart_Cleanup();
+DART_EXPORT char* Dart_Cleanup();
 
 /**
  * Sets command line flags. Should be called before Dart_Initialize.
diff --git a/runtime/lib/array.cc b/runtime/lib/array.cc
index 003f12f..b95e6b0 100644
--- a/runtime/lib/array.cc
+++ b/runtime/lib/array.cc
@@ -22,7 +22,7 @@
   const Array& array = Array::CheckedHandle(arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Smi, index, arguments->NativeArgAt(1));
   if ((index.Value() < 0) || (index.Value() >= array.Length())) {
-    Exceptions::ThrowRangeError("index", index, 0, array.Length());
+    Exceptions::ThrowRangeError("index", index, 0, array.Length() - 1);
   }
   return array.At(index.Value());
 }
@@ -33,7 +33,7 @@
   GET_NON_NULL_NATIVE_ARGUMENT(Smi, index, arguments->NativeArgAt(1));
   const Instance& value = Instance::CheckedHandle(arguments->NativeArgAt(2));
   if ((index.Value() < 0) || (index.Value() >= array.Length())) {
-    Exceptions::ThrowRangeError("index", index, 0, array.Length());
+    Exceptions::ThrowRangeError("index", index, 0, array.Length() - 1);
   }
   array.SetAt(index.Value(), value);
   return Object::null();
@@ -52,22 +52,22 @@
   GET_NON_NULL_NATIVE_ARGUMENT(Smi, start, arguments->NativeArgAt(1));
   GET_NON_NULL_NATIVE_ARGUMENT(Smi, count, arguments->NativeArgAt(2));
   GET_NON_NULL_NATIVE_ARGUMENT(Bool, needs_type_arg, arguments->NativeArgAt(3));
+  intptr_t istart = start.Value();
+  if ((istart < 0) || (istart > src.Length())) {
+    Exceptions::ThrowRangeError(
+        "start",
+        start,
+        0,
+        src.Length());
+  }
   intptr_t icount = count.Value();
   // Zero count should be handled outside already.
   if ((icount <= 0) || (icount > src.Length())) {
     Exceptions::ThrowRangeError(
         "count",
-        Smi::Handle(Smi::New(icount)),
-        1,
-        src.Length() + 1);
-  }
-  intptr_t istart = start.Value();
-  if ((istart < 0) || ((istart + icount) > src.Length())) {
-    Exceptions::ThrowRangeError(
-        "start",
-        Smi::Handle(Smi::New(istart)),
-        0,
-        src.Length() - icount + 1);
+        count,
+        0,                        // This is the limit the user sees.
+        src.Length() - istart);
   }
 
   return src.Slice(istart, icount, needs_type_arg.value());
diff --git a/runtime/lib/bigint.dart b/runtime/lib/bigint.dart
index a278595..ae941b7 100644
--- a/runtime/lib/bigint.dart
+++ b/runtime/lib/bigint.dart
@@ -1745,7 +1745,7 @@
             _absSub(d_digits, abcd_used, b_digits, abcd_used, d_digits);
           } else {
             _absSub(b_digits, abcd_used, d_digits, abcd_used, d_digits);
-            d_neg = !d_neg && (d_cmp_ab != 0);
+            d_neg = !d_neg && (d_cmp_b != 0);
           }
         } else {
           _absAdd(d_digits, abcd_used, b_digits, abcd_used, d_digits);
diff --git a/runtime/lib/growable_array.cc b/runtime/lib/growable_array.cc
index 8181e73..e892813 100644
--- a/runtime/lib/growable_array.cc
+++ b/runtime/lib/growable_array.cc
@@ -20,7 +20,7 @@
     Exceptions::ThrowRangeError(
         "length",
         Integer::Handle(Integer::New(data.Length())),
-        1,
+        0,  // This is the limit the user sees.
         Array::kMaxElements);
   }
   const GrowableObjectArray& new_array =
@@ -35,7 +35,7 @@
       GrowableObjectArray::CheckedHandle(arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Smi, index, arguments->NativeArgAt(1));
   if ((index.Value() < 0) || (index.Value() >= array.Length())) {
-    Exceptions::ThrowRangeError("index", index, 0, array.Length());
+    Exceptions::ThrowRangeError("index", index, 0, array.Length() - 1);
   }
   const Instance& obj = Instance::CheckedHandle(array.At(index.Value()));
   return obj.raw();
@@ -47,7 +47,7 @@
       GrowableObjectArray::CheckedHandle(arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Smi, index, arguments->NativeArgAt(1));
   if ((index.Value() < 0) || (index.Value() >= array.Length())) {
-    Exceptions::ThrowRangeError("index", index, 0, array.Length());
+    Exceptions::ThrowRangeError("index", index, 0, array.Length() - 1);
   }
   GET_NON_NULL_NATIVE_ARGUMENT(Instance, value, arguments->NativeArgAt(2));
   array.SetAt(index.Value(), value);
diff --git a/runtime/lib/growable_array.dart b/runtime/lib/growable_array.dart
index bd79837..39b4522 100644
--- a/runtime/lib/growable_array.dart
+++ b/runtime/lib/growable_array.dart
@@ -70,14 +70,13 @@
   }
 
   void removeRange(int start, int end) {
-    Lists.indicesCheck(this, start, end);
+    RangeError.checkValidRange(start, end, this.length);
     Lists.copy(this, end, this, start, this.length - end);
     this.length = this.length - (end - start);
   }
 
   List<T> sublist(int start, [int end]) {
-    Lists.indicesCheck(this, start, end);
-    if (end == null) end = this.length;
+    end = RangeError.checkValidRange(start, end, this.length);
     int length = end - start;
     if (length == 0) return <T>[];
     List list = new _List(length);
diff --git a/runtime/lib/integers.cc b/runtime/lib/integers.cc
index b1ca62c..e8d655c 100644
--- a/runtime/lib/integers.cc
+++ b/runtime/lib/integers.cc
@@ -275,7 +275,9 @@
         case Token::kSHL:
           return Integer::New(mint_value << shift_count, Heap::kNew, silent);
         case Token::kSHR:
-          return Integer::New(mint_value >> -shift_count, Heap::kNew, silent);
+          shift_count =
+              (-shift_count > Mint::kBits) ? Mint::kBits : -shift_count;
+          return Integer::New(mint_value >> shift_count, Heap::kNew, silent);
         default:
           UNIMPLEMENTED();
       }
diff --git a/runtime/lib/isolate_patch.dart b/runtime/lib/isolate_patch.dart
index e3dbec1..51b7ac0 100644
--- a/runtime/lib/isolate_patch.dart
+++ b/runtime/lib/isolate_patch.dart
@@ -130,6 +130,8 @@
     return sendPort.hashCode();
   }
 
+  Uri get remotePortUri => new Uri.https('localhost', '55');
+
   /**** Internal implementation details ****/
   _get_id() native "RawReceivePortImpl_get_id";
   _get_sendport() native "RawReceivePortImpl_get_sendport";
@@ -306,11 +308,17 @@
 
   /* patch */ static Future<Isolate> spawnUri(
       Uri uri, List<String> args, var message,
-      {bool paused: false, bool checked, Uri packageRoot, bool errorsAreFatal,
-       SendPort onExit, SendPort onError}) {
+      {bool paused: false,
+       bool checked,
+       Uri packageRoot,
+       Map<String, Uri> packages,
+       bool errorsAreFatal,
+       SendPort onExit,
+       SendPort onError}) {
     RawReceivePort readyPort;
     try {
       // The VM will invoke [_startIsolate] and not `main`.
+      // TODO: Handle [packages].
       readyPort = new RawReceivePort();
       var packageRootString =
           (packageRoot == null) ? null : packageRoot.toString();
diff --git a/runtime/lib/map_patch.dart b/runtime/lib/map_patch.dart
index 682ba03..8a8359a 100644
--- a/runtime/lib/map_patch.dart
+++ b/runtime/lib/map_patch.dart
@@ -20,4 +20,6 @@
   /* patch */ factory Map.unmodifiable(Map other) {
     return new UnmodifiableMapView<K, V>(new Map.from(other));
   }
+
+  /* patch */ factory Map() = LinkedHashMap<K, V>;
 }
diff --git a/runtime/lib/simd128.cc b/runtime/lib/simd128.cc
index b9bf55c..4492555 100644
--- a/runtime/lib/simd128.cc
+++ b/runtime/lib/simd128.cc
@@ -14,7 +14,7 @@
 static void ThrowMaskRangeException(int64_t m) {
   if ((m < 0) || (m > 255)) {
     Exceptions::ThrowRangeError(
-        "mask", Integer::Handle(Integer::New(m)), 0, 256);
+        "mask", Integer::Handle(Integer::New(m)), 0, 255);
   }
 }
 
diff --git a/runtime/lib/string.cc b/runtime/lib/string.cc
index 9d4137d..2eae245 100644
--- a/runtime/lib/string.cc
+++ b/runtime/lib/string.cc
@@ -515,7 +515,7 @@
   }
 
   // An index larger than Smi is always illegal.
-  Exceptions::ThrowRangeError("index", index, 0, str.Length());
+  Exceptions::ThrowRangeError("index", index, 0, str.Length() - 1);
   return 0;
 }
 
@@ -601,7 +601,7 @@
   intptr_t array_length = codeUnits.Length();
   intptr_t length_value = length.Value();
   if (length_value < 0 || length_value > array_length) {
-    Exceptions::ThrowRangeError("length", length, 0, array_length + 1);
+    Exceptions::ThrowRangeError("length", length, 0, array_length);
   }
   const String& result = isLatin1.value()
       ? String::Handle(OneByteString::New(length_value, Heap::kNew))
diff --git a/runtime/lib/typed_data.dart b/runtime/lib/typed_data.dart
index f70781a..a56c39f 100644
--- a/runtime/lib/typed_data.dart
+++ b/runtime/lib/typed_data.dart
@@ -477,9 +477,8 @@
   }
 
   List sublist(int start, [int end]) {
-    if (end == null) end = this.length;
+    end = RangeError.checkValidRange(start, end, this.length);
     var length = end - start;
-    _rangeCheck(this.length, start, length);
     List result = _createList(length);
     result.setRange(0, length, this, start);
     return result;
diff --git a/runtime/observatory/lib/service_common.dart b/runtime/observatory/lib/service_common.dart
index cde76a2..ba55349 100644
--- a/runtime/observatory/lib/service_common.dart
+++ b/runtime/observatory/lib/service_common.dart
@@ -88,7 +88,7 @@
   int _requestSerial = 0;
   bool _hasInitiatedConnect = false;
   bool _hasFinishedConnect = false;
-  Utf8Decoder _utf8Decoder = new Utf8Decoder();
+  Utf8Decoder _utf8Decoder = const Utf8Decoder();
 
   CommonWebSocket _webSocket;
 
diff --git a/runtime/observatory/lib/src/debugger/debugger_location.dart b/runtime/observatory/lib/src/debugger/debugger_location.dart
index 469609b..a517cd2 100644
--- a/runtime/observatory/lib/src/debugger/debugger_location.dart
+++ b/runtime/observatory/lib/src/debugger/debugger_location.dart
@@ -52,8 +52,8 @@
     Script script = frame.location.script;
     return script.load().then((_) {
       var line = script.tokenToLine(frame.location.tokenPos);
-      // TODO(turnidge): Pass in the column here once the protocol supports it.
-      return new Future.value(new DebuggerLocation.file(script, line, null));
+      var col = script.tokenToCol(frame.location.tokenPos);
+      return new Future.value(new DebuggerLocation.file(script, line, col));
     });
   }
 
@@ -101,8 +101,11 @@
         return new Future.value(new DebuggerLocation.error(
             'A script must be provided when the stack is empty'));
       }
-      Script script = stack['frames'][0].location.script;
-      return new Future.value(new DebuggerLocation.file(script, line, col));
+      var frame = stack['frames'][debugger.currentFrame];
+      Script script = frame.location.script;
+      return script.load().then((_) {
+        return new Future.value(new DebuggerLocation.file(script, line, col));
+      });
     }
   }
 
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index f652da1..66c9609 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -637,7 +637,7 @@
   Future run(List<String> args) async {
     if (args.length > 1) {
       debugger.console.print('not implemented');
-      return new Future.value(null);
+      return;
     }
     var arg = (args.length == 0 ? '' : args[0]);
     var loc = await DebuggerLocation.parse(debugger, arg);
@@ -654,14 +654,15 @@
         }
       } else {
         assert(loc.script != null);
-        if (loc.col != null) {
-          // TODO(turnidge): Add tokenPos breakpoint support.
+        var script = loc.script;
+        await script.load();
+        if (loc.line < 1 || loc.line > script.lines.length) {
           debugger.console.print(
-              'Ignoring column: '
-              'adding breakpoint at a specific column not yet implemented');
-          }
+              'line number must be in range [1,${script.lines.length}]');
+          return;
+        }
         try {
-          await debugger.isolate.addBreakpoint(loc.script, loc.line);
+          await debugger.isolate.addBreakpoint(script, loc.line, loc.col);
         } on ServerRpcException catch(e) {
           if (e.code == ServerRpcException.kCannotAddBreakpoint) {
             debugger.console.print('Unable to set breakpoint at ${loc}');
@@ -718,48 +719,50 @@
 class ClearCommand extends DebuggerCommand {
   ClearCommand(Debugger debugger) : super(debugger, 'clear', []);
 
-  Future run(List<String> args) {
+  Future run(List<String> args) async {
     if (args.length > 1) {
       debugger.console.print('not implemented');
-      return new Future.value(null);
+      return;
     }
     var arg = (args.length == 0 ? '' : args[0]);
-    return DebuggerLocation.parse(debugger, arg).then((loc) {
-      if (loc.valid) {
-        if (loc.function != null) {
-          debugger.console.print(
-              'Ignoring breakpoint at $loc: '
-              'Function entry breakpoints not yet implemented');
-          return null;
-        }
-        if (loc.col != null) {
-          // TODO(turnidge): Add tokenPos clear support.
-          debugger.console.print(
-              'Ignoring column: '
-              'clearing breakpoint at a specific column not yet implemented');
-        }
+    var loc = await DebuggerLocation.parse(debugger, arg);
+    if (!loc.valid) {
+      debugger.console.print(loc.errorMessage);
+      return;
+    }
+    if (loc.function != null) {
+      debugger.console.print(
+          'Ignoring breakpoint at $loc: '
+          'Clearing function breakpoints not yet implemented');
+      return;
+    }
 
-        for (var bpt in debugger.isolate.breakpoints.values) {
-          var script = bpt.location.script;
-          if (script.id == loc.script.id) {
-            assert(script.loaded);
-            var line = script.tokenToLine(bpt.location.tokenPos);
-            if (line == loc.line) {
-              return debugger.isolate.removeBreakpoint(bpt).then((result) {
-                if (result is DartError) {
-                  debugger.console.print(
-                      'Unable to clear breakpoint at ${loc}: ${result.message}');
-                  return;
-                }
-              });
-            }
+    var script = loc.script;
+    if (loc.line < 1 || loc.line > script.lines.length) {
+      debugger.console.print(
+          'line number must be in range [1,${script.lines.length}]');
+      return;
+    }
+    var lineInfo = script.getLine(loc.line);
+    var bpts = lineInfo.breakpoints;
+    var foundBreakpoint = false;
+    if (bpts != null) {
+      var bptList = bpts.toList();
+      for (var bpt in bptList) {
+        if (loc.col == null ||
+            loc.col == script.tokenToCol(bpt.location.tokenPos)) {
+          foundBreakpoint = true;
+          var result = await debugger.isolate.removeBreakpoint(bpt);
+          if (result is DartError) {
+            debugger.console.print(
+                'Error clearing breakpoint ${bpt.number}: ${result.message}');
           }
         }
-        debugger.console.print('No breakpoint found at ${loc}');
-      } else {
-        debugger.console.print(loc.errorMessage);
       }
-    });
+    }
+    if (!foundBreakpoint) {
+      debugger.console.print('No breakpoint found at ${loc}');
+    }
   }
 
   Future<List<String>> complete(List<String> args) {
@@ -846,7 +849,7 @@
   InfoBreakpointsCommand(Debugger debugger)
       : super(debugger, 'breakpoints', []);
 
-  Future run(List<String> args) {
+  Future run(List<String> args) async {
     if (debugger.isolate.breakpoints.isEmpty) {
       debugger.console.print('No breakpoints');
     }
@@ -854,19 +857,15 @@
     bpts.sort((a, b) => a.number - b.number);
     for (var bpt in bpts) {
       var bpId = bpt.number;
-      var script = bpt.location.script;
-      var tokenPos = bpt.location.tokenPos;
-      var line = script.tokenToLine(tokenPos);
-      var col = script.tokenToCol(tokenPos);
+      var locString = await bpt.location.toUserString();
       if (!bpt.resolved) {
         debugger.console.print(
-            'Future breakpoint ${bpId} at ${script.name}:${line}:${col}');
+            'Future breakpoint ${bpId} at ${locString}');
       } else {
         debugger.console.print(
-            'Breakpoint ${bpId} at ${script.name}:${line}:${col}');
+            'Breakpoint ${bpId} at ${locString}');
       }
     }
-    return new Future.value(null);
   }
 
   String helpShort = 'List all breakpoints';
@@ -1388,7 +1387,7 @@
     }
   }
 
-  Future _reportBreakpointEvent(ServiceEvent event) {
+  Future _reportBreakpointEvent(ServiceEvent event) async {
     var bpt = event.breakpoint;
     var verb = null;
     switch (event.kind) {
@@ -1405,19 +1404,17 @@
         break;
     }
     var script = bpt.location.script;
-    return script.load().then((_) {
-      var bpId = bpt.number;
-      var tokenPos = bpt.location.tokenPos;
-      var line = script.tokenToLine(tokenPos);
-      var col = script.tokenToCol(tokenPos);
-      if (bpt.resolved) {
-        console.print(
-            'Breakpoint ${bpId} ${verb} at ${script.name}:${line}:${col}');
-      } else {
-        console.print(
-            'Future breakpoint ${bpId} ${verb} at ${script.name}:${line}:${col}');
-      }
-    });
+    await script.load();
+
+    var bpId = bpt.number;
+    var locString = await bpt.location.toUserString();
+    if (bpt.resolved) {
+      console.print(
+          'Breakpoint ${bpId} ${verb} at ${locString}');
+    } else {
+      console.print(
+          'Future breakpoint ${bpId} ${verb} at ${locString}');
+    }
   }
 
   void onEvent(ServiceEvent event) {
@@ -1658,16 +1655,16 @@
       var event = isolate.pauseEvent;
       if (event.kind == ServiceEvent.kPauseStart) {
         console.print("Type 'continue' [F7] or 'step' [F10] to start the isolate");
-        return;
+        return null;
       }
       if (event.kind == ServiceEvent.kPauseExit) {
         console.print("Type 'continue' [F7] to exit the isolate");
-        return;
+        return null;
       }
       return isolate.stepOver();
     } else {
       console.print('The program is already running');
-      return;
+      return null;
     }
   }
 
diff --git a/runtime/observatory/lib/src/elements/script_inset.dart b/runtime/observatory/lib/src/elements/script_inset.dart
index 8a95467..d9d9b64 100644
--- a/runtime/observatory/lib/src/elements/script_inset.dart
+++ b/runtime/observatory/lib/src/elements/script_inset.dart
@@ -121,9 +121,18 @@
 
   BreakpointAnnotation(this.bpt) {
     var script = bpt.location.script;
-    var pos = bpt.location.tokenPos;
-    line = script.tokenToLine(pos);
-    columnStart = script.tokenToCol(pos) - 1;  // tokenToCol is 1-origin.
+    var location = bpt.location;
+    if (location.tokenPos != null) {
+      var pos = location.tokenPos;
+      line = script.tokenToLine(pos);
+      columnStart = script.tokenToCol(pos) - 1;  // tokenToCol is 1-origin.
+    } else if (location is UnresolvedSourceLocation) {
+      line = location.line;
+      columnStart = location.column;
+      if (columnStart == null) {
+        columnStart = 0;
+      }
+    }
     var length = script.guessTokenLength(line, columnStart);
     if (length == null) {
       length = 1;
@@ -139,7 +148,11 @@
     var pos = bpt.location.tokenPos;
     int line = script.tokenToLine(pos);
     int column = script.tokenToCol(pos);
-    element.classes.add("breakAnnotation");
+    if (bpt.resolved) {
+      element.classes.add("resolvedBreakAnnotation");
+    } else {
+      element.classes.add("unresolvedBreakAnnotation");
+    }
     element.title = "Breakpoint ${bpt.number} at ${line}:${column}";
   }
 }
@@ -448,6 +461,11 @@
   Element a(String text) => new AnchorElement()..text = text;
   Element span(String text) => new SpanElement()..text = text;
 
+  Element hitsCurrent(Element element) {
+    element.classes.add('hitsCurrent');
+    element.title = "";
+    return element;
+  }
   Element hitsUnknown(Element element) {
     element.classes.add('hitsNone');
     element.title = "";
@@ -930,7 +948,9 @@
     var e = span("$nbsp$lineNumber$nbsp");
     e.classes.add('noCopy');
 
-    if ((line == null) || (line.hits == null)) {
+    if (lineNumber == _currentLine) {
+      hitsCurrent(e);
+    } else if ((line == null) || (line.hits == null)) {
       hitsUnknown(e);
     } else if (line.hits == 0) {
       hitsNotExecuted(e);
@@ -1000,4 +1020,3 @@
   @published bool inDebuggerContext = false;
   @published ObservableList variables;
 }
-
diff --git a/runtime/observatory/lib/src/elements/script_inset.html b/runtime/observatory/lib/src/elements/script_inset.html
index ac2c08c..a76ae42 100644
--- a/runtime/observatory/lib/src/elements/script_inset.html
+++ b/runtime/observatory/lib/src/elements/script_inset.html
@@ -39,11 +39,7 @@
       .currentCol {
         background-color: #6cf;
       }
-      .breakAnnotation {
-        background-color: #e66;
-        color: white;
-      }
-      .hitsNone, .hitsNotExecuted, .hitsExecuted {
+      .hitsCurrent, .hitsNone, .hitsNotExecuted, .hitsExecuted {
         display: table-cell;
         vertical-align: top;
         font: 400 14px consolas, courier, monospace;
@@ -52,6 +48,10 @@
         text-align: right;
         color: #a8a8a8;
       }
+      .hitsCurrent {
+        background-color: #6cf;
+        color: black;
+      }
       .hitsNotExecuted {
         background-color: #faa;
       }
@@ -87,6 +87,14 @@
         color: white;
         background-color: #e66;
       }
+      .unresolvedBreakAnnotation {
+        color: white;
+        background-color: #cac;
+      }
+      .resolvedBreakAnnotation {
+        color: white;
+        background-color: #e66;
+      }
     </style>
   </template>
 </polymer-element>
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index cf244e4..fac9fc5 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -217,6 +217,9 @@
       case 'SourceLocation':
         obj = new SourceLocation._empty(owner);
         break;
+      case 'UnresolvedSourceLocation':
+        obj = new UnresolvedSourceLocation._empty(owner);
+        break;
       case 'Object':
         switch (vmType) {
           case 'ICData':
@@ -426,12 +429,27 @@
   ServiceObject getFromMap(ObservableMap map);
 }
 
+abstract class Location  {
+  Script get script;
+  int get tokenPos;
+}
+
 /// A [SourceLocation] represents a location or range in the source code.
-class SourceLocation extends ServiceObject {
+class SourceLocation extends ServiceObject implements Location {
   Script script;
   int tokenPos;
   int endTokenPos;
 
+  Future<int> getLine() async {
+    await script.load();
+    return script.tokenToLine(tokenPos);
+  }
+
+  Future<int> getColumn() async {
+    await script.load();
+    return script.tokenToCol(tokenPos);
+  }
+
   SourceLocation._empty(ServiceObject owner) : super._empty(owner);
 
   void _update(ObservableMap map, bool mapIsRef) {
@@ -439,8 +457,15 @@
     _upgradeCollection(map, owner);
     script = map['script'];
     tokenPos = map['tokenPos'];
-    assert(script != null && tokenPos != null);
     endTokenPos = map['endTokenPos'];
+
+    assert(script != null && tokenPos != null);
+  }
+
+  Future<String> toUserString() async {
+    int line = await getLine();
+    int column = await getColumn();
+    return '${script.name}:${line}:${column}';
   }
 
   String toString() {
@@ -452,6 +477,86 @@
   }
 }
 
+/// An [UnresolvedSourceLocation] represents a location in the source
+// code which has not been precisely mapped to a token position.
+class UnresolvedSourceLocation extends ServiceObject implements Location {
+  Script script;
+  String scriptUri;
+  int line;
+  int column;
+  int tokenPos;
+
+  Future<int> getLine() async {
+    if (tokenPos != null) {
+      await script.load();
+      return script.tokenToLine(tokenPos);
+    } else {
+      return line;
+    }
+  }
+
+  Future<int> getColumn() async {
+    if (tokenPos != null) {
+      await script.load();
+      return script.tokenToCol(tokenPos);
+    } else {
+      return column;
+    }
+  }
+
+  UnresolvedSourceLocation._empty(ServiceObject owner) : super._empty(owner);
+
+  void _update(ObservableMap map, bool mapIsRef) {
+    assert(!mapIsRef);
+    _upgradeCollection(map, owner);
+    script = map['script'];
+    scriptUri = map['scriptUri'];
+    line = map['line'];
+    column = map['column'];
+    tokenPos = map['tokenPos'];
+
+    assert(script != null || scriptUri != null);
+    assert(line != null || tokenPos != null);
+  }
+
+  Future<String> toUserString() async {
+    StringBuffer sb = new StringBuffer();
+
+    int line = await getLine();
+    int column = await getColumn();
+
+    if (script != null) {
+      sb.write('${script.name}:');
+    } else {
+      sb.write('${scriptUri}:');
+    }
+    if (column != null) {
+      sb.write('${line}:${column}');
+    } else {
+      sb.write('${line}');
+    }
+    return sb.toString();
+  }
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    if (script != null) {
+      sb.write('${script.name}:');
+    } else {
+      sb.write('${scriptUri}:');
+    }
+    if (tokenPos != null) {
+      sb.write('token(${tokenPos})');
+    } else if (column != null) {
+      sb.write('${line}:${column}');
+    } else {
+      sb.write('${line}');
+    }
+    sb.write('[unresolved]');
+    return sb.toString();
+  }
+}
+
 class _EventStreamState {
   VM _vm;
   String streamId;
@@ -1390,19 +1495,23 @@
     }
   }
 
-  Future<ServiceObject> addBreakpoint(Script script, int line) async {
+  Future<ServiceObject> addBreakpoint(
+      Script script, int line, [int col]) async {
     // TODO(turnidge): Pass line as an int instead of a string.
     try {
       Map params = {
         'scriptId': script.id,
-        'line': '$line',
+        'line': line.toString(),
       };
+      if (col != null) {
+        params['column'] = col.toString();
+      }
       Breakpoint bpt = await invokeRpc('addBreakpoint', params);
-      if (bpt.resolved &&
-          script.loaded &&
-          script.tokenToLine(bpt.location.tokenPos) != line) {
-        // TODO(turnidge): Can this still happen?
-        script.getLine(line).possibleBpt = false;
+      if (bpt.resolved && script.loaded) {
+        SourceLocation loc = bpt.location;
+        if (script.tokenToLine(loc.tokenPos) != line) {
+          script.getLine(line).possibleBpt = false;
+        }
       }
       return bpt;
     } on ServerRpcException catch(e) {
@@ -1414,6 +1523,18 @@
     }
   }
 
+  Future<ServiceObject> addBreakpointByScriptUri(
+      String uri, int line, [int col]) {
+    Map params = {
+      'scriptUri': uri,
+      'line': line.toString(),
+    };
+    if (col != null) {
+      params['column'] = col.toString();
+    }
+    return invokeRpc('addBreakpoint', params);
+  }
+
   Future<ServiceObject> addBreakpointAtEntry(ServiceFunction function) {
     return invokeRpc('addBreakpointAtEntry',
                      { 'functionId': function.id });
@@ -1855,8 +1976,11 @@
   // A unique integer identifier for this breakpoint.
   @observable int number;
 
-  // Source location information.
-  @observable SourceLocation location;
+  // Either SourceLocation or UnresolvedSourceLocation.
+  @observable Location location;
+
+  // The breakpoint is in a file which is not yet loaded.
+  @observable bool latent;
 
   // The breakpoint has been assigned to a final source location.
   @observable bool resolved;
@@ -1869,38 +1993,25 @@
     // number never changes.
     assert((number == null) || (number == newNumber));
     number = newNumber;
-
     resolved = map['resolved'];
 
     var oldLocation = location;
     var newLocation = map['location'];
-    var oldScript;
-    var newScript;
-    var oldTokenPos;
-    var newTokenPos;
-    if (oldLocation != null) {
-      oldScript = location.script;
-      oldTokenPos = location.tokenPos;
-    }
-    if (newLocation != null) {
-      newScript = newLocation.script;
-      newTokenPos = newLocation.tokenPos;
-    }
-    // script never changes
-    assert((oldScript == null) || (oldScript == newScript));
-    bool tokenPosChanged = oldTokenPos != newTokenPos;
-    if (newScript.loaded &&
-        (newTokenPos != null) &&
-        tokenPosChanged) {
-      // The breakpoint has moved.  Remove it and add it later.
-      if (oldScript != null) {
+    if (oldLocation is UnresolvedSourceLocation &&
+        newLocation is SourceLocation) {
+      // Breakpoint has been resolved.  Remove old breakpoint.
+      var oldScript = oldLocation.script;
+      if (oldScript != null && oldScript.loaded) {
         oldScript._removeBreakpoint(this);
       }
     }
     location = newLocation;
-    if (newScript.loaded && tokenPosChanged) {
+    var newScript = location.script;
+    if (newScript != null && newScript.loaded) {
       newScript._addBreakpoint(this);
     }
+
+    assert(resolved || location is UnresolvedSourceLocation);
   }
 
   void remove() {
@@ -2893,12 +3004,24 @@
   }
 
   void _addBreakpoint(Breakpoint bpt) {
-    var line = tokenToLine(bpt.location.tokenPos);
+    var line;
+    if (bpt.location.tokenPos != null) {
+      line = tokenToLine(bpt.location.tokenPos);
+    } else {
+      UnresolvedSourceLocation loc = bpt.location;
+      line = loc.line;
+    }
     getLine(line).addBreakpoint(bpt);
   }
 
   void _removeBreakpoint(Breakpoint bpt) {
-    var line = tokenToLine(bpt.location.tokenPos);
+    var line;
+    if (bpt.location.tokenPos != null) {
+      line = tokenToLine(bpt.location.tokenPos);
+    } else {
+      UnresolvedSourceLocation loc = bpt.location;
+      line = loc.line;
+    }
     if (line != null) {
       getLine(line).removeBreakpoint(bpt);
     }
diff --git a/runtime/observatory/observatory.gypi b/runtime/observatory/observatory.gypi
index 50cd334..4971524 100644
--- a/runtime/observatory/observatory.gypi
+++ b/runtime/observatory/observatory.gypi
@@ -30,6 +30,7 @@
           'action': [
             'python',
             '../tools/observatory_tool.py',
+            '--sdk=True',
             '--package-root', '<(PRODUCT_DIR)/packages',
             '--dart-executable',
             '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart_bootstrap<(EXECUTABLE_SUFFIX)',
@@ -63,6 +64,7 @@
           'action': [
             'python',
             '../tools/observatory_tool.py',
+            '--sdk=True',
             '--package-root', '<(PRODUCT_DIR)/packages',
             '--dart-executable',
             '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart_bootstrap<(EXECUTABLE_SUFFIX)',
@@ -83,6 +85,7 @@
           'action': [
             'python',
             '../tools/observatory_tool.py',
+            '--sdk=True',
             '--package-root', '<(PRODUCT_DIR)/packages',
             '--dart-executable',
             '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart_bootstrap<(EXECUTABLE_SUFFIX)',
diff --git a/runtime/observatory/tests/service/add_breakpoint_rpc_test.dart b/runtime/observatory/tests/service/add_breakpoint_rpc_test.dart
new file mode 100644
index 0000000..f1b3a10
--- /dev/null
+++ b/runtime/observatory/tests/service/add_breakpoint_rpc_test.dart
@@ -0,0 +1,215 @@
+// Copyright (c) 2015, 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=--error_on_bad_type --error_on_bad_override
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+import 'deferred_library.dart' deferred as deferredLib;
+import 'dart:async';
+import 'dart:developer' as developer;
+
+int value = 0;
+
+int incValue(int amount) {
+  value += amount;
+  return amount;
+}
+
+Future testMain() async {
+  incValue(incValue(1));  // line 21
+
+  incValue(incValue(1));  // line 23
+
+  await deferredLib.loadLibrary();
+  deferredLib.deferredTest();
+}
+
+var tests = [
+  hasPausedAtStart,
+
+  // Test future breakpoints.
+  (Isolate isolate) async {
+    var rootLib = isolate.rootLibrary;
+    await rootLib.load();
+    var script = rootLib.scripts[0];
+
+    // Future breakpoint.
+    var futureBpt1 = await isolate.addBreakpoint(script, 21);
+    expect(futureBpt1.number, equals(1));
+    expect(futureBpt1.resolved, isFalse);
+    expect(await futureBpt1.location.getLine(), equals(21));
+    expect(await futureBpt1.location.getColumn(), equals(null));
+
+    // Future breakpoint with specific column.
+    var futureBpt2 = await isolate.addBreakpoint(script, 21, 3);
+    expect(futureBpt2.number, equals(2));
+    expect(futureBpt2.resolved, isFalse);
+    expect(await futureBpt2.location.getLine(), equals(21));
+    expect(await futureBpt2.location.getColumn(), equals(3));
+
+    var stream = await isolate.vm.getEventStream(VM.kDebugStream);
+    Completer completer = new Completer();
+    var subscription;
+    var resolvedCount = 0;
+    subscription = stream.listen((ServiceEvent event) async {
+      if (event.kind == ServiceEvent.kBreakpointResolved) {
+        resolvedCount++;
+      }
+      if (event.kind == ServiceEvent.kPauseBreakpoint) {
+        subscription.cancel();
+        completer.complete(null);
+      }
+    });
+    await isolate.resume();
+    await completer.future;
+
+    // After resolution the breakpoints have assigned line & column.
+    expect(resolvedCount, equals(2));
+    expect(futureBpt1.resolved, isTrue);
+    expect(await futureBpt1.location.getLine(), equals(21));
+    expect(await futureBpt1.location.getColumn(), equals(12));
+    expect(futureBpt2.resolved, isTrue);
+    expect(await futureBpt2.location.getLine(), equals(21));
+    expect(await futureBpt2.location.getColumn(), equals(3));
+
+    // The first breakpoint hits before value is modified.
+    expect((await rootLib.evaluate('value')).valueAsString, equals('0'));
+
+    stream = await isolate.vm.getEventStream(VM.kDebugStream);
+    completer = new Completer();
+    subscription = stream.listen((ServiceEvent event) async {
+      if (event.kind == ServiceEvent.kPauseBreakpoint) {
+        subscription.cancel();
+        completer.complete(null);
+      }
+    });
+    await isolate.resume();
+    await completer.future;
+
+    // The second breakpoint hits after value has been modified once.
+    expect((await rootLib.evaluate('value')).valueAsString, equals('1'));
+
+    // Remove the breakpoints.
+    expect((await isolate.removeBreakpoint(futureBpt1)).type,
+           equals('Success'));
+    expect((await isolate.removeBreakpoint(futureBpt2)).type,
+           equals('Success'));
+  },
+
+  // Test breakpoints in deferred libraries (latent breakpoints).
+  (Isolate isolate) async {
+    var rootLib = isolate.rootLibrary;
+    var uri = rootLib.scripts[0].uri;
+    var lastSlashPos = uri.lastIndexOf('/');
+    var deferredUri =uri.substring(0, lastSlashPos) + '/deferred_library.dart';
+
+    // Latent breakpoint.
+    var latentBpt1 = await isolate.addBreakpointByScriptUri(deferredUri, 15);
+    expect(latentBpt1.number, equals(3));
+    expect(latentBpt1.resolved, isFalse);
+    expect(await latentBpt1.location.getLine(), equals(15));
+    expect(await latentBpt1.location.getColumn(), equals(null));
+
+    // Latent breakpoint with specific column.
+    var latentBpt2 =
+    await isolate.addBreakpointByScriptUri(deferredUri, 15, 3);
+    expect(latentBpt2.number, equals(4));
+    expect(latentBpt2.resolved, isFalse);
+    expect(await latentBpt2.location.getLine(), equals(15));
+    expect(await latentBpt2.location.getColumn(), equals(3));
+
+    var stream = await isolate.vm.getEventStream(VM.kDebugStream);
+    Completer completer = new Completer();
+    var subscription;
+    var resolvedCount = 0;
+    subscription = stream.listen((ServiceEvent event) async {
+      if (event.kind == ServiceEvent.kBreakpointResolved) {
+        resolvedCount++;
+      }
+      if (event.kind == ServiceEvent.kPauseBreakpoint) {
+        subscription.cancel();
+        completer.complete(null);
+      }
+    });
+    await isolate.resume();
+    await completer.future;
+
+    // After resolution the breakpoints have assigned line & column.
+    expect(resolvedCount, equals(2));
+    expect(latentBpt1.resolved, isTrue);
+    expect(await latentBpt1.location.getLine(), equals(15));
+    expect(await latentBpt1.location.getColumn(), equals(12));
+    expect(latentBpt2.resolved, isTrue);
+    expect(await latentBpt2.location.getLine(), equals(15));
+    expect(await latentBpt2.location.getColumn(), equals(3));
+
+    // The first breakpoint hits before value is modified.
+    expect((await rootLib.evaluate('deferredLib.value')).valueAsString,
+           equals('0'));
+
+    stream = await isolate.vm.getEventStream(VM.kDebugStream);
+    completer = new Completer();
+    subscription = stream.listen((ServiceEvent event) async {
+      if (event.kind == ServiceEvent.kPauseBreakpoint) {
+        subscription.cancel();
+        completer.complete(null);
+      }
+    });
+    await isolate.resume();
+    await completer.future;
+
+    // The second breakpoint hits after value has been modified once.
+    expect((await rootLib.evaluate('deferredLib.value')).valueAsString,
+           equals('-1'));
+
+    // Remove the breakpoints.
+    expect((await isolate.removeBreakpoint(latentBpt1)).type,
+           equals('Success'));
+    expect((await isolate.removeBreakpoint(latentBpt2)).type,
+           equals('Success'));
+  },
+
+
+  // Test resolution of column breakpoints.
+  (Isolate isolate) async {
+    var script = isolate.rootLibrary.scripts[0];
+    // Try all columns, including some columns that are too big.
+    for (int col = 1; col <= 50; col++) {
+      var bpt = await isolate.addBreakpoint(script, 21, col);
+      expect(bpt.resolved, isTrue);
+      int resolvedLine = await bpt.location.getLine();
+      int resolvedCol = await bpt.location.getColumn();
+      print('21:${col} -> ${resolvedLine}:${resolvedCol}');
+      if (col <= 10) {
+        expect(resolvedLine, equals(21));
+        expect(resolvedCol, equals(3));
+      } else if (col <= 19) {
+        expect(resolvedLine, equals(21));
+        expect(resolvedCol, equals(12));
+      } else {
+        expect(resolvedLine, equals(23));
+        expect(resolvedCol, equals(12));
+      }
+      expect((await isolate.removeBreakpoint(bpt)).type, equals('Success'));
+    }
+
+    // Make sure that a zero column is an error.
+    var caughtException = false;
+    try {
+      await isolate.addBreakpoint(script, 21, 0);
+      expect(false, isTrue, reason:'Unreachable');
+    } on ServerRpcException catch(e) {
+      caughtException = true;
+      expect(e.code, equals(ServerRpcException.kInvalidParams));
+      expect(e.message,
+             "addBreakpoint: invalid 'column' parameter: 0");
+    }
+    expect(caughtException, isTrue);
+  },
+];
+
+main(args) => runIsolateTests(args, tests,
+                              testeeConcurrent: testMain,
+                              pause_on_start: true);
diff --git a/runtime/observatory/tests/service/debugger_location_test.dart b/runtime/observatory/tests/service/debugger_location_test.dart
index 407bd52..33ca476 100644
--- a/runtime/observatory/tests/service/debugger_location_test.dart
+++ b/runtime/observatory/tests/service/debugger_location_test.dart
@@ -59,7 +59,7 @@
   return initDebugger(isolate).then((debugger) {
     return DebuggerLocation.parse(debugger, '').then((DebuggerLocation loc) {
       expect(loc.valid, isTrue);
-      expect(loc.toString(), equals('debugger_location_test.dart:17'));
+      expect(loc.toString(), equals('debugger_location_test.dart:17:5'));
     });
   });
 },
diff --git a/runtime/observatory/tests/service/deferred_library.dart b/runtime/observatory/tests/service/deferred_library.dart
new file mode 100644
index 0000000..d2074ee
--- /dev/null
+++ b/runtime/observatory/tests/service/deferred_library.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2015, 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 deferred_library;
+
+int value = 0;
+
+int decValue(int amount) {
+  value -= amount;
+  return amount;
+}
+
+void deferredTest() {
+  decValue(decValue(1));  // line 15
+
+  decValue(decValue(1));  // line 17
+}
diff --git a/runtime/observatory/tests/service/file_service_test.dart b/runtime/observatory/tests/service/file_service_test.dart
index dbb8e53..22b5827 100644
--- a/runtime/observatory/tests/service/file_service_test.dart
+++ b/runtime/observatory/tests/service/file_service_test.dart
@@ -79,19 +79,23 @@
       var writing = await isolate.invokeRpcNoUpgrade(
            '__getFileByID', { 'id' : result['data'][0]['id'] });
 
-      expect(writing['total_read'], equals(0));
-      expect(writing['read_count'], equals(0));
-      expect(writing['write_count'], equals(3));
-      expect(writing['total_written'], equals(3));
+      expect(writing['totalRead'], equals(0));
+      expect(writing['readCount'], equals(0));
+      expect(writing['writeCount'], equals(3));
+      expect(writing['totalWritten'], equals(3));
+      expect(writing['lastWrite'], greaterThan(0));
+      expect(writing['lastRead'], equals(0));
 
       var reading = await isolate.invokeRpcNoUpgrade(
-           '__getFileByID', { 'id' : result['data'][1]['id'] });
+          '__getFileByID', { 'id' : result['data'][1]['id'] });
 
+      expect(reading['totalRead'], equals(5));
+      expect(reading['readCount'], equals(5));
+      expect(reading['writeCount'], equals(0));
+      expect(reading['totalWritten'], equals(0));
+      expect(reading['lastWrite'], equals(0));
+      expect(reading['lastRead'], greaterThan(0));
 
-      expect(reading['total_read'], equals(5));
-      expect(reading['read_count'], equals(5));
-      expect(reading['write_count'], equals(0));
-      expect(reading['total_written'], equals(0));
     } finally {
       await isolate.invokeRpcNoUpgrade('__cleanup', {});
     }
diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart
index 8c33998..3df8d67 100644
--- a/runtime/observatory/tests/service/get_version_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_version_rpc_test.dart
@@ -12,8 +12,8 @@
   (VM vm) async {
     var result = await vm.invokeRpcNoUpgrade('getVersion', {});
     expect(result['type'], equals('Version'));
-    expect(result['major'], equals(2));
-    expect(result['minor'], equals(1));
+    expect(result['major'], equals(3));
+    expect(result['minor'], equals(0));
     expect(result['_privateMajor'], equals(0));
     expect(result['_privateMinor'], equals(0));
   },
diff --git a/runtime/observatory/tests/service/process_service_test.dart b/runtime/observatory/tests/service/process_service_test.dart
new file mode 100644
index 0000000..956cc77
--- /dev/null
+++ b/runtime/observatory/tests/service/process_service_test.dart
@@ -0,0 +1,127 @@
+// Copyright (c) 2015, 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 'dart:convert';
+import 'dart:developer';
+import 'dart:io' as io;
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+
+Future setupProcesses() async {
+  var dir = await io.Directory.systemTemp.createTemp('file_service');
+
+  var args = ['--pause_isolates_on_start', io.Platform.script.toFilePath()];
+  var process1;
+  var process2;
+  var process3;
+
+  void closeDown() {
+    if (process1 != null) {
+      process1.kill();
+    }
+    if (process2 != null) {
+      process2.kill();
+    }
+    if (process3 != null) {
+      process3.kill();
+    }
+    dir.deleteSync(recursive: true);
+  }
+
+  Future<ServiceExtensionResponse> cleanup(ignored_a, ignored_b) {
+    closeDown();
+    var result = JSON.encode({'type' : 'foobar'});
+    return new Future.value(new ServiceExtensionResponse.result(result));
+  }
+
+  Future<ServiceExtensionResponse> setup(ignored_a, ignored_b) async {
+    try {
+      process1 = await io.Process.start(io.Platform.executable, args);
+      process2 = await io.Process.start(io.Platform.executable,
+                                        args..add('foobar'));
+      var codeFilePath = dir.path + io.Platform.pathSeparator + "other_file";
+      var codeFile = new io.File(codeFilePath);
+      await codeFile.writeAsString(
+          '''
+          import "dart:io";
+
+          void main() async {
+            await stdin.drain();
+          }
+          ''');
+      process3 = await io.Process.start(io.Platform.executable,
+                                        [codeFilePath]);
+    } catch (e) {
+      closeDown();
+      throw e;
+    }
+
+    var result =
+      JSON.encode({'type': 'foobar',
+                   'pids' : [process1.pid, process2.pid, process3.pid]});
+    return new Future.value(new ServiceExtensionResponse.result(result));
+  }
+
+  Future<ServiceExtensionResponse> closeStdin(ignored_a, ignored_b) async {
+    process3.stdin.close();
+    var result = JSON.encode({'type' : 'foobar'});
+    var returnValue =
+        new Future.value(new ServiceExtensionResponse.result(result));
+    return  process3.exitCode.then((int exit) => returnValue);
+  }
+
+  registerExtension('__cleanup', cleanup);
+  registerExtension('__setup', setup);
+  registerExtension('__closeStdin', closeStdin);
+
+}
+
+var processTests = [
+  // Initial.
+  (Isolate isolate) async {
+    var setup = await isolate.invokeRpcNoUpgrade('__setup', {});
+    try {
+      var all = await isolate.invokeRpcNoUpgrade('__getProcesses', {});
+      expect(all['type'], equals('_startedprocesses'));
+
+      expect(all['data'].length, equals(3));
+
+      var first = await isolate.invokeRpcNoUpgrade(
+          '__getProcessById', { 'id' : all['data'][0]['id'] });
+      expect(first['name'], io.Platform.executable);
+      expect(first['pid'], equals(setup['pids'][0]));
+      expect(first['arguments'].contains('foobar'), isFalse);
+      expect(first['startedAt'], greaterThan(0));
+
+      var second = await isolate.invokeRpcNoUpgrade(
+          '__getProcessById', { 'id' : all['data'][1]['id'] });
+      expect(second['name'], io.Platform.executable);
+      expect(second['pid'], equals(setup['pids'][1]));
+      expect(second['arguments'].contains('foobar'), isTrue);
+      expect(second['pid'] != first['pid'], isTrue);
+      expect(second['startedAt'], greaterThan(0));
+      expect(second['startedAt'], greaterThanOrEqualTo(first['startedAt']));
+
+      var third = await isolate.invokeRpcNoUpgrade(
+          '__getProcessById', { 'id' : all['data'][2]['id'] });
+      expect(third['name'], io.Platform.executable);
+      expect(third['pid'], equals(setup['pids'][2]));
+      expect(third['pid'] != first['pid'], isTrue);
+      expect(third['pid'] != second['pid'], isTrue);
+      expect(third['startedAt'], greaterThanOrEqualTo(second['startedAt']));
+
+      await isolate.invokeRpcNoUpgrade('__closeStdin', {});
+      all = await isolate.invokeRpcNoUpgrade('__getProcesses', {});
+      expect(all['type'], equals('_startedprocesses'));
+      expect(all['data'].length, equals(2));
+    } finally {
+      await isolate.invokeRpcNoUpgrade('__cleanup', {});
+    }
+  },
+];
+
+main(args) async => runIsolateTests(args, processTests,
+                                    testeeBefore:setupProcesses);
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
index 75b4f95..088c36a 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -17,3 +17,6 @@
 # Tests with known analyzer issues
 [ $compiler == dartanalyzer || $compiler == dart2analyzer ]
 developer_extension_test: SkipByDesign
+
+[ $arch == arm ]
+process_service_test: Fail # Issue 24344
diff --git a/runtime/observatory/tests/service/tcp_socket_closing_service_test.dart b/runtime/observatory/tests/service/tcp_socket_closing_service_test.dart
index aef5571..20a9b76 100644
--- a/runtime/observatory/tests/service/tcp_socket_closing_service_test.dart
+++ b/runtime/observatory/tests/service/tcp_socket_closing_service_test.dart
@@ -62,12 +62,12 @@
     var server = await isolate.invokeRpcNoUpgrade(
         '__getSocketByID', { 'id' : result['data'][0]['id'] });
     expect(server['listening'], isTrue);
-    expect(server['last_read'], equals(0));
-    expect(server['total_read'], equals(0));
-    expect(server['last_write'], equals(0));
-    expect(server['total_written'], equals(0));
-    expect(server['write_count'], equals(0));
-    expect(server['read_count'], equals(0));
+    expect(server['lastRead'], equals(0));
+    expect(server['totalRead'], equals(0));
+    expect(server['lastWrite'], equals(0));
+    expect(server['totalWritten'], equals(0));
+    expect(server['writeCount'], equals(0));
+    expect(server['readCount'], equals(0));
   },
 ];
 
diff --git a/runtime/observatory/tests/service/tcp_socket_service_test.dart b/runtime/observatory/tests/service/tcp_socket_service_test.dart
index 0a85611..f8dff03 100644
--- a/runtime/observatory/tests/service/tcp_socket_service_test.dart
+++ b/runtime/observatory/tests/service/tcp_socket_service_test.dart
@@ -27,15 +27,6 @@
   await socket2.flush();
 }
 
-void expectTimeBiggerThanZero(time) {
-   // Stopwatch resolution on windows makes us sometimes report 0;
-  if (io.Platform.isWindows) {
-    expect(time, greaterThanOrEqualTo(0));
-  } else {
-    expect(time, greaterThan(0));
-  }
-}
-
 var tcpTests = [
   // Initial.
   (Isolate isolate) async {
@@ -57,17 +48,17 @@
         '__getSocketByID', { 'id' : result['data'][0]['id'] });
     expect(listening['id'], equals(result['data'][0]['id']));
     expect(listening['listening'], isTrue);
-    expect(listening['socket_type'], equals('TCP'));
+    expect(listening['socketType'], equals('TCP'));
     expect(listening['port'], greaterThanOrEqualTo(1024));
-    expectTimeBiggerThanZero(listening['last_read']);
+    expect(listening['lastRead'], greaterThan(0));
 
-    expect(listening['total_read'], equals(2));
-    expect(listening['last_write'], equals(0));
-    expect(listening['total_written'], equals(0));
-    expect(listening['write_count'], equals(0));
-    expect(listening['read_count'], equals(0));
-    expect(listening['remote_host'], equals('NA'));
-    expect(listening['remote_port'], equals('NA'));
+    expect(listening['totalRead'], equals(2));
+    expect(listening['lastWrite'], equals(0));
+    expect(listening['totalWritten'], equals(0));
+    expect(listening['writeCount'], equals(0));
+    expect(listening['readCount'], equals(2));
+    expect(listening['remoteHost'], equals('NA'));
+    expect(listening['remotePort'], equals('NA'));
 
     var client = await isolate.invokeRpcNoUpgrade(
         '__getSocketByID', { 'id' : result['data'][1]['id'] });
@@ -79,8 +70,8 @@
 
     // We expect the client to be connected on the port and
     // host of the listening socket.
-    expect(client['remote_port'], equals(listening['port']));
-    expect(client['remote_host'], equals(listening['host']));
+    expect(client['remotePort'], equals(listening['port']));
+    expect(client['remoteHost'], equals(listening['host']));
     // We expect the third socket (accepted server) to be connected to the
     // same port and host as the listening socket (the listening one).
     expect(server['port'], equals(listening['port']));
@@ -89,8 +80,8 @@
     expect(client['listening'], isFalse);
     expect(server['listening'], isFalse);
 
-    expect(client['socket_type'], equals('TCP'));
-    expect(server['socket_type'], equals('TCP'));
+    expect(client['socketType'], equals('TCP'));
+    expect(server['socketType'], equals('TCP'));
 
     // We are using no reserved ports.
     expect(client['port'], greaterThanOrEqualTo(1024));
@@ -98,76 +89,76 @@
 
     // The client and server "mirror" each other in reads and writes, and the
     // timestamps are in correct order.
-    expect(client['last_read'], equals(0));
-    expectTimeBiggerThanZero(server['last_read']);
-    expect(client['total_read'], equals(0));
-    expect(server['total_read'], equals(12));
-    expect(client['read_count'], equals(0));
-    expect(server['read_count'], greaterThanOrEqualTo(1));
+    expect(client['lastRead'], equals(0));
+    expect(server['lastRead'], greaterThan(0));
+    expect(client['totalRead'], equals(0));
+    expect(server['totalRead'], equals(12));
+    expect(client['readCount'], equals(0));
+    expect(server['readCount'], greaterThanOrEqualTo(1));
 
-    expectTimeBiggerThanZero(client['last_write']);
-    expect(server['last_write'], equals(0));
-    expect(client['total_written'], equals(12));
-    expect(server['total_written'], equals(0));
-    expect(client['write_count'], greaterThanOrEqualTo(2));
-    expect(server['write_count'], equals(0));
+    expect(client['lastWrite'], greaterThan(0));
+    expect(server['lastWrite'], equals(0));
+    expect(client['totalWritten'], equals(12));
+    expect(server['totalWritten'], equals(0));
+    expect(client['writeCount'], greaterThanOrEqualTo(2));
+    expect(server['writeCount'], equals(0));
 
     // Order
     // Stopwatch resolution on windows can make us have the same timestamp.
     if (io.Platform.isWindows) {
-      expect(server['last_read'], greaterThanOrEqualTo(client['last_write']));
+      expect(server['lastRead'], greaterThanOrEqualTo(client['lastWrite']));
     } else {
-      expect(server['last_read'], greaterThan(client['last_write']));
+      expect(server['lastRead'], greaterThan(client['lastWrite']));
     }
 
-    var second_client = await isolate.invokeRpcNoUpgrade(
+    var secondClient = await isolate.invokeRpcNoUpgrade(
         '__getSocketByID', { 'id' : result['data'][3]['id'] });
-    expect(second_client['id'], equals(result['data'][3]['id']));
-    var second_server = await isolate.invokeRpcNoUpgrade(
+    expect(secondClient['id'], equals(result['data'][3]['id']));
+    var secondServer = await isolate.invokeRpcNoUpgrade(
         '__getSocketByID', { 'id' : result['data'][4]['id'] });
-    expect(second_server['id'], equals(result['data'][4]['id']));
+    expect(secondServer['id'], equals(result['data'][4]['id']));
 
     // We expect the client to be connected on the port and
     // host of the listening socket.
-    expect(second_client['remote_port'], equals(listening['port']));
-    expect(second_client['remote_host'], equals(listening['host']));
+    expect(secondClient['remotePort'], equals(listening['port']));
+    expect(secondClient['remoteHost'], equals(listening['host']));
     // We expect the third socket (accepted server) to be connected to the
     // same port and host as the listening socket (the listening one).
-    expect(second_server['port'], equals(listening['port']));
-    expect(second_server['host'], equals(listening['host']));
+    expect(secondServer['port'], equals(listening['port']));
+    expect(secondServer['host'], equals(listening['host']));
 
-    expect(second_client['listening'], isFalse);
-    expect(second_server['listening'], isFalse);
+    expect(secondClient['listening'], isFalse);
+    expect(secondServer['listening'], isFalse);
 
-    expect(second_client['socket_type'], equals('TCP'));
-    expect(second_server['socket_type'], equals('TCP'));
+    expect(secondClient['socketType'], equals('TCP'));
+    expect(secondServer['socketType'], equals('TCP'));
 
     // We are using no reserved ports.
-    expect(second_client['port'], greaterThanOrEqualTo(1024));
-    expect(second_server['port'], greaterThanOrEqualTo(1024));
+    expect(secondClient['port'], greaterThanOrEqualTo(1024));
+    expect(secondServer['port'], greaterThanOrEqualTo(1024));
 
     // The client and server "mirror" each other in reads and writes, and the
     // timestamps are in correct order.
-    expect(second_client['last_read'], equals(0));
-    expectTimeBiggerThanZero(second_server['last_read']);
-    expect(second_client['total_read'], equals(0));
-    expect(second_server['total_read'], equals(12));
-    expect(second_client['read_count'], equals(0));
-    expect(second_server['read_count'], greaterThanOrEqualTo(1));
+    expect(secondClient['lastRead'], equals(0));
+    expect(secondServer['lastRead'], greaterThan(0));
+    expect(secondClient['totalRead'], equals(0));
+    expect(secondServer['totalRead'], equals(12));
+    expect(secondClient['readCount'], equals(0));
+    expect(secondServer['readCount'], greaterThanOrEqualTo(1));
 
-    expectTimeBiggerThanZero(second_client['last_write']);
-    expect(second_server['last_write'], equals(0));
-    expect(second_client['total_written'], equals(12));
-    expect(second_server['total_written'], equals(0));
-    expect(second_client['write_count'], greaterThanOrEqualTo(1));
-    expect(second_server['write_count'], equals(0));
+    expect(secondClient['lastWrite'], greaterThan(0));
+    expect(secondServer['lastWrite'], equals(0));
+    expect(secondClient['totalWritten'], equals(12));
+    expect(secondServer['totalWritten'], equals(0));
+    expect(secondClient['writeCount'], greaterThanOrEqualTo(1));
+    expect(secondServer['writeCount'], equals(0));
 
     // Order
     // Stopwatch resolution on windows make us sometimes report the same value.
     if (io.Platform.isWindows) {
-      expect(server['last_read'], greaterThanOrEqualTo(client['last_write']));
+      expect(server['lastRead'], greaterThanOrEqualTo(client['lastWrite']));
     } else {
-      expect(server['last_read'], greaterThan(client['last_write']));
+      expect(server['lastRead'], greaterThan(client['lastWrite']));
     }
   },
 ];
diff --git a/runtime/observatory/tests/service/test_helper.dart b/runtime/observatory/tests/service/test_helper.dart
index 6c6c223..fa453df 100644
--- a/runtime/observatory/tests/service/test_helper.dart
+++ b/runtime/observatory/tests/service/test_helper.dart
@@ -164,7 +164,6 @@
   isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
     var subscription;
     subscription = stream.listen((ServiceEvent event) {
-        print("Event: $event");
         if (event.kind == ServiceEvent.kPauseBreakpoint) {
           print('Breakpoint reached');
           subscription.cancel();
@@ -195,6 +194,41 @@
 }
 
 
+Future<Isolate> hasPausedAtStart(Isolate isolate) {
+  // Set up a listener to wait for breakpoint events.
+  Completer completer = new Completer();
+  isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
+    var subscription;
+    subscription = stream.listen((ServiceEvent event) {
+        if (event.kind == ServiceEvent.kPauseStart) {
+          print('Paused at isolate start');
+          subscription.cancel();
+          if (completer != null) {
+            // Reload to update isolate.pauseEvent.
+            completer.complete(isolate.reload());
+            completer = null;
+          }
+        }
+    });
+
+    // Pause may have happened before we subscribed.
+    isolate.reload().then((_) {
+      if ((isolate.pauseEvent != null) &&
+         (isolate.pauseEvent.kind == ServiceEvent.kPauseStart)) {
+        print('Paused at isolate start');
+        subscription.cancel();
+        if (completer != null) {
+          completer.complete(isolate);
+          completer = null;
+        }
+      }
+    });
+  });
+
+  return completer.future;
+}
+
+
 // Currying is your friend.
 IsolateTest setBreakpointAtLine(int line) {
   return (Isolate isolate) async {
diff --git a/runtime/observatory/tests/service/udp_socket_service_test.dart b/runtime/observatory/tests/service/udp_socket_service_test.dart
index 6b4b3b9..49ff5e4 100644
--- a/runtime/observatory/tests/service/udp_socket_service_test.dart
+++ b/runtime/observatory/tests/service/udp_socket_service_test.dart
@@ -40,42 +40,42 @@
     var server = await isolate.invokeRpcNoUpgrade(
         '__getSocketByID', { 'id' : result['data'][0]['id'] });
     expect(server['id'], equals(result['data'][0]['id']));
-    expect(server['remote_port'], equals('NA'));
-    expect(server['remote_host'], equals('NA'));
+    expect(server['remotePort'], equals('NA'));
+    expect(server['remoteHost'], equals('NA'));
     expect(server['listening'], isFalse);
-    expect(server['socket_type'], equals('UDP'));
+    expect(server['socketType'], equals('UDP'));
     expect(server['port'], greaterThanOrEqualTo(1024));
     // Stopwatch resolution on windows makes us sometimes report 0;
     if (io.Platform.isWindows) {
-      expect(server['last_read'], greaterThanOrEqualTo(0));
+      expect(server['lastRead'], greaterThanOrEqualTo(0));
     } else {
-      expect(server['last_read'], greaterThan(0));
+      expect(server['lastRead'], greaterThan(0));
     }
-    expect(server['total_read'], equals(6));
-    expect(server['last_write'], equals(0));
-    expect(server['total_written'], equals(0));
-    expect(server['write_count'], equals(0));
-    expect(server['read_count'], greaterThanOrEqualTo(1));
+    expect(server['totalRead'], equals(6));
+    expect(server['lastWrite'], equals(0));
+    expect(server['totalWritten'], equals(0));
+    expect(server['writeCount'], equals(0));
+    expect(server['readCount'], greaterThanOrEqualTo(1));
 
     var client = await isolate.invokeRpcNoUpgrade(
         '__getSocketByID', { 'id' : result['data'][1]['id'] });
     expect(client['id'], equals(result['data'][1]['id']));
-    expect(client['remote_port'], equals('NA'));
-    expect(client['remote_host'], equals('NA'));
+    expect(client['remotePort'], equals('NA'));
+    expect(client['remoteHost'], equals('NA'));
     expect(client['listening'], isFalse);
-    expect(client['socket_type'], equals('UDP'));
+    expect(client['socketType'], equals('UDP'));
     expect(client['port'], greaterThanOrEqualTo(1024));
-    expect(client['last_read'], equals(0));
-    expect(client['total_read'], equals(0));
+    expect(client['lastRead'], equals(0));
+    expect(client['totalRead'], equals(0));
     // Stopwatch resolution on windows makes us sometimes report 0;
     if (io.Platform.isWindows) {
-      expect(client['last_write'], greaterThanOrEqualTo(0));
+      expect(client['lastWrite'], greaterThanOrEqualTo(0));
     } else {
-      expect(client['last_write'], greaterThan(0));
+      expect(client['lastWrite'], greaterThan(0));
     }
-    expect(client['total_written'], equals(6));
-    expect(client['write_count'], greaterThanOrEqualTo(1));
-    expect(client['read_count'], equals(0));
+    expect(client['totalWritten'], equals(6));
+    expect(client['writeCount'], greaterThanOrEqualTo(1));
+    expect(client['readCount'], equals(0));
   },
 ];
 
diff --git a/runtime/observatory/tests/ui/inspector.dart b/runtime/observatory/tests/ui/inspector.dart
index b133e91..fd6d0c3 100644
--- a/runtime/observatory/tests/ui/inspector.dart
+++ b/runtime/observatory/tests/ui/inspector.dart
@@ -6,7 +6,6 @@
 
 library manual_inspector_test;
 
-import 'dart:async';
 import 'dart:isolate';
 import 'dart:mirrors';
 import 'dart:developer';
diff --git a/runtime/tests/vm/dart/spawn_infinite_loop_test.dart b/runtime/tests/vm/dart/spawn_infinite_loop_test.dart
new file mode 100644
index 0000000..cc0fb42
--- /dev/null
+++ b/runtime/tests/vm/dart/spawn_infinite_loop_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2015, 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';
+
+// This test ensures that the VM can kill the spawned isolate during VM
+// shutdown even when the isolate is in an infinite loop and will not finish
+// on its own.
+
+void loop(msg) {
+  while (true) {}
+  throw "Unreachable";
+}
+
+void main() {
+  Isolate.spawn(loop, []);
+}
diff --git a/runtime/tests/vm/dart/spawn_shutdown_test.dart b/runtime/tests/vm/dart/spawn_shutdown_test.dart
new file mode 100644
index 0000000..794e737
--- /dev/null
+++ b/runtime/tests/vm/dart/spawn_shutdown_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2015, 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 'dart:isolate';
+
+// Spawn an isolate |foo| that will continue trying to spawn isolates even after
+// the timer in |main| completes. This test ensures that the VM can shutdown
+// correctly even while an isolate is attempting to spawn more isolates.
+
+isolate1(sendPort) {
+  var receivePort = new ReceivePort();
+  sendPort.send(receivePort.sendPort);
+  receivePort.listen((msg) {});
+}
+
+void foo(_) {
+  while (true) {
+    var receivePort = new ReceivePort();
+    Isolate.spawn(isolate1, receivePort.sendPort);
+    receivePort.listen((sendPort) {
+      Isolate.spawn(isolate1,sendPort);
+      receivePort.close();
+    });
+  }
+}
+
+void main() {
+  Isolate.spawn(foo, null);
+  new Timer(const Duration(seconds: 10), () {});
+}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index d0ffb46..7f82dcb 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -88,6 +88,8 @@
 
 [ $runtime != vm ]
 dart/snapshot_version_test: SkipByDesign  # Spawns processes
+dart/spawn_infinite_loop_test: Skip  # VM shutdown test
+dart/spawn_shutdown_test: Skip  # VM Shutdown test
 
 [ $runtime == vm && $mode == debug && $builder_tag == asan ]
 cc/Dart2JSCompileAll: Skip  # Timeout.
diff --git a/runtime/vm/assembler.cc b/runtime/vm/assembler.cc
index 489f090..5fe8c2f 100644
--- a/runtime/vm/assembler.cc
+++ b/runtime/vm/assembler.cc
@@ -306,6 +306,14 @@
 }
 
 
+intptr_t ObjectPoolWrapper::FindNativeEntry(const ExternalLabel* label,
+                                            Patchability patchable) {
+  return FindObject(ObjectPool::Entry(label->address(),
+                                      ObjectPool::kNativeEntry),
+                    patchable);
+}
+
+
 RawObjectPool* ObjectPoolWrapper::MakeObjectPool() {
   intptr_t len = object_pool_.length();
   if (len == 0) {
diff --git a/runtime/vm/assembler.h b/runtime/vm/assembler.h
index f2ad6fe..3f4d5ea 100644
--- a/runtime/vm/assembler.h
+++ b/runtime/vm/assembler.h
@@ -296,6 +296,8 @@
   intptr_t FindImmediate(uword imm);
   intptr_t FindExternalLabel(const ExternalLabel* label,
                              Patchability patchable);
+  intptr_t FindNativeEntry(const ExternalLabel* label,
+                           Patchability patchable);
 
   RawObjectPool* MakeObjectPool();
 
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index 71a9608..afb5744 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -20,6 +20,7 @@
 
 namespace dart {
 
+DECLARE_FLAG(bool, allow_absolute_addresses);
 DEFINE_FLAG(bool, print_stop_message, true, "Print stop message.");
 DECLARE_FLAG(bool, inline_alloc);
 
@@ -1583,6 +1584,7 @@
   if (object.IsSmi()) {
     LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw()), cond);
   } else if (object.InVMHeap() || !constant_pool_allowed()) {
+    ASSERT(FLAG_allow_absolute_addresses);
     // Make sure that class CallPattern is able to decode this load immediate.
     const int32_t object_raw = reinterpret_cast<int32_t>(object.raw());
     LoadImmediate(rd, object_raw, cond);
@@ -1619,6 +1621,16 @@
 }
 
 
+void Assembler::LoadNativeEntry(Register rd,
+                                const ExternalLabel* label,
+                                Patchability patchable,
+                                Condition cond) {
+  const int32_t offset = ObjectPool::element_offset(
+      object_pool_wrapper_.FindNativeEntry(label, patchable));
+  LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, cond);
+}
+
+
 void Assembler::PushObject(const Object& object) {
   LoadObject(IP, object);
   Push(IP);
@@ -1767,7 +1779,7 @@
       LoadImmediate(temp, Heap::kZap32Bits);
       cmp(old_value, Operand(temp));
       b(&ok, EQ);
-      LoadImmediate(temp, reinterpret_cast<uint32_t>(Object::null()));
+      LoadObject(temp, Object::null_object());
       cmp(old_value, Operand(temp));
       b(&ok, EQ);
       Stop("Expected zapped, Smi or null");
@@ -1997,12 +2009,9 @@
 
 
 void Assembler::LoadClassIdMayBeSmi(Register result, Register object) {
-  static const intptr_t kSmiCidSource = kSmiCid << RawObject::kClassIdTagPos;
-
-  LoadImmediate(TMP, reinterpret_cast<int32_t>(&kSmiCidSource) + 1);
   tst(object, Operand(kSmiTagMask));
-  mov(TMP, Operand(object), NE);
-  LoadClassId(result, TMP);
+  LoadClassId(result, object, NE);
+  LoadImmediate(result, kSmiCid, EQ);
 }
 
 
@@ -2708,7 +2717,7 @@
   // use 'blx ip' in a non-patchable sequence (see other BranchLink flavors).
   const int32_t offset = ObjectPool::element_offset(
       object_pool_wrapper_.FindExternalLabel(label, patchable));
-  LoadWordFromPoolOffset(LR, offset - kHeapObjectTag);
+  LoadWordFromPoolOffset(LR, offset - kHeapObjectTag, AL);
   blx(LR);  // Use blx instruction so that the return branch prediction works.
 }
 
@@ -2761,7 +2770,7 @@
   if ((version == ARMv5TE) || (version == ARMv6)) {
     if (constant_pool_allowed()) {
       const int32_t offset = Array::element_offset(FindImmediate(value));
-      LoadWordFromPoolOffset(rd, offset - kHeapObjectTag);
+      LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, cond);
     } else {
       LoadPatchableImmediate(rd, value, cond);
     }
@@ -3377,6 +3386,7 @@
   ASSERT(cid > 0);
   const intptr_t class_offset = ClassTable::ClassOffsetFor(cid);
   if (inline_isolate) {
+    ASSERT(FLAG_allow_absolute_addresses);
     ClassTable* class_table = Isolate::Current()->class_table();
     ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
     if (cid < kNumPredefinedCids) {
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 79dbea8..6fb2da7 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -671,6 +671,10 @@
                          const ExternalLabel* label,
                          Patchability patchable,
                          Condition cond = AL);
+  void LoadNativeEntry(Register dst,
+                       const ExternalLabel* label,
+                       Patchability patchable,
+                       Condition cond = AL);
   void PushObject(const Object& object);
   void CompareObject(Register rn, const Object& object);
 
@@ -756,7 +760,6 @@
                            Label* miss);
 
   intptr_t FindImmediate(int32_t imm);
-  void LoadWordFromPoolOffset(Register rd, int32_t offset, Condition cond = AL);
   void LoadFromOffset(OperandSize type,
                       Register reg,
                       Register base,
@@ -992,6 +995,8 @@
 
   void BranchLink(const ExternalLabel* label);
 
+  void LoadWordFromPoolOffset(Register rd, int32_t offset, Condition cond);
+
   class CodeComment : public ZoneAllocated {
    public:
     CodeComment(intptr_t pc_offset, const String& comment)
diff --git a/runtime/vm/assembler_arm64.cc b/runtime/vm/assembler_arm64.cc
index 7ea74a2..a360a2d 100644
--- a/runtime/vm/assembler_arm64.cc
+++ b/runtime/vm/assembler_arm64.cc
@@ -20,6 +20,7 @@
 
 namespace dart {
 
+DECLARE_FLAG(bool, allow_absolute_addresses);
 DEFINE_FLAG(bool, use_far_branches, false, "Always use far branches");
 DEFINE_FLAG(bool, print_stop_message, false, "Print stop message.");
 DECLARE_FLAG(bool, inline_alloc);
@@ -396,6 +397,14 @@
 }
 
 
+void Assembler::LoadNativeEntry(Register dst,
+                                const ExternalLabel* label) {
+  const int32_t offset = ObjectPool::element_offset(
+      object_pool_wrapper_.FindNativeEntry(label, kNotPatchable));
+  LoadWordFromPoolOffset(dst, offset);
+}
+
+
 void Assembler::LoadExternalLabelFixed(Register dst,
                                        const ExternalLabel* label,
                                        Patchability patchable) {
@@ -422,6 +431,7 @@
     LoadWordFromPoolOffset(dst, offset);
   } else {
     ASSERT(object.IsSmi() || object.InVMHeap());
+    ASSERT(object.IsSmi() || FLAG_allow_absolute_addresses);
     LoadDecodableImmediate(dst, reinterpret_cast<int64_t>(object.raw()));
   }
 }
@@ -457,6 +467,7 @@
     LoadObject(TMP, object);
     CompareRegisters(reg, TMP);
   } else {
+    ASSERT(object.IsSmi() || FLAG_allow_absolute_addresses);
     CompareImmediate(reg, reinterpret_cast<int64_t>(object.raw()));
   }
 }
@@ -1245,6 +1256,7 @@
   intptr_t counter_offset =
       ClassTable::CounterOffsetFor(cid, space == Heap::kNew);
   if (inline_isolate) {
+    ASSERT(FLAG_allow_absolute_addresses);
     ClassTable* class_table = Isolate::Current()->class_table();
     ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
     if (cid < kNumPredefinedCids) {
@@ -1314,6 +1326,7 @@
   ASSERT(cid > 0);
   intptr_t state_offset = ClassTable::StateOffsetFor(cid);
   if (inline_isolate) {
+    ASSERT(FLAG_allow_absolute_addresses);
     ClassTable* class_table = Isolate::Current()->class_table();
     ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
     if (cid < kNumPredefinedCids) {
diff --git a/runtime/vm/assembler_arm64.h b/runtime/vm/assembler_arm64.h
index dbb4a3b..6a70ff8 100644
--- a/runtime/vm/assembler_arm64.h
+++ b/runtime/vm/assembler_arm64.h
@@ -1288,6 +1288,7 @@
   intptr_t FindImmediate(int64_t imm);
   bool CanLoadFromObjectPool(const Object& object) const;
   void LoadExternalLabel(Register dst, const ExternalLabel* label);
+  void LoadNativeEntry(Register dst, const ExternalLabel* label);
   void LoadExternalLabelFixed(Register dst,
                               const ExternalLabel* label,
                               Patchability patchable);
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index a839a58..4bdc206 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -17,6 +17,7 @@
 #if defined(USING_SIMULATOR)
 DECLARE_FLAG(int, trace_sim_after);
 #endif
+DECLARE_FLAG(bool, allow_absolute_addresses);
 DEFINE_FLAG(bool, print_stop_message, false, "Print stop message.");
 DECLARE_FLAG(bool, inline_alloc);
 
@@ -519,6 +520,7 @@
   if (object.IsSmi()) {
     LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw()));
   } else if (object.InVMHeap() || !constant_pool_allowed()) {
+    ASSERT(FLAG_allow_absolute_addresses);
     // Make sure that class CallPattern is able to decode this load immediate.
     int32_t object_raw = reinterpret_cast<int32_t>(object.raw());
     const uint16_t object_low = Utils::Low16Bits(object_raw);
@@ -555,6 +557,15 @@
 }
 
 
+void Assembler::LoadNativeEntry(Register rd,
+                                const ExternalLabel* label,
+                                Patchability patchable) {
+  const int32_t offset = ObjectPool::element_offset(
+      object_pool_wrapper_.FindNativeEntry(label, patchable));
+  LoadWordFromPoolOffset(rd, offset - kHeapObjectTag);
+}
+
+
 void Assembler::PushObject(const Object& object) {
   ASSERT(!in_delay_slot_);
   LoadObject(TMP, object);
@@ -738,15 +749,14 @@
 
 
 void Assembler::LoadClassIdMayBeSmi(Register result, Register object) {
-  static const intptr_t kSmiCidSource = kSmiCid << RawObject::kClassIdTagPos;
-
-  LoadImmediate(TMP, reinterpret_cast<int32_t>(&kSmiCidSource) + 1);
+  Label heap_object, done;
   andi(CMPRES1, object, Immediate(kSmiTagMask));
-  if (result != object) {
-    mov(result, object);
-  }
-  movz(result, TMP, CMPRES1);
-  LoadClassId(result, result);
+  bne(CMPRES1, ZR, &heap_object);
+  LoadImmediate(result, kSmiCid);
+  b(&done);
+  Bind(&heap_object);
+  LoadClassId(result, object);
+  Bind(&done);
 }
 
 
@@ -859,6 +869,7 @@
   intptr_t counter_offset =
       ClassTable::CounterOffsetFor(cid, space == Heap::kNew);
   if (inline_isolate) {
+    ASSERT(FLAG_allow_absolute_addresses);
     ClassTable* class_table = Isolate::Current()->class_table();
     ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
     if (cid < kNumPredefinedCids) {
@@ -937,6 +948,7 @@
   ASSERT(temp_reg != TMP);
   intptr_t state_offset = ClassTable::StateOffsetFor(cid);
   if (inline_isolate) {
+    ASSERT(FLAG_allow_absolute_addresses);
     ClassTable* class_table = Isolate::Current()->class_table();
     ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
     if (cid < kNumPredefinedCids) {
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index c9b4025..2ae9456 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -1524,6 +1524,9 @@
   void LoadExternalLabel(Register rd,
                          const ExternalLabel* label,
                          Patchability patchable);
+  void LoadNativeEntry(Register rd,
+                       const ExternalLabel* label,
+                       Patchability patchable);
   void PushObject(const Object& object);
 
   void LoadIsolate(Register result);
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index fcab5ea..523f29f 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -17,6 +17,7 @@
 
 namespace dart {
 
+DECLARE_FLAG(bool, allow_absolute_addresses);
 DEFINE_FLAG(bool, print_stop_message, true, "Print stop message.");
 DECLARE_FLAG(bool, inline_alloc);
 
@@ -70,6 +71,15 @@
 }
 
 
+void Assembler::LoadNativeEntry(Register dst,
+                                const ExternalLabel* label,
+                                Patchability patchable) {
+  const int32_t offset = ObjectPool::element_offset(
+      object_pool_wrapper_.FindNativeEntry(label, patchable));
+  LoadWordFromPoolOffset(dst, offset - kHeapObjectTag);
+}
+
+
 void Assembler::call(const ExternalLabel* label) {
   {  // Encode movq(TMP, Immediate(label->address())), but always as imm64.
     AssemblerBuffer::EnsureCapacity ensured(&buffer_);
@@ -2818,6 +2828,7 @@
     LoadWordFromPoolOffset(dst, offset - kHeapObjectTag);
   } else {
     ASSERT(object.IsSmi() || object.InVMHeap());
+    ASSERT(object.IsSmi() || FLAG_allow_absolute_addresses);
     LoadImmediate(dst, Immediate(reinterpret_cast<int64_t>(object.raw())));
   }
 }
@@ -2852,6 +2863,7 @@
     LoadObject(TMP, object);
     movq(dst, TMP);
   } else {
+    ASSERT(object.IsSmi() || FLAG_allow_absolute_addresses);
     MoveImmediate(dst, Immediate(reinterpret_cast<int64_t>(object.raw())));
   }
 }
@@ -2864,6 +2876,7 @@
     LoadObject(TMP, object);
     pushq(TMP);
   } else {
+    ASSERT(object.IsSmi() || FLAG_allow_absolute_addresses);
     PushImmediate(Immediate(reinterpret_cast<int64_t>(object.raw())));
   }
 }
@@ -2877,6 +2890,7 @@
         ObjectPool::element_offset(object_pool_wrapper_.FindObject(object));
     cmpq(reg, Address(PP, offset-kHeapObjectTag));
   } else {
+    ASSERT(object.IsSmi() || FLAG_allow_absolute_addresses);
     CompareImmediate(
         reg, Immediate(reinterpret_cast<int64_t>(object.raw())));
   }
@@ -3026,7 +3040,8 @@
 #else
 #error Only supported in DEBUG mode
 #endif
-  cmpq(dest, Immediate(reinterpret_cast<uint64_t>(Object::null())));
+  LoadObject(TMP, Object::null_object());
+  cmpq(dest, TMP);
   j(EQUAL, &ok, Assembler::kNearJump);
   static const bool kFixedLengthEncoding = true;
   Stop("Expected zapped, Smi or null", kFixedLengthEncoding);
@@ -3444,6 +3459,7 @@
   intptr_t state_offset = ClassTable::StateOffsetFor(cid);
   Register temp_reg = TMP;
   if (inline_isolate) {
+    ASSERT(FLAG_allow_absolute_addresses);
     ClassTable* class_table = Isolate::Current()->class_table();
     ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
     if (cid < kNumPredefinedCids) {
@@ -3474,6 +3490,7 @@
       ClassTable::CounterOffsetFor(cid, space == Heap::kNew);
   Register temp_reg = TMP;
   if (inline_isolate) {
+    ASSERT(FLAG_allow_absolute_addresses);
     ClassTable* class_table = Isolate::Current()->class_table();
     ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
     if (cid < kNumPredefinedCids) {
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index 5cb3c17..a6d64db0 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -763,6 +763,9 @@
   void LoadExternalLabel(Register dst,
                          const ExternalLabel* label,
                          Patchability patchable);
+  void LoadNativeEntry(Register dst,
+                       const ExternalLabel* label,
+                       Patchability patchable);
   void LoadFunctionFromCalleePool(Register dst,
                                   const Function& function,
                                   Register new_pp);
diff --git a/runtime/vm/ast_printer.cc b/runtime/vm/ast_printer.cc
index aa5c29f..7cc69d4 100644
--- a/runtime/vm/ast_printer.cc
+++ b/runtime/vm/ast_printer.cc
@@ -19,38 +19,38 @@
 
 
 void AstPrinter::VisitGenericAstNode(AstNode* node) {
-  ISL_Print("(%s ", node->PrettyName());
+  THR_Print("(%s ", node->PrettyName());
   node->VisitChildren(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
 void AstPrinter::VisitSequenceNode(SequenceNode* node) {
   indent_++;
   LocalScope* scope = node->scope();
-  ISL_Print("(%s (scope \"%p\"", node->PrettyName(), scope);
+  THR_Print("(%s (scope \"%p\"", node->PrettyName(), scope);
   if (scope != NULL) {
-    ISL_Print(" (%" Pd "-%" Pd ") loop %d",
+    THR_Print(" (%" Pd "-%" Pd ") loop %d",
               scope->begin_token_pos(),
               scope->end_token_pos(),
               scope->loop_level());
     if (scope->HasContextLevel()) {
-      ISL_Print(" context %d captures %d",
+      THR_Print(" context %d captures %d",
                 scope->context_level(),
                 scope->num_context_variables());
     } else {
       ASSERT(scope->num_context_variables() == 0);
     }
   }
-  ISL_Print(")");
+  THR_Print(")");
   for (int i = 0; i < node->length(); ++i) {
-    ISL_Print("\n");
+    THR_Print("\n");
     for (intptr_t p = 0; p < indent_; p++) {
-      ISL_Print("  ");
+      THR_Print("  ");
     }
     node->NodeAt(i)->Visit(this);
   }
-  ISL_Print(")");
+  THR_Print(")");
   indent_--;
 }
 
@@ -81,29 +81,29 @@
       kind = "";
       UNREACHABLE();
   }
-  ISL_Print("(%s %s", node->PrettyName(), kind);
+  THR_Print("(%s %s", node->PrettyName(), kind);
   node->VisitChildren(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
 void AstPrinter::VisitGenericLocalNode(AstNode* node,
                                        const LocalVariable& var) {
-  ISL_Print("(%s %s%s \"%s\"",
+  THR_Print("(%s %s%s \"%s\"",
             node->PrettyName(),
             var.is_final() ? "final " : "",
             String::Handle(var.type().Name()).ToCString(),
             var.name().ToCString());
   if (var.HasIndex()) {
     if (var.is_captured()) {
-      ISL_Print(" (context %d %d)", var.owner()->context_level(), var.index());
+      THR_Print(" (context %d %d)", var.owner()->context_level(), var.index());
     } else {
-      ISL_Print(" (stack %d)", var.index());
+      THR_Print(" (stack %d)", var.index());
     }
   }
-  ISL_Print(" ");
+  THR_Print(" ");
   node->VisitChildren(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
@@ -118,14 +118,14 @@
 
 
 void AstPrinter::VisitGenericFieldNode(AstNode* node, const Field& field) {
-  ISL_Print("(%s %s%s \"%s\" ",
+  THR_Print("(%s %s%s \"%s\" ",
             node->PrettyName(),
             field.is_final() ? "final " : "",
             String::Handle(AbstractType::Handle(field.type()).Name()).
                 ToCString(),
             String::Handle(field.name()).ToCString());
   node->VisitChildren(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
@@ -166,13 +166,13 @@
 
 void AstPrinter::VisitLiteralNode(LiteralNode* node) {
   const Instance& literal = node->literal();
-  ISL_Print("(%s \"%s\")", node->PrettyName(), literal.ToCString());
+  THR_Print("(%s \"%s\")", node->PrettyName(), literal.ToCString());
 }
 
 
 void AstPrinter::VisitTypeNode(TypeNode* node) {
   const AbstractType& type = node->type();
-  ISL_Print("(%s \"%s\")",
+  THR_Print("(%s \"%s\")",
             node->PrettyName(),
             String::Handle(type.Name()).ToCString());
 }
@@ -181,24 +181,24 @@
 void AstPrinter::VisitAssignableNode(AssignableNode* node) {
   const AbstractType& type = node->type();
   const String& dst_name = node->dst_name();
-  ISL_Print("(%s (type \"%s\") (of \"%s\") ",
+  THR_Print("(%s (type \"%s\") (of \"%s\") ",
             node->PrettyName(),
             String::Handle(type.Name()).ToCString(),
             dst_name.ToCString());
   node->VisitChildren(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
 void AstPrinter::VisitAwaitNode(AwaitNode* node) {
-  ISL_Print("(*****%s***** (scope \"%p\") ", node->PrettyName(), node->scope());
+  THR_Print("(*****%s***** (scope \"%p\") ", node->PrettyName(), node->scope());
   node->VisitChildren(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
 void AstPrinter::VisitAwaitMarkerNode(AwaitMarkerNode* node) {
-  ISL_Print("(%s (async_scope \"%p\" await_scope \"%p\"))",
+  THR_Print("(%s (async_scope \"%p\" await_scope \"%p\"))",
             node->PrettyName(),
             node->async_scope(),
             node->await_scope());
@@ -206,38 +206,38 @@
 
 
 void AstPrinter::VisitPrimaryNode(PrimaryNode* node) {
-  ISL_Print("(*****%s***** \"%s\")",
+  THR_Print("(*****%s***** \"%s\")",
             node->PrettyName(),
             node->primary().ToCString());
 }
 
 
 void AstPrinter::VisitComparisonNode(ComparisonNode* node) {
-  ISL_Print("(%s %s ", node->PrettyName(), node->TokenName());
+  THR_Print("(%s %s ", node->PrettyName(), node->TokenName());
   node->VisitChildren(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
 void AstPrinter::VisitBinaryOpNode(BinaryOpNode* node) {
-  ISL_Print("(%s %s ", node->PrettyName(), node->TokenName());
+  THR_Print("(%s %s ", node->PrettyName(), node->TokenName());
   node->VisitChildren(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
 void AstPrinter::VisitBinaryOpWithMask32Node(BinaryOpWithMask32Node* node) {
-  ISL_Print("(%s %s ", node->PrettyName(), node->TokenName());
+  THR_Print("(%s %s ", node->PrettyName(), node->TokenName());
   node->VisitChildren(this);
-  ISL_Print(" & \"0x%" Px64 "", node->mask32());
-  ISL_Print("\")");
+  THR_Print(" & \"0x%" Px64 "", node->mask32());
+  THR_Print("\")");
 }
 
 
 void AstPrinter::VisitUnaryOpNode(UnaryOpNode* node) {
-  ISL_Print("(%s %s ", node->PrettyName(), node->TokenName());
+  THR_Print("(%s %s ", node->PrettyName(), node->TokenName());
   node->VisitChildren(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
@@ -252,16 +252,16 @@
 
 
 void AstPrinter::VisitCaseNode(CaseNode* node) {
-  ISL_Print("(%s (", node->PrettyName());
+  THR_Print("(%s (", node->PrettyName());
   for (int i = 0; i < node->case_expressions()->length(); i++) {
     node->case_expressions()->NodeAt(i)->Visit(this);
   }
   if (node->contains_default()) {
-    ISL_Print(" default");
+    THR_Print(" default");
   }
-  ISL_Print(")");
+  THR_Print(")");
   node->statements()->Visit(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
@@ -278,17 +278,17 @@
 void AstPrinter::VisitForNode(ForNode* node) {
   // Complicated because the condition is optional and so we clearly want to
   // indicate the subparts.
-  ISL_Print("(%s (init ", node->PrettyName());
+  THR_Print("(%s (init ", node->PrettyName());
   node->initializer()->Visit(this);
   if (node->condition() != NULL) {
-    ISL_Print(") (cond ");
+    THR_Print(") (cond ");
     node->condition()->Visit(this);
   }
-  ISL_Print(") (update ");
+  THR_Print(") (update ");
   node->increment()->Visit(this);
-  ISL_Print(") ");
+  THR_Print(") ");
   node->body()->Visit(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
@@ -298,7 +298,7 @@
 
 
 void AstPrinter::VisitJumpNode(JumpNode* node) {
-  ISL_Print("(%s %s %s (scope \"%p\"))",
+  THR_Print("(%s %s %s (scope \"%p\"))",
             node->PrettyName(),
             node->TokenName(),
             node->label()->name().ToCString(),
@@ -307,25 +307,25 @@
 
 
 void AstPrinter::VisitInstanceCallNode(InstanceCallNode* node) {
-  ISL_Print("(%s \"%s\" ",
+  THR_Print("(%s \"%s\" ",
             node->PrettyName(),
             node->function_name().ToCString());
   node->VisitChildren(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
 void AstPrinter::VisitStaticCallNode(StaticCallNode* node) {
   const char* function_fullname = node->function().ToFullyQualifiedCString();
-  ISL_Print("(%s \"%s\" ", node->PrettyName(), function_fullname);
+  THR_Print("(%s \"%s\" ", node->PrettyName(), function_fullname);
   node->VisitChildren(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
 void AstPrinter::VisitClosureNode(ClosureNode* node) {
   const char* function_fullname = node->function().ToFullyQualifiedCString();
-  ISL_Print("(%s \"%s\")", node->PrettyName(), function_fullname);
+  THR_Print("(%s \"%s\")", node->PrettyName(), function_fullname);
 }
 
 
@@ -337,39 +337,39 @@
 void AstPrinter::VisitConstructorCallNode(ConstructorCallNode* node) {
   const char* kind = node->constructor().IsFactory() ? "factory " : "";
   const char* constructor_name = node->constructor().ToFullyQualifiedCString();
-  ISL_Print("(%s %s \"%s\" ", node->PrettyName(), kind, constructor_name);
+  THR_Print("(%s %s \"%s\" ", node->PrettyName(), kind, constructor_name);
   node->VisitChildren(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
 void AstPrinter::VisitInstanceGetterNode(InstanceGetterNode* node) {
-  ISL_Print("(%s \"%s\" ",
+  THR_Print("(%s \"%s\" ",
             node->PrettyName(),
             node->field_name().ToCString());
   node->VisitChildren(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
 void AstPrinter::VisitInstanceSetterNode(InstanceSetterNode* node) {
-  ISL_Print("(%s \"%s\" ",
+  THR_Print("(%s \"%s\" ",
             node->PrettyName(),
             node->field_name().ToCString());
   node->VisitChildren(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
 void AstPrinter::VisitInitStaticFieldNode(InitStaticFieldNode* node) {
-  ISL_Print("(%s \"%s\")", node->PrettyName(),
+  THR_Print("(%s \"%s\")", node->PrettyName(),
             String::Handle(node->field().name()).ToCString());
 }
 
 
 void AstPrinter::VisitStaticGetterNode(StaticGetterNode* node) {
   String& class_name = String::Handle(node->cls().Name());
-  ISL_Print("(%s \"%s.%s\")",
+  THR_Print("(%s \"%s.%s\")",
             node->PrettyName(),
             class_name.ToCString(),
             node->field_name().ToCString());
@@ -378,31 +378,31 @@
 
 void AstPrinter::VisitStaticSetterNode(StaticSetterNode* node) {
   String& class_name = String::Handle(node->cls().Name());
-  ISL_Print("(%s \"%s.%s\" ",
+  THR_Print("(%s \"%s.%s\" ",
             node->PrettyName(),
             class_name.ToCString(),
             node->field_name().ToCString());
   node->VisitChildren(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
 void AstPrinter::VisitLoadIndexedNode(LoadIndexedNode* node) {
-  ISL_Print("(%s%s ", node->PrettyName(), node->IsSuperLoad() ? " super" : "");
+  THR_Print("(%s%s ", node->PrettyName(), node->IsSuperLoad() ? " super" : "");
   node->VisitChildren(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
 void AstPrinter::VisitStoreIndexedNode(StoreIndexedNode* node) {
-  ISL_Print("(%s%s ", node->PrettyName(), node->IsSuperStore() ? " super" : "");
+  THR_Print("(%s%s ", node->PrettyName(), node->IsSuperStore() ? " super" : "");
   node->VisitChildren(this);
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
 void AstPrinter::VisitNativeBodyNode(NativeBodyNode* node) {
-  ISL_Print("(%s \"%s\" (%" Pd " args))",
+  THR_Print("(%s \"%s\" (%" Pd " args))",
             node->PrettyName(),
             node->native_c_function_name().ToCString(),
             NativeArguments::ParameterCountForResolution(node->function()));
@@ -415,15 +415,15 @@
 
 
 void AstPrinter::VisitTryCatchNode(TryCatchNode* node) {
-  ISL_Print("(%s ", node->PrettyName());
+  THR_Print("(%s ", node->PrettyName());
   node->try_block()->Visit(this);
   node->catch_block()->Visit(this);
   if (node->finally_block() != NULL) {
-    ISL_Print("(finally ");
+    THR_Print("(finally ");
     node->finally_block()->Visit(this);
-    ISL_Print(")");
+    THR_Print(")");
   }
-  ISL_Print(")");
+  THR_Print(")");
 }
 
 
@@ -433,7 +433,7 @@
 
 
 void AstPrinter::VisitStopNode(StopNode* node) {
-  ISL_Print("(%s %s)", node->PrettyName(), node->message());
+  THR_Print("(%s %s)", node->PrettyName(), node->message());
 }
 
 
@@ -446,13 +446,13 @@
   ASSERT(node != NULL);
   AstPrinter ast_printer;
   node->Visit(&ast_printer);
-  ISL_Print("\n");
+  THR_Print("\n");
 }
 
 
 static void IndentN(int count) {
   for (int i = 0; i < count; i++) {
-    ISL_Print(" ");
+    THR_Print(" ");
   }
 }
 
@@ -463,22 +463,22 @@
   ASSERT(scope != NULL);
   ASSERT(var != NULL);
   IndentN(indent);
-  ISL_Print("(%s%s '%s'",
+  THR_Print("(%s%s '%s'",
             var->is_final() ? "final " : "",
             String::Handle(var->type().Name()).ToCString(),
             var->name().ToCString());
   if (var->owner() != scope) {
-    ISL_Print(" alias");
+    THR_Print(" alias");
   }
   if (var->HasIndex()) {
-    ISL_Print(" @%d", var->index());
+    THR_Print(" @%d", var->index());
     if (var->is_captured()) {
-      ISL_Print(" ctx %d", var->owner()->context_level());
+      THR_Print(" ctx %d", var->owner()->context_level());
     }
   } else if (var->owner()->function_level() != 0) {
-    ISL_Print(" lev %d", var->owner()->function_level());
+    THR_Print(" lev %d", var->owner()->function_level());
   }
-  ISL_Print(" valid %" Pd "-%" Pd ")\n",
+  THR_Print(" valid %" Pd "-%" Pd ")\n",
             var->token_pos(),
             scope->end_token_pos());
 }
@@ -495,16 +495,16 @@
   const LocalScope* child = scope->child();
   while (child != NULL) {
     IndentN(indent);
-    ISL_Print("{scope %p ", child);
+    THR_Print("{scope %p ", child);
     if (child->HasContextLevel()) {
-      ISL_Print("ctx %d numctxvar %d ",
+      THR_Print("ctx %d numctxvar %d ",
                 child->context_level(),
                 child->num_context_variables());
     }
-    ISL_Print("llev %d\n", child->loop_level());
+    THR_Print("llev %d\n", child->loop_level());
     PrintLocalScope(child, 0, indent + kScopeIndent);
     IndentN(indent);
-    ISL_Print("}\n");
+    THR_Print("}\n");
     child = child->sibling();
   }
 }
@@ -518,13 +518,13 @@
   const LocalScope* scope = node_sequence->scope();
   ASSERT(scope != NULL);
   const char* function_name = function.ToFullyQualifiedCString();
-  ISL_Print("Scope for function '%s'\n{scope %p ", function_name, scope);
+  THR_Print("Scope for function '%s'\n{scope %p ", function_name, scope);
   if (scope->HasContextLevel()) {
-    ISL_Print("ctx %d numctxvar %d ",
+    THR_Print("ctx %d numctxvar %d ",
               scope->context_level(),
               scope->num_context_variables());
   }
-  ISL_Print("llev %d\n", scope->loop_level());
+  THR_Print("llev %d\n", scope->loop_level());
   const int num_fixed_params = function.num_fixed_parameters();
   const int num_params = num_fixed_params + function.NumOptionalParameters();
   // Parameters must be listed first and must all appear in the top scope.
@@ -535,7 +535,7 @@
     LocalVariable* param = scope->VariableAt(pos);
     ASSERT(param->owner() == scope);  // No aliases should precede parameters.
     IndentN(indent);
-    ISL_Print("(param %s%s '%s'",
+    THR_Print("(param %s%s '%s'",
               param->is_final() ? "final " : "",
               String::Handle(param->type().Name()).ToCString(),
               param->name().ToCString());
@@ -543,22 +543,22 @@
     if (pos >= num_fixed_params && pos < num_params) {
       const Instance& default_parameter_value =
           parsed_function.DefaultParameterValueAt(pos - num_fixed_params);
-      ISL_Print(" =%s", default_parameter_value.ToCString());
+      THR_Print(" =%s", default_parameter_value.ToCString());
     }
     if (param->HasIndex()) {
-      ISL_Print(" @%d", param->index());
+      THR_Print(" @%d", param->index());
       if (param->is_captured()) {
-        ISL_Print(" ctx %d", param->owner()->context_level());
+        THR_Print(" ctx %d", param->owner()->context_level());
       }
     }
-    ISL_Print(" valid %" Pd "-%" Pd ")\n",
+    THR_Print(" valid %" Pd "-%" Pd ")\n",
               param->token_pos(),
               scope->end_token_pos());
     pos++;
   }
   // Visit remaining non-parameter variables and children scopes.
   PrintLocalScope(scope, pos, indent);
-  ISL_Print("}\n");
+  THR_Print("}\n");
 }
 
 
@@ -569,9 +569,9 @@
   AstPrinter ast_printer;
   const char* function_name =
       parsed_function.function().ToFullyQualifiedCString();
-  ISL_Print("Ast for function '%s' {\n", function_name);
+  THR_Print("Ast for function '%s' {\n", function_name);
   node_sequence->Visit(&ast_printer);
-  ISL_Print("}\n");
+  THR_Print("}\n");
 }
 
 }  // namespace dart
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index ee3ca57..36dfae2 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -354,12 +354,8 @@
   char* script = NULL;
   if (dart_root != NULL) {
     HANDLESCOPE(thread);
-    const char* kFormatStr =
-        "import '%s/pkg/compiler/lib/compiler.dart';";
-    intptr_t len = OS::SNPrint(NULL, 0, kFormatStr, dart_root) + 1;
-    script = reinterpret_cast<char*>(malloc(len));
-    EXPECT(script != NULL);
-    OS::SNPrint(script, len, kFormatStr, dart_root);
+    script = OS::SCreate(NULL,
+        "import '%s/pkg/compiler/lib/compiler.dart';", dart_root);
     Dart_Handle lib = TestCase::LoadTestScript(
         script,
         reinterpret_cast<Dart_NativeEntryResolver>(NativeResolver));
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 494a42d..83df7a9 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -338,7 +338,7 @@
 
   // Target is not resolved yet.
   if (FLAG_trace_class_finalization) {
-    ISL_Print("Resolving redirecting factory: %s\n",
+    THR_Print("Resolving redirecting factory: %s\n",
               String::Handle(factory.name()).ToCString());
   }
   type ^= FinalizeType(cls, type, kCanonicalize);
@@ -460,7 +460,7 @@
     return;
   }
   if (FLAG_trace_type_finalization) {
-    ISL_Print("Resolve type class of '%s'\n",
+    THR_Print("Resolve type class of '%s'\n",
               String::Handle(type.Name()).ToCString());
   }
 
@@ -499,7 +499,7 @@
   }
   ASSERT(type.IsType());
   if (FLAG_trace_type_finalization) {
-    ISL_Print("Resolve type '%s'\n", String::Handle(type.Name()).ToCString());
+    THR_Print("Resolve type '%s'\n", String::Handle(type.Name()).ToCString());
   }
   ResolveTypeClass(cls, type);
   if (type.IsMalformed()) {
@@ -526,7 +526,7 @@
     const Class& cls,
     PendingTypes* pending_types) {
   if (FLAG_trace_type_finalization) {
-    ISL_Print("Finalizing type parameters of '%s'\n",
+    THR_Print("Finalizing type parameters of '%s'\n",
               String::Handle(cls.Name()).ToCString());
   }
   if (cls.IsMixinApplication()) {
@@ -565,7 +565,7 @@
                                         PendingTypes* pending_types) {
   Isolate* isolate = Isolate::Current();
   if (FLAG_trace_type_finalization) {
-    ISL_Print("Checking recursive type '%s': %s\n",
+    THR_Print("Checking recursive type '%s': %s\n",
               String::Handle(type.Name()).ToCString(),
               type.ToCString());
   }
@@ -595,7 +595,7 @@
   for (intptr_t i = num_pending_types - 1; i >= 0; i--) {
     const Type& pending_type = Type::Cast(pending_types->At(i));
     if (FLAG_trace_type_finalization) {
-      ISL_Print("  Comparing with pending type '%s': %s\n",
+      THR_Print("  Comparing with pending type '%s': %s\n",
                 String::Handle(pending_type.Name()).ToCString(),
                 pending_type.ToCString());
     }
@@ -687,7 +687,7 @@
             ASSERT(super_type_arg.IsType());
             CheckRecursiveType(cls, Type::Cast(super_type_arg), pending_types);
             if (FLAG_trace_type_finalization) {
-              ISL_Print("Creating TypeRef '%s': '%s'\n",
+              THR_Print("Creating TypeRef '%s': '%s'\n",
                         String::Handle(super_type_arg.Name()).ToCString(),
                         super_type_arg.ToCString());
             }
@@ -708,7 +708,7 @@
           if (FLAG_trace_type_finalization && super_type_arg.IsTypeRef()) {
             AbstractType& ref_type = AbstractType::Handle(
                 TypeRef::Cast(super_type_arg).type());
-            ISL_Print("Instantiating TypeRef '%s': '%s'\n"
+            THR_Print("Instantiating TypeRef '%s': '%s'\n"
                       "  instantiator: '%s'\n",
                       String::Handle(super_type_arg.Name()).ToCString(),
                       ref_type.ToCString(),
@@ -895,7 +895,7 @@
                            "type '%s' has an out of bound type argument",
                            type_name.ToCString());
     if (FLAG_trace_type_finalization) {
-      ISL_Print("Marking type '%s' as malbounded: %s\n",
+      THR_Print("Marking type '%s' as malbounded: %s\n",
                 String::Handle(type.Name()).ToCString(),
                 bound_error.ToCString());
     }
@@ -940,7 +940,7 @@
 
   Zone* Z = Thread::Current()->zone();
   if (FLAG_trace_type_finalization) {
-    ISL_Print("Finalizing type '%s' for class '%s'\n",
+    THR_Print("Finalizing type '%s' for class '%s'\n",
               String::Handle(Z, type.Name()).ToCString(),
               cls.ToCString());
   }
@@ -967,7 +967,7 @@
     }
 
     if (FLAG_trace_type_finalization) {
-      ISL_Print("Done finalizing type parameter '%s' with index %" Pd "\n",
+      THR_Print("Done finalizing type parameter '%s' with index %" Pd "\n",
                 String::Handle(Z, type_parameter.name()).ToCString(),
                 type_parameter.index());
     }
@@ -1122,7 +1122,7 @@
     for (intptr_t i = pending_types->length() - 1; i >= 0; i--) {
       CheckTypeBounds(cls, Type::Cast(pending_types->At(i)));
       if (FLAG_trace_type_finalization && type.IsRecursive()) {
-        ISL_Print("Done finalizing recursive type '%s': %s\n",
+        THR_Print("Done finalizing recursive type '%s': %s\n",
                   String::Handle(Z, type.Name()).ToCString(),
                   type.ToCString());
       }
@@ -1141,7 +1141,7 @@
   }
 
   if (FLAG_trace_type_finalization) {
-    ISL_Print("Done finalizing type '%s' with %" Pd " type args: %s\n",
+    THR_Print("Done finalizing type '%s' with %" Pd " type args: %s\n",
               String::Handle(Z, parameterized_type.Name()).ToCString(),
               parameterized_type.arguments() == TypeArguments::null() ?
                   0 : num_type_arguments,
@@ -1152,7 +1152,7 @@
     if (FLAG_trace_type_finalization && parameterized_type.IsRecursive()) {
       AbstractType& type = Type::Handle(Z);
       type = parameterized_type.Canonicalize();
-      ISL_Print("Done canonicalizing recursive type '%s': %s\n",
+      THR_Print("Done canonicalizing recursive type '%s': %s\n",
                 String::Handle(Z, type.Name()).ToCString(),
                 type.ToCString());
       return type.raw();
@@ -1853,7 +1853,7 @@
     library.AddClass(inserted_class);
 
     if (FLAG_trace_class_finalization) {
-      ISL_Print("Creating mixin application alias %s\n",
+      THR_Print("Creating mixin application alias %s\n",
                 inserted_class.ToCString());
     }
 
@@ -1988,7 +1988,7 @@
   ASSERT(!mixin_app_class.is_type_finalized());
   ASSERT(!mixin_app_class.is_mixin_type_applied());
   if (FLAG_trace_class_finalization) {
-    ISL_Print("Inserting class '%s' %s\n"
+    THR_Print("Inserting class '%s' %s\n"
               "  as super type '%s' with %" Pd " type args: %s\n"
               "  of mixin application alias '%s' %s\n",
               String::Handle(inserted_class.Name()).ToCString(),
@@ -2015,7 +2015,7 @@
   const Class& mixin_class = Class::Handle(mixin_type.type_class());
 
   if (FLAG_trace_class_finalization) {
-    ISL_Print("Applying mixin type '%s' to %s at pos %" Pd "\n",
+    THR_Print("Applying mixin type '%s' to %s at pos %" Pd "\n",
               String::Handle(mixin_type.Name()).ToCString(),
               mixin_app_class.ToCString(),
               mixin_app_class.token_pos());
@@ -2058,7 +2058,7 @@
   ResolveSuperTypeAndInterfaces(mixin_app_class, &visited_interfaces);
 
   if (FLAG_trace_class_finalization) {
-    ISL_Print("Done applying mixin type '%s' to class '%s' %s extending '%s'\n",
+    THR_Print("Done applying mixin type '%s' to class '%s' %s extending '%s'\n",
               String::Handle(mixin_type.Name()).ToCString(),
               String::Handle(mixin_app_class.Name()).ToCString(),
               TypeArguments::Handle(
@@ -2103,7 +2103,7 @@
       clone_name = Symbols::FromConcat(mixin_name, clone_name);
 
       if (FLAG_trace_class_finalization) {
-        ISL_Print("Cloning constructor '%s' as '%s'\n",
+        THR_Print("Cloning constructor '%s' as '%s'\n",
                   ctor_name.ToCString(),
                   clone_name.ToCString());
       }
@@ -2158,7 +2158,7 @@
   // A default constructor will be created for the mixin app alias class.
 
   if (FLAG_trace_class_finalization) {
-    ISL_Print("Applying mixin members of %s to %s at pos %" Pd "\n",
+    THR_Print("Applying mixin members of %s to %s at pos %" Pd "\n",
               mixin_cls.ToCString(),
               cls.ToCString(),
               cls.token_pos());
@@ -2217,7 +2217,7 @@
   cls.AddFields(cloned_fields);
 
   if (FLAG_trace_class_finalization) {
-    ISL_Print("Done applying mixin members of %s to %s\n",
+    THR_Print("Done applying mixin members of %s to %s\n",
               mixin_cls.ToCString(),
               cls.ToCString());
   }
@@ -2231,7 +2231,7 @@
     return;
   }
   if (FLAG_trace_class_finalization) {
-    ISL_Print("Finalize types in %s\n", cls.ToCString());
+    THR_Print("Finalize types in %s\n", cls.ToCString());
   }
   if (!IsSuperCycleFree(cls)) {
     const String& name = String::Handle(cls.Name());
@@ -2365,7 +2365,7 @@
     return;
   }
   if (FLAG_trace_class_finalization) {
-    ISL_Print("Finalize %s\n", cls.ToCString());
+    THR_Print("Finalize %s\n", cls.ToCString());
   }
   if (cls.is_patch()) {
     // The fields and functions of a patch class are copied to the
@@ -2739,7 +2739,7 @@
       // processed via the super_type chain of a pending class.
 
       if (FLAG_trace_class_finalization) {
-        ISL_Print("Creating mixin application %s\n",
+        THR_Print("Creating mixin application %s\n",
                   mixin_app_class.ToCString());
       }
     }
@@ -2760,7 +2760,7 @@
     }
   }
   if (FLAG_trace_class_finalization) {
-    ISL_Print("ResolveMixinAppType: mixin appl type args: %s\n",
+    THR_Print("ResolveMixinAppType: mixin appl type args: %s\n",
               mixin_app_args.ToCString());
   }
   // The mixin application class at depth k is a subclass of mixin application
@@ -2787,7 +2787,7 @@
   }
   ASSERT(visited != NULL);
   if (FLAG_trace_class_finalization) {
-    ISL_Print("Resolving super and interfaces: %s\n", cls.ToCString());
+    THR_Print("Resolving super and interfaces: %s\n", cls.ToCString());
   }
   Isolate* isolate = Isolate::Current();
   const intptr_t cls_index = cls.id();
@@ -2994,46 +2994,46 @@
   Thread* thread = Thread::Current();
   HANDLESCOPE(thread);
   const String& class_name = String::Handle(cls.Name());
-  ISL_Print("class '%s'", class_name.ToCString());
+  THR_Print("class '%s'", class_name.ToCString());
   const Library& library = Library::Handle(cls.library());
   if (!library.IsNull()) {
-    ISL_Print(" library '%s%s':\n",
+    THR_Print(" library '%s%s':\n",
               String::Handle(library.url()).ToCString(),
               String::Handle(library.private_key()).ToCString());
   } else {
-    ISL_Print(" (null library):\n");
+    THR_Print(" (null library):\n");
   }
   const AbstractType& super_type = AbstractType::Handle(cls.super_type());
   if (super_type.IsNull()) {
-    ISL_Print("  Super: NULL");
+    THR_Print("  Super: NULL");
   } else {
     const String& super_name = String::Handle(super_type.Name());
-    ISL_Print("  Super: %s", super_name.ToCString());
+    THR_Print("  Super: %s", super_name.ToCString());
   }
   const Array& interfaces_array = Array::Handle(cls.interfaces());
   if (interfaces_array.Length() > 0) {
-    ISL_Print("; interfaces: ");
+    THR_Print("; interfaces: ");
     AbstractType& interface = AbstractType::Handle();
     intptr_t len = interfaces_array.Length();
     for (intptr_t i = 0; i < len; i++) {
       interface ^= interfaces_array.At(i);
-      ISL_Print("  %s ", interface.ToCString());
+      THR_Print("  %s ", interface.ToCString());
     }
   }
-  ISL_Print("\n");
+  THR_Print("\n");
   const Array& functions_array = Array::Handle(cls.functions());
   Function& function = Function::Handle();
   intptr_t len = functions_array.Length();
   for (intptr_t i = 0; i < len; i++) {
     function ^= functions_array.At(i);
-    ISL_Print("  %s\n", function.ToCString());
+    THR_Print("  %s\n", function.ToCString());
   }
   const Array& fields_array = Array::Handle(cls.fields());
   Field& field = Field::Handle();
   len = fields_array.Length();
   for (intptr_t i = 0; i < len; i++) {
     field ^= fields_array.At(i);
-    ISL_Print("  %s\n", field.ToCString());
+    THR_Print("  %s\n", field.ToCString());
   }
 }
 
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index daa15fd..53ee195 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -138,7 +138,7 @@
   args.SetAt(1, Integer::Handle(Integer::New(0)));
   args.SetAt(2, Integer::Handle(Integer::New(Array::kMaxElements)));
   args.SetAt(3, Symbols::Length());
-  Exceptions::ThrowByType(Exceptions::kRangeRange, args);
+  Exceptions::ThrowByType(Exceptions::kRange, args);
 }
 
 
@@ -1012,7 +1012,7 @@
   const Array& descriptor = Array::CheckedHandle(arguments.ArgAt(2));
   const String& name = String::Handle(ic_data.target_name());
   const MegamorphicCache& cache = MegamorphicCache::Handle(
-      isolate->megamorphic_cache_table()->Lookup(name, descriptor));
+      MegamorphicCacheTable::Lookup(isolate, name, descriptor));
   Class& cls = Class::Handle(receiver.clazz());
   ASSERT(!cls.IsNull());
   if (FLAG_trace_ic || FLAG_trace_ic_miss_in_optimized) {
@@ -1476,7 +1476,7 @@
     function.set_usage_counter(0);
     if (FLAG_trace_compiler) {
       if (function.HasOptimizedCode()) {
-        ISL_Print("ReCompiling function: '%s' \n",
+        THR_Print("ReCompiling function: '%s' \n",
                   function.ToFullyQualifiedCString());
       }
     }
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index b02e904..fe4fc64 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -192,7 +192,7 @@
     if (FLAG_trace_compiler) {
       const String& script_url = String::Handle(script.url());
       // TODO(iposva): Extract script kind.
-      ISL_Print("Compiling %s '%s'\n", "", script_url.ToCString());
+      THR_Print("Compiling %s '%s'\n", "", script_url.ToCString());
     }
     const String& library_key = String::Handle(library.private_key());
     script.Tokenize(library_key);
@@ -304,7 +304,7 @@
   LongJumpScope jump;
   if (setjmp(*jump.Set()) == 0) {
     if (FLAG_trace_compiler) {
-      ISL_Print("Compiling Class %s '%s'\n", "", cls.ToCString());
+      THR_Print("Compiling Class %s '%s'\n", "", cls.ToCString());
     }
 
     // Add the primary class which needs to be parsed to the parse list.
@@ -427,7 +427,7 @@
           if (FLAG_print_ic_data_map) {
             for (intptr_t i = 0; i < ic_data_array->length(); i++) {
               if ((*ic_data_array)[i] != NULL) {
-                ISL_Print("%" Pd " ", i);
+                THR_Print("%" Pd " ", i);
                 FlowGraphPrinter::PrintICData(*(*ic_data_array)[i]);
               }
             }
@@ -761,9 +761,9 @@
             CodePatcher::PatchEntry(Code::Handle(function.CurrentCode()));
             if (FLAG_trace_compiler || FLAG_trace_patching) {
               if (FLAG_trace_compiler) {
-                ISL_Print("  ");
+                THR_Print("  ");
               }
-              ISL_Print("Patch unoptimized '%s' entry point %#" Px "\n",
+              THR_Print("Patch unoptimized '%s' entry point %#" Px "\n",
                   function.ToFullyQualifiedCString(),
                   Code::Handle(function.unoptimized_code()).EntryPoint());
             }
@@ -822,7 +822,7 @@
         // try again (done = true), and indicate that we did not finish
         // compiling (is_compiled = false).
         if (FLAG_trace_bailout) {
-          ISL_Print("%s\n", error.ToErrorCString());
+          THR_Print("%s\n", error.ToErrorCString());
         }
         done = true;
         ASSERT(optimized);
@@ -844,35 +844,35 @@
 
 static void DisassembleCode(const Function& function, bool optimized) {
   const char* function_fullname = function.ToFullyQualifiedCString();
-  ISL_Print("Code for %sfunction '%s' {\n",
+  THR_Print("Code for %sfunction '%s' {\n",
             optimized ? "optimized " : "",
             function_fullname);
   const Code& code = Code::Handle(function.CurrentCode());
   code.Disassemble();
-  ISL_Print("}\n");
+  THR_Print("}\n");
 
-  ISL_Print("Pointer offsets for function: {\n");
+  THR_Print("Pointer offsets for function: {\n");
   // Pointer offsets are stored in descending order.
   Object& obj = Object::Handle();
   for (intptr_t i = code.pointer_offsets_length() - 1; i >= 0; i--) {
     const uword addr = code.GetPointerOffsetAt(i) + code.EntryPoint();
     obj = *reinterpret_cast<RawObject**>(addr);
-    ISL_Print(" %d : %#" Px " '%s'\n",
+    THR_Print(" %d : %#" Px " '%s'\n",
               code.GetPointerOffsetAt(i), addr, obj.ToCString());
   }
-  ISL_Print("}\n");
+  THR_Print("}\n");
 
-  ISL_Print("PC Descriptors for function '%s' {\n", function_fullname);
+  THR_Print("PC Descriptors for function '%s' {\n", function_fullname);
   PcDescriptors::PrintHeaderString();
   const PcDescriptors& descriptors =
       PcDescriptors::Handle(code.pc_descriptors());
-  ISL_Print("%s}\n", descriptors.ToCString());
+  THR_Print("%s}\n", descriptors.ToCString());
 
   uword start = Instructions::Handle(code.instructions()).EntryPoint();
   const Array& deopt_table = Array::Handle(code.deopt_info_array());
   intptr_t deopt_table_length = DeoptTable::GetLength(deopt_table);
   if (deopt_table_length > 0) {
-    ISL_Print("DeoptInfo: {\n");
+    THR_Print("DeoptInfo: {\n");
     Smi& offset = Smi::Handle();
     TypedData& info = TypedData::Handle();
     Smi& reason_and_flags = Smi::Handle();
@@ -881,31 +881,31 @@
       const intptr_t reason =
           DeoptTable::ReasonField::decode(reason_and_flags.Value());
       ASSERT((0 <= reason) && (reason < ICData::kDeoptNumReasons));
-      ISL_Print("%4" Pd ": 0x%" Px "  %s  (%s)\n",
+      THR_Print("%4" Pd ": 0x%" Px "  %s  (%s)\n",
                 i,
                 start + offset.Value(),
                 DeoptInfo::ToCString(deopt_table, info),
                 DeoptReasonToCString(
                     static_cast<ICData::DeoptReasonId>(reason)));
     }
-    ISL_Print("}\n");
+    THR_Print("}\n");
   }
 
   const ObjectPool& object_pool = ObjectPool::Handle(code.GetObjectPool());
   object_pool.DebugPrint();
 
-  ISL_Print("Stackmaps for function '%s' {\n", function_fullname);
+  THR_Print("Stackmaps for function '%s' {\n", function_fullname);
   if (code.stackmaps() != Array::null()) {
     const Array& stackmap_table = Array::Handle(code.stackmaps());
     Stackmap& map = Stackmap::Handle();
     for (intptr_t i = 0; i < stackmap_table.Length(); ++i) {
       map ^= stackmap_table.At(i);
-      ISL_Print("%s\n", map.ToCString());
+      THR_Print("%s\n", map.ToCString());
     }
   }
-  ISL_Print("}\n");
+  THR_Print("}\n");
 
-  ISL_Print("Variable Descriptors for function '%s' {\n",
+  THR_Print("Variable Descriptors for function '%s' {\n",
             function_fullname);
   const LocalVarDescriptors& var_descriptors =
       LocalVarDescriptors::Handle(code.GetLocalVarDescriptors());
@@ -918,34 +918,34 @@
     var_descriptors.GetInfo(i, &var_info);
     const int8_t kind = var_info.kind();
     if (kind == RawLocalVarDescriptors::kSavedCurrentContext) {
-      ISL_Print("  saved current CTX reg offset %d\n", var_info.index());
+      THR_Print("  saved current CTX reg offset %d\n", var_info.index());
     } else {
       if (kind == RawLocalVarDescriptors::kContextLevel) {
-        ISL_Print("  context level %d scope %d", var_info.index(),
+        THR_Print("  context level %d scope %d", var_info.index(),
             var_info.scope_id);
       } else if (kind == RawLocalVarDescriptors::kStackVar) {
-        ISL_Print("  stack var '%s' offset %d",
+        THR_Print("  stack var '%s' offset %d",
           var_name.ToCString(), var_info.index());
       } else if (kind == RawLocalVarDescriptors::kContextVar) {
-        ISL_Print("  context var '%s' level %d offset %d",
+        THR_Print("  context var '%s' level %d offset %d",
             var_name.ToCString(), var_info.scope_id, var_info.index());
       } else {
         ASSERT(kind == RawLocalVarDescriptors::kAsyncOperation);
-        ISL_Print("  async operation '%s' level %d offset %d",
+        THR_Print("  async operation '%s' level %d offset %d",
             var_name.ToCString(), var_info.scope_id, var_info.index());
       }
-      ISL_Print(" (valid %d-%d)\n", var_info.begin_pos, var_info.end_pos);
+      THR_Print(" (valid %d-%d)\n", var_info.begin_pos, var_info.end_pos);
     }
   }
-  ISL_Print("}\n");
+  THR_Print("}\n");
 
-  ISL_Print("Exception Handlers for function '%s' {\n", function_fullname);
+  THR_Print("Exception Handlers for function '%s' {\n", function_fullname);
   const ExceptionHandlers& handlers =
         ExceptionHandlers::Handle(code.exception_handlers());
-  ISL_Print("%s}\n", handlers.ToCString());
+  THR_Print("%s}\n", handlers.ToCString());
 
   {
-    ISL_Print("Static call target functions {\n");
+    THR_Print("Static call target functions {\n");
     const Array& table = Array::Handle(code.static_calls_target_table());
     Smi& offset = Smi::Handle();
     Function& function = Function::Handle();
@@ -960,24 +960,24 @@
         cls ^= code.owner();
         if (cls.IsNull()) {
           const String& code_name = String::Handle(code.Name());
-          ISL_Print("  0x%" Px ": %s, %p\n",
+          THR_Print("  0x%" Px ": %s, %p\n",
               start + offset.Value(),
               code_name.ToCString(),
               code.raw());
         } else {
-          ISL_Print("  0x%" Px ": allocation stub for %s, %p\n",
+          THR_Print("  0x%" Px ": allocation stub for %s, %p\n",
               start + offset.Value(),
               cls.ToCString(),
               code.raw());
         }
       } else {
-        ISL_Print("  0x%" Px ": %s, %p\n",
+        THR_Print("  0x%" Px ": %s, %p\n",
             start + offset.Value(),
             function.ToFullyQualifiedCString(),
             code.raw());
       }
     }
-    ISL_Print("}\n");
+    THR_Print("}\n");
   }
   if (optimized && FLAG_trace_inlining_intervals) {
     code.DumpInlinedIntervals();
@@ -1039,7 +1039,7 @@
     ParsedFunction* parsed_function = new(zone) ParsedFunction(
         thread, Function::ZoneHandle(zone, function.raw()));
     if (FLAG_trace_compiler) {
-      ISL_Print("Compiling %s%sfunction: '%s' @ token %" Pd ", size %" Pd "\n",
+      THR_Print("Compiling %s%sfunction: '%s' @ token %" Pd ", size %" Pd "\n",
                 (osr_id == Isolate::kNoDeoptId ? "" : "osr "),
                 (optimized ? "optimized " : ""),
                 function.ToFullyQualifiedCString(),
@@ -1069,10 +1069,10 @@
         ASSERT(!Compiler::always_optimize());  // Optimized is the only code.
         // Optimizer bailed out. Disable optimizations and never try again.
         if (FLAG_trace_compiler) {
-          ISL_Print("--> disabling optimizations for '%s'\n",
+          THR_Print("--> disabling optimizations for '%s'\n",
                     function.ToFullyQualifiedCString());
         } else if (FLAG_trace_failed_optimization_attempts) {
-          ISL_Print("Cannot optimize: %s\n",
+          THR_Print("Cannot optimize: %s\n",
                     function.ToFullyQualifiedCString());
         }
         function.SetIsOptimizable(false);
@@ -1084,7 +1084,7 @@
     per_compile_timer.Stop();
 
     if (FLAG_trace_compiler) {
-      ISL_Print("--> '%s' entry: %#" Px " size: %" Pd " time: %" Pd64 " us\n",
+      THR_Print("--> '%s' entry: %#" Px " size: %" Pd " time: %" Pd64 " us\n",
                 function.ToFullyQualifiedCString(),
                 Code::Handle(function.CurrentCode()).EntryPoint(),
                 Code::Handle(function.CurrentCode()).Size(),
@@ -1099,9 +1099,9 @@
                optimized &&
                FlowGraphPrinter::ShouldPrint(function)) {
       // TODO(fschneider): Print unoptimized code along with the optimized code.
-      ISL_Print("*** BEGIN CODE\n");
+      THR_Print("*** BEGIN CODE\n");
       DisassembleCode(function, true);
-      ISL_Print("*** END CODE\n");
+      THR_Print("*** END CODE\n");
     }
 #if defined(DEBUG)
     CheckInliningIntervals(function);
@@ -1170,7 +1170,7 @@
   }
   ASSERT(function.unoptimized_code() != Object::null());
   if (FLAG_trace_compiler) {
-    ISL_Print("Ensure unoptimized code for %s\n", function.ToCString());
+    THR_Print("Ensure unoptimized code for %s\n", function.ToCString());
   }
   return Error::null();
 }
@@ -1288,13 +1288,12 @@
 
 void Compiler::CompileStaticInitializer(const Field& field) {
   ASSERT(field.is_static());
-  if (field.PrecompiledInitializer() != Function::null()) {
+  if (field.HasPrecompiledInitializer()) {
     // TODO(rmacnak): Investigate why this happens for _enum_names.
     OS::Print("Warning: Ignoring repeated request for initializer for %s\n",
               field.ToCString());
     return;
   }
-  ASSERT(field.PrecompiledInitializer() == Function::null());
   Thread* thread = Thread::Current();
   StackZone zone(thread);
 
@@ -1339,6 +1338,8 @@
                                   false,  // optimized
                                   Isolate::kNoDeoptId);
       initializer = parsed_function->function().raw();
+      Code::Handle(initializer.unoptimized_code()).set_var_descriptors(
+          Object::empty_var_descriptors());
     } else {
       initializer ^= field.PrecompiledInitializer();
     }
@@ -1364,7 +1365,7 @@
   if (setjmp(*jump.Set()) == 0) {
     Thread* const thread = Thread::Current();
     if (FLAG_trace_compiler) {
-      ISL_Print("compiling expression: ");
+      THR_Print("compiling expression: ");
       AstPrinter::PrintNode(fragment);
     }
 
@@ -1406,6 +1407,8 @@
                                 parsed_function,
                                 false,
                                 Isolate::kNoDeoptId);
+    Code::Handle(func.unoptimized_code()).set_var_descriptors(
+        Object::empty_var_descriptors());
 
     const Object& result = PassiveObject::Handle(
         DartEntry::InvokeFunction(func, Object::empty_array()));
diff --git a/runtime/vm/compiler_stats.cc b/runtime/vm/compiler_stats.cc
index e04c0c0..86da700 100644
--- a/runtime/vm/compiler_stats.cc
+++ b/runtime/vm/compiler_stats.cc
@@ -124,7 +124,7 @@
   Dart::vm_isolate()->heap()->IterateObjects(&visitor);
 
   Log log(PrintToStats);
-  LogBlock lb(isolate_, &log);
+  LogBlock lb(Thread::Current(), &log);
 
   log.Print("==== Compiler Stats for isolate '%s' ====\n",
             isolate_->debugger_name());
diff --git a/runtime/vm/coverage.cc b/runtime/vm/coverage.cc
index d18ce19..82e7b54 100644
--- a/runtime/vm/coverage.cc
+++ b/runtime/vm/coverage.cc
@@ -247,13 +247,10 @@
   JSONStream stream;
   PrintJSON(isolate, &stream, NULL, false);
 
-  const char* format = "%s/dart-cov-%" Pd "-%" Pd64 ".json";
   intptr_t pid = OS::ProcessId();
-  intptr_t len = OS::SNPrint(NULL, 0, format,
-                             FLAG_coverage_dir, pid, isolate->main_port());
-  char* filename = Thread::Current()->zone()->Alloc<char>(len + 1);
-  OS::SNPrint(filename, len + 1, format,
-              FLAG_coverage_dir, pid, isolate->main_port());
+  char* filename = OS::SCreate(Thread::Current()->zone(),
+      "%s/dart-cov-%" Pd "-%" Pd64 ".json",
+      FLAG_coverage_dir, pid, isolate->main_port());
   void* file = (*file_open)(filename, true);
   if (file == NULL) {
     OS::Print("Failed to write coverage file: %s\n", filename);
diff --git a/runtime/vm/cpuinfo_test.cc b/runtime/vm/cpuinfo_test.cc
index e717d28..860c407 100644
--- a/runtime/vm/cpuinfo_test.cc
+++ b/runtime/vm/cpuinfo_test.cc
@@ -10,10 +10,8 @@
 namespace dart {
 
 UNIT_TEST_CASE(GetCpuModelTest) {
-  CpuInfo::InitOnce();
   const char* cpumodel = CpuInfo::GetCpuModel();
   EXPECT_NE(strlen(cpumodel), 0UL);
-  CpuInfo::Cleanup();
 }
 
 }  // namespace dart
diff --git a/runtime/vm/custom_isolate_test.cc b/runtime/vm/custom_isolate_test.cc
index af30507..2cb2e00 100644
--- a/runtime/vm/custom_isolate_test.cc
+++ b/runtime/vm/custom_isolate_test.cc
@@ -59,6 +59,7 @@
     "     var replyTo = message[1];\n"
     "     echo('Received: $data');\n"
     "     replyTo.send(data + 1);\n"
+    "     mainPort.close();\n"
     "   };\n"
     "}\n"
     "\n"
@@ -179,6 +180,7 @@
   free(const_cast<char*>(main_));
   main_ = NULL;
 
+  Dart_SetMessageNotifyCallback(NULL);
   Dart_ExitScope();
   Dart_ExitIsolate();
 }
@@ -207,6 +209,7 @@
   if (!Dart_HasLivePorts()) {
     OS::Print("<< Shutting down isolate(%p)\n", isolate());
     event_queue->RemoveEventsForIsolate(isolate());
+    Dart_SetMessageNotifyCallback(NULL);
     Dart_ShutdownIsolate();
   } else {
     Dart_ExitScope();
@@ -350,6 +353,7 @@
   free(const_cast<char*>(saved_echo));
 
   delete event_queue;
+  event_queue = NULL;
 }
 
 }  // namespace dart
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index e59c411..89d9fc5 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -35,8 +35,10 @@
 
 DECLARE_FLAG(bool, print_class_table);
 DECLARE_FLAG(bool, trace_isolates);
+DECLARE_FLAG(bool, trace_time_all);
 DEFINE_FLAG(bool, keep_code, false,
             "Keep deoptimized code for profiling.");
+DEFINE_FLAG(bool, shutdown, true, "Do a clean shutdown of the VM");
 
 Isolate* Dart::vm_isolate_ = NULL;
 ThreadPool* Dart::thread_pool_ = NULL;
@@ -118,12 +120,14 @@
     ASSERT(vm_isolate_ == NULL);
     ASSERT(Flags::Initialized());
     const bool is_vm_isolate = true;
+    const bool precompiled = instructions_snapshot != NULL;
 
     // Setup default flags for the VM isolate.
     Isolate::Flags vm_flags;
     Dart_IsolateFlags api_flags;
     vm_flags.CopyTo(&api_flags);
     vm_isolate_ = Isolate::Init("vm-isolate", api_flags, is_vm_isolate);
+    vm_isolate_->set_compilation_allowed(!precompiled);
     // Verify assumptions about executing in the VM isolate.
     ASSERT(vm_isolate_ == Isolate::Current());
     ASSERT(vm_isolate_ == Thread::Current()->isolate());
@@ -135,10 +139,10 @@
     TargetCPUFeatures::InitOnce();
     Object::InitOnce(vm_isolate_);
     ArgumentsDescriptor::InitOnce();
-    StubCode::InitOnce();
-    Thread::InitOnceAfterObjectAndStubCode();
-    // Now that the needed stub has been generated, set the stack limit.
-    vm_isolate_->InitializeStackLimit();
+    // When precompiled the stub code is initialized from the snapshot.
+    if (!precompiled) {
+      StubCode::InitOnce();
+    }
     if (vm_isolate_snapshot != NULL) {
       const Snapshot* snapshot = Snapshot::SetupFromBuffer(vm_isolate_snapshot);
       if (snapshot == NULL) {
@@ -157,7 +161,7 @@
         OS::Print("Size of vm isolate snapshot = %" Pd "\n",
                   snapshot->length());
         vm_isolate_->heap()->PrintSizes();
-        vm_isolate_->megamorphic_cache_table()->PrintSizes();
+        MegamorphicCacheTable::PrintSizes(vm_isolate_);
         intptr_t size;
         intptr_t capacity;
         Symbols::GetStats(vm_isolate_, &size, &capacity);
@@ -167,6 +171,9 @@
     } else {
       Symbols::InitOnce(vm_isolate_);
     }
+    Thread::InitOnceAfterObjectAndStubCode();
+    // Now that the needed stub has been generated, set the stack limit.
+    vm_isolate_->InitializeStackLimit();
     Scanner::InitOnce();
 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
     // Dart VM requires at least SSE2.
@@ -195,38 +202,60 @@
 }
 
 
+// This waits until only the VM isolate remains in the list.
+void Dart::WaitForIsolateShutdown() {
+  ASSERT(!Isolate::creation_enabled_);
+  MonitorLocker ml(Isolate::isolates_list_monitor_);
+  while ((Isolate::isolates_list_head_ != NULL) &&
+         (Isolate::isolates_list_head_->next_ != NULL)) {
+    ml.Wait();
+  }
+  ASSERT(Isolate::isolates_list_head_ == Dart::vm_isolate());
+}
+
+
 const char* Dart::Cleanup() {
-  // Shutdown the service isolate before shutting down the thread pool.
-  ServiceIsolate::Shutdown();
-#if 0
-  // Ideally we should shutdown the VM isolate here, but the thread pool
-  // shutdown does not seem to ensure that all the threads have stopped
-  // execution before it terminates, this results in racing isolates.
+  ASSERT(Isolate::Current() == NULL);
   if (vm_isolate_ == NULL) {
     return "VM already terminated.";
   }
 
-  ASSERT(Isolate::Current() == NULL);
-
-  delete thread_pool_;
-  thread_pool_ = NULL;
-
-  // Set the VM isolate as current isolate.
-  Thread::EnsureInit();
-  Thread::EnterIsolate(vm_isolate_);
-
-  // There is a planned and known asymmetry here: We exit one scope for the VM
-  // isolate to account for the scope that was entered in Dart_InitOnce.
-  Dart_ExitScope();
-
-  ShutdownIsolate();
-  vm_isolate_ = NULL;
-
-  TargetCPUFeatures::Cleanup();
-  StoreBuffer::ShutDown();
-#endif
-
+  // Shut down profiling.
   Profiler::Shutdown();
+
+  if (FLAG_shutdown) {
+    // Disable the creation of new isolates.
+    Isolate::DisableIsolateCreation();
+
+    // Send the OOB Kill message to all remaining application isolates.
+    Isolate::KillAllIsolates();
+
+    // Shutdown the service isolate.
+    ServiceIsolate::Shutdown();
+
+    // Wait for all application isolates and the service isolate to shutdown
+    // before shutting down the thread pool.
+    WaitForIsolateShutdown();
+
+    // Shutdown the thread pool. On return, all thread pool threads have exited.
+    delete thread_pool_;
+    thread_pool_ = NULL;
+
+    // Set the VM isolate as current isolate.
+    Thread::EnsureInit();
+    Thread::EnterIsolate(vm_isolate_);
+
+    ShutdownIsolate();
+    vm_isolate_ = NULL;
+    ASSERT(Isolate::IsolateListLength() == 0);
+
+    TargetCPUFeatures::Cleanup();
+    StoreBuffer::ShutDown();
+  } else {
+    // Shutdown the service isolate.
+    ServiceIsolate::Shutdown();
+  }
+
   CodeObservers::DeleteAll();
   Timeline::Shutdown();
   Metric::Cleanup();
@@ -293,7 +322,7 @@
     }
     if (FLAG_trace_isolates) {
       I->heap()->PrintSizes();
-      I->megamorphic_cache_table()->PrintSizes();
+      MegamorphicCacheTable::PrintSizes(I);
     }
   } else {
     // Populate the isolate's symbol table with all symbols from the
@@ -310,7 +339,7 @@
     StubCode::Init(I);
   }
 
-  I->megamorphic_cache_table()->InitMissHandler();
+  MegamorphicCacheTable::InitMissHandler(I);
   if (snapshot_buffer == NULL) {
     if (!I->object_store()->PreallocateObjects()) {
       return I->object_store()->sticky_error();
diff --git a/runtime/vm/dart.h b/runtime/vm/dart.h
index e06ae4e..c0203cc 100644
--- a/runtime/vm/dart.h
+++ b/runtime/vm/dart.h
@@ -55,6 +55,8 @@
   static bool IsReadOnlyHandle(uword address);
 
  private:
+  static void WaitForIsolateShutdown();
+
   static Isolate* vm_isolate_;
   static ThreadPool* thread_pool_;
   static DebugInfo* pprof_symbol_generator_;
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index f3f1f52..5e1105a 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1254,7 +1254,7 @@
   return Version::String();
 }
 
-DART_EXPORT bool Dart_Initialize(
+DART_EXPORT char* Dart_Initialize(
     const uint8_t* vm_isolate_snapshot,
     const uint8_t* instructions_snapshot,
     Dart_IsolateCreateCallback create,
@@ -1272,21 +1272,19 @@
                                        file_open, file_read, file_write,
                                        file_close, entropy_source);
   if (err_msg != NULL) {
-    OS::PrintErr("Dart_Initialize: %s\n", err_msg);
-    return false;
+    return strdup(err_msg);
   }
-  return true;
+  return NULL;
 }
 
 
-DART_EXPORT bool Dart_Cleanup() {
+DART_EXPORT char* Dart_Cleanup() {
   CHECK_NO_ISOLATE(Isolate::Current());
   const char* err_msg = Dart::Cleanup();
   if (err_msg != NULL) {
-    OS::PrintErr("Dart_Cleanup: %s\n", err_msg);
-    return false;
+    return strdup(err_msg);
   }
-  return true;
+  return NULL;
 }
 
 
@@ -1357,6 +1355,10 @@
   }
   Isolate* I = Dart::CreateIsolate(isolate_name, *flags);
   free(isolate_name);
+  if (I == NULL) {
+    *error = strdup("Isolate creation failed");
+    return reinterpret_cast<Dart_Isolate>(NULL);
+  }
   {
     Thread* T = Thread::Current();
     StackZone zone(T);
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index f79106e..bf4ec2a 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -1107,13 +1107,22 @@
 
 
 TEST_CASE(MalformedStringToUTF8) {
+  // 1D11E = treble clef
+  // [0] should be high surrogate D834
+  // [1] should be low surrogate DD1E
+  // Strings are allowed to have individual or out of order surrogates, even
+  // if that doesn't make sense as renderable characters.
   const char* kScriptChars =
-      "String testMain() {"
+      "String lowSurrogate() {"
       "  return '\\u{1D11E}'[1];"
-      "}";
+      "}"
+      "String highSurrogate() {"
+      "  return '\\u{1D11E}'[0];"
+      "}"
+      "String reversed() => lowSurrogate() + highSurrogate();";
 
   Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
-  Dart_Handle str1 = Dart_Invoke(lib, NewString("testMain"), 0, NULL);
+  Dart_Handle str1 = Dart_Invoke(lib, NewString("lowSurrogate"), 0, NULL);
   EXPECT_VALID(str1);
 
   uint8_t* utf8_encoded = NULL;
@@ -1126,7 +1135,20 @@
   EXPECT_EQ(158, static_cast<intptr_t>(utf8_encoded[2]));
 
   Dart_Handle str2 = Dart_NewStringFromUTF8(utf8_encoded, utf8_length);
-  EXPECT(Dart_IsError(str2));  // Invalid UTF-8.
+  EXPECT_VALID(str2);  // Standalone low surrogate, but still valid
+
+  Dart_Handle reversed = Dart_Invoke(lib, NewString("reversed"), 0, NULL);
+  EXPECT_VALID(reversed);  // This is also allowed.
+  uint8_t* utf8_encoded_reversed = NULL;
+  intptr_t utf8_length_reversed = 0;
+  result = Dart_StringToUTF8(reversed,
+      &utf8_encoded_reversed, &utf8_length_reversed);
+  EXPECT_VALID(result);
+  EXPECT_EQ(6, utf8_length_reversed);
+  uint8_t expected[6] = {237, 180, 158, 237, 160, 180};
+  for (int i = 0; i < 6; i++) {
+    EXPECT_EQ(expected[i], utf8_encoded_reversed[i]);
+  }
 }
 
 
diff --git a/runtime/vm/dart_entry.h b/runtime/vm/dart_entry.h
index 92e8562..016f3ce 100644
--- a/runtime/vm/dart_entry.h
+++ b/runtime/vm/dart_entry.h
@@ -60,6 +60,10 @@
   // Initialize the preallocated fixed length arguments descriptors cache.
   static void InitOnce();
 
+  enum {
+    kCachedDescriptorCount = 32
+  };
+
  private:
   // Absolute indexes into the array.
   enum {
@@ -75,10 +79,6 @@
     kNamedEntrySize,
   };
 
-  enum {
-    kCachedDescriptorCount = 32
-  };
-
   static intptr_t LengthFor(intptr_t count) {
     // Add 1 for the terminating null.
     return kFirstNamedEntryIndex + (kNamedEntrySize * count) + 1;
@@ -91,8 +91,8 @@
   // A cache of VM heap allocated arguments descriptors.
   static RawArray* cached_args_descriptors_[kCachedDescriptorCount];
 
-  friend class FullSnapshotWriter;
-  friend class VmIsolateSnapshotReader;
+  friend class SnapshotReader;
+  friend class SnapshotWriter;
   DISALLOW_COPY_AND_ASSIGN(ArgumentsDescriptor);
 };
 
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 96966d9..e0dd4a9 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -65,7 +65,9 @@
 // Create an unresolved breakpoint in given token range and script.
 BreakpointLocation::BreakpointLocation(const Script& script,
                                        intptr_t token_pos,
-                                       intptr_t end_token_pos)
+                                       intptr_t end_token_pos,
+                                       intptr_t requested_line_number,
+                                       intptr_t requested_column_number)
     : script_(script.raw()),
       url_(script.url()),
       token_pos_(token_pos),
@@ -73,15 +75,19 @@
       is_resolved_(false),
       next_(NULL),
       conditions_(NULL),
+      requested_line_number_(requested_line_number),
+      requested_column_number_(requested_column_number),
       function_(Function::null()),
-      line_number_(-1) {
+      line_number_(-1),
+      column_number_(-1) {
   ASSERT(!script.IsNull());
   ASSERT(token_pos_ >= 0);
 }
 
 // Create a latent breakpoint at given url and line number.
 BreakpointLocation::BreakpointLocation(const String& url,
-                                       intptr_t line_number)
+                                       intptr_t requested_line_number,
+                                       intptr_t requested_column_number)
     : script_(Script::null()),
       url_(url.raw()),
       token_pos_(-1),
@@ -89,9 +95,12 @@
       is_resolved_(false),
       next_(NULL),
       conditions_(NULL),
+      requested_line_number_(requested_line_number),
+      requested_column_number_(requested_column_number),
       function_(Function::null()),
-      line_number_(line_number) {
-  ASSERT(line_number_ >= 0);
+      line_number_(-1),
+      column_number_(-1) {
+  ASSERT(requested_line_number_ >= 0);
 }
 
 
@@ -119,7 +128,6 @@
   function_ = func.raw();
   token_pos_ = token_pos;
   end_token_pos_ = token_pos;
-  line_number_ = -1;  // Recalculate lazily.
   is_resolved_ = true;
 }
 
@@ -129,7 +137,7 @@
 // in more than one library, e.g. the text location of mixin functions.
 void BreakpointLocation::GetCodeLocation(Library* lib,
                                          Script* script,
-                                         intptr_t* pos) {
+                                         intptr_t* pos) const {
   if (IsLatent()) {
     *lib = Library::null();
     *script = Script::null();
@@ -150,8 +158,7 @@
 
 
 intptr_t BreakpointLocation::LineNumber() {
-  // Latent breakpoints must have a requested line number >= 0.
-  ASSERT(!IsLatent() || line_number_ >= 0);
+  ASSERT(IsResolved());
   // Compute line number lazily since it causes scanning of the script.
   if (line_number_ < 0) {
     const Script& script = Script::Handle(this->script());
@@ -161,6 +168,17 @@
 }
 
 
+intptr_t BreakpointLocation::ColumnNumber() {
+  ASSERT(IsResolved());
+  // Compute column number lazily since it causes scanning of the script.
+  if (column_number_ < 0) {
+    const Script& script = Script::Handle(this->script());
+    script.GetTokenLocation(token_pos_, &line_number_, &column_number_);
+  }
+  return column_number_;
+}
+
+
 void Breakpoint::set_bpt_location(BreakpointLocation* new_bpt_location) {
   ASSERT(bpt_location_->IsLatent());  // Only reason to move.
   bpt_location_ = new_bpt_location;
@@ -186,20 +204,17 @@
 
 
 void Breakpoint::PrintJSON(JSONStream* stream) {
-  Isolate* isolate = Isolate::Current();
-
   JSONObject jsobj(stream);
   jsobj.AddProperty("type", "Breakpoint");
 
   jsobj.AddFixedServiceId("breakpoints/%" Pd "", id());
   jsobj.AddProperty("breakpointNumber", id());
   jsobj.AddProperty("resolved", bpt_location_->IsResolved());
-
-  Library& library = Library::Handle(isolate);
-  Script& script = Script::Handle(isolate);
-  intptr_t token_pos;
-  bpt_location_->GetCodeLocation(&library, &script, &token_pos);
-  jsobj.AddLocation(script, token_pos);
+  if (bpt_location_->IsResolved()) {
+    jsobj.AddLocation(bpt_location_);
+  } else {
+    jsobj.AddUnresolvedLocation(bpt_location_);
+  }
 }
 
 
@@ -403,18 +418,10 @@
   Class& func_class = Class::Handle(func.Owner());
   String& class_name = String::Handle(func_class.Name());
 
-  const char* kFormat = "%s%s%s";
-  intptr_t len = OS::SNPrint(NULL, 0, kFormat,
-      func_class.IsTopLevel() ? "" : class_name.ToCString(),
-      func_class.IsTopLevel() ? "" : ".",
-      func_name.ToCString());
-  len++;  // String terminator.
-  char* chars = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, kFormat,
-              func_class.IsTopLevel() ? "" : class_name.ToCString(),
+  return OS::SCreate(Thread::Current()->zone(),
+    "%s%s%s", func_class.IsTopLevel() ? "" : class_name.ToCString(),
               func_class.IsTopLevel() ? "" : ".",
               func_name.ToCString());
-  return chars;
 }
 
 
@@ -667,7 +674,6 @@
       return ctx_;
     }
   }
-  UNREACHABLE();
   return Context::ZoneHandle(Context::null());
 }
 
@@ -1602,13 +1608,66 @@
 }
 
 
-// Given a function and a token range, return the best fit
-// token position to set a breakpoint. The best fit is the safe point
-// in the line closest to the beginning of the token range, and within
-// that line, the safe point with the lowest compiled code address.
+// Returns the best fit token position for a breakpoint.
+//
+// Takes a range of tokens [requested_token_pos, last_token_pos] and
+// an optional column (requested_column).  The range of tokens usually
+// represents one line of the program text, but can represent a larger
+// range on recursive calls.
+//
+// The best fit is found in two passes.
+//
+// The first pass finds a candidate token which:
+//
+//   - is a safepoint,
+//   - has the lowest column number compatible with the requested column
+//     if a column has been specified,
+// and:
+//   - has the lowest token position number which satisfies the above.
+//
+// When we consider a column number, we look for the closed token
+// which intersects the desired column.  For example:
+//
+//          1         2         3
+// 12345678901234567890         0
+//
+//   var x = function(function(y));
+//              ^
+//
+// If we request a breakpoint at column 14, the lowest column number
+// compatible with that would for column 11 (beginning of the
+// 'function' token) in the example above.
+//
+// Once this candidate token from the first pass is found, we then
+// have a second pass which considers only those tokens on the same
+// line as the candidate token.
+//
+// The second pass finds a best fit token which:
+//
+//   - is a safepoint,
+//   - has the same column number as the candidate token (perhaps
+//     more than one token has the same column number),
+// and:
+//   - has the lowest code address in the generated code.
+//
+// We prefer the lowest compiled code address, because this tends to
+// select the first subexpression on a line.  For example in a line
+// with nested function calls f(g(x)), the call to g() will have a
+// lower compiled code address than the call to f().
+//
+// If no best fit token can be found, the search is expanded,
+// searching through the rest of the current function by calling this
+// function recursively.
+//
+// TODO(turnidge): Given that we usually call this function with a
+// token range restricted to a single line, this could be a one-pass
+// algorithm, which would be simpler.  I believe that it only needs
+// two passes to support the recursive try-the-whole-function case.
+// Rewrite this later, once there are more tests in place.
 intptr_t Debugger::ResolveBreakpointPos(const Function& func,
                                         intptr_t requested_token_pos,
-                                        intptr_t last_token_pos) {
+                                        intptr_t last_token_pos,
+                                        intptr_t requested_column) {
   ASSERT(func.HasCode());
   ASSERT(!func.HasOptimizedCode());
 
@@ -1619,6 +1678,7 @@
     last_token_pos = func.end_token_pos();
   }
 
+  Script& script = Script::Handle(func.script());
   Code& code = Code::Handle(func.unoptimized_code());
   ASSERT(!code.IsNull());
   PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
@@ -1626,22 +1686,47 @@
   // First pass: find the safe point which is closest to the beginning
   // of the given token range.
   intptr_t best_fit_pos = INT_MAX;
+  intptr_t best_column = INT_MAX;
   PcDescriptors::Iterator iter(desc, kSafepointKind);
   while (iter.MoveNext()) {
-    const intptr_t desc_token_pos = iter.TokenPos();
-    if ((desc_token_pos != Scanner::kNoSourcePos) &&
-        (desc_token_pos < best_fit_pos) &&
-        (desc_token_pos >= requested_token_pos) &&
-        (desc_token_pos <= last_token_pos)) {
-       best_fit_pos = desc_token_pos;
+    const intptr_t pos = iter.TokenPos();
+    if ((pos == Scanner::kNoSourcePos) ||
+        (pos < requested_token_pos) ||
+        (pos > last_token_pos)) {
+      // Token is not in the target range.
+      continue;
+    }
+
+    intptr_t token_start_column = -1;
+    if (requested_column >= 0) {
+      intptr_t ignored = -1;
+      intptr_t token_len = -1;
+      // TODO(turnidge): GetTokenLocation is a very expensive
+      // operation, and this code will blow up when we are setting
+      // column breakpoints on, for example, a large, single-line
+      // program.  Consider rewriting this code so that it only scans
+      // the program code once and caches the token positions and
+      // lengths.
+      script.GetTokenLocation(pos, &ignored, &token_start_column, &token_len);
+      intptr_t token_end_column = token_start_column + token_len - 1;
+      if ((token_end_column < requested_column) ||
+          (token_start_column > best_column)) {
+        // Prefer the token with the lowest column number compatible
+        // with the requested column.
+        continue;
+      }
+    }
+
+    // Prefer the lowest (first) token pos.
+    if (pos < best_fit_pos) {
+      best_fit_pos = pos;
+      best_column = token_start_column;
     }
   }
-  // Second pass (if we found a safe point in the first pass):
-  // For all token positions on the same line, select the one
-  // with the lowest compiled code address. E.g., in a line with
-  // the nested function calls f(g(x)), the call g() will have a lower
-  // compiled code address but is not the lowest token position in the
-  // line.
+
+  // Second pass (if we found a safe point in the first pass).  Find
+  // the token on the line which is at the best fit column (if column
+  // was specified) and has the lowest code address.
   if (best_fit_pos != INT_MAX) {
     const Script& script = Script::Handle(func.script());
     const TokenStream& tokens = TokenStream::Handle(script.tokens());
@@ -1651,9 +1736,26 @@
     PcDescriptors::Iterator iter(desc, kSafepointKind);
     while (iter.MoveNext()) {
       const intptr_t pos = iter.TokenPos();
-      if ((pos != Scanner::kNoSourcePos) &&
-          (begin_pos <= pos) && (pos <= end_of_line_pos) &&
-          (iter.PcOffset() < lowest_pc_offset)) {
+      if ((pos == Scanner::kNoSourcePos) ||
+          (pos < begin_pos) ||
+          (pos > end_of_line_pos)) {
+        // Token is not on same line as best fit.
+        continue;
+      }
+
+      if (requested_column >= 0) {
+        intptr_t ignored = -1;
+        intptr_t token_start_column = -1;
+        // We look for other tokens at the best column in case there
+        // is more than one token at the same column offset.
+        script.GetTokenLocation(pos, &ignored, &token_start_column);
+        if (token_start_column != best_column) {
+          continue;
+        }
+      }
+
+      // Prefer the lowest pc offset.
+      if (iter.PcOffset() < lowest_pc_offset) {
         lowest_pc_offset = iter.PcOffset();
         best_fit_pos = pos;
       }
@@ -1661,10 +1763,13 @@
     return best_fit_pos;
   }
 
-  // We didn't find a safe point in the given token range. Try and find
-  // a safe point in the remaining source code of the function.
+  // We didn't find a safe point in the given token range. Try and
+  // find a safe point in the remaining source code of the function.
+  // Since we have moved to the next line of the function, we no
+  // longer are requesting a specific column number.
   if (last_token_pos < func.end_token_pos()) {
-    return ResolveBreakpointPos(func, last_token_pos, func.end_token_pos());
+    return ResolveBreakpointPos(func, last_token_pos, func.end_token_pos(),
+                                -1 /* no column */);
   }
   return -1;
 }
@@ -1857,7 +1962,9 @@
 
 BreakpointLocation* Debugger::SetBreakpoint(const Script& script,
                                             intptr_t token_pos,
-                                            intptr_t last_token_pos) {
+                                            intptr_t last_token_pos,
+                                            intptr_t requested_line,
+                                            intptr_t requested_column) {
   Function& func = Function::Handle(isolate_);
   func = FindBestFit(script, token_pos);
   if (func.IsNull()) {
@@ -1881,14 +1988,16 @@
     DeoptimizeWorld();
     func ^= functions.At(0);
     intptr_t breakpoint_pos =
-        ResolveBreakpointPos(func, token_pos, last_token_pos);
+        ResolveBreakpointPos(func, token_pos, last_token_pos, requested_column);
     if (breakpoint_pos >= 0) {
-      BreakpointLocation* bpt = GetBreakpointLocation(script, breakpoint_pos);
+      BreakpointLocation* bpt =
+          GetBreakpointLocation(script, breakpoint_pos, requested_column);
       if (bpt != NULL) {
         // A source breakpoint for this location already exists.
         return bpt;
       }
-      bpt = new BreakpointLocation(script, token_pos, last_token_pos);
+      bpt = new BreakpointLocation(script, token_pos, last_token_pos,
+                                   requested_line, requested_column);
       bpt->SetResolved(func, breakpoint_pos);
       RegisterBreakpointLocation(bpt);
 
@@ -1901,11 +2010,12 @@
       }
       if (FLAG_verbose_debug) {
         intptr_t line_number;
-        script.GetTokenLocation(breakpoint_pos, &line_number, NULL);
+        intptr_t column_number;
+        script.GetTokenLocation(breakpoint_pos, &line_number, &column_number);
         OS::Print("Resolved BP for "
-                  "function '%s' at line %" Pd "\n",
+                  "function '%s' at line %" Pd " col %" Pd "\n",
                   func.ToFullyQualifiedCString(),
-                  line_number);
+                  line_number, column_number);
       }
       return bpt;
     }
@@ -1914,15 +2024,18 @@
   // Register an unresolved breakpoint.
   if (FLAG_verbose_debug && !func.IsNull()) {
     intptr_t line_number;
-    script.GetTokenLocation(token_pos, &line_number, NULL);
+    intptr_t column_number;
+    script.GetTokenLocation(token_pos, &line_number, &column_number);
     OS::Print("Registering pending breakpoint for "
-              "uncompiled function '%s' at line %" Pd "\n",
+              "uncompiled function '%s' at line %" Pd " col %" Pd "\n",
               func.ToFullyQualifiedCString(),
-              line_number);
+              line_number, column_number);
   }
-  BreakpointLocation* bpt = GetBreakpointLocation(script, token_pos);
+  BreakpointLocation* bpt =
+      GetBreakpointLocation(script, token_pos, requested_column);
   if (bpt == NULL) {
-    bpt = new BreakpointLocation(script, token_pos, last_token_pos);
+    bpt = new BreakpointLocation(script, token_pos, last_token_pos,
+                                 requested_line, requested_column);
     RegisterBreakpointLocation(bpt);
   }
   return bpt;
@@ -1969,7 +2082,8 @@
   BreakpointLocation* bpt_location =
       SetBreakpoint(script,
                     target_function.token_pos(),
-                    target_function.end_token_pos());
+                    target_function.end_token_pos(),
+                    -1, -1 /* no requested line/col */);
   if (single_shot) {
     return bpt_location->AddSingleShot(this);
   } else {
@@ -1986,7 +2100,8 @@
   const Script& script = Script::Handle(func.script());
   BreakpointLocation* bpt_location = SetBreakpoint(script,
                                                    func.token_pos(),
-                                                   func.end_token_pos());
+                                                   func.end_token_pos(),
+                                                   -1, -1 /* no line/col */);
   return bpt_location->AddPerClosure(this, closure);
 }
 
@@ -2016,7 +2131,8 @@
 
 Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url,
                                           intptr_t line_number) {
-  BreakpointLocation* loc = BreakpointLocationAtLine(script_url, line_number);
+  BreakpointLocation* loc =
+      BreakpointLocationAtLineCol(script_url, line_number, -1 /* no column */);
   if (loc != NULL) {
     return loc->AddRepeated(this);
   }
@@ -2024,8 +2140,23 @@
 }
 
 
-BreakpointLocation* Debugger::BreakpointLocationAtLine(const String& script_url,
-                                                       intptr_t line_number) {
+Breakpoint* Debugger::SetBreakpointAtLineCol(const String& script_url,
+                                             intptr_t line_number,
+                                             intptr_t column_number) {
+  BreakpointLocation* loc = BreakpointLocationAtLineCol(script_url,
+                                                        line_number,
+                                                        column_number);
+  if (loc != NULL) {
+    return loc->AddRepeated(this);
+  }
+  return NULL;
+}
+
+
+BreakpointLocation* Debugger::BreakpointLocationAtLineCol(
+    const String& script_url,
+    intptr_t line_number,
+    intptr_t column_number) {
   Library& lib = Library::Handle(isolate_);
   Script& script = Script::Handle(isolate_);
   const GrowableObjectArray& libs =
@@ -2043,11 +2174,13 @@
     // No script found with given url. Create a latent breakpoint which
     // will be set if the url is loaded later.
     BreakpointLocation* latent_bpt = GetLatentBreakpoint(script_url,
-                                                         line_number);
+                                                         line_number,
+                                                         column_number);
     if (FLAG_verbose_debug) {
-      OS::Print("Set latent breakpoint in url '%s' at line %" Pd "\n",
+      OS::Print("Set latent breakpoint in url '%s' at "
+                "line %" Pd " col %" Pd "\n",
                 script_url.ToCString(),
-                line_number);
+                line_number, column_number);
     }
     return latent_bpt;
   }
@@ -2079,7 +2212,8 @@
   BreakpointLocation* bpt = NULL;
   ASSERT(first_token_idx <= last_token_idx);
   while ((bpt == NULL) && (first_token_idx <= last_token_idx)) {
-    bpt = SetBreakpoint(script, first_token_idx, last_token_idx);
+    bpt = SetBreakpoint(script, first_token_idx, last_token_idx,
+                        line_number, column_number);
     first_token_idx++;
   }
   if ((bpt == NULL) && FLAG_verbose_debug) {
@@ -2680,7 +2814,8 @@
       if (!loc->IsResolved()) {
         // Resolve source breakpoint in the newly compiled function.
         intptr_t bp_pos =
-            ResolveBreakpointPos(func, loc->token_pos(), loc->end_token_pos());
+            ResolveBreakpointPos(func, loc->token_pos(), loc->end_token_pos(),
+                                 loc->requested_column_number());
         if (bp_pos < 0) {
           if (FLAG_verbose_debug) {
             OS::Print("Failed resolving breakpoint for function '%s'\n",
@@ -2694,14 +2829,18 @@
         Breakpoint* bpt = loc->breakpoints();
         while (bpt != NULL) {
           if (FLAG_verbose_debug) {
-            OS::Print("Resolved BP %" Pd " to pos %" Pd ", line %" Pd ", "
-                      "function '%s' (requested range %" Pd "-%" Pd ")\n",
+            OS::Print("Resolved BP %" Pd " to pos %" Pd ", "
+                      "line %" Pd " col %" Pd ", "
+                      "function '%s' (requested range %" Pd "-%" Pd ", "
+                      "requested col %" Pd ")\n",
                       bpt->id(),
                       loc->token_pos(),
                       loc->LineNumber(),
+                      loc->ColumnNumber(),
                       func.ToFullyQualifiedCString(),
                       requested_pos,
-                      requested_end_pos);
+                      requested_end_pos,
+                      loc->requested_column_number());
           }
           SignalBpResolved(bpt);
           SendServiceBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt);
@@ -2712,9 +2851,11 @@
       if (FLAG_verbose_debug) {
         Breakpoint* bpt = loc->breakpoints();
         while (bpt != NULL) {
-          OS::Print("Setting breakpoint %" Pd " at line %" Pd " for %s '%s'\n",
+          OS::Print("Setting breakpoint %" Pd " at line %" Pd " col %" Pd ""
+                    " for %s '%s'\n",
                     bpt->id(),
                     loc->LineNumber(),
+                    loc->ColumnNumber(),
                     func.IsClosureFunction() ? "closure" : "function",
                     String::Handle(func.name()).ToCString());
           bpt = bpt->next();
@@ -2757,7 +2898,8 @@
         }
         // Now find the token range at the requested line and make a
         // new unresolved source breakpoint.
-        intptr_t line_number = matched_loc->LineNumber();
+        intptr_t line_number = matched_loc->requested_line_number();
+        intptr_t column_number = matched_loc->requested_column_number();
         ASSERT(line_number >= 0);
         intptr_t first_token_pos, last_token_pos;
         script.TokenRangeAtLine(line_number, &first_token_pos, &last_token_pos);
@@ -2784,15 +2926,15 @@
           // If there is one, assert in debug build but silently drop
           // the latent breakpoint in release build.
           BreakpointLocation* existing_loc =
-              GetBreakpointLocation(script, first_token_pos);
+              GetBreakpointLocation(script, first_token_pos, column_number);
           ASSERT(existing_loc == NULL);
           if (existing_loc == NULL) {
             // Create and register a new source breakpoint for the
             // latent breakpoint.
             BreakpointLocation* unresolved_loc =
                 new BreakpointLocation(script,
-                                       first_token_pos,
-                                       last_token_pos);
+                                       first_token_pos, last_token_pos,
+                                       line_number, column_number);
             RegisterBreakpointLocation(unresolved_loc);
 
             // Move breakpoints over.
@@ -2803,10 +2945,10 @@
               bpt->set_bpt_location(unresolved_loc);
               if (FLAG_verbose_debug) {
                 OS::Print("Converted latent breakpoint "
-                          "%" Pd " in '%s' at line %" Pd "\n",
+                          "%" Pd " in '%s' at line %" Pd " col %" Pd "\n",
                           bpt->id(),
                           url.ToCString(),
-                          line_number);
+                          line_number, column_number);
               }
               bpt = bpt->next();
             }
@@ -2970,10 +3112,13 @@
 
 
 BreakpointLocation* Debugger::GetBreakpointLocation(const Script& script,
-                                                    intptr_t token_pos) {
+                                                    intptr_t token_pos,
+                                                    intptr_t requested_column) {
   BreakpointLocation* bpt = breakpoint_locations_;
   while (bpt != NULL) {
-    if ((bpt->script_ == script.raw()) && (bpt->token_pos_ == token_pos)) {
+    if ((bpt->script_ == script.raw()) &&
+        (bpt->token_pos_ == token_pos) &&
+        (bpt->requested_column_number_ == requested_column)) {
       return bpt;
     }
     bpt = bpt->next();
@@ -2999,18 +3144,21 @@
 
 
 BreakpointLocation* Debugger::GetLatentBreakpoint(const String& url,
-                                                  intptr_t line) {
+                                                  intptr_t line,
+                                                  intptr_t column) {
   BreakpointLocation* bpt = latent_locations_;
   String& bpt_url = String::Handle(isolate_);
   while (bpt != NULL) {
     bpt_url = bpt->url();
-    if (bpt_url.Equals(url) && (bpt->LineNumber() == line)) {
+    if (bpt_url.Equals(url) &&
+        (bpt->requested_line_number() == line) &&
+        (bpt->requested_column_number() == column)) {
       return bpt;
     }
     bpt = bpt->next();
   }
-  // No breakpint for this url and line requested. Allocate new one.
-  bpt = new BreakpointLocation(url, line);
+  // No breakpoint for this location requested. Allocate new one.
+  bpt = new BreakpointLocation(url, line, column);
   bpt->set_next(latent_locations_);
   latent_locations_ = bpt;
   return bpt;
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index 396e8b2..685e5b5 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -99,10 +99,13 @@
   // Create a new unresolved breakpoint.
   BreakpointLocation(const Script& script,
                      intptr_t token_pos,
-                     intptr_t end_token_pos);
+                     intptr_t end_token_pos,
+                     intptr_t requested_line_number,
+                     intptr_t requested_column_number);
   // Create a new latent breakpoint.
   BreakpointLocation(const String& url,
-                     intptr_t line_number);
+                     intptr_t requested_line_number,
+                     intptr_t requested_column_number);
 
   ~BreakpointLocation();
 
@@ -112,9 +115,16 @@
 
   RawScript* script() const { return script_; }
   RawString* url() const { return url_; }
-  intptr_t LineNumber();
 
-  void GetCodeLocation(Library* lib, Script* script, intptr_t* token_pos);
+  intptr_t requested_line_number() const { return requested_line_number_; }
+  intptr_t requested_column_number() const { return requested_column_number_; }
+
+  intptr_t LineNumber();
+  intptr_t ColumnNumber();
+
+  void GetCodeLocation(Library* lib,
+                       Script* script,
+                       intptr_t* token_pos) const;
 
   Breakpoint* AddRepeated(Debugger* dbg);
   Breakpoint* AddSingleShot(Debugger* dbg);
@@ -144,10 +154,13 @@
   bool is_resolved_;
   BreakpointLocation* next_;
   Breakpoint* conditions_;
+  intptr_t requested_line_number_;
+  intptr_t requested_column_number_;
 
   // Valid for resolved breakpoints:
   RawFunction* function_;
   intptr_t line_number_;
+  intptr_t column_number_;
 
   friend class Debugger;
   DISALLOW_COPY_AND_ASSIGN(BreakpointLocation);
@@ -460,10 +473,14 @@
   // TODO(turnidge): script_url may no longer be specific enough.
   Breakpoint* SetBreakpointAtLine(const String& script_url,
                                   intptr_t line_number);
+  Breakpoint* SetBreakpointAtLineCol(const String& script_url,
+                                     intptr_t line_number,
+                                     intptr_t column_number);
   RawError* OneTimeBreakAtEntry(const Function& target_function);
 
-  BreakpointLocation* BreakpointLocationAtLine(const String& script_url,
-                                               intptr_t line_number);
+  BreakpointLocation* BreakpointLocationAtLineCol(const String& script_url,
+                                                  intptr_t line_number,
+                                                  intptr_t column_number);
 
 
   void RemoveBreakpoint(intptr_t bp_id);
@@ -555,6 +572,8 @@
 
   static bool IsDebuggable(const Function& func);
 
+  intptr_t limitBreakpointId() { return next_id_; }
+
  private:
   enum ResumeAction {
     kContinue,
@@ -575,18 +594,24 @@
                                     intptr_t token_pos);
   intptr_t ResolveBreakpointPos(const Function& func,
                                 intptr_t requested_token_pos,
-                                intptr_t last_token_pos);
+                                intptr_t last_token_pos,
+                                intptr_t requested_column);
   void DeoptimizeWorld();
   BreakpointLocation* SetBreakpoint(const Script& script,
                                     intptr_t token_pos,
-                                    intptr_t last_token_pos);
+                                    intptr_t last_token_pos,
+                                    intptr_t requested_line,
+                                    intptr_t requested_column);
   void RemoveInternalBreakpoints();
   void UnlinkCodeBreakpoints(BreakpointLocation* bpt_location);
-  BreakpointLocation* GetLatentBreakpoint(const String& url, intptr_t line);
+  BreakpointLocation* GetLatentBreakpoint(const String& url,
+                                          intptr_t line,
+                                          intptr_t column);
   void RegisterBreakpointLocation(BreakpointLocation* bpt);
   void RegisterCodeBreakpoint(CodeBreakpoint* bpt);
   BreakpointLocation* GetBreakpointLocation(const Script& script,
-                                            intptr_t token_pos);
+                                            intptr_t token_pos,
+                                            intptr_t requested_column);
   void MakeCodeBreakpointAt(const Function& func,
                             BreakpointLocation* bpt);
   // Returns NULL if no breakpoint exists for the given address.
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index 9fd26d8..ad0198b 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -361,7 +361,11 @@
     return Api::NewError("%s: breakpoint with id %" Pd " does not exist",
                          CURRENT_FUNC, bp_id);
   }
-  return Dart_NewInteger(bpt->bpt_location()->LineNumber());
+  if (bpt->bpt_location()->IsResolved()) {
+    return Dart_NewInteger(bpt->bpt_location()->LineNumber());
+  } else {
+    return Dart_NewInteger(bpt->bpt_location()->requested_line_number());
+  }
 }
 
 
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index e539374..bd9e3e1 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -1405,6 +1405,7 @@
   EXPECT(Dart_GetIsolateId(isolate) == test_isolate_id);
   Dart_ExitScope();
   Dart_ShutdownIsolate();
+  Dart_SetIsolateEventHandler(NULL);
   EXPECT(verify_callback == 0x5);  // Only created and shutdown events.
 }
 
diff --git a/runtime/vm/debugger_test.cc b/runtime/vm/debugger_test.cc
index 7393c67..b418cbf 100644
--- a/runtime/vm/debugger_test.cc
+++ b/runtime/vm/debugger_test.cc
@@ -69,18 +69,18 @@
         js.ToCString(),
         "[{\"type\":\"Breakpoint\",\"fixedId\":true,\"id\":\"breakpoints\\/2\","
         "\"breakpointNumber\":2,\"resolved\":false,"
-        "\"location\":{\"type\":\"SourceLocation\","
+        "\"location\":{\"type\":\"UnresolvedSourceLocation\","
         "\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
         "\"id\":\"libraries\\/%" Pd "\\/scripts\\/test-lib\","
         "\"uri\":\"test-lib\","
-        "\"_kind\":\"script\"},\"tokenPos\":14}},"
+        "\"_kind\":\"script\"},\"line\":3}},"
         "{\"type\":\"Breakpoint\",\"fixedId\":true,\"id\":\"breakpoints\\/1\","
         "\"breakpointNumber\":1,\"resolved\":false,"
-        "\"location\":{\"type\":\"SourceLocation\","
+        "\"location\":{\"type\":\"UnresolvedSourceLocation\","
         "\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
         "\"id\":\"libraries\\/%" Pd "\\/scripts\\/test-lib\","
         "\"uri\":\"test-lib\","
-        "\"_kind\":\"script\"},\"tokenPos\":5}}]",
+        "\"_kind\":\"script\"},\"line\":2}}]",
         vmlib.index(), vmlib.index());
   }
 }
diff --git a/runtime/vm/disassembler.cc b/runtime/vm/disassembler.cc
index 1a92450..c63d459 100644
--- a/runtime/vm/disassembler.cc
+++ b/runtime/vm/disassembler.cc
@@ -21,22 +21,22 @@
                                              uword pc) {
   static const int kHexColumnWidth = 23;
   uint8_t* pc_ptr = reinterpret_cast<uint8_t*>(pc);
-  ISL_Print("%p    %s", pc_ptr, hex_buffer);
+  THR_Print("%p    %s", pc_ptr, hex_buffer);
   int hex_length = strlen(hex_buffer);
   if (hex_length < kHexColumnWidth) {
     for (int i = kHexColumnWidth - hex_length; i > 0; i--) {
-      ISL_Print(" ");
+      THR_Print(" ");
     }
   }
-  ISL_Print("%s", human_buffer);
-  ISL_Print("\n");
+  THR_Print("%s", human_buffer);
+  THR_Print("\n");
 }
 
 
 void DisassembleToStdout::Print(const char* format, ...) {
   va_list args;
   va_start(args, format);
-  ISL_VPrint(format, args);
+  THR_VPrint(format, args);
   va_end(args);
 }
 
diff --git a/runtime/vm/disassembler.h b/runtime/vm/disassembler.h
index 86413f8..1becc4d 100644
--- a/runtime/vm/disassembler.h
+++ b/runtime/vm/disassembler.h
@@ -99,13 +99,13 @@
                           uword end,
                           const Code& code) {
     DisassembleToStdout stdout_formatter;
-    LogBlock lb(Isolate::Current());
+    LogBlock lb;
     Disassemble(start, end, &stdout_formatter, code);
   }
 
   static void Disassemble(uword start, uword end) {
     DisassembleToStdout stdout_formatter;
-    LogBlock lb(Isolate::Current());
+    LogBlock lb;
     Disassemble(start, end, &stdout_formatter);
   }
 
diff --git a/runtime/vm/disassembler_ia32.cc b/runtime/vm/disassembler_ia32.cc
index b18dd3f..036f5d0 100644
--- a/runtime/vm/disassembler_ia32.cc
+++ b/runtime/vm/disassembler_ia32.cc
@@ -479,11 +479,8 @@
 
   const Class& clazz = Class::Handle(obj.clazz());
   const char* full_class_name = clazz.ToCString();
-  const char* format = "instance of %s";
-  intptr_t len = OS::SNPrint(NULL, 0, format, full_class_name) + 1;
-  char* chars = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, format, full_class_name);
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(),
+      "instance of %s", full_class_name);
 }
 
 
diff --git a/runtime/vm/disassembler_x64.cc b/runtime/vm/disassembler_x64.cc
index 9f43a38..ffd6108 100644
--- a/runtime/vm/disassembler_x64.cc
+++ b/runtime/vm/disassembler_x64.cc
@@ -796,11 +796,8 @@
 
   const Class& clazz = Class::Handle(obj.clazz());
   const char* full_class_name = clazz.ToCString();
-  const char* format = "instance of %s";
-  intptr_t len = OS::SNPrint(NULL, 0, format, full_class_name) + 1;
-  char* chars = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, format, full_class_name);
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(),
+      "instance of %s", full_class_name);
 }
 
 
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index de44cf0..9f99503 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -571,7 +571,7 @@
   args.SetAt(1, Integer::Handle(Integer::New(expected_from)));
   args.SetAt(2, Integer::Handle(Integer::New(expected_to)));
   args.SetAt(3, String::Handle(String::New(argument_name)));
-  Exceptions::ThrowByType(Exceptions::kRangeRange, args);
+  Exceptions::ThrowByType(Exceptions::kRange, args);
 }
 
 
@@ -588,10 +588,6 @@
     case kRange:
       library = Library::CoreLibrary();
       class_name = &Symbols::RangeError();
-      break;
-    case kRangeRange:
-      library = Library::CoreLibrary();
-      class_name = &Symbols::RangeError();
       constructor_name = &Symbols::DotRange();
       break;
     case kArgument:
diff --git a/runtime/vm/exceptions.h b/runtime/vm/exceptions.h
index 75addb2..0bd97f8 100644
--- a/runtime/vm/exceptions.h
+++ b/runtime/vm/exceptions.h
@@ -51,7 +51,6 @@
   enum ExceptionType {
     kNone,
     kRange,
-    kRangeRange,
     kArgument,
     kArgumentValue,
     kNoSuchMethod,
diff --git a/runtime/vm/flow_graph_allocator.cc b/runtime/vm/flow_graph_allocator.cc
index 6f5deb4..93d964a 100644
--- a/runtime/vm/flow_graph_allocator.cc
+++ b/runtime/vm/flow_graph_allocator.cc
@@ -450,21 +450,21 @@
     return;
   }
 
-  ISL_Print("  live range v%" Pd " [%" Pd ", %" Pd ") in ", vreg(),
+  THR_Print("  live range v%" Pd " [%" Pd ", %" Pd ") in ", vreg(),
                                                             Start(),
                                                             End());
   assigned_location().Print();
   if (spill_slot_.HasStackIndex()) {
     intptr_t stack_slot = spill_slot_.stack_index();
-    ISL_Print(" allocated spill slot: %" Pd "", stack_slot);
+    THR_Print(" allocated spill slot: %" Pd "", stack_slot);
   }
-  ISL_Print("\n");
+  THR_Print("\n");
 
   SafepointPosition* safepoint = first_safepoint();
   while (safepoint != NULL) {
-    ISL_Print("    Safepoint [%" Pd "]: ", safepoint->pos());
+    THR_Print("    Safepoint [%" Pd "]: ", safepoint->pos());
     safepoint->locs()->stack_bitmap()->Print();
-    ISL_Print("\n");
+    THR_Print("\n");
     safepoint = safepoint->next();
   }
 
@@ -472,16 +472,16 @@
   for (UseInterval* interval = first_use_interval_;
        interval != NULL;
        interval = interval->next()) {
-    ISL_Print("    use interval [%" Pd ", %" Pd ")\n",
+    THR_Print("    use interval [%" Pd ", %" Pd ")\n",
               interval->start(),
               interval->end());
     while ((use_pos != NULL) && (use_pos->pos() <= interval->end())) {
-      ISL_Print("      use at %" Pd "", use_pos->pos());
+      THR_Print("      use at %" Pd "", use_pos->pos());
       if (use_pos->location_slot() != NULL) {
-        ISL_Print(" as ");
+        THR_Print(" as ");
         use_pos->location_slot()->Print();
       }
-      ISL_Print("\n");
+      THR_Print("\n");
       use_pos = use_pos->next();
     }
   }
@@ -1784,7 +1784,7 @@
                                 first_safepoint_after_split,
                                 next_sibling_);
 
-  TRACE_ALLOC(ISL_Print("  split sibling [%" Pd ", %" Pd ")\n",
+  TRACE_ALLOC(THR_Print("  split sibling [%" Pd ", %" Pd ")\n",
                         next_sibling_->Start(), next_sibling_->End()));
 
   last_use_interval_ = last_before_split;
@@ -1801,7 +1801,7 @@
 LiveRange* FlowGraphAllocator::SplitBetween(LiveRange* range,
                                             intptr_t from,
                                             intptr_t to) {
-  TRACE_ALLOC(ISL_Print("split v%" Pd " [%" Pd ", %" Pd
+  TRACE_ALLOC(THR_Print("split v%" Pd " [%" Pd ", %" Pd
                         ") between [%" Pd ", %" Pd ")\n",
                         range->vreg(), range->Start(), range->End(), from, to));
 
@@ -1841,7 +1841,7 @@
                                       intptr_t from,
                                       intptr_t to) {
   ASSERT(from < to);
-  TRACE_ALLOC(ISL_Print("spill v%" Pd " [%" Pd ", %" Pd ") "
+  TRACE_ALLOC(THR_Print("spill v%" Pd " [%" Pd ", %" Pd ") "
                         "between [%" Pd ", %" Pd ")\n",
                         range->vreg(), range->Start(), range->End(), from, to));
   LiveRange* tail = range->SplitAt(from);
@@ -1859,7 +1859,7 @@
 
 
 void FlowGraphAllocator::SpillAfter(LiveRange* range, intptr_t from) {
-  TRACE_ALLOC(ISL_Print("spill v%" Pd " [%" Pd ", %" Pd ") after %" Pd "\n",
+  TRACE_ALLOC(THR_Print("spill v%" Pd " [%" Pd ", %" Pd ") after %" Pd "\n",
                         range->vreg(), range->Start(), range->End(), from));
 
   // When spilling the value inside the loop check if this spill can
@@ -1873,7 +1873,7 @@
         RangeHasOnlyUnconstrainedUsesInLoop(range, loop_header->loop_id())) {
       ASSERT(loop_header->entry()->start_pos() <= from);
       from = loop_header->entry()->start_pos();
-      TRACE_ALLOC(ISL_Print("  moved spill position to loop header %" Pd "\n",
+      TRACE_ALLOC(THR_Print("  moved spill position to loop header %" Pd "\n",
                             from));
     }
   }
@@ -2105,7 +2105,7 @@
       candidate = hint.register_code();
     }
 
-    TRACE_ALLOC(ISL_Print("found hint %s for v%" Pd ": free until %" Pd "\n",
+    TRACE_ALLOC(THR_Print("found hint %s for v%" Pd ": free until %" Pd "\n",
                           hint.Name(),
                           unallocated->vreg(),
                           free_until));
@@ -2168,7 +2168,7 @@
     }
 
     if (used_on_backedge[candidate]) {
-      TRACE_ALLOC(ISL_Print(
+      TRACE_ALLOC(THR_Print(
           "considering %s for v%" Pd ": has interference on the back edge"
           " {loop [%" Pd ", %" Pd ")}\n",
           MakeRegisterLocation(candidate).Name(),
@@ -2187,7 +2187,7 @@
         if (intersection >= free_until) {
           candidate = reg;
           free_until = intersection;
-          TRACE_ALLOC(ISL_Print(
+          TRACE_ALLOC(THR_Print(
               "found %s for v%" Pd " with no interference on the back edge\n",
               MakeRegisterLocation(candidate).Name(),
               candidate));
@@ -2197,13 +2197,13 @@
     }
   }
 
-  TRACE_ALLOC(ISL_Print("assigning free register "));
+  TRACE_ALLOC(THR_Print("assigning free register "));
   TRACE_ALLOC(MakeRegisterLocation(candidate).Print());
-  TRACE_ALLOC(ISL_Print(" to v%" Pd "\n", unallocated->vreg()));
+  TRACE_ALLOC(THR_Print(" to v%" Pd "\n", unallocated->vreg()));
 
   if (free_until != kMaxPosition) {
     // There was an intersection. Split unallocated.
-    TRACE_ALLOC(ISL_Print("  splitting at %" Pd "\n", free_until));
+    TRACE_ALLOC(THR_Print("  splitting at %" Pd "\n", free_until));
     LiveRange* tail = unallocated->SplitAt(free_until);
     AddToUnallocated(tail);
   }
@@ -2302,9 +2302,9 @@
 
   ASSERT(candidate != kNoRegister);
 
-  TRACE_ALLOC(ISL_Print("assigning blocked register "));
+  TRACE_ALLOC(THR_Print("assigning blocked register "));
   TRACE_ALLOC(MakeRegisterLocation(candidate).Print());
-  TRACE_ALLOC(ISL_Print(" to live range v%" Pd " until %" Pd "\n",
+  TRACE_ALLOC(THR_Print(" to live range v%" Pd " until %" Pd "\n",
                         unallocated->vreg(), blocked_at));
 
   if (blocked_at < unallocated->End()) {
@@ -2469,9 +2469,9 @@
   ASSERT(use->location_slot() != NULL);
   Location* slot = use->location_slot();
   ASSERT(slot->IsUnallocated());
-  TRACE_ALLOC(ISL_Print("  use at %" Pd " converted to ", use->pos()));
+  TRACE_ALLOC(THR_Print("  use at %" Pd " converted to ", use->pos()));
   TRACE_ALLOC(loc.Print());
-  TRACE_ALLOC(ISL_Print("\n"));
+  TRACE_ALLOC(THR_Print("\n"));
   *slot = loc;
 }
 
@@ -2482,11 +2482,11 @@
   const Location loc = range->assigned_location();
   ASSERT(!loc.IsInvalid());
 
-  TRACE_ALLOC(ISL_Print("range [%" Pd ", %" Pd ") "
+  TRACE_ALLOC(THR_Print("range [%" Pd ", %" Pd ") "
                         "for v%" Pd " has been allocated to ",
                         range->Start(), range->End(), range->vreg()));
   TRACE_ALLOC(loc.Print());
-  TRACE_ALLOC(ISL_Print(":\n"));
+  TRACE_ALLOC(THR_Print(":\n"));
 
   for (UsePosition* use = range->first_use(); use != NULL; use = use->next()) {
     ConvertUseTo(use, loc);
@@ -2662,7 +2662,7 @@
   while (!unallocated_.is_empty()) {
     LiveRange* range = unallocated_.RemoveLast();
     const intptr_t start = range->Start();
-    TRACE_ALLOC(ISL_Print("Processing live range for v%" Pd " "
+    TRACE_ALLOC(THR_Print("Processing live range for v%" Pd " "
                           "starting at %" Pd "\n",
                           range->vreg(),
                           start));
@@ -2686,7 +2686,7 @@
 
   // Finish allocation.
   AdvanceActiveIntervals(kMaxPosition);
-  TRACE_ALLOC(ISL_Print("Allocation completed\n"));
+  TRACE_ALLOC(THR_Print("Allocation completed\n"));
 }
 
 
@@ -2705,13 +2705,13 @@
 void FlowGraphAllocator::ConnectSplitSiblings(LiveRange* parent,
                                               BlockEntryInstr* source_block,
                                               BlockEntryInstr* target_block) {
-  TRACE_ALLOC(ISL_Print("Connect v%" Pd " on the edge B%" Pd " -> B%" Pd "\n",
+  TRACE_ALLOC(THR_Print("Connect v%" Pd " on the edge B%" Pd " -> B%" Pd "\n",
                         parent->vreg(),
                         source_block->block_id(),
                         target_block->block_id()));
   if (parent->next_sibling() == NULL) {
     // Nothing to connect. The whole range was allocated to the same location.
-    TRACE_ALLOC(ISL_Print("range v%" Pd " has no siblings\n", parent->vreg()));
+    TRACE_ALLOC(THR_Print("range v%" Pd " has no siblings\n", parent->vreg()));
     return;
   }
 
@@ -2748,7 +2748,7 @@
     range = range->next_sibling();
   }
 
-  TRACE_ALLOC(ISL_Print("connecting v%" Pd " between [%" Pd ", %" Pd ") {%s} "
+  TRACE_ALLOC(THR_Print("connecting v%" Pd " between [%" Pd ", %" Pd ") {%s} "
                         "to [%" Pd ", %" Pd ") {%s}\n",
                         parent->vreg(),
                         source_cover->Start(),
@@ -2785,13 +2785,13 @@
 
     while (range->next_sibling() != NULL) {
       LiveRange* sibling = range->next_sibling();
-      TRACE_ALLOC(ISL_Print("connecting [%" Pd ", %" Pd ") [",
+      TRACE_ALLOC(THR_Print("connecting [%" Pd ", %" Pd ") [",
                             range->Start(), range->End()));
       TRACE_ALLOC(range->assigned_location().Print());
-      TRACE_ALLOC(ISL_Print("] to [%" Pd ", %" Pd ") [",
+      TRACE_ALLOC(THR_Print("] to [%" Pd ", %" Pd ") [",
                             sibling->Start(), sibling->End()));
       TRACE_ALLOC(sibling->assigned_location().Print());
-      TRACE_ALLOC(ISL_Print("]\n"));
+      TRACE_ALLOC(THR_Print("]\n"));
       if ((range->End() == sibling->Start()) &&
           !TargetLocationIsSpillSlot(range, sibling->assigned_location()) &&
           !range->assigned_location().Equals(sibling->assigned_location()) &&
@@ -2922,16 +2922,16 @@
 
   if (FLAG_print_ssa_liveranges) {
     const Function& function = flow_graph_.function();
-    ISL_Print("-- [before ssa allocator] ranges [%s] ---------\n",
+    THR_Print("-- [before ssa allocator] ranges [%s] ---------\n",
               function.ToFullyQualifiedCString());
     PrintLiveRanges();
-    ISL_Print("----------------------------------------------\n");
+    THR_Print("----------------------------------------------\n");
 
-    ISL_Print("-- [before ssa allocator] ir [%s] -------------\n",
+    THR_Print("-- [before ssa allocator] ir [%s] -------------\n",
               function.ToFullyQualifiedCString());
     FlowGraphPrinter printer(flow_graph_, true);
     printer.PrintBlocks();
-    ISL_Print("----------------------------------------------\n");
+    THR_Print("----------------------------------------------\n");
   }
 
   PrepareForAllocation(Location::kRegister,
@@ -2963,16 +2963,16 @@
   if (FLAG_print_ssa_liveranges) {
     const Function& function = flow_graph_.function();
 
-    ISL_Print("-- [after ssa allocator] ranges [%s] ---------\n",
+    THR_Print("-- [after ssa allocator] ranges [%s] ---------\n",
               function.ToFullyQualifiedCString());
     PrintLiveRanges();
-    ISL_Print("----------------------------------------------\n");
+    THR_Print("----------------------------------------------\n");
 
-    ISL_Print("-- [after ssa allocator] ir [%s] -------------\n",
+    THR_Print("-- [after ssa allocator] ir [%s] -------------\n",
               function.ToFullyQualifiedCString());
     FlowGraphPrinter printer(flow_graph_, true);
     printer.PrintBlocks();
-    ISL_Print("----------------------------------------------\n");
+    THR_Print("----------------------------------------------\n");
   }
 }
 
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index c1d94b4..54f18c1 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -28,6 +28,8 @@
 
 namespace dart {
 
+DEFINE_FLAG(bool, allow_absolute_addresses, true,
+    "Allow embedding absolute addresses in generated code.");
 DEFINE_FLAG(bool, always_megamorphic_calls, false,
     "Instance call always as megamorphic.");
 DEFINE_FLAG(bool, enable_simd_inline, true,
@@ -51,6 +53,7 @@
 DECLARE_FLAG(bool, disassemble);
 DECLARE_FLAG(bool, disassemble_optimized);
 DECLARE_FLAG(bool, emit_edge_counters);
+DECLARE_FLAG(bool, fields_may_be_reset);
 DECLARE_FLAG(bool, guess_other_cid);
 DECLARE_FLAG(bool, ic_range_profiling);
 DECLARE_FLAG(bool, intrinsify);
@@ -120,6 +123,8 @@
     FLAG_enable_mirrors = false;
     FLAG_precompile_collect_closures = true;
     FLAG_link_natives_lazily = true;
+    FLAG_fields_may_be_reset = true;
+    FLAG_allow_absolute_addresses = false;
   }
 }
 
@@ -431,7 +436,7 @@
   intptr_t inlining_id;
   IntervalStruct(intptr_t s, intptr_t id) : start(s), inlining_id(id) {}
   void Dump() {
-    ISL_Print("start: 0x%" Px " iid: %" Pd " ",  start, inlining_id);
+    THR_Print("start: 0x%" Px " iid: %" Pd " ",  start, inlining_id);
   }
 };
 
@@ -520,7 +525,7 @@
   }
 
   if (is_optimizing()) {
-    LogBlock lb(Thread::Current());
+    LogBlock lb;
     intervals.Add(IntervalStruct(prev_offset, prev_inlining_id));
     inlined_code_intervals_ =
         Array::New(intervals.length() * Code::kInlIntNumEntries, Heap::kOld);
@@ -532,7 +537,7 @@
         const Function& function =
             *inline_id_to_function_.At(intervals[i].inlining_id);
         intervals[i].Dump();
-        ISL_Print(" parent iid %" Pd " %s\n",
+        THR_Print(" parent iid %" Pd " %s\n",
             caller_inline_id_[intervals[i].inlining_id],
             function.ToQualifiedCString());
       }
@@ -549,10 +554,10 @@
   }
   set_current_block(NULL);
   if (FLAG_trace_inlining_intervals && is_optimizing()) {
-    LogBlock lb(Isolate::Current());
-    ISL_Print("Intervals:\n");
+    LogBlock lb;
+    THR_Print("Intervals:\n");
     for (intptr_t cc = 0; cc < caller_inline_id_.length(); cc++) {
-      ISL_Print("  iid: %" Pd " caller iid: %" Pd "\n",
+      THR_Print("  iid: %" Pd " caller iid: %" Pd "\n",
           cc, caller_inline_id_[cc]);
     }
     Smi& temp = Smi::Handle();
@@ -560,9 +565,9 @@
          i += Code::kInlIntNumEntries) {
       temp ^= inlined_code_intervals_.At(i + Code::kInlIntStart);
       ASSERT(!temp.IsNull());
-      ISL_Print("% " Pd " start: 0x%" Px " ", i, temp.Value());
+      THR_Print("% " Pd " start: 0x%" Px " ", i, temp.Value());
       temp ^= inlined_code_intervals_.At(i + Code::kInlIntInliningId);
-      ISL_Print("iid: %" Pd " ", temp.Value());
+      THR_Print("iid: %" Pd " ", temp.Value());
     }
   }
 }
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 17f61ac..5781c29 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -210,8 +210,7 @@
                                            Label* is_true,
                                            Label* is_false) {
   Label fall_through;
-  __ CompareImmediate(bool_register,
-                      reinterpret_cast<intptr_t>(Object::null()));
+  __ CompareObject(bool_register, Object::null_object());
   __ b(&fall_through, EQ);
   __ CompareObject(bool_register, Bool::True());
   __ b(is_true, EQ);
@@ -236,11 +235,11 @@
   __ LoadUniqueObject(R2, type_test_cache);
   if (test_kind == kTestTypeOneArg) {
     ASSERT(type_arguments_reg == kNoRegister);
-    __ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null()));
+    __ LoadObject(R1, Object::null_object());
     __ BranchLink(*StubCode::Subtype1TestCache_entry());
   } else if (test_kind == kTestTypeTwoArgs) {
     ASSERT(type_arguments_reg == kNoRegister);
-    __ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null()));
+    __ LoadObject(R1, Object::null_object());
     __ BranchLink(*StubCode::Subtype2TestCache_entry());
   } else if (test_kind == kTestTypeThreeArgs) {
     ASSERT(type_arguments_reg == R1);
@@ -390,7 +389,7 @@
     // Check if instance is a closure.
     __ LoadClassById(R3, kClassIdReg);
     __ ldr(R3, FieldAddress(R3, Class::signature_function_offset()));
-    __ CompareImmediate(R3, reinterpret_cast<int32_t>(Object::null()));
+    __ CompareObject(R3, Object::null_object());
     __ b(is_instance_lbl, NE);
   }
   // Custom checking for numbers (Smi, Mint, Bigint and Double).
@@ -458,7 +457,7 @@
     __ ldr(R1, Address(SP, 0));  // Get instantiator type arguments.
     // R1: instantiator type arguments.
     // Check if type arguments are null, i.e. equivalent to vector of dynamic.
-    __ CompareImmediate(R1, reinterpret_cast<intptr_t>(Object::null()));
+    __ CompareObject(R1, Object::null_object());
     __ b(is_instance_lbl, EQ);
     __ ldr(R2,
         FieldAddress(R1, TypeArguments::type_at_offset(type_param.index())));
@@ -603,7 +602,7 @@
     // We can only inline this null check if the type is instantiated at compile
     // time, since an uninstantiated type at compile time could be Object or
     // dynamic at run time.
-    __ CompareImmediate(R0, reinterpret_cast<int32_t>(Object::null()));
+    __ CompareObject(R0, Object::null_object());
     __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ);
   }
 
@@ -679,7 +678,7 @@
   __ PushList((1 << R1) | (1 << R2));
   // A null object is always assignable and is returned as result.
   Label is_assignable, runtime_call;
-  __ CompareImmediate(R0, reinterpret_cast<int32_t>(Object::null()));
+  __ CompareObject(R0, Object::null_object());
   __ b(&is_assignable, EQ);
 
   // Generate throw new TypeError() if the type is malformed or malbounded.
@@ -877,7 +876,7 @@
       // Check that R6 now points to the null terminator in the arguments
       // descriptor.
       __ ldr(R5, Address(R6, 0));
-      __ CompareImmediate(R5, reinterpret_cast<int32_t>(Object::null()));
+      __ CompareObject(R5, Object::null_object());
       __ b(&all_arguments_processed, EQ);
     }
   } else {
@@ -939,7 +938,7 @@
   __ SmiUntag(R9);
   __ add(R7, FP, Operand((kParamEndSlotFromFp + 1) * kWordSize));
   const Address original_argument_addr(R7, R9, LSL, 2);
-  __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(IP, Object::null_object());
   Label null_args_loop, null_args_loop_condition;
   __ b(&null_args_loop_condition);
   __ Bind(&null_args_loop);
@@ -970,7 +969,7 @@
   __ ldr(R0, Address(SP, 1 * kWordSize));  // Receiver.
   __ ldr(R1, Address(SP, 0 * kWordSize));  // Value.
   __ StoreIntoObjectOffset(R0, offset, R1);
-  __ LoadImmediate(R0, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(R0, Object::null_object());
   __ Ret();
 }
 
@@ -1104,7 +1103,7 @@
     const intptr_t context_index =
         parsed_function().current_context_var()->index();
     if (num_locals > 1) {
-      __ LoadImmediate(R0, reinterpret_cast<intptr_t>(Object::null()));
+      __ LoadObject(R0, Object::null_object());
     }
     for (intptr_t i = 0; i < num_locals; ++i) {
       // Subtract index i (locals lie at lower addresses than FP).
@@ -1285,13 +1284,12 @@
     intptr_t deopt_id,
     intptr_t token_pos,
     LocationSummary* locs) {
-  MegamorphicCacheTable* table = Isolate::Current()->megamorphic_cache_table();
   const String& name = String::Handle(zone(), ic_data.target_name());
   const Array& arguments_descriptor =
       Array::ZoneHandle(zone(), ic_data.arguments_descriptor());
   ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
-  const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
-      zone(), table->Lookup(name, arguments_descriptor));
+  const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(),
+      MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor));
   const Register receiverR = R0;
   const Register cacheR = R1;
   const Register targetR = R1;
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index 11bc02d..f7ce841 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -1257,13 +1257,12 @@
     intptr_t deopt_id,
     intptr_t token_pos,
     LocationSummary* locs) {
-  MegamorphicCacheTable* table = Isolate::Current()->megamorphic_cache_table();
   const String& name = String::Handle(zone(), ic_data.target_name());
   const Array& arguments_descriptor =
       Array::ZoneHandle(zone(), ic_data.arguments_descriptor());
   ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
-  const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
-      zone(), table->Lookup(name, arguments_descriptor));
+  const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(),
+      MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor));
   const Register receiverR = R0;
   const Register cacheR = R1;
   const Register targetR = R1;
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 8df27db..81befda 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -1296,13 +1296,12 @@
     intptr_t deopt_id,
     intptr_t token_pos,
     LocationSummary* locs) {
-  MegamorphicCacheTable* table = isolate()->megamorphic_cache_table();
   const String& name = String::Handle(zone(), ic_data.target_name());
   const Array& arguments_descriptor =
       Array::ZoneHandle(zone(), ic_data.arguments_descriptor());
   ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
   const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(),
-      table->Lookup(name, arguments_descriptor));
+      MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor));
   const Register receiverR = EDI;
   const Register cacheR = EBX;
   const Register targetR = EBX;
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 93716a8..f9dea83 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -227,11 +227,11 @@
   __ LoadUniqueObject(A2, type_test_cache);
   if (test_kind == kTestTypeOneArg) {
     ASSERT(type_arguments_reg == kNoRegister);
-    __ LoadImmediate(A1, reinterpret_cast<int32_t>(Object::null()));
+    __ LoadObject(A1, Object::null_object());
     __ BranchLink(*StubCode::Subtype1TestCache_entry());
   } else if (test_kind == kTestTypeTwoArgs) {
     ASSERT(type_arguments_reg == kNoRegister);
-    __ LoadImmediate(A1, reinterpret_cast<int32_t>(Object::null()));
+    __ LoadObject(A1, Object::null_object());
     __ BranchLink(*StubCode::Subtype2TestCache_entry());
   } else if (test_kind == kTestTypeThreeArgs) {
     ASSERT(type_arguments_reg == A1);
@@ -445,7 +445,7 @@
     __ lw(A1, Address(SP, 0));  // Get instantiator type arguments.
     // A1: instantiator type arguments.
     // Check if type arguments are null, i.e. equivalent to vector of dynamic.
-    __ LoadImmediate(T7, reinterpret_cast<int32_t>(Object::null()));
+    __ LoadObject(T7, Object::null_object());
     __ beq(A1, T7, is_instance_lbl);
     __ lw(T2,
         FieldAddress(A1, TypeArguments::type_at_offset(type_param.index())));
@@ -954,7 +954,7 @@
   __ Bind(&null_args_loop);
   __ addiu(T2, T2, Immediate(-kWordSize));
   __ addu(T3, T1, T2);
-  __ LoadImmediate(T5, reinterpret_cast<int32_t>(Object::null()));
+  __ LoadObject(T5, Object::null_object());
   __ bgtz(T2, &null_args_loop);
   __ delay_slot()->sw(T5, Address(T3));
   __ Bind(&null_args_loop_exit);
@@ -981,7 +981,7 @@
   __ lw(T0, Address(SP, 1 * kWordSize));  // Receiver.
   __ lw(T1, Address(SP, 0 * kWordSize));  // Value.
   __ StoreIntoObjectOffset(T0, offset, T1);
-  __ LoadImmediate(V0, reinterpret_cast<int32_t>(Object::null()));
+  __ LoadObject(V0, Object::null_object());
   __ Ret();
 }
 
@@ -1121,7 +1121,7 @@
     const intptr_t context_index =
         parsed_function().current_context_var()->index();
     if (num_locals > 1) {
-      __ LoadImmediate(V0, reinterpret_cast<int32_t>(Object::null()));
+      __ LoadObject(V0, Object::null_object());
     }
     for (intptr_t i = 0; i < num_locals; ++i) {
       // Subtract index i (locals lie at lower addresses than FP).
@@ -1282,13 +1282,12 @@
     intptr_t deopt_id,
     intptr_t token_pos,
     LocationSummary* locs) {
-  MegamorphicCacheTable* table = Isolate::Current()->megamorphic_cache_table();
   const String& name = String::Handle(zone(), ic_data.target_name());
   const Array& arguments_descriptor =
       Array::ZoneHandle(zone(), ic_data.arguments_descriptor());
   ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
-  const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
-      zone(), table->Lookup(name, arguments_descriptor));
+  const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(),
+      MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor));
   __ Comment("MegamorphicInstanceCall");
   const Register receiverR = T0;
   const Register cacheR = T1;
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 40143d4..59934cd 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -1311,13 +1311,12 @@
     intptr_t deopt_id,
     intptr_t token_pos,
     LocationSummary* locs) {
-  MegamorphicCacheTable* table = isolate()->megamorphic_cache_table();
   const String& name = String::Handle(zone(), ic_data.target_name());
   const Array& arguments_descriptor =
       Array::ZoneHandle(zone(), ic_data.arguments_descriptor());
   ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
-  const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
-      zone(), table->Lookup(name, arguments_descriptor));
+  const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(),
+      MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor));
   const Register receiverR = RDI;
   const Register cacheR = RBX;
   const Register targetR = RCX;
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 6c14228..09cc2c7 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -563,13 +563,13 @@
                                          inlining_depth_,
                                          &inlined_info_);
     while (collected_call_sites_->HasCalls()) {
-      TRACE_INLINING(ISL_Print("  Depth %" Pd " ----------\n",
+      TRACE_INLINING(THR_Print("  Depth %" Pd " ----------\n",
                                inlining_depth_));
       if (collected_call_sites_->NumCalls() > FLAG_max_inlined_per_depth) {
         break;
       }
       if (FLAG_print_inlining_tree) {
-        ISL_Print("**Depth % " Pd " calls to inline %" Pd "\n",
+        THR_Print("**Depth % " Pd " calls to inline %" Pd "\n",
             inlining_depth_, collected_call_sites_->NumCalls());
       }
       // Swap collected and inlining arrays and clear the new collecting array.
@@ -614,7 +614,7 @@
   bool TryInlining(const Function& function,
                    const Array& argument_names,
                    InlinedCallData* call_data) {
-    TRACE_INLINING(ISL_Print("  => %s (deopt count %d)\n",
+    TRACE_INLINING(THR_Print("  => %s (deopt count %d)\n",
                              function.ToCString(),
                              function.deoptimization_counter()));
 
@@ -623,7 +623,7 @@
     const Code& unoptimized_code = Code::Handle(function.unoptimized_code());
     // Abort if the inlinable bit on the function is low.
     if (!function.CanBeInlined()) {
-      TRACE_INLINING(ISL_Print("     Bailout: not inlinable\n"));
+      TRACE_INLINING(THR_Print("     Bailout: not inlinable\n"));
       PRINT_INLINING_TREE("Not inlinable",
           &call_data->caller, &function, call_data->call);
       return false;
@@ -633,7 +633,7 @@
     if (function.deoptimization_counter() >=
         FLAG_deoptimization_counter_threshold) {
       function.set_is_inlinable(false);
-      TRACE_INLINING(ISL_Print("     Bailout: deoptimization threshold\n"));
+      TRACE_INLINING(THR_Print("     Bailout: deoptimization threshold\n"));
       PRINT_INLINING_TREE("Deoptimization threshold exceeded",
           &call_data->caller, &function, call_data->call);
       return false;
@@ -642,7 +642,7 @@
     const char* kNeverInlineAnnotation = "NeverInline";
     if (FLAG_enable_inlining_annotations &&
         HasAnnotation(function, kNeverInlineAnnotation)) {
-      TRACE_INLINING(ISL_Print("     Bailout: NeverInline annotation\n"));
+      TRACE_INLINING(THR_Print("     Bailout: NeverInline annotation\n"));
       return false;
     }
 
@@ -652,7 +652,7 @@
                         function.optimized_instruction_count(),
                         function.optimized_call_site_count(),
                         constant_arguments)) {
-      TRACE_INLINING(ISL_Print("     Bailout: early heuristics with "
+      TRACE_INLINING(THR_Print("     Bailout: early heuristics with "
                                "code size:  %" Pd ", "
                                "call sites: %" Pd ", "
                                "const args: %" Pd "\n",
@@ -670,7 +670,7 @@
     volatile bool is_recursive_call = IsCallRecursive(function, call);
     if (is_recursive_call &&
         inlining_recursion_depth_ >= FLAG_inlining_recursion_depth_threshold) {
-      TRACE_INLINING(ISL_Print("     Bailout: recursive function\n"));
+      TRACE_INLINING(THR_Print("     Bailout: recursive function\n"));
       PRINT_INLINING_TREE("Recursive function",
           &call_data->caller, &function, call_data->call);
       return false;
@@ -733,14 +733,14 @@
       // arrays so that actual arguments are in one-to-one with the formal
       // parameters.
       if (function.HasOptionalParameters()) {
-        TRACE_INLINING(ISL_Print("     adjusting for optional parameters\n"));
+        TRACE_INLINING(THR_Print("     adjusting for optional parameters\n"));
         if (!AdjustForOptionalParameters(*parsed_function,
                                          argument_names,
                                          arguments,
                                          param_stubs,
                                          callee_graph)) {
           function.set_is_inlinable(false);
-          TRACE_INLINING(ISL_Print("     Bailout: optional arg mismatch\n"));
+          TRACE_INLINING(THR_Print("     Bailout: optional arg mismatch\n"));
           PRINT_INLINING_TREE("Optional arg mismatch",
               &call_data->caller, &function, call_data->call);
           return false;
@@ -791,7 +791,7 @@
 
       if (FLAG_trace_inlining &&
           (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) {
-        ISL_Print("Callee graph for inlining %s\n",
+        THR_Print("Callee graph for inlining %s\n",
                   function.ToFullyQualifiedCString());
         FlowGraphPrinter printer(*callee_graph);
         printer.PrintBlocks();
@@ -821,7 +821,7 @@
           function.set_is_inlinable(false);
         }
         isolate()->set_deopt_id(prev_deopt_id);
-        TRACE_INLINING(ISL_Print("     Bailout: heuristics with "
+        TRACE_INLINING(THR_Print("     Bailout: heuristics with "
                                  "code size:  %" Pd ", "
                                  "call sites: %" Pd ", "
                                  "const args: %" Pd "\n",
@@ -872,7 +872,7 @@
       // We allocate a ZoneHandle for the unoptimized code so that it cannot be
       // disconnected from its function during the rest of compilation.
       Code::ZoneHandle(unoptimized_code.raw());
-      TRACE_INLINING(ISL_Print("     Success\n"));
+      TRACE_INLINING(THR_Print("     Success\n"));
       PRINT_INLINING_TREE(NULL,
           &call_data->caller, &function, call);
       return true;
@@ -881,7 +881,7 @@
       error = isolate()->object_store()->sticky_error();
       isolate()->object_store()->clear_sticky_error();
       isolate()->set_deopt_id(prev_deopt_id);
-      TRACE_INLINING(ISL_Print("     Bailout: %s\n", error.ToErrorCString()));
+      TRACE_INLINING(THR_Print("     Bailout: %s\n", error.ToErrorCString()));
       PRINT_INLINING_TREE("Bailout",
           &call_data->caller, &function, call);
       return false;
@@ -890,7 +890,7 @@
 
   void PrintInlinedInfo(const Function& top) {
     if (inlined_info_.length() > 0) {
-      ISL_Print("Inlining into: '%s' growth: %f (%" Pd " -> %" Pd ")\n",
+      THR_Print("Inlining into: '%s' growth: %f (%" Pd " -> %" Pd ")\n",
           top.ToFullyQualifiedCString(),
           GrowthFactor(),
           initial_size_,
@@ -923,9 +923,9 @@
           (info.caller->raw() == caller.raw()) &&
           !Contains(call_instructions_printed, info.call_instr->GetDeoptId())) {
         for (int t = 0; t < depth; t++) {
-          ISL_Print("  ");
+          THR_Print("  ");
         }
-        ISL_Print("%" Pd " %s\n",
+        THR_Print("%" Pd " %s\n",
             info.call_instr->GetDeoptId(),
             info.inlined->ToQualifiedCString());
         PrintInlinedInfoFor(*info.inlined, depth + 1);
@@ -943,9 +943,9 @@
           (info.caller->raw() == caller.raw()) &&
           !Contains(call_instructions_printed, info.call_instr->GetDeoptId())) {
         for (int t = 0; t < depth; t++) {
-          ISL_Print("  ");
+          THR_Print("  ");
         }
-        ISL_Print("NO %" Pd " %s - %s\n",
+        THR_Print("NO %" Pd " %s - %s\n",
             info.call_instr->GetDeoptId(),
             info.inlined->ToQualifiedCString(),
             info.bailout_reason);
@@ -1043,7 +1043,7 @@
   void InlineStaticCalls() {
     const GrowableArray<CallSites::StaticCallInfo>& call_info =
         inlining_call_sites_->static_calls();
-    TRACE_INLINING(ISL_Print("  Static Calls (%" Pd ")\n", call_info.length()));
+    TRACE_INLINING(THR_Print("  Static Calls (%" Pd ")\n", call_info.length()));
     for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) {
       StaticCallInstr* call = call_info[call_idx].call;
       if (call->function().name() == Symbols::ListFactory().raw()) {
@@ -1061,7 +1061,7 @@
       const Function& target = call->function();
       if (!inliner_->AlwaysInline(target) &&
           (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
-        TRACE_INLINING(ISL_Print(
+        TRACE_INLINING(THR_Print(
             "  => %s (deopt count %d)\n     Bailout: cold %f\n",
             target.ToCString(),
             target.deoptimization_counter(),
@@ -1086,7 +1086,7 @@
   void InlineClosureCalls() {
     const GrowableArray<CallSites::ClosureCallInfo>& call_info =
         inlining_call_sites_->closure_calls();
-    TRACE_INLINING(ISL_Print("  Closure Calls (%" Pd ")\n",
+    TRACE_INLINING(THR_Print("  Closure Calls (%" Pd ")\n",
         call_info.length()));
     for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) {
       ClosureCallInstr* call = call_info[call_idx].call;
@@ -1108,7 +1108,7 @@
       }
 
       if (target.IsNull()) {
-        TRACE_INLINING(ISL_Print("     Bailout: non-closure operator\n"));
+        TRACE_INLINING(THR_Print("     Bailout: non-closure operator\n"));
         continue;
       }
       GrowableArray<Value*> arguments(call->ArgumentCount());
@@ -1129,7 +1129,7 @@
   void InlineInstanceCalls() {
     const GrowableArray<CallSites::InstanceCallInfo>& call_info =
         inlining_call_sites_->instance_calls();
-    TRACE_INLINING(ISL_Print("  Polymorphic Instance Calls (%" Pd ")\n",
+    TRACE_INLINING(THR_Print("  Polymorphic Instance Calls (%" Pd ")\n",
                              call_info.length()));
     for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) {
       PolymorphicInstanceCallInstr* call = call_info[call_idx].call;
@@ -1148,7 +1148,7 @@
       const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
       if (!inliner_->AlwaysInline(target) &&
           (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
-        TRACE_INLINING(ISL_Print(
+        TRACE_INLINING(THR_Print(
             "  => %s (deopt count %d)\n     Bailout: cold %f\n",
             target.ToCString(),
             target.deoptimization_counter(),
@@ -1829,7 +1829,7 @@
   const char* kAlwaysInlineAnnotation = "AlwaysInline";
   if (FLAG_enable_inlining_annotations &&
       HasAnnotation(function, kAlwaysInlineAnnotation)) {
-    TRACE_INLINING(ISL_Print("AlwaysInline annotation for %s\n",
+    TRACE_INLINING(THR_Print("AlwaysInline annotation for %s\n",
                              function.ToCString()));
     return true;
   }
@@ -1857,11 +1857,11 @@
     return;
   }
 
-  TRACE_INLINING(ISL_Print("Inlining calls in %s\n", top.ToCString()));
+  TRACE_INLINING(THR_Print("Inlining calls in %s\n", top.ToCString()));
 
   if (trace_inlining() &&
       (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) {
-    ISL_Print("Before Inlining of %s\n", flow_graph_->
+    THR_Print("Before Inlining of %s\n", flow_graph_->
               function().ToFullyQualifiedCString());
     FlowGraphPrinter printer(*flow_graph_);
     printer.PrintBlocks();
@@ -1876,9 +1876,9 @@
   if (inliner.inlined()) {
     flow_graph_->DiscoverBlocks();
     if (trace_inlining()) {
-      ISL_Print("Inlining growth factor: %f\n", inliner.GrowthFactor());
+      THR_Print("Inlining growth factor: %f\n", inliner.GrowthFactor());
       if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) {
-        ISL_Print("After Inlining of %s\n", flow_graph_->
+        THR_Print("After Inlining of %s\n", flow_graph_->
                   function().ToFullyQualifiedCString());
         FlowGraphPrinter printer(*flow_graph_);
         printer.PrintBlocks();
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 95ea36e..54a571a 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -637,16 +637,16 @@
     EnsureSSATempIndex(graph, current_defn, replacement_defn);
 
     if (FLAG_trace_optimization) {
-      ISL_Print("Replacing v%" Pd " with v%" Pd "\n",
+      THR_Print("Replacing v%" Pd " with v%" Pd "\n",
                 current_defn->ssa_temp_index(),
                 replacement_defn->ssa_temp_index());
     }
   } else if (FLAG_trace_optimization) {
     if (current_defn == NULL) {
-      ISL_Print("Removing %s\n", current->DebugName());
+      THR_Print("Removing %s\n", current->DebugName());
     } else {
       ASSERT(!current_defn->HasUses());
-      ISL_Print("Removing v%" Pd ".\n", current_defn->ssa_temp_index());
+      THR_Print("Removing v%" Pd ".\n", current_defn->ssa_temp_index());
     }
   }
   iterator->RemoveCurrentFromGraph();
@@ -2337,7 +2337,7 @@
     const Class& cls = Class::Handle(Z, function.Owner());
     if (!thread()->cha()->HasOverride(cls, name)) {
       if (FLAG_trace_cha) {
-        ISL_Print("  **(CHA) Instance call needs no check, "
+        THR_Print("  **(CHA) Instance call needs no check, "
             "no overrides of '%s' '%s'\n",
             name.ToCString(), cls.ToCString());
       }
@@ -4036,7 +4036,7 @@
   if (!type_class.IsPrivate()) {
     if (FLAG_use_cha_deopt) {
       if (FLAG_trace_cha) {
-        ISL_Print("  **(CHA) Typecheck as class equality since no "
+        THR_Print("  **(CHA) Typecheck as class equality since no "
             "subclasses: %s\n",
             type_class.ToCString());
       }
@@ -4620,7 +4620,7 @@
     }
     if (!unboxed_field) {
       if (FLAG_trace_optimization || FLAG_trace_field_guards) {
-        ISL_Print("Disabling unboxing of %s\n", field.ToCString());
+        THR_Print("Disabling unboxing of %s\n", field.ToCString());
         if (!setter.IsNull()) {
           OS::Print("  setter usage count: %" Pd "\n", setter.usage_counter());
         }
@@ -4849,7 +4849,7 @@
     }
 
     if (FLAG_trace_smi_widening) {
-      ISL_Print("analysing candidate: %s\n", op->ToCString());
+      THR_Print("analysing candidate: %s\n", op->ToCString());
     }
     worklist.Clear();
     worklist.Add(op);
@@ -4861,14 +4861,14 @@
       Definition* defn = worklist.definitions()[j];
 
       if (FLAG_trace_smi_widening) {
-        ISL_Print("> %s\n", defn->ToCString());
+        THR_Print("> %s\n", defn->ToCString());
       }
 
       if (defn->IsBinarySmiOp() &&
           BenefitsFromWidening(defn->AsBinarySmiOp())) {
         gain++;
         if (FLAG_trace_smi_widening) {
-          ISL_Print("^ [%" Pd "] (o) %s\n", gain, defn->ToCString());
+          THR_Print("^ [%" Pd "] (o) %s\n", gain, defn->ToCString());
         }
       }
 
@@ -4886,7 +4886,7 @@
           // Mint operation produces untagged result. We avoid tagging.
           gain++;
           if (FLAG_trace_smi_widening) {
-            ISL_Print("^ [%" Pd "] (i) %s\n", gain, input->ToCString());
+            THR_Print("^ [%" Pd "] (i) %s\n", gain, input->ToCString());
           }
         } else if (defn_loop == loops[input->GetBlock()->preorder_number()] &&
                    (input->Type()->ToCid() == kSmiCid)) {
@@ -4897,7 +4897,7 @@
           // coalesced with untagging. Start coalescing them.
           gain--;
           if (FLAG_trace_smi_widening) {
-            ISL_Print("v [%" Pd "] (i) %s\n", gain, input->ToCString());
+            THR_Print("v [%" Pd "] (i) %s\n", gain, input->ToCString());
           }
         }
       }
@@ -4914,7 +4914,7 @@
           if (!instr->IsReturn() && !instr->IsPushArgument()) {
             gain--;
             if (FLAG_trace_smi_widening) {
-              ISL_Print("v [%" Pd "] (u) %s\n",
+              THR_Print("v [%" Pd "] (u) %s\n",
                         gain,
                         use->instruction()->ToCString());
             }
@@ -4932,14 +4932,14 @@
           // sign extension operation.
           gain++;
           if (FLAG_trace_smi_widening) {
-            ISL_Print("^ [%" Pd "] (u) %s\n",
+            THR_Print("^ [%" Pd "] (u) %s\n",
                       gain,
                       use->instruction()->ToCString());
           }
         } else if (defn_loop == loops[instr->GetBlock()->preorder_number()]) {
           gain--;
           if (FLAG_trace_smi_widening) {
-            ISL_Print("v [%" Pd "] (u) %s\n",
+            THR_Print("v [%" Pd "] (u) %s\n",
                       gain,
                       use->instruction()->ToCString());
           }
@@ -4950,7 +4950,7 @@
     processed->AddAll(worklist.contains_vector());
 
     if (FLAG_trace_smi_widening) {
-      ISL_Print("~ %s gain %" Pd "\n", op->ToCString(), gain);
+      THR_Print("~ %s gain %" Pd "\n", op->ToCString(), gain);
     }
 
     if (gain > 0) {
@@ -5078,7 +5078,7 @@
     current->AsCheckArrayBound()->set_licm_hoisted(true);
   }
   if (FLAG_trace_optimization) {
-    ISL_Print("Hoisting instruction %s:%" Pd " from B%" Pd " to B%" Pd "\n",
+    THR_Print("Hoisting instruction %s:%" Pd " from B%" Pd " to B%" Pd "\n",
               current->DebugName(),
               current->GetDeoptId(),
               current->GetBlock()->block_id(),
@@ -5895,9 +5895,9 @@
          !it.Done();
          it.Advance()) {
       if (comma) {
-        ISL_Print(", ");
+        THR_Print(", ");
       }
-      ISL_Print("%s", places_[it.Current()]->ToCString());
+      THR_Print("%s", places_[it.Current()]->ToCString());
       comma = true;
     }
   }
@@ -5992,16 +5992,16 @@
     }
 
     if (FLAG_trace_load_optimization) {
-      ISL_Print("Aliases KILL sets:\n");
+      THR_Print("Aliases KILL sets:\n");
       for (intptr_t i = 0; i < aliases_.length(); ++i) {
         const Place* alias = aliases_[i];
         BitVector* kill = GetKilledSet(alias->id());
 
-        ISL_Print("%s: ", alias->ToCString());
+        THR_Print("%s: ", alias->ToCString());
         if (kill != NULL) {
           PrintSet(kill);
         }
-        ISL_Print("\n");
+        THR_Print("\n");
       }
     }
   }
@@ -6388,7 +6388,7 @@
       BlockEntryInstr* block = phi->GetBlock();
 
       if (FLAG_trace_optimization) {
-        ISL_Print("phi dependent place %s\n", place->ToCString());
+        THR_Print("phi dependent place %s\n", place->ToCString());
       }
 
       Place input_place(*place);
@@ -6401,7 +6401,7 @@
           map->Insert(result);
           places->Add(result);
           if (FLAG_trace_optimization) {
-            ISL_Print("  adding place %s as %" Pd "\n",
+            THR_Print("  adding place %s as %" Pd "\n",
                       result->ToCString(),
                       result->id());
           }
@@ -6457,7 +6457,7 @@
         places->Add(result);
 
         if (FLAG_trace_optimization) {
-          ISL_Print("numbering %s as %" Pd "\n",
+          THR_Print("numbering %s as %" Pd "\n",
                     result->ToCString(),
                     result->id());
         }
@@ -6726,7 +6726,7 @@
           Definition* replacement = (*out_values)[place_id];
           EnsureSSATempIndex(graph_, defn, replacement);
           if (FLAG_trace_optimization) {
-            ISL_Print("Replacing load v%" Pd " with v%" Pd "\n",
+            THR_Print("Replacing load v%" Pd " with v%" Pd "\n",
                       defn->ssa_temp_index(),
                       replacement->ssa_temp_index());
           }
@@ -6934,18 +6934,18 @@
       }
 
       if (FLAG_trace_load_optimization) {
-        ISL_Print("B%" Pd "\n", block->block_id());
-        ISL_Print("  IN: ");
+        THR_Print("B%" Pd "\n", block->block_id());
+        THR_Print("  IN: ");
         aliased_set_->PrintSet(in_[preorder_number]);
-        ISL_Print("\n");
+        THR_Print("\n");
 
-        ISL_Print("  KILL: ");
+        THR_Print("  KILL: ");
         aliased_set_->PrintSet(kill_[preorder_number]);
-        ISL_Print("\n");
+        THR_Print("\n");
 
-        ISL_Print("  OUT: ");
+        THR_Print("  OUT: ");
         aliased_set_->PrintSet(out_[preorder_number]);
-        ISL_Print("\n");
+        THR_Print("\n");
       }
     }
 
@@ -6998,7 +6998,7 @@
 
       if (FLAG_trace_optimization) {
         for (BitVector::Iterator it(loop_gen); !it.Done(); it.Advance()) {
-          ISL_Print("place %s is loop invariant for B%" Pd "\n",
+          THR_Print("place %s is loop invariant for B%" Pd "\n",
                     aliased_set_->places()[it.Current()]->ToCString(),
                     header->block_id());
         }
@@ -7069,7 +7069,7 @@
     phis_.Add(phi);  // Postpone phi insertion until after load forwarding.
 
     if (FLAG_trace_load_optimization) {
-      ISL_Print("created pending phi %s for %s at B%" Pd "\n",
+      THR_Print("created pending phi %s for %s at B%" Pd "\n",
                 phi->ToCString(),
                 aliased_set_->places()[place_id]->ToCString(),
                 block->block_id());
@@ -7108,7 +7108,7 @@
           EnsureSSATempIndex(graph_, load, replacement);
 
           if (FLAG_trace_optimization) {
-            ISL_Print("Replacing load v%" Pd " with v%" Pd "\n",
+            THR_Print("Replacing load v%" Pd " with v%" Pd "\n",
                       load->ssa_temp_index(),
                       replacement->ssa_temp_index());
           }
@@ -7297,7 +7297,7 @@
       }
 
       if (FLAG_trace_load_optimization) {
-        ISL_Print("Replacing %s with congruent %s\n",
+        THR_Print("Replacing %s with congruent %s\n",
                   a->ToCString(),
                   b->ToCString());
       }
@@ -7503,7 +7503,7 @@
             if (!live_in->Contains(instr->place_id()) &&
                 CanEliminateStore(instr)) {
               if (FLAG_trace_optimization) {
-                ISL_Print(
+                THR_Print(
                     "Removing dead store to place %" Pd " in block B%" Pd "\n",
                     instr->place_id(), block->block_id());
               }
@@ -7556,7 +7556,7 @@
     }
     if (FLAG_trace_load_optimization) {
       Dump();
-      ISL_Print("---\n");
+      THR_Print("---\n");
     }
   }
 
@@ -7590,7 +7590,7 @@
         if (!live_out->Contains(instr->place_id()) &&
             CanEliminateStore(instr)) {
           if (FLAG_trace_optimization) {
-            ISL_Print("Removing dead store to place %" Pd " block B%" Pd "\n",
+            THR_Print("Removing dead store to place %" Pd " block B%" Pd "\n",
                       instr->place_id(), block->block_id());
           }
           instr->RemoveFromGraph(/* ignored */ false);
@@ -7684,14 +7684,14 @@
             phi->UnuseAllInputs();
             (*join->phis_)[i] = NULL;
             if (FLAG_trace_optimization) {
-              ISL_Print("Removing dead phi v%" Pd "\n", phi->ssa_temp_index());
+              THR_Print("Removing dead phi v%" Pd "\n", phi->ssa_temp_index());
             }
           } else if (phi->IsRedundant()) {
             phi->ReplaceUsesWith(phi->InputAt(0)->definition());
             phi->UnuseAllInputs();
             (*join->phis_)[i] = NULL;
             if (FLAG_trace_optimization) {
-              ISL_Print("Removing redundant phi v%" Pd "\n",
+              THR_Print("Removing redundant phi v%" Pd "\n",
                          phi->ssa_temp_index());
             }
           } else {
@@ -8234,7 +8234,7 @@
        use = use->next_use()) {
     if (!IsSafeUse(use, check_type)) {
       if (FLAG_trace_optimization) {
-        ISL_Print("use of %s at %s is unsafe for allocation sinking\n",
+        THR_Print("use of %s at %s is unsafe for allocation sinking\n",
                   alloc->ToCString(),
                   use->instruction()->ToCString());
       }
@@ -8264,7 +8264,7 @@
   ASSERT(IsAllocationSinkingCandidate(alloc, kStrictCheck));
 
   if (FLAG_trace_optimization) {
-    ISL_Print("removing allocation from the graph: v%" Pd "\n",
+    THR_Print("removing allocation from the graph: v%" Pd "\n",
               alloc->ssa_temp_index());
   }
 
@@ -8345,7 +8345,7 @@
     Definition* alloc = candidates_[i];
     if (alloc->Identity().IsAllocationSinkingCandidate()) {
       if (FLAG_trace_optimization) {
-        ISL_Print("discovered allocation sinking candidate: v%" Pd "\n",
+        THR_Print("discovered allocation sinking candidate: v%" Pd "\n",
                   alloc->ssa_temp_index());
       }
 
@@ -8440,7 +8440,7 @@
     Definition* alloc = candidates_[i];
     if (!alloc->Identity().IsAllocationSinkingCandidate()) {
       if (FLAG_trace_optimization) {
-        ISL_Print("allocation v%" Pd " can't be eliminated\n",
+        THR_Print("allocation v%" Pd " can't be eliminated\n",
                   alloc->ssa_temp_index());
       }
 
diff --git a/runtime/vm/flow_graph_range_analysis.cc b/runtime/vm/flow_graph_range_analysis.cc
index cd45479..9016d1c 100644
--- a/runtime/vm/flow_graph_range_analysis.cc
+++ b/runtime/vm/flow_graph_range_analysis.cc
@@ -184,7 +184,7 @@
         InductionVariableInfo* info = DetectSimpleInductionVariable(current);
         if (info != NULL) {
           if (FLAG_trace_range_analysis) {
-            ISL_Print("Simple loop variable: %s bound <%s>\n",
+            THR_Print("Simple loop variable: %s bound <%s>\n",
                        current->ToCString(),
                        info->limit() != NULL ?
                            info->limit()->ToCString() : "?");
@@ -694,7 +694,7 @@
 
     if (!range.Equals(defn->range())) {
       if (FLAG_trace_range_analysis) {
-        ISL_Print("%c [%" Pd "] %s:  %s => %s\n",
+        THR_Print("%c [%" Pd "] %s:  %s => %s\n",
                   OpPrefix(op),
                   iteration,
                   defn->ToCString(),
@@ -997,7 +997,7 @@
     if (upper_bound == UnwrapConstraint(check->index()->definition())) {
       // Unable to construct upper bound for the index.
       if (FLAG_trace_range_analysis) {
-        ISL_Print("Failed to construct upper bound for %s index\n",
+        THR_Print("Failed to construct upper bound for %s index\n",
                   check->ToCString());
       }
       return;
@@ -1008,7 +1008,7 @@
     // upper bound through scheduler.
     if (!Simplify(&upper_bound, NULL)) {
       if (FLAG_trace_range_analysis) {
-        ISL_Print("Failed to simplify upper bound for %s index\n",
+        THR_Print("Failed to simplify upper bound for %s index\n",
                   check->ToCString());
       }
       return;
@@ -1023,7 +1023,7 @@
     GrowableArray<Definition*> non_positive_symbols;
     if (!FindNonPositiveSymbols(&non_positive_symbols, upper_bound)) {
       if (FLAG_trace_range_analysis) {
-        ISL_Print("Failed to generalize %s index to %s"
+        THR_Print("Failed to generalize %s index to %s"
                   " (can't ensure positivity)\n",
                   check->ToCString(),
                   IndexBoundToCString(upper_bound));
@@ -1057,7 +1057,7 @@
       // Can't prove that lower bound is positive even with additional checks
       // against potentially non-positive symbols. Give up.
       if (FLAG_trace_range_analysis) {
-        ISL_Print("Failed to generalize %s index to %s"
+        THR_Print("Failed to generalize %s index to %s"
                   " (lower bound is not positive)\n",
                   check->ToCString(),
                   IndexBoundToCString(upper_bound));
@@ -1066,7 +1066,7 @@
     }
 
     if (FLAG_trace_range_analysis) {
-      ISL_Print("For %s computed index bounds [%s, %s]\n",
+      THR_Print("For %s computed index bounds [%s, %s]\n",
                 check->ToCString(),
                 IndexBoundToCString(lower_bound),
                 IndexBoundToCString(upper_bound));
@@ -1087,7 +1087,7 @@
       precondition = scheduler_.Emit(precondition, check);
       if (precondition == NULL) {
         if (FLAG_trace_range_analysis) {
-          ISL_Print("  => failed to insert positivity constraint\n");
+          THR_Print("  => failed to insert positivity constraint\n");
         }
         scheduler_.Rollback();
         return;
@@ -1101,7 +1101,7 @@
     new_check->mark_generalized();
     if (new_check->IsRedundant(array_length)) {
       if (FLAG_trace_range_analysis) {
-        ISL_Print("  => generalized check is redundant\n");
+        THR_Print("  => generalized check is redundant\n");
       }
       RemoveGeneralizedCheck(check);
       return;
@@ -1110,13 +1110,13 @@
     new_check = scheduler_.Emit(new_check, check);
     if (new_check != NULL) {
       if (FLAG_trace_range_analysis) {
-        ISL_Print("  => generalized check was hoisted into B%" Pd "\n",
+        THR_Print("  => generalized check was hoisted into B%" Pd "\n",
                   new_check->GetBlock()->block_id());
       }
       RemoveGeneralizedCheck(check);
     } else {
       if (FLAG_trace_range_analysis) {
-        ISL_Print("  => generalized check can't be hoisted\n");
+        THR_Print("  => generalized check can't be hoisted\n");
       }
       scheduler_.Rollback();
     }
@@ -1566,7 +1566,7 @@
       if (target == branch->true_successor()) {
         // True unreachable.
         if (FLAG_trace_constant_propagation) {
-          ISL_Print("Range analysis: True unreachable (B%" Pd ")\n",
+          THR_Print("Range analysis: True unreachable (B%" Pd ")\n",
                     branch->true_successor()->block_id());
         }
         branch->set_constant_target(branch->false_successor());
@@ -1574,7 +1574,7 @@
         ASSERT(target == branch->false_successor());
         // False unreachable.
         if (FLAG_trace_constant_propagation) {
-          ISL_Print("Range analysis: False unreachable (B%" Pd ")\n",
+          THR_Print("Range analysis: False unreachable (B%" Pd ")\n",
                     branch->false_successor()->block_id());
         }
         branch->set_constant_target(branch->true_successor());
@@ -1662,14 +1662,14 @@
 
 void IntegerInstructionSelector::Select() {
   if (FLAG_trace_integer_ir_selection) {
-    ISL_Print("---- starting integer ir selection -------\n");
+    THR_Print("---- starting integer ir selection -------\n");
   }
   FindPotentialUint32Definitions();
   FindUint32NarrowingDefinitions();
   Propagate();
   ReplaceInstructions();
   if (FLAG_trace_integer_ir_selection) {
-    ISL_Print("---- after integer ir selection -------\n");
+    THR_Print("---- after integer ir selection -------\n");
     FlowGraphPrinter printer(*flow_graph_);
     printer.PrintBlocks();
   }
@@ -1690,7 +1690,7 @@
 
 void IntegerInstructionSelector::FindPotentialUint32Definitions() {
   if (FLAG_trace_integer_ir_selection) {
-    ISL_Print("++++ Finding potential Uint32 definitions:\n");
+    THR_Print("++++ Finding potential Uint32 definitions:\n");
   }
 
   for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
@@ -1706,7 +1706,7 @@
       if ((defn != NULL) && defn->HasSSATemp()) {
         if (IsPotentialUint32Definition(defn)) {
           if (FLAG_trace_integer_ir_selection) {
-           ISL_Print("Adding %s\n", current->ToCString());
+           THR_Print("Adding %s\n", current->ToCString());
           }
           potential_uint32_defs_.Add(defn);
         }
@@ -1740,14 +1740,14 @@
 void IntegerInstructionSelector::FindUint32NarrowingDefinitions() {
   ASSERT(selected_uint32_defs_ != NULL);
   if (FLAG_trace_integer_ir_selection) {
-    ISL_Print("++++ Selecting Uint32 definitions:\n");
-    ISL_Print("++++ Initial set:\n");
+    THR_Print("++++ Selecting Uint32 definitions:\n");
+    THR_Print("++++ Initial set:\n");
   }
   for (intptr_t i = 0; i < potential_uint32_defs_.length(); i++) {
     Definition* defn = potential_uint32_defs_[i];
     if (IsUint32NarrowingDefinition(defn)) {
       if (FLAG_trace_integer_ir_selection) {
-        ISL_Print("Adding %s\n", defn->ToCString());
+        THR_Print("Adding %s\n", defn->ToCString());
       }
       selected_uint32_defs_->Add(defn->ssa_temp_index());
     }
@@ -1807,7 +1807,7 @@
   intptr_t iteration = 0;
   while (changed) {
     if (FLAG_trace_integer_ir_selection) {
-      ISL_Print("+++ Iteration: %" Pd "\n", iteration++);
+      THR_Print("+++ Iteration: %" Pd "\n", iteration++);
     }
     changed = false;
     for (intptr_t i = 0; i < potential_uint32_defs_.length(); i++) {
@@ -1822,7 +1822,7 @@
       }
       if (CanBecomeUint32(defn)) {
         if (FLAG_trace_integer_ir_selection) {
-          ISL_Print("Adding %s\n", defn->ToCString());
+          THR_Print("Adding %s\n", defn->ToCString());
         }
         // Found a new candidate.
         selected_uint32_defs_->Add(defn->ssa_temp_index());
@@ -1832,7 +1832,7 @@
     }
   }
   if (FLAG_trace_integer_ir_selection) {
-    ISL_Print("Reached fixed point\n");
+    THR_Print("Reached fixed point\n");
   }
 }
 
@@ -1879,7 +1879,7 @@
 
 void IntegerInstructionSelector::ReplaceInstructions() {
   if (FLAG_trace_integer_ir_selection) {
-    ISL_Print("++++ Replacing instructions:\n");
+    THR_Print("++++ Replacing instructions:\n");
   }
   for (intptr_t i = 0; i < potential_uint32_defs_.length(); i++) {
     Definition* defn = potential_uint32_defs_[i];
@@ -1890,7 +1890,7 @@
     Definition* replacement = ConstructReplacementFor(defn);
     ASSERT(replacement != NULL);
     if (FLAG_trace_integer_ir_selection) {
-      ISL_Print("Replacing %s with %s\n", defn->ToCString(),
+      THR_Print("Replacing %s with %s\n", defn->ToCString(),
                                           replacement->ToCString());
     }
     if (!Range::IsUnknown(defn->range())) {
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index c80005d..3448fd0 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -74,13 +74,13 @@
   while (!worklist_.is_empty()) {
     Definition* def = RemoveLastFromWorklist();
     if (FLAG_trace_type_propagation) {
-      ISL_Print("recomputing type of v%" Pd ": %s\n",
+      THR_Print("recomputing type of v%" Pd ": %s\n",
                 def->ssa_temp_index(),
                 def->Type()->ToCString());
     }
     if (def->RecomputeType()) {
       if (FLAG_trace_type_propagation) {
-        ISL_Print("  ... new type %s\n", def->Type()->ToCString());
+        THR_Print("  ... new type %s\n", def->Type()->ToCString());
       }
       for (Value::Iterator it(def->input_use_list());
            !it.Done();
@@ -267,7 +267,7 @@
   value->SetReachingType(type);
 
   if (FLAG_trace_type_propagation) {
-    ISL_Print("reaching type to v%" Pd " for v%" Pd " is %s\n",
+    THR_Print("reaching type to v%" Pd " for v%" Pd " is %s\n",
               value->instruction()->IsDefinition() ?
                   value->instruction()->AsDefinition()->ssa_temp_index() : -1,
               value->definition()->ssa_temp_index(),
@@ -552,7 +552,7 @@
           cid_ = type_class.id();
         } else if (FLAG_use_cha_deopt) {
           if (FLAG_trace_cha) {
-            ISL_Print("  **(CHA) Compile type not subclassed: %s\n",
+            THR_Print("  **(CHA) Compile type not subclassed: %s\n",
                 type_class.ToCString());
           }
           cha->AddToLeafClasses(type_class);
@@ -698,7 +698,7 @@
   CompileType result = CompileType::None();
   for (intptr_t i = 0; i < InputCount(); i++) {
     if (FLAG_trace_type_propagation) {
-      ISL_Print("  phi %" Pd " input %" Pd ": v%" Pd " has reaching type %s\n",
+      THR_Print("  phi %" Pd " input %" Pd ": v%" Pd " has reaching type %s\n",
                 ssa_temp_index(),
                 i,
                 InputAt(i)->definition()->ssa_temp_index(),
@@ -795,7 +795,7 @@
         } else {
           if (FLAG_use_cha_deopt) {
             if (FLAG_trace_cha) {
-              ISL_Print("  **(CHA) Computing exact type of parameters, "
+              THR_Print("  **(CHA) Computing exact type of parameters, "
                   "no subclasses: %s\n",
                   type_class.ToCString());
             }
diff --git a/runtime/vm/gc_marker.cc b/runtime/vm/gc_marker.cc
index 42a08bd..1d151d0 100644
--- a/runtime/vm/gc_marker.cc
+++ b/runtime/vm/gc_marker.cc
@@ -110,7 +110,7 @@
           // helper functions to the raw object interface.
           String name;
           name = func->ptr()->name_;
-          ISL_Print("Detaching code: %s\n", name.ToCString());
+          THR_Print("Detaching code: %s\n", name.ToCString());
           current_code_count++;
         }
       }
@@ -127,8 +127,8 @@
       }
     }
     if (FLAG_log_code_drop) {
-      ISL_Print("  total detached current: %" Pd "\n", current_code_count);
-      ISL_Print("  total detached unoptimized: %" Pd "\n",
+      THR_Print("  total detached current: %" Pd "\n", current_code_count);
+      THR_Print("  total detached unoptimized: %" Pd "\n",
                 unoptimized_code_count);
     }
     // Clean up.
@@ -700,11 +700,9 @@
       MarkingWeakVisitor mark_weak;
       IterateWeakRoots(isolate, &mark_weak,
                        !visit_prologue_weak_persistent_handles);
-      // TODO(koda): Move this into Phase 3 after making ISL_Print thread-safe
-      // (used in SkippedCodeFunctions::DetachCode).
-      FinalizeResultsFrom(&mark);
       MainSync(num_tasks);
       // Phase 3: Finalize results from all markers (detach code, etc.).
+      FinalizeResultsFrom(&mark);
       MainSync(num_tasks);
       // Finalization complete and all tasks exited.
     }
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index 9e0b653..c691b85 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -83,11 +83,11 @@
 
 
 void FlowGraphPrinter::PrintGraph(const char* phase, FlowGraph* flow_graph) {
-  LogBlock lb(Isolate::Current());
-  ISL_Print("*** BEGIN CFG\n%s\n", phase);
+  LogBlock lb;
+  THR_Print("*** BEGIN CFG\n%s\n", phase);
   FlowGraphPrinter printer(*flow_graph);
   printer.PrintBlocks();
-  ISL_Print("*** END CFG\n");
+  THR_Print("*** END CFG\n");
   fflush(stdout);
 }
 
@@ -96,19 +96,19 @@
                                   bool print_locations) {
   // Print the block entry.
   PrintOneInstruction(block, print_locations);
-  ISL_Print("\n");
+  THR_Print("\n");
   // And all the successors in the block.
   for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
     Instruction* current = it.Current();
     PrintOneInstruction(current, print_locations);
-    ISL_Print("\n");
+    THR_Print("\n");
   }
 }
 
 
 void FlowGraphPrinter::PrintBlocks() {
   if (!function_.IsNull()) {
-    ISL_Print("==== %s\n", function_.ToFullyQualifiedCString());
+    THR_Print("==== %s\n", function_.ToFullyQualifiedCString());
   }
 
   for (intptr_t i = 0; i < block_order_.length(); ++i) {
@@ -134,12 +134,12 @@
     instr->locs()->PrintTo(&f);
   }
   if (instr->lifetime_position() != -1) {
-    ISL_Print("%3" Pd ": ", instr->lifetime_position());
+    THR_Print("%3" Pd ": ", instr->lifetime_position());
   }
-  if (!instr->IsBlockEntry()) ISL_Print("    ");
-  ISL_Print("%s", str);
+  if (!instr->IsBlockEntry()) THR_Print("    ");
+  THR_Print("%s", str);
   if (FLAG_trace_inlining_intervals) {
-    ISL_Print(" iid: %" Pd "", instr->inlining_id());
+    THR_Print(" iid: %" Pd "", instr->inlining_id());
   }
 }
 
@@ -154,7 +154,7 @@
     if (value != NULL && value->reaching_type_ != NULL) {
       compile_type_name = value->reaching_type_->ToCString();
     }
-    ISL_Print("%s type check: compile type %s is %s specific than "
+    THR_Print("%s type check: compile type %s is %s specific than "
               "type '%s' of '%s'.\n",
                          eliminated ? "Eliminated" : "Generated",
                          compile_type_name,
@@ -228,9 +228,9 @@
   char buffer[1024];
   BufferFormatter f(buffer, sizeof(buffer));
   PrintICDataHelper(&f, ic_data);
-  ISL_Print("%s ", buffer);
+  THR_Print("%s ", buffer);
   const Array& a = Array::Handle(ic_data.arguments_descriptor());
-  ISL_Print(" arg-desc %" Pd "\n", a.Length());
+  THR_Print(" arg-desc %" Pd "\n", a.Length());
 }
 
 
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 8754ecf..b8db54d 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -37,6 +37,8 @@
     "Generate special IC stubs for two args Smi operations");
 DEFINE_FLAG(bool, unbox_numeric_fields, true,
     "Support unboxed double and float32x4 fields.");
+DEFINE_FLAG(bool, fields_may_be_reset, false,
+            "Don't optimize away static field initialization");
 DECLARE_FLAG(bool, eliminate_type_checks);
 DECLARE_FLAG(bool, trace_optimization);
 DECLARE_FLAG(bool, throw_on_javascript_int_overflow);
@@ -385,7 +387,11 @@
   const bool is_initialized =
       (field_.StaticValue() != Object::sentinel().raw()) &&
       (field_.StaticValue() != Object::transition_sentinel().raw());
-  return is_initialized ? NULL : this;
+  // When precompiling, the fact that a field is currently initialized does not
+  // make it safe to omit code that checks if the field needs initialization
+  // because the field will be reset so it starts uninitialized in the process
+  // running the precompiled code. We must be prepared to reinitialize fields.
+  return is_initialized && !FLAG_fields_may_be_reset ? NULL : this;
 }
 
 
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index bc4ba3c..45ec027 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -24,6 +24,7 @@
 
 namespace dart {
 
+DECLARE_FLAG(bool, allow_absolute_addresses);
 DECLARE_FLAG(bool, emit_edge_counters);
 DECLARE_FLAG(int, optimization_counter_threshold);
 DECLARE_FLAG(bool, use_osr);
@@ -947,7 +948,7 @@
     entry = reinterpret_cast<uword>(&NativeEntry::LinkNativeCall);
 #if defined(USING_SIMULATOR)
     entry = Simulator::RedirectExternalReference(
-        entry, Simulator::kBootstrapNativeCall, function().NumParameters());
+        entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments);
 #endif
   } else {
     entry = reinterpret_cast<uword>(native_c_function());
@@ -955,7 +956,7 @@
       stub_entry = StubCode::CallBootstrapCFunction_entry();
 #if defined(USING_SIMULATOR)
       entry = Simulator::RedirectExternalReference(
-          entry, Simulator::kBootstrapNativeCall, function().NumParameters());
+          entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments);
 #endif
     } else {
       // In the case of non bootstrap native methods the CallNativeCFunction
@@ -965,14 +966,14 @@
 #if defined(USING_SIMULATOR)
       if (!function().IsNativeAutoSetupScope()) {
         entry = Simulator::RedirectExternalReference(
-            entry, Simulator::kBootstrapNativeCall, function().NumParameters());
+            entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments);
       }
 #endif
     }
   }
   __ LoadImmediate(R1, argc_tag);
   ExternalLabel label(entry);
-  __ LoadExternalLabel(R5, &label, link_lazily() ? kPatchable : kNotPatchable);
+  __ LoadNativeEntry(R5, &label, link_lazily() ? kPatchable : kNotPatchable);
   compiler->GenerateCall(token_pos(),
                          *stub_entry,
                          RawPcDescriptors::kOther,
@@ -1703,8 +1704,7 @@
         if (field_cid != kSmiCid) {
           __ CompareImmediate(value_cid_reg, kNullCid);
         } else {
-          __ CompareImmediate(value_reg,
-                              reinterpret_cast<intptr_t>(Object::null()));
+          __ CompareObject(value_reg, Object::null_object());
         }
       }
       __ b(fail, NE);
@@ -2034,8 +2034,7 @@
                              Register temp) {
   Label done;
   __ ldr(box_reg, FieldAddress(instance_reg, offset));
-  __ CompareImmediate(box_reg,
-                      reinterpret_cast<intptr_t>(Object::null()));
+  __ CompareObject(box_reg, Object::null_object());
   __ b(&done, NE);
 
   BoxAllocationSlowPath::Allocate(
@@ -2352,7 +2351,7 @@
   // R6: null
   if (num_elements > 0) {
     const intptr_t array_size = instance_size - sizeof(RawArray);
-    __ LoadImmediate(R6, reinterpret_cast<intptr_t>(Object::null()));
+    __ LoadObject(R6, Object::null_object());
     if (num_elements >= 2) {
       __ mov(R7, Operand(R6));
     } else {
@@ -2621,7 +2620,7 @@
   Label type_arguments_instantiated;
   const intptr_t len = type_arguments().Length();
   if (type_arguments().IsRawInstantiatedRaw(len)) {
-    __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null()));
+    __ LoadObject(IP, Object::null_object());
     __ cmp(instantiator_reg, Operand(IP));
     __ b(&type_arguments_instantiated, EQ);
   }
@@ -2886,6 +2885,7 @@
       const Register value = instruction_->locs()->temp(0).reg();
       __ Comment("CheckStackOverflowSlowPathOsr");
       __ Bind(osr_entry_label());
+      ASSERT(FLAG_allow_absolute_addresses);
       __ LoadImmediate(IP, flags_address);
       __ LoadImmediate(value, Isolate::kOsrRequest);
       __ str(value, Address(IP));
@@ -2930,7 +2930,7 @@
   CheckStackOverflowSlowPath* slow_path = new CheckStackOverflowSlowPath(this);
   compiler->AddSlowPathCode(slow_path);
 
-  if (compiler->is_optimizing()) {
+  if (compiler->is_optimizing() && FLAG_allow_absolute_addresses) {
     __ LoadImmediate(IP, Isolate::Current()->stack_limit_address());
     __ ldr(IP, Address(IP));
   } else {
@@ -3757,7 +3757,7 @@
 
     if ((value()->Type()->ToNullableCid() == box_cid) &&
         value()->Type()->is_nullable()) {
-      __ CompareImmediate(box, reinterpret_cast<intptr_t>(Object::null()));
+      __ CompareObject(box, Object::null_object());
       __ b(deopt, EQ);
     } else {
       __ tst(box, Operand(kSmiTagMask));
@@ -5916,8 +5916,7 @@
                                         ICData::kDeoptCheckClass,
                                         licm_hoisted_ ? ICData::kHoisted : 0);
   if (IsNullCheck()) {
-    __ CompareImmediate(locs()->in(0).reg(),
-                        reinterpret_cast<intptr_t>(Object::null()));
+    __ CompareObject(locs()->in(0).reg(), Object::null_object());
     ASSERT(DeoptIfNull() || DeoptIfNotNull());
     Condition cond = DeoptIfNull() ? EQ : NE;
     __ b(deopt, cond);
diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc
index 8c87b54..7ae62c0 100644
--- a/runtime/vm/intermediate_language_arm64.cc
+++ b/runtime/vm/intermediate_language_arm64.cc
@@ -23,6 +23,7 @@
 
 namespace dart {
 
+DECLARE_FLAG(bool, allow_absolute_addresses);
 DECLARE_FLAG(bool, emit_edge_counters);
 DECLARE_FLAG(int, optimization_counter_threshold);
 DECLARE_FLAG(bool, use_osr);
@@ -800,7 +801,7 @@
     entry = reinterpret_cast<uword>(&NativeEntry::LinkNativeCall);
 #if defined(USING_SIMULATOR)
     entry = Simulator::RedirectExternalReference(
-        entry, Simulator::kBootstrapNativeCall, function().NumParameters());
+        entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments);
 #endif
   } else {
     entry = reinterpret_cast<uword>(native_c_function());
@@ -808,7 +809,7 @@
       stub_entry = StubCode::CallBootstrapCFunction_entry();
 #if defined(USING_SIMULATOR)
       entry = Simulator::RedirectExternalReference(
-          entry, Simulator::kBootstrapNativeCall, function().NumParameters());
+          entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments);
 #endif
     } else {
       // In the case of non bootstrap native methods the CallNativeCFunction
@@ -818,14 +819,14 @@
 #if defined(USING_SIMULATOR)
       if (!function().IsNativeAutoSetupScope()) {
         entry = Simulator::RedirectExternalReference(
-            entry, Simulator::kBootstrapNativeCall, function().NumParameters());
+            entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments);
       }
 #endif
     }
   }
   __ LoadImmediate(R1, argc_tag);
   ExternalLabel label(entry);
-  __ LoadExternalLabel(R5, &label);
+  __ LoadNativeEntry(R5, &label);
   compiler->GenerateCall(token_pos(),
                          *stub_entry,
                          RawPcDescriptors::kOther,
@@ -2598,6 +2599,7 @@
       const Register value = instruction_->locs()->temp(0).reg();
       __ Comment("CheckStackOverflowSlowPathOsr");
       __ Bind(osr_entry_label());
+      ASSERT(FLAG_allow_absolute_addresses);
       __ LoadImmediate(TMP, flags_address);
       __ LoadImmediate(value, Isolate::kOsrRequest);
       __ str(value, Address(TMP));
@@ -2642,7 +2644,7 @@
   CheckStackOverflowSlowPath* slow_path = new CheckStackOverflowSlowPath(this);
   compiler->AddSlowPathCode(slow_path);
 
-  if (compiler->is_optimizing()) {
+  if (compiler->is_optimizing() && FLAG_allow_absolute_addresses) {
     __ LoadImmediate(TMP, Isolate::Current()->stack_limit_address());
     __ ldr(TMP, Address(TMP));
   } else {
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index eb7d932..fe30067 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -23,6 +23,7 @@
 
 namespace dart {
 
+DECLARE_FLAG(bool, allow_absolute_addresses);
 DECLARE_FLAG(bool, emit_edge_counters);
 DECLARE_FLAG(int, optimization_counter_threshold);
 DECLARE_FLAG(bool, use_osr);
@@ -998,7 +999,7 @@
     entry = reinterpret_cast<uword>(&NativeEntry::LinkNativeCall);
 #if defined(USING_SIMULATOR)
     entry = Simulator::RedirectExternalReference(
-        entry, Simulator::kBootstrapNativeCall, function().NumParameters());
+      entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments);
 #endif
   } else {
     entry = reinterpret_cast<uword>(native_c_function());
@@ -1006,7 +1007,7 @@
       stub_entry = StubCode::CallBootstrapCFunction_entry();
 #if defined(USING_SIMULATOR)
       entry = Simulator::RedirectExternalReference(
-          entry, Simulator::kBootstrapNativeCall, function().NumParameters());
+          entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments);
 #endif
     } else {
       // In the case of non bootstrap native methods the CallNativeCFunction
@@ -1016,14 +1017,14 @@
 #if defined(USING_SIMULATOR)
       if (!function().IsNativeAutoSetupScope()) {
         entry = Simulator::RedirectExternalReference(
-            entry, Simulator::kBootstrapNativeCall, function().NumParameters());
+            entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments);
       }
 #endif
     }
   }
   __ LoadImmediate(A1, argc_tag);
   ExternalLabel label(entry);
-  __ LoadExternalLabel(T5, &label, kNotPatchable);
+  __ LoadNativeEntry(T5, &label, kNotPatchable);
   compiler->GenerateCall(token_pos(),
                          *stub_entry,
                          RawPcDescriptors::kOther,
@@ -1737,7 +1738,7 @@
           __ LoadImmediate(TMP, kNullCid);
           __ subu(CMPRES1, value_cid_reg, TMP);
         } else {
-          __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null()));
+          __ LoadObject(TMP, Object::null_object());
           __ subu(CMPRES1, value_reg, TMP);
         }
       }
@@ -2204,7 +2205,7 @@
   // T7: null.
   if (num_elements > 0) {
     const intptr_t array_size = instance_size - sizeof(RawArray);
-    __ LoadImmediate(T7, reinterpret_cast<int32_t>(Object::null()));
+    __ LoadObject(T7, Object::null_object());
     __ AddImmediate(T2, V0, sizeof(RawArray) - kHeapObjectTag);
     if (array_size < (kInlineArraySize * kWordSize)) {
       intptr_t current_offset = 0;
@@ -2715,6 +2716,7 @@
       Register value = instruction_->locs()->temp(0).reg();
       __ Comment("CheckStackOverflowSlowPathOsr");
       __ Bind(osr_entry_label());
+      ASSERT(FLAG_allow_absolute_addresses);
       __ LoadImmediate(TMP, flags_address);
       __ LoadImmediate(value, Isolate::kOsrRequest);
       __ sw(value, Address(TMP));
@@ -2760,7 +2762,7 @@
   CheckStackOverflowSlowPath* slow_path = new CheckStackOverflowSlowPath(this);
   compiler->AddSlowPathCode(slow_path);
 
-  if (compiler->is_optimizing()) {
+  if (compiler->is_optimizing() && FLAG_allow_absolute_addresses) {
     __ LoadImmediate(TMP, Isolate::Current()->stack_limit_address());
     __ lw(CMPRES1, Address(TMP));
   } else {
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 4955df6..19fc8b3 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -22,6 +22,7 @@
 
 namespace dart {
 
+DECLARE_FLAG(bool, allow_absolute_addresses);
 DECLARE_FLAG(bool, emit_edge_counters);
 DECLARE_FLAG(int, optimization_counter_threshold);
 DECLARE_FLAG(bool, throw_on_javascript_int_overflow);
@@ -785,14 +786,14 @@
   const StubEntry* stub_entry;
   if (link_lazily()) {
     stub_entry = StubCode::CallBootstrapCFunction_entry();
-    __ LoadExternalLabel(
+    __ LoadNativeEntry(
         RBX, &NativeEntry::LinkNativeCallLabel(), kPatchable);
   } else {
     stub_entry = (is_bootstrap_native() || is_leaf_call)
         ? StubCode::CallBootstrapCFunction_entry()
         : StubCode::CallNativeCFunction_entry();
     const ExternalLabel label(reinterpret_cast<uword>(native_c_function()));
-    __ LoadExternalLabel(RBX, &label, kNotPatchable);
+    __ LoadNativeEntry(RBX, &label, kNotPatchable);
   }
   compiler->GenerateCall(token_pos(),
                          *stub_entry,
@@ -2600,6 +2601,7 @@
       Register temp = instruction_->locs()->temp(0).reg();
       __ Comment("CheckStackOverflowSlowPathOsr");
       __ Bind(osr_entry_label());
+      ASSERT(FLAG_allow_absolute_addresses);
       __ LoadImmediate(temp, Immediate(flags_address));
       __ movq(Address(temp, 0), Immediate(Isolate::kOsrRequest));
     }
@@ -2646,7 +2648,7 @@
 
   Register temp = locs()->temp(0).reg();
   // Generate stack overflow check.
-  if (compiler->is_optimizing()) {
+  if (compiler->is_optimizing() && FLAG_allow_absolute_addresses) {
     __ LoadImmediate(
         temp, Immediate(Isolate::Current()->stack_limit_address()));
     __ cmpq(RSP, Address(temp, 0));
@@ -3405,9 +3407,7 @@
 
     if ((value()->Type()->ToNullableCid() == box_cid) &&
         value()->Type()->is_nullable()) {
-      const Immediate& raw_null =
-          Immediate(reinterpret_cast<intptr_t>(Object::null()));
-      __ cmpq(box, raw_null);
+      __ CompareObject(box, Object::null_object());
       __ j(EQUAL, deopt);
     } else {
       __ testq(box, Immediate(kSmiTagMask));
diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc
index ffeda36..5e24dd3 100644
--- a/runtime/vm/intrinsifier.cc
+++ b/runtime/vm/intrinsifier.cc
@@ -155,7 +155,7 @@
   }
 
   if (FLAG_print_flow_graph && FlowGraphPrinter::ShouldPrint(function)) {
-    ISL_Print("Intrinsic graph before\n");
+    THR_Print("Intrinsic graph before\n");
     FlowGraphPrinter printer(*graph);
     printer.PrintBlocks();
   }
@@ -165,7 +165,7 @@
   allocator.AllocateRegisters();
 
   if (FLAG_print_flow_graph && FlowGraphPrinter::ShouldPrint(function)) {
-    ISL_Print("Intrinsic graph after\n");
+    THR_Print("Intrinsic graph after\n");
     FlowGraphPrinter printer(*graph);
     printer.PrintBlocks();
   }
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 2618ef9..7d3421d 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -56,19 +56,18 @@
     const intptr_t type_args_field_offset =
         ComputeObjectArrayTypeArgumentsOffset();
     // Inline simple tests (Smi, null), fallthrough if not positive.
-    const int32_t raw_null = reinterpret_cast<intptr_t>(Object::null());
     Label checked_ok;
     __ ldr(R2, Address(SP, 0 * kWordSize));  // Value.
 
     // Null value is valid for any type.
-    __ CompareImmediate(R2, raw_null);
+    __ CompareObject(R2, Object::null_object());
     __ b(&checked_ok, EQ);
 
     __ ldr(R1, Address(SP, 2 * kWordSize));  // Array.
     __ ldr(R1, FieldAddress(R1, type_args_field_offset));
 
     // R1: Type arguments of array.
-    __ CompareImmediate(R1, raw_null);
+    __ CompareObject(R1, Object::null_object());
     __ b(&checked_ok, EQ);
 
     // Check if it's dynamic.
@@ -179,8 +178,7 @@
   ASSERT(kSmiTagShift == 1);
   __ add(R1, R2, Operand(R1, LSL, 1));
   __ StoreIntoObject(R2, FieldAddress(R1, Array::data_offset()), R0);
-  const int32_t raw_null = reinterpret_cast<int32_t>(Object::null());
-  __ LoadImmediate(R0, raw_null);
+  __ LoadObject(R0, Object::null_object());
   __ Ret();
   __ Bind(&fall_through);
 }
@@ -1587,7 +1585,7 @@
   __ LoadClassById(R2, R1);
   // R2: class of instance (R0).
   __ ldr(R3, FieldAddress(R2, Class::signature_function_offset()));
-  __ CompareImmediate(R3, reinterpret_cast<int32_t>(Object::null()));
+  __ CompareObject(R3, Object::null_object());
   __ b(&fall_through, NE);
 
   __ ldrh(R3, FieldAddress(R2, Class::num_type_arguments_offset()));
@@ -1595,7 +1593,7 @@
   __ b(&fall_through, NE);
 
   __ ldr(R0, FieldAddress(R2, Class::canonical_types_offset()));
-  __ CompareImmediate(R0, reinterpret_cast<int32_t>(Object::null()));
+  __ CompareObject(R0, Object::null_object());
   __ b(&fall_through, EQ);
   __ Ret();
 
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index d5df533..95783b6 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -58,7 +58,7 @@
     __ lw(T2, Address(SP, 0 * kWordSize));  // Value.
 
     // Null value is valid for any type.
-    __ LoadImmediate(T7, reinterpret_cast<int32_t>(Object::null()));
+    __ LoadObject(T7, Object::null_object());
     __ beq(T2, T7, &checked_ok);
 
     __ lw(T1, Address(SP, 2 * kWordSize));  // Array.
@@ -169,7 +169,7 @@
   __ StoreIntoObject(T2,
                      FieldAddress(T1, Array::data_offset()),
                      T0);
-  __ LoadImmediate(T7, reinterpret_cast<int32_t>(Object::null()));
+  __ LoadObject(T7, Object::null_object());
   __ Ret();
   __ delay_slot()->mov(V0, T7);
   __ Bind(&fall_through);
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 06dfad2..87ab7eb 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -5,11 +5,13 @@
 #include "vm/isolate.h"
 
 #include "include/dart_api.h"
+#include "include/dart_native_api.h"
 #include "platform/assert.h"
 #include "platform/json.h"
 #include "vm/code_observers.h"
 #include "vm/compiler_stats.h"
 #include "vm/coverage.h"
+#include "vm/dart_api_message.h"
 #include "vm/dart_api_state.h"
 #include "vm/dart_entry.h"
 #include "vm/debugger.h"
@@ -38,6 +40,7 @@
 #include "vm/thread_interrupter.h"
 #include "vm/thread_registry.h"
 #include "vm/timeline.h"
+#include "vm/timeline_analysis.h"
 #include "vm/timer.h"
 #include "vm/visitor.h"
 
@@ -45,6 +48,7 @@
 namespace dart {
 
 DECLARE_FLAG(bool, print_metrics);
+DECLARE_FLAG(bool, timing);
 DECLARE_FLAG(bool, trace_service);
 
 DEFINE_FLAG(bool, trace_isolates, false,
@@ -56,9 +60,6 @@
 DEFINE_FLAG(bool, break_at_isolate_spawn, false,
             "Insert a one-time breakpoint at the entrypoint for all spawned "
             "isolates");
-DEFINE_FLAG(charp, isolate_log_filter, NULL,
-            "Log isolates whose name include the filter. "
-            "Default: service isolate log messages are suppressed.");
 
 DEFINE_FLAG(int, new_gen_semi_max_size, (kWordSize <= 4) ? 16 : 32,
             "Max size of new gen semi space in MB");
@@ -166,7 +167,6 @@
   bool IsCurrentIsolate() const;
   virtual Isolate* isolate() const { return isolate_; }
 
- private:
   // Keep both these enums in sync with isolate_patch.dart.
   // The different Isolate API message types.
   enum {
@@ -187,6 +187,7 @@
     kAsEventAction = 2
   };
 
+ private:
   // A result of false indicates that the isolate should terminate the
   // processing of further events.
   bool HandleLibMessage(const Array& message);
@@ -656,6 +657,7 @@
 Isolate::Isolate(const Dart_IsolateFlags& api_flags)
   :   vm_tag_(0),
       store_buffer_(new StoreBuffer()),
+      heap_(NULL),
       thread_registry_(new ThreadRegistry()),
       message_notify_callback_(NULL),
       name_(NULL),
@@ -666,7 +668,6 @@
       pause_capability_(0),
       terminate_capability_(0),
       errors_fatal_(true),
-      heap_(NULL),
       object_store_(NULL),
       top_exit_frame_info_(0),
       init_callback_data_(NULL),
@@ -699,7 +700,6 @@
       edge_counter_increment_size_(-1),
       compiler_stats_(NULL),
       is_service_isolate_(false),
-      log_(new class Log()),
       stacktrace_(NULL),
       stack_frame_index_(-1),
       last_allocationprofile_accumulator_reset_timestamp_(0),
@@ -747,8 +747,6 @@
   message_handler_ = NULL;  // Fail fast if we send messages to a dead isolate.
   ASSERT(deopt_context_ == NULL);  // No deopt in progress when isolate deleted.
   delete spawn_state_;
-  delete log_;
-  log_ = NULL;
   delete object_id_ring_;
   object_id_ring_ = NULL;
   delete pause_loop_monitor_;
@@ -772,6 +770,7 @@
   create_callback_ = NULL;
   isolates_list_monitor_ = new Monitor();
   ASSERT(isolates_list_monitor_ != NULL);
+  EnableIsolateCreation();
 }
 
 
@@ -850,8 +849,14 @@
     result->compiler_stats_ = new CompilerStats(result);
   }
   ObjectIdRing::Init(result);
-  // Add to isolate list.
-  AddIsolateTolist(result);
+
+  // Add to isolate list. Shutdown and delete the isolate on failure.
+  if (!AddIsolateToList(result)) {
+    result->LowLevelShutdown();
+    Thread::ExitIsolate();
+    delete result;
+    return NULL;
+  }
 
   return result;
 }
@@ -900,27 +905,7 @@
     name_ = strdup(name_prefix);
     return;
   }
-  const char* kFormat = "%s-%lld";
-  intptr_t len = OS::SNPrint(NULL, 0, kFormat, name_prefix, main_port()) + 1;
-  name_ = reinterpret_cast<char*>(malloc(len));
-  OS::SNPrint(name_, len, kFormat, name_prefix, main_port());
-}
-
-
-Log* Isolate::Log() const {
-  if (FLAG_isolate_log_filter == NULL) {
-    if (is_service_isolate_) {
-      // By default, do not log for the service isolate.
-      return Log::NoOpLog();
-    }
-    return log_;
-  }
-  ASSERT(name_ != NULL);
-  if (strstr(name_, FLAG_isolate_log_filter) == NULL) {
-    // Filter does not match, do not log for this isolate.
-    return Log::NoOpLog();
-  }
-  return log_;
+  name_ = OS::SCreate(NULL, "%s-%" Pd64 "", name_prefix, main_port());
 }
 
 
@@ -1486,6 +1471,70 @@
 };
 
 
+void Isolate::LowLevelShutdown() {
+  // Ensure we have a zone and handle scope so that we can call VM functions,
+  // but we no longer allocate new heap objects.
+  Thread* thread = Thread::Current();
+  StackZone stack_zone(thread);
+  HandleScope handle_scope(thread);
+  NoSafepointScope no_safepoint_scope;
+
+  if (compiler_stats_ != NULL) {
+    OS::Print("%s", compiler_stats()->PrintToZone());
+  }
+
+  // Notify exit listeners that this isolate is shutting down.
+  if (object_store() != NULL) {
+    NotifyExitListeners();
+  }
+
+  // Clean up debugger resources.
+  debugger()->Shutdown();
+
+  // Close all the ports owned by this isolate.
+  PortMap::ClosePorts(message_handler());
+
+  // Fail fast if anybody tries to post any more messsages to this isolate.
+  delete message_handler();
+  set_message_handler(NULL);
+
+  // Dump all accumulated timer data for the isolate.
+  timer_list_.ReportTimers();
+
+  // Before analyzing the isolate's timeline blocks- close all of them.
+  CloseAllTimelineBlocks();
+
+  // Dump all timing data for the isolate.
+  if (FLAG_timing) {
+    TimelinePauseTrace tpt;
+    tpt.Print();
+  }
+
+  // Finalize any weak persistent handles with a non-null referent.
+  FinalizeWeakPersistentHandlesVisitor visitor;
+  api_state()->weak_persistent_handles().VisitHandles(&visitor);
+  api_state()->prologue_weak_persistent_handles().VisitHandles(&visitor);
+
+  if (FLAG_trace_isolates) {
+    heap()->PrintSizes();
+    MegamorphicCacheTable::PrintSizes(this);
+    Symbols::DumpStats();
+    OS::Print("[-] Stopping isolate:\n"
+              "\tisolate:    %s\n", name());
+  }
+  if (FLAG_print_metrics) {
+    LogBlock lb;
+    THR_Print("Printing metrics for %s\n", name());
+#define ISOLATE_METRIC_PRINT(type, variable, name, unit)                       \
+  THR_Print("%s\n", metric_##variable##_.ToString());
+
+    ISOLATE_METRIC_LIST(ISOLATE_METRIC_PRINT);
+#undef ISOLATE_METRIC_PRINT
+    THR_Print("\n");
+  }
+}
+
+
 void Isolate::Shutdown() {
   ASSERT(this == Isolate::Current());
   ASSERT(top_resource() == NULL);
@@ -1505,7 +1554,10 @@
     HandleScope handle_scope(thread);
 
     // Write out the coverage data if collection has been enabled.
-    CodeCoverage::Write(this);
+    if ((this != Dart::vm_isolate()) &&
+        !ServiceIsolate::IsServiceIsolateDescendant(this)) {
+      CodeCoverage::Write(this);
+    }
   }
 
   // Remove this isolate from the list *before* we start tearing it down, to
@@ -1523,57 +1575,7 @@
   }
 
   // Then, proceed with low-level teardown.
-  {
-    // Ensure we have a zone and handle scope so that we can call VM functions,
-    // but we no longer allocate new heap objects.
-    StackZone stack_zone(thread);
-    HandleScope handle_scope(thread);
-    NoSafepointScope no_safepoint_scope;
-
-    if (compiler_stats_ != NULL) {
-      OS::Print("%s", compiler_stats()->PrintToZone());
-    }
-
-    // Notify exit listeners that this isolate is shutting down.
-    if (object_store() != NULL) {
-      NotifyExitListeners();
-    }
-
-    // Clean up debugger resources.
-    debugger()->Shutdown();
-
-    // Close all the ports owned by this isolate.
-    PortMap::ClosePorts(message_handler());
-
-    // Fail fast if anybody tries to post any more messsages to this isolate.
-    delete message_handler();
-    set_message_handler(NULL);
-
-    // Dump all accumulated timer data for the isolate.
-    timer_list_.ReportTimers();
-
-    // Finalize any weak persistent handles with a non-null referent.
-    FinalizeWeakPersistentHandlesVisitor visitor;
-    api_state()->weak_persistent_handles().VisitHandles(&visitor);
-    api_state()->prologue_weak_persistent_handles().VisitHandles(&visitor);
-
-    if (FLAG_trace_isolates) {
-      heap()->PrintSizes();
-      megamorphic_cache_table()->PrintSizes();
-      Symbols::DumpStats();
-      OS::Print("[-] Stopping isolate:\n"
-                "\tisolate:    %s\n", name());
-    }
-    if (FLAG_print_metrics) {
-      LogBlock lb(this);
-      ISL_Print("Printing metrics for %s\n", name());
-#define ISOLATE_METRIC_PRINT(type, variable, name, unit)                       \
-  ISL_Print("%s\n", metric_##variable##_.ToString());
-  ISOLATE_METRIC_LIST(ISOLATE_METRIC_PRINT);
-#undef ISOLATE_METRIC_PRINT
-      ISL_Print("\n");
-    }
-  }
+  LowLevelShutdown();
 
 #if defined(DEBUG)
   // No concurrent sweeper tasks should be running at this point.
@@ -1593,6 +1595,17 @@
 }
 
 
+void Isolate::CloseAllTimelineBlocks() {
+  // Close all blocks
+  thread_registry_->CloseAllTimelineBlocks();
+  TimelineEventRecorder* recorder = Timeline::recorder();
+  if (recorder != NULL) {
+    MutexLocker ml(&recorder->lock_);
+    Thread::Current()->CloseTimelineBlock();
+  }
+}
+
+
 Dart_IsolateCreateCallback Isolate::create_callback_ = NULL;
 Dart_IsolateInterruptCallback Isolate::interrupt_callback_ = NULL;
 Dart_IsolateUnhandledExceptionCallback
@@ -1606,7 +1619,7 @@
 
 Monitor* Isolate::isolates_list_monitor_ = NULL;
 Isolate* Isolate::isolates_list_head_ = NULL;
-
+bool Isolate::creation_enabled_ = false;
 
 void Isolate::IterateObjectPointers(ObjectPointerVisitor* visitor,
                                     bool visit_prologue_weak_handles,
@@ -1627,9 +1640,6 @@
   // Visit objects in the class table.
   class_table()->VisitObjectPointers(visitor);
 
-  // Visit objects in the megamorphic cache.
-  megamorphic_cache_table()->VisitObjectPointers(visitor);
-
   // Visit objects in per isolate stubs.
   StubCode::VisitObjectPointers(visitor);
 
@@ -2119,12 +2129,16 @@
 }
 
 
-void Isolate::AddIsolateTolist(Isolate* isolate) {
+bool Isolate::AddIsolateToList(Isolate* isolate) {
   MonitorLocker ml(isolates_list_monitor_);
+  if (!creation_enabled_) {
+    return false;
+  }
   ASSERT(isolate != NULL);
   ASSERT(isolate->next_ == NULL);
   isolate->next_ = isolates_list_head_;
   isolates_list_head_ = isolate;
+  return true;
 }
 
 
@@ -2133,6 +2147,9 @@
   ASSERT(isolate != NULL);
   if (isolate == isolates_list_head_) {
     isolates_list_head_ = isolate->next_;
+    if (!creation_enabled_) {
+      ml.Notify();
+    }
     return;
   }
   Isolate* previous = NULL;
@@ -2141,12 +2158,28 @@
     if (current == isolate) {
       ASSERT(previous != NULL);
       previous->next_ = current->next_;
+      if (!creation_enabled_) {
+        ml.Notify();
+      }
       return;
     }
     previous = current;
     current = current->next_;
   }
-  UNREACHABLE();
+  // If we are shutting down the VM, the isolate may not be in the list.
+  ASSERT(!creation_enabled_);
+}
+
+
+void Isolate::DisableIsolateCreation() {
+  MonitorLocker ml(isolates_list_monitor_);
+  creation_enabled_ = false;
+}
+
+
+void Isolate::EnableIsolateCreation() {
+  MonitorLocker ml(isolates_list_monitor_);
+  creation_enabled_ = true;
 }
 
 
@@ -2158,6 +2191,93 @@
 }
 
 
+void Isolate::KillLocked() {
+  Dart_CObject kill_msg;
+  Dart_CObject* list_values[4];
+  kill_msg.type = Dart_CObject_kArray;
+  kill_msg.value.as_array.length = 4;
+  kill_msg.value.as_array.values = list_values;
+
+  Dart_CObject oob;
+  oob.type = Dart_CObject_kInt32;
+  oob.value.as_int32 = Message::kIsolateLibOOBMsg;
+  list_values[0] = &oob;
+
+  Dart_CObject kill;
+  kill.type = Dart_CObject_kInt32;
+  kill.value.as_int32 = IsolateMessageHandler::kKillMsg;
+  list_values[1] = &kill;
+
+  Dart_CObject cap;
+  cap.type = Dart_CObject_kCapability;
+  cap.value.as_capability.id = terminate_capability();
+  list_values[2] = &cap;
+
+  Dart_CObject imm;
+  imm.type = Dart_CObject_kInt32;
+  imm.value.as_int32 = IsolateMessageHandler::kImmediateAction;
+  list_values[3] = &imm;
+
+  {
+    uint8_t* buffer = NULL;
+    ApiMessageWriter writer(&buffer, allocator);
+    bool success = writer.WriteCMessage(&kill_msg);
+    ASSERT(success);
+
+    // Post the message at the given port.
+    success = PortMap::PostMessage(new Message(main_port(),
+                                               buffer,
+                                               writer.BytesWritten(),
+                                               Message::kOOBPriority));
+    ASSERT(success);
+  }
+}
+
+
+class IsolateKillerVisitor : public IsolateVisitor {
+ public:
+  IsolateKillerVisitor() : target_(NULL) {}
+
+  explicit IsolateKillerVisitor(Isolate* isolate)
+      : target_(isolate) {
+    ASSERT(isolate != Dart::vm_isolate());
+  }
+
+  virtual ~IsolateKillerVisitor() {}
+
+  void VisitIsolate(Isolate* isolate) {
+    ASSERT(isolate != NULL);
+    if (ShouldKill(isolate)) {
+      isolate->KillLocked();
+    }
+  }
+
+ private:
+  bool ShouldKill(Isolate* isolate) {
+    // If a target_ is specified, then only kill the target_.
+    // Otherwise, don't kill the service isolate or vm isolate.
+    return (((target_ != NULL) && (isolate == target_)) ||
+            ((target_ == NULL) &&
+             !ServiceIsolate::IsServiceIsolateDescendant(isolate) &&
+             (isolate != Dart::vm_isolate())));
+  }
+
+  Isolate* target_;
+};
+
+
+void Isolate::KillAllIsolates() {
+  IsolateKillerVisitor visitor;
+  VisitIsolates(&visitor);
+}
+
+
+void Isolate::KillIfExists(Isolate* isolate) {
+  IsolateKillerVisitor visitor(isolate);
+  VisitIsolates(&visitor);
+}
+
+
 static RawInstance* DeserializeObject(Thread* thread,
                                       uint8_t* obj_data,
                                       intptr_t obj_len) {
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index b8e7a4c..5c75c94 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -145,10 +145,6 @@
     return OFFSET_OF(Isolate, class_table_);
   }
 
-  MegamorphicCacheTable* megamorphic_cache_table() {
-    return &megamorphic_cache_table_;
-  }
-
   Dart_MessageNotifyCallback message_notify_callback() const {
     return message_notify_callback_;
   }
@@ -170,9 +166,6 @@
   const char* debugger_name() const { return debugger_name_; }
   void set_debugger_name(const char* name);
 
-  // TODO(koda): Move to Thread.
-  class Log* Log() const;
-
   int64_t start_time() const { return start_time_; }
 
   Dart_Port main_port() const { return main_port_; }
@@ -759,8 +752,17 @@
     mutator_thread_->set_zone(zone);
   }
 
+  bool is_service_isolate() const { return is_service_isolate_; }
+
+  static void KillAllIsolates();
+  static void KillIfExists(Isolate* isolate);
+
+  static void DisableIsolateCreation();
+  static void EnableIsolateCreation();
+
  private:
   friend class Dart;  // Init, InitOnce, Shutdown.
+  friend class IsolateKillerVisitor;  // Kill().
 
   explicit Isolate(const Dart_IsolateFlags& api_flags);
 
@@ -768,7 +770,14 @@
   static Isolate* Init(const char* name_prefix,
                        const Dart_IsolateFlags& api_flags,
                        bool is_vm_isolate = false);
+
+  // The isolates_list_monitor_ should be held when calling Kill().
+  void KillLocked();
+
+  void LowLevelShutdown();
   void Shutdown();
+  // Assumes mutator is the only thread still in the isolate.
+  void CloseAllTimelineBlocks();
 
   void BuildName(const char* name_prefix);
   void PrintInvokedFunctions();
@@ -812,9 +821,9 @@
 
   uword vm_tag_;
   StoreBuffer* store_buffer_;
+  Heap* heap_;
   ThreadRegistry* thread_registry_;
   ClassTable class_table_;
-  MegamorphicCacheTable megamorphic_cache_table_;
   Dart_MessageNotifyCallback message_notify_callback_;
   char* name_;
   char* debugger_name_;
@@ -824,7 +833,6 @@
   uint64_t pause_capability_;
   uint64_t terminate_capability_;
   bool errors_fatal_;
-  Heap* heap_;
   ObjectStore* object_store_;
   uword top_exit_frame_info_;
   void* init_callback_data_;
@@ -858,9 +866,7 @@
 
   CompilerStats* compiler_stats_;
 
-  // Log.
   bool is_service_isolate_;
-  class Log* log_;
 
   // Status support.
   char* stacktrace_;
@@ -962,11 +968,13 @@
   static void WakePauseEventHandler(Dart_Isolate isolate);
 
   // Manage list of existing isolates.
-  static void AddIsolateTolist(Isolate* isolate);
+  static bool AddIsolateToList(Isolate* isolate);
   static void RemoveIsolateFromList(Isolate* isolate);
 
-  static Monitor* isolates_list_monitor_;  // Protects isolates_list_head_
+  // This monitor protects isolates_list_head_, and creation_enabled_.
+  static Monitor* isolates_list_monitor_;
   static Isolate* isolates_list_head_;
+  static bool creation_enabled_;
 
 #define REUSABLE_FRIEND_DECLARATION(name)                                      \
   friend class Reusable##name##HandleScope;
diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc
index e0ee6b7..f6a255d 100644
--- a/runtime/vm/json_stream.cc
+++ b/runtime/vm/json_stream.cc
@@ -686,7 +686,7 @@
 
 void JSONObject::AddLocation(const Script& script,
                              intptr_t token_pos,
-                             intptr_t end_token_pos) {
+                             intptr_t end_token_pos) const {
   JSONObject location(this, "location");
   location.AddProperty("type", "SourceLocation");
   location.AddProperty("script", script);
@@ -697,6 +697,49 @@
 }
 
 
+void JSONObject::AddLocation(const BreakpointLocation* bpt_loc) const {
+  ASSERT(bpt_loc->IsResolved());
+
+  Isolate* isolate = Isolate::Current();
+  Library& library = Library::Handle(isolate);
+  Script& script = Script::Handle(isolate);
+  intptr_t token_pos;
+  bpt_loc->GetCodeLocation(&library, &script, &token_pos);
+  AddLocation(script, token_pos);
+}
+
+
+void JSONObject::AddUnresolvedLocation(
+    const BreakpointLocation* bpt_loc) const {
+  ASSERT(!bpt_loc->IsResolved());
+
+  Isolate* isolate = Isolate::Current();
+  Library& library = Library::Handle(isolate);
+  Script& script = Script::Handle(isolate);
+  intptr_t token_pos;
+  bpt_loc->GetCodeLocation(&library, &script, &token_pos);
+
+  JSONObject location(this, "location");
+  location.AddProperty("type", "UnresolvedSourceLocation");
+  if (!script.IsNull()) {
+    location.AddProperty("script", script);
+  } else {
+    const String& scriptUri = String::Handle(isolate, bpt_loc->url());
+    location.AddPropertyStr("scriptUri", scriptUri);
+  }
+  if (bpt_loc->requested_line_number() >= 0) {
+    // This unresolved breakpoint was specified at a particular line.
+    location.AddProperty("line", bpt_loc->requested_line_number());
+    if (bpt_loc->requested_column_number() >= 0) {
+      location.AddProperty("column",
+                           bpt_loc->requested_column_number());
+    }
+  } else {
+    // This unresolved breakpoint was requested at some function entry.
+    location.AddProperty("tokenPos", token_pos);
+  }
+}
+
 
 void JSONObject::AddPropertyF(const char* name,
                               const char* format, ...) const {
diff --git a/runtime/vm/json_stream.h b/runtime/vm/json_stream.h
index cdc5c4e..f835edc 100644
--- a/runtime/vm/json_stream.h
+++ b/runtime/vm/json_stream.h
@@ -15,6 +15,7 @@
 
 class Array;
 class Breakpoint;
+class BreakpointLocation;
 class Field;
 class GrowableObjectArray;
 class Instance;
@@ -209,7 +210,11 @@
 
   void AddLocation(const Script& script,
                    intptr_t token_pos,
-                   intptr_t end_token_pos = -1);
+                   intptr_t end_token_pos = -1) const;
+
+  void AddLocation(const BreakpointLocation* bpt_loc) const;
+
+  void AddUnresolvedLocation(const BreakpointLocation* bpt_loc) const;
 
   void AddProperty(const char* name, bool b) const {
     stream_->PrintPropertyBool(name, b);
diff --git a/runtime/vm/json_test.cc b/runtime/vm/json_test.cc
index 5bce0d39..6ca6760 100644
--- a/runtime/vm/json_test.cc
+++ b/runtime/vm/json_test.cc
@@ -299,8 +299,12 @@
     JSONObject jsobj(&jsarr);
     jsobj.AddProperty("object_key", Object::Handle(Object::null()));
   }
+  char buffer[1024];
+  ElideJSONSubstring("classes", js.ToCString(), buffer);
   EXPECT_STREQ("[{\"type\":\"@Instance\","
                "\"_vmType\":\"null\","
+               "\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
+               "\"name\":\"Null\"},"
                "\"kind\":\"Null\","
                "\"fixedId\":true,"
                "\"id\":\"objects\\/null\","
@@ -308,11 +312,13 @@
                "{\"object_key\":"
                "{\"type\":\"@Instance\","
                "\"_vmType\":\"null\","
+               "\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
+               "\"name\":\"Null\"},"
                "\"kind\":\"Null\","
                "\"fixedId\":true,"
                "\"id\":\"objects\\/null\","
                "\"valueAsString\":\"null\"}}]",
-               js.ToCString());
+               buffer);
 }
 
 TEST_CASE(JSON_JSONStream_EscapedString) {
diff --git a/runtime/vm/locations.cc b/runtime/vm/locations.cc
index 525855a..e460a2d 100644
--- a/runtime/vm/locations.cc
+++ b/runtime/vm/locations.cc
@@ -225,9 +225,9 @@
 
 void Location::Print() const {
   if (kind() == kStackSlot) {
-    ISL_Print("S%+" Pd "", stack_index());
+    THR_Print("S%+" Pd "", stack_index());
   } else {
-    ISL_Print("%s", Name());
+    THR_Print("%s", Name());
   }
 }
 
diff --git a/runtime/vm/locations.h b/runtime/vm/locations.h
index 48fbd6f..5e92c16 100644
--- a/runtime/vm/locations.h
+++ b/runtime/vm/locations.h
@@ -519,7 +519,7 @@
     for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) {
       Register r = static_cast<Register>(i);
       if (ContainsRegister(r)) {
-        ISL_Print("%s %s\n", Assembler::RegisterName(r),
+        THR_Print("%s %s\n", Assembler::RegisterName(r),
                            IsTagged(r) ? "tagged" : "untagged");
       }
     }
@@ -527,7 +527,7 @@
     for (intptr_t i = 0; i < kNumberOfFpuRegisters; i++) {
       FpuRegister r = static_cast<FpuRegister>(i);
       if (ContainsFpuRegister(r)) {
-        ISL_Print("%s\n", Assembler::FpuRegisterName(r));
+        THR_Print("%s\n", Assembler::FpuRegisterName(r));
       }
     }
   }
diff --git a/runtime/vm/log.cc b/runtime/vm/log.cc
index 5bb9842..e29432f 100644
--- a/runtime/vm/log.cc
+++ b/runtime/vm/log.cc
@@ -11,6 +11,10 @@
 
 DEFINE_FLAG(bool, force_log_flush, false, "Always flush log messages.");
 
+DEFINE_FLAG(charp, isolate_log_filter, NULL,
+            "Log isolates whose name include the filter. "
+            "Default: service isolate log messages are suppressed.");
+
 Log::Log(LogPrinter printer)
     : printer_(printer),
       manual_flush_(0),
@@ -18,6 +22,23 @@
 }
 
 
+Log::~Log() {
+  // Did someone enable manual flushing and then forgot to Flush?
+  ASSERT(cursor() == 0);
+}
+
+
+Log* Log::Current() {
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
+  if (isolate != NULL && Log::ShouldLogForIsolate(isolate)) {
+    return thread->log();
+  } else {
+    return Log::NoOpLog();
+  }
+}
+
+
 void Log::Print(const char* format, ...) {
   if (this == NoOpLog()) {
     return;
@@ -92,6 +113,24 @@
 }
 
 
+bool Log::ShouldLogForIsolate(const Isolate* isolate) {
+  if (FLAG_isolate_log_filter == NULL) {
+    if (isolate->is_service_isolate()) {
+      // By default, do not log for the service isolate.
+      return false;
+    }
+    return true;
+  }
+  const char* name = isolate->name();
+  ASSERT(name != NULL);
+  if (strstr(name, FLAG_isolate_log_filter) == NULL) {
+    // Filter does not match, do not log for this isolate.
+    return false;
+  }
+  return true;
+}
+
+
 Log Log::noop_log_;
 Log* Log::NoOpLog() {
   return &noop_log_;
@@ -117,25 +156,14 @@
 }
 
 
-LogBlock::LogBlock(Thread* thread, Log* log)
-    : StackResource(thread),
-      log_(log), cursor_(log->cursor()) {
-  CommonConstructor();
+void LogBlock::Initialize() {
+  log_->EnableManualFlush();
 }
 
 
-LogBlock::LogBlock(Isolate* isolate)
-    : StackResource(isolate),
-      log_(isolate->Log()), cursor_(isolate->Log()->cursor()) {
-  CommonConstructor();
-}
-
-
-LogBlock::LogBlock(Thread* thread)
-    : StackResource(thread),
-      log_(thread->isolate()->Log()),
-      cursor_(thread->isolate()->Log()->cursor()) {
-  CommonConstructor();
+LogBlock::~LogBlock() {
+  log_->Flush(cursor_);
+  log_->DisableManualFlush();
 }
 
 }  // namespace dart
diff --git a/runtime/vm/log.h b/runtime/vm/log.h
index f4c58e9..a2f18fa 100644
--- a/runtime/vm/log.h
+++ b/runtime/vm/log.h
@@ -11,26 +11,28 @@
 
 namespace dart {
 
-class Isolate;
 class LogBlock;
 class Thread;
 
 #if defined(_MSC_VER)
-#define ISL_Print(format, ...) \
-    Isolate::Current()->Log()->Print(format, __VA_ARGS__)
+#define THR_Print(format, ...) \
+    Log::Current()->Print(format, __VA_ARGS__)
 #else
-#define ISL_Print(format, ...) \
-    Isolate::Current()->Log()->Print(format, ##__VA_ARGS__)
+#define THR_Print(format, ...) \
+    Log::Current()->Print(format, ##__VA_ARGS__)
 #endif
 
-#define ISL_VPrint(format, args) \
-    Isolate::Current()->Log()->VPrint(format, args)
+#define THR_VPrint(format, args) \
+    Log::Current()->VPrint(format, args)
 
 typedef void (*LogPrinter)(const char* str, ...);
 
 class Log {
  public:
   explicit Log(LogPrinter printer = OS::Print);
+  ~Log();
+
+  static Log* Current();
 
   // Append a formatted string to the log.
   void Print(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
@@ -55,6 +57,9 @@
   void EnableManualFlush();
   void DisableManualFlush();
 
+  // Returns false if we should drop log messages related to 'isolate'.
+  static bool ShouldLogForIsolate(const Isolate* isolate);
+
   static Log noop_log_;
   LogPrinter printer_;
   intptr_t manual_flush_;
@@ -70,31 +75,24 @@
 // Can be nested.
 class LogBlock : public StackResource {
  public:
-  LogBlock(Isolate* isolate, Log* log)
-      : StackResource(isolate),
-        log_(log), cursor_(log->cursor()) {
-    CommonConstructor();
+  LogBlock(Thread* thread, Log* log)
+      : StackResource(thread), log_(log), cursor_(log->cursor()) {
+    Initialize();
   }
 
-  explicit LogBlock(Isolate* isolate);
-  explicit LogBlock(Thread* thread);
-
-  LogBlock(Thread* thread, Log* log);
-
-  ~LogBlock() {
-    CommonDestructor();
+  LogBlock()
+      : StackResource(Thread::Current()),
+        log_(Log::Current()),
+        cursor_(Log::Current()->cursor()) {
+    Initialize();
   }
 
+  ~LogBlock();
+
  private:
-  void CommonConstructor() {
-    log_->EnableManualFlush();
-  }
+  void Initialize();
 
-  void CommonDestructor() {
-    log_->Flush(cursor_);
-    log_->DisableManualFlush();
-  }
-  Log* log_;
+  Log* const log_;
   const intptr_t cursor_;
 };
 
diff --git a/runtime/vm/log_test.cc b/runtime/vm/log_test.cc
index 370fefc..84ef855 100644
--- a/runtime/vm/log_test.cc
+++ b/runtime/vm/log_test.cc
@@ -47,13 +47,12 @@
 
 TEST_CASE(Log_Macro) {
   test_output_ = NULL;
-  Isolate* isolate = Isolate::Current();
-  Log* log = isolate->Log();
+  Log* log = Log::Current();
   LogTestHelper::SetPrinter(log, TestPrinter);
 
-  ISL_Print("Hello %s", "World");
+  THR_Print("Hello %s", "World");
   EXPECT_STREQ("Hello World", test_output_);
-  ISL_Print("SingleArgument");
+  THR_Print("SingleArgument");
   EXPECT_STREQ("SingleArgument", test_output_);
 }
 
@@ -72,15 +71,13 @@
   test_output_ = NULL;
   Log* log = new Log(TestPrinter);
 
-  Isolate* isolate = Isolate::Current();
-
   EXPECT_EQ(reinterpret_cast<const char*>(NULL), test_output_);
   {
-    LogBlock ba(isolate, log);
+    LogBlock ba(thread, log);
     log->Print("APPLE");
     EXPECT_EQ(reinterpret_cast<const char*>(NULL), test_output_);
     {
-      LogBlock ba(isolate, log);
+      LogBlock ba(thread, log);
       log->Print("BANANA");
       EXPECT_EQ(reinterpret_cast<const char*>(NULL), test_output_);
     }
diff --git a/runtime/vm/megamorphic_cache_table.cc b/runtime/vm/megamorphic_cache_table.cc
index 3bbc529..c87be96 100644
--- a/runtime/vm/megamorphic_cache_table.cc
+++ b/runtime/vm/megamorphic_cache_table.cc
@@ -6,50 +6,52 @@
 
 #include <stdlib.h>
 #include "vm/object.h"
+#include "vm/object_store.h"
 #include "vm/stub_code.h"
 #include "vm/symbols.h"
 
 namespace dart {
 
-MegamorphicCacheTable::MegamorphicCacheTable()
-    : miss_handler_function_(NULL),
-      miss_handler_code_(NULL),
-      capacity_(0),
-      length_(0),
-      table_(NULL) {
-}
-
-
-MegamorphicCacheTable::~MegamorphicCacheTable() {
-  free(table_);
-}
-
-
-RawMegamorphicCache* MegamorphicCacheTable::Lookup(const String& name,
+RawMegamorphicCache* MegamorphicCacheTable::Lookup(Isolate* isolate,
+                                                   const String& name,
                                                    const Array& descriptor) {
-  for (intptr_t i = 0; i < length_; ++i) {
-    if ((table_[i].name == name.raw()) &&
-        (table_[i].descriptor == descriptor.raw())) {
-      return table_[i].cache;
+  ASSERT(name.IsSymbol());
+  // TODO(rmacnak): ASSERT(descriptor.IsCanonical());
+
+  // TODO(rmacnak): Make a proper hashtable a la symbol table.
+  GrowableObjectArray& table = GrowableObjectArray::Handle(
+      isolate->object_store()->megamorphic_cache_table());
+  if (table.IsNull()) {
+    table = GrowableObjectArray::New();
+    ASSERT((table.Length() % kEntrySize) == 0);
+    isolate->object_store()->set_megamorphic_cache_table(table);
+  } else {
+    for (intptr_t i = 0; i < table.Length(); i += kEntrySize) {
+      if ((table.At(i + kEntryNameOffset) == name.raw()) &&
+          (table.At(i + kEntryDescriptorOffset) == descriptor.raw())) {
+        return MegamorphicCache::RawCast(table.At(i + kEntryCacheOffset));
+      }
     }
   }
 
-  if (length_ == capacity_) {
-    capacity_ += kCapacityIncrement;
-    table_ =
-        reinterpret_cast<Entry*>(realloc(table_, capacity_ * sizeof(*table_)));
-  }
-
-  ASSERT(length_ < capacity_);
   const MegamorphicCache& cache =
       MegamorphicCache::Handle(MegamorphicCache::New());
-  Entry entry = { name.raw(), descriptor.raw(), cache.raw() };
-  table_[length_++] = entry;
+  table.Add(name);
+  table.Add(descriptor);
+  table.Add(cache);
+  ASSERT((table.Length() % kEntrySize) == 0);
   return cache.raw();
 }
 
 
-void MegamorphicCacheTable::InitMissHandler() {
+RawFunction* MegamorphicCacheTable::miss_handler(Isolate* isolate) {
+  ASSERT(isolate->object_store()->megamorphic_miss_function() !=
+         Function::null());
+  return isolate->object_store()->megamorphic_miss_function();
+}
+
+
+void MegamorphicCacheTable::InitMissHandler(Isolate* isolate) {
   // The miss handler for a class ID not found in the table is invoked as a
   // normal Dart function.
   const Code& code =
@@ -69,37 +71,27 @@
                                      0));  // No token position.
   function.set_is_debuggable(false);
   function.set_is_visible(false);
-  miss_handler_code_ = code.raw();
-  miss_handler_function_ = function.raw();
   function.AttachCode(code);
+
+  isolate->object_store()->SetMegamorphicMissHandler(code, function);
 }
 
 
-void MegamorphicCacheTable::VisitObjectPointers(ObjectPointerVisitor* v) {
-  ASSERT(v != NULL);
-  v->VisitPointer(reinterpret_cast<RawObject**>(&miss_handler_code_));
-  v->VisitPointer(reinterpret_cast<RawObject**>(&miss_handler_function_));
-  for (intptr_t i = 0; i < length_; ++i) {
-    v->VisitPointer(reinterpret_cast<RawObject**>(&table_[i].name));
-    v->VisitPointer(reinterpret_cast<RawObject**>(&table_[i].descriptor));
-    v->VisitPointer(reinterpret_cast<RawObject**>(&table_[i].cache));
-  }
-}
-
-
-void MegamorphicCacheTable::PrintSizes() {
+void MegamorphicCacheTable::PrintSizes(Isolate* isolate) {
   StackZone zone(Thread::Current());
   intptr_t size = 0;
   MegamorphicCache& cache = MegamorphicCache::Handle();
   Array& buckets = Array::Handle();
-  for (intptr_t i = 0; i < length_; ++i) {
-    cache = table_[i].cache;
+  const GrowableObjectArray& table = GrowableObjectArray::Handle(
+      isolate->object_store()->megamorphic_cache_table());
+  for (intptr_t i = 0; i < table.Length(); i += kEntrySize) {
+    cache ^= table.At(i + kEntryCacheOffset);
     buckets = cache.buckets();
     size += MegamorphicCache::InstanceSize();
     size += Array::InstanceSize(buckets.Length());
   }
   OS::Print("%" Pd " megamorphic caches using %" Pd "KB.\n",
-            length_, size / 1024);
+            table.Length() / kEntrySize, size / 1024);
 }
 
 }  // namespace dart
diff --git a/runtime/vm/megamorphic_cache_table.h b/runtime/vm/megamorphic_cache_table.h
index eafb35b..c47d4d8 100644
--- a/runtime/vm/megamorphic_cache_table.h
+++ b/runtime/vm/megamorphic_cache_table.h
@@ -11,6 +11,7 @@
 
 class Array;
 class Function;
+class Isolate;
 class ObjectPointerVisitor;
 class RawArray;
 class RawFunction;
@@ -19,36 +20,24 @@
 class RawString;
 class String;
 
-class MegamorphicCacheTable {
+class MegamorphicCacheTable : public AllStatic {
  public:
-  MegamorphicCacheTable();
-  ~MegamorphicCacheTable();
+  static RawFunction* miss_handler(Isolate* isolate);
+  static void InitMissHandler(Isolate* isolate);
 
-  RawFunction* miss_handler() const { return miss_handler_function_; }
-  void InitMissHandler();
+  static RawMegamorphicCache* Lookup(Isolate* isolate,
+                                     const String& name,
+                                     const Array& descriptor);
 
-  RawMegamorphicCache* Lookup(const String& name, const Array& descriptor);
-
-  void VisitObjectPointers(ObjectPointerVisitor* visitor);
-
-  void PrintSizes();
+  static void PrintSizes(Isolate* isolate);
 
  private:
-  struct Entry {
-    RawString* name;
-    RawArray* descriptor;
-    RawMegamorphicCache* cache;
+  enum {
+    kEntryNameOffset = 0,
+    kEntryDescriptorOffset,
+    kEntryCacheOffset,
+    kEntrySize
   };
-
-  static const int kCapacityIncrement = 128;
-
-  RawFunction* miss_handler_function_;
-  RawCode* miss_handler_code_;
-  intptr_t capacity_;
-  intptr_t length_;
-  Entry* table_;
-
-  DISALLOW_COPY_AND_ASSIGN(MegamorphicCacheTable);
 };
 
 }  // namespace dart
diff --git a/runtime/vm/message_handler.cc b/runtime/vm/message_handler.cc
index f832cbc..ef8a71e 100644
--- a/runtime/vm/message_handler.cc
+++ b/runtime/vm/message_handler.cc
@@ -24,6 +24,7 @@
   }
 
   virtual void Run() {
+    ASSERT(handler_ != NULL);
     handler_->TaskCallback();
   }
 
@@ -82,6 +83,7 @@
                          StartCallback start_callback,
                          EndCallback end_callback,
                          CallbackData data) {
+  bool task_running;
   MonitorLocker ml(&monitor_);
   if (FLAG_trace_isolates) {
     OS::Print("[+] Starting message handler:\n"
@@ -94,12 +96,14 @@
   end_callback_ = end_callback;
   callback_data_ = data;
   task_ = new MessageHandlerTask(this);
-  pool_->Run(task_);
+  task_running = pool_->Run(task_);
+  ASSERT(task_running);
 }
 
 
 void MessageHandler::PostMessage(Message* message, bool before_events) {
   Message::Priority saved_priority;
+  bool task_running = true;
   {
     MonitorLocker ml(&monitor_);
     if (FLAG_trace_isolates) {
@@ -124,11 +128,13 @@
     }
     message = NULL;  // Do not access message.  May have been deleted.
 
-    if (pool_ != NULL && task_ == NULL) {
+    if ((pool_ != NULL) && (task_ == NULL)) {
       task_ = new MessageHandlerTask(this);
-      pool_->Run(task_);
+      task_running = pool_->Run(task_);
     }
   }
+  ASSERT(task_running);
+
   // Invoke any custom message notification.
   MessageNotify(saved_priority);
 }
@@ -149,7 +155,7 @@
   // If isolate() returns NULL StartIsolateScope does nothing.
   StartIsolateScope start_isolate(isolate());
 
-  // ThreadInterrupter may have gone to sleep waiting while waiting for
+  // ThreadInterrupter may have gone to sleep while waiting for
   // an isolate to start handling messages.
   ThreadInterrupter::WakeUp();
 
diff --git a/runtime/vm/native_entry.cc b/runtime/vm/native_entry.cc
index ad351c8..5f373df 100644
--- a/runtime/vm/native_entry.cc
+++ b/runtime/vm/native_entry.cc
@@ -184,7 +184,6 @@
   bool call_through_wrapper = false;
 #ifdef USING_SIMULATOR
   bool is_native_auto_setup_scope = false;
-  intptr_t num_parameters = -1;
 #endif
 
   {
@@ -197,7 +196,6 @@
     const Function& func = Function::Handle(code.function());
 #ifdef USING_SIMULATOR
     is_native_auto_setup_scope = func.IsNativeAutoSetupScope();
-    num_parameters = func.NumParameters();
 #endif
 
     if (FLAG_trace_natives) {
@@ -225,7 +223,7 @@
                  Simulator::RedirectExternalReference(
                      reinterpret_cast<uword>(LinkNativeCall),
                      Simulator::kBootstrapNativeCall,
-                     func.NumParameters())));
+                     NativeEntry::kNumArguments)));
 #endif
       ASSERT(current_trampoline ==
              StubCode::CallBootstrapCFunction_entry()->EntryPoint());
@@ -248,7 +246,7 @@
       patch_target_function = reinterpret_cast<NativeFunction>(
           Simulator::RedirectExternalReference(
               reinterpret_cast<uword>(patch_target_function),
-              Simulator::kBootstrapNativeCall, num_parameters));
+              Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments));
     }
 #endif
 
diff --git a/runtime/vm/native_entry.h b/runtime/vm/native_entry.h
index cacf42d..4dd655d 100644
--- a/runtime/vm/native_entry.h
+++ b/runtime/vm/native_entry.h
@@ -102,6 +102,7 @@
 // Helper class for resolving and handling native functions.
 class NativeEntry : public AllStatic {
  public:
+  static const intptr_t kNumArguments = 1;
   static const intptr_t kNumCallWrapperArguments = 2;
 
   // Resolve specified dart native function to the actual native entrypoint.
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 107ad5d..d95e73d 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -1640,7 +1640,7 @@
 
 
 void Object::Print() const {
-  ISL_Print("%s\n", ToCString());
+  THR_Print("%s\n", ToCString());
 }
 
 
@@ -1667,7 +1667,7 @@
   if (!same_type) {
     jsobj->AddProperty("_vmType", vm_type);
   }
-  if (!ref || IsInstance()) {
+  if (!ref || IsInstance() || IsNull()) {
     // TODO(turnidge): Provide the type arguments here too?
     const Class& cls = Class::Handle(this->clazz());
     jsobj->AddProperty("class", cls);
@@ -2731,7 +2731,7 @@
   virtual void ReportDeoptimization(const Code& code) {
     if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
       Function& function = Function::Handle(code.function());
-      ISL_Print("Deoptimizing %s because CHA optimized (%s).\n",
+      THR_Print("Deoptimizing %s because CHA optimized (%s).\n",
           function.ToFullyQualifiedCString(),
           cls_.ToCString());
     }
@@ -2740,7 +2740,7 @@
   virtual void ReportSwitchingCode(const Code& code) {
     if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
       Function& function = Function::Handle(code.function());
-      ISL_Print("Switching %s to unoptimized code because CHA invalid"
+      THR_Print("Switching %s to unoptimized code because CHA invalid"
                 " (%s)\n",
                 function.ToFullyQualifiedCString(),
                 cls_.ToCString());
@@ -2755,7 +2755,7 @@
 
 void Class::RegisterCHACode(const Code& code) {
   if (FLAG_trace_cha) {
-    ISL_Print("RegisterCHACode %s class %s\n",
+    THR_Print("RegisterCHACode %s class %s\n",
         Function::Handle(code.function()).ToQualifiedCString(), ToCString());
   }
   ASSERT(code.is_optimized());
@@ -4238,16 +4238,12 @@
 
 
 const char* Class::ToCString() const {
-  const char* format = "%s %sClass: %s";
   const Library& lib = Library::Handle(library());
   const char* library_name = lib.IsNull() ? "" : lib.ToCString();
   const char* patch_prefix = is_patch() ? "Patch " : "";
   const char* class_name = String::Handle(Name()).ToCString();
-  intptr_t len =
-      OS::SNPrint(NULL, 0, format, library_name, patch_prefix, class_name) + 1;
-  char* chars = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, format, library_name, patch_prefix, class_name);
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(),
+      "%s %sClass: %s", library_name, patch_prefix, class_name);
 }
 
 
@@ -4415,12 +4411,9 @@
 
 
 const char* UnresolvedClass::ToCString() const {
-  const char* format = "unresolved class '%s'";
   const char* cname =  String::Handle(Name()).ToCString();
-  intptr_t len = OS::SNPrint(NULL, 0, format, cname) + 1;
-  char* chars = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, format, cname);
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(),
+      "unresolved class '%s'", cname);
 }
 
 
@@ -5167,14 +5160,12 @@
   if (IsNull()) {
     return "NULL TypeArguments";
   }
-  const char* format = "%s [%s]";
   const char* prev_cstr = "TypeArguments:";
   for (int i = 0; i < Length(); i++) {
     const AbstractType& type_at = AbstractType::Handle(TypeAt(i));
     const char* type_cstr = type_at.IsNull() ? "null" : type_at.ToCString();
-    intptr_t len = OS::SNPrint(NULL, 0, format, prev_cstr, type_cstr) + 1;
-    char* chars = Thread::Current()->zone()->Alloc<char>(len);
-    OS::SNPrint(chars, len, format, prev_cstr, type_cstr);
+    char* chars = OS::SCreate(Thread::Current()->zone(),
+        "%s [%s]", prev_cstr, type_cstr);
     prev_cstr = chars;
   }
   return prev_cstr;
@@ -5182,13 +5173,10 @@
 
 
 const char* PatchClass::ToCString() const {
-  const char* kFormat = "PatchClass for %s";
   const Class& cls = Class::Handle(patched_class());
   const char* cls_name = cls.ToCString();
-  intptr_t len = OS::SNPrint(NULL, 0, kFormat, cls_name) + 1;
-  char* chars = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, kFormat, cls_name);
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(),
+      "PatchClass for %s", cls_name);
 }
 
 
@@ -5257,7 +5245,7 @@
 
 
 void Function::ClearCode() const {
-  ASSERT(ic_data_array() == Array::null());
+  ASSERT((usage_counter() != 0) || (ic_data_array() == Array::null()));
   StorePointer(&raw_ptr()->unoptimized_code_, Code::null());
   SetInstructions(Code::Handle(StubCode::LazyCompile_entry()->code()));
 }
@@ -5271,7 +5259,7 @@
   const Code& current_code = Code::Handle(zone, CurrentCode());
 
   if (FLAG_trace_deoptimization_verbose) {
-    ISL_Print("Disabling optimized code: '%s' entry: %#" Px "\n",
+    THR_Print("Disabling optimized code: '%s' entry: %#" Px "\n",
       ToFullyQualifiedCString(),
       current_code.EntryPoint());
   }
@@ -6965,10 +6953,10 @@
       // to replace the old values.
       // sed -i .bak -f /tmp/newkeys runtime/vm/method_recognizer.h
       // sed -i .bak -f /tmp/newkeys runtime/vm/flow_graph_builder.h
-      ISL_Print("s/V(%s, %d)/V(%s, %d)/\n",
+      THR_Print("s/V(%s, %d)/V(%s, %d)/\n",
                 prefix, fp, prefix, SourceFingerprint());
     } else {
-      ISL_Print("FP mismatch while recognizing method %s:"
+      THR_Print("FP mismatch while recognizing method %s:"
                 " expecting %d found %d\n",
                 ToFullyQualifiedCString(),
                 fp,
@@ -7022,14 +7010,10 @@
     default:
       UNREACHABLE();
   }
-  const char* kFormat = "Function '%s':%s%s%s%s.";
   const char* function_name = String::Handle(name()).ToCString();
-  intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name,
-                             static_str, abstract_str, kind_str, const_str) + 1;
-  char* chars = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, kFormat, function_name,
-              static_str, abstract_str, kind_str, const_str);
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(),
+      "Function '%s':%s%s%s%s.",
+      function_name, static_str, abstract_str, kind_str, const_str);
 }
 
 
@@ -7409,15 +7393,11 @@
   const char* kF0 = is_static() ? " static" : "";
   const char* kF1 = is_final() ? " final" : "";
   const char* kF2 = is_const() ? " const" : "";
-  const char* kFormat = "Field <%s.%s>:%s%s%s";
   const char* field_name = String::Handle(name()).ToCString();
   const Class& cls = Class::Handle(owner());
   const char* cls_name = String::Handle(cls.Name()).ToCString();
-  intptr_t len =
-      OS::SNPrint(NULL, 0, kFormat, cls_name, field_name, kF0, kF1, kF2) + 1;
-  char* chars = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, kFormat, cls_name, field_name, kF0, kF1, kF2);
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(),
+      "Field <%s.%s>:%s%s%s", cls_name, field_name, kF0, kF1, kF2);
 }
 
 void Field::PrintJSONImpl(JSONStream* stream, bool ref) const {
@@ -7569,7 +7549,7 @@
   virtual void ReportDeoptimization(const Code& code) {
     if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
       Function& function = Function::Handle(code.function());
-      ISL_Print("Deoptimizing %s because guard on field %s failed.\n",
+      THR_Print("Deoptimizing %s because guard on field %s failed.\n",
                 function.ToFullyQualifiedCString(), field_.ToCString());
     }
   }
@@ -7577,7 +7557,7 @@
   virtual void ReportSwitchingCode(const Code& code) {
     if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
       Function& function = Function::Handle(code.function());
-      ISL_Print("Switching %s to unoptimized code because guard"
+      THR_Print("Switching %s to unoptimized code because guard"
                 " on field %s was violated.\n",
                 function.ToFullyQualifiedCString(),
                 field_.ToCString());
@@ -7616,11 +7596,13 @@
 
 
 bool Field::HasPrecompiledInitializer() const {
-  return raw_ptr()->initializer_.precompiled_->IsFunction();
+  return raw_ptr()->initializer_.precompiled_->IsHeapObject() &&
+         raw_ptr()->initializer_.precompiled_->IsFunction();
 }
 
 
 void Field::SetSavedInitialStaticValue(const Instance& value) const {
+  ASSERT(!HasPrecompiledInitializer());
   StorePointer(&raw_ptr()->initializer_.saved_value_, value.raw());
 }
 
@@ -7637,7 +7619,7 @@
     }
     ASSERT(value.IsNull() || value.IsInstance());
     SetStaticValue(value.IsNull() ? Instance::null_instance()
-                             : Instance::Cast(value));
+                                  : Instance::Cast(value));
     return;
   } else if (StaticValue() == Object::transition_sentinel().raw()) {
     SetStaticValue(Object::null_instance());
@@ -7755,7 +7737,7 @@
     }
 
     if (FLAG_trace_field_guards) {
-      ISL_Print("    => %s\n", GuardedPropertiesAsCString());
+      THR_Print("    => %s\n", GuardedPropertiesAsCString());
     }
 
     return false;
@@ -7810,7 +7792,7 @@
   }
 
   if (FLAG_trace_field_guards) {
-    ISL_Print("Store %s %s <- %s\n",
+    THR_Print("Store %s %s <- %s\n",
               ToCString(),
               GuardedPropertiesAsCString(),
               value.ToCString());
@@ -7818,7 +7800,7 @@
 
   if (UpdateGuardedCidAndLength(value)) {
     if (FLAG_trace_field_guards) {
-      ISL_Print("    => %s\n", GuardedPropertiesAsCString());
+      THR_Print("    => %s\n", GuardedPropertiesAsCString());
     }
 
     DeoptimizeDependentCode();
@@ -8620,7 +8602,8 @@
 
 void Script::GetTokenLocation(intptr_t token_pos,
                               intptr_t* line,
-                              intptr_t* column) const {
+                              intptr_t* column,
+                              intptr_t* token_len) const {
   ASSERT(line != NULL);
   const TokenStream& tkns = TokenStream::Handle(tokens());
   if (column == NULL) {
@@ -8642,6 +8625,13 @@
     intptr_t relative_line = scanner.CurrentPosition().line;
     *line = relative_line + line_offset();
     *column = scanner.CurrentPosition().column;
+    if (token_len != NULL) {
+      if (scanner.current_token().literal != NULL) {
+        *token_len = scanner.current_token().literal->Length();
+      } else {
+        *token_len = 1;
+      }
+    }
     // On the first line of the script we must add the column offset.
     if (relative_line == 1) {
       *column += col_offset();
@@ -10198,12 +10188,9 @@
 
 
 const char* Library::ToCString() const {
-  const char* kFormat = "Library:'%s'";
   const String& name = String::Handle(url());
-  intptr_t len = OS::SNPrint(NULL, 0, kFormat, name.ToCString()) + 1;
-  char* chars = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, kFormat, name.ToCString());
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(),
+      "Library:'%s'", name.ToCString());
 }
 
 
@@ -10536,7 +10523,7 @@
 
   virtual void ReportSwitchingCode(const Code& code) {
     if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
-      ISL_Print("Prefix '%s': disabling %s code for %s function '%s'\n",
+      THR_Print("Prefix '%s': disabling %s code for %s function '%s'\n",
           String::Handle(prefix_.name()).ToCString(),
           code.is_optimized() ? "optimized" : "unoptimized",
           CodePatcher::IsEntryPatched(code) ? "patched" : "unpatched",
@@ -10614,12 +10601,9 @@
 
 
 const char* LibraryPrefix::ToCString() const {
-  const char* kFormat = "LibraryPrefix:'%s'";
   const String& prefix = String::Handle(name());
-  intptr_t len = OS::SNPrint(NULL, 0, kFormat, prefix.ToCString()) + 1;
-  char* chars = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, kFormat, prefix.ToCString());
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(),
+      "LibraryPrefix:'%s'", prefix.ToCString());
 }
 
 
@@ -10670,12 +10654,9 @@
 
 
 const char* Namespace::ToCString() const {
-  const char* kFormat = "Namespace for library '%s'";
   const Library& lib = Library::Handle(library());
-  intptr_t len = OS::SNPrint(NULL, 0, kFormat, lib.ToCString()) + 1;
-  char* chars = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, kFormat, lib.ToCString());
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(),
+      "Namespace for library '%s'", lib.ToCString());
 }
 
 
@@ -11053,6 +11034,7 @@
         jsarr.AddValue64(imm);
         break;
       case ObjectPool::kExternalLabel:
+      case ObjectPool::kNativeEntry:
         imm = RawValueAt(i);
         jsarr.AddValueF("0x%" Px, imm);
         break;
@@ -11070,38 +11052,31 @@
     return stub_name;
   }
 
-  RuntimeFunctionId rt_id = RuntimeEntry::RuntimeFunctionIdFromAddress(addr);
-  if (rt_id != kNoRuntimeFunctionId) {
-    return "runtime entry";
-  }
-
-  if (addr == NativeEntry::LinkNativeCallLabel().address()) {
-    return "link native";
-  }
-
   return "UNKNOWN";
 }
 
 
 void ObjectPool::DebugPrint() const {
-  ISL_Print("Object Pool: {\n");
+  THR_Print("Object Pool: {\n");
   for (intptr_t i = 0; i < Length(); i++) {
     intptr_t offset = OffsetFromIndex(i);
-    ISL_Print("  %" Pd " PP+0x%" Px ": ", i, offset);
+    THR_Print("  %" Pd " PP+0x%" Px ": ", i, offset);
     if (InfoAt(i) == kTaggedObject) {
       RawObject* obj = ObjectAt(i);
-      ISL_Print("0x%" Px " %s (obj)\n",
+      THR_Print("0x%" Px " %s (obj)\n",
           reinterpret_cast<uword>(obj),
           Object::Handle(obj).ToCString());
     } else if (InfoAt(i) == kExternalLabel) {
       uword addr = RawValueAt(i);
-      ISL_Print("0x%" Px " (external label: %s)\n",
+      THR_Print("0x%" Px " (external label: %s)\n",
                 addr, DescribeExternalLabel(addr));
+    } else if (InfoAt(i) == kNativeEntry) {
+      THR_Print("0x%" Px " (native entry)\n", RawValueAt(i));
     } else {
-      ISL_Print("0x%" Px " (raw)\n", RawValueAt(i));
+      THR_Print("0x%" Px " (raw)\n", RawValueAt(i));
     }
   }
-  ISL_Print("}\n");
+  THR_Print("}\n");
 }
 
 
@@ -11183,27 +11158,26 @@
   const int addr_width = (kBitsPerWord / 4) + 2;
   // "*" in a printf format specifier tells it to read the field width from
   // the printf argument list.
-  ISL_Print("%-*s\tkind    \tdeopt-id\ttok-ix\ttry-ix\n",
+  THR_Print("%-*s\tkind    \tdeopt-id\ttok-ix\ttry-ix\n",
             addr_width, "pc");
 }
 
 
 const char* PcDescriptors::ToCString() const {
+  // "*" in a printf format specifier tells it to read the field width from
+  // the printf argument list.
+#define FORMAT "%#-*" Px "\t%s\t%" Pd "\t\t%" Pd "\t%" Pd "\n"
   if (Length() == 0) {
     return "empty PcDescriptors\n";
   }
   // 4 bits per hex digit.
   const int addr_width = kBitsPerWord / 4;
-  // "*" in a printf format specifier tells it to read the field width from
-  // the printf argument list.
-  const char* kFormat =
-      "%#-*" Px "\t%s\t%" Pd "\t\t%" Pd "\t%" Pd "\n";
   // First compute the buffer size required.
   intptr_t len = 1;  // Trailing '\0'.
   {
     Iterator iter(*this, RawPcDescriptors::kAnyKind);
     while (iter.MoveNext()) {
-      len += OS::SNPrint(NULL, 0, kFormat, addr_width,
+      len += OS::SNPrint(NULL, 0, FORMAT, addr_width,
                          iter.PcOffset(),
                          KindAsStr(iter.Kind()),
                          iter.DeoptId(),
@@ -11217,7 +11191,7 @@
   intptr_t index = 0;
   Iterator iter(*this, RawPcDescriptors::kAnyKind);
   while (iter.MoveNext()) {
-    index += OS::SNPrint((buffer + index), (len - index), kFormat, addr_width,
+    index += OS::SNPrint((buffer + index), (len - index), FORMAT, addr_width,
                          iter.PcOffset(),
                          KindAsStr(iter.Kind()),
                          iter.DeoptId(),
@@ -11225,6 +11199,7 @@
                          iter.TryIndex());
   }
   return buffer;
+#undef FORMAT
 }
 
 
@@ -11395,11 +11370,11 @@
 
 
 const char* Stackmap::ToCString() const {
+#define FORMAT "%#x: "
   if (IsNull()) {
     return "{null}";
   } else {
-    const char* kFormat = "%#" Px ": ";
-    intptr_t fixed_length = OS::SNPrint(NULL, 0, kFormat, PcOffset()) + 1;
+    intptr_t fixed_length = OS::SNPrint(NULL, 0, FORMAT, PcOffset()) + 1;
     Thread* thread = Thread::Current();
     // Guard against integer overflow in the computation of alloc_size.
     //
@@ -11410,13 +11385,14 @@
     }
     intptr_t alloc_size = fixed_length + Length();
     char* chars = thread->zone()->Alloc<char>(alloc_size);
-    intptr_t index = OS::SNPrint(chars, alloc_size, kFormat, PcOffset());
+    intptr_t index = OS::SNPrint(chars, alloc_size, FORMAT, PcOffset());
     for (intptr_t i = 0; i < Length(); i++) {
       chars[index++] = IsObject(i) ? '1' : '0';
     }
     chars[index] = '\0';
     return chars;
   }
+#undef FORMAT
 }
 
 
@@ -11747,6 +11723,8 @@
 
 
 const char* ExceptionHandlers::ToCString() const {
+#define FORMAT1 "%" Pd " => %#x  (%" Pd " types) (outer %d)\n"
+#define FORMAT2 "  %d. %s\n"
   if (num_entries() == 0) {
     return "empty ExceptionHandlers\n";
   }
@@ -11754,16 +11732,13 @@
   Type& type = Type::Handle();
   RawExceptionHandlers::HandlerInfo info;
   // First compute the buffer size required.
-  const char* kFormat = "%" Pd " => %#" Px "  (%" Pd
-                        " types) (outer %" Pd ")\n";
-  const char* kFormat2 = "  %d. %s\n";
   intptr_t len = 1;  // Trailing '\0'.
   for (intptr_t i = 0; i < num_entries(); i++) {
     GetHandlerInfo(i, &info);
     handled_types = GetHandledTypes(i);
     const intptr_t num_types =
         handled_types.IsNull() ? 0 : handled_types.Length();
-    len += OS::SNPrint(NULL, 0, kFormat,
+    len += OS::SNPrint(NULL, 0, FORMAT1,
                        i,
                        info.handler_pc_offset,
                        num_types,
@@ -11771,7 +11746,7 @@
     for (int k = 0; k < num_types; k++) {
       type ^= handled_types.At(k);
       ASSERT(!type.IsNull());
-      len += OS::SNPrint(NULL, 0, kFormat2, k, type.ToCString());
+      len += OS::SNPrint(NULL, 0, FORMAT2, k, type.ToCString());
     }
   }
   // Allocate the buffer.
@@ -11785,7 +11760,7 @@
         handled_types.IsNull() ? 0 : handled_types.Length();
     num_chars += OS::SNPrint((buffer + num_chars),
                              (len - num_chars),
-                             kFormat,
+                             FORMAT1,
                              i,
                              info.handler_pc_offset,
                              num_types,
@@ -11794,10 +11769,12 @@
       type ^= handled_types.At(k);
       num_chars += OS::SNPrint((buffer + num_chars),
                                (len - num_chars),
-                               kFormat2, k, type.ToCString());
+                               FORMAT2, k, type.ToCString());
     }
   }
   return buffer;
+#undef FORMAT1
+#undef FORMAT2
 }
 
 
@@ -11874,13 +11851,14 @@
 
 const char* DeoptInfo::ToCString(const Array& deopt_table,
                                  const TypedData& packed) {
+#define FORMAT "[%s]"
   GrowableArray<DeoptInstr*> deopt_instrs;
   Unpack(deopt_table, packed, &deopt_instrs);
 
   // Compute the buffer size required.
   intptr_t len = 1;  // Trailing '\0'.
   for (intptr_t i = 0; i < deopt_instrs.length(); i++) {
-    len += OS::SNPrint(NULL, 0, "[%s]", deopt_instrs[i]->ToCString());
+    len += OS::SNPrint(NULL, 0, FORMAT, deopt_instrs[i]->ToCString());
   }
 
   // Allocate the buffer.
@@ -11891,11 +11869,12 @@
   for (intptr_t i = 0; i < deopt_instrs.length(); i++) {
     index += OS::SNPrint((buffer + index),
                          (len - index),
-                         "[%s]",
+                         FORMAT,
                          deopt_instrs[i]->ToCString());
   }
 
   return buffer;
+#undef FORMAT
 }
 
 
@@ -11914,16 +11893,12 @@
 
 
 const char* ICData::ToCString() const {
-  const char* kFormat = "ICData target:'%s' num-args: %" Pd
-                        " num-checks: %" Pd "";
   const String& name = String::Handle(target_name());
   const intptr_t num_args = NumArgsTested();
   const intptr_t num_checks = NumberOfChecks();
-  intptr_t len = OS::SNPrint(NULL, 0, kFormat, name.ToCString(),
-      num_args, num_checks) + 1;
-  char* chars = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, kFormat, name.ToCString(), num_args, num_checks);
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(),
+      "ICData target:'%s' num-args: %" Pd " num-checks: %" Pd "",
+      name.ToCString(), num_args, num_checks);
 }
 
 
@@ -13491,8 +13466,8 @@
 
 
 void Code::DumpInlinedIntervals() const {
-  LogBlock lb(Isolate::Current());
-  ISL_Print("Inlined intervals:\n");
+  LogBlock lb;
+  THR_Print("Inlined intervals:\n");
   const Array& intervals = Array::Handle(GetInlinedIntervals());
   if (intervals.IsNull() || (intervals.Length() == 0)) return;
   Smi& start = Smi::Handle();
@@ -13504,38 +13479,38 @@
     ASSERT(!start.IsNull());
     if (start.IsNull()) continue;
     inlining_id ^= intervals.At(i + Code::kInlIntInliningId);
-    ISL_Print("  %" Px " iid: %" Pd " ; ", start.Value(), inlining_id.Value());
+    THR_Print("  %" Px " iid: %" Pd " ; ", start.Value(), inlining_id.Value());
     inlined_functions.Clear();
 
-    ISL_Print("inlined: ");
+    THR_Print("inlined: ");
     GetInlinedFunctionsAt(start.Value(), &inlined_functions);
 
     for (intptr_t j = 0; j < inlined_functions.length(); j++) {
       const char* name = inlined_functions[j]->ToQualifiedCString();
-      ISL_Print("  %s <-", name);
+      THR_Print("  %s <-", name);
     }
     if (inlined_functions[inlined_functions.length() - 1]->raw() !=
            inliner.raw()) {
-      ISL_Print(" (ERROR, missing inliner)\n");
+      THR_Print(" (ERROR, missing inliner)\n");
     } else {
-      ISL_Print("\n");
+      THR_Print("\n");
     }
   }
-  ISL_Print("Inlined ids:\n");
+  THR_Print("Inlined ids:\n");
   const Array& id_map = Array::Handle(GetInlinedIdToFunction());
   Function& function = Function::Handle();
   for (intptr_t i = 0; i < id_map.Length(); i++) {
     function ^= id_map.At(i);
     if (!function.IsNull()) {
-      ISL_Print("  %" Pd ": %s\n", i, function.ToQualifiedCString());
+      THR_Print("  %" Pd ": %s\n", i, function.ToQualifiedCString());
     }
   }
-  ISL_Print("Caller Inlining Ids:\n");
+  THR_Print("Caller Inlining Ids:\n");
   const Array& caller_map = Array::Handle(GetInlinedCallerIdMap());
   Smi& smi = Smi::Handle();
   for (intptr_t i = 0; i < caller_map.Length(); i++) {
     smi ^= caller_map.At(i);
-    ISL_Print("  iid: %" Pd " caller iid: %" Pd "\n", i, smi.Value());
+    THR_Print("  iid: %" Pd " caller iid: %" Pd "\n", i, smi.Value());
   }
 }
 
@@ -13582,7 +13557,7 @@
 
 static void IndentN(int count) {
   for (int i = 0; i < count; i++) {
-    ISL_Print(" ");
+    THR_Print(" ");
   }
 }
 
@@ -13590,17 +13565,17 @@
 void Context::Dump(int indent) const {
   if (IsNull()) {
     IndentN(indent);
-    ISL_Print("Context@null\n");
+    THR_Print("Context@null\n");
     return;
   }
 
   IndentN(indent);
-  ISL_Print("Context@%p vars(%" Pd ") {\n", this->raw(), num_variables());
+  THR_Print("Context@%p vars(%" Pd ") {\n", this->raw(), num_variables());
   Object& obj = Object::Handle();
   for (intptr_t i = 0; i < num_variables(); i++) {
     IndentN(indent + 2);
     obj = At(i);
-    ISL_Print("[%" Pd "] = %s\n", i, obj.ToCString());
+    THR_Print("[%" Pd "] = %s\n", i, obj.ToCString());
   }
 
   const Context& parent_ctx = Context::Handle(parent());
@@ -13608,7 +13583,7 @@
     parent_ctx.Dump(indent + 2);
   }
   IndentN(indent);
-  ISL_Print("}\n");
+  THR_Print("}\n");
 }
 
 
@@ -13756,8 +13731,6 @@
 
 
 const char* ContextScope::ToCString() const {
-  const char* format =
-      "%s\nvar %s  token-pos %" Pd "  ctx lvl %" Pd "  index %" Pd "";
   const char* prev_cstr = "ContextScope:";
   String& name = String::Handle();
   for (int i = 0; i < num_variables(); i++) {
@@ -13766,10 +13739,9 @@
     intptr_t pos = TokenIndexAt(i);
     intptr_t idx = ContextIndexAt(i);
     intptr_t lvl = ContextLevelAt(i);
-    intptr_t len =
-        OS::SNPrint(NULL, 0, format, prev_cstr, cname, pos, lvl, idx) + 1;
-    char* chars = Thread::Current()->zone()->Alloc<char>(len);
-    OS::SNPrint(chars, len, format, prev_cstr, cname, pos, lvl, idx);
+    char* chars = OS::SCreate(Thread::Current()->zone(),
+        "%s\nvar %s  token-pos %" Pd "  ctx lvl %" Pd "  index %" Pd "",
+        prev_cstr, cname, pos, lvl, idx);
     prev_cstr = chars;
   }
   return prev_cstr;
@@ -13825,9 +13797,8 @@
   const intptr_t capacity = kInitialCapacity;
   const Array& buckets = Array::Handle(
       Array::New(kEntryLength * capacity, Heap::kOld));
-  ASSERT(Isolate::Current()->megamorphic_cache_table()->miss_handler() != NULL);
   const Function& handler = Function::Handle(
-      Isolate::Current()->megamorphic_cache_table()->miss_handler());
+      MegamorphicCacheTable::miss_handler(Isolate::Current()));
   for (intptr_t i = 0; i < capacity; ++i) {
     SetEntry(buckets, i, smi_illegal_cid(), handler);
   }
@@ -13848,7 +13819,7 @@
         Array::Handle(Array::New(kEntryLength * new_capacity));
 
     Function& target = Function::Handle(
-        Isolate::Current()->megamorphic_cache_table()->miss_handler());
+        MegamorphicCacheTable::miss_handler(Isolate::Current()));
     for (intptr_t i = 0; i < new_capacity; ++i) {
       SetEntry(new_buckets, i, smi_illegal_cid(), target);
     }
@@ -13890,7 +13861,7 @@
 
 
 const char* MegamorphicCache::ToCString() const {
-  return "";
+  return "MegamorphicCache";
 }
 
 
@@ -14251,11 +14222,8 @@
   if (!strtmp.IsError()) {
     stack_str = strtmp.ToCString();
   }
-  const char* format = "Unhandled exception:\n%s\n%s";
-  intptr_t len = OS::SNPrint(NULL, 0, format, exc_str, stack_str);
-  char* chars = thread->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, format, exc_str, stack_str);
-  return chars;
+  return OS::SCreate(thread->zone(),
+      "Unhandled exception:\n%s\n%s", exc_str, stack_str);
 }
 
 
@@ -14416,11 +14384,8 @@
           this->SetFieldAtOffset(field_offset, obj);
         } else {
           ASSERT(error_str != NULL);
-          const char* kFormat = "field: %s\n";
-          const intptr_t len =
-              OS::SNPrint(NULL, 0, kFormat, obj.ToCString()) + 1;
-          char* chars = Thread::Current()->zone()->Alloc<char>(len);
-          OS::SNPrint(chars, len, kFormat, obj.ToCString());
+          char* chars = OS::SCreate(Thread::Current()->zone(),
+              "field: %s\n", obj.ToCString());
           *error_str = chars;
           return false;
         }
@@ -14744,7 +14709,6 @@
     if (IsClosure()) {
       return Closure::ToCString(*this);
     }
-    const char* kFormat = "Instance of '%s'";
     const Class& cls = Class::Handle(clazz());
     TypeArguments& type_arguments = TypeArguments::Handle();
     const intptr_t num_type_arguments = cls.NumTypeArguments();
@@ -14754,11 +14718,8 @@
     const Type& type =
         Type::Handle(Type::New(cls, type_arguments, Scanner::kNoSourcePos));
     const String& type_name = String::Handle(type.UserVisibleName());
-    // Calculate the size of the string.
-    intptr_t len = OS::SNPrint(NULL, 0, kFormat, type_name.ToCString()) + 1;
-    char* chars = Thread::Current()->zone()->Alloc<char>(len);
-    OS::SNPrint(chars, len, kFormat, type_name.ToCString());
-    return chars;
+    return OS::SCreate(Thread::Current()->zone(),
+        "Instance of '%s'", type_name.ToCString());
   }
 }
 
@@ -15930,29 +15891,18 @@
     class_name = UnresolvedClass::Handle(unresolved_class()).ToCString();
   }
   if (type_arguments.IsNull()) {
-    const char* format = "%sType: class '%s'";
-    const intptr_t len =
-        OS::SNPrint(NULL, 0, format, unresolved, class_name) + 1;
-    char* chars = Thread::Current()->zone()->Alloc<char>(len);
-    OS::SNPrint(chars, len, format, unresolved, class_name);
-    return chars;
+    return OS::SCreate(Thread::Current()->zone(),
+        "%sType: class '%s'", unresolved, class_name);
   } else if (IsResolved() && IsFinalized() && IsRecursive()) {
-    const char* format = "Type: (@%" Px " H%" Px ") class '%s', args:[%s]";
     const intptr_t hash = Hash();
     const char* args_cstr = TypeArguments::Handle(arguments()).ToCString();
-    const intptr_t len =
-        OS::SNPrint(NULL, 0, format, raw(), hash, class_name, args_cstr) + 1;
-    char* chars = Thread::Current()->zone()->Alloc<char>(len);
-    OS::SNPrint(chars, len, format, raw(), hash, class_name, args_cstr);
-    return chars;
+    return OS::SCreate(Thread::Current()->zone(),
+        "Type: (@%p H%" Px ") class '%s', args:[%s]",
+        raw(), hash, class_name, args_cstr);
   } else {
-    const char* format = "%sType: class '%s', args:[%s]";
     const char* args_cstr = TypeArguments::Handle(arguments()).ToCString();
-    const intptr_t len =
-        OS::SNPrint(NULL, 0, format, unresolved, class_name, args_cstr) + 1;
-    char* chars = Thread::Current()->zone()->Alloc<char>(len);
-    OS::SNPrint(chars, len, format, unresolved, class_name, args_cstr);
-    return chars;
+    return OS::SCreate(Thread::Current()->zone(),
+        "%sType: class '%s', args:[%s]", unresolved, class_name, args_cstr);
   }
 }
 
@@ -16134,19 +16084,12 @@
       type_class()).Name()).ToCString();
   AbstractType& ref_type = AbstractType::Handle(type());
   if (ref_type.IsFinalized()) {
-    const char* format = "TypeRef: %s<...> (@%" Px " H%" Px ")";
     const intptr_t hash = ref_type.Hash();
-    const intptr_t len =
-        OS::SNPrint(NULL, 0, format, type_cstr, ref_type.raw(), hash) + 1;
-    char* chars = Thread::Current()->zone()->Alloc<char>(len);
-    OS::SNPrint(chars, len, format, type_cstr, ref_type.raw(), hash);
-    return chars;
+    return OS::SCreate(Thread::Current()->zone(),
+        "TypeRef: %s<...> (@%p H%" Px ")", type_cstr, ref_type.raw(), hash);
   } else {
-    const char* format = "TypeRef: %s<...>";
-    const intptr_t len = OS::SNPrint(NULL, 0, format, type_cstr) + 1;
-    char* chars = Thread::Current()->zone()->Alloc<char>(len);
-    OS::SNPrint(chars, len, format, type_cstr);
-    return chars;
+    return OS::SCreate(Thread::Current()->zone(),
+        "TypeRef: %s<...>", type_cstr);
   }
 }
 
@@ -17136,12 +17079,7 @@
 
 
 const char* Smi::ToCString() const {
-  const char* kFormat = "%ld";
-  // Calculate the size of the string.
-  intptr_t len = OS::SNPrint(NULL, 0, kFormat, Value()) + 1;
-  char* chars = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, kFormat, Value());
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(), "%" Pd "", Value());
 }
 
 
@@ -17267,12 +17205,7 @@
 
 
 const char* Mint::ToCString() const {
-  const char* kFormat = "%lld";
-  // Calculate the size of the string.
-  intptr_t len = OS::SNPrint(NULL, 0, kFormat, value()) + 1;
-  char* chars = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, kFormat, value());
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(), "%" Pd64 "", value());
 }
 
 
@@ -20120,11 +20053,8 @@
         this->SetAt(i, obj);
       } else {
         ASSERT(error_str != NULL);
-        const char* kFormat = "element at index %" Pd ": %s\n";
-        const intptr_t len =
-            OS::SNPrint(NULL, 0, kFormat, i, obj.ToCString()) + 1;
-        char* chars = Thread::Current()->zone()->Alloc<char>(len);
-        OS::SNPrint(chars, len, kFormat, i, obj.ToCString());
+        char* chars = OS::SCreate(Thread::Current()->zone(),
+            "element at index %" Pd ": %s\n", i, obj.ToCString());
         *error_str = chars;
         return false;
       }
@@ -20248,11 +20178,8 @@
   if (IsNull()) {
     return "_GrowableList NULL";
   }
-  const char* format = "Instance(length:%" Pd ") of '_GrowableList'";
-  intptr_t len = OS::SNPrint(NULL, 0, format, Length()) + 1;
-  char* chars = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, format, Length());
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(),
+      "Instance(length:%" Pd ") of '_GrowableList'", Length());
 }
 
 
@@ -20474,16 +20401,12 @@
 
 
 const char* Float32x4::ToCString() const {
-  const char* kFormat = "[%f, %f, %f, %f]";
   float _x = x();
   float _y = y();
   float _z = z();
   float _w = w();
-  // Calculate the size of the string.
-  intptr_t len = OS::SNPrint(NULL, 0, kFormat, _x, _y, _z, _w) + 1;
-  char* chars = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, kFormat, _x, _y, _z, _w);
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(),
+      "[%f, %f, %f, %f]", _x, _y, _z, _w);
 }
 
 
@@ -20583,16 +20506,12 @@
 
 
 const char* Int32x4::ToCString() const {
-  const char* kFormat = "[%08x, %08x, %08x, %08x]";
   int32_t _x = x();
   int32_t _y = y();
   int32_t _z = z();
   int32_t _w = w();
-  // Calculate the size of the string.
-  intptr_t len = OS::SNPrint(NULL, 0, kFormat, _x, _y, _z, _w) + 1;
-  char* chars = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, kFormat, _x, _y, _z, _w);
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(),
+      "[%08x, %08x, %08x, %08x]", _x, _y, _z, _w);
 }
 
 
@@ -20669,14 +20588,9 @@
 
 
 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 = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, kFormat, _x, _y);
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(), "[%f, %f]", _x, _y);
 }
 
 
@@ -20946,11 +20860,8 @@
   const char* fun_sig = String::Handle(fun.UserVisibleSignature()).ToCString();
   const char* from = is_implicit_closure ? " from " : "";
   const char* fun_desc = is_implicit_closure ? fun.ToCString() : "";
-  const char* format = "Closure: %s%s%s";
-  intptr_t len = OS::SNPrint(NULL, 0, format, fun_sig, from, fun_desc) + 1;
-  char* chars = Thread::Current()->zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, format, fun_sig, from, fun_desc);
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(),
+      "Closure: %s%s%s", fun_sig, from, fun_desc);
 }
 
 
@@ -21069,9 +20980,6 @@
                                    const Function& function,
                                    const Code& code,
                                    intptr_t frame_index) {
-  const char* kFormatWithCol = "#%-6d %s (%s:%d:%d)\n";
-  const char* kFormatNoCol = "#%-6d %s (%s:%d)\n";
-  const char* kFormatNoLine = "#%-6d %s (%s)\n";
   const intptr_t token_pos = code.GetTokenIndexOfPC(pc);
   const Script& script = Script::Handle(zone, function.script());
   const String& function_name =
@@ -21086,36 +20994,22 @@
       script.GetTokenLocation(token_pos, &line, NULL);
     }
   }
-  intptr_t len = 0;
   char* chars = NULL;
   if (column >= 0) {
-    len = OS::SNPrint(NULL, 0, kFormatWithCol,
-                      frame_index, function_name.ToCString(),
-                      url.ToCString(), line, column);
-    chars = zone->Alloc<char>(len + 1);
-    OS::SNPrint(chars, (len + 1), kFormatWithCol,
-                frame_index,
-                function_name.ToCString(),
-                url.ToCString(), line, column);
+    chars = OS::SCreate(zone,
+        "#%-6" Pd " %s (%s:%" Pd ":%" Pd ")\n",
+        frame_index, function_name.ToCString(), url.ToCString(), line, column);
   } else if (line >= 0) {
-    len = OS::SNPrint(NULL, 0, kFormatNoCol,
-                      frame_index, function_name.ToCString(),
-                      url.ToCString(), line);
-    chars = zone->Alloc<char>(len + 1);
-    OS::SNPrint(chars, (len + 1), kFormatNoCol,
-                frame_index, function_name.ToCString(),
-                url.ToCString(), line);
+    chars = OS::SCreate(zone,
+        "#%-6" Pd " %s (%s:%" Pd ")\n",
+        frame_index, function_name.ToCString(), url.ToCString(), line);
   } else {
-    len = OS::SNPrint(NULL, 0, kFormatNoLine,
-                      frame_index, function_name.ToCString(),
-                      url.ToCString());
-    chars = zone->Alloc<char>(len + 1);
-    OS::SNPrint(chars, (len + 1), kFormatNoLine,
-                frame_index, function_name.ToCString(),
-                url.ToCString());
+    chars = OS::SCreate(zone,
+        "#%-6" Pd " %s (%s)\n",
+        frame_index, function_name.ToCString(), url.ToCString());
   }
   frame_strings->Add(chars);
-  return len;
+  return strlen(chars);
 }
 
 
@@ -21282,11 +21176,8 @@
 
 const char* JSRegExp::ToCString() const {
   const String& str = String::Handle(pattern());
-  const char* format = "JSRegExp: pattern=%s flags=%s";
-  intptr_t len = OS::SNPrint(NULL, 0, format, str.ToCString(), Flags());
-  char* chars = Thread::Current()->zone()->Alloc<char>(len + 1);
-  OS::SNPrint(chars, (len + 1), format, str.ToCString(), Flags());
-  return chars;
+  return OS::SCreate(Thread::Current()->zone(),
+      "JSRegExp: pattern=%s flags=%s", str.ToCString(), Flags());
 }
 
 
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 9d1326e..75ec1f4 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1751,6 +1751,10 @@
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(RawPatchClass));
   }
+  static bool IsInFullSnapshot(RawPatchClass* cls) {
+    NoSafepointScope no_safepoint;
+    return Class::IsInFullSnapshot(cls->ptr()->patched_class_);
+  }
 
   static RawPatchClass* New(const Class& patched_class,
                             const Class& source_class);
@@ -3222,7 +3226,9 @@
   void SetLocationOffset(intptr_t line_offset, intptr_t col_offset) const;
 
   void GetTokenLocation(intptr_t token_pos,
-                        intptr_t* line, intptr_t* column) const;
+                        intptr_t* line,
+                        intptr_t* column,
+                        intptr_t* token_len = NULL) const;
 
   // Returns index of first and last token on the given line. Returns both
   // indices < 0 if no token exists on or after the line. If a token exists
@@ -3604,6 +3610,7 @@
     kTaggedObject,
     kImmediate,
     kExternalLabel,
+    kNativeEntry,
   };
 
   struct Entry {
@@ -8033,6 +8040,7 @@
   ASSERT(is_static());  // Valid only for static dart fields.
   StorePointer(&raw_ptr()->value_.static_value_, value.raw());
   if (save_initial_value) {
+    ASSERT(!HasPrecompiledInitializer());
     StorePointer(&raw_ptr()->initializer_.saved_value_, value.raw());
   }
 }
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 25469da..8c32a4a 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -88,7 +88,10 @@
     empty_uint32_array_(TypedData::null()),
     handle_message_function_(Function::null()),
     library_load_error_table_(Array::null()),
-    compile_time_constants_(Array::null()) {
+    compile_time_constants_(Array::null()),
+    megamorphic_cache_table_(GrowableObjectArray::null()),
+    megamorphic_miss_code_(Code::null()),
+    megamorphic_miss_function_(Function::null()) {
   for (RawObject** current = from(); current <= to(); current++) {
     ASSERT(*current == Object::null());
   }
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index e22a096..fda986d 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -433,6 +433,21 @@
     compile_time_constants_ = value.raw();
   }
 
+  RawGrowableObjectArray* megamorphic_cache_table() const {
+    return megamorphic_cache_table_;
+  }
+  void set_megamorphic_cache_table(const GrowableObjectArray& value) {
+    megamorphic_cache_table_ = value.raw();
+  }
+  RawFunction* megamorphic_miss_function() const {
+    return megamorphic_miss_function_;
+  }
+  void SetMegamorphicMissHandler(const Code& code, const Function& func) {
+    // Hold onto the code so it is traced and not detached from the function.
+    megamorphic_miss_code_ = code.raw();
+    megamorphic_miss_function_ = func.raw();
+  }
+
   // Visit all object pointers.
   void VisitObjectPointers(ObjectPointerVisitor* visitor);
 
@@ -523,10 +538,17 @@
   RawFunction* handle_message_function_;
   RawArray* library_load_error_table_;
   RawArray* compile_time_constants_;
-  RawObject** to() {
+  RawObject** to_snapshot() {
     return reinterpret_cast<RawObject**>(&compile_time_constants_);
   }
+  RawGrowableObjectArray* megamorphic_cache_table_;
+  RawCode* megamorphic_miss_code_;
+  RawFunction* megamorphic_miss_function_;
+  RawObject** to() {
+    return reinterpret_cast<RawObject**>(&megamorphic_miss_function_);
+  }
 
+  friend class FullSnapshotWriter;
   friend class SnapshotReader;
   friend class VmIsolateSnapshotReader;
 
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 692a03b..c7ddd97 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -4229,40 +4229,6 @@
 }
 
 
-// Elide a substring which starts with some prefix and ends with a ".
-//
-// This is used to remove non-deterministic or fragile substrings from
-// JSON output.
-//
-// For example:
-//
-//    prefix = "classes"
-//    in = "\"id\":\"classes/46\""
-//
-// Yields:
-//
-//    out = "\"id\":\"\""
-//
-static void elideSubstring(const char* prefix, const char* in, char* out) {
-  const char* pos = strstr(in, prefix);
-  while (pos != NULL) {
-    // Copy up to pos into the output buffer.
-    while (in < pos) {
-      *out++ = *in++;
-    }
-
-    // Skip to the close quote.
-    in += strcspn(in, "\"");
-    pos = strstr(in, prefix);
-  }
-  // Copy the remainder of in to out.
-  while (*in != '\0') {
-    *out++ = *in++;
-  }
-  *out = '\0';
-}
-
-
 TEST_CASE(PrintJSONPrimitives) {
   char buffer[1024];
   Isolate* isolate = Isolate::Current();
@@ -4272,7 +4238,7 @@
     JSONStream js;
     Class& cls = Class::Handle(isolate->object_store()->bool_class());
     cls.PrintJSON(&js, true);
-    elideSubstring("classes", js.ToCString(), buffer);
+    ElideJSONSubstring("classes", js.ToCString(), buffer);
     EXPECT_STREQ(
         "{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\",\"name\":\"bool\"}",
         buffer);
@@ -4285,7 +4251,7 @@
     Function& func = Function::Handle(cls.LookupFunction(func_name));
     ASSERT(!func.IsNull());
     func.PrintJSON(&js, true);
-    elideSubstring("classes", js.ToCString(), buffer);
+    ElideJSONSubstring("classes", js.ToCString(), buffer);
     EXPECT_STREQ(
         "{\"type\":\"@Function\",\"fixedId\":true,"
         "\"id\":\"\",\"name\":\"toString\","
@@ -4300,7 +4266,7 @@
     JSONStream js;
     Library& lib = Library::Handle(isolate->object_store()->core_library());
     lib.PrintJSON(&js, true);
-    elideSubstring("libraries", js.ToCString(), buffer);
+    ElideJSONSubstring("libraries", js.ToCString(), buffer);
     EXPECT_STREQ(
         "{\"type\":\"@Library\",\"fixedId\":true,\"id\":\"\","
         "\"name\":\"dart.core\",\"uri\":\"dart:core\"}",
@@ -4310,7 +4276,7 @@
   {
     JSONStream js;
     Bool::True().PrintJSON(&js, true);
-    elideSubstring("classes", js.ToCString(), buffer);
+    ElideJSONSubstring("classes", js.ToCString(), buffer);
     EXPECT_STREQ(
         "{\"type\":\"@Instance\","
         "\"_vmType\":\"Bool\","
@@ -4326,8 +4292,8 @@
     JSONStream js;
     const Integer& smi = Integer::Handle(Integer::New(7));
     smi.PrintJSON(&js, true);
-    elideSubstring("classes", js.ToCString(), buffer);
-    elideSubstring("_Smi@", buffer, buffer);
+    ElideJSONSubstring("classes", js.ToCString(), buffer);
+    ElideJSONSubstring("_Smi@", buffer, buffer);
     EXPECT_STREQ(
         "{\"type\":\"@Instance\","
         "\"_vmType\":\"Smi\","
@@ -4344,9 +4310,9 @@
     JSONStream js;
     const Integer& smi = Integer::Handle(Integer::New(Mint::kMinValue));
     smi.PrintJSON(&js, true);
-    elideSubstring("classes", js.ToCString(), buffer);
-    elideSubstring("objects", buffer, buffer);
-    elideSubstring("_Mint@", buffer, buffer);
+    ElideJSONSubstring("classes", js.ToCString(), buffer);
+    ElideJSONSubstring("objects", buffer, buffer);
+    ElideJSONSubstring("_Mint@", buffer, buffer);
     EXPECT_STREQ(
         "{\"type\":\"@Instance\","
         "\"_vmType\":\"Mint\","
@@ -4363,9 +4329,9 @@
         String::Handle(String::New("44444444444444444444444444444444"));
     const Integer& bigint = Integer::Handle(Integer::New(bigint_str));
     bigint.PrintJSON(&js, true);
-    elideSubstring("classes", js.ToCString(), buffer);
-    elideSubstring("objects", buffer, buffer);
-    elideSubstring("_Bigint@", buffer, buffer);
+    ElideJSONSubstring("classes", js.ToCString(), buffer);
+    ElideJSONSubstring("objects", buffer, buffer);
+    ElideJSONSubstring("_Bigint@", buffer, buffer);
     EXPECT_STREQ(
         "{\"type\":\"@Instance\","
         "\"_vmType\":\"Bigint\","
@@ -4380,9 +4346,9 @@
     JSONStream js;
     const Double& dub = Double::Handle(Double::New(0.1234));
     dub.PrintJSON(&js, true);
-    elideSubstring("classes", js.ToCString(), buffer);
-    elideSubstring("objects", buffer, buffer);
-    elideSubstring("_Double@", buffer, buffer);
+    ElideJSONSubstring("classes", js.ToCString(), buffer);
+    ElideJSONSubstring("objects", buffer, buffer);
+    ElideJSONSubstring("_Double@", buffer, buffer);
     EXPECT_STREQ(
         "{\"type\":\"@Instance\","
         "\"_vmType\":\"Double\","
@@ -4397,9 +4363,9 @@
     JSONStream js;
     const String& str = String::Handle(String::New("dw"));
     str.PrintJSON(&js, true);
-    elideSubstring("classes", js.ToCString(), buffer);
-    elideSubstring("objects", buffer, buffer);
-    elideSubstring("_OneByteString@", buffer, buffer);
+    ElideJSONSubstring("classes", js.ToCString(), buffer);
+    ElideJSONSubstring("objects", buffer, buffer);
+    ElideJSONSubstring("_OneByteString@", buffer, buffer);
     EXPECT_STREQ(
         "{\"type\":\"@Instance\","
         "\"_vmType\":\"String\","
@@ -4414,9 +4380,9 @@
     JSONStream js;
     const Array& array = Array::Handle(Array::New(0));
     array.PrintJSON(&js, true);
-    elideSubstring("classes", js.ToCString(), buffer);
-    elideSubstring("objects", buffer, buffer);
-    elideSubstring("_List@", buffer, buffer);
+    ElideJSONSubstring("classes", js.ToCString(), buffer);
+    ElideJSONSubstring("objects", buffer, buffer);
+    ElideJSONSubstring("_List@", buffer, buffer);
     EXPECT_STREQ(
         "{\"type\":\"@Instance\","
         "\"_vmType\":\"Array\","
@@ -4432,9 +4398,9 @@
     const GrowableObjectArray& array =
         GrowableObjectArray::Handle(GrowableObjectArray::New());
     array.PrintJSON(&js, true);
-    elideSubstring("classes", js.ToCString(), buffer);
-    elideSubstring("objects", buffer, buffer);
-    elideSubstring("_GrowableList@", buffer, buffer);
+    ElideJSONSubstring("classes", js.ToCString(), buffer);
+    ElideJSONSubstring("objects", buffer, buffer);
+    ElideJSONSubstring("_GrowableList@", buffer, buffer);
     EXPECT_STREQ(
         "{\"type\":\"@Instance\","
         "\"_vmType\":\"GrowableObjectArray\","
@@ -4451,9 +4417,9 @@
     const LinkedHashMap& array =
         LinkedHashMap::Handle(LinkedHashMap::NewDefault());
     array.PrintJSON(&js, true);
-    elideSubstring("classes", js.ToCString(), buffer);
-    elideSubstring("objects", buffer, buffer);
-    elideSubstring("_InternalLinkedHashMap@", buffer, buffer);
+    ElideJSONSubstring("classes", js.ToCString(), buffer);
+    ElideJSONSubstring("objects", buffer, buffer);
+    ElideJSONSubstring("_InternalLinkedHashMap@", buffer, buffer);
     EXPECT_STREQ(
         "{\"type\":\"@Instance\","
         "\"_vmType\":\"LinkedHashMap\","
@@ -4469,9 +4435,9 @@
     JSONStream js;
     Instance& tag = Instance::Handle(isolate->default_tag());
     tag.PrintJSON(&js, true);
-    elideSubstring("classes", js.ToCString(), buffer);
-    elideSubstring("objects", buffer, buffer);
-    elideSubstring("_UserTag@", buffer, buffer);
+    ElideJSONSubstring("classes", js.ToCString(), buffer);
+    ElideJSONSubstring("objects", buffer, buffer);
+    ElideJSONSubstring("_UserTag@", buffer, buffer);
     EXPECT_STREQ(
         "{\"type\":\"@Instance\","
         "\"_vmType\":\"UserTag\","
@@ -4487,9 +4453,9 @@
     JSONStream js;
     Instance& type = Instance::Handle(isolate->object_store()->bool_type());
     type.PrintJSON(&js, true);
-    elideSubstring("classes", js.ToCString(), buffer);
-    elideSubstring("objects", buffer, buffer);
-    elideSubstring("_Type@", buffer, buffer);
+    ElideJSONSubstring("classes", js.ToCString(), buffer);
+    ElideJSONSubstring("objects", buffer, buffer);
+    ElideJSONSubstring("_Type@", buffer, buffer);
     EXPECT_STREQ(
         "{\"type\":\"@Instance\","
         "\"_vmType\":\"Type\","
@@ -4505,14 +4471,17 @@
   {
     JSONStream js;
     Object::null_object().PrintJSON(&js, true);
+    ElideJSONSubstring("classes", js.ToCString(), buffer);
     EXPECT_STREQ(
         "{\"type\":\"@Instance\","
         "\"_vmType\":\"null\","
+        "\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
+        "\"name\":\"Null\"},"
         "\"kind\":\"Null\","
         "\"fixedId\":true,"
         "\"id\":\"objects\\/null\","
         "\"valueAsString\":\"null\"}",
-        js.ToCString());
+        buffer);
   }
   // Sentinel reference
   {
@@ -4541,7 +4510,7 @@
     JSONStream js;
     LiteralToken& tok = LiteralToken::Handle(LiteralToken::New());
     tok.PrintJSON(&js, true);
-    elideSubstring("objects", js.ToCString(), buffer);
+    ElideJSONSubstring("objects", js.ToCString(), buffer);
     EXPECT_STREQ(
         "{\"type\":\"@Object\",\"_vmType\":\"LiteralToken\",\"id\":\"\"}",
         buffer);
diff --git a/runtime/vm/os.h b/runtime/vm/os.h
index 60456e4..871b23e 100644
--- a/runtime/vm/os.h
+++ b/runtime/vm/os.h
@@ -14,6 +14,7 @@
 
 // Forward declarations.
 class Isolate;
+class Zone;
 
 // Interface to the underlying OS platform.
 class OS {
@@ -120,6 +121,13 @@
                       const char* format,
                       va_list args);
 
+  // Allocate a string and print formatted output into the buffer.
+  // Uses the zone for allocation if one if provided, and otherwise uses
+  // malloc.
+  static char* SCreate(Zone* zone, const char* format, ...)
+      PRINTF_ATTRIBUTE(2, 3);
+  static char* VSCreate(Zone* zone, const char* format, va_list args);
+
   // Converts a C string which represents a valid dart integer into a 64 bit
   // value.
   // Returns false if it is unable to convert the string to a 64 bit value,
diff --git a/runtime/vm/os_android.cc b/runtime/vm/os_android.cc
index 676e278..0966a52 100644
--- a/runtime/vm/os_android.cc
+++ b/runtime/vm/os_android.cc
@@ -44,12 +44,10 @@
     if (file_open == NULL) {
       return;
     }
-    const char* format = "/tmp/perf-%ld.map";
     intptr_t pid = getpid();
-    intptr_t len = OS::SNPrint(NULL, 0, format, pid);
-    char* filename = new char[len + 1];
-    OS::SNPrint(filename, len + 1, format, pid);
+    char* filename = OS::SCreate(NULL, "/tmp/perf-%" Pd ".map", pid);
     out_file_ = (*file_open)(filename, true);
+    free(filename);
   }
 
   ~PerfCodeObserver() {
@@ -73,12 +71,10 @@
     if ((file_write == NULL) || (out_file_ == NULL)) {
       return;
     }
-    const char* format = "%" Px " %" Px " %s%s\n";
     const char* marker = optimized ? "*" : "";
-    intptr_t len = OS::SNPrint(NULL, 0, format, base, size, marker, name);
-    char* buffer = Thread::Current()->zone()->Alloc<char>(len + 1);
-    OS::SNPrint(buffer, len + 1, format, base, size, marker, name);
-    (*file_write)(buffer, len, out_file_);
+    char* buffer = OS::SCreate(Thread::Current()->zone(),
+        "%" Px " %" Px " %s%s\n", base, size, marker, name);
+    (*file_write)(buffer, strlen(buffer), out_file_);
   }
 
  private:
@@ -107,10 +103,8 @@
       // the prologue sequence is not the first instruction:
       // <name>_entry is used for code preceding the prologue sequence.
       // <name> for rest of the code (first instruction is prologue sequence).
-      const char* kFormat = "%s_%s";
-      intptr_t len = OS::SNPrint(NULL, 0, kFormat, name, "entry");
-      char* pname = Thread::Current()->zone()->Alloc<char>(len + 1);
-      OS::SNPrint(pname, (len + 1), kFormat, name, "entry");
+      char* pname = OS::SCreate(Thread::Current()->zone(),
+          "%s_%s", name, "entry");
       DebugInfo::RegisterSection(pname, base, size);
       DebugInfo::RegisterSection(name,
                                  (base + prologue_offset),
@@ -354,6 +348,39 @@
 }
 
 
+char* OS::SCreate(Zone* zone, const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  char* buffer = VSCreate(zone, format, args);
+  va_end(args);
+  return buffer;
+}
+
+
+char* OS::VSCreate(Zone* zone, const char* format, va_list args) {
+  // Measure.
+  va_list measure_args;
+  va_copy(measure_args, args);
+  intptr_t len = VSNPrint(NULL, 0, format, measure_args);
+  va_end(measure_args);
+
+  char* buffer;
+  if (zone) {
+    buffer = zone->Alloc<char>(len + 1);
+  } else {
+    buffer = reinterpret_cast<char*>(malloc(len + 1));
+  }
+  ASSERT(buffer != NULL);
+
+  // Print.
+  va_list print_args;
+  va_copy(print_args, args);
+  VSNPrint(buffer, len + 1, format, print_args);
+  va_end(print_args);
+  return buffer;
+}
+
+
 bool OS::StringToInt64(const char* str, int64_t* value) {
   ASSERT(str != NULL && strlen(str) > 0 && value != NULL);
   int32_t base = 10;
diff --git a/runtime/vm/os_linux.cc b/runtime/vm/os_linux.cc
index 288db46..73fc0ea 100644
--- a/runtime/vm/os_linux.cc
+++ b/runtime/vm/os_linux.cc
@@ -49,13 +49,10 @@
     if (file_open == NULL) {
       return;
     }
-    const char* format = "/tmp/perf-%" Pd ".map";
     intptr_t pid = getpid();
-    intptr_t len = OS::SNPrint(NULL, 0, format, pid);
-    char* filename = new char[len + 1];
-    OS::SNPrint(filename, len + 1, format, pid);
+    char* filename = OS::SCreate(NULL, "/tmp/perf-%" Pd ".map", pid);
     out_file_ = (*file_open)(filename, true);
-    delete[] filename;
+    free(filename);
   }
 
   ~PerfCodeObserver() {
@@ -79,14 +76,12 @@
     if ((file_write == NULL) || (out_file_ == NULL)) {
       return;
     }
-    const char* format = "%" Px " %" Px " %s%s\n";
     const char* marker = optimized ? "*" : "";
-    intptr_t len = OS::SNPrint(NULL, 0, format, base, size, marker, name);
-    char* buffer = Thread::Current()->zone()->Alloc<char>(len + 1);
-    OS::SNPrint(buffer, len + 1, format, base, size, marker, name);
+    char* buffer = OS::SCreate(Thread::Current()->zone(),
+        "%" Px " %" Px " %s%s\n", base, size, marker, name);
     {
       MutexLocker ml(CodeObservers::mutex());
-      (*file_write)(buffer, len, out_file_);
+      (*file_write)(buffer, strlen(buffer), out_file_);
     }
   }
 
@@ -116,10 +111,8 @@
       // the prologue sequence is not the first instruction:
       // <name>_entry is used for code preceding the prologue sequence.
       // <name> for rest of the code (first instruction is prologue sequence).
-      const char* kFormat = "%s_%s";
-      intptr_t len = OS::SNPrint(NULL, 0, kFormat, name, "entry");
-      char* pname = Thread::Current()->zone()->Alloc<char>(len + 1);
-      OS::SNPrint(pname, (len + 1), kFormat, name, "entry");
+      char* pname = OS::SCreate(Thread::Current()->zone(),
+          "%s_%s", name, "entry");
       DebugInfo::RegisterSection(pname, base, size);
       DebugInfo::RegisterSection(name,
                                  (base + prologue_offset),
@@ -245,12 +238,8 @@
   };
 
   const char* GenerateCodeName(const char* name, bool optimized) {
-    const char* format = "%s%s";
     const char* marker = optimized ? "*" : "";
-    intptr_t len = OS::SNPrint(NULL, 0, format, marker, name);
-    char* buffer = Thread::Current()->zone()->Alloc<char>(len + 1);
-    OS::SNPrint(buffer, len + 1, format, marker, name);
-    return buffer;
+    return OS::SCreate(Thread::Current()->zone(), "%s%s", marker, name);
   }
 
   uint32_t GetElfMach() {
@@ -549,6 +538,39 @@
 }
 
 
+char* OS::SCreate(Zone* zone, const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  char* buffer = VSCreate(zone, format, args);
+  va_end(args);
+  return buffer;
+}
+
+
+char* OS::VSCreate(Zone* zone, const char* format, va_list args) {
+  // Measure.
+  va_list measure_args;
+  va_copy(measure_args, args);
+  intptr_t len = VSNPrint(NULL, 0, format, measure_args);
+  va_end(measure_args);
+
+  char* buffer;
+  if (zone) {
+    buffer = zone->Alloc<char>(len + 1);
+  } else {
+    buffer = reinterpret_cast<char*>(malloc(len + 1));
+  }
+  ASSERT(buffer != NULL);
+
+  // Print.
+  va_list print_args;
+  va_copy(print_args, args);
+  VSNPrint(buffer, len + 1, format, print_args);
+  va_end(print_args);
+  return buffer;
+}
+
+
 bool OS::StringToInt64(const char* str, int64_t* value) {
   ASSERT(str != NULL && strlen(str) > 0 && value != NULL);
   int32_t base = 10;
diff --git a/runtime/vm/os_macos.cc b/runtime/vm/os_macos.cc
index efdcd2b..ce4003e 100644
--- a/runtime/vm/os_macos.cc
+++ b/runtime/vm/os_macos.cc
@@ -18,6 +18,7 @@
 
 #include "platform/utils.h"
 #include "vm/isolate.h"
+#include "vm/zone.h"
 
 namespace dart {
 
@@ -214,6 +215,39 @@
 }
 
 
+char* OS::SCreate(Zone* zone, const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  char* buffer = VSCreate(zone, format, args);
+  va_end(args);
+  return buffer;
+}
+
+
+char* OS::VSCreate(Zone* zone, const char* format, va_list args) {
+  // Measure.
+  va_list measure_args;
+  va_copy(measure_args, args);
+  intptr_t len = VSNPrint(NULL, 0, format, measure_args);
+  va_end(measure_args);
+
+  char* buffer;
+  if (zone) {
+    buffer = zone->Alloc<char>(len + 1);
+  } else {
+    buffer = reinterpret_cast<char*>(malloc(len + 1));
+  }
+  ASSERT(buffer != NULL);
+
+  // Print.
+  va_list print_args;
+  va_copy(print_args, args);
+  VSNPrint(buffer, len + 1, format, print_args);
+  va_end(print_args);
+  return buffer;
+}
+
+
 bool OS::StringToInt64(const char* str, int64_t* value) {
   ASSERT(str != NULL && strlen(str) > 0 && value != NULL);
   int32_t base = 10;
diff --git a/runtime/vm/os_thread.h b/runtime/vm/os_thread.h
index 36436aa..5d6a21e 100644
--- a/runtime/vm/os_thread.h
+++ b/runtime/vm/os_thread.h
@@ -29,6 +29,7 @@
  public:
   static ThreadLocalKey kUnsetThreadLocalKey;
   static ThreadId kInvalidThreadId;
+  static ThreadJoinId kInvalidThreadJoinId;
 
   typedef void (*ThreadStartFunction) (uword parameter);
   typedef void (*ThreadDestructor) (void* parameter);
@@ -47,7 +48,11 @@
   static void SetThreadLocal(ThreadLocalKey key, uword value);
   static intptr_t GetMaxStackSize();
   static ThreadId GetCurrentThreadId();
-  static bool Join(ThreadId id);
+  static intptr_t CurrentCurrentThreadIdAsIntPtr() {
+    return ThreadIdToIntPtr(GetCurrentThreadId());
+  }
+  static ThreadJoinId GetCurrentThreadJoinId();
+  static void Join(ThreadJoinId id);
   static intptr_t ThreadIdToIntPtr(ThreadId id);
   static ThreadId ThreadIdFromIntPtr(intptr_t id);
   static bool Compare(ThreadId a, ThreadId b);
diff --git a/runtime/vm/os_thread_android.cc b/runtime/vm/os_thread_android.cc
index 377fd94..1f8de35 100644
--- a/runtime/vm/os_thread_android.cc
+++ b/runtime/vm/os_thread_android.cc
@@ -101,9 +101,6 @@
   int result = pthread_attr_init(&attr);
   RETURN_ON_PTHREAD_FAILURE(result);
 
-  result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-  RETURN_ON_PTHREAD_FAILURE(result);
-
   result = pthread_attr_setstacksize(&attr, OSThread::GetMaxStackSize());
   RETURN_ON_PTHREAD_FAILURE(result);
 
@@ -123,6 +120,7 @@
 ThreadLocalKey OSThread::kUnsetThreadLocalKey =
     static_cast<pthread_key_t>(-1);
 ThreadId OSThread::kInvalidThreadId = static_cast<ThreadId>(0);
+ThreadJoinId OSThread::kInvalidThreadJoinId = static_cast<ThreadJoinId>(0);
 
 ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
   pthread_key_t key = kUnsetThreadLocalKey;
@@ -158,8 +156,13 @@
 }
 
 
-bool OSThread::Join(ThreadId id) {
-  return false;
+ThreadJoinId OSThread::GetCurrentThreadJoinId() {
+  return pthread_self();
+}
+
+
+void OSThread::Join(ThreadJoinId id) {
+  ASSERT(pthread_join(id, NULL) == 0);
 }
 
 
diff --git a/runtime/vm/os_thread_android.h b/runtime/vm/os_thread_android.h
index 5ac0f81..061066e 100644
--- a/runtime/vm/os_thread_android.h
+++ b/runtime/vm/os_thread_android.h
@@ -17,7 +17,8 @@
 namespace dart {
 
 typedef pthread_key_t ThreadLocalKey;
-typedef pthread_t ThreadId;
+typedef pid_t ThreadId;
+typedef pthread_t ThreadJoinId;
 
 class ThreadInlineImpl {
  private:
diff --git a/runtime/vm/os_thread_linux.cc b/runtime/vm/os_thread_linux.cc
index c99189b..f9bb9b5 100644
--- a/runtime/vm/os_thread_linux.cc
+++ b/runtime/vm/os_thread_linux.cc
@@ -102,9 +102,6 @@
   int result = pthread_attr_init(&attr);
   RETURN_ON_PTHREAD_FAILURE(result);
 
-  result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-  RETURN_ON_PTHREAD_FAILURE(result);
-
   result = pthread_attr_setstacksize(&attr, OSThread::GetMaxStackSize());
   RETURN_ON_PTHREAD_FAILURE(result);
 
@@ -124,6 +121,7 @@
 ThreadLocalKey OSThread::kUnsetThreadLocalKey =
     static_cast<pthread_key_t>(-1);
 ThreadId OSThread::kInvalidThreadId = static_cast<ThreadId>(0);
+ThreadJoinId OSThread::kInvalidThreadJoinId = static_cast<ThreadJoinId>(0);
 
 ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
   pthread_key_t key = kUnsetThreadLocalKey;
@@ -159,8 +157,13 @@
 }
 
 
-bool OSThread::Join(ThreadId id) {
-  return false;
+ThreadJoinId OSThread::GetCurrentThreadJoinId() {
+  return pthread_self();
+}
+
+
+void OSThread::Join(ThreadJoinId id) {
+  ASSERT(pthread_join(id, NULL) == 0);
 }
 
 
diff --git a/runtime/vm/os_thread_linux.h b/runtime/vm/os_thread_linux.h
index 840b36e..5901214 100644
--- a/runtime/vm/os_thread_linux.h
+++ b/runtime/vm/os_thread_linux.h
@@ -18,6 +18,7 @@
 
 typedef pthread_key_t ThreadLocalKey;
 typedef pthread_t ThreadId;
+typedef pthread_t ThreadJoinId;
 
 class ThreadInlineImpl {
  private:
diff --git a/runtime/vm/os_thread_macos.cc b/runtime/vm/os_thread_macos.cc
index bcac828..ffb94e9 100644
--- a/runtime/vm/os_thread_macos.cc
+++ b/runtime/vm/os_thread_macos.cc
@@ -94,9 +94,6 @@
   int result = pthread_attr_init(&attr);
   RETURN_ON_PTHREAD_FAILURE(result);
 
-  result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-  RETURN_ON_PTHREAD_FAILURE(result);
-
   result = pthread_attr_setstacksize(&attr, OSThread::GetMaxStackSize());
   RETURN_ON_PTHREAD_FAILURE(result);
 
@@ -116,6 +113,8 @@
 ThreadLocalKey OSThread::kUnsetThreadLocalKey =
     static_cast<pthread_key_t>(-1);
 ThreadId OSThread::kInvalidThreadId = reinterpret_cast<ThreadId>(NULL);
+ThreadJoinId OSThread::kInvalidThreadJoinId =
+    reinterpret_cast<ThreadJoinId>(NULL);
 
 ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
   pthread_key_t key = kUnsetThreadLocalKey;
@@ -151,8 +150,13 @@
 }
 
 
-bool OSThread::Join(ThreadId id) {
-  return false;
+ThreadJoinId OSThread::GetCurrentThreadJoinId() {
+  return pthread_self();
+}
+
+
+void OSThread::Join(ThreadJoinId id) {
+  ASSERT(pthread_join(id, NULL) == 0);
 }
 
 
diff --git a/runtime/vm/os_thread_macos.h b/runtime/vm/os_thread_macos.h
index d2b9143..63b4f02 100644
--- a/runtime/vm/os_thread_macos.h
+++ b/runtime/vm/os_thread_macos.h
@@ -18,6 +18,7 @@
 
 typedef pthread_key_t ThreadLocalKey;
 typedef pthread_t ThreadId;
+typedef pthread_t ThreadJoinId;
 
 class ThreadInlineImpl {
  private:
diff --git a/runtime/vm/os_thread_win.cc b/runtime/vm/os_thread_win.cc
index 12659491..7af1ce4 100644
--- a/runtime/vm/os_thread_win.cc
+++ b/runtime/vm/os_thread_win.cc
@@ -71,6 +71,7 @@
 
 ThreadLocalKey OSThread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
 ThreadId OSThread::kInvalidThreadId = 0;
+ThreadJoinId OSThread::kInvalidThreadJoinId = 0;
 
 ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor unused) {
   ThreadLocalKey key = TlsAlloc();
@@ -101,14 +102,29 @@
 }
 
 
-bool OSThread::Join(ThreadId id) {
+ThreadJoinId OSThread::GetCurrentThreadJoinId() {
+  return ::GetCurrentThreadId();
+}
+
+
+void OSThread::Join(ThreadJoinId id) {
   HANDLE handle = OpenThread(SYNCHRONIZE, false, id);
-  if (handle == INVALID_HANDLE_VALUE) {
-    return false;
+
+  // TODO(zra): OSThread::Start() closes the handle to the thread. Thus, by the
+  // time we try to join the thread, its resources may have already been
+  // reclaimed, and joining will fail. This can be avoided in a couple of ways.
+  // First, GetCurrentThreadJoinId could call OpenThread and return a handle.
+  // This is bad, because each of those handles would have to be closed.
+  // Second OSThread could be refactored to no longer be AllStatic. Then the
+  // handle could be cached in the object by the Start method.
+  if (handle == NULL) {
+    ASSERT(GetLastError() == ERROR_INVALID_PARAMETER);
+    return;
   }
+
   DWORD res = WaitForSingleObject(handle, INFINITE);
   CloseHandle(handle);
-  return res == WAIT_OBJECT_0;
+  ASSERT(res == WAIT_OBJECT_0);
 }
 
 
diff --git a/runtime/vm/os_thread_win.h b/runtime/vm/os_thread_win.h
index 27a5b14..5dc9b18 100644
--- a/runtime/vm/os_thread_win.h
+++ b/runtime/vm/os_thread_win.h
@@ -16,7 +16,7 @@
 
 typedef DWORD ThreadLocalKey;
 typedef DWORD ThreadId;
-
+typedef DWORD ThreadJoinId;
 
 class ThreadInlineImpl {
  private:
diff --git a/runtime/vm/os_win.cc b/runtime/vm/os_win.cc
index 1f66ad4..8513341 100644
--- a/runtime/vm/os_win.cc
+++ b/runtime/vm/os_win.cc
@@ -15,6 +15,7 @@
 #include "platform/assert.h"
 #include "vm/os_thread.h"
 #include "vm/vtune.h"
+#include "vm/zone.h"
 
 namespace dart {
 
@@ -271,6 +272,39 @@
 }
 
 
+char* OS::SCreate(Zone* zone, const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  char* buffer = VSCreate(zone, format, args);
+  va_end(args);
+  return buffer;
+}
+
+
+char* OS::VSCreate(Zone* zone, const char* format, va_list args) {
+  // Measure.
+  va_list measure_args;
+  va_copy(measure_args, args);
+  intptr_t len = VSNPrint(NULL, 0, format, measure_args);
+  va_end(measure_args);
+
+  char* buffer;
+  if (zone) {
+    buffer = zone->Alloc<char>(len + 1);
+  } else {
+    buffer = reinterpret_cast<char*>(malloc(len + 1));
+  }
+  ASSERT(buffer != NULL);
+
+  // Print.
+  va_list print_args;
+  va_copy(print_args, args);
+  VSNPrint(buffer, len + 1, format, print_args);
+  va_end(print_args);
+  return buffer;
+}
+
+
 bool OS::StringToInt64(const char* str, int64_t* value) {
   ASSERT(str != NULL && strlen(str) > 0 && value != NULL);
   int32_t base = 10;
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index d837830..23c45fd 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -9091,7 +9091,7 @@
   ConsumeToken();  // Consume assert keyword.
   ExpectToken(Token::kLPAREN);
   const intptr_t condition_pos = TokenPos();
-  if (!I->flags().asserts() && !I->flags().type_checks()) {
+  if (!I->flags().asserts()) {
     SkipExpr();
     ExpectToken(Token::kRPAREN);
     return NULL;
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index c49e68c..426aa88 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -62,7 +62,7 @@
 
 
 void Precompiler::DoCompileAll() {
-  LogBlock lb(thread_);
+  LogBlock lb;
 
   // Drop all existing code so we can use the presence of code as an indicator
   // that we have already looked for the function's callees.
@@ -81,7 +81,7 @@
   CleanUp();
 
   if (FLAG_trace_precompiler) {
-    ISL_Print("Precompiled %" Pd " functions, %" Pd " dynamic types,"
+    THR_Print("Precompiled %" Pd " functions, %" Pd " dynamic types,"
               " %" Pd " dynamic selectors.\n Dropped %" Pd " functions.\n",
               function_count_,
               class_count_,
@@ -276,7 +276,7 @@
     lib = Library::LookupLibrary(library_name);
     if (lib.IsNull()) {
       if (FLAG_trace_precompiler) {
-        ISL_Print("WARNING: Missing %s\n", kExternallyCalled[i].library_);
+        THR_Print("WARNING: Missing %s\n", kExternallyCalled[i].library_);
       }
       continue;
     }
@@ -287,7 +287,7 @@
       cls = lib.LookupClassAllowPrivate(class_name);
       if (cls.IsNull()) {
         if (FLAG_trace_precompiler) {
-          ISL_Print("WARNING: Missing %s %s\n",
+          THR_Print("WARNING: Missing %s %s\n",
                     kExternallyCalled[i].library_,
                     kExternallyCalled[i].class_);
         }
@@ -300,7 +300,7 @@
 
     if (func.IsNull()) {
       if (FLAG_trace_precompiler) {
-        ISL_Print("WARNING: Missing %s %s %s\n",
+        THR_Print("WARNING: Missing %s %s %s\n",
                   kExternallyCalled[i].library_,
                   kExternallyCalled[i].class_,
                   kExternallyCalled[i].function_);
@@ -350,7 +350,7 @@
     function_count_++;
 
     if (FLAG_trace_precompiler) {
-      ISL_Print("Precompiling %" Pd " %s (%" Pd ", %s)\n",
+      THR_Print("Precompiling %" Pd " %s (%" Pd ", %s)\n",
                 function_count_,
                 function.ToLibNamePrefixedQualifiedCString(),
                 function.token_pos(),
@@ -439,11 +439,13 @@
     AddClass(cls);
 
     if (field.has_initializer()) {
-      if (field.PrecompiledInitializer() != Function::null()) return;
+      if (field.HasPrecompiledInitializer()) return;
 
       if (FLAG_trace_precompiler) {
-        ISL_Print("Precompiling initializer for %s\n", field.ToCString());
+        THR_Print("Precompiling initializer for %s\n", field.ToCString());
       }
+      ASSERT(Object::instructions_snapshot_buffer() == NULL);
+      field.SetStaticValue(Instance::Handle(field.SavedInitialStaticValue()));
       Compiler::CompileStaticInitializer(field);
 
       const Function& function =
@@ -474,7 +476,7 @@
     changed_ = true;
 
     if (FLAG_trace_precompiler) {
-      ISL_Print("Enqueueing selector %" Pd " %s\n",
+      THR_Print("Enqueueing selector %" Pd " %s\n",
                 selector_count_,
                 selector.ToCString());
     }
@@ -497,7 +499,7 @@
   changed_ = true;
 
   if (FLAG_trace_precompiler) {
-    ISL_Print("Allocation %" Pd " %s\n", class_count_, cls.ToCString());
+    THR_Print("Allocation %" Pd " %s\n", class_count_, cls.ToCString());
   }
 
   const Class& superclass = Class::Handle(cls.SuperClass());
@@ -614,7 +616,7 @@
         } else {
           dropped_function_count_++;
           if (FLAG_trace_precompiler) {
-            ISL_Print("Precompilation dropping %s\n",
+            THR_Print("Precompilation dropping %s\n",
                       function.ToLibNamePrefixedQualifiedCString());
           }
         }
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index bacbfe8..2110436 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -763,8 +763,10 @@
   RawObject** to_snapshot() {
     return reinterpret_cast<RawObject**>(&ptr()->data_);
   }
-  // Fields below are not part of the snapshot.
   RawArray* ic_data_array_;  // ICData of unoptimized code.
+  RawObject** to_optimized_snapshot() {
+    return reinterpret_cast<RawObject**>(&ptr()->ic_data_array_);
+  }
   RawObject** to_no_code() {
     return reinterpret_cast<RawObject**>(&ptr()->ic_data_array_);
   }
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 13791de..051855f 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -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.
 
+#include "vm/native_entry.h"
 #include "vm/object.h"
 #include "vm/object_store.h"
 #include "vm/snapshot.h"
@@ -504,10 +505,7 @@
   // Set all the object fields.
   READ_OBJECT_FIELDS(cls, cls.raw()->from(), cls.raw()->to(), kAsReference);
 
-  ASSERT(((kind == Snapshot::kScript) &&
-          !Class::IsInFullSnapshot(cls.source_class())) ||
-         (kind == Snapshot::kFull));
-
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
   return cls.raw();
 }
 
@@ -631,37 +629,45 @@
   ASSERT(reader != NULL);
   ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
-  // Allocate function object.
-  Function& func = Function::ZoneHandle(
-      reader->zone(), NEW_OBJECT(Function));
-  reader->AddBackRef(object_id, &func, kIsDeserialized);
+  bool is_in_fullsnapshot = reader->Read<bool>();
+  if ((kind == Snapshot::kFull) || !is_in_fullsnapshot) {
+    // Allocate function object.
+    Function& func = Function::ZoneHandle(
+        reader->zone(), NEW_OBJECT(Function));
+    reader->AddBackRef(object_id, &func, kIsDeserialized);
 
-  // Set all the non object fields.
-  func.set_token_pos(reader->Read<int32_t>());
-  func.set_end_token_pos(reader->Read<int32_t>());
-  func.set_usage_counter(reader->Read<int32_t>());
-  func.set_num_fixed_parameters(reader->Read<int16_t>());
-  func.set_num_optional_parameters(reader->Read<int16_t>());
-  func.set_deoptimization_counter(reader->Read<int16_t>());
-  func.set_kind_tag(reader->Read<uint32_t>());
-  func.set_optimized_instruction_count(reader->Read<uint16_t>());
-  func.set_optimized_call_site_count(reader->Read<uint16_t>());
+    // Set all the non object fields.
+    func.set_token_pos(reader->Read<int32_t>());
+    func.set_end_token_pos(reader->Read<int32_t>());
+    func.set_usage_counter(reader->Read<int32_t>());
+    func.set_num_fixed_parameters(reader->Read<int16_t>());
+    func.set_num_optional_parameters(reader->Read<int16_t>());
+    func.set_deoptimization_counter(reader->Read<int16_t>());
+    func.set_kind_tag(reader->Read<uint32_t>());
+    func.set_optimized_instruction_count(reader->Read<uint16_t>());
+    func.set_optimized_call_site_count(reader->Read<uint16_t>());
 
-  // Set all the object fields.
-  READ_OBJECT_FIELDS(func,
-                     func.raw()->from(),
-                     reader->snapshot_code() ? func.raw()->to()
-                                             : func.raw()->to_snapshot(),
-                     kAsReference);
-
-  if (!reader->snapshot_code()) {
-    // Initialize all fields that are not part of the snapshot.
-    func.ClearICDataArray();
-    func.ClearCode();
+    // Set all the object fields.
+    bool is_optimized = func.usage_counter() != 0;
+    RawObject** toobj = reader->snapshot_code() ? func.raw()->to() :
+        (is_optimized ? func.raw()->to_optimized_snapshot() :
+         func.raw()->to_snapshot());
+    READ_OBJECT_FIELDS(func,
+                       func.raw()->from(), toobj,
+                       kAsReference);
+    if (!reader->snapshot_code()) {
+      // Initialize all fields that are not part of the snapshot.
+      if (!is_optimized) {
+        func.ClearICDataArray();
+      }
+      func.ClearCode();
+    } else {
+      // TODO(rmacnak): Fix entry_point_.
+    }
+    return func.raw();
   } else {
-    // TODO(rmacnak): Fix entry_point_.
+    return reader->ReadFunctionId(object_id);
   }
-  return func.raw();
 }
 
 
@@ -670,6 +676,17 @@
                           Snapshot::Kind kind) {
   ASSERT(writer != NULL);
   ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
+  bool is_in_fullsnapshot = false;
+  bool owner_is_class = false;
+  if (kind == Snapshot::kScript) {
+    intptr_t tags = writer->GetObjectTags(ptr()->owner_);
+    intptr_t cid = ClassIdTag::decode(tags);
+    owner_is_class = (cid == kClassCid);
+    is_in_fullsnapshot =  owner_is_class ?
+        Class::IsInFullSnapshot(reinterpret_cast<RawClass*>(ptr()->owner_)) :
+        PatchClass::IsInFullSnapshot(
+            reinterpret_cast<RawPatchClass*>(ptr()->owner_));
+  }
 
   // Write out the serialization header value for this object.
   writer->WriteInlinedObjectHeader(object_id);
@@ -678,25 +695,38 @@
   writer->WriteVMIsolateObject(kFunctionCid);
   writer->WriteTags(writer->GetObjectTags(this));
 
-  // Write out all the non object fields.
-  writer->Write<int32_t>(ptr()->token_pos_);
-  writer->Write<int32_t>(ptr()->end_token_pos_);
-  if (Code::IsOptimized(ptr()->instructions_->ptr()->code_)) {
-    writer->Write<int32_t>(FLAG_optimization_counter_threshold);
-  } else {
-    writer->Write<int32_t>(0);
-  }
-  writer->Write<int16_t>(ptr()->num_fixed_parameters_);
-  writer->Write<int16_t>(ptr()->num_optional_parameters_);
-  writer->Write<int16_t>(ptr()->deoptimization_counter_);
-  writer->Write<uint32_t>(ptr()->kind_tag_);
-  writer->Write<uint16_t>(ptr()->optimized_instruction_count_);
-  writer->Write<uint16_t>(ptr()->optimized_call_site_count_);
+  // Write out the boolean is_in_fullsnapshot first as this will
+  // help the reader decide how the rest of the information needs
+  // to be interpreted.
+  writer->Write<bool>(is_in_fullsnapshot);
 
-  // Write out all the object pointer fields.
-  SnapshotWriterVisitor visitor(writer);
-  visitor.VisitPointers(from(), writer->snapshot_code() ? to()
-                                                        : to_snapshot());
+  if (kind == Snapshot::kFull || !is_in_fullsnapshot) {
+    bool is_optimized = Code::IsOptimized(ptr()->instructions_->ptr()->code_);
+
+    // Write out all the non object fields.
+    writer->Write<int32_t>(ptr()->token_pos_);
+    writer->Write<int32_t>(ptr()->end_token_pos_);
+    if (is_optimized) {
+      writer->Write<int32_t>(FLAG_optimization_counter_threshold);
+    } else {
+      writer->Write<int32_t>(0);
+    }
+    writer->Write<int16_t>(ptr()->num_fixed_parameters_);
+    writer->Write<int16_t>(ptr()->num_optional_parameters_);
+    writer->Write<int16_t>(ptr()->deoptimization_counter_);
+    writer->Write<uint32_t>(ptr()->kind_tag_);
+    writer->Write<uint16_t>(ptr()->optimized_instruction_count_);
+    writer->Write<uint16_t>(ptr()->optimized_call_site_count_);
+
+    // Write out all the object pointer fields.
+    RawObject** toobj =
+        writer->snapshot_code() ? to() :
+        (is_optimized ? to_optimized_snapshot() : to_snapshot());
+    SnapshotWriterVisitor visitor(writer);
+    visitor.VisitPointers(from(), toobj);
+  } else {
+    writer->WriteFunctionId(this, owner_is_class);
+  }
 }
 
 
@@ -755,15 +785,25 @@
   writer->WriteObjectImpl(ptr()->type_, kAsReference);
   // Write out the initial static value or field offset.
   if (Field::StaticBit::decode(ptr()->kind_bits_)) {
-    // For static field we write out the initial static value.
-    writer->WriteObjectImpl(ptr()->initializer_.saved_value_, kAsReference);
+    if (writer->snapshot_code()) {
+      // For precompiled static fields, the value was already reset and
+      // initializer_ now contains a Function.
+      writer->WriteObjectImpl(ptr()->value_.static_value_, kAsReference);
+    } else {
+      // Otherwise, for static fields we write out the initial static value.
+      writer->WriteObjectImpl(ptr()->initializer_.saved_value_, kAsReference);
+    }
   } else {
     writer->WriteObjectImpl(ptr()->value_.offset_, kAsReference);
   }
   // Write out the dependent code.
   writer->WriteObjectImpl(ptr()->dependent_code_, kAsReference);
-  // Write out the initializer value.
-  writer->WriteObjectImpl(ptr()->initializer_.saved_value_, kAsReference);
+  // Write out the initializer function or saved initial value.
+  if (writer->snapshot_code()) {
+    writer->WriteObjectImpl(ptr()->initializer_.precompiled_, kAsReference);
+  } else {
+    writer->WriteObjectImpl(ptr()->initializer_.saved_value_, kAsReference);
+  }
   // Write out the guarded list length.
   writer->WriteObjectImpl(ptr()->guarded_list_length_, kAsReference);
 }
@@ -1296,6 +1336,16 @@
         result.SetRawValueAt(i, raw_value);
         break;
       }
+      case ObjectPool::kNativeEntry: {
+        // Read nothing. Initialize with the lazy link entry.
+        uword entry = reinterpret_cast<uword>(&NativeEntry::LinkNativeCall);
+#if defined(USING_SIMULATOR)
+        entry = Simulator::RedirectExternalReference(
+            entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments);
+#endif
+        result.SetRawValueAt(i, entry);
+        break;
+      }
       default:
         UNREACHABLE();
     }
@@ -1339,6 +1389,9 @@
         // TODO(rmacnak): Write symbolically.
         writer->Write<intptr_t>(entry.raw_value_);
         break;
+      case ObjectPool::kNativeEntry:
+        // Write nothing. Will initialize with the lazy link entry.
+        break;
       default:
         UNREACHABLE();
     }
@@ -1665,8 +1718,7 @@
                             intptr_t object_id,
                             intptr_t tags,
                             Snapshot::Kind kind) {
-  ASSERT(reader->snapshot_code());
-  ASSERT(kind == Snapshot::kFull);
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   ICData& result = ICData::ZoneHandle(reader->zone(), NEW_OBJECT(ICData));
   reader->AddBackRef(object_id, &result, kIsDeserialized);
@@ -1686,8 +1738,7 @@
 void RawICData::WriteTo(SnapshotWriter* writer,
                         intptr_t object_id,
                         Snapshot::Kind kind) {
-  ASSERT(writer->snapshot_code());
-  ASSERT(kind == Snapshot::kFull);
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   // Write out the serialization header value for this object.
   writer->WriteInlinedObjectHeader(object_id);
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index c0959e3..4cb379e 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -1354,6 +1354,29 @@
 }
 
 
+static RawObject* LookupHeapObjectMessage(Isolate* isolate,
+                                          char** parts, int num_parts) {
+  if (num_parts != 2) {
+    return Object::sentinel().raw();
+  }
+  uword message_id = 0;
+  if (!GetUnsignedIntegerId(parts[1], &message_id, 16)) {
+    return Object::sentinel().raw();
+  }
+  MessageHandler::AcquiredQueues aq;
+  isolate->message_handler()->AcquireQueues(&aq);
+  Message* message = aq.queue()->FindMessageById(message_id);
+  if (message == NULL) {
+    // The user may try to load an expired message.
+    return Object::sentinel().raw();
+  }
+  MessageSnapshotReader reader(message->data(),
+                               message->len(),
+                               Thread::Current());
+  return reader.ReadObject();
+}
+
+
 static RawObject* LookupHeapObject(Isolate* isolate,
                                    const char* id_original,
                                    ObjectIdRing::LookupResult* result) {
@@ -1406,6 +1429,8 @@
     return LookupHeapObjectTypeArguments(isolate, parts, num_parts);
   } else if (strcmp(parts[0], "code") == 0) {
     return LookupHeapObjectCode(isolate, parts, num_parts);
+  } else if (strcmp(parts[0], "messages") == 0) {
+    return LookupHeapObjectMessage(isolate, parts, num_parts);
   }
 
   // Not found.
@@ -1443,7 +1468,10 @@
 }
 
 
-static Breakpoint* LookupBreakpoint(Isolate* isolate, const char* id) {
+static Breakpoint* LookupBreakpoint(Isolate* isolate,
+                                    const char* id,
+                                    ObjectIdRing::LookupResult* result) {
+  *result = ObjectIdRing::kInvalid;
   size_t end_pos = strcspn(id, "/");
   if (end_pos == strlen(id)) {
     return NULL;
@@ -1454,46 +1482,20 @@
     Breakpoint* bpt = NULL;
     if (GetIntegerId(rest, &bpt_id)) {
       bpt = isolate->debugger()->GetBreakpointById(bpt_id);
+      if (bpt) {
+        *result = ObjectIdRing::kValid;
+        return bpt;
+      }
+      if (bpt_id < isolate->debugger()->limitBreakpointId()) {
+        *result = ObjectIdRing::kCollected;
+        return NULL;
+      }
     }
-    return bpt;
   }
   return NULL;
 }
 
 
-// Scans |isolate|'s message queue looking for a message with |id|.
-// If found, the message is printed to |js| and true is returned.
-// If not found, false is returned.
-static bool PrintMessage(JSONStream* js, Isolate* isolate, const char* id) {
-  size_t end_pos = strcspn(id, "/");
-  if (end_pos == strlen(id)) {
-    return false;
-  }
-  const char* rest = id + end_pos + 1;  // +1 for '/'.
-  if (strncmp("messages", id, end_pos) == 0) {
-    uword message_id = 0;
-    if (GetUnsignedIntegerId(rest, &message_id, 16)) {
-      MessageHandler::AcquiredQueues aq;
-      isolate->message_handler()->AcquireQueues(&aq);
-      Message* message = aq.queue()->FindMessageById(message_id);
-      if (message == NULL) {
-        // The user may try to load an expired message, so we treat
-        // unrecognized ids as if they are expired.
-        PrintSentinel(js, kExpiredSentinel);
-        return true;
-      }
-      MessageSnapshotReader reader(message->data(),
-                                   message->len(),
-                                   Thread::Current());
-      const Object& msg_obj = Object::Handle(reader.ReadObject());
-      msg_obj.PrintJSON(js);
-      return true;
-    }
-  }
-  return false;
-}
-
-
 static bool PrintInboundReferences(Isolate* isolate,
                                    Object* target,
                                    intptr_t limit,
@@ -2041,8 +2043,10 @@
 
 static const MethodParameter* add_breakpoint_params[] = {
   ISOLATE_PARAMETER,
-  new IdParameter("scriptId", true),
+  new IdParameter("scriptId", false),
+  new IdParameter("scriptUri", false),
   new UIntParameter("line", true),
+  new UIntParameter("column", false),
   NULL,
 };
 
@@ -2050,16 +2054,41 @@
 static bool AddBreakpoint(Isolate* isolate, JSONStream* js) {
   const char* line_param = js->LookupParam("line");
   intptr_t line = UIntParameter::Parse(line_param);
-  const char* script_id = js->LookupParam("scriptId");
-  Object& obj = Object::Handle(LookupHeapObject(isolate, script_id, NULL));
-  if (obj.raw() == Object::sentinel().raw() || !obj.IsScript()) {
-    PrintInvalidParamError(js, "scriptId");
+  const char* col_param = js->LookupParam("column");
+  intptr_t col = -1;
+  if (col_param != NULL) {
+    col = UIntParameter::Parse(col_param);
+    if (col == 0) {
+      // Column number is 1-based.
+      PrintInvalidParamError(js, "column");
+      return true;
+    }
+  }
+  const char* script_id_param = js->LookupParam("scriptId");
+  const char* script_uri_param = js->LookupParam("scriptUri");
+  if (script_id_param == NULL && script_uri_param == NULL) {
+    js->PrintError(kInvalidParams,
+                   "%s expects the 'scriptId' or the 'scriptUri' parameter",
+                   js->method());
     return true;
   }
-  const Script& script = Script::Cast(obj);
-  const String& script_url = String::Handle(script.url());
-  Breakpoint* bpt =
-      isolate->debugger()->SetBreakpointAtLine(script_url, line);
+  String& script_uri = String::Handle(isolate);
+  if (script_id_param != NULL) {
+    Object& obj =
+        Object::Handle(LookupHeapObject(isolate, script_id_param, NULL));
+    if (obj.raw() == Object::sentinel().raw() || !obj.IsScript()) {
+      PrintInvalidParamError(js, "scriptId");
+      return true;
+    }
+    const Script& script = Script::Cast(obj);
+    script_uri = script.url();
+  }
+  if (script_uri_param != NULL) {
+    script_uri = String::New(script_uri_param);
+  }
+  ASSERT(!script_uri.IsNull());
+  Breakpoint* bpt = NULL;
+  bpt = isolate->debugger()->SetBreakpointAtLineCol(script_uri, line, col);
   if (bpt == NULL) {
     js->PrintError(kCannotAddBreakpoint,
                    "%s: Cannot add breakpoint at line '%s'",
@@ -2139,7 +2168,10 @@
     return true;
   }
   const char* bpt_id = js->LookupParam("breakpointId");
-  Breakpoint* bpt = LookupBreakpoint(isolate, bpt_id);
+  ObjectIdRing::LookupResult lookup_result;
+  Breakpoint* bpt = LookupBreakpoint(isolate, bpt_id, &lookup_result);
+  // TODO(turnidge): Should we return a different error for bpts whic
+  // have been already removed?
   if (bpt == NULL) {
     PrintInvalidParamError(js, "breakpointId");
     return true;
@@ -2794,13 +2826,12 @@
   }
 
   // Handle non-heap objects.
-  Breakpoint* bpt = LookupBreakpoint(isolate, id);
+  Breakpoint* bpt = LookupBreakpoint(isolate, id, &lookup_result);
   if (bpt != NULL) {
     bpt->PrintJSON(js);
     return true;
-  }
-
-  if (PrintMessage(js, isolate, id)) {
+  } else if (lookup_result == ObjectIdRing::kCollected) {
+    PrintSentinel(js, kCollectedSentinel);
     return true;
   }
 
@@ -2866,8 +2897,8 @@
 static bool GetVersion(Isolate* isolate, JSONStream* js) {
   JSONObject jsobj(js);
   jsobj.AddProperty("type", "Version");
-  jsobj.AddProperty("major", static_cast<intptr_t>(2));
-  jsobj.AddProperty("minor", static_cast<intptr_t>(1));
+  jsobj.AddProperty("major", static_cast<intptr_t>(3));
+  jsobj.AddProperty("minor", static_cast<intptr_t>(0));
   jsobj.AddProperty("_privateMajor", static_cast<intptr_t>(0));
   jsobj.AddProperty("_privateMinor", static_cast<intptr_t>(0));
   return true;
diff --git a/runtime/vm/service/client.dart b/runtime/vm/service/client.dart
index 1ac2a23..279b424 100644
--- a/runtime/vm/service/client.dart
+++ b/runtime/vm/service/client.dart
@@ -15,6 +15,9 @@
     service._addClient(this);
   }
 
+  // Disconnects the client.
+  disconnect();
+
   /// When implementing, call [close] when the network connection closes.
   void close() {
     service._removeClient(this);
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index c18f390..b390460 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1,8 +1,8 @@
-# Dart VM Service Protocol 2.0
+# Dart VM Service Protocol 3.0
 
 > Please post feedback to the [observatory-discuss group][discuss-list]
 
-This document describes of _version 2.0_ of the Dart VM Service Protocol. This
+This document describes of _version 3.0_ of the Dart VM Service Protocol. This
 protocol is used to communicate with a running Dart Virtual Machine.
 
 To use the Service Protocol, start the VM with the *--observe* flag.
@@ -68,6 +68,7 @@
 	- [Message](#message)
 	- [Null](#null)
 	- [Object](#object)
+	- [Response](#response)
 	- [Sentinel](#sentinel)
 	- [SentinelKind](#sentinelkind)
 	- [Script](#script)
@@ -76,7 +77,7 @@
 	- [StepOption](#stepoption)
 	- [Success](#success)
 	- [TypeArguments](#typearguments)
-	- [Response](#response)
+	- [UresolvedSourceLocation](#unresolvedsourcelocation)
 	- [Version](#version)
 	- [VM](#vm)
 - [Revision History](#revision-history)
@@ -109,7 +110,7 @@
   "jsonrpc": "2.0",
   "result": {
     "type": "Version",
-    "major": 2,
+    "major": 3,
     "minor": 0
   }
   "id": "1"
@@ -299,7 +300,7 @@
 ```
   "result": {
     "type": "Version",
-    "major": 2,
+    "major": 3,
     "minor": 0
   }
 ```
@@ -371,13 +372,29 @@
 
 ```
 Breakpoint addBreakpoint(string isolateId,
-                         string scriptId,
-                         int line)
+                         string scriptId [optional],
+                         string scriptUri [optional],
+                         int line,
+                         int column [optional])
 ```
 
 The _addBreakpoint_ RPC is used to add a breakpoint at a specific line
 of some script.
 
+The _scriptId_ or _scriptUri_ parameter is used to specify the target
+script. One of these two parameters must always be provided.
+
+The _line_ parameter is used to specify the target line for the
+breakpoint. If there are multiple possible breakpoints on the target
+line, then the VM will place the breakpoint at the location which
+would execute soonest. If it is not possible to set a breakpoint at
+the target line, the breakpoint will be added at the next possible
+breakpoint location within the same function.
+
+The _column_ parameter may be optionally specified.  This is useful
+for targeting a specific breakpoint on a line with multiple possible
+breakpoints.
+
 If no breakpoint is possible at that line, the _102_ (Cannot add
 breakpoint) error code is returned.
 
@@ -481,10 +498,13 @@
 If _objectId_ is a temporary id which has expired, then then _Expired_
 [Sentinel](#sentinel) is returned.
 
-If _objectId_ refers to an object which has been collected by the VM's
+If _objectId_ refers to a heap object which has been collected by the VM's
 garbage collector, then the _Collected_ [Sentinel](#sentinel) is
 returned.
 
+If _objectId_ refers to a non-heap object which has been deleted, then
+the _Collected_ [Sentinel](#sentinel) is returned.
+
 If the object handle has not expired and the object has not been
 collected, then an [Object](#object) will be returned.
 
@@ -757,14 +777,25 @@
 
 ```
 class Breakpoint extends Object {
+  // A number identifying this breakpoint to the user.
   int breakpointNumber;
+
+  // Has this breakpoint been assigned to a specific program location?
   bool resolved;
-  SourceLocation location;
+
+  // SourceLocation when breakpoint is resolved, UnresolvedSourceLocation
+  // when a breakpoint is not resolved.
+  SourceLocation|UnresolvedSourceLocation location;
 }
 ```
 
 A _Breakpoint_ describes a debugger breakpoint.
 
+A breakpoint is _resolved_ when it has been assigned to a specific
+program location.  A breakpoint my remain unresolved when it is in
+code which has not yet been compiled or in a library which has not
+been loaded (i.e. a deferred library).
+
 ### Class
 
 ```
@@ -868,14 +899,14 @@
 ### Context
 
 ```
-class @Context {
+class @Context extends @Object {
   // The number of variables in this context.
   int length;
 }
 ```
 
 ```
-class Context {
+class Context extends Object {
   // The number of variables in this context.
   int length;
 
@@ -887,6 +918,9 @@
 }
 ```
 
+A _Context_ is a data structure which holds the captured variables for
+some closure.
+
 ### ContextElement
 
 ```
@@ -1293,9 +1327,11 @@
 
   // The pattern of a RegExp instance.
   //
+  // The pattern is always an instance of kind String.
+  //
   // Provided for instance kinds:
   //   RegExp
-  String pattern [optional];
+  @Instance pattern [optional];
 }
 ```
 
@@ -1378,6 +1414,8 @@
 
   // The bytes of a TypedData instance.
   //
+  // The data is provided as a Base64 encoded string.
+  //
   // Provided for instance kinds:
   //   Uint8ClampedList
   //   Uint8List
@@ -1393,7 +1431,7 @@
   //   Int32x4List
   //   Float32x4List
   //   Float64x2List
-  int[] bytes [optional];
+  string bytes [optional];
 
   // The function associated with a Closure instance.
   //
@@ -1405,7 +1443,7 @@
   //
   // Provided for instance kinds:
   //   Closure
-  @Function closureContext [optional];
+  @Context closureContext [optional];
 
   // The referent of a MirrorReference instance.
   //
@@ -1715,15 +1753,32 @@
 
 ```
 class Message extends Response {
+  // The index in the isolate's message queue. The 0th message being the next
+  // message to be processed.
   int index;
+
+  // An advisory name describing this message.
   string name;
+
+  // An instance id for the decoded message. This id can be passed to other
+  // RPCs, for example, getObject or evaluate.
   string messageObjectId;
+
+  // The size (bytes) of the encoded message.
   int size;
+
+  // A reference to the function that will be invoked to handle this message.
   @Function handler [optional];
+
+  // The source location of handler.
   SourceLocation location [optional];
 }
 ```
 
+A _Message_ provides information about a pending isolate message and the
+function that will be invoked to handle it.
+
+
 ### Null
 
 ```
@@ -1787,6 +1842,21 @@
 
 An _Object_ is a  persistent object that is owned by some isolate.
 
+### Response
+
+```
+class Response {
+  // Every response returned by the VM Service has the
+  // type property. This allows the client distinguish
+  // between different kinds of responses.
+  string type;
+}
+```
+
+Every non-error response returned by the Service Protocol extends _Response_.
+By using the _type_ property, the client can determine which [type](#types)
+of response has been provided.
+
 ### Sentinel
 
 ```
@@ -1955,20 +2025,42 @@
 A _TypeArguments_ object represents the type argument vector for some
 instantiated generic type.
 
-### Response
+### UnresolvedSourceLocation
 
 ```
-class Response {
-  // Every response returned by the VM Service has the
-  // type property. This allows the client distinguish
-  // between different kinds of responses.
-  string type;
+class UnresolvedSourceLocation extends Response {
+  // The script containing the source location if the script has been loaded.
+  @Script script [optional];
+
+  // The uri of the script containing the source location if the script
+  // has yet to be loaded.
+  string scriptUri [optional];
+
+  // An approximate token position for the source location.  This may
+  // change when the location is resolved.
+  int tokenPos [optional];
+
+  // An approximate line number for the source location.  This may
+  // change when the location is resolved.
+  int line [optional];
+
+  // An approximate column number for the source location.  This may
+  // change when the location is resolved.
+  int column [optional];
+
 }
 ```
 
-Every non-error response returned by the Service Protocol extends _Response_.
-By using the _type_ property, the client can determine which [type](#types)
-of response has been provided.
+The _UnresolvedSourceLocation_ class is used to refer to an unresolved
+breakpoint location.  As such, it is meant to approximate the final
+location of the breakpoint but it is not exact.
+
+Either the _script_ or the _scriptUri_ field will be present.
+
+Either the _tokenPos_ or the _line_ field will be present.
+
+The _column_ field will only be present when the breakpoint was
+specified with a specific column number.
 
 ### Version
 
@@ -2020,6 +2112,8 @@
 version | comments
 ------- | --------
 1.0 draft 1 | initial revision
+1.1 | Describe protocol version 2.0.
+1.2 | Describe protocol version 3.0.  Added UnresolvedSourceLocation.
 
 
 [discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/runtime/vm/service/vmservice.dart b/runtime/vm/service/vmservice.dart
index 4c12cdb..f2210c5 100644
--- a/runtime/vm/service/vmservice.dart
+++ b/runtime/vm/service/vmservice.dart
@@ -106,10 +106,11 @@
   void _exit() {
     isolateLifecyclePort.close();
     scriptLoadPort.close();
-    // Create a copy of the set as a list because client.close() alters the set.
+    // Create a copy of the set as a list because client.disconnect() will
+    // alter the connected clients set.
     var clientsList = clients.toList();
     for (var client in clientsList) {
-      client.close();
+      client.disconnect();
     }
     // Call embedder shutdown hook after the internal shutdown.
     if (onShutdown != null) {
diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc
index 2068e40..29a71ce 100644
--- a/runtime/vm/service_isolate.cc
+++ b/runtime/vm/service_isolate.cc
@@ -675,6 +675,8 @@
   static void ShutdownIsolate(uword parameter) {
     Isolate* I = reinterpret_cast<Isolate*>(parameter);
     ASSERT(ServiceIsolate::IsServiceIsolate(I));
+    ServiceIsolate::SetServiceIsolate(NULL);
+    ServiceIsolate::SetServicePort(ILLEGAL_PORT);
     {
       // Print the error if there is one.  This may execute dart code to
       // print the exception object, so we need to use a StartIsolateScope.
@@ -695,8 +697,6 @@
       SwitchIsolateScope switch_scope(I);
       Dart::ShutdownIsolate();
     }
-    ServiceIsolate::SetServiceIsolate(NULL);
-    ServiceIsolate::SetServicePort(ILLEGAL_PORT);
     if (FLAG_trace_service) {
       OS::Print("vm-service: Shutdown.\n");
     }
@@ -762,8 +762,30 @@
 }
 
 
+void ServiceIsolate::KillServiceIsolate() {
+  {
+    MonitorLocker ml(monitor_);
+    shutting_down_ = true;
+  }
+  Isolate::KillIfExists(isolate_);
+  {
+    MonitorLocker ml(monitor_);
+    while (shutting_down_) {
+      ml.Wait();
+    }
+  }
+}
+
+
 void ServiceIsolate::Shutdown() {
   if (!IsRunning()) {
+    if (isolate_ != NULL) {
+      // TODO(johnmccutchan,turnidge) When it is possible to properly create
+      // the VMService object and set up its shutdown handler in the service
+      // isolate's main() function, this case will no longer be possible and
+      // can be removed.
+      KillServiceIsolate();
+    }
     return;
   }
   {
diff --git a/runtime/vm/service_isolate.h b/runtime/vm/service_isolate.h
index fbcd136..86433c9 100644
--- a/runtime/vm/service_isolate.h
+++ b/runtime/vm/service_isolate.h
@@ -32,6 +32,9 @@
   static void SendServiceExitMessage();
   static void Shutdown();
 
+ private:
+  static void KillServiceIsolate();
+
  protected:
   static void SetServicePort(Dart_Port port);
   static void SetServiceIsolate(Isolate* isolate);
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 45ae49a..4b3fb8a 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -1578,6 +1578,7 @@
             set_register(R1, r1);
           }
         } else if (redirection->call_kind() == kBootstrapNativeCall) {
+          ASSERT(redirection->argument_count() == 1);
           NativeArguments* arguments;
           arguments = reinterpret_cast<NativeArguments*>(get_register(R0));
           SimulatorBootstrapNativeCall target =
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index 9663fdc..3c7b99d 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -1626,6 +1626,7 @@
       set_vregisterd(V0, 0, bit_cast<int64_t, double>(res));
       set_vregisterd(V0, 1, 0);
     } else if (redirection->call_kind() == kBootstrapNativeCall) {
+      ASSERT(redirection->argument_count() == 1);
       NativeArguments* arguments;
       arguments = reinterpret_cast<NativeArguments*>(get_register(R0));
       SimulatorBootstrapNativeCall target =
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index fdcdcf2..f8da783 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -1268,6 +1268,7 @@
         d0 = target(d6, d7);
         set_fregister_double(F0, d0);
       } else if (redirection->call_kind() == kBootstrapNativeCall) {
+        ASSERT(redirection->argument_count() == 1);
         NativeArguments* arguments;
         arguments = reinterpret_cast<NativeArguments*>(get_register(A0));
         SimulatorBootstrapNativeCall target =
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index b336512..decc5a7 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -198,6 +198,8 @@
       data_(ExternalTypedData::Handle(zone_)),
       typed_data_(TypedData::Handle(zone_)),
       code_(Code::Handle(zone_)),
+      function_(Function::Handle(zone_)),
+      megamorphic_cache_(MegamorphicCache::Handle(zone_)),
       error_(UnhandledException::Handle(zone_)),
       max_vm_isolate_object_id_(
           (kind == Snapshot::kFull) ?
@@ -262,6 +264,43 @@
 }
 
 
+RawFunction* SnapshotReader::ReadFunctionId(intptr_t object_id) {
+  ASSERT(kind_ == Snapshot::kScript);
+  // Read the function header information and lookup the function.
+  intptr_t func_header = Read<int32_t>();
+  ASSERT((func_header & kSmiTagMask) != kSmiTag);
+  ASSERT(!IsVMIsolateObject(func_header) ||
+         !IsSingletonClassId(GetVMIsolateObjectId(func_header)));
+  ASSERT((SerializedHeaderTag::decode(func_header) != kObjectId) ||
+         !IsObjectStoreClassId(SerializedHeaderData::decode(func_header)));
+  Function& func = Function::ZoneHandle(zone(), Function::null());
+  AddBackRef(object_id, &func, kIsDeserialized);
+  // Read the library/class/function information and lookup the function.
+  str_ ^= ReadObjectImpl(func_header, kAsInlinedObject, kInvalidPatchIndex, 0);
+  library_ = Library::LookupLibrary(str_);
+  if (library_.IsNull() || !library_.Loaded()) {
+    SetReadException("Expected a library name, but found an invalid name.");
+  }
+  str_ ^= ReadObjectImpl(kAsInlinedObject);
+  if (str_.Equals(Symbols::TopLevel(), 0, Symbols::TopLevel().Length())) {
+    str_ ^= ReadObjectImpl(kAsInlinedObject);
+    func ^= library_.LookupLocalFunction(str_);
+  } else {
+    cls_ = library_.LookupClass(str_);
+    if (cls_.IsNull()) {
+      SetReadException("Expected a class name, but found an invalid name.");
+    }
+    cls_.EnsureIsFinalized(isolate());
+    str_ ^= ReadObjectImpl(kAsInlinedObject);
+    func ^= cls_.LookupFunctionAllowPrivate(str_);
+  }
+  if (func.IsNull()) {
+    SetReadException("Expected a function name, but found an invalid name.");
+  }
+  return func.raw();
+}
+
+
 RawObject* SnapshotReader::ReadStaticImplicitClosure(intptr_t object_id,
                                                      intptr_t class_header) {
   ASSERT(kind_ != Snapshot::kFull);
@@ -660,7 +699,9 @@
     HeapLocker hl(isolate, old_space());
 
     // Read in all the objects stored in the object store.
-    intptr_t num_flds = (object_store->to() - object_store->from());
+    RawObject** toobj = snapshot_code() ? object_store->to()
+                                        : object_store->to_snapshot();
+    intptr_t num_flds = (toobj - object_store->from());
     for (intptr_t i = 0; i <= num_flds; i++) {
       *(object_store->from() + i) = ReadObjectImpl(kAsInlinedObject);
     }
@@ -1307,58 +1348,59 @@
 }
 
 
+#define READ_VM_SINGLETON_OBJ(id, obj)                                         \
+  if (object_id == id) {                                                       \
+    return obj;                                                                \
+  }                                                                            \
+
 RawObject* SnapshotReader::ReadVMIsolateObject(intptr_t header_value) {
   intptr_t object_id = GetVMIsolateObjectId(header_value);
-  if (object_id == kNullObject) {
-    // This is a singleton null object, return it.
-    return Object::null();
-  }
-  if (object_id == kSentinelObject) {
-    return Object::sentinel().raw();
-  }
-  if (object_id == kTransitionSentinelObject) {
-    return Object::transition_sentinel().raw();
-  }
-  if (object_id == kEmptyArrayObject) {
-    return Object::empty_array().raw();
-  }
-  if (object_id == kZeroArrayObject) {
-    return Object::zero_array().raw();
-  }
-  if (object_id == kDynamicType) {
-    return Object::dynamic_type();
-  }
-  if (object_id == kVoidType) {
-    return Object::void_type();
-  }
-  if (object_id == kTrueValue) {
-    return Bool::True().raw();
-  }
-  if (object_id == kFalseValue) {
-    return Bool::False().raw();
-  }
-  if (object_id == kExtractorParameterTypes) {
-    return Object::extractor_parameter_types().raw();
-  }
-  if (object_id == kExtractorParameterNames) {
-    return Object::extractor_parameter_names().raw();
-  }
-  if (object_id == kEmptyContextScopeObject) {
-    return Object::empty_context_scope().raw();
-  }
+
+  // First check if it is one of the singleton objects.
+  READ_VM_SINGLETON_OBJ(kNullObject, Object::null());
+  READ_VM_SINGLETON_OBJ(kSentinelObject, Object::sentinel().raw());
+  READ_VM_SINGLETON_OBJ(kTransitionSentinelObject,
+                        Object::transition_sentinel().raw());
+  READ_VM_SINGLETON_OBJ(kEmptyArrayObject, Object::empty_array().raw());
+  READ_VM_SINGLETON_OBJ(kZeroArrayObject, Object::zero_array().raw());
+  READ_VM_SINGLETON_OBJ(kDynamicType, Object::dynamic_type());
+  READ_VM_SINGLETON_OBJ(kVoidType, Object::void_type());
+  READ_VM_SINGLETON_OBJ(kTrueValue, Bool::True().raw());
+  READ_VM_SINGLETON_OBJ(kFalseValue, Bool::False().raw());
+  READ_VM_SINGLETON_OBJ(kExtractorParameterTypes,
+                        Object::extractor_parameter_types().raw());
+  READ_VM_SINGLETON_OBJ(kExtractorParameterNames,
+                        Object::extractor_parameter_names().raw());
+  READ_VM_SINGLETON_OBJ(kEmptyContextScopeObject,
+                        Object::empty_context_scope().raw());
+  READ_VM_SINGLETON_OBJ(kEmptyObjectPool, Object::empty_object_pool().raw());
+  READ_VM_SINGLETON_OBJ(kEmptyDescriptors, Object::empty_descriptors().raw());
+  READ_VM_SINGLETON_OBJ(kEmptyVarDescriptors,
+                        Object::empty_var_descriptors().raw());
+  READ_VM_SINGLETON_OBJ(kEmptyExceptionHandlers,
+                        Object::empty_exception_handlers().raw());
+
+  // Check if it is a double.
   if (object_id == kDoubleObject) {
     ASSERT(kind_ == Snapshot::kMessage);
     return Double::New(ReadDouble());
   }
+
+  // Check it is a singleton class object.
   intptr_t class_id = ClassIdFromObjectId(object_id);
   if (IsSingletonClassId(class_id)) {
     return isolate()->class_table()->At(class_id);  // get singleton class.
-  } else {
-    ASSERT(Symbols::IsVMSymbolId(object_id));
-    return Symbols::GetVMSymbol(object_id);  // return VM symbol.
   }
-  UNREACHABLE();
-  return Object::null();
+
+  // Check if it is a singleton Argument descriptor object.
+  for (intptr_t i = 0; i < ArgumentsDescriptor::kCachedDescriptorCount; i++) {
+    if (object_id == (kCachedArgumentsDescriptor0 + i)) {
+      return ArgumentsDescriptor::cached_args_descriptors_[i];
+    }
+  }
+
+  ASSERT(Symbols::IsVMSymbolId(object_id));
+  return Symbols::GetVMSymbol(object_id);  // return VM symbol.
 }
 
 
@@ -1525,27 +1567,8 @@
     // only memory.
     *(ArrayHandle()) ^= ReadObject();
 
-
     if (snapshot_code()) {
-      for (intptr_t i = 0;
-           i < ArgumentsDescriptor::kCachedDescriptorCount;
-           i++) {
-        *(ArrayHandle()) ^= ReadObject();
-        // TODO(rmacnak):
-        // ArgumentsDescriptor::InitOnceFromSnapshot(i, *(ArrayHandle()));
-      }
-
-      ObjectPool::CheckedHandle(ReadObject());  // empty pool
-      PcDescriptors::CheckedHandle(ReadObject());  // empty pc desc
-      LocalVarDescriptors::CheckedHandle(ReadObject());  // empty var desc
-      ExceptionHandlers::CheckedHandle(ReadObject());  // empty exc handlers
-
-#define READ_STUB(name)                                                       \
-      *(CodeHandle()) ^= ReadObject();
-      // TODO(rmacnak):
-      // StubCode::name##_entry()->InitOnceFromSnapshot(CodeHandle())
-      VM_STUB_CODE_LIST(READ_STUB);
-#undef READ_STUB
+      StubCode::ReadFrom(this);
     }
 
     // Validate the class table.
@@ -1569,6 +1592,7 @@
                      new ZoneGrowableArray<BackRefNode>(
                          kNumInitialReferencesInFullSnapshot),
                      thread) {
+  isolate()->set_compilation_allowed(instructions_buffer_ == NULL);
 }
 
 
@@ -1657,78 +1681,36 @@
     return true;                                                               \
   }                                                                            \
 
+#define WRITE_VM_SINGLETON_OBJ(obj, id)                                        \
+  if (rawobj == obj) {                                                         \
+    WriteVMIsolateObject(id);                                                  \
+    return true;                                                               \
+  }                                                                            \
+
 bool SnapshotWriter::HandleVMIsolateObject(RawObject* rawobj) {
-  // Check if it is a singleton null object.
-  if (rawobj == Object::null()) {
-    WriteVMIsolateObject(kNullObject);
-    return true;
-  }
-
-  // Check if it is a singleton sentinel object.
-  if (rawobj == Object::sentinel().raw()) {
-    WriteVMIsolateObject(kSentinelObject);
-    return true;
-  }
-
-  // Check if it is a singleton sentinel object.
-  if (rawobj == Object::transition_sentinel().raw()) {
-    WriteVMIsolateObject(kTransitionSentinelObject);
-    return true;
-  }
-
-  // Check if it is a singleton empty array object.
-  if (rawobj == Object::empty_array().raw()) {
-    WriteVMIsolateObject(kEmptyArrayObject);
-    return true;
-  }
-
-  // Check if it is a singleton zero array object.
-  if (rawobj == Object::zero_array().raw()) {
-    WriteVMIsolateObject(kZeroArrayObject);
-    return true;
-  }
-
-  // Check if it is a singleton dyanmic Type object.
-  if (rawobj == Object::dynamic_type()) {
-    WriteVMIsolateObject(kDynamicType);
-    return true;
-  }
-
-  // Check if it is a singleton void Type object.
-  if (rawobj == Object::void_type()) {
-    WriteVMIsolateObject(kVoidType);
-    return true;
-  }
-
-  // Check if it is a singleton boolean true object.
-  if (rawobj == Bool::True().raw()) {
-    WriteVMIsolateObject(kTrueValue);
-    return true;
-  }
-
-  // Check if it is a singleton boolean false object.
-  if (rawobj == Bool::False().raw()) {
-    WriteVMIsolateObject(kFalseValue);
-    return true;
-  }
-
-  // Check if it is a singleton extractor parameter types array.
-  if (rawobj == Object::extractor_parameter_types().raw()) {
-    WriteVMIsolateObject(kExtractorParameterTypes);
-    return true;
-  }
-
-  // Check if it is a singleton extractor parameter names array.
-  if (rawobj == Object::extractor_parameter_names().raw()) {
-    WriteVMIsolateObject(kExtractorParameterNames);
-    return true;
-  }
-
-  // Check if it is a singleton empty context scope object.
-  if (rawobj == Object::empty_context_scope().raw()) {
-    WriteVMIsolateObject(kEmptyContextScopeObject);
-    return true;
-  }
+  // Check if it is one of the singleton VM objects.
+  WRITE_VM_SINGLETON_OBJ(Object::null(), kNullObject);
+  WRITE_VM_SINGLETON_OBJ(Object::sentinel().raw(), kSentinelObject);
+  WRITE_VM_SINGLETON_OBJ(Object::transition_sentinel().raw(),
+                         kTransitionSentinelObject);
+  WRITE_VM_SINGLETON_OBJ(Object::empty_array().raw(), kEmptyArrayObject);
+  WRITE_VM_SINGLETON_OBJ(Object::zero_array().raw(), kZeroArrayObject);
+  WRITE_VM_SINGLETON_OBJ(Object::dynamic_type(), kDynamicType);
+  WRITE_VM_SINGLETON_OBJ(Object::void_type(), kVoidType);
+  WRITE_VM_SINGLETON_OBJ(Bool::True().raw(), kTrueValue);
+  WRITE_VM_SINGLETON_OBJ(Bool::False().raw(), kFalseValue);
+  WRITE_VM_SINGLETON_OBJ(Object::extractor_parameter_types().raw(),
+                         kExtractorParameterTypes);
+  WRITE_VM_SINGLETON_OBJ(Object::extractor_parameter_names().raw(),
+                         kExtractorParameterNames);
+  WRITE_VM_SINGLETON_OBJ(Object::empty_context_scope().raw(),
+                         kEmptyContextScopeObject);
+  WRITE_VM_SINGLETON_OBJ(Object::empty_object_pool().raw(), kEmptyObjectPool);
+  WRITE_VM_SINGLETON_OBJ(Object::empty_descriptors().raw(), kEmptyDescriptors);
+  WRITE_VM_SINGLETON_OBJ(Object::empty_var_descriptors().raw(),
+                         kEmptyVarDescriptors);
+  WRITE_VM_SINGLETON_OBJ(Object::empty_exception_handlers().raw(),
+                         kEmptyExceptionHandlers);
 
   // Check if it is a singleton class object which is shared by
   // all isolates.
@@ -1743,6 +1725,14 @@
     }
   }
 
+  // Check if it is a singleton Argument descriptor object.
+  for (intptr_t i = 0; i < ArgumentsDescriptor::kCachedDescriptorCount; i++) {
+    if (rawobj == ArgumentsDescriptor::cached_args_descriptors_[i]) {
+      WriteVMIsolateObject(kCachedArgumentsDescriptor0 + i);
+      return true;
+    }
+  }
+
   if (kind() == Snapshot::kFull) {
     // Check it is a predefined symbol in the VM isolate.
     id = Symbols::LookupVMSymbol(rawobj);
@@ -1937,22 +1927,7 @@
 
     if (snapshot_code_) {
       ASSERT(!vm_isolate_is_symbolic_);
-
-      for (intptr_t i = 0;
-           i < ArgumentsDescriptor::kCachedDescriptorCount;
-           i++) {
-        writer.WriteObject(ArgumentsDescriptor::cached_args_descriptors_[i]);
-      }
-
-      writer.WriteObject(Object::empty_object_pool().raw());
-      writer.WriteObject(Object::empty_descriptors().raw());
-      writer.WriteObject(Object::empty_var_descriptors().raw());
-      writer.WriteObject(Object::empty_exception_handlers().raw());
-
-#define WRITE_STUB(name)                                                       \
-      writer.WriteObject(StubCode::name##_entry()->code());
-      VM_STUB_CODE_LIST(WRITE_STUB);
-#undef WRITE_STUB
+      StubCode::WriteTo(&writer);
     }
 
 
@@ -1994,7 +1969,9 @@
     // Write out all the objects in the object store of the isolate which
     // is the root set for all dart allocated objects at this point.
     SnapshotWriterVisitor visitor(&writer, false);
-    object_store->VisitObjectPointers(&visitor);
+    visitor.VisitPointers(object_store->from(),
+                          snapshot_code_ ? object_store->to()
+                                         : object_store->to_snapshot());
 
     // Write out all forwarded objects.
     writer.WriteForwardedObjects();
@@ -2441,6 +2418,22 @@
 }
 
 
+void SnapshotWriter::WriteFunctionId(RawFunction* func, bool owner_is_class) {
+  ASSERT(kind_ == Snapshot::kScript);
+  RawClass* cls = (owner_is_class) ?
+      reinterpret_cast<RawClass*>(func->ptr()->owner_) :
+      reinterpret_cast<RawPatchClass*>(
+          func->ptr()->owner_)->ptr()->patched_class_;
+
+  // Write out the library url and class name.
+  RawLibrary* library = cls->ptr()->library_;
+  ASSERT(library != Library::null());
+  WriteObjectImpl(library->ptr()->url_, kAsInlinedObject);
+  WriteObjectImpl(cls->ptr()->name_, kAsInlinedObject);
+  WriteObjectImpl(func->ptr()->name_, kAsInlinedObject);
+}
+
+
 void SnapshotWriter::WriteStaticImplicitClosure(intptr_t object_id,
                                                 RawFunction* func,
                                                 intptr_t tags) {
@@ -2515,13 +2508,10 @@
     ASSERT(!errorFunc.IsNull());
 
     // All other closures are errors.
-    const char* format = "Illegal argument in isolate message"
-        " : (object is a closure - %s %s)";
     UnmarkAll();  // Unmark objects now as we are about to print stuff.
-    intptr_t len = OS::SNPrint(NULL, 0, format,
-                               clazz.ToCString(), errorFunc.ToCString()) + 1;
-    char* chars = thread()->zone()->Alloc<char>(len);
-    OS::SNPrint(chars, len, format, clazz.ToCString(), errorFunc.ToCString());
+    char* chars = OS::SCreate(thread()->zone(),
+        "Illegal argument in isolate message : (object is a closure - %s %s)",
+        clazz.ToCString(), errorFunc.ToCString());
     SetWriteException(Exceptions::kArgument, chars);
   }
   return Function::null();
@@ -2544,13 +2534,12 @@
   if (cls->ptr()->num_native_fields_ != 0) {
     // We do not allow objects with native fields in an isolate message.
     HANDLESCOPE(thread());
-    const char* format = "Illegal argument in isolate message"
-                         " : (object extends NativeWrapper - %s)";
     UnmarkAll();  // Unmark objects now as we are about to print stuff.
     const Class& clazz = Class::Handle(isolate(), cls);
-    intptr_t len = OS::SNPrint(NULL, 0, format, clazz.ToCString()) + 1;
-    char* chars = thread()->zone()->Alloc<char>(len);
-    OS::SNPrint(chars, len, format, clazz.ToCString());
+    char* chars = OS::SCreate(thread()->zone(),
+        "Illegal argument in isolate message"
+        " : (object extends NativeWrapper - %s)",
+        clazz.ToCString());
     SetWriteException(Exceptions::kArgument, chars);
   }
 }
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index f612073..a23e692 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -32,6 +32,7 @@
 class Object;
 class PassiveObject;
 class ObjectStore;
+class MegamorphicCache;
 class PageSpace;
 class RawApiError;
 class RawArray;
@@ -339,6 +340,8 @@
   ExternalTypedData* DataHandle() { return &data_; }
   TypedData* TypedDataHandle() { return &typed_data_; }
   Code* CodeHandle() { return &code_; }
+  Function* FunctionHandle() { return &function_; }
+  MegamorphicCache* MegamorphicCacheHandle() { return &megamorphic_cache_; }
   Snapshot::Kind kind() const { return kind_; }
   bool snapshot_code() const { return snapshot_code_; }
 
@@ -442,6 +445,7 @@
   RawObject* AllocateUninitialized(intptr_t class_id, intptr_t size);
 
   RawClass* ReadClassId(intptr_t object_id);
+  RawFunction* ReadFunctionId(intptr_t object_id);
   RawObject* ReadStaticImplicitClosure(intptr_t object_id, intptr_t cls_header);
 
   // Implementation to read an object.
@@ -521,6 +525,8 @@
   ExternalTypedData& data_;  // Temporary stream data handle.
   TypedData& typed_data_;  // Temporary typed data handle.
   Code& code_;  // Temporary code handle.
+  Function& function_;  // Temporary function handle.
+  MegamorphicCache& megamorphic_cache_;  // Temporary megamorphic cache handle.
   UnhandledException& error_;  // Error handle.
   intptr_t max_vm_isolate_object_id_;
   ZoneGrowableArray<BackRefNode>* backward_references_;
@@ -876,6 +882,8 @@
     return instructions_writer_->SetInstructionsCode(instructions, code);
   }
 
+  void WriteFunctionId(RawFunction* func, bool owner_is_class);
+
  protected:
   void UnmarkAll() {
     if (!unmarked_objects_ && forward_list_ != NULL) {
diff --git a/runtime/vm/snapshot_ids.h b/runtime/vm/snapshot_ids.h
index a65df69..856887d 100644
--- a/runtime/vm/snapshot_ids.h
+++ b/runtime/vm/snapshot_ids.h
@@ -6,6 +6,7 @@
 #define VM_SNAPSHOT_IDS_H_
 
 #include "vm/raw_object.h"
+#include "vm/dart_entry.h"
 
 namespace dart {
 
@@ -46,6 +47,13 @@
   kExtractorParameterNames,
   kEmptyContextScopeObject,
   kImplicitClosureScopeObject,
+  kEmptyObjectPool,
+  kEmptyDescriptors,
+  kEmptyVarDescriptors,
+  kEmptyExceptionHandlers,
+  kCachedArgumentsDescriptor0,
+  kCachedArgumentsDescriptorN = (kCachedArgumentsDescriptor0 +
+      ArgumentsDescriptor::kCachedDescriptorCount - 1),
 
   kInstanceObjectId,
   kStaticImplicitClosureObjectId,
diff --git a/runtime/vm/stack_frame_test.cc b/runtime/vm/stack_frame_test.cc
index 426ede7..c5f280a 100644
--- a/runtime/vm/stack_frame_test.cc
+++ b/runtime/vm/stack_frame_test.cc
@@ -101,10 +101,8 @@
       const Library& lib = Library::Handle(Library::LookupLibrary(url));
       ASSERT(!lib.IsNull());
       const char* lib_name = String::Handle(lib.url()).ToCString();
-      intptr_t length = OS::SNPrint(NULL, 0, "%s_%s", lib_name, expected_name);
-      char* full_name = Thread::Current()->zone()->Alloc<char>(length + 1);
-      ASSERT(full_name != NULL);
-      OS::SNPrint(full_name, (length + 1), "%s_%s", lib_name, expected_name);
+      char* full_name = OS::SCreate(Thread::Current()->zone(),
+          "%s_%s", lib_name, expected_name);
       if (strcmp(full_name, name) != 0) {
         FATAL("StackFrame_validateFrame fails, incorrect frame.\n");
       }
diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc
index 486531a..65a4966 100644
--- a/runtime/vm/stub_code.cc
+++ b/runtime/vm/stub_code.cc
@@ -10,6 +10,7 @@
 #include "vm/disassembler.h"
 #include "vm/flags.h"
 #include "vm/object_store.h"
+#include "vm/snapshot.h"
 #include "vm/virtual_memory.h"
 #include "vm/visitor.h"
 
@@ -53,6 +54,24 @@
 #undef STUB_CODE_GENERATE
 
 
+void StubCode::ReadFrom(SnapshotReader* reader) {
+#define READ_STUB(name)                                                        \
+  *(reader->CodeHandle()) ^= reader->ReadObject();                             \
+  name##_entry_ = new StubEntry(*(reader->CodeHandle()));
+  VM_STUB_CODE_LIST(READ_STUB);
+#undef READ_STUB
+}
+
+void StubCode::WriteTo(SnapshotWriter* writer) {
+  // TODO(rmacnak): Consider writing only the instructions to avoid
+  // vm_isolate_is_symbolic.
+#define WRITE_STUB(name)                                                       \
+  writer->WriteObject(StubCode::name##_entry()->code());
+  VM_STUB_CODE_LIST(WRITE_STUB);
+#undef WRITE_STUB
+}
+
+
 void StubCode::Init(Isolate* isolate) { }
 
 
@@ -93,11 +112,11 @@
     stub.set_owner(cls);
     cls.set_allocation_stub(stub);
     if (FLAG_disassemble_stubs) {
-      LogBlock lb(Isolate::Current());
-      ISL_Print("Code for allocation stub '%s': {\n", name);
+      LogBlock lb;
+      THR_Print("Code for allocation stub '%s': {\n", name);
       DisassembleToStdout formatter;
       stub.Disassemble(&formatter);
-      ISL_Print("}\n");
+      THR_Print("}\n");
       const ObjectPool& object_pool = ObjectPool::Handle(
           Instructions::Handle(stub.instructions()).object_pool());
       object_pool.DebugPrint();
@@ -131,11 +150,11 @@
   GenerateStub(&assembler);
   const Code& code = Code::Handle(Code::FinalizeCode(name, &assembler));
   if (FLAG_disassemble_stubs) {
-    LogBlock lb(Isolate::Current());
-    ISL_Print("Code for stub '%s': {\n", name);
+    LogBlock lb;
+    THR_Print("Code for stub '%s': {\n", name);
     DisassembleToStdout formatter;
     code.Disassemble(&formatter);
-    ISL_Print("}\n");
+    THR_Print("}\n");
     const ObjectPool& object_pool = ObjectPool::Handle(
         Instructions::Handle(code.instructions()).object_pool());
     object_pool.DebugPrint();
diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h
index 3a5ffc1..3d3c016 100644
--- a/runtime/vm/stub_code.h
+++ b/runtime/vm/stub_code.h
@@ -15,6 +15,8 @@
 class Isolate;
 class ObjectPointerVisitor;
 class RawCode;
+class SnapshotReader;
+class SnapshotWriter;
 
 
 // List of stubs created in the VM isolate, these stubs are shared by different
@@ -98,6 +100,9 @@
   // only once and the stub code resides in the vm_isolate heap.
   static void InitOnce();
 
+  static void ReadFrom(SnapshotReader* reader);
+  static void WriteTo(SnapshotWriter* writer);
+
   // Generate all stubs which are generated on a per isolate basis as they
   // have embedded objects which are isolate specific.
   static void Init(Isolate* isolate);
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index ab56734..9d2883b 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -303,7 +303,7 @@
   // calling into the runtime.
   __ EnterStubFrame();
   // Setup space on stack for return value and preserve arguments descriptor.
-  __ LoadImmediate(R0, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(R0, Object::null_object());
   __ PushList((1 << R0) | (1 << R4));
   __ CallRuntime(kPatchStaticCallRuntimeEntry, 0);
   // Get Code object result and restore arguments descriptor array.
@@ -324,7 +324,7 @@
   // calling into the runtime.
   __ EnterStubFrame();
   // Setup space on stack for return value and preserve arguments descriptor.
-  __ LoadImmediate(R0, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(R0, Object::null_object());
   __ PushList((1 << R0) | (1 << R4));
   __ CallRuntime(kFixCallersTargetRuntimeEntry, 0);
   // Get Code object result and restore arguments descriptor array.
@@ -342,7 +342,7 @@
 void StubCode::GenerateFixAllocationStubTargetStub(Assembler* assembler) {
   __ EnterStubFrame();
   // Setup space on stack for return value.
-  __ LoadImmediate(R0, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(R0, Object::null_object());
   __ Push(R0);
   __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0);
   // Get Code object result.
@@ -360,7 +360,7 @@
 //   FP[kParamEndSlotFromFp + 1]: last argument.
 static void PushArgumentsArray(Assembler* assembler) {
   // Allocate array to store arguments of caller.
-  __ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(R1, Object::null_object());
   // R1: null element type for raw Array.
   // R2: smi-tagged argument count, may be zero.
   __ BranchLink(*StubCode::AllocateArray_entry());
@@ -563,7 +563,7 @@
   // Push the receiver.
   // Push IC data object.
   // Push arguments descriptor array.
-  __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(IP, Object::null_object());
   __ PushList((1 << R4) | (1 << R5) | (1 << R6) | (1 << IP));
   __ CallRuntime(kMegamorphicCacheMissHandlerRuntimeEntry, 3);
   // Remove arguments.
@@ -688,7 +688,7 @@
   // R7: new object end address.
   // R9: allocation size.
 
-  __ LoadImmediate(R4, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(R4, Object::null_object());
   __ mov(R5, Operand(R4));
   __ AddImmediate(R6, R0, sizeof(RawArray) - kHeapObjectTag);
   __ InitializeFieldsNoBarrier(R0, R6, R7, R4, R5);
@@ -701,7 +701,7 @@
   // Create a stub frame as we are pushing some objects on the stack before
   // calling into the runtime.
   __ EnterStubFrame();
-  __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(IP, Object::null_object());
   // Setup space on stack for return value.
   // Push array length as Smi and element type.
   __ PushList((1 << R1) | (1 << R2) | (1 << IP));
@@ -914,7 +914,7 @@
     // R2: object size.
     // R3: next object start.
     // R6: allocation stats address.
-    __ LoadImmediate(R4, reinterpret_cast<intptr_t>(Object::null()));
+    __ LoadObject(R4, Object::null_object());
     __ InitializeFieldNoBarrier(R0, FieldAddress(R0, Context::parent_offset()),
                                 R4);
 
@@ -940,7 +940,7 @@
   // calling into the runtime.
   __ EnterStubFrame();
   // Setup space on stack for return value.
-  __ LoadImmediate(R2, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(R2, Object::null_object());
   __ SmiTag(R1);
   __ PushList((1 << R1) | (1 << R2));
   __ CallRuntime(kAllocateContextRuntimeEntry, 1);  // Allocate context.
@@ -1086,7 +1086,7 @@
     __ add(R0, R0, Operand(kHeapObjectTag));
 
     // Initialize the remaining words of the object.
-    __ LoadImmediate(R2, reinterpret_cast<intptr_t>(Object::null()));
+    __ LoadObject(R2, Object::null_object());
 
     // R2: raw null.
     // R0: new object (tagged).
@@ -1144,7 +1144,7 @@
   // Create a stub frame as we are pushing some objects on the stack before
   // calling into the runtime.
   __ EnterStubFrame();  // Uses pool pointer to pass cls to runtime.
-  __ LoadImmediate(R2, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(R2, Object::null_object());
   __ Push(R2);  // Setup space on stack for return value.
   __ PushObject(cls);  // Push class of object to be allocated.
   if (is_cls_parameterized) {
@@ -1184,7 +1184,7 @@
   // Push space for the return value.
   // Push the receiver.
   // Push arguments descriptor array.
-  __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(IP, Object::null_object());
   __ PushList((1 << R4) | (1 << R6) | (1 << IP));
 
   // R2: Smi-tagged arguments array length.
@@ -1424,7 +1424,7 @@
   // Create a stub frame as we are pushing some objects on the stack before
   // calling into the runtime.
   __ EnterStubFrame();
-  __ LoadImmediate(R0, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(R0, Object::null_object());
   // Preserve IC data object and arguments descriptor array and
   // setup space on stack for result (target code object).
   __ PushList((1 << R0) | (1 << R4) | (1 << R5));
@@ -1699,7 +1699,7 @@
 // R5: Contains an ICData.
 void StubCode::GenerateICCallBreakpointStub(Assembler* assembler) {
   __ EnterStubFrame();
-  __ LoadImmediate(R0, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(R0, Object::null_object());
   // Preserve arguments descriptor and make room for result.
   __ PushList((1 << R0) | (1 << R5));
   __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0);
@@ -1711,7 +1711,7 @@
 
 void StubCode::GenerateRuntimeCallBreakpointStub(Assembler* assembler) {
   __ EnterStubFrame();
-  __ LoadImmediate(R0, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(R0, Object::null_object());
   // Make room for result.
   __ PushList((1 << R0));
   __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0);
@@ -1754,7 +1754,7 @@
     __ LoadClass(R3, R0, R4);
     // Compute instance type arguments into R4.
     Label has_no_type_arguments;
-    __ LoadImmediate(R4, reinterpret_cast<intptr_t>(Object::null()));
+    __ LoadObject(R4, Object::null_object());
     __ ldr(R5, FieldAddress(R3,
         Class::type_arguments_field_offset_in_words_offset()));
     __ CompareImmediate(R5, Class::kNoTypeArguments);
@@ -1779,7 +1779,7 @@
   __ SmiTag(R3);
   __ Bind(&loop);
   __ ldr(R5, Address(R2, kWordSize * SubtypeTestCache::kInstanceClassId));
-  __ CompareImmediate(R5, reinterpret_cast<intptr_t>(Object::null()));
+  __ CompareObject(R5, Object::null_object());
   __ b(&not_found, EQ);
   __ cmp(R5, Operand(R3));
   if (n == 1) {
@@ -1804,7 +1804,7 @@
   __ b(&loop);
   // Fall through to not found.
   __ Bind(&not_found);
-  __ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(R1, Object::null_object());
   __ Ret();
 
   __ Bind(&found);
@@ -1889,7 +1889,7 @@
 void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) {
   __ EnterStubFrame();
   __ Push(R4);
-  __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(IP, Object::null_object());
   __ Push(IP);  // Setup space on stack for return value.
   __ Push(R6);
   __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry, 1);
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index 44498fc..d6b55f8 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -316,7 +316,7 @@
 
   __ addiu(SP, SP, Immediate(-2 * kWordSize));
   __ sw(S4, Address(SP, 1 * kWordSize));
-  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(TMP, Object::null_object());
   __ sw(TMP, Address(SP, 0 * kWordSize));
 
   __ CallRuntime(kPatchStaticCallRuntimeEntry, 0);
@@ -345,7 +345,7 @@
   // Setup space on stack for return value and preserve arguments descriptor.
   __ addiu(SP, SP, Immediate(-2 * kWordSize));
   __ sw(S4, Address(SP, 1 * kWordSize));
-  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(TMP, Object::null_object());
   __ sw(TMP, Address(SP, 0 * kWordSize));
   __ CallRuntime(kFixCallersTargetRuntimeEntry, 0);
   // Get Code object result and restore arguments descriptor array.
@@ -368,7 +368,7 @@
   __ EnterStubFrame();
   // Setup space on stack for return value.
   __ addiu(SP, SP, Immediate(-1 * kWordSize));
-  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(TMP, Object::null_object());
   __ sw(TMP, Address(SP, 0 * kWordSize));
   __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0);
   // Get Code object result.
@@ -389,7 +389,7 @@
 static void PushArgumentsArray(Assembler* assembler) {
   __ Comment("PushArgumentsArray");
   // Allocate array to store arguments of caller.
-  __ LoadImmediate(A0, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(A0, Object::null_object());
   // A0: Null element type for raw Array.
   // A1: Smi-tagged argument count, may be zero.
   __ BranchLink(*StubCode::AllocateArray_entry());
@@ -568,7 +568,7 @@
   // Push arguments descriptor array.
   // Push original arguments array.
   __ addiu(SP, SP, Immediate(-4 * kWordSize));
-  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(TMP, Object::null_object());
   __ sw(TMP, Address(SP, 3 * kWordSize));
   __ sw(T6, Address(SP, 2 * kWordSize));
   __ sw(S5, Address(SP, 1 * kWordSize));
@@ -602,7 +602,7 @@
   // Push the receiver.
   // Push IC data object.
   // Push arguments descriptor array.
-  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(TMP, Object::null_object());
   __ sw(TMP, Address(SP, 3 * kWordSize));
   __ sw(T6, Address(SP, 2 * kWordSize));
   __ sw(S5, Address(SP, 1 * kWordSize));
@@ -731,7 +731,7 @@
                               FieldAddress(T0, Array::length_offset()),
                               A1);
 
-  __ LoadImmediate(T7, reinterpret_cast<int32_t>(Object::null()));
+  __ LoadObject(T7, Object::null_object());
   // Initialize all array elements to raw_null.
   // T0: new object start as a tagged pointer.
   // T1: new object end address.
@@ -761,7 +761,7 @@
   // Setup space on stack for return value.
   // Push array length as Smi and element type.
   __ addiu(SP, SP, Immediate(-3 * kWordSize));
-  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(TMP, Object::null_object());
   __ sw(TMP, Address(SP, 2 * kWordSize));
   __ sw(A1, Address(SP, 1 * kWordSize));
   __ sw(A0, Address(SP, 0 * kWordSize));
@@ -995,7 +995,7 @@
     // T1: number of context variables as integer value (not object).
     __ sw(T1, FieldAddress(V0, Context::num_variables_offset()));
 
-    __ LoadImmediate(T7, reinterpret_cast<intptr_t>(Object::null()));
+    __ LoadObject(T7, Object::null_object());
 
     // Initialize the context variables.
     // V0: new object.
@@ -1025,7 +1025,7 @@
   // Setup space on stack for return value.
   __ SmiTag(T1);
   __ addiu(SP, SP, Immediate(-2 * kWordSize));
-  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(TMP, Object::null_object());
   __ sw(TMP, Address(SP, 1 * kWordSize));  // Store null.
   __ sw(T1, Address(SP, 0 * kWordSize));
   __ CallRuntime(kAllocateContextRuntimeEntry, 1);  // Allocate context.
@@ -1167,7 +1167,7 @@
     __ LoadImmediate(T0, tags);
     __ sw(T0, Address(T2, Instance::tags_offset()));
 
-    __ LoadImmediate(T7, reinterpret_cast<intptr_t>(Object::null()));
+    __ LoadObject(T7, Object::null_object());
 
     // Initialize the remaining words of the object.
     // T2: new object start.
@@ -1218,7 +1218,7 @@
 
   __ addiu(SP, SP, Immediate(-3 * kWordSize));
   // Space on stack for return value.
-  __ LoadImmediate(T7, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(T7, Object::null_object());
   __ sw(T7, Address(SP, 2 * kWordSize));
   __ sw(TMP, Address(SP, 1 * kWordSize));  // Class of object to be allocated.
 
@@ -1263,7 +1263,7 @@
   // Push arguments descriptor array.
   const intptr_t kNumArgs = 3;
   __ addiu(SP, SP, Immediate(-kNumArgs * kWordSize));
-  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(TMP, Object::null_object());
   __ sw(TMP, Address(SP, 2 * kWordSize));
   __ sw(T6, Address(SP, 1 * kWordSize));
   __ sw(S4, Address(SP, 0 * kWordSize));
@@ -1539,7 +1539,7 @@
   __ addiu(SP, SP, Immediate(-num_slots * kWordSize));
   __ sw(S5, Address(SP, (num_slots - 1) * kWordSize));
   __ sw(S4, Address(SP, (num_slots - 2) * kWordSize));
-  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(TMP, Object::null_object());
   __ sw(TMP, Address(SP, (num_slots - 3) * kWordSize));
   // Push call arguments.
   for (intptr_t i = 0; i < num_args; i++) {
@@ -1838,7 +1838,7 @@
   __ EnterStubFrame();
   __ addiu(SP, SP, Immediate(-2 * kWordSize));
   __ sw(S5, Address(SP, 1 * kWordSize));
-  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(TMP, Object::null_object());
   __ sw(TMP, Address(SP, 0 * kWordSize));
 
   __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0);
@@ -1855,7 +1855,7 @@
   __ Comment("RuntimeCallBreakpoint stub");
   __ EnterStubFrame();
   __ addiu(SP, SP, Immediate(-1 * kWordSize));
-  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(TMP, Object::null_object());
   __ sw(TMP, Address(SP, 0 * kWordSize));
 
   __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0);
@@ -1906,7 +1906,7 @@
     __ LoadClass(T0, A0);
     // Compute instance type arguments into T1.
     Label has_no_type_arguments;
-    __ LoadImmediate(T1, reinterpret_cast<intptr_t>(Object::null()));
+    __ LoadObject(T1, Object::null_object());
     __ lw(T2, FieldAddress(T0,
         Class::type_arguments_field_offset_in_words_offset()));
     __ BranchEqual(
@@ -1925,7 +1925,7 @@
   __ lw(T2, FieldAddress(A2, SubtypeTestCache::cache_offset()));
   __ AddImmediate(T2, Array::data_offset() - kHeapObjectTag);
 
-  __ LoadImmediate(T7, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(T7, Object::null_object());
 
   Label loop, found, not_found, next_iteration;
   // T0: instance class id.
@@ -2048,7 +2048,7 @@
   __ addiu(SP, SP, Immediate(-3 * kWordSize));
   __ sw(S4, Address(SP, 2 * kWordSize));
   // Setup space on stack for return value.
-  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(TMP, Object::null_object());
   __ sw(TMP, Address(SP, 1 * kWordSize));
   __ sw(T0, Address(SP, 0 * kWordSize));
   __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry, 1);
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 9d389c1..0dd4640 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -493,16 +493,14 @@
   __ Comment("NoSuchMethodDispatch");
   // When lazily generated invocation dispatchers are disabled, the
   // miss-handler may return null.
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
-  __ cmpq(RAX, raw_null);
+  __ CompareObject(RAX, Object::null_object());
   __ j(NOT_EQUAL, call_target_function);
   __ EnterStubFrame();
   // Load the receiver.
   __ movq(RDI, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
   __ movq(RAX, Address(
       RBP, RDI, TIMES_HALF_WORD_SIZE, kParamEndSlotFromFp * kWordSize));
-  __ pushq(raw_null);  // Setup space on stack for result.
+  __ PushObject(Object::null_object());  // Setup space on stack for result.
   __ pushq(RAX);  // Receiver.
   __ pushq(RBX);
   __ pushq(R10);  // Arguments descriptor array.
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 7d817d3..ceba83f 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -7,6 +7,7 @@
 #include "vm/growable_array.h"
 #include "vm/isolate.h"
 #include "vm/lockers.h"
+#include "vm/log.h"
 #include "vm/object.h"
 #include "vm/os_thread.h"
 #include "vm/profiler.h"
@@ -52,6 +53,8 @@
   // Clear |this| from all isolate's thread registry.
   ThreadPruner pruner(this);
   Isolate::VisitIsolates(&pruner);
+  delete log_;
+  log_ = NULL;
 }
 
 
@@ -108,7 +111,8 @@
       thread_interrupt_data_(NULL),
       isolate_(NULL),
       heap_(NULL),
-      store_buffer_block_(NULL) {
+      store_buffer_block_(NULL),
+      log_(new class Log()) {
   ClearState();
 
 #define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value)    \
@@ -307,6 +311,11 @@
 }
 
 
+Log* Thread::log() const {
+  return log_;
+}
+
+
 void Thread::SetThreadInterrupter(ThreadInterruptCallback callback,
                                   void* data) {
   ASSERT(Thread::Current() == this);
@@ -333,6 +342,14 @@
 }
 
 
+void Thread::CloseTimelineBlock() {
+  if (timeline_block() != NULL) {
+    timeline_block()->Finish();
+    set_timeline_block(NULL);
+  }
+}
+
+
 bool Thread::CanLoadFromThread(const Object& object) {
 #define CHECK_OBJECT(type_name, member_name, expr, default_init_value)         \
   if (object.raw() == expr) return true;
@@ -352,6 +369,7 @@
   return -1;
 }
 
+
 intptr_t Thread::OffsetFromThread(const RuntimeEntry* runtime_entry) {
 #define COMPUTE_OFFSET(name)                                                   \
   if (runtime_entry->function() == k##name##RuntimeEntry.function())         { \
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 16eade4..5e14a8f 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -16,6 +16,7 @@
 class HandleScope;
 class Heap;
 class Isolate;
+class Log;
 class LongJumpScope;
 class Object;
 class RawBool;
@@ -256,6 +257,9 @@
     state_.timeline_block = block;
   }
 
+  void CloseTimelineBlock();
+  class Log* log() const;
+
   LongJumpScope* long_jump_base() const { return state_.long_jump_base; }
   void set_long_jump_base(LongJumpScope* value) {
     state_.long_jump_base = value;
@@ -281,6 +285,7 @@
   Heap* heap_;
   State state_;
   StoreBufferBlock* store_buffer_block_;
+  class Log* log_;
 #define DECLARE_MEMBERS(type_name, member_name, expr, default_init_value)      \
   type_name member_name;
 CACHED_CONSTANTS_LIST(DECLARE_MEMBERS)
diff --git a/runtime/vm/thread_interrupter.cc b/runtime/vm/thread_interrupter.cc
index 0cf7c38..58c94be 100644
--- a/runtime/vm/thread_interrupter.cc
+++ b/runtime/vm/thread_interrupter.cc
@@ -51,8 +51,8 @@
 bool ThreadInterrupter::initialized_ = false;
 bool ThreadInterrupter::shutdown_ = false;
 bool ThreadInterrupter::thread_running_ = false;
-ThreadId ThreadInterrupter::interrupter_thread_id_ =
-    OSThread::kInvalidThreadId;
+ThreadJoinId ThreadInterrupter::interrupter_thread_id_ =
+    OSThread::kInvalidThreadJoinId;
 Monitor* ThreadInterrupter::monitor_ = NULL;
 intptr_t ThreadInterrupter::interrupt_period_ = 1000;
 intptr_t ThreadInterrupter::current_wait_time_ = Monitor::kNoTimeout;
@@ -71,7 +71,7 @@
   if (FLAG_trace_thread_interrupter) {
     OS::Print("ThreadInterrupter starting up.\n");
   }
-  ASSERT(interrupter_thread_id_ == OSThread::kInvalidThreadId);
+  ASSERT(interrupter_thread_id_ == OSThread::kInvalidThreadJoinId);
   {
     MonitorLocker startup_ml(monitor_);
     OSThread::Start(ThreadMain, 0);
@@ -79,7 +79,7 @@
       startup_ml.Wait();
     }
   }
-  ASSERT(interrupter_thread_id_ != OSThread::kInvalidThreadId);
+  ASSERT(interrupter_thread_id_ != OSThread::kInvalidThreadJoinId);
   if (FLAG_trace_thread_interrupter) {
     OS::Print("ThreadInterrupter running.\n");
   }
@@ -101,24 +101,12 @@
       OS::Print("ThreadInterrupter shutting down.\n");
     }
   }
-#if defined(TARGET_OS_WINDOWS)
-  // On Windows, a thread's exit-code can leak into the process's exit-code,
-  // if exiting 'at same time' as the process ends. By joining with the thread
-  // here, we avoid this race condition.
-  ASSERT(interrupter_thread_id_ != OSThread::kInvalidThreadId);
+
+  // Join the thread.
+  ASSERT(interrupter_thread_id_ != OSThread::kInvalidThreadJoinId);
   OSThread::Join(interrupter_thread_id_);
-  interrupter_thread_id_ = OSThread::kInvalidThreadId;
-#else
-  // On non-Windows platforms, just wait for the thread interrupter to signal
-  // that it has exited the loop.
-  {
-    MonitorLocker shutdown_ml(monitor_);
-    while (thread_running_) {
-      // Wait for thread to exit.
-      shutdown_ml.Wait();
-    }
-  }
-#endif
+  interrupter_thread_id_ = OSThread::kInvalidThreadJoinId;
+
   if (FLAG_trace_thread_interrupter) {
     OS::Print("ThreadInterrupter shut down.\n");
   }
@@ -187,7 +175,7 @@
   {
     // Signal to main thread we are ready.
     MonitorLocker startup_ml(monitor_);
-    interrupter_thread_id_ = OSThread::GetCurrentThreadId();
+    interrupter_thread_id_ = OSThread::GetCurrentThreadJoinId();
     thread_running_ = true;
     startup_ml.Notify();
   }
@@ -198,6 +186,10 @@
     while (!shutdown_) {
       intptr_t r = wait_ml.WaitMicros(current_wait_time_);
 
+      if ((r == Monitor::kNotified) && shutdown_) {
+        break;
+      }
+
       if ((r == Monitor::kNotified) && InDeepSleep()) {
         // Woken up from deep sleep.
         ASSERT(visitor.profiled_thread_count() == 0);
diff --git a/runtime/vm/thread_interrupter.h b/runtime/vm/thread_interrupter.h
index 0fa00e1..9d3ccab 100644
--- a/runtime/vm/thread_interrupter.h
+++ b/runtime/vm/thread_interrupter.h
@@ -40,7 +40,7 @@
   static bool initialized_;
   static bool shutdown_;
   static bool thread_running_;
-  static ThreadId interrupter_thread_id_;
+  static ThreadJoinId interrupter_thread_id_;
   static Monitor* monitor_;
   static intptr_t interrupt_period_;
   static intptr_t current_wait_time_;
diff --git a/runtime/vm/thread_pool.cc b/runtime/vm/thread_pool.cc
index 5b3a713..e4453d8 100644
--- a/runtime/vm/thread_pool.cc
+++ b/runtime/vm/thread_pool.cc
@@ -12,9 +12,6 @@
 DEFINE_FLAG(int, worker_timeout_millis, 5000,
             "Free workers when they have been idle for this amount of time.");
 
-Monitor* ThreadPool::exit_monitor_ = NULL;
-int* ThreadPool::exit_count_ = NULL;
-
 ThreadPool::ThreadPool()
   : shutting_down_(false),
     all_workers_(NULL),
@@ -22,7 +19,9 @@
     count_started_(0),
     count_stopped_(0),
     count_running_(0),
-    count_idle_(0) {
+    count_idle_(0),
+    shutting_down_workers_(NULL),
+    join_list_(NULL) {
 }
 
 
@@ -31,7 +30,7 @@
 }
 
 
-void ThreadPool::Run(Task* task) {
+bool ThreadPool::Run(Task* task) {
   Worker* worker = NULL;
   bool new_worker = false;
   {
@@ -39,7 +38,7 @@
     // ThreadPool state.
     MutexLocker ml(&mutex_);
     if (shutting_down_) {
-      return;
+      return false;
     }
     if (idle_workers_ == NULL) {
       worker = new Worker(this);
@@ -51,15 +50,17 @@
       worker->all_next_ = all_workers_;
       all_workers_ = worker;
       worker->owned_ = true;
+      count_running_++;
     } else {
       // Get the first worker from the idle worker list.
       worker = idle_workers_;
       idle_workers_ = worker->idle_next_;
       worker->idle_next_ = NULL;
       count_idle_--;
+      count_running_++;
     }
-    count_running_++;
   }
+
   // Release ThreadPool::mutex_ before calling Worker functions.
   ASSERT(worker != NULL);
   worker->SetTask(task);
@@ -67,6 +68,7 @@
     // Call StartThread after we've assigned the first task.
     worker->StartThread();
   }
+  return true;
 }
 
 
@@ -94,15 +96,48 @@
   }
   // Release ThreadPool::mutex_ before calling Worker functions.
 
-  Worker* current = saved;
-  while (current != NULL) {
-    // We may access all_next_ without holding ThreadPool::mutex_ here
-    // because the worker is no longer owned by the ThreadPool.
-    Worker* next = current->all_next_;
-    current->all_next_ = NULL;
-    current->Shutdown();
-    current = next;
+  {
+    MonitorLocker eml(&exit_monitor_);
+
+    // First tell all the workers to shut down.
+    Worker* current = saved;
+    ThreadId id = OSThread::GetCurrentThreadId();
+    while (current != NULL) {
+      Worker* next = current->all_next_;
+      ThreadId currentId = current->id();
+      if (currentId != id) {
+        AddWorkerToShutdownList(current);
+      }
+      current->Shutdown();
+      current = next;
+    }
+    saved = NULL;
+
+    // Wait until all workers will exit.
+    while (shutting_down_workers_ != NULL) {
+      // Here, we are waiting for workers to exit. When a worker exits we will
+      // be notified.
+      eml.Wait();
+    }
   }
+
+  // Extract the join list, and join on the threads.
+  JoinList* list = NULL;
+  {
+    MutexLocker ml(&mutex_);
+    list = join_list_;
+    join_list_ = NULL;
+  }
+
+  // Join non-idle threads.
+  JoinList::Join(&list);
+
+#if defined(DEBUG)
+  {
+    MutexLocker ml(&mutex_);
+    ASSERT(join_list_ == NULL);
+  }
+#endif
 }
 
 
@@ -156,7 +191,7 @@
     all_workers_ = worker->all_next_;
     worker->all_next_ = NULL;
     worker->owned_ = false;
-    worker->pool_ = NULL;
+    worker->done_ = true;
     return true;
   }
 
@@ -174,16 +209,24 @@
 }
 
 
-void ThreadPool::SetIdle(Worker* worker) {
-  MutexLocker ml(&mutex_);
-  if (shutting_down_) {
-    return;
+void ThreadPool::SetIdleAndReapExited(Worker* worker) {
+  JoinList* list = NULL;
+  {
+    MutexLocker ml(&mutex_);
+    if (shutting_down_) {
+      return;
+    }
+    ASSERT(worker->owned_ && !IsIdle(worker));
+    worker->idle_next_ = idle_workers_;
+    idle_workers_ = worker;
+    count_idle_++;
+    count_running_--;
+
+    // While we have the lock, opportunistically grab and clear the join_list_.
+    list = join_list_;
+    join_list_ = NULL;
   }
-  ASSERT(worker->owned_ && !IsIdle(worker));
-  worker->idle_next_ = idle_workers_;
-  idle_workers_ = worker;
-  count_idle_++;
-  count_running_--;
+  JoinList::Join(&list);
 }
 
 
@@ -200,12 +243,62 @@
   bool found = RemoveWorkerFromAllList(worker);
   ASSERT(found);
 
+  // The thread for worker will exit. Add its ThreadId to the join_list_
+  // so that we can join on it at the next opportunity.
+  JoinList::AddLocked(OSThread::GetCurrentThreadJoinId(), &join_list_);
   count_stopped_++;
   count_idle_--;
   return true;
 }
 
 
+// Only call while holding the exit_monitor_
+void ThreadPool::AddWorkerToShutdownList(Worker* worker) {
+  worker->shutdown_next_ = shutting_down_workers_;
+  shutting_down_workers_ = worker;
+}
+
+
+// Only call while holding the exit_monitor_
+bool ThreadPool::RemoveWorkerFromShutdownList(Worker* worker) {
+  ASSERT(worker != NULL);
+  ASSERT(shutting_down_workers_ != NULL);
+
+  // Special case head of list.
+  if (shutting_down_workers_ == worker) {
+    shutting_down_workers_ = worker->shutdown_next_;
+    worker->shutdown_next_ = NULL;
+    return true;
+  }
+
+  for (Worker* current = shutting_down_workers_;
+       current->shutdown_next_ != NULL;
+       current = current->shutdown_next_) {
+    if (current->shutdown_next_ == worker) {
+      current->shutdown_next_ = worker->shutdown_next_;
+      worker->shutdown_next_ = NULL;
+      return true;
+    }
+  }
+  return false;
+}
+
+
+void ThreadPool::JoinList::AddLocked(ThreadJoinId id, JoinList** list) {
+  *list = new JoinList(id, *list);
+}
+
+
+void ThreadPool::JoinList::Join(JoinList** list) {
+  while (*list != NULL) {
+    JoinList* current = *list;
+    *list = current->next();
+    OSThread::Join(current->id());
+    delete current;
+  }
+}
+
+
 ThreadPool::Task::Task() {
 }
 
@@ -217,9 +310,18 @@
 ThreadPool::Worker::Worker(ThreadPool* pool)
   : pool_(pool),
     task_(NULL),
+    id_(OSThread::kInvalidThreadId),
+    done_(false),
     owned_(false),
     all_next_(NULL),
-    idle_next_(NULL) {
+    idle_next_(NULL),
+    shutdown_next_(NULL) {
+}
+
+
+ThreadId ThreadPool::Worker::id() {
+  MonitorLocker ml(&monitor_);
+  return id_;
 }
 
 
@@ -264,7 +366,7 @@
 }
 
 
-void ThreadPool::Worker::Loop() {
+bool ThreadPool::Worker::Loop() {
   MonitorLocker ml(&monitor_);
   int64_t idle_start;
   while (true) {
@@ -281,10 +383,10 @@
 
     ASSERT(task_ == NULL);
     if (IsDone()) {
-      return;
+      return false;
     }
-    ASSERT(pool_ != NULL);
-    pool_->SetIdle(this);
+    ASSERT(!done_);
+    pool_->SetIdleAndReapExited(this);
     idle_start = OS::GetCurrentTimeMillis();
     while (true) {
       Monitor::WaitResult result = ml.Wait(ComputeTimeout(idle_start));
@@ -294,21 +396,21 @@
         break;
       }
       if (IsDone()) {
-        return;
+        return false;
       }
-      if (result == Monitor::kTimedOut &&
-          pool_->ReleaseIdleWorker(this)) {
-        return;
+      if ((result == Monitor::kTimedOut) && pool_->ReleaseIdleWorker(this)) {
+        return true;
       }
     }
   }
   UNREACHABLE();
+  return false;
 }
 
 
 void ThreadPool::Worker::Shutdown() {
   MonitorLocker ml(&monitor_);
-  pool_ = NULL;  // Fail fast if someone tries to access pool_.
+  done_ = true;
   ml.Notify();
 }
 
@@ -317,20 +419,58 @@
 void ThreadPool::Worker::Main(uword args) {
   Thread::EnsureInit();
   Worker* worker = reinterpret_cast<Worker*>(args);
-  worker->Loop();
+  ThreadId id = OSThread::GetCurrentThreadId();
+  ThreadJoinId join_id = OSThread::GetCurrentThreadJoinId();
+  ThreadPool* pool;
+
+  {
+    MonitorLocker ml(&worker->monitor_);
+    ASSERT(worker->task_);
+    worker->id_ = id;
+    pool = worker->pool_;
+  }
+
+  bool released = worker->Loop();
 
   // It should be okay to access these unlocked here in this assert.
-  ASSERT(!worker->owned_ &&
-         worker->all_next_ == NULL &&
-         worker->idle_next_ == NULL);
+  // worker->all_next_ is retained by the pool for shutdown monitoring.
+  ASSERT(!worker->owned_ && (worker->idle_next_ == NULL));
 
-  // The exit monitor is only used during testing.
-  if (ThreadPool::exit_monitor_) {
-    MonitorLocker ml(ThreadPool::exit_monitor_);
-    (*ThreadPool::exit_count_)++;
-    ml.Notify();
+  if (!released) {
+    // This worker is exiting because the thread pool is being shut down.
+    // Inform the thread pool that we are exiting. We remove this worker from
+    // shutting_down_workers_ list because there will be no need for the
+    // ThreadPool to take action for this worker.
+    {
+      MutexLocker ml(&pool->mutex_);
+      JoinList::AddLocked(join_id, &pool->join_list_);
+    }
+
+    // worker->id_ should never be read again, so set to invalid in debug mode
+    // for asserts.
+#if defined(DEBUG)
+    {
+      MonitorLocker ml(&worker->monitor_);
+      worker->id_ = OSThread::kInvalidThreadId;
+    }
+#endif
+
+    // Remove from the shutdown list, delete, and notify the thread pool.
+    {
+      MonitorLocker eml(&pool->exit_monitor_);
+      pool->RemoveWorkerFromShutdownList(worker);
+      delete worker;
+      eml.Notify();
+    }
+  } else {
+    // This worker is going down because it was idle for too long. This case
+    // is not due to a ThreadPool Shutdown. Thus, we simply delete the worker.
+    // The worker's id is added to the thread pool's join list by
+    // ReleaseIdleWorker, so in the case that the thread pool begins shutting
+    // down immediately after returning from worker->Loop() above, we still
+    // wait for the thread to exit by joining on it in Shutdown().
+    delete worker;
   }
-  delete worker;
 #if defined(TARGET_OS_WINDOWS)
   Thread::CleanUp();
 #endif
diff --git a/runtime/vm/thread_pool.h b/runtime/vm/thread_pool.h
index 792aef7..1713781 100644
--- a/runtime/vm/thread_pool.h
+++ b/runtime/vm/thread_pool.h
@@ -5,6 +5,7 @@
 #ifndef VM_THREAD_POOL_H_
 #define VM_THREAD_POOL_H_
 
+#include "vm/allocation.h"
 #include "vm/globals.h"
 #include "vm/os_thread.h"
 
@@ -29,12 +30,12 @@
 
   ThreadPool();
 
-  // Shuts down this thread pool.  Causes workers to terminate
+  // Shuts down this thread pool. Causes workers to terminate
   // themselves when they are active again.
   ~ThreadPool();
 
   // Runs a task on the thread pool.
-  void Run(Task* task);
+  bool Run(Task* task);
 
   // Some simple stats.
   uint64_t workers_running() const { return count_running_; }
@@ -43,8 +44,6 @@
   uint64_t workers_stopped() const { return count_stopped_; }
 
  private:
-  friend class ThreadPoolTestPeer;
-
   class Worker {
    public:
     explicit Worker(ThreadPool* pool);
@@ -56,24 +55,30 @@
     // after a task has been set by the initial call to SetTask().
     void StartThread();
 
-    // Main loop for a worker.
-    void Loop();
+    // Main loop for a worker. Returns true if worker is removed from thread
+    // lists, false otherwise.
+    bool Loop();
 
     // Causes worker to terminate eventually.
     void Shutdown();
 
+    // Get the Worker's thread id.
+    ThreadId id();
+
    private:
     friend class ThreadPool;
 
     // The main entry point for new worker threads.
     static void Main(uword args);
 
-    bool IsDone() const { return pool_ == NULL; }
+    bool IsDone() const { return done_; }
 
     // Fields owned by Worker.
     Monitor monitor_;
     ThreadPool* pool_;
     Task* task_;
+    ThreadId id_;
+    bool done_;
 
     // Fields owned by ThreadPool.  Workers should not look at these
     // directly.  It's like looking at the sun.
@@ -81,9 +86,31 @@
     Worker* all_next_;   // Protected by ThreadPool::mutex_
     Worker* idle_next_;  // Protected by ThreadPool::mutex_
 
+    Worker* shutdown_next_;  // Protected by ThreadPool::exit_monitor
+
     DISALLOW_COPY_AND_ASSIGN(Worker);
   };
 
+  class JoinList {
+   public:
+    explicit JoinList(ThreadJoinId id, JoinList* next) : id_(id), next_(next) {
+    }
+
+    // The thread pool's mutex_ must be held when calling this.
+    static void AddLocked(ThreadJoinId id, JoinList** list);
+
+    static void Join(JoinList** list);
+
+    ThreadJoinId id() const { return id_; }
+    JoinList* next() const { return next_; }
+
+   private:
+    ThreadJoinId id_;
+    JoinList* next_;
+
+    DISALLOW_COPY_AND_ASSIGN(JoinList);
+  };
+
   void Shutdown();
 
   // Expensive.  Use only in assertions.
@@ -92,8 +119,13 @@
   bool RemoveWorkerFromIdleList(Worker* worker);
   bool RemoveWorkerFromAllList(Worker* worker);
 
+  void AddWorkerToShutdownList(Worker* worker);
+  bool RemoveWorkerFromShutdownList(Worker* worker);
+
+  void ReapExitedIdleThreads();
+
   // Worker operations.
-  void SetIdle(Worker* worker);
+  void SetIdleAndReapExited(Worker* worker);
   bool ReleaseIdleWorker(Worker* worker);
 
   Mutex mutex_;
@@ -105,8 +137,9 @@
   uint64_t count_running_;
   uint64_t count_idle_;
 
-  static Monitor* exit_monitor_;  // Used only in testing.
-  static int* exit_count_;        // Used only in testing.
+  Monitor exit_monitor_;
+  Worker* shutting_down_workers_;
+  JoinList* join_list_;
 
   DISALLOW_COPY_AND_ASSIGN(ThreadPool);
 };
diff --git a/runtime/vm/thread_pool_test.cc b/runtime/vm/thread_pool_test.cc
index 35a6127..48d2125 100644
--- a/runtime/vm/thread_pool_test.cc
+++ b/runtime/vm/thread_pool_test.cc
@@ -12,18 +12,6 @@
 DECLARE_FLAG(int, worker_timeout_millis);
 
 
-class ThreadPoolTestPeer {
- public:
-  // When the pool has an exit monitor, workers notify a monitor just
-  // before they exit.  This is only used in tests to make sure that
-  // Shutdown works.
-  static void SetExitMonitor(Monitor* exit_monitor, int* exit_count) {
-    ThreadPool::exit_monitor_ = exit_monitor;
-    ThreadPool::exit_count_ = exit_count;
-  }
-};
-
-
 UNIT_TEST_CASE(ThreadPool_Create) {
   ThreadPool thread_pool;
 }
@@ -88,40 +76,73 @@
 
 class SleepTask : public ThreadPool::Task {
  public:
-  explicit SleepTask(int millis)
-      : millis_(millis) {
+  SleepTask(Monitor* sync, int* started_count, int* slept_count, int millis)
+      : sync_(sync),
+        started_count_(started_count),
+        slept_count_(slept_count),
+        millis_(millis) {
   }
 
   virtual void Run() {
+    {
+      MonitorLocker ml(sync_);
+      *started_count_ = *started_count_ + 1;
+      ml.Notify();
+    }
+    // Sleep so we can be sure the ThreadPool destructor blocks until we're
+    // done.
     OS::Sleep(millis_);
+    {
+      MonitorLocker ml(sync_);
+      *slept_count_ = *slept_count_ + 1;
+      // No notification here. The main thread is blocked in ThreadPool
+      // shutdown waiting for this thread to finish.
+    }
   }
 
  private:
+  Monitor* sync_;
+  int* started_count_;
+  int* slept_count_;
   int millis_;
 };
 
 
 UNIT_TEST_CASE(ThreadPool_WorkerShutdown) {
-  Monitor exit_sync;
-  int exit_count = 0;
-  MonitorLocker ml(&exit_sync);
+  const int kTaskCount = 10;
+  Monitor sync;
+  int slept_count = 0;
+  int started_count = 0;
 
   // Set up the ThreadPool so that workers notify before they exit.
   ThreadPool* thread_pool = new ThreadPool();
-  ThreadPoolTestPeer::SetExitMonitor(&exit_sync, &exit_count);
 
   // Run a single task.
-  thread_pool->Run(new SleepTask(2));
+  for (int i = 0; i < kTaskCount; i++) {
+    thread_pool->Run(new SleepTask(&sync, &started_count, &slept_count, 2));
+  }
 
-  // Kill the thread pool.
+  {
+    // Wait for everybody to start.
+    MonitorLocker ml(&sync);
+    while (started_count < kTaskCount) {
+      ml.Wait();
+    }
+  }
+
+  // Kill the thread pool while the workers are sleeping.
   delete thread_pool;
   thread_pool = NULL;
 
-  // Wait for the workers to terminate.
-  while (exit_count == 0) {
-    ml.Wait();
+  int final_count = 0;
+  {
+    MonitorLocker ml(&sync);
+    final_count = slept_count;
   }
-  EXPECT_EQ(1, exit_count);
+
+  // We should have waited for all the workers to finish, so they all should
+  // have had a chance to increment slept_count.
+  EXPECT_EQ(kTaskCount, final_count);
 }
 
 
@@ -172,12 +193,11 @@
 
     // Spawn 0-2 children.
     if (todo_ > 0) {
-      pool_->Run(
-          new SpawnTask(pool_, sync_, todo_ - child_todo, total_, done_));
+      pool_->Run(new SpawnTask(
+          pool_, sync_, todo_ - child_todo, total_, done_));
     }
     if (todo_ > 1) {
-      pool_->Run(
-          new SpawnTask(pool_, sync_, child_todo, total_, done_));
+      pool_->Run(new SpawnTask(pool_, sync_, child_todo, total_, done_));
     }
 
     {
@@ -214,5 +234,4 @@
   EXPECT_EQ(kTotalTasks, done);
 }
 
-
 }  // namespace dart
diff --git a/runtime/vm/thread_registry.cc b/runtime/vm/thread_registry.cc
index d4ef68d..3648bff 100644
--- a/runtime/vm/thread_registry.cc
+++ b/runtime/vm/thread_registry.cc
@@ -10,23 +10,7 @@
 namespace dart {
 
 ThreadRegistry::~ThreadRegistry() {
-  {
-    // Each thread that is scheduled in this isolate may have a cached timeline
-    // block. Mark these timeline blocks as finished.
-    MonitorLocker ml(monitor_);
-    TimelineEventRecorder* recorder = Timeline::recorder();
-    if (recorder != NULL) {
-      MutexLocker recorder_lock(&recorder->lock_);
-      for (intptr_t i = 0; i < entries_.length(); i++) {
-        // NOTE: It is only safe to access |entry.state| here.
-        const Entry& entry = entries_.At(i);
-        if (entry.state.timeline_block != NULL) {
-          entry.state.timeline_block->Finish();
-        }
-      }
-    }
-  }
-
+  CloseAllTimelineBlocks();
   // Delete monitor.
   delete monitor_;
 }
@@ -83,6 +67,15 @@
   if (found_index < 0) {
     return;
   }
+  {
+    TimelineEventRecorder* recorder = Timeline::recorder();
+    if (recorder != NULL) {
+      MutexLocker recorder_lock(&recorder->lock_);
+      // Cleanup entry.
+      Entry& entry_to_remove = entries_[found_index];
+      CloseTimelineBlockLocked(&entry_to_remove);
+    }
+  }
   if (found_index != (length - 1)) {
     // Swap with last entry.
     entries_.Swap(found_index, length - 1);
@@ -91,6 +84,31 @@
 }
 
 
+void ThreadRegistry::CloseAllTimelineBlocks() {
+  // Each thread that is scheduled in this isolate may have a cached timeline
+  // block. Mark these timeline blocks as finished.
+  MonitorLocker ml(monitor_);
+  TimelineEventRecorder* recorder = Timeline::recorder();
+  if (recorder != NULL) {
+    MutexLocker recorder_lock(&recorder->lock_);
+    for (intptr_t i = 0; i < entries_.length(); i++) {
+      // NOTE: It is only safe to access |entry.state| here.
+      Entry& entry = entries_[i];
+      CloseTimelineBlockLocked(&entry);
+    }
+  }
+}
+
+
+void ThreadRegistry::CloseTimelineBlockLocked(Entry* entry) {
+  if ((entry != NULL) && !entry->scheduled &&
+      (entry->state.timeline_block != NULL)) {
+    entry->state.timeline_block->Finish();
+    entry->state.timeline_block = NULL;
+  }
+}
+
+
 ThreadRegistry::EntryIterator::EntryIterator(ThreadRegistry* registry)
     : index_(0),
       registry_(NULL) {
diff --git a/runtime/vm/thread_registry.h b/runtime/vm/thread_registry.h
index cb10626..01f52a3 100644
--- a/runtime/vm/thread_registry.h
+++ b/runtime/vm/thread_registry.h
@@ -142,6 +142,8 @@
 
   void PruneThread(Thread* thread);
 
+  void CloseAllTimelineBlocks();
+
   struct Entry {
     // NOTE: |thread| is deleted automatically when the thread exits.
     // In other words, it is not safe to dereference |thread| unless you are on
@@ -182,6 +184,11 @@
     return NULL;
   }
 
+  // Close the timeline block cache inside entry.
+  // NOTE: Lock should be taken before this function is called.
+  // NOTE: Recorder lock should be taken before this function is called.
+  void CloseTimelineBlockLocked(Entry* entry);
+
   // Note: Lock should be taken before this function is called.
   void CheckSafepointLocked();
 
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index ecdd085..d510d5e 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -8,15 +8,20 @@
 #include "vm/isolate.h"
 #include "vm/json_stream.h"
 #include "vm/lockers.h"
+#include "vm/log.h"
 #include "vm/object.h"
 #include "vm/thread.h"
 #include "vm/timeline.h"
 
 namespace dart {
 
-DEFINE_FLAG(bool, trace_timeline, false, "Trace timeline backend");
 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline");
-
+DEFINE_FLAG(bool, trace_timeline, false,
+            "Trace timeline backend");
+DEFINE_FLAG(bool, trace_timeline_analysis, false,
+            "Trace timeline analysis backend");
+DEFINE_FLAG(bool, timing, false,
+            "Dump isolate timing information from timeline.");
 DEFINE_FLAG(charp, timeline_dir, NULL,
             "Enable all timeline trace streams and output VM global trace "
             "into specified directory.");
@@ -26,7 +31,8 @@
   // Default to ring recorder being enabled.
   const bool use_ring_recorder = true;
   // Some flags require that we use the endless recorder.
-  const bool use_endless_recorder = (FLAG_timeline_dir != NULL);
+  const bool use_endless_recorder =
+      (FLAG_timeline_dir != NULL) || FLAG_timing;
   if (use_endless_recorder) {
     recorder_ = new TimelineEventEndlessRecorder();
   } else if (use_ring_recorder) {
@@ -56,7 +62,7 @@
 
 bool Timeline::EnableStreamByDefault(const char* stream_name) {
   // TODO(johnmccutchan): Allow for command line control over streams.
-  return FLAG_timeline_dir != NULL;
+  return (FLAG_timeline_dir != NULL) || FLAG_timing;
 }
 
 
@@ -410,6 +416,10 @@
 
 TimelineEvent* TimelineEventRecorder::GlobalBlockStartEvent() {
   MutexLocker ml(&lock_);
+  if (FLAG_trace_timeline) {
+    OS::Print("GlobalBlockStartEvent in block %p for thread %" Px "\n",
+              global_block_, OSThread::CurrentCurrentThreadIdAsIntPtr());
+  }
   if ((global_block_ != NULL) && global_block_->IsFull()) {
     // Global block is full.
     global_block_->Finish();
@@ -418,6 +428,7 @@
   if (global_block_ == NULL) {
     // Allocate a new block.
     global_block_ = GetNewBlockLocked(NULL);
+    ASSERT(global_block_ != NULL);
   }
   if (global_block_ != NULL) {
     ASSERT(!global_block_->IsFull());
@@ -441,11 +452,9 @@
   TimelineEventFilter filter;
   PrintJSON(&js, &filter);
 
-  const char* format = "%s/dart-timeline-%" Pd ".json";
   intptr_t pid = OS::ProcessId();
-  intptr_t len = OS::SNPrint(NULL, 0, format, directory, pid);
-  char* filename = reinterpret_cast<char*>(malloc(len + 1));
-  OS::SNPrint(filename, len + 1, format, directory, pid);
+  char* filename = OS::SCreate(NULL,
+      "%s/dart-timeline-%" Pd ".json", directory, pid);
   void* file = (*file_open)(filename, true);
   if (file == NULL) {
     OS::Print("Failed to write timeline file: %s\n", filename);
@@ -632,7 +641,6 @@
 TimelineEventEndlessRecorder::TimelineEventEndlessRecorder()
     : head_(NULL),
       block_index_(0) {
-  GetNewBlock();
 }
 
 
@@ -670,6 +678,14 @@
   block->set_next(head_);
   block->Open(isolate);
   head_ = block;
+  if (FLAG_trace_timeline) {
+    if (isolate != NULL) {
+      OS::Print("Created new isolate block %p for %s\n",
+                block, isolate->name());
+    } else {
+      OS::Print("Created new global block %p\n", block);
+    }
+  }
   return head_;
 }
 
@@ -725,6 +741,10 @@
 
 TimelineEvent* TimelineEventBlock::StartEvent() {
   ASSERT(!IsFull());
+  if (FLAG_trace_timeline) {
+    OS::Print("StartEvent in block %p for thread %" Px "\n",
+              this, OSThread::CurrentCurrentThreadIdAsIntPtr());
+  }
   return &events_[length_++];
 }
 
@@ -785,6 +805,9 @@
 
 
 void TimelineEventBlock::Finish() {
+  if (FLAG_trace_timeline) {
+    OS::Print("Finish block %p\n", this);
+  }
   open_ = false;
 }
 
diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h
index 983d3fc..3c771292 100644
--- a/runtime/vm/timeline.h
+++ b/runtime/vm/timeline.h
@@ -396,6 +396,7 @@
   void Open(Isolate* isolate);
   void Finish();
 
+  friend class Thread;
   friend class ThreadRegistry;
   friend class TimelineEventRecorder;
   friend class TimelineEventRingRecorder;
diff --git a/runtime/vm/timeline_analysis.cc b/runtime/vm/timeline_analysis.cc
index 08deb77..1ca8442 100644
--- a/runtime/vm/timeline_analysis.cc
+++ b/runtime/vm/timeline_analysis.cc
@@ -10,7 +10,8 @@
 
 namespace dart {
 
-DEFINE_FLAG(bool, trace_timeline_analysis, false, "Trace timeline analysis");
+DECLARE_FLAG(bool, trace_timeline_analysis);
+DECLARE_FLAG(bool, timing);
 
 TimelineAnalysisThread::TimelineAnalysisThread(ThreadId id)
     : id_(id) {
@@ -39,7 +40,7 @@
 void TimelineAnalysisThread::Finalize() {
   blocks_.Sort(CompareBlocksLowerTimeBound);
   if (FLAG_trace_timeline_analysis) {
-    ISL_Print("Thread %" Px " has %" Pd " blocks\n",
+    THR_Print("Thread %" Px " has %" Pd " blocks\n",
               OSThread::ThreadIdToIntPtr(id_),
               blocks_.length());
   }
@@ -161,9 +162,13 @@
       // Skip empty blocks.
       continue;
     }
+    if (block->isolate() != isolate_) {
+      // Skip blocks for other isolates.
+      continue;
+    }
     if (!block->CheckBlock()) {
       if (FLAG_trace_timeline_analysis) {
-        ISL_Print("DiscoverThreads block %" Pd " "
+        THR_Print("DiscoverThreads block %" Pd " "
                   "violates invariants.\n", block->block_index());
       }
       SetError("Block %" Pd " violates invariants. See "
@@ -226,6 +231,20 @@
 }
 
 
+void TimelineLabelPauseInfo::Aggregate(
+    const TimelineLabelPauseInfo* thread_pause_info) {
+  ASSERT(thread_pause_info != NULL);
+  inclusive_micros_ += thread_pause_info->inclusive_micros_;
+  exclusive_micros_ += thread_pause_info->exclusive_micros_;
+  if (max_inclusive_micros_ < thread_pause_info->max_inclusive_micros_) {
+    max_inclusive_micros_ = thread_pause_info->max_inclusive_micros_;
+  }
+  if (max_exclusive_micros_ < thread_pause_info->max_exclusive_micros_) {
+    max_exclusive_micros_ = thread_pause_info->max_exclusive_micros_;
+  }
+}
+
+
 TimelinePauses::TimelinePauses(Zone* zone,
                                Isolate* isolate,
                                TimelineEventRecorder* recorder)
@@ -300,7 +319,7 @@
 
   TimelineAnalysisThreadEventIterator it(thread);
   if (FLAG_trace_timeline_analysis) {
-    ISL_Print(">>> TimelinePauses::ProcessThread %" Px "\n",
+    THR_Print(">>> TimelinePauses::ProcessThread %" Px "\n",
               OSThread::ThreadIdToIntPtr(thread->id()));
   }
   intptr_t event_count = 0;
@@ -322,7 +341,7 @@
   // Pop remaining stack.
   PopFinished(kMaxInt64);
   if (FLAG_trace_timeline_analysis) {
-    ISL_Print("<<< TimelinePauses::ProcessThread %" Px " had %" Pd " events\n",
+    THR_Print("<<< TimelinePauses::ProcessThread %" Px " had %" Pd " events\n",
               OSThread::ThreadIdToIntPtr(thread->id()),
               event_count);
   }
@@ -350,7 +369,7 @@
       // Top of stack completes before |start|.
       stack_.RemoveLast();
       if (FLAG_trace_timeline_analysis) {
-        ISL_Print("Popping %s (%" Pd64 " <= %" Pd64 ")\n",
+        THR_Print("Popping %s (%" Pd64 " <= %" Pd64 ")\n",
                   top.event->label(),
                   top.event->TimeEnd(),
                   start);
@@ -367,7 +386,7 @@
   ASSERT(pause_info != NULL);
   // |pause_info| will be running for |event->TimeDuration()|.
   if (FLAG_trace_timeline_analysis) {
-    ISL_Print("Pushing %s %" Pd64 " us\n",
+    THR_Print("Pushing %s %" Pd64 " us\n",
               pause_info->name(),
               event->TimeDuration());
   }
@@ -386,7 +405,7 @@
 }
 
 
-bool TimelinePauses::IsLabelOnStack(const char* label) {
+bool TimelinePauses::IsLabelOnStack(const char* label) const {
   ASSERT(label != NULL);
   for (intptr_t i = 0; i < stack_.length(); i++) {
     const StackItem& slot = stack_.At(i);
@@ -422,4 +441,95 @@
   return pause_info;
 }
 
+
+TimelinePauseTrace::TimelinePauseTrace() {
+}
+
+
+TimelinePauseTrace::~TimelinePauseTrace() {
+}
+
+
+void TimelinePauseTrace::Print() {
+  Thread* thread = Thread::Current();
+  ASSERT(thread != NULL);
+  Isolate* isolate = thread->isolate();
+  ASSERT(isolate != NULL);
+  Zone* zone = thread->zone();
+  ASSERT(zone != NULL);
+  TimelineEventRecorder* recorder = Timeline::recorder();
+  ASSERT(recorder != NULL);
+  TimelinePauses pauses(zone, isolate, recorder);
+  pauses.Setup();
+
+  THR_Print("Timing for isolate %s (from %" Pd " threads)\n",
+            isolate->name(),
+            pauses.NumThreads());
+  THR_Print("\n");
+  for (intptr_t t_idx = 0; t_idx < pauses.NumThreads(); t_idx++) {
+    TimelineAnalysisThread* tat = pauses.At(t_idx);
+    ASSERT(tat != NULL);
+    pauses.CalculatePauseTimesForThread(tat->id());
+    THR_Print("Thread %" Pd " (%" Px "):\n",
+              t_idx,
+              OSThread::ThreadIdToIntPtr(tat->id()));
+    for (intptr_t j = 0; j < pauses.NumPauseInfos(); j++) {
+      const TimelineLabelPauseInfo* pause_info = pauses.PauseInfoAt(j);
+      ASSERT(pause_info != NULL);
+      Aggregate(pause_info);
+      PrintPauseInfo(pause_info);
+    }
+    THR_Print("\n");
+  }
+  THR_Print("Totals:\n");
+  for (intptr_t i = 0; i < isolate_labels_.length(); i++) {
+    TimelineLabelPauseInfo* pause_info = isolate_labels_.At(i);
+    ASSERT(pause_info != NULL);
+    PrintPauseInfo(pause_info);
+  }
+  THR_Print("\n");
+}
+
+
+TimelineLabelPauseInfo* TimelinePauseTrace::GetOrAddLabelPauseInfo(
+    const char* name) {
+  ASSERT(name != NULL);
+  // Linear lookup because we expect N (# of labels in an isolate) to be small.
+  for (intptr_t i = 0; i < isolate_labels_.length(); i++) {
+    TimelineLabelPauseInfo* label = isolate_labels_.At(i);
+    if (strcmp(label->name(), name) == 0) {
+      return label;
+    }
+  }
+  // New label.
+  TimelineLabelPauseInfo* pause_info = new TimelineLabelPauseInfo(name);
+  isolate_labels_.Add(pause_info);
+  return pause_info;
+}
+
+
+void TimelinePauseTrace::Aggregate(
+    const TimelineLabelPauseInfo* thread_pause_info) {
+  ASSERT(thread_pause_info != NULL);
+  TimelineLabelPauseInfo* isolate_pause_info =
+      GetOrAddLabelPauseInfo(thread_pause_info->name());
+  ASSERT(isolate_pause_info != NULL);
+  isolate_pause_info->Aggregate(thread_pause_info);
+}
+
+
+void TimelinePauseTrace::PrintPauseInfo(
+    const TimelineLabelPauseInfo* pause_info) {
+  ASSERT(pause_info != NULL);
+  THR_Print("%s : ", pause_info->name());
+  THR_Print("%.3f ms total on stack; ",
+            MicrosecondsToMilliseconds(pause_info->inclusive_micros()));
+  THR_Print("%.3f ms total executing; ",
+            MicrosecondsToMilliseconds(pause_info->exclusive_micros()));
+  THR_Print("%.3f ms max on stack; ",
+            MicrosecondsToMilliseconds(pause_info->max_inclusive_micros()));
+  THR_Print("%.3f ms max executing.\n",
+            MicrosecondsToMilliseconds(pause_info->max_exclusive_micros()));
+}
+
 }  // namespace dart
diff --git a/runtime/vm/timeline_analysis.h b/runtime/vm/timeline_analysis.h
index 5f5049b..b49d821 100644
--- a/runtime/vm/timeline_analysis.h
+++ b/runtime/vm/timeline_analysis.h
@@ -150,6 +150,8 @@
     ASSERT(exclusive_micros_ >= 0);
   }
 
+  void Aggregate(const TimelineLabelPauseInfo* thread_pause_info);
+
   const char* name_;
   int64_t inclusive_micros_;
   int64_t exclusive_micros_;
@@ -157,6 +159,7 @@
   int64_t max_exclusive_micros_;
 
   friend class TimelinePauses;
+  friend class TimelinePauseTrace;
 };
 
 
@@ -177,6 +180,14 @@
   int64_t MaxInclusiveTime(const char* name) const;
   int64_t MaxExclusiveTime(const char* name) const;
 
+  intptr_t NumPauseInfos() const {
+    return labels_.length();
+  }
+
+  const TimelineLabelPauseInfo* PauseInfoAt(intptr_t i) const {
+    return labels_.At(i);
+  }
+
  private:
   struct StackItem {
     TimelineEvent* event;
@@ -188,7 +199,7 @@
   bool CheckStack(TimelineEvent* event);
   void PopFinished(int64_t start);
   void Push(TimelineEvent* event);
-  bool IsLabelOnStack(const char* label);
+  bool IsLabelOnStack(const char* label) const;
   intptr_t StackDepth() const;
   StackItem& GetStackTop();
   TimelineLabelPauseInfo* GetOrAddLabelPauseInfo(const char* name);
@@ -197,6 +208,22 @@
   ZoneGrowableArray<TimelineLabelPauseInfo*> labels_;
 };
 
+
+class TimelinePauseTrace : public ValueObject {
+ public:
+  TimelinePauseTrace();
+  ~TimelinePauseTrace();
+
+  void Print();
+
+ private:
+  TimelineLabelPauseInfo* GetOrAddLabelPauseInfo(const char* name);
+  void Aggregate(const TimelineLabelPauseInfo* thread_pause_info);
+  void PrintPauseInfo(const TimelineLabelPauseInfo* pause_info);
+
+  ZoneGrowableArray<TimelineLabelPauseInfo*> isolate_labels_;
+};
+
 }  // namespace dart
 
 #endif  // VM_TIMELINE_ANALYSIS_H_
diff --git a/runtime/vm/unicode.cc b/runtime/vm/unicode.cc
index 615e87b..8e1649e 100644
--- a/runtime/vm/unicode.cc
+++ b/runtime/vm/unicode.cc
@@ -102,8 +102,7 @@
       if (!((is_malformed == false) &&
             (j == num_trail_bytes) &&
             !Utf::IsOutOfRange(ch) &&
-            !IsNonShortestForm(ch, j) &&
-            !Utf16::IsSurrogate(ch))) {
+            !IsNonShortestForm(ch, j))) {
         return false;
       }
     }
@@ -201,8 +200,7 @@
     if (!((is_malformed == false) &&
           (i == num_trail_bytes) &&
           !Utf::IsOutOfRange(ch) &&
-          !IsNonShortestForm(ch, i) &&
-          !Utf16::IsSurrogate(ch))) {
+          !IsNonShortestForm(ch, i))) {
       *dst = -1;
       return 0;
     }
diff --git a/runtime/vm/unicode_test.cc b/runtime/vm/unicode_test.cc
index 582a2a6..36fdf85 100644
--- a/runtime/vm/unicode_test.cc
+++ b/runtime/vm/unicode_test.cc
@@ -832,6 +832,8 @@
   }
 
   // 5.1 - Single UTF-16 surrogates
+  // UTF-8 suggests single surrogates are invalid, but both JS and
+  // Dart allow them and make use of them.
 
   // 5.1.1 - U+D800 = ed a0 80 = "\xED\xA0\x80"
   {
@@ -840,8 +842,8 @@
     int32_t dst[ARRAY_SIZE(expected)];
     memset(dst, 0, sizeof(dst));
     bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
-    EXPECT(!is_valid);
-    EXPECT(memcmp(expected, dst, sizeof(expected)));
+    EXPECT(is_valid);
+    EXPECT(!memcmp(expected, dst, sizeof(expected)));
   }
 
   // 5.1.2 - U+DB7F = ed ad bf = "\xED\xAD\xBF"
@@ -851,8 +853,8 @@
     int32_t dst[ARRAY_SIZE(expected)];
     memset(dst, 0, sizeof(dst));
     bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
-    EXPECT(!is_valid);
-    EXPECT(memcmp(expected, dst, sizeof(expected)));
+    EXPECT(is_valid);
+    EXPECT(!memcmp(expected, dst, sizeof(expected)));
   }
 
   // 5.1.3 - U+DB80 = ed ae 80 = "\xED\xAE\x80"
@@ -862,8 +864,8 @@
     int32_t dst[ARRAY_SIZE(expected)];
     memset(dst, 0, sizeof(dst));
     bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
-    EXPECT(!is_valid);
-    EXPECT(memcmp(expected, dst, sizeof(expected)));
+    EXPECT(is_valid);
+    EXPECT(!memcmp(expected, dst, sizeof(expected)));
   }
 
   // 5.1.4 - U+DBFF = ed af bf = "\xED\xAF\xBF"
@@ -873,8 +875,8 @@
     int32_t dst[ARRAY_SIZE(expected)];
     memset(dst, 0, sizeof(dst));
     bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
-    EXPECT(!is_valid);
-    EXPECT(memcmp(expected, dst, sizeof(expected)));
+    EXPECT(is_valid);
+    EXPECT(!memcmp(expected, dst, sizeof(expected)));
   }
 
   // 5.1.5 - U+DC00 = ed b0 80 = "\xED\xB0\x80"
@@ -884,8 +886,8 @@
     int32_t dst[ARRAY_SIZE(expected)];
     memset(dst, 0, sizeof(dst));
     bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
-    EXPECT(!is_valid);
-    EXPECT(memcmp(expected, dst, sizeof(expected)));
+    EXPECT(is_valid);
+    EXPECT(!memcmp(expected, dst, sizeof(expected)));
   }
 
   // 5.1.6 - U+DF80 = ed be 80 = "\xED\xBE\x80"
@@ -895,8 +897,8 @@
     int32_t dst[ARRAY_SIZE(expected)];
     memset(dst, 0, sizeof(dst));
     bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
-    EXPECT(!is_valid);
-    EXPECT(memcmp(expected, dst, sizeof(expected)));
+    EXPECT(is_valid);
+    EXPECT(!memcmp(expected, dst, sizeof(expected)));
   }
 
   // 5.1.7 - U+DFFF = ed bf bf = "\xED\xBF\xBF"
@@ -906,11 +908,16 @@
     int32_t dst[ARRAY_SIZE(expected)];
     memset(dst, 0, sizeof(dst));
     bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
-    EXPECT(!is_valid);
-    EXPECT(memcmp(expected, dst, sizeof(expected)));
+    EXPECT(is_valid);
+    EXPECT(!memcmp(expected, dst, sizeof(expected)));
   }
 
   // 5.2 Paired UTF-16 surrogates
+  // Also not a valid string, but accepted in Dart, even if it doesn't make
+  // sense. e.g.
+  // var s =  new String.fromCharCodes([0xd800, 0xDC00]);
+  // print(s.runes);  // (65536) (0x10000)
+  // print(s.codeUnits); // [55296, 56320]
 
   // 5.2.1 - U+D800 U+DC00 = ed a0 80 ed b0 80 = "\xED\xA0\x80\xED\xB0\x80"
   {
@@ -919,8 +926,8 @@
     int32_t dst[ARRAY_SIZE(expected)];
     memset(dst, 0, sizeof(dst));
     bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
-    EXPECT(!is_valid);
-    EXPECT(memcmp(expected, dst, sizeof(expected)));
+    EXPECT(is_valid);
+    EXPECT(!memcmp(expected, dst, sizeof(expected)));
   }
 
   // 5.2.2 - U+D800 U+DFFF = ed a0 80 ed bf bf = "\xED\xA0\x80\xED\xBF\xBF"
@@ -930,8 +937,8 @@
     int32_t dst[ARRAY_SIZE(expected)];
     memset(dst, 0, sizeof(dst));
     bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
-    EXPECT(!is_valid);
-    EXPECT(memcmp(expected, dst, sizeof(expected)));
+    EXPECT(is_valid);
+    EXPECT(!memcmp(expected, dst, sizeof(expected)));
   }
 
   // 5.2.3 - U+DB7F U+DC00 = ed a0 80 ed bf bf = "\xED\xAD\xBF\xED\xB0\x80"
@@ -941,8 +948,8 @@
     int32_t dst[ARRAY_SIZE(expected)];
     memset(dst, 0, sizeof(dst));
     bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
-    EXPECT(!is_valid);
-    EXPECT(memcmp(expected, dst, sizeof(expected)));
+    EXPECT(is_valid);
+    EXPECT(!memcmp(expected, dst, sizeof(expected)));
   }
 
   // 5.2.4 - U+DB7F U+DFFF = ed ad bf ed bf bf = "\xED\xAD\xBF\xED\xBF\xBF"
@@ -952,8 +959,8 @@
     int32_t dst[ARRAY_SIZE(expected)];
     memset(dst, 0, sizeof(dst));
     bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
-    EXPECT(!is_valid);
-    EXPECT(memcmp(expected, dst, sizeof(expected)));
+    EXPECT(is_valid);
+    EXPECT(!memcmp(expected, dst, sizeof(expected)));
   }
 
   // 5.2.5 - U+DB80 U+DC00 = ed ae 80 ed b0 80 = "\xED\xAE\x80\xED\xB0\x80"
@@ -963,8 +970,8 @@
     int32_t dst[ARRAY_SIZE(expected)];
     memset(dst, 0, sizeof(dst));
     bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
-    EXPECT(!is_valid);
-    EXPECT(memcmp(expected, dst, sizeof(expected)));
+    EXPECT(is_valid);
+    EXPECT(!memcmp(expected, dst, sizeof(expected)));
   }
 
   // 5.2.6 - U+DB80 U+DFFF = ed ae 80 ed bf bf = "\xED\xAE\x80\xED\xBF\xBF"
@@ -974,8 +981,8 @@
     int32_t dst[ARRAY_SIZE(expected)];
     memset(dst, 0, sizeof(dst));
     bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
-    EXPECT(!is_valid);
-    EXPECT(memcmp(expected, dst, sizeof(expected)));
+    EXPECT(is_valid);
+    EXPECT(!memcmp(expected, dst, sizeof(expected)));
   }
 
   // 5.2.7 - U+DBFF U+DC00 = ed af bf ed b0 80 = "\xED\xAF\xBF\xED\xB0\x80"
@@ -985,8 +992,8 @@
     int32_t dst[ARRAY_SIZE(expected)];
     memset(dst, 0, sizeof(dst));
     bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
-    EXPECT(!is_valid);
-    EXPECT(memcmp(expected, dst, sizeof(expected)));
+    EXPECT(is_valid);
+    EXPECT(!memcmp(expected, dst, sizeof(expected)));
   }
 
   // 5.2.8 - U+DBFF U+DFFF = ed af bf ed bf bf = "\xED\xAF\xBF\xED\xBF\xBF"
@@ -996,8 +1003,8 @@
     int32_t dst[ARRAY_SIZE(expected)];
     memset(dst, 0, sizeof(dst));
     bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
-    EXPECT(!is_valid);
-    EXPECT(memcmp(expected, dst, sizeof(expected)));
+    EXPECT(is_valid);
+    EXPECT(!memcmp(expected, dst, sizeof(expected)));
   }
 
   // 5.3 - Other illegal code positions
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index 421bbdc..9694527 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -282,4 +282,24 @@
 }
 
 
+void ElideJSONSubstring(const char* prefix, const char* in, char* out) {
+  const char* pos = strstr(in, prefix);
+  while (pos != NULL) {
+    // Copy up to pos into the output buffer.
+    while (in < pos) {
+      *out++ = *in++;
+    }
+
+    // Skip to the close quote.
+    in += strcspn(in, "\"");
+    pos = strstr(in, prefix);
+  }
+  // Copy the remainder of in to out.
+  while (*in != '\0') {
+    *out++ = *in++;
+  }
+  *out = '\0';
+}
+
+
 }  // namespace dart
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index 1edeb15..d4853e4 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -521,6 +521,24 @@
     }                                                                          \
   } while (0)
 
+
+// Elide a substring which starts with some prefix and ends with a ".
+//
+// This is used to remove non-deterministic or fragile substrings from
+// JSON output.
+//
+// For example:
+//
+//    prefix = "classes"
+//    in = "\"id\":\"classes/46\""
+//
+// Yields:
+//
+//    out = "\"id\":\"\""
+//
+void ElideJSONSubstring(const char* prefix, const char* in, char* out);
+
+
 }  // namespace dart
 
 #endif  // VM_UNIT_TEST_H_
diff --git a/runtime/vm/verified_memory_test.cc b/runtime/vm/verified_memory_test.cc
index 6d97216..21978e7 100644
--- a/runtime/vm/verified_memory_test.cc
+++ b/runtime/vm/verified_memory_test.cc
@@ -15,12 +15,22 @@
 }
 
 
+void Shutdown() {
+#if defined(DEBUG)
+  // We must reset this to false to avoid checking some assumptions in
+  // VM shutdown that are left violated by these tests.
+  FLAG_verified_mem = false;
+#endif
+}
+
+
 UNIT_TEST_CASE(VerifiedMemoryReserve) {
   Init();
   const intptr_t kReservationSize = 64 * KB;
   VirtualMemory* vm = VerifiedMemory::Reserve(kReservationSize);
   EXPECT_EQ(kReservationSize, vm->size());
   delete vm;
+  Shutdown();
 }
 
 
@@ -31,6 +41,7 @@
   EXPECT_EQ(kReservationSize, vm->size());
   vm->Commit(false);
   delete vm;
+  Shutdown();
 }
 
 
@@ -53,6 +64,7 @@
   *unverified = 123;
   VerifiedMemory::Verify(reinterpret_cast<uword>(addr), 3 * sizeof(double));
   delete vm;
+  Shutdown();
 }
 
 
@@ -72,6 +84,7 @@
   VerifiedMemory::Accept(reinterpret_cast<uword>(addr), 2 * sizeof(double));
   VerifiedMemory::Verify(reinterpret_cast<uword>(addr), 3 * sizeof(double));
   delete vm;
+  Shutdown();
 }
 
 
@@ -86,6 +99,7 @@
   double* addr = reinterpret_cast<double*>(vm->address());
   addr[0] = 0.5;  // Forget to use Write.
   VerifiedMemory::Write(&addr[0], 1.5);
+  Shutdown();
 }
 
 
@@ -101,6 +115,7 @@
   addr[1] = 3.5;  // Forget to use Write.
   VerifiedMemory::Write(&addr[2], 2.5);
   VerifiedMemory::Verify(reinterpret_cast<uword>(addr), 3 * sizeof(double));
+  Shutdown();
 }
 
 }  // namespace dart
diff --git a/runtime/vm/version_in.cc b/runtime/vm/version_in.cc
index 34d7fc6..d196310 100644
--- a/runtime/vm/version_in.cc
+++ b/runtime/vm/version_in.cc
@@ -14,14 +14,9 @@
 
 const char* Version::String() {
   if (formatted_version == NULL) {
-    const char* format = "%s on \"%s_%s\"";
     const char* os = OS::Name();
     const char* arch = CPU::Id();
-
-    intptr_t len = OS::SNPrint(NULL, 0, format, str_, os, arch);
-    char* buffer = reinterpret_cast<char*>(malloc(len + 1));
-    OS::SNPrint(buffer, (len + 1), format, str_, os, arch);
-    formatted_version = buffer;
+    formatted_version = OS::SCreate(NULL, "%s on \"%s_%s\"", str_, os, arch);
   }
   return formatted_version;
 }
diff --git a/runtime/vm/zone.cc b/runtime/vm/zone.cc
index c271991..ea42f49 100644
--- a/runtime/vm/zone.cc
+++ b/runtime/vm/zone.cc
@@ -203,24 +203,14 @@
 char* Zone::PrintToString(const char* format, ...) {
   va_list args;
   va_start(args, format);
-  return VPrint(format, args);
+  char* buffer = OS::VSCreate(this, format, args);
+  va_end(args);
+  return buffer;
 }
 
 
 char* Zone::VPrint(const char* format, va_list args) {
-  // Measure.
-  va_list measure_args;
-  va_copy(measure_args, args);
-  intptr_t len = OS::VSNPrint(NULL, 0, format, measure_args);
-  va_end(measure_args);
-
-  // Print.
-  char* buffer = Alloc<char>(len + 1);
-  va_list print_args;
-  va_copy(print_args, args);
-  OS::VSNPrint(buffer, (len + 1), format, print_args);
-  va_end(print_args);
-  return buffer;
+  return OS::VSCreate(this, format, args);
 }
 
 
diff --git a/runtime/vm/zone.h b/runtime/vm/zone.h
index 4850e5e..361e6e2 100644
--- a/runtime/vm/zone.h
+++ b/runtime/vm/zone.h
@@ -46,9 +46,12 @@
   // Make a copy of the string in the zone allocated area.
   char* MakeCopyOfString(const char* str);
 
+  // TODO(zra): Remove these calls and replace them with calls to OS::SCreate
+  // and OS::VSCreate.
+  // These calls are deprecated. Do not add further calls to these functions.
+  // instead use OS::SCreate and OS::VSCreate.
   // Make a zone-allocated string based on printf format and args.
   char* PrintToString(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
-
   char* VPrint(const char* format, va_list args);
 
   // Compute the total size of this zone. This includes wasted space that is
diff --git a/sdk/lib/_internal/js_runtime/lib/core_patch.dart b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
index 3c639dc..7d6ad7c 100644
--- a/sdk/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
@@ -18,7 +18,8 @@
                               stringJoinUnchecked,
                               objectHashCode,
                               Closure,
-                              readHttp;
+                              readHttp,
+                              JsLinkedHashMap;
 
 import 'dart:_foreign_helper' show JS;
 
@@ -311,6 +312,9 @@
 class Map<K, V> {
   @patch
   factory Map.unmodifiable(Map other) = ConstantMap<K, V>.from;
+
+  @patch
+  factory Map() = JsLinkedHashMap<K, V>.es6;
 }
 
 @patch
diff --git a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
index 15cafa8..8349d14 100644
--- a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
@@ -4,7 +4,7 @@
 
 // Patch file for dart:developer library.
 
-import 'dart:_js_helper' show patch;
+import 'dart:_js_helper' show patch, ForceInline;
 import 'dart:_foreign_helper' show JS;
 
 @patch
diff --git a/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart b/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
index eb68107..70eda5b 100644
--- a/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
@@ -62,9 +62,15 @@
   @patch
   static Future<Isolate> spawnUri(
       Uri uri, List<String> args, var message,
-      {bool paused: false, bool checked, Uri packageRoot, bool errorsAreFatal,
-       SendPort onExit, SendPort onError}) {
+      {bool paused: false,
+       bool checked,
+       Uri packageRoot,
+       Map<String, Uri> packages,
+       bool errorsAreFatal,
+       SendPort onExit,
+       SendPort onError}) {
     if (packageRoot != null) throw new UnimplementedError("packageRoot");
+    if (packages != null) throw new UnimplementedError("packages");
     bool forcePause = (errorsAreFatal != null) ||
                       (onExit != null) ||
                       (onError != null);
@@ -78,6 +84,7 @@
       } else if (args != null) {
         throw new ArgumentError("Args must be a list of Strings $args");
       }
+      // TODO: Handle [packageRoot]/[packages] somehow, possibly by throwing.
       // TODO: Consider passing the errorsAreFatal/onExit/onError values
       //       as arguments to the internal spawnUri instead of setting
       //       them after the isolate has been created.
diff --git a/sdk/lib/_internal/js_runtime/lib/js_array.dart b/sdk/lib/_internal/js_runtime/lib/js_array.dart
index 51a8fb4..5495a6c 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_array.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_array.dart
@@ -150,7 +150,7 @@
 
   E removeLast() {
     checkGrowable('removeLast');
-    if (length == 0) throw new RangeError.value(-1);
+    if (length == 0) throw diagnoseIndexError(this, -1);
     return JS('var', r'#.pop()', this);
   }
 
@@ -351,14 +351,14 @@
     checkNull(start); // TODO(ahe): This is not specified but co19 tests it.
     if (start is !int) throw argumentErrorValue(start);
     if (start < 0 || start > length) {
-      throw new RangeError.range(start, 0, length);
+      throw new RangeError.range(start, 0, length, "start");
     }
     if (end == null) {
       end = length;
     } else {
       if (end is !int) throw argumentErrorValue(end);
       if (end < start || end > length) {
-        throw new RangeError.range(end, start, length);
+        throw new RangeError.range(end, start, length, "end");
       }
     }
     if (start == end) return <E>[];
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index 91049cd..b4ab91c 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -1566,7 +1566,7 @@
  */
 @NoInline()
 Error diagnoseIndexError(indexable, index) {
-  if (index is !int) return new ArgumentError.value(index, 'index');
+  if (index is! int) return new ArgumentError.value(index, 'index');
   int length = indexable.length;
   // The following returns the same error that would be thrown by calling
   // [RangeError.checkValidIndex] with no optional parameters provided.
@@ -1577,6 +1577,29 @@
   return new RangeError.value(index, 'index');
 }
 
+/**
+ * Diagnoses a range error. Returns the ArgumentError or RangeError that
+ * describes the problem.
+ */
+@NoInline()
+Error diagnoseRangeError(start, end, length) {
+  if (start is! int) {
+    return new ArgumentError.value(start, 'start');
+  }
+  if (start < 0 || start > length) {
+    return new RangeError.range(start, 0, length, 'start');
+  }
+  if (end != null) {
+    if (end is! int) {
+      return new ArgumentError.value(end, 'end');
+    }
+    if (end < start || end > length) {
+      return new RangeError.range(end, start, length, 'end');
+    }
+  }
+  // The above should always match, but if it does not, use the following.
+  return new ArgumentError.value(end, "end");
+}
 
 stringLastIndexOfUnchecked(receiver, element, start)
   => JS('int', r'#.lastIndexOf(#, #)', receiver, element, start);
diff --git a/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart b/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart
index d134c6d..ec50a86 100644
--- a/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart
+++ b/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart
@@ -13,7 +13,7 @@
 import 'dart:_interceptors' show JSIndexable, JSUInt32, JSUInt31;
 import 'dart:_js_helper' show
     Creates, JavaScriptIndexingBehavior, JSName, Native, Null, Returns,
-    diagnoseIndexError;
+    diagnoseIndexError, diagnoseRangeError;
 import 'dart:_foreign_helper' show JS;
 import 'dart:math' as Math;
 
@@ -148,39 +148,10 @@
 
   int get elementSizeInBytes => Float32x4List.BYTES_PER_ELEMENT;
 
-  void _invalidIndex(int index, int length) {
-    if (index < 0 || index >= length) {
-      if (length == this.length) {
-        throw new RangeError.index(index, this);
-      }
-      throw new RangeError.range(index, 0, length - 1);
-    } 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;
-  }
-
   int get length => _storage.length ~/ 4;
 
   Float32x4 operator[](int index) {
-    _checkIndex(index, length);
+    _checkValidIndex(index, this, this.length);
     double _x = _storage[(index * 4) + 0];
     double _y = _storage[(index * 4) + 1];
     double _z = _storage[(index * 4) + 2];
@@ -189,7 +160,7 @@
   }
 
   void operator[]=(int index, Float32x4 value) {
-    _checkIndex(index, length);
+    _checkValidIndex(index, this, this.length);
     _storage[(index * 4) + 0] = value.x;
     _storage[(index * 4) + 1] = value.y;
     _storage[(index * 4) + 2] = value.z;
@@ -197,7 +168,7 @@
   }
 
   List<Float32x4> sublist(int start, [int end]) {
-    end = _checkSublistArguments(start, end, length);
+    end = _checkValidRange(start, end, this.length);
     return new NativeFloat32x4List._externalStorage(
         _storage.sublist(start * 4, end * 4));
   }
@@ -257,40 +228,10 @@
 
   int get elementSizeInBytes => Int32x4List.BYTES_PER_ELEMENT;
 
-  void _invalidIndex(int index, int length) {
-    if (index < 0 || index >= length) {
-      if (length == this.length) {
-        throw new RangeError.index(index, this);
-      }
-      throw new RangeError.range(index, 0, length - 1);
-    } else {
-      throw new ArgumentError('Invalid list index $index');
-    }
-  }
-
-  void _checkIndex(int index, int length) {
-    if (JS('bool', '(# >>> 0 != #)', index, index)
-        || JS('bool', '# >= #', 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;
-  }
-
   int get length => _storage.length ~/ 4;
 
   Int32x4 operator[](int index) {
-    _checkIndex(index, length);
+    _checkValidIndex(index, this, this.length);
     int _x = _storage[(index * 4) + 0];
     int _y = _storage[(index * 4) + 1];
     int _z = _storage[(index * 4) + 2];
@@ -299,7 +240,7 @@
   }
 
   void operator[]=(int index, Int32x4 value) {
-    _checkIndex(index, length);
+    _checkValidIndex(index, this, this.length);
     _storage[(index * 4) + 0] = value.x;
     _storage[(index * 4) + 1] = value.y;
     _storage[(index * 4) + 2] = value.z;
@@ -307,7 +248,7 @@
   }
 
   List<Int32x4> sublist(int start, [int end]) {
-    end = _checkSublistArguments(start, end, length);
+    end = _checkValidRange(start, end, this.length);
     return new NativeInt32x4List._externalStorage(
         _storage.sublist(start * 4, end * 4));
   }
@@ -366,52 +307,23 @@
 
   int get elementSizeInBytes => Float64x2List.BYTES_PER_ELEMENT;
 
-  void _invalidIndex(int index, int length) {
-    if (index < 0 || index >= length) {
-      if (length == this.length) {
-        throw new RangeError.index(index, this);
-      }
-      throw new RangeError.range(index, 0, length - 1);
-    } 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;
-  }
-
   int get length => _storage.length ~/ 2;
 
   Float64x2 operator[](int index) {
-    _checkIndex(index, length);
+    _checkValidIndex(index, this, this.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);
+    _checkValidIndex(index, this, this.length);
     _storage[(index * 2) + 0] = value.x;
     _storage[(index * 2) + 1] = value.y;
   }
 
   List<Float64x2> sublist(int start, [int end]) {
-    end = _checkSublistArguments(start, end, length);
+    end = _checkValidRange(start, end, this.length);
     return new NativeFloat64x2List._externalStorage(
         _storage.sublist(start * 2, end * 2));
   }
@@ -446,37 +358,20 @@
   @JSName('BYTES_PER_ELEMENT')
   final int elementSizeInBytes;
 
-  void _checkIndex(int index, int length) {
-    if (JS('bool', '(# >>> 0) !== #', index, index) ||
-        JS('int', '#', index) >= length) {  // 'int' guaranteed by above test.
-      throw diagnoseIndexError(this, index);
-    }
-  }
-
-  void _invalidPosition(int position, int length) {
+  void _invalidPosition(int position, int length, String name) {
     if (position is !int) {
-      throw new ArgumentError.value(position, null, 'Invalid list position');
+      throw new ArgumentError.value(position, name, 'Invalid list position');
     } else {
-      throw new RangeError.range(position, 0, length);
+      throw new RangeError.range(position, 0, length, name);
     }
   }
 
-  void _checkPosition(int position, int length) {
+  void _checkPosition(int position, int length, String name) {
     if (JS('bool', '(# >>> 0) !== #', position, position) ||
         JS('int', '#', position) > length) {  // 'int' guaranteed by above test.
-      _invalidPosition(position, length);
+      _invalidPosition(position, length, name);
     }
   }
-
-  int _checkSublistArguments(int start, int end, int length) {
-    // For `sublist` the [start] and [end] indices are allowed to be equal to
-    // [length].
-    _checkPosition(start, length);
-    if (end == null) return length;
-    _checkPosition(end, length);
-    if (start > end) throw new RangeError.range(start, 0, end);
-    return end;
-  }
 }
 
 
@@ -862,8 +757,8 @@
   void _setRangeFast(int start, int end,
       NativeTypedArray source, int skipCount) {
     int targetLength = this.length;
-    _checkPosition(start, targetLength);
-    _checkPosition(end, targetLength);
+    _checkPosition(start, targetLength, "start");
+    _checkPosition(end, targetLength, "end");
     if (start > end) throw new RangeError.range(start, 0, end);
     int count = end - start;
 
@@ -888,12 +783,12 @@
         with ListMixin<double>, FixedLengthListMixin<double> {
 
   num operator[](int index) {
-    _checkIndex(index, length);
+    _checkValidIndex(index, this, this.length);
     return JS('num', '#[#]', this, index);
   }
 
   void operator[]=(int index, num value) {
-    _checkIndex(index, length);
+    _checkValidIndex(index, this, this.length);
     JS('void', '#[#] = #', this, index, value);
   }
 
@@ -916,7 +811,7 @@
   // types
 
   void operator[]=(int index, int value) {
-    _checkIndex(index, length);
+    _checkValidIndex(index, this, this.length);
     JS('void', '#[#] = #', this, index, value);
   }
 
@@ -952,7 +847,7 @@
   Type get runtimeType => Float32List;
 
   List<double> sublist(int start, [int end]) {
-    end = _checkSublistArguments(start, end, length);
+    end = _checkValidRange(start, end, this.length);
     var source = JS('NativeFloat32List', '#.subarray(#, #)', this, start, end);
     return _create1(source);
   }
@@ -989,7 +884,7 @@
   Type get runtimeType => Float64List;
 
   List<double> sublist(int start, [int end]) {
-    end = _checkSublistArguments(start, end, length);
+    end = _checkValidRange(start, end, this.length);
     var source = JS('NativeFloat64List', '#.subarray(#, #)', this, start, end);
     return _create1(source);
   }
@@ -1026,12 +921,12 @@
   Type get runtimeType => Int16List;
 
   int operator[](int index) {
-    _checkIndex(index, length);
+    _checkValidIndex(index, this, this.length);
     return JS('int', '#[#]', this, index);
   }
 
   List<int> sublist(int start, [int end]) {
-    end = _checkSublistArguments(start, end, length);
+    end = _checkValidRange(start, end, this.length);
     var source = JS('NativeInt16List', '#.subarray(#, #)', this, start, end);
     return _create1(source);
   }
@@ -1066,12 +961,12 @@
   Type get runtimeType => Int32List;
 
   int operator[](int index) {
-    _checkIndex(index, length);
+    _checkValidIndex(index, this, this.length);
     return JS('int', '#[#]', this, index);
   }
 
   List<int> sublist(int start, [int end]) {
-    end = _checkSublistArguments(start, end, length);
+    end = _checkValidRange(start, end, this.length);
     var source = JS('NativeInt32List', '#.subarray(#, #)', this, start, end);
     return _create1(source);
   }
@@ -1106,12 +1001,12 @@
   Type get runtimeType => Int8List;
 
   int operator[](int index) {
-    _checkIndex(index, length);
+    _checkValidIndex(index, this, this.length);
     return JS('int', '#[#]', this, index);
   }
 
   List<int> sublist(int start, [int end]) {
-    end = _checkSublistArguments(start, end, length);
+    end = _checkValidRange(start, end, this.length);
     var source = JS('NativeInt8List', '#.subarray(#, #)', this, start, end);
     return _create1(source);
   }
@@ -1146,12 +1041,12 @@
   Type get runtimeType => Uint16List;
 
   int operator[](int index) {
-    _checkIndex(index, length);
+    _checkValidIndex(index, this, this.length);
     return JS('JSUInt31', '#[#]', this, index);
   }
 
   List<int> sublist(int start, [int end]) {
-    end = _checkSublistArguments(start, end, length);
+    end = _checkValidRange(start, end, this.length);
     var source = JS('NativeUint16List', '#.subarray(#, #)', this, start, end);
     return _create1(source);
   }
@@ -1186,12 +1081,12 @@
   Type get runtimeType => Uint32List;
 
   int operator[](int index) {
-    _checkIndex(index, length);
+    _checkValidIndex(index, this, this.length);
     return JS('JSUInt32', '#[#]', this, index);
   }
 
   List<int> sublist(int start, [int end]) {
-    end = _checkSublistArguments(start, end, length);
+    end = _checkValidRange(start, end, this.length);
     var source = JS('NativeUint32List', '#.subarray(#, #)', this, start, end);
     return _create1(source);
   }
@@ -1230,12 +1125,12 @@
   int get length => JS('JSUInt32', '#.length', this);
 
   int operator[](int index) {
-    _checkIndex(index, length);
+    _checkValidIndex(index, this, this.length);
     return JS('JSUInt31', '#[#]', this, index);
   }
 
   List<int> sublist(int start, [int end]) {
-    end = _checkSublistArguments(start, end, length);
+    end = _checkValidRange(start, end, this.length);
     var source = JS('NativeUint8ClampedList', '#.subarray(#, #)',
         this, start, end);
     return _create1(source);
@@ -1278,12 +1173,12 @@
   int get length => JS('JSUInt32', '#.length', this);
 
   int operator[](int index) {
-    _checkIndex(index, length);
+    _checkValidIndex(index, this, this.length);
     return JS('JSUInt31', '#[#]', this, index);
   }
 
   List<int> sublist(int start, [int end]) {
-    end = _checkSublistArguments(start, end, length);
+    end = _checkValidRange(start, end, this.length);
     var source = JS('NativeUint8List', '#.subarray(#, #)', this, start, end);
     return _create1(source);
   }
@@ -2006,3 +1901,37 @@
       return new NativeFloat64x2._doubles(Math.sqrt(x), Math.sqrt(y));
   }
 }
+
+/// Checks that the value is a Uint32. If not, it's not valid as an array
+/// index or offset. Also ensures that the value is non-negative.
+bool _isInvalidArrayIndex(int index) {
+  return (JS('bool', '(# >>> 0 !== #)', index, index));
+}
+
+/// Checks that [index] is a valid index into [list] which has length [length].
+///
+/// That is, [index] is an insteger in the range `0..length - 1`.
+void _checkValidIndex(int index, List list, int length) {
+  if (_isInvalidArrayIndex(index) || JS('int', '#', index) >= length) {
+    throw diagnoseIndexError(list, index);
+  }
+}
+
+/// Checks that [start] and [end] form a range of a list of length [length].
+///
+/// That is: `start` and `end` are integers with `0 <= start <= end <= length`.
+/// If `end` is `null` in which case it is considered to be `length`
+///
+/// Returns the actual value of `end`, which is `length` if `end` is `null`, and
+/// the original value of `end` otherwise.
+int _checkValidRange(int start, int end, int length) {
+  if (_isInvalidArrayIndex(start) ||  // Ensures start is non-negative int.
+      ((end == null) ? start > length
+                     : (_isInvalidArrayIndex(end) ||
+                        start > end ||
+                        end > length))) {
+    throw diagnoseRangeError(start, end, length);
+  }
+  if (end == null) return length;
+  return end;
+}
diff --git a/sdk/lib/collection/hash_map.dart b/sdk/lib/collection/hash_map.dart
index 6fb73a5..5a22dc0 100644
--- a/sdk/lib/collection/hash_map.dart
+++ b/sdk/lib/collection/hash_map.dart
@@ -27,7 +27,7 @@
  *
  * Iterating the map's keys, values or entries (through [forEach])
  * may happen in any order.
- * The itearation order only changes when the map is modified.
+ * The iteration order only changes when the map is modified.
  * Values are iterated in the same order as their associated keys,
  * so iterating the [keys] and [values] in parallel
  * will give matching key and value pairs.
diff --git a/sdk/lib/convert/utf.dart b/sdk/lib/convert/utf.dart
index 9128e61..8b1a1e0 100644
--- a/sdk/lib/convert/utf.dart
+++ b/sdk/lib/convert/utf.dart
@@ -66,7 +66,7 @@
     return new Utf8Decoder(allowMalformed: allowMalformed).convert(codeUnits);
   }
 
-  Utf8Encoder get encoder => new Utf8Encoder();
+  Utf8Encoder get encoder => const Utf8Encoder();
   Utf8Decoder get decoder {
     return new Utf8Decoder(allowMalformed: _allowMalformed);
   }
diff --git a/sdk/lib/core/errors.dart b/sdk/lib/core/errors.dart
index 0e99b0b..3053807 100644
--- a/sdk/lib/core/errors.dart
+++ b/sdk/lib/core/errors.dart
@@ -392,12 +392,13 @@
   String get _errorName => "RangeError";
   String get _errorExplanation {
     assert(_hasValue);
-    String target = Error.safeToString(indexable);
-    var explanation = ": index should be less than $length";
     if (invalidValue < 0) {
-      explanation = ": index must not be negative";
+      return ": index must not be negative";
     }
-    return explanation;
+    if (length == 0) {
+      return ": no indices are valid";
+    }
+    return ": index should be less than $length";
   }
 }
 
diff --git a/sdk/lib/core/map.dart b/sdk/lib/core/map.dart
index d19d108..e92c780 100644
--- a/sdk/lib/core/map.dart
+++ b/sdk/lib/core/map.dart
@@ -35,7 +35,7 @@
    * `operator==` and `hashCode`, and it allows null as a key.
    * It iterates in key insertion order.
    */
-  factory Map() = LinkedHashMap<K, V>;
+  external factory Map();
 
   /**
    * Creates a [LinkedHashMap] instance that contains all key-value pairs of
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index 2164bc9..6b0dc96 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -632,8 +632,7 @@
       if (_isErrorResponse(response)) {
         throw _exceptionFromResponse(response, "readByte failed", path);
       }
-      _resourceInfo.readCount++;
-      _resourceInfo.totalRead++;
+      _resourceInfo.addRead(1);
       return response;
     });
   }
@@ -646,8 +645,7 @@
     if (result is OSError) {
       throw new FileSystemException("readByte failed", path, result);
     }
-    _resourceInfo.readCount++;
-    _resourceInfo.totalRead++;
+    _resourceInfo.addRead(1);
     return result;
   }
 
@@ -659,8 +657,7 @@
       if (_isErrorResponse(response)) {
         throw _exceptionFromResponse(response, "read failed", path);
       }
-      _resourceInfo.readCount++;
-      _resourceInfo.totalRead += response[1].length;
+      _resourceInfo.addRead(response[1].length);
       return response[1];
     });
   }
@@ -676,8 +673,7 @@
     if (result is OSError) {
       throw new FileSystemException("readSync failed", path, result);
     }
-    _resourceInfo.readCount++;
-    _resourceInfo.totalRead += result.length;
+    _resourceInfo.addRead(result.length);
     return result;
   }
 
@@ -697,8 +693,7 @@
       var read = response[1];
       var data = response[2];
       buffer.setRange(start, start + read, data);
-      _resourceInfo.readCount++;
-      _resourceInfo.totalRead += read;
+      _resourceInfo.addRead(read);
       return read;
     });
   }
@@ -718,8 +713,7 @@
     if (result is OSError) {
       throw new FileSystemException("readInto failed", path, result);
     }
-    _resourceInfo.readCount++;
-    _resourceInfo.totalRead += result;
+    _resourceInfo.addRead(result);
     return result;
   }
 
@@ -731,8 +725,7 @@
       if (_isErrorResponse(response)) {
         throw _exceptionFromResponse(response, "writeByte failed", path);
       }
-      _resourceInfo.writeCount++;
-      _resourceInfo.totalWritten++;
+      _resourceInfo.addWrite(1);
       return this;
     });
   }
@@ -748,8 +741,7 @@
     if (result is OSError) {
       throw new FileSystemException("writeByte failed", path, result);
     }
-    _resourceInfo.writeCount++;
-    _resourceInfo.totalWritten++;
+    _resourceInfo.addWrite(1);
     return result;
   }
 
@@ -778,8 +770,7 @@
       if (_isErrorResponse(response)) {
         throw _exceptionFromResponse(response, "writeFrom failed", path);
       }
-      _resourceInfo.writeCount++;
-      _resourceInfo.totalWritten += end - (start - result.start);
+      _resourceInfo.addWrite(end - (start - result.start));
       return this;
     });
   }
@@ -804,8 +795,7 @@
     if (result is OSError) {
       throw new FileSystemException("writeFrom failed", path, result);
     }
-    _resourceInfo.writeCount++;
-    _resourceInfo.totalWritten += end - (start - bufferAndStart.start);
+    _resourceInfo.addWrite(end - (start - bufferAndStart.start));
   }
 
   Future<RandomAccessFile> writeString(String string,
diff --git a/sdk/lib/io/io_resource_info.dart b/sdk/lib/io/io_resource_info.dart
index 8c30c64..1a18fc9 100644
--- a/sdk/lib/io/io_resource_info.dart
+++ b/sdk/lib/io/io_resource_info.dart
@@ -10,9 +10,12 @@
   String get name;
   static int _count = 0;
 
-  _IOResourceInfo(this.type) : id = _IOResourceInfo.getNextID();
+  static final Stopwatch _sw = new Stopwatch()..start();
+  static final _startTime = new DateTime.now().millisecondsSinceEpoch;
 
-  String toJSON();
+  static double get timestamp => _startTime + _sw.elapsedMicroseconds/1000;
+
+  _IOResourceInfo(this.type) : id = _IOResourceInfo.getNextID();
 
   /// Get the full set of values for a specific implementation. This is normally
   /// looked up based on an id from a referenceValueMap.
@@ -31,9 +34,6 @@
   static int getNextID() => _count++;
 }
 
-// TODO(ricow): Move stopwatch into this class and use it for both files
-// and sockets (by using setters on totalRead/totalWritten). Also, consider
-// setting readCount and writeCount in those setters.
 abstract class _ReadWriteResourceInfo extends _IOResourceInfo {
   int totalRead;
   int totalWritten;
@@ -42,6 +42,26 @@
   double lastRead;
   double lastWrite;
 
+  // Not all call sites use this. In some cases, e.g., a socket, a read does
+  // not always mean that we actually read some bytes (we may do a read to see
+  // if there are some bytes available).
+  void addRead(int bytes) {
+    totalRead += bytes;
+    readCount++;
+    lastRead = _IOResourceInfo.timestamp;
+  }
+
+  // In cases where we read but did not neccesarily get any bytes, use this to
+  // update the readCount and timestamp. Manually update totalRead if any bytes
+  // where acutally read.
+  void didRead() => addRead(0);
+
+  void addWrite(int bytes) {
+    totalWritten += bytes;
+    writeCount++;
+    lastWrite = _IOResourceInfo.timestamp;
+  }
+
   _ReadWriteResourceInfo(String type) :
     totalRead = 0,
     totalWritten = 0,
@@ -56,17 +76,13 @@
       'type': type,
       'id': id,
       'name': name,
-      'total_read': totalRead,
-      'total_written': totalWritten,
-      'read_count': readCount,
-      'write_count': writeCount,
-      'last_read': lastRead,
-      'last_write': lastWrite
+      'totalRead': totalRead,
+      'totalWritten': totalWritten,
+      'readCount': readCount,
+      'writeCount': writeCount,
+      'lastRead': lastRead,
+      'lastWrite': lastWrite
     };
-
-  String toJSON() {
-    return JSON.encode(fullValueMap);
-  }
 }
 
 class _FileResourceInfo extends _ReadWriteResourceInfo {
@@ -121,6 +137,68 @@
   }
 }
 
+class _ProcessResourceInfo extends _IOResourceInfo{
+  static const String TYPE = '_process';
+  final process;
+  final double startedAt;
+
+  static Map<int, _ProcessResourceInfo> startedProcesses =
+      new Map<int, _ProcessResourceInfo>();
+
+  _ProcessResourceInfo(this.process) :
+      startedAt = _IOResourceInfo.timestamp,
+      super(TYPE) {
+    ProcessStarted(this);
+  }
+
+  String get name => process._path;
+
+  void stopped() => ProcessStopped(this);
+
+  Map<String, String> get fullValueMap =>
+    {
+      'type': type,
+      'id': id,
+      'name': name,
+      'pid': process.pid,
+      'startedAt': startedAt,
+      'arguments': process._arguments,
+      'workingDirectory':
+          process._workingDirectory == null ? '.' : process._workingDirectory,
+    };
+
+  static ProcessStarted(_ProcessResourceInfo info) {
+    assert(!startedProcesses.containsKey(info.id));
+    startedProcesses[info.id] = info;
+  }
+
+  static ProcessStopped(_ProcessResourceInfo info) {
+    assert(startedProcesses.containsKey(info.id));
+    startedProcesses.remove(info.id);
+  }
+
+  static Iterable<Map<String, String>> getStartedProcessesList() =>
+      new List.from(startedProcesses.values.map((e) => e.referenceValueMap));
+
+  static Future<ServiceExtensionResponse> getStartedProcesses(
+      String function, Map<String, String> params) {
+    assert(function == '__getProcesses');
+    var data = {'type': '_startedprocesses', 'data': getStartedProcessesList()};
+    var json = JSON.encode(data);
+    return new Future.value(new ServiceExtensionResponse.result(json));
+  }
+
+  static Future<ServiceExtensionResponse> getProcessInfoMapById(
+      String function, Map<String, String> params) {
+    var id = int.parse(params['id']);
+    var result = startedProcesses.containsKey(id)
+        ? startedProcesses[id].fullValueMap
+        : {};
+    var json = JSON.encode(result);
+    return new Future.value(new ServiceExtensionResponse.result(json));
+  }
+}
+
 class _SocketResourceInfo extends _ReadWriteResourceInfo {
   static const String TCP_STRING = 'TCP';
   static const String UDP_STRING = 'UDP';
@@ -154,24 +232,24 @@
 
   Map<String, String> getSocketInfoMap() {
     var result = fullValueMap;
-    result['socket_type'] = socket.isTcp ? TCP_STRING : UDP_STRING;
+    result['socketType'] = socket.isTcp ? TCP_STRING : UDP_STRING;
     result['listening'] = socket.isListening;
     result['host'] = socket.address.host;
     result['port'] = socket.port;
     if (!socket.isListening) {
       try {
-        result['remote_host'] = socket.remoteAddress.host;
-        result['remote_port'] = socket.remotePort;
+        result['remoteHost'] = socket.remoteAddress.host;
+        result['remotePort'] = socket.remotePort;
       } catch (e) {
         // UDP.
-        result['remote_port'] = 'NA';
-        result['remote_host'] = 'NA';
+        result['remotePort'] = 'NA';
+        result['remoteHost'] = 'NA';
       }
     } else {
-      result['remote_port'] = 'NA';
-      result['remote_host'] = 'NA';
+      result['remotePort'] = 'NA';
+      result['remoteHost'] = 'NA';
     }
-    result['address_type'] = socket.address.type.name;
+    result['addressType'] = socket.address.type.name;
     return result;
   }
 
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index d239ef2..d5534ba 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -212,20 +212,30 @@
    *
    * WARNING: The [checked] parameter is not implemented on all platforms yet.
    *
-   * If the [packageRoot] parameter is provided, it is used to find the location
-   * of packages imports in the spawned isolate.
+   * If either the [packageRoot] or the [packages] parameter is provided,
+   * it is used to find the location of package sources in the spawned isolate.
+   *
    * The `packageRoot` URI must be a "file" or "http"/"https" URI that specifies
    * a directory. If it doesn't end in a slash, one will be added before
    * using the URI, and any query or fragment parts are ignored.
-   * Package imports (like "package:foo/bar.dart") in the new isolate are
+   * Package imports (like `"package:foo/bar.dart"`) in the new isolate are
    * resolved against this location, as by
    * `packageRoot.resolve("foo/bar.dart")`.
-   * This includes the main entry [uri] if it happens to be a package-URL.
-   * If [packageRoot] is omitted, it defaults to the same URI that
-   * the current isolate is using.
    *
-   * WARNING: The [packageRoot] parameter is not implemented on all
-   * platforms yet.
+   * The `packages` map maps package names to URIs with the same requirements
+   * as `packageRoot`. Package imports (like `"package:foo/bar/baz.dart"`) in
+   * the new isolate are resolved against the URI for that package (if any),
+   * as by `packages["foo"].resolve("bar/baz.dart")
+   *
+   * This resolution also applies to the main entry [uri]
+   * if that happens to be a package-URI.
+   *
+   * If both [packageRoot] and [packages] are omitted, the new isolate uses
+   * the same package resolution as the current isolate.
+   * It's not allowed to provide both a `packageRoot` and a `package` parameter.
+   *
+   * WARNING: The [packageRoot] and [packages] parameters are not implemented
+   * on all platforms yet.
    *
    * Returns a future that will complete with an [Isolate] instance if the
    * spawning succeeded. It will complete with an error otherwise.
@@ -237,6 +247,7 @@
       {bool paused: false,
        bool checked,
        Uri packageRoot,
+       Map<String, Uri> packages,
        bool errorsAreFatal,
        SendPort onExit,
        SendPort onError});
diff --git a/site/try/poi/scope_information_visitor.dart b/site/try/poi/scope_information_visitor.dart
index c9d2af0..5ae18ee 100644
--- a/site/try/poi/scope_information_visitor.dart
+++ b/site/try/poi/scope_information_visitor.dart
@@ -74,7 +74,7 @@
         // TODO(ahe): We omit the import scope if there is no current
         // class. That's wrong.
         omitEnclosing: ignoreImports || currentClass == null,
-        name: e.getLibraryName(),
+        name: e.libraryName,
         serializeEnclosing: () {
           // The enclosing scope of a library is a scope which contains all the
           // imported names.
diff --git a/tests/compiler/dart2js/analyze_dart2js_helpers_test.dart b/tests/compiler/dart2js/analyze_dart2js_helpers_test.dart
index ac72614..98555ea 100644
--- a/tests/compiler/dart2js/analyze_dart2js_helpers_test.dart
+++ b/tests/compiler/dart2js/analyze_dart2js_helpers_test.dart
@@ -11,6 +11,7 @@
     Diagnostic;
 import 'package:compiler/src/apiimpl.dart' show
     Compiler;
+import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/constants/expressions.dart' show
     ConstructedConstantExpression;
 import 'package:compiler/src/dart_types.dart' show
@@ -36,11 +37,11 @@
   bool verbose = arguments.contains('-v');
 
   List<String> options = <String>[
-    '--analyze-only',
-    '--analyze-main',
+    Flags.analyzeOnly,
+    Flags.analyzeMain,
     '--categories=Client,Server'];
   if (verbose) {
-    options.add('--verbose');
+    options.add(Flags.verbose);
   }
   asyncTest(() async {
     Compiler compiler = compilerFor(
diff --git a/tests/compiler/dart2js/analyze_dart2js_test.dart b/tests/compiler/dart2js/analyze_dart2js_test.dart
index 602f904..f5fc77c 100644
--- a/tests/compiler/dart2js/analyze_dart2js_test.dart
+++ b/tests/compiler/dart2js/analyze_dart2js_test.dart
@@ -4,9 +4,11 @@
 
 library analyze_dart2js;
 
+import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/filenames.dart';
+import 'package:compiler/src/compiler.dart';
 import 'analyze_helper.dart';
-import "package:async_helper/async_helper.dart";
+import 'related_types.dart';
 
 /**
  * Map of whitelisted warnings and errors.
@@ -24,5 +26,11 @@
 
 void main() {
   var uri = currentDirectory.resolve('pkg/compiler/lib/src/dart2js.dart');
-  asyncTest(() => analyze([uri], WHITE_LIST));
+  asyncTest(() => analyze([uri], WHITE_LIST, checkResults: checkResults));
 }
+
+bool checkResults(Compiler compiler,
+                  CollectingDiagnosticHandler handler) {
+  checkRelatedTypes(compiler);
+  return !handler.hasHint;
+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/analyze_helper.dart b/tests/compiler/dart2js/analyze_helper.dart
index ccd9b3b..a916133 100644
--- a/tests/compiler/dart2js/analyze_helper.dart
+++ b/tests/compiler/dart2js/analyze_helper.dart
@@ -8,6 +8,7 @@
 import 'dart:io';
 import 'package:compiler/compiler.dart' as api;
 import 'package:compiler/src/apiimpl.dart';
+import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/diagnostics/messages.dart' show
     Message;
 import 'package:compiler/src/filenames.dart';
@@ -155,9 +156,9 @@
       currentDirectory.resolveUri(new Uri.file('${Platform.packageRoot}/'));
   var provider = new CompilerSourceFileProvider();
   var handler = new CollectingDiagnosticHandler(whiteList, provider);
-  var options = <String>['--analyze-only', '--categories=Client,Server',
-    '--show-package-warnings'];
-  if (analyzeAll) options.add('--analyze-all');
+  var options = <String>[Flags.analyzeOnly, '--categories=Client,Server',
+      Flags.showPackageWarnings];
+  if (analyzeAll) options.add(Flags.analyzeAll);
   var compiler = new Compiler(
       provider,
       null,
diff --git a/tests/compiler/dart2js/analyze_only_test.dart b/tests/compiler/dart2js/analyze_only_test.dart
index bb42728..08100a6 100644
--- a/tests/compiler/dart2js/analyze_only_test.dart
+++ b/tests/compiler/dart2js/analyze_only_test.dart
@@ -11,7 +11,7 @@
 
 import '../../utils/dummy_compiler_test.dart' as dummy;
 import 'package:compiler/compiler.dart';
-
+import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/diagnostics/messages.dart' show
     MessageKind, MessageTemplate;
 
@@ -64,7 +64,7 @@
 main() {
   runCompiler(
     "",
-    ['--generate-code-with-compile-time-errors'],
+    [Flags.generateCodeWithCompileTimeErrors],
     (String code, List errors, List warnings) {
       Expect.isNotNull(code);
       Expect.isTrue(errors.isEmpty, 'errors is not empty: $errors');
@@ -77,7 +77,7 @@
 
   runCompiler(
     "main() {}",
-    ['--generate-code-with-compile-time-errors'],
+    [Flags.generateCodeWithCompileTimeErrors],
     (String code, List errors, List warnings) {
       Expect.isNotNull(code);
       Expect.isTrue(errors.isEmpty);
@@ -86,7 +86,7 @@
 
   runCompiler(
     "",
-    ['--analyze-only'],
+    [Flags.analyzeOnly],
     (String code, List errors, List warnings) {
       Expect.isNull(code);
       Expect.isTrue(errors.isEmpty, 'errors is not empty: $errors');
@@ -99,7 +99,7 @@
 
   runCompiler(
     "main() {}",
-    ['--analyze-only'],
+    [Flags.analyzeOnly],
     (String code, List errors, List warnings) {
       Expect.isNull(code);
       Expect.isTrue(errors.isEmpty);
@@ -108,7 +108,7 @@
 
   runCompiler(
     "Foo foo; // Unresolved but not analyzed.",
-    ['--analyze-only'],
+    [Flags.analyzeOnly],
     (String code, List errors, List warnings) {
       Expect.isNull(code);
       Expect.isTrue(errors.isEmpty, 'errors is not empty: $errors');
@@ -123,7 +123,7 @@
     """main() {
          Foo foo; // Unresolved and analyzed.
        }""",
-    ['--analyze-only'],
+    [Flags.analyzeOnly],
     (String code, List errors, List warnings) {
       Expect.isNull(code);
       Expect.isTrue(errors.isEmpty);
@@ -136,7 +136,7 @@
     """main() {
          Foo foo; // Unresolved and analyzed.
        }""",
-    ['--analyze-only', '--analyze-signatures-only'],
+    [Flags.analyzeOnly, Flags.analyzeSignaturesOnly],
     (String code, List errors, List warnings) {
       Expect.isNull(code);
       Expect.isTrue(errors.isEmpty);
@@ -145,7 +145,7 @@
 
   runCompiler(
     "Foo foo; // Unresolved and analyzed.",
-    ['--analyze-only', '--analyze-all'],
+    [Flags.analyzeOnly, Flags.analyzeAll],
     (String code, List errors, List warnings) {
       Expect.isNull(code);
       Expect.isTrue(errors.isEmpty);
@@ -156,7 +156,7 @@
   runCompiler(
     """Foo foo; // Unresolved and analyzed.
        main() {}""",
-    ['--analyze-only', '--analyze-all'],
+    [Flags.analyzeOnly, Flags.analyzeAll],
     (String code, List errors, List warnings) {
       Expect.isNull(code);
       Expect.isTrue(errors.isEmpty, 'Unexpected errors: $errors.');
@@ -167,7 +167,7 @@
 
   runCompiler(
     "",
-    ['--analyze-only', '--analyze-all'],
+    [Flags.analyzeOnly, Flags.analyzeAll],
     (String code, List errors, List warnings) {
       Expect.isNull(code);
       Expect.isTrue(errors.isEmpty);
@@ -177,7 +177,7 @@
   // --analyze-signatures-only implies --analyze-only
   runCompiler(
     "",
-    ['--analyze-signatures-only', '--analyze-all'],
+    [Flags.analyzeSignaturesOnly, Flags.analyzeAll],
     (String code, List errors, List warnings) {
       Expect.isNull(code);
       Expect.isTrue(errors.isEmpty);
diff --git a/tests/compiler/dart2js/arithmetic_simplification_test.dart b/tests/compiler/dart2js/arithmetic_simplification_test.dart
index 8b69d50..039a844 100644
--- a/tests/compiler/dart2js/arithmetic_simplification_test.dart
+++ b/tests/compiler/dart2js/arithmetic_simplification_test.dart
@@ -81,7 +81,8 @@
   asyncTest(() => Future.wait([
     compileAndDoNotMatch(INT_PLUS_ZERO, 'main', plusZero),
     compileAndDoNotMatch(ZERO_PLUS_INT, 'main', zeroPlus),
-    compileAndMatch(NUM_PLUS_ZERO, 'main', plusZero),
+    // TODO(johnniwinther): Find out why this doesn't work without [useMock].
+    compileAndMatch(NUM_PLUS_ZERO, 'main', plusZero, useMock: true),
     compileAndMatch(ZERO_PLUS_NUM, 'main', zeroPlus),
     compileAndDoNotMatch(INT_TIMES_ONE, 'main', timesOne),
     compileAndDoNotMatch(ONE_TIMES_INT, 'main', oneTimes),
diff --git a/tests/compiler/dart2js/array_tracing_mirror_test.dart b/tests/compiler/dart2js/array_tracing_mirror_test.dart
index 2c4c9aa..6a083ca 100644
--- a/tests/compiler/dart2js/array_tracing_mirror_test.dart
+++ b/tests/compiler/dart2js/array_tracing_mirror_test.dart
@@ -34,9 +34,10 @@
   asyncTest(() async {
     var result = await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
     var compiler = result.compiler;
-    var element = compiler.mainApp.findExported('main');
-    var code = compiler.backend.assembleCode(element);
-    Expect.isTrue(code.contains('return 2'));
+    var element = compiler.mainFunction;
+    var code = compiler.backend.getGeneratedCode(element);
+    Expect.isTrue(code.contains('return 2'),
+        "Unexpected code:\n$code");
   });
 }
 
diff --git a/tests/compiler/dart2js/bad_loop_test.dart b/tests/compiler/dart2js/bad_loop_test.dart
index 82d8607..bd1053c 100644
--- a/tests/compiler/dart2js/bad_loop_test.dart
+++ b/tests/compiler/dart2js/bad_loop_test.dart
@@ -8,6 +8,7 @@
 
 import 'package:compiler/compiler.dart'
        show Diagnostic;
+import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/old_to_new_api.dart';
 
 main() {
@@ -38,7 +39,7 @@
       new LegacyCompilerDiagnostics(diagnosticHandler),
       libraryRoot,
       packageRoot,
-      ['--analyze-only'],
+      [Flags.analyzeOnly],
       {});
   asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
     Expect.isTrue(compiler.compilationFailed);
diff --git a/tests/compiler/dart2js/class_set_test.dart b/tests/compiler/dart2js/class_set_test.dart
index 2e12cdbf..c3ee031 100644
--- a/tests/compiler/dart2js/class_set_test.dart
+++ b/tests/compiler/dart2js/class_set_test.dart
@@ -55,7 +55,7 @@
     void checkClass(ClassElement cls,
                     {bool directlyInstantiated: false,
                      bool indirectlyInstantiated: false}) {
-      ClassHierarchyNode node = world.classHierarchyNode(cls);
+      ClassHierarchyNode node = world.getClassHierarchyNode(cls);
       Expect.isNotNull(node, "Expected ClassHierarchyNode for $cls.");
       Expect.equals(
           directlyInstantiated || indirectlyInstantiated,
@@ -131,7 +131,7 @@
     }
 
     iterator = new ClassHierarchyNodeIterable(
-        world.classHierarchyNode(G)).iterator;
+        world.getClassHierarchyNode(G)).iterator;
     checkState(G, currentNode: null, stack: null);
     Expect.isNull(iterator.current);
     Expect.isTrue(iterator.moveNext());
@@ -142,7 +142,8 @@
     Expect.isNull(iterator.current);
 
     iterator = new ClassHierarchyNodeIterable(
-        world.classHierarchyNode(G), includeRoot: false).iterator;
+        world.getClassHierarchyNode(G),
+        includeRoot: false).iterator;
     checkState(G, currentNode: null, stack: null);
     Expect.isNull(iterator.current);
     Expect.isFalse(iterator.moveNext());
@@ -150,7 +151,7 @@
     Expect.isNull(iterator.current);
 
     iterator = new ClassHierarchyNodeIterable(
-        world.classHierarchyNode(C)).iterator;
+        world.getClassHierarchyNode(C)).iterator;
     checkState(C, currentNode: null, stack: null);
     Expect.isNull(iterator.current);
     Expect.isTrue(iterator.moveNext());
@@ -170,7 +171,7 @@
     Expect.isNull(iterator.current);
 
     iterator = new ClassHierarchyNodeIterable(
-        world.classHierarchyNode(D)).iterator;
+        world.getClassHierarchyNode(D)).iterator;
     checkState(D, currentNode: null, stack: null);
     Expect.isNull(iterator.current);
     Expect.isTrue(iterator.moveNext());
@@ -181,7 +182,7 @@
     Expect.isNull(iterator.current);
 
     iterator = new ClassHierarchyNodeIterable(
-        world.classHierarchyNode(B)).iterator;
+        world.getClassHierarchyNode(B)).iterator;
     checkState(B, currentNode: null, stack: null);
     Expect.isNull(iterator.current);
     Expect.isTrue(iterator.moveNext());
@@ -195,7 +196,8 @@
     Expect.isNull(iterator.current);
 
     iterator = new ClassHierarchyNodeIterable(
-        world.classHierarchyNode(B), includeRoot: false).iterator;
+        world.getClassHierarchyNode(B),
+        includeRoot: false).iterator;
     checkState(B, currentNode: null, stack: null);
     Expect.isNull(iterator.current);
     Expect.isTrue(iterator.moveNext());
@@ -206,7 +208,8 @@
     Expect.isNull(iterator.current);
 
     iterator = new ClassHierarchyNodeIterable(
-        world.classHierarchyNode(B), directlyInstantiatedOnly: true).iterator;
+        world.getClassHierarchyNode(B),
+        includeIndirectlyInstantiated: false).iterator;
     checkState(B, currentNode: null, stack: null);
     Expect.isNull(iterator.current);
     Expect.isTrue(iterator.moveNext());
@@ -217,7 +220,7 @@
     Expect.isNull(iterator.current);
 
     iterator = new ClassHierarchyNodeIterable(
-        world.classHierarchyNode(A)).iterator;
+        world.getClassHierarchyNode(A)).iterator;
     checkState(A, currentNode: null, stack: null);
     Expect.isNull(iterator.current);
     Expect.isTrue(iterator.moveNext());
@@ -246,7 +249,8 @@
     Expect.isNull(iterator.current);
 
     iterator = new ClassHierarchyNodeIterable(
-        world.classHierarchyNode(A), includeRoot: false).iterator;
+        world.getClassHierarchyNode(A),
+        includeRoot: false).iterator;
     checkState(A, currentNode: null, stack: null);
     Expect.isNull(iterator.current);
     Expect.isTrue(iterator.moveNext());
@@ -272,7 +276,8 @@
     Expect.isNull(iterator.current);
 
     iterator = new ClassHierarchyNodeIterable(
-        world.classHierarchyNode(A), directlyInstantiatedOnly: true).iterator;
+        world.getClassHierarchyNode(A),
+        includeIndirectlyInstantiated: false).iterator;
     checkState(A, currentNode: null, stack: null);
     Expect.isNull(iterator.current);
     Expect.isTrue(iterator.moveNext());
@@ -298,8 +303,9 @@
     Expect.isNull(iterator.current);
 
     iterator = new ClassHierarchyNodeIterable(
-        world.classHierarchyNode(A),
-        includeRoot: false, directlyInstantiatedOnly: true).iterator;
+        world.getClassHierarchyNode(A),
+        includeRoot: false,
+        includeIndirectlyInstantiated: false).iterator;
     checkState(A, currentNode: null, stack: null);
     Expect.isNull(iterator.current);
     Expect.isTrue(iterator.moveNext());
diff --git a/tests/compiler/dart2js/codegen_helper.dart b/tests/compiler/dart2js/codegen_helper.dart
index 1512442..36fadff 100644
--- a/tests/compiler/dart2js/codegen_helper.dart
+++ b/tests/compiler/dart2js/codegen_helper.dart
@@ -31,7 +31,7 @@
     for (var element in backend.generatedCode.keys) {
       if (element.compilationUnit.script.readableUri != uri) continue;
       var name = element.name;
-      var code = backend.assembleCode(element);
+      var code = backend.getGeneratedCode(element);
       result[name] = code;
     }
     return result;
diff --git a/tests/compiler/dart2js/compiler_helper.dart b/tests/compiler/dart2js/compiler_helper.dart
index 9c84a8c..d3ac2ac 100644
--- a/tests/compiler/dart2js/compiler_helper.dart
+++ b/tests/compiler/dart2js/compiler_helper.dart
@@ -7,8 +7,6 @@
 import 'dart:async';
 import "package:expect/expect.dart";
 
-import 'package:compiler/compiler.dart' as api;
-
 import 'package:compiler/src/elements/elements.dart'
        as lego;
 export 'package:compiler/src/elements/elements.dart';
@@ -16,6 +14,7 @@
 import 'package:compiler/src/js_backend/js_backend.dart'
        as js;
 
+import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/common/codegen.dart';
 import 'package:compiler/src/common/resolution.dart';
 
@@ -39,24 +38,35 @@
 import 'mock_compiler.dart';
 export 'mock_compiler.dart';
 
+import 'memory_compiler.dart' hide compilerFor;
+
 import 'output_collector.dart';
 export 'output_collector.dart';
 
+/// Compile [code] and returns the code for [entry].
+///
+/// If [check] is provided, it is executed on the code for [entry] before
+/// returning. If [useMock] is `true` the [MockCompiler] is used for
+/// compilation, otherwise the memory compiler is used.
 Future<String> compile(String code,
                        {String entry: 'main',
                         bool enableTypeAssertions: false,
                         bool minify: false,
                         bool analyzeAll: false,
                         bool disableInlining: true,
-                        void check(String generated)}) {
-  MockCompiler compiler = new MockCompiler.internal(
-      enableTypeAssertions: enableTypeAssertions,
-      // Type inference does not run when manually
-      // compiling a method.
-      disableTypeInference: true,
-      enableMinification: minify,
-      disableInlining: disableInlining);
-  return compiler.init().then((_) {
+                        bool useMock: false,
+                        void check(String generated)}) async {
+  if (useMock) {
+    // TODO(johnniwinther): Remove this when no longer needed by
+    // `arithmetic_simplication_test.dart`.
+    MockCompiler compiler = new MockCompiler.internal(
+        enableTypeAssertions: enableTypeAssertions,
+        // Type inference does not run when manually
+        // compiling a method.
+        disableTypeInference: true,
+        enableMinification: minify,
+        disableInlining: disableInlining);
+    await compiler.init();
     compiler.parseScript(code);
     lego.Element element = compiler.mainApp.find(entry);
     if (element == null) return null;
@@ -75,40 +85,49 @@
     compiler.phase = Compiler.PHASE_COMPILING;
     work.run(compiler, compiler.enqueuer.codegen);
     js.JavaScriptBackend backend = compiler.backend;
-    String generated = backend.assembleCode(element);
+    String generated = backend.getGeneratedCode(element);
     if (check != null) {
       check(generated);
     }
     return generated;
-  });
-}
+  } else {
+    List<String> options = <String>[
+        Flags.disableTypeInference];
+    if (enableTypeAssertions) {
+      options.add(Flags.enableCheckedMode);
+    }
+    if (minify) {
+      options.add(Flags.minify);
+    }
+    if (analyzeAll) {
+      options.add(Flags.analyzeAll);
+    }
 
-// TODO(herhut): Disallow warnings and errors during compilation by default.
-MockCompiler compilerFor(String code, Uri uri,
-                         {bool analyzeAll: false,
-                          bool analyzeOnly: false,
-                          Map<String, String> coreSource,
-                          bool disableInlining: true,
-                          bool minify: false,
-                          bool trustTypeAnnotations: false,
-                          bool enableTypeAssertions: false,
-                          int expectedErrors,
-                          int expectedWarnings,
-                          api.CompilerOutputProvider outputProvider}) {
-  MockCompiler compiler = new MockCompiler.internal(
-      analyzeAll: analyzeAll,
-      analyzeOnly: analyzeOnly,
-      coreSource: coreSource,
-      disableInlining: disableInlining,
-      enableMinification: minify,
-      trustTypeAnnotations: trustTypeAnnotations,
-      enableTypeAssertions: enableTypeAssertions,
-      expectedErrors: expectedErrors,
-      expectedWarnings: expectedWarnings,
-      outputProvider: outputProvider);
-  compiler.registerSource(uri, code);
-  compiler.diagnosticHandler = createHandler(compiler, code);
-  return compiler;
+    Map<String, String> source;
+    if (entry != 'main') {
+      source = {'main.dart': "$code\n\nmain() => $entry;" };
+    } else {
+      source = {'main.dart': code};
+    }
+
+    CompilationResult result = await runCompiler(
+        memorySourceFiles: source,
+        options: options,
+        beforeRun: (compiler) {
+          if (disableInlining) {
+            compiler.disableInlining = true;
+          }
+        });
+    Expect.isTrue(result.isSuccess);
+    Compiler compiler =  result.compiler;
+    lego.Element element = compiler.mainApp.find(entry);
+    js.JavaScriptBackend backend = compiler.backend;
+    String generated = backend.getGeneratedCode(element);
+    if (check != null) {
+      check(generated);
+    }
+    return generated;
+  }
 }
 
 Future<String> compileAll(String code,
@@ -225,8 +244,11 @@
   Expect.isFalse(hasNext, "Found more than $nb matches");
 }
 
-Future compileAndMatch(String code, String entry, RegExp regexp) {
-  return compile(code, entry: entry, check: (String generated) {
+Future compileAndMatch(String code, String entry, RegExp regexp,
+                       {bool useMock: false}) {
+  return compile(code, entry: entry,
+      useMock: useMock,
+      check: (String generated) {
     Expect.isTrue(regexp.hasMatch(generated),
                   '"$generated" does not match /$regexp/');
   });
diff --git a/tests/compiler/dart2js/dart2js.status b/tests/compiler/dart2js/dart2js.status
index 3518280..0ae992d 100644
--- a/tests/compiler/dart2js/dart2js.status
+++ b/tests/compiler/dart2js/dart2js.status
@@ -69,6 +69,7 @@
 check_elements_invariants_test: Slow, Pass
 import_mirrors_test: Slow, Pass
 exit_code_test: Pass, Slow
+value_range_test: Pass, Slow
 
 [ $mode == debug ]
 check_elements_invariants_test: Skip # Slow and only needs to be run in one
diff --git a/tests/compiler/dart2js/dictionary_types_test.dart b/tests/compiler/dart2js/dictionary_types_test.dart
index 11734e1..f173c23 100644
--- a/tests/compiler/dart2js/dictionary_types_test.dart
+++ b/tests/compiler/dart2js/dictionary_types_test.dart
@@ -147,7 +147,7 @@
     checker(typesTask, getType, compiler);
   } else {
     var element = compiler.mainFunction;
-    var code = compiler.backend.assembleCode(element);
+    var code = compiler.backend.getGeneratedCode(element);
     checker(code);
   }
 }
diff --git a/tests/compiler/dart2js/duplicate_library_test.dart b/tests/compiler/dart2js/duplicate_library_test.dart
index 0164981..80aa6fe 100644
--- a/tests/compiler/dart2js/duplicate_library_test.dart
+++ b/tests/compiler/dart2js/duplicate_library_test.dart
@@ -8,6 +8,7 @@
 import 'dart:async';
 import 'package:async_helper/async_helper.dart';
 import 'package:expect/expect.dart';
+import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/diagnostics/messages.dart' show MessageKind;
 import 'memory_compiler.dart';
 
@@ -30,7 +31,7 @@
       memorySourceFiles: source,
       diagnosticHandler: collector,
       showDiagnostics: true,
-      options: ['--analyze-only', '--analyze-all'],
+      options: [Flags.analyzeOnly, Flags.analyzeAll],
       packageRoot: Uri.parse('memory:pkg/'));
 
   Expect.isTrue(collector.errors.isEmpty);
diff --git a/tests/compiler/dart2js/frontend_checker.dart b/tests/compiler/dart2js/frontend_checker.dart
index 67b88d3..8624cfe 100644
--- a/tests/compiler/dart2js/frontend_checker.dart
+++ b/tests/compiler/dart2js/frontend_checker.dart
@@ -9,6 +9,7 @@
 import 'dart:io';
 
 import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/util/uri_extras.dart'
     show relativize;
 import 'memory_compiler.dart';
@@ -49,7 +50,7 @@
           entryPoint: Uri.parse('memory:$testFileName'),
           memorySourceFiles: {testFileName: testSources[testName]},
           diagnosticHandler: collector,
-          options: ['--analyze-only']..addAll(options),
+          options: [Flags.analyzeOnly]..addAll(options),
           showDiagnostics: verbose,
           cachedCompiler: cachedCompiler);
       var compiler = result.compiler;
diff --git a/tests/compiler/dart2js/in_user_code_test.dart b/tests/compiler/dart2js/in_user_code_test.dart
index 9870491..0a6e13f 100644
--- a/tests/compiler/dart2js/in_user_code_test.dart
+++ b/tests/compiler/dart2js/in_user_code_test.dart
@@ -7,6 +7,7 @@
 import 'dart:async';
 import 'package:async_helper/async_helper.dart';
 import 'package:expect/expect.dart';
+import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/compiler.dart' show Compiler;
 import 'memory_compiler.dart';
 
@@ -47,7 +48,7 @@
   CompilationResult result = await runCompiler(
     entryPoints: entryPoints,
     memorySourceFiles: SOURCE,
-    options: ['--analyze-only', '--analyze-all'],
+    options: [Flags.analyzeOnly, Flags.analyzeAll],
     packageRoot: Uri.parse('memory:pkg/'));
   Compiler compiler = result.compiler;
   expectedResults.forEach((String uri, bool expectedResult) {
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_operators_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_operators_test.dart
index 1665195..877b371 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir_operators_test.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir_operators_test.dart
@@ -11,7 +11,8 @@
 const List<TestEntry> tests = const [
   const TestEntry("main() { return true ? 42 : 'foo'; }"),
   const TestEntry("""
-foo() => foo();
+var x = 1;
+foo() => ++x > 10;
 main() {
   print(foo() ? "hello world" : "bad bad");
 }""","""
@@ -19,16 +20,17 @@
   P.print(V.foo() ? "hello world" : "bad bad");
 }"""),
   const TestEntry("""
-foo() { print('foo'); }
+var x = 1;
+foo() => ++x > 10;
 main() {
   print(foo() ? "hello world" : "bad bad");
 }""","""
 function() {
-  V.foo();
-  P.print("bad bad");
+  P.print(V.foo() ? "hello world" : "bad bad");
 }"""),
   const TestEntry("""
-get foo => foo;
+var x = 1;
+get foo => ++x > 10;
 main() {
   print(foo ? "hello world" : "bad bad");
 }""","""
@@ -36,19 +38,28 @@
   P.print(V.foo() ? "hello world" : "bad bad");
 }"""),
   const TestEntry("""
-get foo => foo;
+var x = 1;
+get foo => ++x > 10;
 main() { print(foo && foo); }
 """, """
 function() {
   P.print(V.foo() ? !!V.foo() : false);
 }"""),
   const TestEntry("""
-get foo => foo;
+var x = 1;
+get foo => ++x > 10;
 main() { print(foo || foo); }
 ""","""
 function() {
   P.print(V.foo() ? true : !!V.foo());
 }"""),
+const TestEntry("""
+get foo => foo;
+main() { print(foo || foo); }
+""","""
+function() {
+  V.foo();
+}"""),
 
 // Needs interceptor calling convention
 //const TestEntry("""
diff --git a/tests/compiler/dart2js/js_spec_optimization_test.dart b/tests/compiler/dart2js/js_spec_optimization_test.dart
index 078104f..8c83b3b 100644
--- a/tests/compiler/dart2js/js_spec_optimization_test.dart
+++ b/tests/compiler/dart2js/js_spec_optimization_test.dart
@@ -70,7 +70,7 @@
     return compiler.runCompiler(uri).then((_) {
       var element = findElement(compiler, 'main');
       var backend = compiler.backend;
-      String generated = backend.assembleCode(element);
+      String generated = backend.getGeneratedCode(element);
 
       for (Match match in directivePattern.allMatches(test)) {
         String directive = match.group(1);
diff --git a/tests/compiler/dart2js/memory_compiler.dart b/tests/compiler/dart2js/memory_compiler.dart
index 06e73144..49664b7 100644
--- a/tests/compiler/dart2js/memory_compiler.dart
+++ b/tests/compiler/dart2js/memory_compiler.dart
@@ -81,6 +81,10 @@
   bool get hasRegularMessages {
     return messages.any((m) => m.kind != Diagnostic.VERBOSE_INFO);
   }
+
+  void clear() {
+    messages.clear();
+  }
 }
 
 class MultiDiagnostics implements CompilerDiagnostics {
diff --git a/tests/compiler/dart2js/message_kind_helper.dart b/tests/compiler/dart2js/message_kind_helper.dart
index af32b58..12089cf 100644
--- a/tests/compiler/dart2js/message_kind_helper.dart
+++ b/tests/compiler/dart2js/message_kind_helper.dart
@@ -7,6 +7,7 @@
 import 'package:expect/expect.dart';
 import 'dart:async';
 
+import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/compiler.dart' show
     Compiler;
 import 'package:compiler/src/dart_backend/dart_backend.dart' show
@@ -84,8 +85,8 @@
     Compiler compiler = compilerFor(
         memorySourceFiles: example,
         diagnosticHandler: new LegacyCompilerDiagnostics(collect),
-        options: ['--analyze-only',
-                  '--enable-experimental-mirrors']..addAll(template.options),
+        options: [Flags.analyzeOnly,
+                  Flags.enableExperimentalMirrors]..addAll(template.options),
         cachedCompiler:
              // TODO(johnniwinther): Remove this restriction when constant
              // values can be computed directly from the expressions.
diff --git a/tests/compiler/dart2js/message_kind_test.dart b/tests/compiler/dart2js/message_kind_test.dart
index efaecc8..3ed7010 100644
--- a/tests/compiler/dart2js/message_kind_test.dart
+++ b/tests/compiler/dart2js/message_kind_test.dart
@@ -26,7 +26,8 @@
         || name == 'COMPILER_CRASHED'
         || name == 'PLEASE_REPORT_THE_CRASH'
         // We cannot provide examples for patch errors.
-        || name.startsWith('PATCH_')) continue;
+        || name.startsWith('PATCH_')
+        || name == 'LIBRARY_NOT_SUPPORTED') continue;
     if (template.examples != null) {
       examples.add(template);
     } else {
diff --git a/tests/compiler/dart2js/metadata_test.dart b/tests/compiler/dart2js/metadata_test.dart
index b304b4f..205c897 100644
--- a/tests/compiler/dart2js/metadata_test.dart
+++ b/tests/compiler/dart2js/metadata_test.dart
@@ -33,9 +33,9 @@
 
   compileAndCheck(source1, name, (compiler, element) {
     compiler.enqueuer.resolution.queueIsClosed = false;
-    Expect.equals(1, length(element.metadata),
+    Expect.equals(1, element.metadata.length,
         'Unexpected metadata count on $element.');
-    PartialMetadataAnnotation annotation = element.metadata.head;
+    PartialMetadataAnnotation annotation = element.metadata.first;
     annotation.ensureResolved(compiler);
     PrimitiveConstantValue value =
         compiler.constants.getConstantValue(annotation.constant);
@@ -53,9 +53,9 @@
 
   compileAndCheck(source2, name, (compiler, element) {
     compiler.enqueuer.resolution.queueIsClosed = false;
-    Expect.equals(2, length(element.metadata));
-    PartialMetadataAnnotation annotation1 = element.metadata.head;
-    PartialMetadataAnnotation annotation2 = element.metadata.tail.head;
+    Expect.equals(2, element.metadata.length);
+    PartialMetadataAnnotation annotation1 = element.metadata.elementAt(0);
+    PartialMetadataAnnotation annotation2 = element.metadata.elementAt(1);
     annotation1.ensureResolved(compiler);
     annotation2.ensureResolved(compiler);
     Expect.isFalse(identical(annotation1, annotation2),
@@ -86,12 +86,12 @@
 
   compileAndCheck(source3, 'Foo', (compiler, element) {
     compiler.enqueuer.resolution.queueIsClosed = false;
-    Expect.equals(0, length(element.metadata));
+    Expect.equals(0, element.metadata.length);
     element.ensureResolved(compiler);
-    Expect.equals(0, length(element.metadata));
+    Expect.equals(0, element.metadata.length);
     element = element.lookupLocalMember(name);
-    Expect.equals(1, length(element.metadata));
-    PartialMetadataAnnotation annotation = element.metadata.head;
+    Expect.equals(1, element.metadata.length);
+    PartialMetadataAnnotation annotation = element.metadata.first;
     annotation.ensureResolved(compiler);
     PrimitiveConstantValue value =
         compiler.constants.getConstantValue(annotation.constant);
@@ -111,13 +111,13 @@
 
   compileAndCheck(source4, 'Foo', (compiler, element) {
     compiler.enqueuer.resolution.queueIsClosed = false;
-    Expect.equals(0, length(element.metadata));
+    Expect.equals(0, element.metadata.length);
     element.ensureResolved(compiler);
-    Expect.equals(0, length(element.metadata));
+    Expect.equals(0, element.metadata.length);
     element = element.lookupLocalMember(name);
-    Expect.equals(2, length(element.metadata));
-    PartialMetadataAnnotation annotation1 = element.metadata.head;
-    PartialMetadataAnnotation annotation2 = element.metadata.tail.head;
+    Expect.equals(2, element.metadata.length);
+    PartialMetadataAnnotation annotation1 = element.metadata.elementAt(0);
+    PartialMetadataAnnotation annotation2 = element.metadata.elementAt(1);
     annotation1.ensureResolved(compiler);
     annotation2.ensureResolved(compiler);
     Expect.isFalse(identical(annotation1, annotation2),
@@ -152,7 +152,7 @@
 void testLibraryTags() {
   void compileAndCheckLibrary(
       String source,
-      Link<MetadataAnnotation> extractMetadata(LibraryElement element)) {
+      List<MetadataAnnotation> extractMetadata(LibraryElement element)) {
     Uri partUri = new Uri(scheme: 'source', path: 'part.dart');
     String partSource = '@native part of foo;';
 
@@ -170,10 +170,10 @@
       LibraryElement element = compiler.libraryLoader.lookupLibrary(uri);
       Expect.isNotNull(element, 'Cannot find $uri');
 
-      Link<MetadataAnnotation> metadata = extractMetadata(element);
-      Expect.equals(1, length(metadata));
+      List<MetadataAnnotation> metadata = extractMetadata(element);
+      Expect.equals(1, metadata.length);
 
-      PartialMetadataAnnotation annotation = metadata.head;
+      PartialMetadataAnnotation annotation = metadata.first;
       annotation.ensureResolved(compiler);
       PrimitiveConstantValue value =
           compiler.constants.getConstantValue(annotation.constant);
diff --git a/tests/compiler/dart2js/minimal_resolution_test.dart b/tests/compiler/dart2js/minimal_resolution_test.dart
new file mode 100644
index 0000000..ca61f80
--- /dev/null
+++ b/tests/compiler/dart2js/minimal_resolution_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2015, 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 elements are not needlessly required by dart2js.
+
+import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/compiler.dart';
+import 'package:expect/expect.dart';
+import 'memory_compiler.dart';
+
+main() {
+  asyncTest(() async {
+    await analyze('main() {}');
+    await analyze('main() => proxy;', proxyConstant: true);
+  });
+}
+
+analyze(String code,
+        {bool proxyConstant: false}) async {
+  CompilationResult result = await runCompiler(
+      memorySourceFiles: {'main.dart': code},
+      options: ['--analyze-only']);
+  Expect.isTrue(result.isSuccess);
+  Compiler compiler = result.compiler;
+  Expect.equals(proxyConstant, compiler.proxyConstant != null);
+}
diff --git a/tests/compiler/dart2js/mirrors_test.dart b/tests/compiler/dart2js/mirrors_test.dart
index 2c7b09f..7d3c48c 100644
--- a/tests/compiler/dart2js/mirrors_test.dart
+++ b/tests/compiler/dart2js/mirrors_test.dart
@@ -183,7 +183,8 @@
   Expect.isTrue(metadata is InstanceMirror);
   Expect.isFalse(metadata.hasReflectee);
   Expect.throws(() => metadata.reflectee, (_) => true);
-  Expect.isTrue(metadata is CommentInstanceMirror);
+  Expect.isTrue(metadata is CommentInstanceMirror,
+      "Unexpected metadata: $metadata");
   Expect.equals(commentType.originalDeclaration, metadata.type);
   Expect.isTrue(metadata.isDocComment);
   Expect.stringEquals(
diff --git a/tests/compiler/dart2js/missing_file_test.dart b/tests/compiler/dart2js/missing_file_test.dart
index efbc43f..457a4f0 100644
--- a/tests/compiler/dart2js/missing_file_test.dart
+++ b/tests/compiler/dart2js/missing_file_test.dart
@@ -14,35 +14,73 @@
 
 const MEMORY_SOURCE_FILES = const {
   'main.dart': '''
-
 import 'foo.dart';
+main() {}
+''',
 
+'bar.dart': '''
+import 'dart:foo';
+main() {}
+''',
+
+'baz.dart': '''
+import 'dart:io';
 main() {}
 ''',
 };
 
-Future runTest(Uri main, MessageKind expectedMessageKind) async {
-  print("\n\n\n");
+Future runTest(Uri main,
+               {MessageKind error,
+                MessageKind info}) async {
+  print("----\nentry-point: $main\n");
 
   DiagnosticCollector diagnostics = new DiagnosticCollector();
   OutputCollector output = new OutputCollector();
   await runCompiler(
+      entryPoint: main,
       memorySourceFiles: MEMORY_SOURCE_FILES,
       diagnosticHandler: diagnostics,
       outputProvider: output);
 
   Expect.isFalse(output.hasExtraOutput);
-  Expect.equals(1, diagnostics.errors.length);
-  Expect.equals(expectedMessageKind, diagnostics.errors.first.message.kind);
+  Expect.equals(error != null ? 1 : 0, diagnostics.errors.length);
+  if (error != null) {
+    Expect.equals(error, diagnostics.errors.first.message.kind);
+  }
+  Expect.equals(info != null ? 1 : 0, diagnostics.infos.length);
+  if (info != null) {
+    Expect.equals(info, diagnostics.infos.first.message.kind);
+  }
+  Expect.equals(0, diagnostics.warnings.length);
+  Expect.equals(0, diagnostics.hints.length);
 }
 
 void main() {
   asyncTest(() async {
     await runTest(
-        Uri.parse('memory:main.dart'), MessageKind.READ_SCRIPT_ERROR);
+        Uri.parse('memory:main.dart'),
+        error: MessageKind.READ_SCRIPT_ERROR);
+
     await runTest(
-        Uri.parse('memory:foo.dart'), MessageKind.READ_SCRIPT_ERROR);
+        Uri.parse('memory:foo.dart'),
+        error: MessageKind.READ_SELF_ERROR);
+
     await runTest(
-        Uri.parse('dart:foo'), MessageKind.READ_SCRIPT_ERROR);
+        Uri.parse('dart:foo'),
+        error: MessageKind.LIBRARY_NOT_FOUND);
+
+    await runTest(
+        Uri.parse('dart:io'),
+        error: MessageKind.LIBRARY_NOT_SUPPORTED,
+        info: MessageKind.DISALLOWED_LIBRARY_IMPORT);
+
+    await runTest(
+        Uri.parse('memory:bar.dart'),
+        error: MessageKind.LIBRARY_NOT_FOUND);
+
+    await runTest(
+        Uri.parse('memory:baz.dart'),
+        error: MessageKind.LIBRARY_NOT_SUPPORTED,
+        info: MessageKind.DISALLOWED_LIBRARY_IMPORT);
   });
 }
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index cda5aa6..b52951c 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -279,7 +279,7 @@
   }
 
   Uri translateResolvedUri(LibraryElement importingLibrary,
-                           Uri resolvedUri, Node node) => resolvedUri;
+                           Uri resolvedUri, Spannable spannable) => resolvedUri;
 
   // The mock library doesn't need any patches.
   Uri resolvePatchUri(String dartLibraryName) {
@@ -370,7 +370,8 @@
   }
   if (foundIterator.hasNext) {
     do {
-      print('Additional $kind "${foundIterator.next()}"');
+      WarningMessage message = foundIterator.next();
+      print('Additional $kind "${message}: ${message.message}"');
     } while (foundIterator.hasNext);
     fail('Too many ${kind}s');
   }
@@ -436,3 +437,31 @@
 
   bool get hasNode => false;
 }
+
+// TODO(herhut): Disallow warnings and errors during compilation by default.
+MockCompiler compilerFor(String code, Uri uri,
+                         {bool analyzeAll: false,
+                          bool analyzeOnly: false,
+                          Map<String, String> coreSource,
+                          bool disableInlining: true,
+                          bool minify: false,
+                          bool trustTypeAnnotations: false,
+                          bool enableTypeAssertions: false,
+                          int expectedErrors,
+                          int expectedWarnings,
+                          api.CompilerOutputProvider outputProvider}) {
+  MockCompiler compiler = new MockCompiler.internal(
+      analyzeAll: analyzeAll,
+      analyzeOnly: analyzeOnly,
+      coreSource: coreSource,
+      disableInlining: disableInlining,
+      enableMinification: minify,
+      trustTypeAnnotations: trustTypeAnnotations,
+      enableTypeAssertions: enableTypeAssertions,
+      expectedErrors: expectedErrors,
+      expectedWarnings: expectedWarnings,
+      outputProvider: outputProvider);
+  compiler.registerSource(uri, code);
+  compiler.diagnosticHandler = createHandler(compiler, code);
+  return compiler;
+}
diff --git a/tests/compiler/dart2js/mock_libraries.dart b/tests/compiler/dart2js/mock_libraries.dart
index b10aedb..5de30cb 100644
--- a/tests/compiler/dart2js/mock_libraries.dart
+++ b/tests/compiler/dart2js/mock_libraries.dart
@@ -45,7 +45,14 @@
       }''',
   'identical': 'bool identical(Object a, Object b) { return true; }',
   'int': 'abstract class int extends num { }',
-  'Iterable': 'abstract class Iterable {}',
+  'Iterable': '''
+      abstract class Iterable<E> {
+          Iterator<E> get iterator => null;
+      }''',
+  'Iterator': '''
+      abstract class Iterator<E> {
+          E get current => null;
+      }''',
   'LinkedHashMap': r'''
       class LinkedHashMap {
         factory LinkedHashMap._empty() => null;
@@ -54,7 +61,7 @@
         static _makeLiteral(elements) => null;
       }''',
   'List': r'''
-      class List<E> {
+      class List<E> extends Iterable<E> {
         var length;
         List([length]);
         List.filled(length, element);
@@ -286,6 +293,7 @@
             E removeAt(index) => this[0];
             E elementAt(index) => this[0];
             E singleWhere(f) => this[0];
+            Iterator<E> get iterator => null; 
           }''',
   'JSBool': 'class JSBool extends Interceptor implements bool {}',
   'JSDouble': 'class JSDouble extends JSNumber implements double {}',
@@ -384,7 +392,7 @@
 
 const Map<String, String> DEFAULT_ASYNC_LIBRARY = const <String, String>{
   'DeferredLibrary': 'class DeferredLibrary {}',
-  'Future': 
+  'Future':
       '''
       class Future<T> {
         Future.value([value]);
@@ -434,5 +442,5 @@
         : _entries = const [], _nestedMaps = const [];
     V operator[](K k) => null;
   }''',
-  '_version': 'const _version = "0.0.1";',
+  '_version': 'const _version = "0.0.1+1";',
 };
diff --git a/tests/compiler/dart2js/patch_test.dart b/tests/compiler/dart2js/patch_test.dart
index 1981842..6077db8 100644
--- a/tests/compiler/dart2js/patch_test.dart
+++ b/tests/compiler/dart2js/patch_test.dart
@@ -125,24 +125,49 @@
   return element;
 }
 
-testPatchFunction() {
-  asyncTest(() => applyPatch(
+Future testPatchFunction() async {
+  var compiler = await applyPatch(
       "external test();",
-      "@patch test() { return 'string'; } ").then((compiler) {
-    ensure(compiler, "test", compiler.coreLibrary.find,
-           expectIsPatched: true, checkHasBody: true);
-    ensure(compiler, "test", compiler.coreLibrary.patch.find,
-           expectIsPatch: true, checkHasBody: true);
+      "@patch test() { return 'string'; } ");
+  ensure(compiler, "test", compiler.coreLibrary.find,
+         expectIsPatched: true, checkHasBody: true);
+  ensure(compiler, "test", compiler.coreLibrary.patch.find,
+         expectIsPatch: true, checkHasBody: true);
 
-    Expect.isTrue(compiler.warnings.isEmpty,
-                  "Unexpected warnings: ${compiler.warnings}");
-    Expect.isTrue(compiler.errors.isEmpty,
-                  "Unexpected errors: ${compiler.errors}");
-  }));
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  Expect.isTrue(compiler.errors.isEmpty,
+                "Unexpected errors: ${compiler.errors}");
+}
+
+Future testPatchFunctionMetadata() async {
+  var compiler = await applyPatch(
+      """
+      const a = 0;
+      @a external test();
+      """,
+      """
+      const b = 1;
+      @patch @b test() {}
+      """);
+  Element origin = ensure(compiler, "test", compiler.coreLibrary.find,
+         expectIsPatched: true, checkHasBody: true);
+  Element patch = ensure(compiler, "test", compiler.coreLibrary.patch.find,
+         expectIsPatch: true, checkHasBody: true);
+
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  Expect.isTrue(compiler.errors.isEmpty,
+                "Unexpected errors: ${compiler.errors}");
+
+  Expect.equals(1, origin.metadata.length,
+                "Unexpected origin metadata: ${origin.metadata}.");
+  Expect.equals(3, patch.metadata.length,
+                "Unexpected patch metadata: ${patch.metadata}.");
 }
 
 
-testPatchVersioned() {
+Future testPatchVersioned() async {
   String fullPatch = "test(){return 'string';}";
   String lazyPatch = "test(){return 'new and improved string';}";
 
@@ -152,64 +177,64 @@
       @patch_lazy $lazyPatch
       """;
 
-  test(String patchVersion,
+  Future test(String patchVersion,
        {String patchText,
         bool expectIsPatched: true,
         String expectedError,
         String defaultPatch: '',
-        String expectedInternalError}) {
-    asyncTest(() => applyPatch(
+        String expectedInternalError}) async {
+    return applyPatch(
         "external test();",
         """
         $defaultPatch
         $patchSource
         """,
         patchVersion: patchVersion).then((compiler) {
-      Element origin =
-          ensure(compiler, "test", compiler.coreLibrary.find,
-               expectIsPatched: expectIsPatched, checkHasBody: true);
-      if (expectIsPatched) {
-        AstElement patch =
-            ensure(compiler, "test", compiler.coreLibrary.patch.find,
-                expectIsPatch: true, checkHasBody: true);
-        Expect.equals(origin.patch, patch);
-        Expect.equals(patch.origin, origin);
-        Expect.equals(patchText, patch.node.toString());
-      }
+        Element origin =
+            ensure(compiler, "test", compiler.coreLibrary.find,
+                 expectIsPatched: expectIsPatched, checkHasBody: true);
+        if (expectIsPatched) {
+          AstElement patch =
+              ensure(compiler, "test", compiler.coreLibrary.patch.find,
+                  expectIsPatch: true, checkHasBody: true);
+          Expect.equals(origin.patch, patch);
+          Expect.equals(patch.origin, origin);
+          Expect.equals(patchText, patch.node.toString());
+        }
 
-      compiler.analyzeElement(origin);
-      compiler.enqueuer.resolution.emptyDeferredTaskQueue();
+        compiler.analyzeElement(origin);
+        compiler.enqueuer.resolution.emptyDeferredTaskQueue();
 
-      Expect.isTrue(compiler.warnings.isEmpty,
-                    "Unexpected warnings: ${compiler.warnings}");
-      if (expectedError != null) {
-        Expect.equals(expectedError,
-                      compiler.errors[0].message.toString());
-      } else {
-        Expect.isTrue(compiler.errors.isEmpty,
-                      "Unexpected errors: ${compiler.errors}");
-      }
-    }).catchError((error) {
-      if (expectedInternalError != null) {
-        Expect.equals(
-            'Internal Error: $expectedInternalError', error.toString());
-      } else {
-        throw error;
-      }
-    }));
+        Expect.isTrue(compiler.warnings.isEmpty,
+                      "Unexpected warnings: ${compiler.warnings}");
+        if (expectedError != null) {
+          Expect.equals(expectedError,
+                        compiler.errors[0].message.toString());
+        } else {
+          Expect.isTrue(compiler.errors.isEmpty,
+                        "Unexpected errors: ${compiler.errors}");
+        }
+      }).catchError((error) {
+        if (expectedInternalError != null) {
+          Expect.equals(
+              'Internal Error: $expectedInternalError', error.toString());
+        } else {
+          throw error;
+        }
+      });
   }
 
-  test('full', patchText: fullPatch);
-  test('lazy', patchText: lazyPatch);
-  test('unknown', expectIsPatched: false,
+  await test('full', patchText: fullPatch);
+  await test('lazy', patchText: lazyPatch);
+  await test('unknown', expectIsPatched: false,
        expectedError: 'External method without an implementation.');
-  test('full',
+  await test('full',
        defaultPatch: "@patch test(){}",
        expectedInternalError: "Trying to patch a function more than once.");
 }
 
-testPatchConstructor() {
-  asyncTest(() => applyPatch(
+Future testPatchConstructor() async {
+  var compiler = await applyPatch(
       """
       class Class {
         external Class();
@@ -219,35 +244,34 @@
       @patch class Class {
         @patch Class();
       }
-      """).then((compiler) {
-    var classOrigin = ensure(compiler, "Class", compiler.coreLibrary.find,
-                             expectIsPatched: true);
-    classOrigin.ensureResolved(compiler);
-    var classPatch = ensure(compiler, "Class", compiler.coreLibrary.patch.find,
-                            expectIsPatch: true);
+      """);
+  var classOrigin = ensure(compiler, "Class", compiler.coreLibrary.find,
+                           expectIsPatched: true);
+  classOrigin.ensureResolved(compiler);
+  var classPatch = ensure(compiler, "Class", compiler.coreLibrary.patch.find,
+                          expectIsPatch: true);
 
-    Expect.equals(classPatch, classOrigin.patch);
-    Expect.equals(classOrigin, classPatch.origin);
+  Expect.equals(classPatch, classOrigin.patch);
+  Expect.equals(classOrigin, classPatch.origin);
 
-    var constructorOrigin = ensure(compiler, "",
-                                   (name) => classOrigin.localLookup(name),
-                                   expectIsPatched: true);
-    var constructorPatch = ensure(compiler, "",
-                                  (name) => classPatch.localLookup(name),
-                                  expectIsPatch: true);
+  var constructorOrigin = ensure(compiler, "",
+                                 (name) => classOrigin.localLookup(name),
+                                 expectIsPatched: true);
+  var constructorPatch = ensure(compiler, "",
+                                (name) => classPatch.localLookup(name),
+                                expectIsPatch: true);
 
-    Expect.equals(constructorPatch, constructorOrigin.patch);
-    Expect.equals(constructorOrigin, constructorPatch.origin);
+  Expect.equals(constructorPatch, constructorOrigin.patch);
+  Expect.equals(constructorOrigin, constructorPatch.origin);
 
-    Expect.isTrue(compiler.warnings.isEmpty,
-                  "Unexpected warnings: ${compiler.warnings}");
-    Expect.isTrue(compiler.errors.isEmpty,
-                  "Unexpected errors: ${compiler.errors}");
-  }));
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  Expect.isTrue(compiler.errors.isEmpty,
+                "Unexpected errors: ${compiler.errors}");
 }
 
-testPatchRedirectingConstructor() {
-  asyncTest(() => applyPatch(
+Future testPatchRedirectingConstructor() async {
+  var compiler = await applyPatch(
       """
       class Class {
         Class(x) : this._(x, false);
@@ -259,42 +283,41 @@
       @patch class Class {
         @patch Class._(x, y) { print('$x,$y'); }
       }
-      """).then((compiler) {
-    var classOrigin = ensure(compiler, "Class", compiler.coreLibrary.find,
-                             expectIsPatched: true);
-    classOrigin.ensureResolved(compiler);
+      """);
+  var classOrigin = ensure(compiler, "Class", compiler.coreLibrary.find,
+                           expectIsPatched: true);
+  classOrigin.ensureResolved(compiler);
 
-    var classPatch = ensure(compiler, "Class", compiler.coreLibrary.patch.find,
-                            expectIsPatch: true);
+  var classPatch = ensure(compiler, "Class", compiler.coreLibrary.patch.find,
+                          expectIsPatch: true);
 
-    Expect.equals(classOrigin, classPatch.origin);
-    Expect.equals(classPatch, classOrigin.patch);
+  Expect.equals(classOrigin, classPatch.origin);
+  Expect.equals(classPatch, classOrigin.patch);
 
-    var constructorRedirecting =
-        ensure(compiler, "",
-               (name) => classOrigin.localLookup(name));
-    var constructorOrigin =
-        ensure(compiler, "_",
-               (name) => classOrigin.localLookup(name),
-               expectIsPatched: true);
-    var constructorPatch =
-        ensure(compiler, "_",
-               (name) => classPatch.localLookup(name),
-               expectIsPatch: true);
-    Expect.equals(constructorOrigin, constructorPatch.origin);
-    Expect.equals(constructorPatch, constructorOrigin.patch);
+  var constructorRedirecting =
+      ensure(compiler, "",
+             (name) => classOrigin.localLookup(name));
+  var constructorOrigin =
+      ensure(compiler, "_",
+             (name) => classOrigin.localLookup(name),
+             expectIsPatched: true);
+  var constructorPatch =
+      ensure(compiler, "_",
+             (name) => classPatch.localLookup(name),
+             expectIsPatch: true);
+  Expect.equals(constructorOrigin, constructorPatch.origin);
+  Expect.equals(constructorPatch, constructorOrigin.patch);
 
-    compiler.resolver.resolve(constructorRedirecting);
+  compiler.resolver.resolve(constructorRedirecting);
 
-    Expect.isTrue(compiler.warnings.isEmpty,
-                  "Unexpected warnings: ${compiler.warnings}");
-    Expect.isTrue(compiler.errors.isEmpty,
-                  "Unexpected errors: ${compiler.errors}");
-   }));
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  Expect.isTrue(compiler.errors.isEmpty,
+                "Unexpected errors: ${compiler.errors}");
 }
 
-testPatchMember() {
-  asyncTest(() => applyPatch(
+Future testPatchMember() async {
+  var compiler = await applyPatch(
       """
       class Class {
         external String toString();
@@ -304,27 +327,26 @@
       @patch class Class {
         @patch String toString() => 'string';
       }
-      """).then((compiler) {
-    var container = ensure(compiler, "Class", compiler.coreLibrary.find,
-                           expectIsPatched: true);
-    container.parseNode(compiler);
-    ensure(compiler, "Class", compiler.coreLibrary.patch.find,
-           expectIsPatch: true);
+      """);
+  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
+                         expectIsPatched: true);
+  container.parseNode(compiler);
+  ensure(compiler, "Class", compiler.coreLibrary.patch.find,
+         expectIsPatch: true);
 
-    ensure(compiler, "toString", container.lookupLocalMember,
-           expectIsPatched: true, checkHasBody: true);
-    ensure(compiler, "toString", container.patch.lookupLocalMember,
-           expectIsPatch: true, checkHasBody: true);
+  ensure(compiler, "toString", container.lookupLocalMember,
+         expectIsPatched: true, checkHasBody: true);
+  ensure(compiler, "toString", container.patch.lookupLocalMember,
+         expectIsPatch: true, checkHasBody: true);
 
-    Expect.isTrue(compiler.warnings.isEmpty,
-                  "Unexpected warnings: ${compiler.warnings}");
-    Expect.isTrue(compiler.errors.isEmpty,
-                  "Unexpected errors: ${compiler.errors}");
-  }));
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  Expect.isTrue(compiler.errors.isEmpty,
+                "Unexpected errors: ${compiler.errors}");
 }
 
-testPatchGetter() {
-  asyncTest(() => applyPatch(
+Future testPatchGetter() async {
+  var compiler = await applyPatch(
       """
       class Class {
         external int get field;
@@ -334,32 +356,31 @@
       @patch class Class {
         @patch int get field => 5;
       }
-      """).then((compiler) {
-    var container = ensure(compiler, "Class", compiler.coreLibrary.find,
-                           expectIsPatched: true);
-    container.parseNode(compiler);
-    ensure(compiler,
-           "field",
-           container.lookupLocalMember,
-           expectIsGetter: true,
-           expectIsPatched: true,
-           checkHasBody: true);
-    ensure(compiler,
-           "field",
-           container.patch.lookupLocalMember,
-           expectIsGetter: true,
-           expectIsPatch: true,
-           checkHasBody: true);
+      """);
+  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
+                         expectIsPatched: true);
+  container.parseNode(compiler);
+  ensure(compiler,
+         "field",
+         container.lookupLocalMember,
+         expectIsGetter: true,
+         expectIsPatched: true,
+         checkHasBody: true);
+  ensure(compiler,
+         "field",
+         container.patch.lookupLocalMember,
+         expectIsGetter: true,
+         expectIsPatch: true,
+         checkHasBody: true);
 
-    Expect.isTrue(compiler.warnings.isEmpty,
-                  "Unexpected warnings: ${compiler.warnings}");
-    Expect.isTrue(compiler.errors.isEmpty,
-                  "Unexpected errors: ${compiler.errors}");
-  }));
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  Expect.isTrue(compiler.errors.isEmpty,
+                "Unexpected errors: ${compiler.errors}");
 }
 
-testRegularMember() {
-  asyncTest(() => applyPatch(
+Future testRegularMember() async {
+  var compiler = await applyPatch(
       """
       class Class {
         void regular() {}
@@ -368,27 +389,26 @@
       """
       @patch class Class {
       }
-      """).then((compiler) {
-    var container = ensure(compiler, "Class", compiler.coreLibrary.find,
-                           expectIsPatched: true);
-    container.parseNode(compiler);
-    ensure(compiler, "Class", compiler.coreLibrary.patch.find,
-           expectIsPatch: true);
+      """);
+  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
+                         expectIsPatched: true);
+  container.parseNode(compiler);
+  ensure(compiler, "Class", compiler.coreLibrary.patch.find,
+         expectIsPatch: true);
 
-    ensure(compiler, "regular", container.lookupLocalMember,
-           checkHasBody: true, expectIsRegular: true);
-    ensure(compiler, "regular", container.patch.lookupLocalMember,
-           checkHasBody: true, expectIsRegular: true);
+  ensure(compiler, "regular", container.lookupLocalMember,
+         checkHasBody: true, expectIsRegular: true);
+  ensure(compiler, "regular", container.patch.lookupLocalMember,
+         checkHasBody: true, expectIsRegular: true);
 
-    Expect.isTrue(compiler.warnings.isEmpty,
-                  "Unexpected warnings: ${compiler.warnings}");
-    Expect.isTrue(compiler.errors.isEmpty,
-                  "Unexpected errors: ${compiler.errors}");
-  }));
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  Expect.isTrue(compiler.errors.isEmpty,
+                "Unexpected errors: ${compiler.errors}");
 }
 
-testGhostMember() {
-  asyncTest(() => applyPatch(
+Future testGhostMember() async {
+  var compiler = await applyPatch(
       """
       class Class {
       }
@@ -397,47 +417,45 @@
       @patch class Class {
         void ghost() {}
       }
-      """).then((compiler) {
-    var container = ensure(compiler, "Class", compiler.coreLibrary.find,
-                           expectIsPatched: true);
-    container.parseNode(compiler);
-    ensure(compiler, "Class", compiler.coreLibrary.patch.find,
-           expectIsPatch: true);
+      """);
+  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
+                         expectIsPatched: true);
+  container.parseNode(compiler);
+  ensure(compiler, "Class", compiler.coreLibrary.patch.find,
+         expectIsPatch: true);
 
-    ensure(compiler, "ghost", container.lookupLocalMember,
-           expectIsFound: false);
-    ensure(compiler, "ghost", container.patch.lookupLocalMember,
-           checkHasBody: true, expectIsRegular: true);
+  ensure(compiler, "ghost", container.lookupLocalMember,
+         expectIsFound: false);
+  ensure(compiler, "ghost", container.patch.lookupLocalMember,
+         checkHasBody: true, expectIsRegular: true);
 
-    Expect.isTrue(compiler.warnings.isEmpty,
-                  "Unexpected warnings: ${compiler.warnings}");
-    Expect.isTrue(compiler.errors.isEmpty,
-                  "Unexpected errors: ${compiler.errors}");
-  }));
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  Expect.isTrue(compiler.errors.isEmpty,
+                "Unexpected errors: ${compiler.errors}");
 }
 
-testInjectFunction() {
-  asyncTest(() => applyPatch(
+Future testInjectFunction() async {
+  var compiler = await applyPatch(
       "",
-      "int _function() => 5;").then((compiler) {
-    ensure(compiler,
-           "_function",
-           compiler.coreLibrary.find,
-           expectIsFound: false);
-    ensure(compiler,
-           "_function",
-           compiler.coreLibrary.patch.find,
-           checkHasBody: true, expectIsRegular: true);
+      "int _function() => 5;");
+  ensure(compiler,
+         "_function",
+         compiler.coreLibrary.find,
+         expectIsFound: false);
+  ensure(compiler,
+         "_function",
+         compiler.coreLibrary.patch.find,
+         checkHasBody: true, expectIsRegular: true);
 
-    Expect.isTrue(compiler.warnings.isEmpty,
-                  "Unexpected warnings: ${compiler.warnings}");
-    Expect.isTrue(compiler.errors.isEmpty,
-                  "Unexpected errors: ${compiler.errors}");
-  }));
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  Expect.isTrue(compiler.errors.isEmpty,
+                "Unexpected errors: ${compiler.errors}");
 }
 
-testPatchSignatureCheck() {
-  asyncTest(() => applyPatch(
+Future testPatchSignatureCheck() async {
+  var compiler = await applyPatch(
       """
       class Class {
         external String method1();
@@ -467,78 +485,76 @@
         @patch void method10([int str]) {}
         @patch void method11({int str}) {}
       }
-      """).then((compiler) {
-    var container = ensure(compiler, "Class", compiler.coreLibrary.find,
-                           expectIsPatched: true);
-    container.ensureResolved(compiler);
-    container.parseNode(compiler);
+      """);
+  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
+                         expectIsPatched: true);
+  container.ensureResolved(compiler);
+  container.parseNode(compiler);
 
-    void expect(String methodName, List infos, List errors) {
-      compiler.clearMessages();
-      compiler.resolver.resolveMethodElement(
-          ensure(compiler, methodName, container.lookupLocalMember,
-              expectIsPatched: true, checkHasBody: true));
-      Expect.equals(0, compiler.warnings.length);
-      Expect.equals(infos.length, compiler.infos.length,
-                    "Unexpected infos: ${compiler.infos} on $methodName");
-      for (int i = 0 ; i < infos.length ; i++) {
-        Expect.equals(infos[i], compiler.infos[i].message.kind);
-      }
-      Expect.equals(errors.length, compiler.errors.length,
-                    "Unexpected errors: ${compiler.errors} on $methodName");
-      for (int i = 0 ; i < errors.length ; i++) {
-        Expect.equals(errors[i], compiler.errors[i].message.kind);
-      }
+  void expect(String methodName, List infos, List errors) {
+    compiler.clearMessages();
+    compiler.resolver.resolveMethodElement(
+        ensure(compiler, methodName, container.lookupLocalMember,
+            expectIsPatched: true, checkHasBody: true));
+    Expect.equals(0, compiler.warnings.length);
+    Expect.equals(infos.length, compiler.infos.length,
+                  "Unexpected infos: ${compiler.infos} on $methodName");
+    for (int i = 0 ; i < infos.length ; i++) {
+      Expect.equals(infos[i], compiler.infos[i].message.kind);
     }
+    Expect.equals(errors.length, compiler.errors.length,
+                  "Unexpected errors: ${compiler.errors} on $methodName");
+    for (int i = 0 ; i < errors.length ; i++) {
+      Expect.equals(errors[i], compiler.errors[i].message.kind);
+    }
+  }
 
-    expect("method1", [], [MessageKind.PATCH_RETURN_TYPE_MISMATCH]);
-    expect("method2", [],
-           [MessageKind.PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH]);
-    expect("method3", [MessageKind.PATCH_POINT_TO_PARAMETER],
-                      [MessageKind.PATCH_PARAMETER_MISMATCH]);
-    expect("method4", [],
-           [MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH]);
-    expect("method5", [],
-           [MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH]);
-    expect("method6", [],
-           [MessageKind.PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH]);
-    expect("method7", [MessageKind.PATCH_POINT_TO_PARAMETER],
-                      [MessageKind.PATCH_PARAMETER_MISMATCH]);
-    expect("method8", [MessageKind.PATCH_POINT_TO_PARAMETER],
-                      [MessageKind.PATCH_PARAMETER_MISMATCH]);
-    expect("method9", [MessageKind.PATCH_POINT_TO_PARAMETER],
-                      [MessageKind.PATCH_PARAMETER_TYPE_MISMATCH]);
-    expect("method10", [MessageKind.PATCH_POINT_TO_PARAMETER],
-                       [MessageKind.PATCH_PARAMETER_TYPE_MISMATCH]);
-    expect("method11", [MessageKind.PATCH_POINT_TO_PARAMETER],
-                       [MessageKind.PATCH_PARAMETER_TYPE_MISMATCH]);
-  }));
+  expect("method1", [], [MessageKind.PATCH_RETURN_TYPE_MISMATCH]);
+  expect("method2", [],
+         [MessageKind.PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH]);
+  expect("method3", [MessageKind.PATCH_POINT_TO_PARAMETER],
+                    [MessageKind.PATCH_PARAMETER_MISMATCH]);
+  expect("method4", [],
+         [MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH]);
+  expect("method5", [],
+         [MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH]);
+  expect("method6", [],
+         [MessageKind.PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH]);
+  expect("method7", [MessageKind.PATCH_POINT_TO_PARAMETER],
+                    [MessageKind.PATCH_PARAMETER_MISMATCH]);
+  expect("method8", [MessageKind.PATCH_POINT_TO_PARAMETER],
+                    [MessageKind.PATCH_PARAMETER_MISMATCH]);
+  expect("method9", [MessageKind.PATCH_POINT_TO_PARAMETER],
+                    [MessageKind.PATCH_PARAMETER_TYPE_MISMATCH]);
+  expect("method10", [MessageKind.PATCH_POINT_TO_PARAMETER],
+                     [MessageKind.PATCH_PARAMETER_TYPE_MISMATCH]);
+  expect("method11", [MessageKind.PATCH_POINT_TO_PARAMETER],
+                     [MessageKind.PATCH_PARAMETER_TYPE_MISMATCH]);
 }
 
-testExternalWithoutImplementationTopLevel() {
-  asyncTest(() => applyPatch(
+Future testExternalWithoutImplementationTopLevel() async {
+  var compiler = await applyPatch(
       """
       external void foo();
       """,
       """
       // @patch void foo() {}
-      """).then((compiler) {
-    var function = ensure(compiler, "foo", compiler.coreLibrary.find);
-    compiler.resolver.resolve(function);
-    Expect.isTrue(compiler.warnings.isEmpty,
-                  "Unexpected warnings: ${compiler.warnings}");
-    print('testExternalWithoutImplementationTopLevel:${compiler.errors}');
-    Expect.equals(1, compiler.errors.length);
-    Expect.isTrue(
-        compiler.errors[0].message.kind ==
-            MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
-    Expect.stringEquals('External method without an implementation.',
-                        compiler.errors[0].message.toString());
-  }));
+      """);
+  var function = ensure(compiler, "foo", compiler.coreLibrary.find);
+  compiler.resolver.resolve(function);
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  print('testExternalWithoutImplementationTopLevel:${compiler.errors}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind ==
+          MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
+  Expect.stringEquals('External method without an implementation.',
+                      compiler.errors[0].message.toString());
 }
 
-testExternalWithoutImplementationMember() {
-  asyncTest(() => applyPatch(
+Future testExternalWithoutImplementationMember() async {
+  var compiler = await applyPatch(
       """
       class Class {
         external void foo();
@@ -548,63 +564,60 @@
       @patch class Class {
         // @patch void foo() {}
       }
-      """).then((compiler) {
-    var container = ensure(compiler, "Class", compiler.coreLibrary.find,
-                           expectIsPatched: true);
-    container.parseNode(compiler);
+      """);
+  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
+                         expectIsPatched: true);
+  container.parseNode(compiler);
 
-    compiler.warnings.clear();
-    compiler.errors.clear();
-    compiler.resolver.resolveMethodElement(
-        ensure(compiler, "foo", container.lookupLocalMember));
-    Expect.isTrue(compiler.warnings.isEmpty,
-                  "Unexpected warnings: ${compiler.warnings}");
-    print('testExternalWithoutImplementationMember:${compiler.errors}');
-    Expect.equals(1, compiler.errors.length);
-    Expect.isTrue(
-        compiler.errors[0].message.kind ==
-            MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
-    Expect.stringEquals('External method without an implementation.',
-                        compiler.errors[0].message.toString());
-  }));
+  compiler.warnings.clear();
+  compiler.errors.clear();
+  compiler.resolver.resolveMethodElement(
+      ensure(compiler, "foo", container.lookupLocalMember));
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  print('testExternalWithoutImplementationMember:${compiler.errors}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind ==
+          MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
+  Expect.stringEquals('External method without an implementation.',
+                      compiler.errors[0].message.toString());
 }
 
-testIsSubclass() {
-  asyncTest(() => applyPatch(
+Future testIsSubclass() async {
+  var compiler = await applyPatch(
       """
       class A {}
       """,
       """
       @patch class A {}
-      """).then((compiler) {
-    ClassElement cls = ensure(compiler, "A", compiler.coreLibrary.find,
-                              expectIsPatched: true);
-    ClassElement patch = cls.patch;
-    Expect.isTrue(cls != patch);
-    Expect.isTrue(cls.isSubclassOf(patch));
-    Expect.isTrue(patch.isSubclassOf(cls));
-  }));
+      """);
+  ClassElement cls = ensure(compiler, "A", compiler.coreLibrary.find,
+                            expectIsPatched: true);
+  ClassElement patch = cls.patch;
+  Expect.isTrue(cls != patch);
+  Expect.isTrue(cls.isSubclassOf(patch));
+  Expect.isTrue(patch.isSubclassOf(cls));
 }
 
-testPatchNonExistingTopLevel() {
-  asyncTest(() => applyPatch(
+Future testPatchNonExistingTopLevel() async {
+  var compiler = await applyPatch(
       """
       // class Class {}
       """,
       """
       @patch class Class {}
-      """).then((compiler) {
-    Expect.isTrue(compiler.warnings.isEmpty,
-                  "Unexpected warnings: ${compiler.warnings}");
-    print('testPatchNonExistingTopLevel:${compiler.errors}');
-    Expect.equals(1, compiler.errors.length);
-    Expect.isTrue(
-        compiler.errors[0].message.kind == MessageKind.PATCH_NON_EXISTING);
-  }));
+      """);
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  print('testPatchNonExistingTopLevel:${compiler.errors}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NON_EXISTING);
 }
 
-testPatchNonExistingMember() {
-  asyncTest(() => applyPatch(
+Future testPatchNonExistingMember() async {
+  var compiler = await applyPatch(
       """
       class Class {}
       """,
@@ -612,84 +625,80 @@
       @patch class Class {
         @patch void foo() {}
       }
-      """).then((compiler) {
-    var container = ensure(compiler, "Class", compiler.coreLibrary.find,
-                           expectIsPatched: true);
-    container.parseNode(compiler);
+      """);
+  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
+                         expectIsPatched: true);
+  container.parseNode(compiler);
 
-    Expect.isTrue(compiler.warnings.isEmpty,
-                  "Unexpected warnings: ${compiler.warnings}");
-    print('testPatchNonExistingMember:${compiler.errors}');
-    Expect.equals(1, compiler.errors.length);
-    Expect.isTrue(
-        compiler.errors[0].message.kind == MessageKind.PATCH_NON_EXISTING);
-  }));
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  print('testPatchNonExistingMember:${compiler.errors}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NON_EXISTING);
 }
 
-testPatchNonPatchablePatch() {
-  asyncTest(() => applyPatch(
+Future testPatchNonPatchablePatch() async {
+  var compiler = await applyPatch(
       """
       external get foo;
       """,
       """
       @patch var foo;
-      """).then((compiler) {
-    ensure(compiler, "foo", compiler.coreLibrary.find);
+      """);
+  ensure(compiler, "foo", compiler.coreLibrary.find);
 
-    Expect.isTrue(compiler.warnings.isEmpty,
-                  "Unexpected warnings: ${compiler.warnings}");
-    print('testPatchNonPatchablePatch:${compiler.errors}');
-    Expect.equals(1, compiler.errors.length);
-    Expect.isTrue(
-        compiler.errors[0].message.kind == MessageKind.PATCH_NONPATCHABLE);
-  }));
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  print('testPatchNonPatchablePatch:${compiler.errors}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NONPATCHABLE);
 }
 
-testPatchNonPatchableOrigin() {
-  asyncTest(() => applyPatch(
+Future testPatchNonPatchableOrigin() async {
+  var compiler = await applyPatch(
       """
       external var foo;
       """,
       """
       @patch get foo => 0;
-      """).then((compiler) {
-    ensure(compiler, "foo", compiler.coreLibrary.find);
+      """);
+  ensure(compiler, "foo", compiler.coreLibrary.find);
 
-    Expect.isTrue(compiler.warnings.isEmpty,
-                  "Unexpected warnings: ${compiler.warnings}");
-    print('testPatchNonPatchableOrigin:${compiler.errors}');
-    Expect.equals(2, compiler.errors.length);
-    Expect.equals(
-        MessageKind.EXTRANEOUS_MODIFIER, compiler.errors[0].message.kind);
-    Expect.equals(
-        // TODO(ahe): Eventually, this error should be removed as it will be
-        // handled by the regular parser.
-        MessageKind.PATCH_NONPATCHABLE, compiler.errors[1].message.kind);
-  }));
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  print('testPatchNonPatchableOrigin:${compiler.errors}');
+  Expect.equals(2, compiler.errors.length);
+  Expect.equals(
+      MessageKind.EXTRANEOUS_MODIFIER, compiler.errors[0].message.kind);
+  Expect.equals(
+      // TODO(ahe): Eventually, this error should be removed as it will be
+      // handled by the regular parser.
+      MessageKind.PATCH_NONPATCHABLE, compiler.errors[1].message.kind);
 }
 
-testPatchNonExternalTopLevel() {
-  asyncTest(() => applyPatch(
+Future testPatchNonExternalTopLevel() async {
+  var compiler = await applyPatch(
       """
       void foo() {}
       """,
       """
       @patch void foo() {}
-      """).then((compiler) {
-    print('testPatchNonExternalTopLevel.errors:${compiler.errors}');
-    print('testPatchNonExternalTopLevel.warnings:${compiler.warnings}');
-    Expect.equals(1, compiler.errors.length);
-    Expect.isTrue(
-        compiler.errors[0].message.kind == MessageKind.PATCH_NON_EXTERNAL);
-    Expect.equals(0, compiler.warnings.length);
-    Expect.equals(1, compiler.infos.length);
-    Expect.isTrue(compiler.infos[0].message.kind ==
-        MessageKind.PATCH_POINT_TO_FUNCTION);
-  }));
+      """);
+  print('testPatchNonExternalTopLevel.errors:${compiler.errors}');
+  print('testPatchNonExternalTopLevel.warnings:${compiler.warnings}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NON_EXTERNAL);
+  Expect.equals(0, compiler.warnings.length);
+  Expect.equals(1, compiler.infos.length);
+  Expect.isTrue(compiler.infos[0].message.kind ==
+      MessageKind.PATCH_POINT_TO_FUNCTION);
 }
 
-testPatchNonExternalMember() {
-  asyncTest(() => applyPatch(
+Future testPatchNonExternalMember() async {
+  var compiler = await applyPatch(
       """
       class Class {
         void foo() {}
@@ -699,146 +708,139 @@
       @patch class Class {
         @patch void foo() {}
       }
-      """).then((compiler) {
-    var container = ensure(compiler, "Class", compiler.coreLibrary.find,
-                           expectIsPatched: true);
-    container.parseNode(compiler);
+      """);
+  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
+                         expectIsPatched: true);
+  container.parseNode(compiler);
 
-    print('testPatchNonExternalMember.errors:${compiler.errors}');
-    print('testPatchNonExternalMember.warnings:${compiler.warnings}');
-    Expect.equals(1, compiler.errors.length);
-    Expect.isTrue(
-        compiler.errors[0].message.kind == MessageKind.PATCH_NON_EXTERNAL);
-    Expect.equals(0, compiler.warnings.length);
-    Expect.equals(1, compiler.infos.length);
-    Expect.isTrue(compiler.infos[0].message.kind ==
-        MessageKind.PATCH_POINT_TO_FUNCTION);
-  }));
+  print('testPatchNonExternalMember.errors:${compiler.errors}');
+  print('testPatchNonExternalMember.warnings:${compiler.warnings}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NON_EXTERNAL);
+  Expect.equals(0, compiler.warnings.length);
+  Expect.equals(1, compiler.infos.length);
+  Expect.isTrue(compiler.infos[0].message.kind ==
+      MessageKind.PATCH_POINT_TO_FUNCTION);
 }
 
-testPatchNonClass() {
-  asyncTest(() => applyPatch(
+Future testPatchNonClass() async {
+  var compiler = await applyPatch(
       """
       external void Class() {}
       """,
       """
       @patch class Class {}
-      """).then((compiler) {
-    print('testPatchNonClass.errors:${compiler.errors}');
-    print('testPatchNonClass.warnings:${compiler.warnings}');
-    Expect.equals(1, compiler.errors.length);
-    Expect.isTrue(
-        compiler.errors[0].message.kind == MessageKind.PATCH_NON_CLASS);
-    Expect.equals(0, compiler.warnings.length);
-    Expect.equals(1, compiler.infos.length);
-    Expect.isTrue(
-        compiler.infos[0].message.kind == MessageKind.PATCH_POINT_TO_CLASS);
-  }));
+      """);
+  print('testPatchNonClass.errors:${compiler.errors}');
+  print('testPatchNonClass.warnings:${compiler.warnings}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NON_CLASS);
+  Expect.equals(0, compiler.warnings.length);
+  Expect.equals(1, compiler.infos.length);
+  Expect.isTrue(
+      compiler.infos[0].message.kind == MessageKind.PATCH_POINT_TO_CLASS);
 }
 
-testPatchNonGetter() {
-  asyncTest(() => applyPatch(
+Future testPatchNonGetter() async {
+  var compiler = await applyPatch(
       """
       external void foo() {}
       """,
       """
       @patch get foo => 0;
-      """).then((compiler) {
-    print('testPatchNonClass.errors:${compiler.errors}');
-    print('testPatchNonClass.warnings:${compiler.warnings}');
-    Expect.equals(1, compiler.errors.length);
-    Expect.isTrue(
-        compiler.errors[0].message.kind == MessageKind.PATCH_NON_GETTER);
-    Expect.equals(0, compiler.warnings.length);
-    Expect.equals(1, compiler.infos.length);
-    Expect.isTrue(
-        compiler.infos[0].message.kind == MessageKind.PATCH_POINT_TO_GETTER);
-  }));
+      """);
+  print('testPatchNonClass.errors:${compiler.errors}');
+  print('testPatchNonClass.warnings:${compiler.warnings}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NON_GETTER);
+  Expect.equals(0, compiler.warnings.length);
+  Expect.equals(1, compiler.infos.length);
+  Expect.isTrue(
+      compiler.infos[0].message.kind == MessageKind.PATCH_POINT_TO_GETTER);
 }
 
-testPatchNoGetter() {
-  asyncTest(() => applyPatch(
+Future testPatchNoGetter() async {
+  var compiler = await applyPatch(
       """
       external set foo(var value) {}
       """,
       """
       @patch get foo => 0;
-      """).then((compiler) {
-    print('testPatchNonClass.errors:${compiler.errors}');
-    print('testPatchNonClass.warnings:${compiler.warnings}');
-    Expect.equals(1, compiler.errors.length);
-    Expect.isTrue(
-        compiler.errors[0].message.kind == MessageKind.PATCH_NO_GETTER);
-    Expect.equals(0, compiler.warnings.length);
-    Expect.equals(1, compiler.infos.length);
-    Expect.isTrue(
-        compiler.infos[0].message.kind == MessageKind.PATCH_POINT_TO_GETTER);
-  }));
+      """);
+  print('testPatchNonClass.errors:${compiler.errors}');
+  print('testPatchNonClass.warnings:${compiler.warnings}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NO_GETTER);
+  Expect.equals(0, compiler.warnings.length);
+  Expect.equals(1, compiler.infos.length);
+  Expect.isTrue(
+      compiler.infos[0].message.kind == MessageKind.PATCH_POINT_TO_GETTER);
 }
 
-testPatchNonSetter() {
-  asyncTest(() => applyPatch(
+Future testPatchNonSetter() async {
+  var compiler = await applyPatch(
       """
       external void foo() {}
       """,
       """
       @patch set foo(var value) {}
-      """).then((compiler) {
-    print('testPatchNonClass.errors:${compiler.errors}');
-    print('testPatchNonClass.warnings:${compiler.warnings}');
-    Expect.equals(1, compiler.errors.length);
-    Expect.isTrue(
-        compiler.errors[0].message.kind == MessageKind.PATCH_NON_SETTER);
-    Expect.equals(0, compiler.warnings.length);
-    Expect.equals(1, compiler.infos.length);
-    Expect.isTrue(
-        compiler.infos[0].message.kind == MessageKind.PATCH_POINT_TO_SETTER);
-  }));
+      """);
+  print('testPatchNonClass.errors:${compiler.errors}');
+  print('testPatchNonClass.warnings:${compiler.warnings}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NON_SETTER);
+  Expect.equals(0, compiler.warnings.length);
+  Expect.equals(1, compiler.infos.length);
+  Expect.isTrue(
+      compiler.infos[0].message.kind == MessageKind.PATCH_POINT_TO_SETTER);
 }
 
-testPatchNoSetter() {
-  asyncTest(() => applyPatch(
+Future testPatchNoSetter() async {
+  var compiler = await applyPatch(
       """
       external get foo;
       """,
       """
       @patch set foo(var value) {}
-      """).then((compiler) {
-    print('testPatchNonClass.errors:${compiler.errors}');
-    print('testPatchNonClass.warnings:${compiler.warnings}');
-    Expect.equals(1, compiler.errors.length);
-    Expect.isTrue(
-        compiler.errors[0].message.kind == MessageKind.PATCH_NO_SETTER);
-    Expect.equals(0, compiler.warnings.length);
-    Expect.equals(1, compiler.infos.length);
-    Expect.isTrue(
-        compiler.infos[0].message.kind == MessageKind.PATCH_POINT_TO_SETTER);
-  }));
+      """);
+  print('testPatchNonClass.errors:${compiler.errors}');
+  print('testPatchNonClass.warnings:${compiler.warnings}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NO_SETTER);
+  Expect.equals(0, compiler.warnings.length);
+  Expect.equals(1, compiler.infos.length);
+  Expect.isTrue(
+      compiler.infos[0].message.kind == MessageKind.PATCH_POINT_TO_SETTER);
 }
 
-testPatchNonFunction() {
-  asyncTest(() => applyPatch(
+Future testPatchNonFunction() async {
+  var compiler = await applyPatch(
       """
       external get foo;
       """,
       """
       @patch void foo() {}
-      """).then((compiler) {
-    print('testPatchNonClass.errors:${compiler.errors}');
-    print('testPatchNonClass.warnings:${compiler.warnings}');
-    Expect.equals(1, compiler.errors.length);
-    Expect.isTrue(
-        compiler.errors[0].message.kind == MessageKind.PATCH_NON_FUNCTION);
-    Expect.equals(0, compiler.warnings.length);
-    Expect.equals(1, compiler.infos.length);
-    Expect.isTrue(
-        compiler.infos[0].message.kind ==
-            MessageKind.PATCH_POINT_TO_FUNCTION);
-  }));
+      """);
+  print('testPatchNonClass.errors:${compiler.errors}');
+  print('testPatchNonClass.warnings:${compiler.warnings}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NON_FUNCTION);
+  Expect.equals(0, compiler.warnings.length);
+  Expect.equals(1, compiler.infos.length);
+  Expect.isTrue(
+      compiler.infos[0].message.kind ==
+          MessageKind.PATCH_POINT_TO_FUNCTION);
 }
 
-testPatchAndSelector() {
-  asyncTest(() => applyPatch(
+Future testPatchAndSelector() async {
+  var compiler = await applyPatch(
       """
       class A {
         external void clear();
@@ -858,76 +860,73 @@
         new B();
       }
       """,
-      runCompiler: true, analyzeOnly: true).then((Compiler compiler) {
-    World world = compiler.world;
+      runCompiler: true, analyzeOnly: true);
+  World world = compiler.world;
 
-    ClassElement cls = ensure(compiler, "A", compiler.coreLibrary.find,
-                              expectIsPatched: true);
-    cls.ensureResolved(compiler);
+  ClassElement cls = ensure(compiler, "A", compiler.coreLibrary.find,
+                            expectIsPatched: true);
+  cls.ensureResolved(compiler);
 
-    ensure(compiler, "method", cls.patch.lookupLocalMember,
-           checkHasBody: true, expectIsRegular: true);
+  ensure(compiler, "method", cls.patch.lookupLocalMember,
+         checkHasBody: true, expectIsRegular: true);
 
-    ensure(compiler, "clear", cls.lookupLocalMember,
-           checkHasBody: true, expectIsPatched: true);
+  ensure(compiler, "clear", cls.lookupLocalMember,
+         checkHasBody: true, expectIsPatched: true);
 
-    compiler.phase = Compiler.PHASE_DONE_RESOLVING;
+  compiler.phase = Compiler.PHASE_DONE_RESOLVING;
 
-    // Check that a method just in the patch class is a target for a
-    // typed selector.
-    Selector selector =
-        new Selector.call(const PublicName('method'), CallStructure.NO_ARGS);
-    TypeMask typeMask = new TypeMask.exact(cls, world);
-    FunctionElement method = cls.implementation.lookupLocalMember('method');
-    method.computeType(compiler);
-    Expect.isTrue(selector.applies(method, world));
-    Expect.isTrue(typeMask.canHit(method, selector, world));
+  // Check that a method just in the patch class is a target for a
+  // typed selector.
+  Selector selector =
+      new Selector.call(const PublicName('method'), CallStructure.NO_ARGS);
+  TypeMask typeMask = new TypeMask.exact(cls, world);
+  FunctionElement method = cls.implementation.lookupLocalMember('method');
+  method.computeType(compiler);
+  Expect.isTrue(selector.applies(method, world));
+  Expect.isTrue(typeMask.canHit(method, selector, world));
 
-    // Check that the declaration method in the declaration class is a target
-    // for a typed selector.
-    selector =
-        new Selector.call(const PublicName('clear'), CallStructure.NO_ARGS);
-    typeMask = new TypeMask.exact(cls, world);
-    method = cls.lookupLocalMember('clear');
-    method.computeType(compiler);
-    Expect.isTrue(selector.applies(method, world));
-    Expect.isTrue(typeMask.canHit(method, selector, world));
+  // Check that the declaration method in the declaration class is a target
+  // for a typed selector.
+  selector =
+      new Selector.call(const PublicName('clear'), CallStructure.NO_ARGS);
+  typeMask = new TypeMask.exact(cls, world);
+  method = cls.lookupLocalMember('clear');
+  method.computeType(compiler);
+  Expect.isTrue(selector.applies(method, world));
+  Expect.isTrue(typeMask.canHit(method, selector, world));
 
-    // Check that the declaration method in the declaration class is a target
-    // for a typed selector on a subclass.
-    cls = ensure(compiler, "B", compiler.coreLibrary.find);
-    cls.ensureResolved(compiler);
-    typeMask = new TypeMask.exact(cls, world);
-    Expect.isTrue(selector.applies(method, world));
-    Expect.isTrue(typeMask.canHit(method, selector, world));
-  }));
+  // Check that the declaration method in the declaration class is a target
+  // for a typed selector on a subclass.
+  cls = ensure(compiler, "B", compiler.coreLibrary.find);
+  cls.ensureResolved(compiler);
+  typeMask = new TypeMask.exact(cls, world);
+  Expect.isTrue(selector.applies(method, world));
+  Expect.isTrue(typeMask.canHit(method, selector, world));
 }
 
-void testAnalyzeAllInjectedMembers() {
-  void expect(String patchText, [expectedWarnings]) {
+Future testAnalyzeAllInjectedMembers() async {
+  Future expect(String patchText, [expectedWarnings]) async {
     if (expectedWarnings == null) expectedWarnings = [];
     if (expectedWarnings is! List) {
       expectedWarnings = <MessageKind>[expectedWarnings];
     }
 
-    asyncTest(() => applyPatch('', patchText, analyzeAll: true,
-               analyzeOnly: true).then((compiler) {
+    var compiler = await applyPatch('', patchText, analyzeAll: true,
+               analyzeOnly: true);
       compiler.librariesToAnalyzeWhenRun = [Uri.parse('dart:core')];
-      return compiler.runCompiler(null).then((_) {
-        compareWarningKinds(patchText, expectedWarnings, compiler.warnings);
-      });
-    }));
+    await compiler.runCompiler(null);
+    compareWarningKinds(patchText, expectedWarnings, compiler.warnings);
   }
 
-  expect('String s = 0;', MessageKind.NOT_ASSIGNABLE);
-  expect('void method() { String s = 0; }', MessageKind.NOT_ASSIGNABLE);
-  expect('''
+  await expect('String s = 0;', MessageKind.NOT_ASSIGNABLE);
+  await expect('void method() { String s = 0; }', MessageKind.NOT_ASSIGNABLE);
+  await expect('''
          class Class {
            String s = 0;
          }
          ''',
          MessageKind.NOT_ASSIGNABLE);
-  expect('''
+  await expect('''
          class Class {
            void method() {
              String s = 0;
@@ -937,7 +936,7 @@
          MessageKind.NOT_ASSIGNABLE);
 }
 
-void testEffectiveTarget() {
+Future testEffectiveTarget() async {
   String origin = """
     class A {
       A() : super();
@@ -958,76 +957,76 @@
     }
     """;
 
-  asyncTest(() => applyPatch(origin, patch, analyzeAll: true,
-                 analyzeOnly: true, runCompiler: true).then((compiler) {
-    ClassElement clsA = compiler.coreLibrary.find("A");
-    ClassElement clsB = compiler.coreLibrary.find("B");
+  var compiler = await applyPatch(origin, patch, analyzeAll: true,
+                 analyzeOnly: true, runCompiler: true);
+  ClassElement clsA = compiler.coreLibrary.find("A");
+  ClassElement clsB = compiler.coreLibrary.find("B");
 
-    ConstructorElement forward = clsA.lookupConstructor("forward");
-    ConstructorElement target = forward.effectiveTarget;
-    Expect.isTrue(target.isPatch);
-    Expect.equals("patchTarget", target.name);
+  ConstructorElement forward = clsA.lookupConstructor("forward");
+  ConstructorElement target = forward.effectiveTarget;
+  Expect.isTrue(target.isPatch);
+  Expect.equals("patchTarget", target.name);
 
-    ConstructorElement forwardTwo = clsA.lookupConstructor("forwardTwo");
-    target = forwardTwo.effectiveTarget;
-    Expect.isFalse(forwardTwo.isErroneous);
-    Expect.isFalse(target.isPatch);
-    Expect.equals("originTarget", target.name);
-  }));
+  ConstructorElement forwardTwo = clsA.lookupConstructor("forwardTwo");
+  target = forwardTwo.effectiveTarget;
+  Expect.isFalse(forwardTwo.isErroneous);
+  Expect.isFalse(target.isPatch);
+  Expect.equals("originTarget", target.name);
 }
 
-void testTypecheckPatchedMembers() {
+Future testTypecheckPatchedMembers() async {
   String originText = "external void method();";
   String patchText = """
                      @patch void method() {
                        String s = 0;
                      }
                      """;
-  asyncTest(() => applyPatch(originText, patchText,
-             analyzeAll: true, analyzeOnly: true).then((compiler) {
-    compiler.librariesToAnalyzeWhenRun = [Uri.parse('dart:core')];
-    return compiler.runCompiler(null).then((_) {
-      compareWarningKinds(patchText,
-          [MessageKind.NOT_ASSIGNABLE], compiler.warnings);
-    });
-  }));
+  var compiler = await applyPatch(originText, patchText,
+             analyzeAll: true, analyzeOnly: true);
+  compiler.librariesToAnalyzeWhenRun = [Uri.parse('dart:core')];
+  await compiler.runCompiler(null);
+  compareWarningKinds(patchText,
+      [MessageKind.NOT_ASSIGNABLE], compiler.warnings);
 }
 
 main() {
-  testPatchConstructor();
-  testPatchRedirectingConstructor();
-  testPatchFunction();
-  testPatchMember();
-  testPatchGetter();
-  testRegularMember();
-  testGhostMember();
-  testInjectFunction();
-  testPatchSignatureCheck();
+  asyncTest(() async {
+    await testPatchConstructor();
+    await testPatchRedirectingConstructor();
+    await testPatchFunction();
+    await testPatchFunctionMetadata();
+    await testPatchMember();
+    await testPatchGetter();
+    await testRegularMember();
+    await testGhostMember();
+    await testInjectFunction();
+    await testPatchSignatureCheck();
 
-  testPatchVersioned();
+    await testPatchVersioned();
 
-  testExternalWithoutImplementationTopLevel();
-  testExternalWithoutImplementationMember();
+    await testExternalWithoutImplementationTopLevel();
+    await testExternalWithoutImplementationMember();
 
-  testIsSubclass();
+    await testIsSubclass();
 
-  testPatchNonExistingTopLevel();
-  testPatchNonExistingMember();
-  testPatchNonPatchablePatch();
-  testPatchNonPatchableOrigin();
-  testPatchNonExternalTopLevel();
-  testPatchNonExternalMember();
-  testPatchNonClass();
-  testPatchNonGetter();
-  testPatchNoGetter();
-  testPatchNonSetter();
-  testPatchNoSetter();
-  testPatchNonFunction();
+    await testPatchNonExistingTopLevel();
+    await testPatchNonExistingMember();
+    await testPatchNonPatchablePatch();
+    await testPatchNonPatchableOrigin();
+    await testPatchNonExternalTopLevel();
+    await testPatchNonExternalMember();
+    await testPatchNonClass();
+    await testPatchNonGetter();
+    await testPatchNoGetter();
+    await testPatchNonSetter();
+    await testPatchNoSetter();
+    await testPatchNonFunction();
 
-  testPatchAndSelector();
+    await testPatchAndSelector();
 
-  testEffectiveTarget(); /// bug: ok
+    await testEffectiveTarget(); /// bug: ok
 
-  testAnalyzeAllInjectedMembers();
-  testTypecheckPatchedMembers();
+    await testAnalyzeAllInjectedMembers();
+    await testTypecheckPatchedMembers();
+  });
 }
diff --git a/tests/compiler/dart2js/pretty_parameter_test.dart b/tests/compiler/dart2js/pretty_parameter_test.dart
index 723683b..3aa4db1 100644
--- a/tests/compiler/dart2js/pretty_parameter_test.dart
+++ b/tests/compiler/dart2js/pretty_parameter_test.dart
@@ -35,7 +35,7 @@
 """;
 
 const String NO_LOCAL = r"""
-foo(bar, bar) {
+foo(bar, baz) {
   if (bar) {
     baz = 2;
   } else {
diff --git a/tests/compiler/dart2js/reexport_handled_test.dart b/tests/compiler/dart2js/reexport_handled_test.dart
index 4bdd62d..ade3373 100644
--- a/tests/compiler/dart2js/reexport_handled_test.dart
+++ b/tests/compiler/dart2js/reexport_handled_test.dart
@@ -32,24 +32,15 @@
     return compiler.libraryLoader.loadLibrary(exportingLibraryUri);
   }).then((exportingLibrary) {
     Expect.isTrue(exportingLibrary.exportsHandled);
-    var foo = findInExports(exportingLibrary, 'foo');
+    var foo = exportingLibrary.findExported('foo');
     Expect.isNotNull(foo);
     Expect.isTrue(foo.isField);
 
     // Load reexporting library when exports are handled on the exporting library.
     return compiler.libraryLoader.loadLibrary(reexportingLibraryUri);
   }).then((reexportingLibrary) {
-    var foo = findInExports(reexportingLibrary, 'foo');
+    var foo = reexportingLibrary.findExported('foo');
     Expect.isNotNull(foo);
     Expect.isTrue(foo.isField);
   }));
 }
-
-Element findInExports(LibraryElement library, String name) {
-  for (var export in library.exports) {
-    if (export.name == name) {
-      return export;
-    }
-  }
-  return null;
-}
diff --git a/tests/compiler/dart2js/related_types.dart b/tests/compiler/dart2js/related_types.dart
new file mode 100644
index 0000000..9843180
--- /dev/null
+++ b/tests/compiler/dart2js/related_types.dart
@@ -0,0 +1,430 @@
+// Copyright (c) 2015, 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 related_types;
+
+import 'package:compiler/src/commandline_options.dart';
+import 'package:compiler/src/compiler.dart';
+import 'package:compiler/src/core_types.dart';
+import 'package:compiler/src/dart_types.dart';
+import 'package:compiler/src/diagnostics/messages.dart';
+import 'package:compiler/src/elements/elements.dart';
+import 'package:compiler/src/filenames.dart';
+import 'package:compiler/src/resolution/semantic_visitor.dart';
+import 'package:compiler/src/tree/tree.dart';
+import 'package:compiler/src/universe/universe.dart';
+import 'package:compiler/src/world.dart';
+import 'memory_compiler.dart';
+
+main(List<String> arguments) async {
+  if (arguments.isNotEmpty) {
+    Uri entryPoint = Uri.base.resolve(nativeToUriPath(arguments.last));
+    CompilationResult result = await runCompiler(
+        entryPoint: entryPoint,
+        options: [Flags.analyzeOnly, '--categories=Client,Server']);
+    if (result.isSuccess) {
+      checkRelatedTypes(result.compiler);
+    }
+  } else {
+    print('Usage dart related_types.dart <entry-point>');
+  }
+}
+
+/// Check all loaded libraries in [compiler] for unrelated types.
+void checkRelatedTypes(Compiler compiler) {
+  for (LibraryElement library in compiler.libraryLoader.libraries) {
+    checkLibraryElement(compiler, library);
+  }
+}
+
+/// Check [library] for unrelated types.
+void checkLibraryElement(Compiler compiler, LibraryElement library) {
+  library.forEachLocalMember((Element element) {
+    if (element.isClass) {
+      ClassElement cls = element;
+      cls.forEachLocalMember((MemberElement member) {
+        checkMemberElement(compiler, member);
+      });
+    } else if (!element.isTypedef) {
+      checkMemberElement(compiler, element);
+    }
+  });
+}
+
+/// Check [member] for unrelated types.
+void checkMemberElement(Compiler compiler, MemberElement member) {
+  if (!compiler.enqueuer.resolution.hasBeenResolved(member)) return;
+
+  ResolvedAst resolvedAst = member.resolvedAst;
+  RelatedTypesChecker relatedTypesChecker =
+      new RelatedTypesChecker(compiler, resolvedAst);
+  if (resolvedAst.node != null) {
+    compiler.withCurrentElement(member.implementation, () {
+      relatedTypesChecker.apply(resolvedAst.node);
+    });
+  }
+}
+
+class RelatedTypesChecker extends TraversalVisitor<DartType, dynamic> {
+  final Compiler compiler;
+  final ResolvedAst resolvedAst;
+
+  RelatedTypesChecker(this.compiler, ResolvedAst resolvedAst)
+      : this.resolvedAst = resolvedAst,
+        super(resolvedAst.elements);
+
+  ClassWorld get world => compiler.world;
+
+  CoreTypes get coreTypes => compiler.coreTypes;
+
+  InterfaceType get thisType => resolvedAst.element.enclosingClass.thisType;
+
+  /// Returns `true` if there exists no common subtype of [left] and [right].
+  bool hasEmptyIntersection(DartType left, DartType right) {
+    if (left == right) return false;
+    if (left == null || right == null) return false;
+    ClassElement leftClass = const ClassFinder().findClass(left);
+    ClassElement rightClass = const ClassFinder().findClass(right);
+    if (leftClass != null && rightClass != null) {
+      return !world.haveAnyCommonSubtypes(leftClass, rightClass);
+    }
+    return false;
+  }
+
+  /// Checks that there exists a common subtype of [left] and [right] or report
+  /// a hint otherwise.
+  void checkRelated(Node node, DartType left, DartType right) {
+    if (hasEmptyIntersection(left, right)) {
+      compiler.reportHint(
+          node, MessageKind.NO_COMMON_SUBTYPES, {'left': left, 'right': right});
+    }
+  }
+
+  /// Check weakly typed collection methods, like `Map.containsKey`,
+  /// `Map.containsValue` and `Iterable.contains`.
+  void checkDynamicInvoke(
+      Node node,
+      DartType receiverType,
+      List<DartType> argumentTypes,
+      Selector selector) {
+    if (selector.name == 'containsKey' &&
+        selector.callStructure == CallStructure.ONE_ARG) {
+      InterfaceType mapType = findMapType(receiverType);
+      if (mapType != null) {
+        DartType keyType = findMapKeyType(mapType);
+        checkRelated(node, keyType, argumentTypes.first);
+      }
+    } else if (selector.name == 'containsValue' &&
+               selector.callStructure == CallStructure.ONE_ARG) {
+      InterfaceType mapType = findMapType(receiverType);
+      if (mapType != null) {
+        DartType valueType = findMapValueType(mapType);
+        checkRelated(node, valueType, argumentTypes.first);
+      }
+    } else if (selector.name == 'contains' &&
+               selector.callStructure == CallStructure.ONE_ARG) {
+      InterfaceType iterableType = findIterableType(receiverType);
+      if (iterableType != null) {
+        DartType elementType = findIterableElementType(iterableType);
+        checkRelated(node, elementType, argumentTypes.first);
+      }
+    } else if (selector.name == 'remove' &&
+               selector.callStructure == CallStructure.ONE_ARG) {
+      InterfaceType mapType = findMapType(receiverType);
+      if (mapType != null) {
+        DartType keyType = findMapKeyType(mapType);
+        checkRelated(node, keyType, argumentTypes.first);
+      }
+      InterfaceType listType = findListType(receiverType);
+      if (listType != null) {
+        DartType valueType = findListElementType(listType);
+        checkRelated(node, valueType, argumentTypes.first);
+      }
+    }
+  }
+
+  /// Return the interface type implemented by [type] or `null` if no interface
+  /// type is implied by [type].
+  InterfaceType findInterfaceType(DartType type) {
+    return Types.computeInterfaceType(compiler, type);
+  }
+
+  /// Returns the supertype of [receiver] that implements [cls], if any.
+  InterfaceType findClassType(DartType receiver, ClassElement cls) {
+    InterfaceType interfaceType = findInterfaceType(receiver);
+    if (interfaceType == null) return null;
+    InterfaceType mapType = interfaceType.asInstanceOf(cls);
+    if (mapType == null) return null;
+    return mapType;
+  }
+
+  /// Returns the supertype of [receiver] that implements `Iterable`, if any.
+  InterfaceType findIterableType(DartType receiver) {
+    return findClassType(receiver, compiler.iterableClass);
+  }
+
+  /// Returns the element type of the supertype of [receiver] that implements
+  /// `Iterable`, if any.
+  DartType findIterableElementType(InterfaceType iterableType) {
+    if (iterableType == null) return null;
+    return iterableType.typeArguments[0];
+  }
+
+  /// Returns the supertype of [receiver] that implements `Map`, if any.
+  InterfaceType findMapType(DartType receiver) {
+    return findClassType(receiver, compiler.mapClass);
+  }
+
+  /// Returns the key type of the supertype of [receiver] that implements
+  /// `Map`, if any.
+  DartType findMapKeyType(InterfaceType mapType) {
+    if (mapType == null) return null;
+    return mapType.typeArguments[0];
+  }
+
+  /// Returns the value type of the supertype of [receiver] that implements
+  /// `Map`, if any.
+  DartType findMapValueType(InterfaceType mapType) {
+    if (mapType == null) return null;
+    return mapType.typeArguments[1];
+  }
+
+  /// Returns the supertype of [receiver] that implements `List`, if any.
+  InterfaceType findListType(DartType receiver) {
+    return findClassType(receiver, compiler.listClass);
+  }
+
+  /// Returns the element type of the supertype of [receiver] that implements
+  /// `List`, if any.
+  DartType findListElementType(InterfaceType listType) {
+    if (listType == null) return null;
+    return listType.typeArguments[0];
+  }
+
+  /// Returns the implied return type of [type] or `dynamic` if no return type
+  /// is implied.
+  DartType findReturnType(DartType type) {
+    if (type is FunctionType) {
+      return type.returnType;
+    }
+    return const DynamicType();
+  }
+
+  /// Visits [arguments] and returns the list of their corresponding types.
+  List<DartType> findArgumentTypes(NodeList arguments) {
+    List<DartType> argumentTypes = <DartType>[];
+    for (Node argument in arguments) {
+      argumentTypes.add(apply(argument));
+    }
+    return argumentTypes;
+  }
+
+  /// Finds the [MemberSignature] of the [name] property on [type], if any.
+  MemberSignature lookupInterfaceMember(DartType type, Name name) {
+    InterfaceType interfaceType = findInterfaceType(type);
+    if (interfaceType == null) return null;
+    return interfaceType.lookupInterfaceMember(name);
+  }
+
+  /// Returns the type of an access of the [name] property on [type], or
+  /// `dynamic` if no property was found.
+  DartType lookupInterfaceMemberAccessType(DartType type, Name name) {
+    MemberSignature member = lookupInterfaceMember(type, name);
+    if (member == null) return const DynamicType();
+    return member.type;
+  }
+
+  /// Returns the function type of the [name] property on [type], or
+  /// `dynamic` if no property was found.
+  FunctionType lookupInterfaceMemberInvocationType(DartType type, Name name) {
+    MemberSignature member = lookupInterfaceMember(type, name);
+    if (member == null) return null;
+    return member.functionType;
+  }
+
+  DartType apply(Node node, [_]) {
+    DartType type = node.accept(this);
+    if (type == null) {
+      type = const DynamicType();
+    }
+    return type;
+  }
+
+  @override
+  DartType visitEquals(Send node, Node left, Node right, _) {
+    DartType leftType = apply(left);
+    DartType rightType = apply(right);
+    checkRelated(node, leftType, rightType);
+    return coreTypes.boolType;
+  }
+
+  @override
+  DartType visitNotEquals(Send node, Node left, Node right, _) {
+    DartType leftType = apply(left);
+    DartType rightType = apply(right);
+    checkRelated(node, leftType, rightType);
+    return coreTypes.boolType;
+  }
+
+  @override
+  DartType visitIndex(Send node, Node receiver, Node index, _) {
+    DartType receiverType = apply(receiver);
+    DartType indexType = apply(index);
+    InterfaceType mapType = findMapType(receiverType);
+    DartType keyType = findMapKeyType(mapType);
+    DartType valueType = findMapValueType(mapType);
+    checkRelated(index, keyType, indexType);
+    return valueType;
+  }
+
+  @override
+  DartType visitLiteralInt(LiteralInt node) {
+    return coreTypes.intType;
+  }
+
+  @override
+  DartType visitLiteralString(LiteralString node) {
+    return coreTypes.stringType;
+  }
+
+  @override
+  DartType visitLiteralBool(LiteralBool node) {
+    return coreTypes.boolType;
+  }
+
+  @override
+  DartType visitLiteralMap(LiteralMap node) {
+    return elements.getType(node);
+  }
+
+  @override
+  DartType visitLiteralList(LiteralList node) {
+    return elements.getType(node);
+  }
+
+  @override
+  DartType visitLiteralNull(LiteralNull node) {
+    return elements.getType(node);
+  }
+
+  @override
+  DartType visitLocalVariableGet(Send node, LocalVariableElement variable, _) {
+    return variable.type;
+  }
+
+  @override
+  DartType visitLocalFunctionGet(Send node, LocalFunctionElement function, _) {
+    return function.type;
+  }
+
+  @override
+  DartType visitParameterGet(Send node, ParameterElement parameter, _) {
+    return parameter.type;
+  }
+
+  @override
+  DartType visitThisPropertyGet(Send node, Name name, _) {
+    return lookupInterfaceMemberAccessType(thisType, name);
+  }
+
+  @override
+  DartType visitDynamicPropertyGet(Send node, Node receiver, Name name, _) {
+    DartType receiverType = apply(receiver);
+    return lookupInterfaceMemberAccessType(receiverType, name);
+  }
+
+  @override
+  DartType visitIfNotNullDynamicPropertyGet(
+      Send node, Node receiver, Name name, _) {
+    DartType receiverType = apply(receiver);
+    return lookupInterfaceMemberAccessType(receiverType, name);
+  }
+
+  @override
+  DartType visitStaticFieldGet(Send node, FieldElement field, _) {
+    return field.type;
+  }
+
+  @override
+  DartType visitTopLevelFieldGet(Send node, FieldElement field, _) {
+    return field.type;
+  }
+
+  @override
+  DartType visitDynamicPropertyInvoke(
+      Send node,
+      Node receiver,
+      NodeList arguments,
+      Selector selector, _) {
+    DartType receiverType = apply(receiver);
+    List<DartType> argumentTypes = findArgumentTypes(arguments);
+    FunctionType methodType = lookupInterfaceMemberInvocationType(
+        receiverType, selector.memberName);
+    checkDynamicInvoke(node, receiverType, argumentTypes, selector);
+    return findReturnType(methodType);
+  }
+
+  @override
+  DartType visitThisPropertyInvoke(
+      Send node,
+      NodeList arguments,
+      Selector selector, _) {
+    DartType receiverType = thisType;
+    List<DartType> argumentTypes = findArgumentTypes(arguments);
+    FunctionType methodType = lookupInterfaceMemberInvocationType(
+        receiverType, selector.memberName);
+    checkDynamicInvoke(node, receiverType, argumentTypes, selector);
+    return findReturnType(methodType);
+  }
+
+  @override
+  DartType visitIfNotNullDynamicPropertyInvoke(
+      Send node,
+      Node receiver,
+      NodeList arguments,
+      Selector selector, _) {
+    DartType receiverType = apply(receiver);
+    List<DartType> argumentTypes = findArgumentTypes(arguments);
+    FunctionType methodType = lookupInterfaceMemberInvocationType(
+        receiverType, selector.memberName);
+    checkDynamicInvoke(node, receiverType, argumentTypes, selector);
+    return findReturnType(methodType);
+  }
+
+  @override
+  DartType visitTopLevelFunctionInvoke(
+      Send node,
+      MethodElement function,
+      NodeList arguments,
+      CallStructure callStructure, _) {
+    apply(arguments);
+    return findReturnType(function.type);
+  }
+
+  @override
+  DartType visitStaticFunctionInvoke(
+      Send node,
+      MethodElement function,
+      NodeList arguments,
+      CallStructure callStructure, _) {
+    apply(arguments);
+    return findReturnType(function.type);
+  }
+}
+
+/// Computes the [ClassElement] implied by a type.
+// TODO(johnniwinther): Handle type variables, function types and typedefs.
+class ClassFinder extends BaseDartTypeVisitor<ClassElement, dynamic> {
+  const ClassFinder();
+
+  ClassElement findClass(DartType type) => type.accept(this, null);
+
+  @override
+  ClassElement visitType(DartType type, _) => null;
+
+  @override
+  ClassElement visitInterfaceType(InterfaceType type, _) {
+    return type.element;
+  }
+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/related_types_test.dart b/tests/compiler/dart2js/related_types_test.dart
new file mode 100644
index 0000000..dfb50b4
--- /dev/null
+++ b/tests/compiler/dart2js/related_types_test.dart
@@ -0,0 +1,294 @@
+// Copyright (c) 2015, 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 related_types;
+
+import 'package:async_helper/async_helper.dart';
+import 'package:expect/expect.dart';
+import 'package:compiler/src/commandline_options.dart';
+import 'package:compiler/src/compiler.dart';
+import 'package:compiler/src/diagnostics/messages.dart';
+import 'package:compiler/src/elements/elements.dart';
+import 'memory_compiler.dart';
+
+import 'related_types.dart';
+
+const String CODE = '''
+Map<String, int> topLevelMap;
+List<String> topLevelList;
+
+Map<String, int> getTopLevelMap() => null;
+List<String> getTopLevelList() => null;
+
+class Class {
+  Map<String, int> instanceMap;
+  List<String> instanceList;
+
+  Map<String, int> getInstanceMap() => null;
+  List<String> getInstanceList() => null;
+
+  static Map<String, int> staticMap;
+  static List<String> staticList;
+
+  static Map<String, int> getStaticMap() => null;
+  static List<String> getStaticList() => null;
+  
+  test_instanceMapIndex() {
+    instanceMap[0];
+  }
+  test_instanceMapContainsKey() {
+    instanceMap.containsKey(0);
+  }
+  test_instanceMapContainsValue() {
+    instanceMap.containsValue('');
+  }
+  test_instanceMapRemove() {
+    instanceMap.remove(0);
+  }
+  test_instanceListContains() {
+    instanceList.contains(0);
+  }
+  test_instanceListRemove() {
+    instanceList.remove(0);
+  }
+  
+  test_getInstanceMapIndex() {
+    getInstanceMap()[0];
+  }
+  test_getInstanceMapContainsKey() {
+    getInstanceMap().containsKey(0);
+  }
+  test_getInstanceMapContainsValue() {
+    getInstanceMap().containsValue('');
+  }
+  test_getInstanceMapRemove() {
+    getInstanceMap().remove(0);
+  }
+  test_getInstanceListContains() {
+    getInstanceList().contains(0);
+  }
+  test_getInstanceListRemove() {
+    getInstanceList().remove(0);
+  }
+  
+  static test_staticMapIndex() {
+    staticMap[0];
+  }
+  static test_staticMapContainsKey() {
+    staticMap.containsKey(0);
+  }
+  static test_staticMapContainsValue() {
+    staticMap.containsValue('');
+  }
+  static test_staticMapRemove() {
+    staticMap.remove(0);
+  }
+  static test_staticListContains() {
+    staticList.contains(0);
+  }
+  static test_staticListRemove() {
+    staticList.remove(0);
+  }
+  
+  static test_getStaticMapIndex() {
+    getStaticMap()[0];
+  }
+  static test_getStaticMapContainsKey() {
+    getStaticMap().containsKey(0);
+  }
+  static test_getStaticMapContainsValue() {
+    getStaticMap().containsValue('');
+  }
+  static test_getStaticMapRemove() {
+    getStaticMap().remove(0);
+  }
+  static test_getStaticListContains() {
+    getStaticList().contains(0);
+  }
+  static test_getStaticListRemove() {
+    getStaticList().remove(0);
+  }
+}
+
+main() {}
+
+test_equals() => 0 == '';
+test_notEquals() => 0 != '';
+test_index() => <String, int>{}[0];
+
+test_localMapIndex() {
+  Map<String, int> map;
+  map[0];
+}
+test_localMapContainsKey() {
+  Map<String, int> map;
+  map.containsKey(0);
+}
+test_localMapContainsValue() {
+  Map<String, int> map;
+  map.containsValue('');
+}
+test_localMapRemove() {
+  Map<String, int> map;
+  map.remove(0);
+}
+test_localListContains() {
+  List<String> list;
+  list.contains(0);
+}
+test_localListRemove() {
+  List<String> list;
+  list.remove(0);
+}
+
+test_topLevelMapIndex() {
+  topLevelMap[0];
+}
+test_topLevelMapContainsKey() {
+  topLevelMap.containsKey(0);
+}
+test_topLevelMapContainsValue() {
+  topLevelMap.containsValue('');
+}
+test_topLevelMapRemove() {
+  topLevelMap.remove(0);
+}
+test_topLevelListContains() {
+  topLevelList.contains(0);
+}
+test_topLevelListRemove() {
+  topLevelList.remove(0);
+}
+
+test_getTopLevelMapIndex() {
+  getTopLevelMap()[0];
+}
+test_getTopLevelMapContainsKey() {
+  getTopLevelMap().containsKey(0);
+}
+test_getTopLevelMapContainsValue() {
+  getTopLevelMap().containsValue('');
+}
+test_getTopLevelMapRemove() {
+  getTopLevelMap().remove(0);
+}
+test_getTopLevelListContains() {
+  getTopLevelList().contains(0);
+}
+test_getTopLevelListRemove() {
+  getTopLevelList().remove(0);
+}
+
+test_staticMapIndex() {
+  Class.staticMap[0];
+}
+test_staticMapContainsKey() {
+  Class.staticMap.containsKey(0);
+}
+test_staticMapContainsValue() {
+  Class.staticMap.containsValue('');
+}
+test_staticMapRemove() {
+  Class.staticMap.remove(0);
+}
+test_staticListContains() {
+  Class.staticList.contains(0);
+}
+test_staticListRemove() {
+  Class.staticList.remove(0);
+}
+
+test_getStaticMapIndex() {
+  Class.getStaticMap()[0];
+}
+test_getStaticMapContainsKey() {
+  Class.getStaticMap().containsKey(0);
+}
+test_getStaticMapContainsValue() {
+  Class.getStaticMap().containsValue('');
+}
+test_getStaticMapRemove() {
+  Class.getStaticMap().remove(0);
+}
+test_getStaticListContains() {
+  Class.getStaticList().contains(0);
+}
+test_getStaticListRemove() {
+  Class.getStaticList().remove(0);
+}
+  
+test_instanceMapIndex(Class c) {
+  c.instanceMap[0];
+}
+test_instanceMapContainsKey(Class c) {
+  c.instanceMap.containsKey(0);
+}
+test_instanceMapContainsValue(Class c) {
+  c.instanceMap.containsValue('');
+}
+test_instanceMapRemove(Class c) {
+  c.instanceMap.remove(0);
+}
+test_instanceListContains(Class c) {
+  c.instanceList.contains(0);
+}
+test_instanceListRemove(Class c) {
+  c.instanceList.remove(0);
+}
+
+test_getInstanceMapIndex(Class c) {
+  c.getInstanceMap()[0];
+}
+test_getInstanceMapContainsKey(Class c) {
+  c.getInstanceMap().containsKey(0);
+}
+test_getInstanceMapContainsValue(Class c) {
+  c.getInstanceMap().containsValue('');
+}
+test_getInstanceMapRemove(Class c) {
+  c.getInstanceMap().remove(0);
+}
+test_getInstanceListContains(Class c) {
+  c.getInstanceList().contains(0);
+}
+test_getInstanceListRemove(Class c) {
+  c.getInstanceList().remove(0);
+}
+''';
+
+main(List<String> arguments) {
+  asyncTest(() async {
+    DiagnosticCollector collector = new DiagnosticCollector();
+    CompilationResult result = await runCompiler(
+        memorySourceFiles: {'main.dart': CODE},
+        options: [Flags.analyzeOnly, Flags.analyzeMain],
+        diagnosticHandler: collector);
+    Expect.isFalse(collector.hasRegularMessages, "Unexpected analysis messages.");
+    Compiler compiler = result.compiler;
+
+
+    void checkMember(MemberElement member) {
+      if (!member.name.startsWith('test_')) return;
+
+      collector.clear();
+      checkMemberElement(compiler, member);
+      Expect.equals(1, collector.hints.length,
+          "Unexpected hint count for $member.");
+      Expect.equals(
+          MessageKind.NO_COMMON_SUBTYPES,
+          collector.hints.first.message.kind,
+          "Unexpected message kind ${collector.hints.first.message.kind} "
+          "for $member.");
+    }
+
+    compiler.mainApp.forEachLocalMember((Element element) {
+      if (element.isClass) {
+        ClassElement cls = element;
+        cls.forEachLocalMember(checkMember);
+      } else {
+        checkMember(element);
+      }
+    });
+  });
+}
diff --git a/tests/compiler/dart2js/semantic_visitor_test.dart b/tests/compiler/dart2js/semantic_visitor_test.dart
index 37d83bb..575b758 100644
--- a/tests/compiler/dart2js/semantic_visitor_test.dart
+++ b/tests/compiler/dart2js/semantic_visitor_test.dart
@@ -8,6 +8,7 @@
 import 'dart:mirrors';
 import 'package:async_helper/async_helper.dart';
 import 'package:expect/expect.dart';
+import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/constants/expressions.dart';
 import 'package:compiler/src/dart_types.dart';
 import 'package:compiler/src/diagnostics/spannable.dart';
@@ -292,9 +293,7 @@
 
   CompilationResult result = await runCompiler(
       memorySourceFiles: sourceFiles,
-      options: ['--analyze-all',
-                '--analyze-only',
-                '--enable-null-aware-operators']);
+      options: [Flags.analyzeAll, Flags.analyzeOnly]);
   Compiler compiler = result.compiler;
   testMap.forEach((String filename, Test test) {
     LibraryElement library = compiler.libraryLoader.lookupLibrary(
diff --git a/tests/compiler/dart2js/serialization_analysis_test.dart b/tests/compiler/dart2js/serialization_analysis_test.dart
index e20726f..445ea45 100644
--- a/tests/compiler/dart2js/serialization_analysis_test.dart
+++ b/tests/compiler/dart2js/serialization_analysis_test.dart
@@ -7,6 +7,7 @@
 import 'dart:async';
 import 'package:async_helper/async_helper.dart';
 import 'package:expect/expect.dart';
+import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/elements/elements.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/enqueue.dart';
@@ -180,7 +181,7 @@
   await runCompiler(
       entryPoint: entryPoint,
       memorySourceFiles: test != null ? test.sourceFiles : const {},
-      options: ['--analyze-only', '--output-type=dart'],
+      options: [Flags.analyzeOnly, '--output-type=dart'],
       diagnosticHandler: diagnosticCollector,
       beforeRun: (Compiler compiler) {
         compiler.serialization.deserializer =
diff --git a/tests/compiler/dart2js/serialization_test.dart b/tests/compiler/dart2js/serialization_test.dart
index 53bfa02..c913a3c 100644
--- a/tests/compiler/dart2js/serialization_test.dart
+++ b/tests/compiler/dart2js/serialization_test.dart
@@ -427,6 +427,26 @@
           element1.name, element2.name);
     visit(element1.functionDeclaration, element2.functionDeclaration);
   }
+
+  @override
+  void visitImportElement(ImportElement element1, ImportElement element2) {
+    visit(element1.importedLibrary, element2.importedLibrary);
+    visit(element1.library, element2.library);
+  }
+
+  @override
+  void visitExportElement(ExportElement element1, ExportElement element2) {
+    visit(element1.exportedLibrary, element2.exportedLibrary);
+    visit(element1.library, element2.library);
+  }
+
+  @override
+  void visitPrefixElement(PrefixElement element1, PrefixElement element2) {
+    check(element1, element2,
+          'name',
+          element1.name, element2.name);
+    visit(element1.library, element2.library);
+  }
 }
 
 /// Visitor that checks for equivalence of [Element] properties.
@@ -448,8 +468,8 @@
   void visitLibraryElement(LibraryElement element1, LibraryElement element2) {
     checkElementIdentities(null, null, null, element1, element2);
     check(element1, element2, 'name', element1.name, element2.name);
-    check(element1, element2, 'getLibraryName',
-          element1.getLibraryName(), element2.getLibraryName());
+    check(element1, element2, 'libraryName',
+          element1.libraryName, element2.libraryName);
     visitMembers(element1, element2);
     visit(element1.entryCompilationUnit, element2.entryCompilationUnit);
     checkElementLists(
@@ -457,18 +477,10 @@
         element1.compilationUnits.toList(),
         element2.compilationUnits.toList());
 
-    bool filterTags(LibraryTag tag) => tag.asLibraryDependency() != null;
-
-    List<LibraryTag> tags1 = element1.tags.where(filterTags).toList();
-    List<LibraryTag> tags2 = element2.tags.where(filterTags).toList();
-    checkListEquivalence(element1, element2, 'tags', tags1, tags2,
-        (Object object1, Object object2, String property,
-         LibraryDependency tag1, LibraryDependency tag2) {
-      checkElementIdentities(
-          tag1, tag2, 'getLibraryFromTag',
-          element1.getLibraryFromTag(tag1),
-          element2.getLibraryFromTag(tag2));
-    });
+    checkElementListIdentities(
+        element1, element2, 'imports', element1.imports, element2.imports);
+    checkElementListIdentities(
+        element1, element2, 'exports', element1.exports, element2.exports);
 
     List<Element> imports1 = <Element>[];
     List<Element> imports2 = <Element>[];
@@ -481,7 +493,7 @@
       imports2.add(import);
     });
     checkElementListIdentities(
-        element1, element2, 'imports', imports1, imports2);
+        element1, element2, 'importScope', imports1, imports2);
 
     List<Element> exports1 = <Element>[];
     List<Element> exports2 = <Element>[];
@@ -494,7 +506,7 @@
       exports2.add(export);
     });
     checkElementListIdentities(
-        element1, element2, 'exports', exports1, exports2);
+        element1, element2, 'exportScope', exports1, exports2);
   }
 
   @override
@@ -779,6 +791,39 @@
         element1, element2, 'fieldElement',
         element1.fieldElement, element2.fieldElement);
   }
+
+  @override
+  void visitImportElement(ImportElement element1, ImportElement element2) {
+    check(element1, element2, 'uri', element1.uri, element2.uri);
+    check(
+        element1, element2, 'isDeferred',
+        element1.isDeferred, element2.isDeferred);
+    checkElementProperties(
+        element1, element2, 'prefix',
+        element1.prefix, element2.prefix);
+    checkElementIdentities(
+        element1, element2, 'importedLibrary',
+        element1.importedLibrary, element2.importedLibrary);
+  }
+
+  @override
+  void visitExportElement(ExportElement element1, ExportElement element2) {
+    check(element1, element2, 'uri', element1.uri, element2.uri);
+    checkElementIdentities(
+        element1, element2, 'importedLibrary',
+        element1.exportedLibrary, element2.exportedLibrary);
+  }
+
+  @override
+  void visitPrefixElement(PrefixElement element1, PrefixElement element2) {
+    check(
+        element1, element2, 'isDeferred',
+        element1.isDeferred, element2.isDeferred);
+    checkElementIdentities(
+        element1, element2, 'importedLibrary',
+        element1.deferredImport, element2.deferredImport);
+    // TODO(johnniwinther): Check members.
+  }
 }
 
 /// Visitor that checks for equivalence of [DartType]s.
diff --git a/tests/compiler/dart2js/show_package_warnings_test.dart b/tests/compiler/dart2js/show_package_warnings_test.dart
index 5673032..e94983c 100644
--- a/tests/compiler/dart2js/show_package_warnings_test.dart
+++ b/tests/compiler/dart2js/show_package_warnings_test.dart
@@ -7,6 +7,7 @@
 import 'dart:async';
 import 'package:async_helper/async_helper.dart';
 import 'package:expect/expect.dart';
+import 'package:compiler/src/commandline_options.dart';
 import 'memory_compiler.dart';
 
 /// Error code that creates 1 warning, 1 hint, and 1 info.
@@ -47,9 +48,9 @@
              int warnings: 0,
              int hints: 0,
              int infos: 0}) async {
-  var options = ['--analyze-only', '--analyze-all'];
+  var options = [Flags.analyzeOnly, Flags.analyzeAll];
   if (showPackageWarnings) {
-    options.add('--show-package-warnings');
+    options.add(Flags.showPackageWarnings);
   }
   var collector = new DiagnosticCollector();
   await runCompiler(
diff --git a/tests/compiler/dart2js/space_test.dart b/tests/compiler/dart2js/space_test.dart
index fbf933d..b721952 100644
--- a/tests/compiler/dart2js/space_test.dart
+++ b/tests/compiler/dart2js/space_test.dart
@@ -5,6 +5,7 @@
 import 'dart:io';
 import 'package:compiler/src/dart2js.dart'
   as dart2js;
+import 'package:compiler/src/commandline_options.dart';
 
 main() {
   Uri currentDirectory = Uri.base;
@@ -13,6 +14,6 @@
   Directory.current = script.resolve("path with spaces").toFilePath();
 
   return dart2js.main(["--library-root=${libraryRoot.toFilePath()}",
-                       "--analyze-only",
+                       Flags.analyzeOnly,
                        "file with spaces.dart"]);
 }
diff --git a/tests/compiler/dart2js/subtypeset_test.dart b/tests/compiler/dart2js/subtypeset_test.dart
new file mode 100644
index 0000000..6673041
--- /dev/null
+++ b/tests/compiler/dart2js/subtypeset_test.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2015, 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 for iterators on for [SubclassNode].
+
+library world_test;
+
+import 'package:expect/expect.dart';
+import 'package:async_helper/async_helper.dart';
+import 'type_test_helper.dart';
+import 'package:compiler/src/elements/elements.dart'
+       show Element, ClassElement;
+import 'package:compiler/src/universe/class_set.dart';
+import 'package:compiler/src/world.dart';
+
+void main() {
+  asyncTest(() => TypeEnvironment.create(r"""
+      ///        A
+      ///       / \
+      ///      B   C
+      ///     /   /|\
+      ///    D   E F G 
+      ///
+      class A {
+        call(H h, I i) {} // Make `H` and `I` part of the world.
+      }
+      class B extends A implements C {}
+      class C extends A {}
+      class D extends B implements A {}
+      class E extends C implements B {}
+      class F extends C {}
+      class G extends C {}
+      class H implements C {}
+      class I implements H {}
+      """,
+        mainSource: r"""
+      main() {
+        new A();
+        new C();
+        new D();
+        new E();
+        new F();
+        new G();
+      }
+      """,
+      useMockCompiler: false).then((env) {
+    World world = env.compiler.world;
+
+    ClassElement A = env.getElement("A");
+    ClassElement B = env.getElement("B");
+    ClassElement C = env.getElement("C");
+    ClassElement D = env.getElement("D");
+    ClassElement E = env.getElement("E");
+    ClassElement F = env.getElement("F");
+    ClassElement G = env.getElement("G");
+    ClassElement H = env.getElement("H");
+    ClassElement I = env.getElement("I");
+
+    void checkClass(ClassElement cls,
+                    List<ClassElement> subtypes) {
+      ClassSet node = world.getClassSet(cls);
+      print('$cls:\n${node}');
+      Expect.listEquals(subtypes,
+          node.subtypes().toList(),
+          "Unexpected subtypes of ${cls.name}:\n"
+          "Expected: $subtypes\n"
+          "Found   : ${node.subtypes().toList()}");
+    }
+
+    checkClass(A, [A, C, E, F, G, B, D, H, I]);
+    checkClass(B, [B, D, E]);
+    checkClass(C, [C, E, F, G, H, B, D, I]);
+    checkClass(D, [D]);
+    checkClass(E, [E]);
+    checkClass(F, [F]);
+    checkClass(G, [G]);
+    checkClass(H, [H, I]);
+    checkClass(I, [I]);
+  }));
+}
diff --git a/tests/compiler/dart2js/tag_mapping_test.dart b/tests/compiler/dart2js/tag_mapping_test.dart
index 04af1fc..ed781f3 100644
--- a/tests/compiler/dart2js/tag_mapping_test.dart
+++ b/tests/compiler/dart2js/tag_mapping_test.dart
@@ -33,11 +33,11 @@
     Expect.isNotNull(mainApp, 'Could not find main.dart library');
     Expect.isNotNull(lib, 'Could not find library.dart library');
 
-    Import tag = mainApp.tags.single;
-    Expect.isNotNull(tag, 'Could not find import tag in $mainApp');
+    ImportElement import = mainApp.imports.single;
+    Expect.isNotNull(import, 'Could not find import tag in $mainApp');
 
     // Test that we can get from the import tag in main.dart to the
     // library element representing library.dart.
-    Expect.identical(lib, mainApp.getLibraryFromTag(tag));
+    Expect.identical(lib, import.importedLibrary);
   }));
 }
diff --git a/tests/compiler/dart2js/trust_type_annotations2_test.dart b/tests/compiler/dart2js/trust_type_annotations2_test.dart
index 4eeb0a6..f688380 100644
--- a/tests/compiler/dart2js/trust_type_annotations2_test.dart
+++ b/tests/compiler/dart2js/trust_type_annotations2_test.dart
@@ -30,7 +30,7 @@
         options: ['--trust-type-annotations']);
     var compiler = result.compiler;
     var element = compiler.mainFunction;
-    var code = compiler.backend.assembleCode(element);
+    var code = compiler.backend.getGeneratedCode(element);
     Expect.isTrue(code.contains('+'), code);
   });
 }
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart
index c906192..0e6a54e 100644
--- a/tests/compiler/dart2js/type_checker_test.dart
+++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -34,6 +34,8 @@
   List tests = [testSimpleTypes,
                 testReturn,
                 testFor,
+                testSyncForIn,
+                testAsyncForIn,
                 testWhile,
                 testTry,
                 testSwitch,
@@ -126,6 +128,302 @@
 //  check("for (String s in true) {}", MessageKind.METHOD_NOT_FOUND);
 }
 
+
+testSyncForIn(MockCompiler compiler) {
+  String script = """
+class HasUntypedIterator {
+  get iterator => null;
+}
+
+class HasIntIterator {
+  Iterator<int> get iterator => null;
+}
+
+class HasNoIterator {
+}
+
+class HasCustomIntIterator {
+  CustomIntIterator get iterator => null;
+}
+
+class CustomIntIterator {
+  int current;
+}
+
+class HasCustomNoCurrentIterator {
+  CustomNoCurrentIterator get iterator => null;
+}
+
+class CustomNoCurrentIterator {
+}
+
+var topLevelDyn;
+String topLevelString;
+int topLevelInt;
+
+class Class {
+  void forIn() {}
+
+  var instanceDyn;
+  String instanceString;
+  int instanceInt;
+
+  static var staticDyn;
+  static String staticString;
+  static int staticInt;
+}
+""";
+  compiler.parseScript(script);
+  ClassElement foo = compiler.mainApp.find("Class");
+  foo.ensureResolved(compiler);
+  FunctionElement method = foo.lookupLocalMember('forIn');
+
+  analyzeIn(compiler, method, """{ 
+      for (var e in <String>[]) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      for (String e in <String>[]) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      for (int e in <String>[]) {} 
+  }""", hints: MessageKind.FORIN_NOT_ASSIGNABLE);
+  analyzeIn(compiler, method, """{ 
+      for (int e in []) {} 
+  }""");
+
+  analyzeIn(compiler, method, """{ 
+      for (var e in new HasUntypedIterator()) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      for (String e in new HasUntypedIterator()) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      for (int e in new HasUntypedIterator()) {} 
+  }""");
+
+  analyzeIn(compiler, method, """{ 
+      for (var e in new HasIntIterator()) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      for (String e in new HasIntIterator()) {} 
+  }""", hints: MessageKind.FORIN_NOT_ASSIGNABLE);
+  analyzeIn(compiler, method, """{ 
+      for (int e in new HasIntIterator()) {} 
+  }""");
+
+  analyzeIn(compiler, method, """{ 
+      for (var e in new HasNoIterator()) {} 
+  }""", warnings: MessageKind.MEMBER_NOT_FOUND);
+  analyzeIn(compiler, method, """{ 
+      for (String e in new HasNoIterator()) {} 
+  }""", warnings: MessageKind.MEMBER_NOT_FOUND);
+  analyzeIn(compiler, method, """{ 
+      for (int e in new HasNoIterator()) {} 
+  }""", warnings: MessageKind.MEMBER_NOT_FOUND);
+
+  analyzeIn(compiler, method, """{ 
+      for (var e in new HasCustomIntIterator()) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      for (String e in new HasCustomIntIterator()) {} 
+  }""", hints: MessageKind.FORIN_NOT_ASSIGNABLE);
+  analyzeIn(compiler, method, """{ 
+      for (int e in new HasCustomIntIterator()) {} 
+  }""");
+
+  analyzeIn(compiler, method, """{ 
+      for (var e in new HasCustomNoCurrentIterator()) {} 
+  }""", hints: MessageKind.MEMBER_NOT_FOUND);
+  analyzeIn(compiler, method, """{ 
+      for (String e in new HasCustomNoCurrentIterator()) {} 
+  }""", hints: MessageKind.MEMBER_NOT_FOUND);
+  analyzeIn(compiler, method, """{ 
+      for (int e in new HasCustomNoCurrentIterator()) {} 
+  }""", hints: MessageKind.MEMBER_NOT_FOUND);
+
+  analyzeIn(compiler, method, """{ 
+      var localDyn; 
+      for (localDyn in <String>[]) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      String localString; 
+      for (localString in <String>[]) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      int localInt; 
+      for (localInt in <String>[]) {} 
+  }""", hints: MessageKind.FORIN_NOT_ASSIGNABLE);
+
+  analyzeIn(compiler, method, """{ 
+      for (topLevelDyn in <String>[]) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      for (topLevelString in <String>[]) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      for (topLevelInt in <String>[]) {} 
+  }""", hints: MessageKind.FORIN_NOT_ASSIGNABLE);
+
+  analyzeIn(compiler, method, """{ 
+      for (instanceDyn in <String>[]) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      for (instanceString in <String>[]) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      for (instanceInt in <String>[]) {} 
+  }""", hints: MessageKind.FORIN_NOT_ASSIGNABLE);
+
+  analyzeIn(compiler, method, """{ 
+      for (staticDyn in <String>[]) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      for (staticString in <String>[]) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      for (staticInt in <String>[]) {} 
+  }""", hints: MessageKind.FORIN_NOT_ASSIGNABLE);
+}
+
+testAsyncForIn(MockCompiler compiler) {
+  String script = """
+abstract class CustomStream<T> implements Stream<T> {}
+abstract class StringStream implements Stream<String> {}
+
+var topLevelDyn;
+String topLevelString;
+int topLevelInt;
+
+class Class {
+  void forIn() async {}
+
+  var instanceDyn;
+  String instanceString;
+  int instanceInt;
+
+  static var staticDyn;
+  static String staticString;
+  static int staticInt;
+}
+""";
+  compiler.parseScript(script);
+  ClassElement foo = compiler.mainApp.find("Class");
+  foo.ensureResolved(compiler);
+  FunctionElement method = foo.lookupLocalMember('forIn');
+
+  analyzeIn(compiler, method, """{
+      var stream;
+      await for (var e in stream) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      var stream;
+      await for (String e in stream) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      var stream;
+      await for (int e in stream) {} 
+  }""");
+
+  analyzeIn(compiler, method, """{ 
+      await for (var e in []) {} 
+  }""", hints: MessageKind.NOT_ASSIGNABLE);
+
+  analyzeIn(compiler, method, """{ 
+      Stream<String> stream;
+      await for (var e in stream) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      Stream<String> stream;
+      await for (String e in stream) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      Stream<String> stream;
+      await for (int e in stream) {} 
+  }""", hints: MessageKind.FORIN_NOT_ASSIGNABLE);
+
+  analyzeIn(compiler, method, """{ 
+      CustomStream<String> stream;
+      await for (var e in stream) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      CustomStream<String> stream;
+      await for (String e in stream) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      CustomStream<String> stream;
+      await for (int e in stream) {} 
+  }""", hints: MessageKind.FORIN_NOT_ASSIGNABLE);
+
+  analyzeIn(compiler, method, """{ 
+      StringStream stream;
+      await for (var e in stream) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      StringStream stream;
+      await for (String e in stream) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      StringStream stream;
+      await for (int e in stream) {} 
+  }""", hints: MessageKind.FORIN_NOT_ASSIGNABLE);
+
+  analyzeIn(compiler, method, """{ 
+      Stream<String> stream;
+      var localDyn; 
+      await for (localDyn in stream) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      Stream<String> stream;
+      String localString; 
+      await for (localString in stream) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      Stream<String> stream;
+      int localInt; 
+      await for (localInt in stream) {} 
+  }""", hints: MessageKind.FORIN_NOT_ASSIGNABLE);
+
+  analyzeIn(compiler, method, """{ 
+      Stream<String> stream;
+      await for (topLevelDyn in stream) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      Stream<String> stream;
+      await for (topLevelString in stream) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      Stream<String> stream;
+      await for (topLevelInt in stream) {} 
+  }""", hints: MessageKind.FORIN_NOT_ASSIGNABLE);
+
+  analyzeIn(compiler, method, """{ 
+      Stream<String> stream;
+      await for (instanceDyn in stream) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      Stream<String> stream;
+      await for (instanceString in stream) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      Stream<String> stream;
+      await for (instanceInt in stream) {} 
+  }""", hints: MessageKind.FORIN_NOT_ASSIGNABLE);
+
+  analyzeIn(compiler, method, """{ 
+      Stream<String> stream;
+      await for (staticDyn in stream) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      Stream<String> stream;
+      await for (staticString in stream) {} 
+  }""");
+  analyzeIn(compiler, method, """{ 
+      Stream<String> stream;
+      await for (staticInt in stream) {} 
+  }""", hints: MessageKind.FORIN_NOT_ASSIGNABLE);
+}
+
+
 testWhile(MockCompiler compiler) {
   check(String code, {warnings}) {
     analyze(compiler, code, warnings: warnings);
@@ -614,7 +912,7 @@
                      int localMethod(String str) { return 0; }
                      $text
                    }""",
-                expectedWarnings);
+                warnings: expectedWarnings);
     }
 
 
@@ -894,7 +1192,7 @@
   ClassElement foo = compiler.mainApp.find("Foo");
   foo.ensureResolved(compiler);
   Element method = foo.lookupLocalMember('method');
-  analyzeIn(compiler, method, "{ int i = this; }", NOT_ASSIGNABLE);
+  analyzeIn(compiler, method, "{ int i = this; }", warnings: NOT_ASSIGNABLE);
   analyzeIn(compiler, method, "{ Object o = this; }");
   analyzeIn(compiler, method, "{ Foo f = this; }");
 }
@@ -914,7 +1212,8 @@
   ClassElement B = compiler.mainApp.find("B");
   B.ensureResolved(compiler);
   Element method = B.lookupLocalMember('method');
-  analyzeIn(compiler, method, "{ int i = super.field; }", NOT_ASSIGNABLE);
+  analyzeIn(compiler, method, "{ int i = super.field; }",
+      warnings: NOT_ASSIGNABLE);
   analyzeIn(compiler, method, "{ Object o = super.field; }");
   analyzeIn(compiler, method, "{ String s = super.field; }");
 }
@@ -1222,14 +1521,17 @@
   Element method = foo.lookupLocalMember('method');
 
   analyzeIn(compiler, method, "{ Type type = T; }");
-  analyzeIn(compiler, method, "{ T type = T; }", NOT_ASSIGNABLE);
-  analyzeIn(compiler, method, "{ int type = T; }", NOT_ASSIGNABLE);
+  analyzeIn(compiler, method, "{ T type = T; }", warnings: NOT_ASSIGNABLE);
+  analyzeIn(compiler, method, "{ int type = T; }", warnings: NOT_ASSIGNABLE);
 
   analyzeIn(compiler, method, "{ String typeName = T.toString(); }");
-  analyzeIn(compiler, method, "{ T.foo; }", MEMBER_NOT_FOUND);
-  analyzeIn(compiler, method, "{ T.foo = 0; }", MessageKind.SETTER_NOT_FOUND);
-  analyzeIn(compiler, method, "{ T.foo(); }", MessageKind.METHOD_NOT_FOUND);
-  analyzeIn(compiler, method, "{ T + 1; }", MessageKind.OPERATOR_NOT_FOUND);
+  analyzeIn(compiler, method, "{ T.foo; }", warnings: MEMBER_NOT_FOUND);
+  analyzeIn(compiler, method, "{ T.foo = 0; }",
+      warnings: MessageKind.SETTER_NOT_FOUND);
+  analyzeIn(compiler, method, "{ T.foo(); }",
+      warnings: MessageKind.METHOD_NOT_FOUND);
+  analyzeIn(compiler, method, "{ T + 1; }",
+      warnings: MessageKind.OPERATOR_NOT_FOUND);
 }
 
 void testTypeVariableLookup1(MockCompiler compiler) {
@@ -1254,7 +1556,7 @@
   FunctionElement methodTest = classTest.lookupLocalMember("test");
 
   test(String expression, [message]) {
-    analyzeIn(compiler, methodTest, "{ $expression; }", message);
+    analyzeIn(compiler, methodTest, "{ $expression; }", warnings: message);
   }
 
   test('s.field');
@@ -1294,7 +1596,7 @@
   FunctionElement methodTest = classTest.lookupLocalMember("test");
 
   test(String expression, [message]) {
-    analyzeIn(compiler, methodTest, "{ $expression; }", message);
+    analyzeIn(compiler, methodTest, "{ $expression; }", warnings: message);
   }
 
   test('s.field');
@@ -1316,7 +1618,7 @@
   FunctionElement methodTest = classTest.lookupLocalMember("test");
 
   test(String expression, [message]) {
-    analyzeIn(compiler, methodTest, "{ $expression; }", message);
+    analyzeIn(compiler, methodTest, "{ $expression; }", warnings: message);
   }
 
   test('s.toString');
@@ -2027,18 +2329,19 @@
   FunctionElement method = foo.lookupLocalMember('method');
   analyzeIn(compiler, method, "{ await 0; }");
   analyzeIn(compiler, method, "{ int i = await 0; }");
-  analyzeIn(compiler, method, "{ String s = await 0; }", NOT_ASSIGNABLE);
+  analyzeIn(compiler, method, "{ String s = await 0; }",
+      warnings: NOT_ASSIGNABLE);
   analyzeIn(compiler, method, "{ await asyncInt(); }");
   analyzeIn(compiler, method, "{ int i = await asyncInt(); }");
   analyzeIn(compiler, method, "{ String s = await asyncInt(); }",
-            NOT_ASSIGNABLE);
+      warnings: NOT_ASSIGNABLE);
   analyzeIn(compiler, method, "{ Foo f = self(); }");
   analyzeIn(compiler, method, "{ Foo f = await self(); }");
   analyzeIn(compiler, method, "{ Foo f = await self().asyncInt(); }",
-            NOT_ASSIGNABLE);
+      warnings: NOT_ASSIGNABLE);
   analyzeIn(compiler, method, "{ int i = await self().asyncInt(); }");
   analyzeIn(compiler, method, "{ String s = await self().asyncInt(); }",
-            NOT_ASSIGNABLE);
+      warnings: NOT_ASSIGNABLE);
 }
 
 testAsyncReturn(MockCompiler compiler) {
@@ -2283,9 +2586,11 @@
 analyzeIn(MockCompiler compiler,
           FunctionElement element,
           String text,
-          [expectedWarnings]) {
-  if (expectedWarnings == null) expectedWarnings = [];
-  if (expectedWarnings is !List) expectedWarnings = [expectedWarnings];
+          {warnings, hints}) {
+  if (warnings == null) warnings = [];
+  if (warnings is !List) warnings = [warnings];
+  if (hints == null) hints = [];
+  if (hints is !List) hints = [hints];
 
   compiler.resolver.resolve(element);
   Token tokens = scan(text);
@@ -2301,5 +2606,6 @@
   compiler.clearMessages();
   checker.analyze(node);
   generateOutput(compiler, text);
-  compareWarningKinds(text, expectedWarnings, compiler.warnings);
+  compareWarningKinds(text, warnings, compiler.warnings);
+  compareWarningKinds(text, hints, compiler.hints);
 }
diff --git a/tests/compiler/dart2js/type_test_helper.dart b/tests/compiler/dart2js/type_test_helper.dart
index 4f6dcd1..c67d0ba 100644
--- a/tests/compiler/dart2js/type_test_helper.dart
+++ b/tests/compiler/dart2js/type_test_helper.dart
@@ -8,6 +8,7 @@
 import 'package:expect/expect.dart';
 import 'compiler_helper.dart' as mock;
 import 'memory_compiler.dart' as memory;
+import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/dart_types.dart';
 import 'package:compiler/src/compiler.dart'
     show Compiler;
@@ -65,7 +66,7 @@
           memorySourceFiles: {'main.dart': source},
           diagnosticHandler: collector,
           options: stopAfterTypeInference
-              ? [] : ['--analyze-all', '--analyze-only']);
+              ? [] : [Flags.analyzeAll, Flags.analyzeOnly]);
       getErrors = () => collector.errors;
       getWarnings = () => collector.warnings;
     }
diff --git a/tests/compiler/dart2js/use_checks_test.dart b/tests/compiler/dart2js/use_checks_test.dart
index 26d81c6..4056696 100644
--- a/tests/compiler/dart2js/use_checks_test.dart
+++ b/tests/compiler/dart2js/use_checks_test.dart
@@ -29,7 +29,7 @@
         options: ['--enable-checked-mode']);
     var compiler = result.compiler;
     var element = compiler.mainFunction;
-    var code = compiler.backend.assembleCode(element);
+    var code = compiler.backend.getGeneratedCode(element);
     Expect.isTrue(code.contains('+'), code);
   });
 }
diff --git a/tests/compiler/dart2js/value_range3_test.dart b/tests/compiler/dart2js/value_range3_test.dart
index 2e65cee..91c3c37 100644
--- a/tests/compiler/dart2js/value_range3_test.dart
+++ b/tests/compiler/dart2js/value_range3_test.dart
@@ -27,7 +27,7 @@
     var result = await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
     var compiler = result.compiler;
     var element = compiler.mainFunction;
-    var code = compiler.backend.assembleCode(element);
+    var code = compiler.backend.getGeneratedCode(element);
     Expect.isFalse(code.contains('ioore'));
   });
 }
diff --git a/tests/compiler/dart2js/warnings_checker.dart b/tests/compiler/dart2js/warnings_checker.dart
index cf31943..1652a1e 100644
--- a/tests/compiler/dart2js/warnings_checker.dart
+++ b/tests/compiler/dart2js/warnings_checker.dart
@@ -10,6 +10,7 @@
 import 'package:expect/expect.dart';
 import 'package:async_helper/async_helper.dart';
 import 'memory_compiler.dart';
+import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/filenames.dart';
 import 'package:compiler/src/io/source_file.dart';
 import 'package:compiler/src/source_file_provider.dart';
@@ -41,7 +42,7 @@
     await runCompiler(
         entryPoint: uri,
         diagnosticHandler: collector,
-        options: ['--analyze-only'],
+        options: [Flags.analyzeOnly],
         showDiagnostics: verbose);
     Map<String, List<int>> statusMap = tests[test];
     // Line numbers with known unexpected warnings.
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index e0321e9..2edae80 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -75,15 +75,13 @@
 async_stacktrace_test/none: RuntimeError # $async$temp1.Tracer$ is not a function
 closure_capture5_test: Crash # (i=0): For-loop variable captured in loop header
 deferred/deferred_class_test: RuntimeError # Z.loadLibrary is not a function
-deferred/deferred_constant2_test: Crash # (lib.C1): deferred access is not implemented
-deferred/deferred_constant3_test: Crash # (lib.C1): deferred access is not implemented
+deferred/deferred_constant2_test: RuntimeError # TypeError: U.loadLibrary is not a function
+deferred/deferred_constant3_test: RuntimeError # TypeError: Y.loadLibrary is not a function
 deferred/deferred_constant4_test: RuntimeError # B.loadLibrary is not a function
 deferred/deferred_function_test: Crash # (lib.foo): deferred access is not implemented
-deferred/deferred_mirrors1_test: Crash # (lazy.foo()): deferred access is not implemented
+deferred/deferred_mirrors1_test: RuntimeError # TypeError: U.loadLibrary is not a function
 deferred/deferred_overlapping_test: RuntimeError # E.loadLibrary is not a function
-deferred_fail_and_retry_test: Crash # (lib.foo()): deferred access is not implemented
-deferred_fail_and_retry_worker_test: Crash # (lib.foo()): deferred access is not implemented
-deferred_split_test: Crash # (b.createA()): deferred access is not implemented
+deferred_split_test: RuntimeError # TypeError: Z.loadLibrary is not a function
 lookup_map/live_entry_through_mirrors_test: Crash # (static Iterable<Str...  cannot handle sync*/async* functions
 mirror_printer_test: Crash # (static Iterable<Str...  cannot handle sync*/async* functions
 mirror_test: Crash # (static Iterable<Str...  cannot handle sync*/async* functions
diff --git a/tests/compiler/dart2js_extra/js_array_index_error_test.dart b/tests/compiler/dart2js_extra/js_array_index_error_test.dart
new file mode 100644
index 0000000..9cfc873
--- /dev/null
+++ b/tests/compiler/dart2js_extra/js_array_index_error_test.dart
@@ -0,0 +1,330 @@
+// Copyright (c) 2015, 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 optimized JSArray indexers enerate the same error as dyncamically
+// dispatched calls.
+
+
+import 'package:expect/expect.dart';
+
+@NoInline() @AssumeDynamic()
+confuse(x) => x;
+
+
+Error getError(action(), name, part) {
+  try {
+    action();
+  } catch (e) {
+    return e;
+  }
+  Expect.fail('must throw: $name: $part');
+}
+
+indexErrorContainsIndex() {
+  makeFault(i) => () => confuse([])[i];
+
+  var name = 'index error contains index';
+  var e1 = getError(makeFault(1234), name, 'small');
+  var e2 = getError(makeFault(1234000), name, 'medium');
+  var e3 = getError(makeFault(1234000000000), name, 'large');
+
+  Expect.equals('$e1', '$e2'.replaceAll('000', ''));
+  Expect.equals('$e1', '$e3'.replaceAll('000', ''));
+  Expect.equals('$e1'.length + 3, '$e2'.length);
+  Expect.equals('$e1'.length + 9, '$e3'.length);
+}
+
+
+compare(name, fault1(), fault2(), fault3()) {
+  var e1 = getError(fault1, name, 'fault1');
+  var e2 = getError(fault2, name, 'fault2');
+  var e3 = getError(fault3, name, 'fault3');
+
+  Expect.equals('$e1', '$e2', '$name: fault1 vs fault2');
+  Expect.equals('$e1', '$e3', '$name: fault1 vs fault3');
+}
+
+// These tests are a bit tedious and avoid common helpers with higher order
+// functions to keep the type inference for each test independent from the
+// others.
+//
+// The 'constant' tests have a constant index which might permit different
+// optimizations to a variable index.  e.g. the compiler might determine HUGE is
+// always out of range since the maximum JavaScript Array length is 2^32.
+//
+// The 'variable' forms take the index as an argument.
+
+const int HUGE = 1000000000000;
+
+constantIndexEmpty() {
+  // Single dynamic receiver indexing might go via one-shot interceptor that
+  // might have an accelerated path.
+  fault1() => confuse([])[0];
+
+  fault2() {
+    var a = [];
+    while (confuse(false)) a.add(1);
+    // Easily inferred type and open coded indexer.
+    return a[0];
+  }
+
+  fault3() {
+    var a = confuse([]);
+    // Multiple indexing might go via shared interceptor.
+    return [a[0], a[1], a[2]];
+  }
+
+  compare('constant index on empty list', fault1, fault2, fault3);
+}
+
+constantIndexHugeEmpty() {
+  // Single dynamic receiver indexing might go via one-shot interceptor that
+  // might have an accelerated path.
+  fault1() => confuse([])[HUGE];
+
+  fault2() {
+    var a = [];
+    while (confuse(false)) a.add(1);
+    return a[HUGE];
+  }
+
+  fault3() {
+    var a = confuse([]);
+    return [a[HUGE], a[1], a[2]];
+  }
+
+  compare('constant index on empty list with huge index',
+      fault1, fault2, fault3);
+}
+
+constantIndexNonempty() {
+  // Single dynamic receiver indexing might go via one-shot interceptor that
+  // might have an accelerated path.
+  fault1() => confuse([1])[1];
+
+  fault2() {
+    var a = [1];
+    while (confuse(false)) a.add(1);
+    // Easily inferred type and open coded indexer.
+    return a[1];
+  }
+
+  fault3() {
+    var a = confuse([1]);
+    // Multiple indexing might go via shared interceptor.
+    return [a[1], a[2], a[3]];
+  }
+
+  compare('constant index on non-empty list', fault1, fault2, fault3);
+}
+
+constantIndexHugeNonempty() {
+  // Single dynamic receiver indexing might go via one-shot interceptor that
+  // might have an accelerated path.
+  fault1() => confuse([1])[HUGE];
+
+  fault2() {
+    var a = [1];
+    while (confuse(false)) a.add(1);
+    // Easily inferred type and open coded indexer.
+    return a[HUGE];
+  }
+
+  fault3() {
+    var a = confuse([1]);
+    // Multiple indexing might go via shared interceptor.
+    return [a[HUGE], a[1], a[2]];
+  }
+
+  compare('constant index on non-empty list with huge index',
+      fault1, fault2, fault3);
+}
+
+constantIndexSetEmpty() {
+  fault1() {
+    // Single dynamic receiver indexing might go via one-shot interceptor that
+    // might have an accelerated path.
+    confuse([])[0] = 0;
+  }
+
+  fault2() {
+    var a = [];
+    while (confuse(false)) a.add(1);
+    // Easily inferred type and open coded indexer.
+    a[0] = 0;
+    return a;
+  }
+
+  fault3() {
+    var a = confuse([]);
+    // Multiple indexing might go via shared interceptor.
+    a[0] = 0;
+    a[1] = 0;
+    a[2] = 0;
+    return a;
+  }
+
+  compare('coinstant index-set on empty list', fault1, fault2, fault3);
+}
+
+constantIndexSetNonempty() {
+  fault1() {
+    // Single dynamic receiver indexing might go via one-shot interceptor that
+    // might have an accelerated path.
+    confuse([1])[1] = 0;
+  }
+
+  fault2() {
+    var a = [1];
+    while (confuse(false)) a.add(1);
+    // Easily inferred type and open coded indexer.
+    a[1] = 0;
+    return a;
+  }
+
+  fault3() {
+    var a = confuse([1]);
+    // Multiple indexing might go via shared interceptor.
+    a[0] = 0;
+    a[1] = 0;
+    a[2] = 0;
+    return a;
+  }
+
+  compare('constant index-set on non-empty list', fault1, fault2, fault3);
+}
+
+
+variableIndexEmpty(index, qualifier) {
+  // Single dynamic receiver indexing might go via one-shot interceptor that
+  // might have an accelerated path.
+  fault1() => confuse([])[index];
+
+  fault2() {
+    var a = [];
+    while (confuse(false)) a.add(1);
+    // Easily inferred type and open coded indexer.
+    return a[index];
+  }
+
+  fault3() {
+    var a = confuse([]);
+    // Multiple indexing might go via shared interceptor.
+    return [a[index], a[1], a[2]];
+  }
+
+  compare('general index on empty list $qualifier', fault1, fault2, fault3);
+}
+
+variableIndexNonempty(index, qualifier) {
+  // Single dynamic receiver indexing might go via one-shot interceptor that
+  // might have an accelerated path.
+  fault1() => confuse([1])[index];
+
+  fault2() {
+    var a = [1];
+    while (confuse(false)) a.add(1);
+    // Easily inferred type and open coded indexer.
+    return a[index];
+  }
+
+  fault3() {
+    var a = confuse([1]);
+    // Multiple indexing might go via shared interceptor.
+    return [a[index], a[1], a[2]];
+  }
+
+  compare('variable index on non-empty list $qualifier',
+      fault1, fault2, fault3);
+}
+
+variableIndexSetEmpty(index, qualifier) {
+  fault1() {
+    var a = confuse([]);
+    // Single dynamic receiver indexing might go via one-shot interceptor that
+    // might have an accelerated path.
+    a[index] = 1;
+    return a;
+  }
+
+  fault2() {
+    var a = [];
+    while (confuse(false)) a.add(1);
+    // Easily inferred type and open coded indexer.
+    a[index] = 1;
+    return a;
+  }
+
+  fault3() {
+    var a = confuse([]);
+    // Multiple indexing might go via shared interceptor.
+    a[index] = 1;
+    a[2] = 2;
+    a[3] = 3;
+    return a;
+  }
+
+  compare('variable index-set on empty list $qualifier',
+      fault1, fault2, fault3);
+}
+
+variableIndexSetNonempty(index, qualifier) {
+  fault1() {
+    var a = confuse([1]);
+    // Single dynamic receiver indexing might go via one-shot interceptor that
+    // might have an accelerated path.
+    a[index] = 1;
+    return a;
+  }
+
+  fault2() {
+    var a = [1];
+    while (confuse(false)) a.add(1);
+    // Easily inferred type and open coded indexer.
+    a[index] = 1;
+    return a;
+  }
+
+  fault3() {
+    var a = confuse([1]);
+    // Multiple indexing might go via shared interceptor.
+    a[index] = 1;
+    a[2] = 2;
+    a[3] = 3;
+    return a;
+  }
+
+  compare('variable index-set on non-empty list $qualifier',
+      fault1, fault2, fault3);
+}
+
+
+main() {
+  indexErrorContainsIndex();
+
+  constantIndexEmpty();
+  constantIndexHugeEmpty();
+  constantIndexNonempty();
+  constantIndexHugeNonempty();
+  constantIndexSetEmpty();
+  constantIndexSetNonempty();
+
+  variableIndexEmpty(0, 'zero index');
+  variableIndexEmpty(10, 'small index');
+  variableIndexEmpty(-1, 'negative index');
+  variableIndexEmpty(HUGE, 'huge index');
+
+  variableIndexNonempty(10, 'small index');
+  variableIndexNonempty(-1, 'negative index');
+  variableIndexNonempty(HUGE, 'huge index');
+
+  variableIndexSetEmpty(0, 'zero index');
+  variableIndexSetEmpty(10, 'small index');
+  variableIndexSetEmpty(-1, 'negative index');
+  variableIndexSetEmpty(HUGE, 'huge index');
+
+  variableIndexSetNonempty(10, 'small index');
+  variableIndexSetNonempty(-1, 'negative index');
+  variableIndexSetNonempty(HUGE, 'huge index');
+}
diff --git a/tests/compiler/dart2js_extra/js_array_removeLast_error_test.dart b/tests/compiler/dart2js_extra/js_array_removeLast_error_test.dart
new file mode 100644
index 0000000..6fc14dc
--- /dev/null
+++ b/tests/compiler/dart2js_extra/js_array_removeLast_error_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2015, 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 optimized JSArray removeLast() calls generate the same error as
+// dyncamically dispatched calls.
+
+import 'package:expect/expect.dart';
+
+@NoInline() @AssumeDynamic()
+confuse(x) => x;
+
+
+Error getError(action()) {
+  try {
+    action();
+    Expect.fail('must throw');
+  } catch (e) {
+    return e;
+  }
+}
+
+main() {
+  fault1() {
+    return confuse([]).removeLast();
+  }
+
+  fault2() {
+    var a = [];
+    while (confuse(false)) a.add(1);
+    // This one should be optimized since [a] is a growable JSArray.
+    return a.removeLast();
+  }
+
+  var e1 = getError(fault1);
+  var e2 = getError(fault2);
+
+  Expect.equals('$e1', '$e2');
+}
diff --git a/tests/corelib/list_test.dart b/tests/corelib/list_test.dart
index 5187ee8..c26c1cf 100644
--- a/tests/corelib/list_test.dart
+++ b/tests/corelib/list_test.dart
@@ -46,6 +46,89 @@
   testTypedGrowableList(new Int32List(0).toList());
 
   testListConstructor();
+
+  testErrors();
+}
+
+void testErrors() {
+  // Regression for issue http://dartbug.com/24295
+  testIndexError(list, index, name) {
+    try {
+      list[list.length];
+    } catch (err, s) {
+      Expect.isTrue(err is RangeError, "$name[$index]");
+      Expect.equals(list.length, err.invalidValue, "$name[$index] value");
+      Expect.equals(list.length - 1, err.end, "$name[$index] end");
+      Expect.equals(0, err.start, "$name[$index] start");
+    }
+  }
+  testIndex(list, name) {
+    testIndexError(list, list.length, name);   // Just too big.
+    testIndexError(list, -1, name);            // Negative.
+    testIndexError(list, 0x123456789, name);   // > 2^32.
+    testIndexError(list, -0x123456789, name);  // < -2^32.
+  }
+
+  // Slices.
+  testSliceError(list, start, end, name) {
+    name = "$name[$start:$end]";
+    var realError;
+    try {
+      RangeError.checkValidRange(start, end, list.length);
+    } catch (e) {
+      realError = e;
+    }
+    var result;
+    try {
+      result = list.sublist(start, end);
+    } catch (actualError) {
+      Expect.isNotNull(realError, "$name should not fail");
+      Expect.isTrue(actualError is RangeError, "$name is-error: $actualError");
+      Expect.equals(realError.name, actualError.name, "$name name");
+      Expect.equals(realError.invalidValue, actualError.invalidValue,
+                    "$name[0:l+1] value");
+      Expect.equals(realError.start, actualError.start, "$name[0:l+1] start");
+      Expect.equals(realError.end, actualError.end, "$name[0:l+1] end");
+      return;
+    }
+    // Didn't throw.
+    Expect.isNull(realError, "$name should fail");
+    Expect.equals(end - start, result.length, "$name result length");
+  }
+
+  testSlice(list, name) {
+    testSliceError(list, 0, list.length, name);  // Should not fail.
+    testSliceError(list, 0, list.length + 1, name);
+    testSliceError(list, 0, 0x123456789, name);
+    testSliceError(list, -1, list.length, name);
+    testSliceError(list, -0x123456789, list.length, name);
+    testSliceError(list, list.length + 1, list.length + 1, name);
+    testSliceError(list, -1, null, name);
+    if (list.length > 0) {
+      testSliceError(list, list.length, list.length - 1, name);
+    }
+  }
+
+  testRangeErrors(list, name) {
+    testIndex(list, "$name#${list.length} index");
+    testSlice(list, "$name#${list.length} slice");
+  }
+  // Empty lists.
+  testRangeErrors([], "list");
+  testRangeErrors(new List(0), "fixed-list");
+  testRangeErrors(const [], "const-list");
+  testRangeErrors(new List.unmodifiable([]), "unmodifiable");
+  testRangeErrors(new Uint8List(0), "typed-list");
+  testRangeErrors(new Uint8List.view(new Uint8List(0).buffer), "typed-list");
+  testRangeErrors([1, 2, 3].sublist(1, 1), "sub-list");
+  // Non-empty lists.
+  testRangeErrors([1, 2, 3], "list");
+  testRangeErrors(new List(3), "fixed-list");
+  testRangeErrors(const [1, 2, 3], "const-list");
+  testRangeErrors(new List.unmodifiable([1, 2, 3]), "unmodifiable");
+  testRangeErrors(new Uint8List(3), "typed-list");
+  testRangeErrors(new Uint8List.view(new Uint8List(3).buffer), "typed-list");
+  testRangeErrors([1, 2, 3, 4, 5].sublist(1, 3), "sub-list");
 }
 
 void testLength(int length, List list) {
@@ -475,6 +558,7 @@
 
 class Yes {
   operator ==(var other) => true;
+  int get hashCode => 0;
 }
 
 class MyList<E> extends ListBase<E> {
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 4073b51..d686774 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -138,7 +138,7 @@
 package_root_test: SkipByDesign # Uses dart:io.
 
 [ $compiler == dart2js && $cps_ir ]
-deferred_in_isolate2_test: Crash # (lib.f()): deferred access is not implemented
+deferred_in_isolate2_test: RuntimeError # Exception: Some tests failed.
 isolate_current_test: RuntimeError # Please triage this failure.
 message3_test/byteBuffer: RuntimeError # Please triage this failure.
 message3_test/fun: RuntimeError # Please triage this failure.
diff --git a/tests/isolate/nested_spawn2_test.dart b/tests/isolate/nested_spawn2_test.dart
index fbeaeef..faf105d 100644
--- a/tests/isolate/nested_spawn2_test.dart
+++ b/tests/isolate/nested_spawn2_test.dart
@@ -57,7 +57,7 @@
   test("spawned isolate can spawn other isolates", () {
     ReceivePort init = new ReceivePort();
     Isolate.spawn(isolateA, init.sendPort);
-    init.first.then(expectAsync((port) {
+    return init.first.then(expectAsync((port) {
       _call(port, "launch nested!", expectAsync((msg, replyTo) {
         expect(msg[0], "0");
         _call(replyTo, msg1, expectAsync((msg, replyTo) {
diff --git a/tests/isolate/nested_spawn_test.dart b/tests/isolate/nested_spawn_test.dart
index 0dc35a0..083a94a 100644
--- a/tests/isolate/nested_spawn_test.dart
+++ b/tests/isolate/nested_spawn_test.dart
@@ -24,7 +24,7 @@
   test("spawned isolates can spawn nested isolates", () {
     ReceivePort port = new ReceivePort();
     Isolate.spawn(isolateA, [port.sendPort, "main"]);
-    port.first.then((message) {
+    return port.first.then((message) {
       expect("main", message[1]);
       expect("isolateA", message[2]);
       expect("isolateB", message[3]);
diff --git a/tests/language/assertion_test.dart b/tests/language/assertion_test.dart
index 68bdf04..2f0a12d 100644
--- a/tests/language/assertion_test.dart
+++ b/tests/language/assertion_test.dart
@@ -1,7 +1,7 @@
 // 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.
-// VMOptions=--enable_type_checks
+// VMOptions=--enable_asserts
 //
 // Dart test program testing assert statements.
 
diff --git a/tests/language/bit_shift_test.dart b/tests/language/bit_shift_test.dart
index 3032736..e939e5a 100644
--- a/tests/language/bit_shift_test.dart
+++ b/tests/language/bit_shift_test.dart
@@ -7,6 +7,8 @@
 constants() {
   Expect.equals(0, 499 >> 33);
   Expect.equals(0, (499 << 33) & 0xFFFFFFFF);
+  Expect.equals(0, (499 << 32) >> 65);
+  Expect.equals(0, ((499 << 32) << 65) & 0xFFFFFFFFFFFFFFFF);
 }
 
 foo(i) {
@@ -29,13 +31,18 @@
 interceptors() {
   Expect.equals(0, id(499) >> 33);
   Expect.equals(0, (id(499) << 33) & 0xFFFFFFFF);
+  Expect.equals(0, id(499 << 32) >> 65);
+  Expect.equals(0, (id(499 << 32) << 65) & 0xFFFFFFFFFFFFFFFF);
 }
 
 speculative() {
   var a = id(499);
+  var b = id(499 << 32);
   for (int i = 0; i < 1; i++) {
     Expect.equals(0, a >> 33);
     Expect.equals(0, (a << 33) & 0xFFFFFFFF);
+    Expect.equals(0, b >> 65);
+    Expect.equals(0, (b << 65) & 0xFFFFFFFFFFFFFFFF);
   }
 }
 
diff --git a/tests/language/deferred_super_dependency_lib.dart b/tests/language/deferred_super_dependency_lib.dart
new file mode 100644
index 0000000..a592dab
--- /dev/null
+++ b/tests/language/deferred_super_dependency_lib.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2015, 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.
+
+class A {
+}
+
+class C extends A {
+  foo() {
+    super.foo = 3;
+  }
+}
\ No newline at end of file
diff --git a/tests/language/deferred_super_dependency_test.dart b/tests/language/deferred_super_dependency_test.dart
new file mode 100644
index 0000000..d2f801f
--- /dev/null
+++ b/tests/language/deferred_super_dependency_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2015, 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.
+// lib.C.foo has code that references `super.foo=` that does not exist. This
+// used to cause a crash.
+
+import "package:expect/expect.dart";
+import "deferred_super_dependency_lib.dart" deferred as lib; /// 01: static type warning
+
+main() async {
+  await lib.loadLibrary(); /// 01: continued
+  Expect.throws(() => new lib.C().foo(), (e) => e is NoSuchMethodError); /// 01: continued
+}
\ No newline at end of file
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 1ced213..58c8f07 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -148,6 +148,7 @@
 double_int_to_string_test: RuntimeError # Issue 1533
 mint_arithmetic_test: RuntimeError # Issue 1533
 left_shift_test: RuntimeError # Issue 1533
+regress_24283_test: RuntimeError # Issue 1533
 bad_override_test/01: CompileTimeError # Issue 11496
 bad_override_test/02: CompileTimeError # Issue 11496
 constructor_named_arguments_test/01: CompileTimeError # Issue 5519
@@ -279,6 +280,8 @@
 async_star_stream_take_test: Crash # (await for(var v in s.take(5))r+= v;): await for
 async_star_take_reyield_test: Crash # (fivePartialSums(Str...  cannot handle sync*/async* functions
 async_star_test: Crash # (f()async*{}): cannot handle sync*/async* functions
+async_switch_test/none: RuntimeError # Uncaught Error: Expect.equals(expected: <1>, actual: <null>) fails.
+async_switch_test/withDefault: RuntimeError # Uncaught Error: Expect.equals(expected: <1>, actual: <null>) fails.
 asyncstar_concat_test: Crash # (concat(a,b)async*{yield* a;yield* b;}): cannot handle sync*/async* functions
 asyncstar_throw_in_catch_test: Crash # (foo4(Tracer tracer)...  cannot handle sync*/async* functions
 asyncstar_yield_test: Crash # (Stream<int> foo4()a...  cannot handle sync*/async* functions
@@ -286,7 +289,7 @@
 await_for_cancel_test: Crash # (await for(var x in controller.stream){for(int j=0;j<10;j++ ){if(j==5)continue outer;}}): await for
 await_for_test: Crash # (await for(var x in infiniteStream()){i++ ;if(i>10)break;t4.record(x);}): await for
 await_for_use_local_test: Crash # (await for(var v in s){accum+= v;}): await for
-await_future_test: RuntimeError # Please triage this failure.
+await_future_test: Timeout
 await_regression_test: RuntimeError # "Obelix".then$1 is not a function
 cha_deopt1_test: Crash # (d.make_u()): deferred access is not implemented
 cha_deopt2_test: Crash # (d.make_u()): deferred access is not implemented
@@ -298,30 +301,30 @@
 crash_6725_test/01: Crash # unsupported operation on erroneous element
 cyclic_default_values_test: RuntimeError # Z.cyclic_default_values_test__foo$closure is not a function
 deferred_call_empty_before_load_test: Crash # (lib1.thefun()): deferred access is not implemented
-deferred_closurize_load_library_test: Crash # (lib.trueVar): deferred access is not implemented
-deferred_constant_list_test: Crash # (lib.finalConstList): deferred access is not implemented
+deferred_closurize_load_library_test: RuntimeError # TypeError: D.loadLibrary is not a function
+deferred_constant_list_test: RuntimeError # TypeError: K.loadLibrary is not a function
 deferred_constraints_constants_test/none: Crash # (lib.constantInstance): deferred access is not implemented
 deferred_constraints_constants_test/reference_after_load: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_constraints_type_annotation_test/as_operation: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_constraints_type_annotation_test/catch_check: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_constraints_type_annotation_test/is_check: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_constraints_type_annotation_test/new: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_constraints_type_annotation_test/new_before_load: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_constraints_type_annotation_test/new_generic1: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_constraints_type_annotation_test/new_generic2: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_constraints_type_annotation_test/new_generic3: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_constraints_type_annotation_test/none: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_constraints_type_annotation_test/static_method: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_constraints_type_annotation_test/type_annotation1: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_constraints_type_annotation_test/type_annotation_generic1: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_constraints_type_annotation_test/type_annotation_generic2: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_constraints_type_annotation_test/type_annotation_generic3: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_constraints_type_annotation_test/type_annotation_generic4: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_constraints_type_annotation_test/type_annotation_non_deferred: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_constraints_type_annotation_test/type_annotation_null: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_constraints_type_annotation_test/type_annotation_top_level: Crash # (lib.constantInstance): deferred access is not implemented
-deferred_function_type_test: Crash # (lib.runTest()): deferred access is not implemented
-deferred_global_test: Crash # (lib.finalConstGlobal): deferred access is not implemented
+deferred_constraints_type_annotation_test/as_operation: RuntimeError # TypeError: Z.loadLibrary is not a function
+deferred_constraints_type_annotation_test/catch_check: RuntimeError # TypeError: D.loadLibrary is not a function
+deferred_constraints_type_annotation_test/is_check: RuntimeError # TypeError: L.loadLibrary is not a function
+deferred_constraints_type_annotation_test/new: RuntimeError # TypeError: R.loadLibrary is not a function
+deferred_constraints_type_annotation_test/new_before_load: RuntimeError # TypeError: K.loadLibrary is not a function
+deferred_constraints_type_annotation_test/new_generic1: RuntimeError # TypeError: R.loadLibrary is not a function
+deferred_constraints_type_annotation_test/new_generic2: RuntimeError # TypeError: X.loadLibrary is not a function
+deferred_constraints_type_annotation_test/new_generic3: RuntimeError # TypeError: K.loadLibrary is not a function
+deferred_constraints_type_annotation_test/none: RuntimeError # TypeError: D.loadLibrary is not a function
+deferred_constraints_type_annotation_test/static_method: RuntimeError # TypeError: F.loadLibrary is not a function
+deferred_constraints_type_annotation_test/type_annotation1: RuntimeError # TypeError: K.loadLibrary is not a function
+deferred_constraints_type_annotation_test/type_annotation_generic1: RuntimeError # TypeError: T.loadLibrary is not a function
+deferred_constraints_type_annotation_test/type_annotation_generic2: RuntimeError # TypeError: Q.loadLibrary is not a function
+deferred_constraints_type_annotation_test/type_annotation_generic3: RuntimeError # TypeError: Z.loadLibrary is not a function
+deferred_constraints_type_annotation_test/type_annotation_generic4: RuntimeError # TypeError: Q.loadLibrary is not a function
+deferred_constraints_type_annotation_test/type_annotation_non_deferred: RuntimeError # TypeError: R.loadLibrary is not a function
+deferred_constraints_type_annotation_test/type_annotation_null: RuntimeError # TypeError: Z.loadLibrary is not a function
+deferred_constraints_type_annotation_test/type_annotation_top_level: RuntimeError # TypeError: U.loadLibrary is not a function
+deferred_function_type_test: RuntimeError # TypeError: N.loadLibrary is not a function
+deferred_global_test: RuntimeError # TypeError: Y.loadLibrary is not a function
 deferred_inlined_test: Crash # (lib.foo()): deferred access is not implemented
 deferred_load_constants_test/none: Crash # (foo.c): deferred access is not implemented
 deferred_load_inval_code_test: Crash # (d.foo()): deferred access is not implemented
@@ -329,18 +332,20 @@
 deferred_mixin_test: RuntimeError # X.loadLibrary is not a function
 deferred_no_such_method_test: RuntimeError # D.loadLibrary is not a function
 deferred_not_loaded_check_test: Crash # (lib.closure(sideEffect())): deferred access is not implemented
-deferred_only_constant_test: Crash # (lib.constant): deferred access is not implemented
+deferred_only_constant_test: RuntimeError # TypeError: O.loadLibrary is not a function
 deferred_optimized_test: Crash # (lib.foo()): deferred access is not implemented
 deferred_redirecting_factory_test: Crash # (lib1.loadLib2()): deferred access is not implemented
-deferred_regression_22995_test: Crash # (lib.foofoo()): deferred access is not implemented
-deferred_shadow_load_library_test: Crash # (lib.trueVar): deferred access is not implemented
-deferred_shared_and_unshared_classes_test: Crash # (lib2.foo()): deferred access is not implemented
-deferred_static_seperate_test: Crash # (lib1.x): deferred access is not implemented
+deferred_regression_22995_test: RuntimeError # TypeError: U.loadLibrary is not a function
+deferred_shadow_load_library_test: RuntimeError # TypeError: Y.loadLibrary is not a function
+deferred_shared_and_unshared_classes_test: RuntimeError # TypeError: U.loadLibrary is not a function
+deferred_static_seperate_test: RuntimeError # TypeError: L.loadLibrary is not a function
+deferred_super_dependency_test/01: RuntimeError # Uncaught Error: NoSuchMethodError: method not found: 'loadLibrary' ($async$temp1.loadLibrary is not a function)
 deferred_type_dependency_test/as: Crash # (lib1.fooAs("string")): deferred access is not implemented
 deferred_type_dependency_test/is: Crash # (lib1.fooIs("string")): deferred access is not implemented
 deferred_type_dependency_test/none: Crash # (lib2.getInstance()): deferred access is not implemented
 deferred_type_dependency_test/type_annotation: Crash # (lib1.fooAnnotation("string")): deferred access is not implemented
 enum_mirror_test: Crash # (static Iterable<Str...  cannot handle sync*/async* functions
+field3a_negative_test: Fail # Bogus result from type inference in case of invalid program.
 first_class_types_test: RuntimeError # Please triage this failure.
 for2_test: Crash # The null object does not have a getter 'field'.
 for_variable_capture_test: Crash # (i=0): For-loop variable captured in loop header
diff --git a/tests/language/regress_24283_test.dart b/tests/language/regress_24283_test.dart
new file mode 100644
index 0000000..d98e829
--- /dev/null
+++ b/tests/language/regress_24283_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2015, 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";
+
+main() {
+  // Smi
+  var i = 1 << 30;
+  var j = -i;
+  Expect.equals(0, i >> 37);
+  Expect.equals(-1, j >> 37);
+  // Mint
+  i = 1 << 50;
+  j = -i;
+  Expect.equals(0, i >> 67);
+  Expect.equals(-1, j >> 67);
+  // Bigint
+  i = i << 120;
+  j = -i;
+  Expect.equals(0, i >> 199);
+  Expect.equals(-1, j >> 199);
+}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index e409184..9a65284 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -357,9 +357,9 @@
 mirrors/constructors_test: Crash # (static Iterable<Str...  cannot handle sync*/async* functions
 mirrors/dart2js_mirrors_test: Crash # (static Iterable<Str...  cannot handle sync*/async* functions
 mirrors/declarations_type_test: Crash # (static Iterable<Str...  cannot handle sync*/async* functions
-mirrors/deferred_mirrors_metadata_test: Crash # (lib1.foo()): deferred access is not implemented
-mirrors/deferred_mirrors_metatarget_test: Crash # (lib.foo()): deferred access is not implemented
-mirrors/deferred_mirrors_update_test: Crash # (l.foo()): deferred access is not implemented
+mirrors/deferred_mirrors_metadata_test: RuntimeError # TypeError: U.loadLibrary is not a function
+mirrors/deferred_mirrors_metatarget_test: RuntimeError # TypeError: X.loadLibrary is not a function
+mirrors/deferred_mirrors_update_test: RuntimeError # TypeError: U.loadLibrary is not a function
 mirrors/deferred_type_test: Crash # (static Iterable<Str...  cannot handle sync*/async* functions
 mirrors/delegate_call_through_getter_test: RuntimeError # Please triage this failure.
 mirrors/delegate_class_test: Crash # (static Iterable<Str...  cannot handle sync*/async* functions
diff --git a/tests/standalone/no_assert_test.dart b/tests/standalone/no_assert_test.dart
new file mode 100644
index 0000000..825578b
--- /dev/null
+++ b/tests/standalone/no_assert_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2015, 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=--no-enable_asserts --enable_type_checks
+
+// Ensure that enabling of type checks does not automatically enable asserts.
+
+main() {
+  assert(false);
+  try {
+    int i = "String";
+    throw "FAIL";
+  } on TypeError catch (e) {
+    print("PASS");
+  }
+}
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index b6e570b..7d7fc8f 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -17,6 +17,9 @@
 
 javascript_compatibility_errors_test/none: Fail, OK  # Not possible to exclude or annotate with '/// none:'
 
+[ $runtime != vm && ($runtime != drt || $compiler != none)) ]
+no_assert_test: Fail, OK # This is testing a vm flag.
+
 [ $runtime == vm ]
 package/package_isolate_test: Fail # Issue 12474
 io/observatory_test: Fail
@@ -186,9 +189,6 @@
 io/test_runner_test: Skip  # Timeout.
 io/http_client_stays_alive_test: Skip  # Timeout.
 
-[ $compiler == dart2js ]
-io/observatory_test: Crash # Issue 24291
-
 [ $runtime == vm ]
 # Failures in secure networking while NSS is replaced with BoringSSL
 io/https_client_certificate_test: RuntimeError # Issue 24070
@@ -198,11 +198,8 @@
 io/secure_socket_bad_data_test: RuntimeError  # An error in a secure connection just puts a READ_CLOSED on the stream, rather than signaling an error on the stream.
 
 [ $compiler == dart2js && $cps_ir ]
-coverage_test: Crash # (static Iterable<Str...  cannot handle sync*/async* functions
-io/addlatexhash_test: Crash # (static Iterable<Str...  cannot handle sync*/async* functions
 io/file_error_test: Crash # (static Iterable<Str...  cannot handle sync*/async* functions
 io/file_read_encoded_test: Crash # (static Iterable<Str...  cannot handle sync*/async* functions
 io/file_test: Crash # (static Iterable<Str...  cannot handle sync*/async* functions
-io/http_client_connect_test: Crash # (static Iterable<Str...  cannot handle sync*/async* functions
-io/skipping_dart2js_compilations_test: Crash # (static Iterable<Str...  cannot handle sync*/async* functions
+io/observatory_test: Crash # (static Iterable<Str...  cannot handle sync*/async* functions
 priority_queue_stress_test: RuntimeError # Cannot read property 'length' of undefined
diff --git a/tests/try/poi/compiler_test_case.dart b/tests/try/poi/compiler_test_case.dart
index 8827c97..a1df70a 100644
--- a/tests/try/poi/compiler_test_case.dart
+++ b/tests/try/poi/compiler_test_case.dart
@@ -14,7 +14,7 @@
 import 'package:async_helper/async_helper.dart' show
     asyncTest;
 
-import '../../compiler/dart2js/compiler_helper.dart' show
+import '../../compiler/dart2js/mock_compiler.dart' show
     MockCompiler,
     compilerFor;
 
diff --git a/tests/try/poi/diff_test.dart b/tests/try/poi/diff_test.dart
index 17890ac..c6de2fd 100644
--- a/tests/try/poi/diff_test.dart
+++ b/tests/try/poi/diff_test.dart
@@ -31,7 +31,7 @@
     Difference,
     computeDifference;
 
-import '../../compiler/dart2js/compiler_helper.dart' show
+import '../../compiler/dart2js/mock_compiler.dart' show
     MockCompiler,
     compilerFor;
 
diff --git a/tests/try/poi/forget_element_assertion.dart b/tests/try/poi/forget_element_assertion.dart
index c098234..a825532 100644
--- a/tests/try/poi/forget_element_assertion.dart
+++ b/tests/try/poi/forget_element_assertion.dart
@@ -6,7 +6,7 @@
 // Remove this file when dart2js support such features.
 library trydart.forget_element_assertion;
 
-import '../../compiler/dart2js/compiler_helper.dart' show
+import '../../compiler/dart2js/mock_compiler.dart' show
     compilerFor;
 
 import 'compiler_test_case.dart';
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index f793816..77594d3 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -31,4 +31,4 @@
 [ $compiler == dart2js && $cps_ir ]
 dummy_compiler_test: Crash # (switch (function.na...  continue to a labeled switch case
 recursive_import_test: Crash # (switch (function.na...  continue to a labeled switch case
-source_mirrors_test: Crash # (switch (function.na...  continue to a labeled switch case
+source_mirrors_test: Crash, Slow # (switch (function.na...  continue to a labeled switch case
diff --git a/tools/VERSION b/tools/VERSION
index 03c8deb..593aeba 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 1
 MINOR 13
 PATCH 0
-PRERELEASE 2
+PRERELEASE 3
 PRERELEASE_PATCH 0
diff --git a/tools/bots/bot_utils.py b/tools/bots/bot_utils.py
index e5f5de2..da166aa 100644
--- a/tools/bots/bot_utils.py
+++ b/tools/bots/bot_utils.py
@@ -71,7 +71,7 @@
 
   Under every base path, the following structure is used:
     - /VERSION
-    - /api-docs/dart-api-docs.zip
+    - /api-docs/{dart-api-docs.zip,dartdocs-gen-api.zip}
     - /dartium/{chromedriver,content_shell,dartium}
          -{linux,macos,windows}-{ia32,x64}-release.zip
     - /sdk/dartsdk-{linux,macos,windows}-{ia32,x64}-release.zip
@@ -119,10 +119,6 @@
     return '/'.join([self.dartium_directory(revision),
       self.dartium_variant_zipfilename(name, system, arch, mode)])
 
-  def apidocs_zipfilepath(self, revision):
-    return '/'.join([self.apidocs_directory(revision),
-      self.apidocs_zipfilename()])
-
   def dartium_android_apk_filepath(self, revision, name, arch, mode):
     return '/'.join([self.dartium_android_directory(revision),
       self.dartium_android_apk_filename(name, arch, mode)])
diff --git a/tools/build.py b/tools/build.py
index fc2e1cf..0c5e235 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -77,11 +77,6 @@
       help='Name of the devenv.com/msbuild executable on Windows (varies for '
            'different versions of Visual Studio)',
       default=vs_executable)
-  result.add_option("--use-bootstrap-for-observatory",
-      help='Use a stripped down Dart binary built on the host machine '
-           'for building Observatory. Necessary on Linux machines which have '
-           'libc incompatibilities with the prebuilt Dart binaries.',
-      default=False, action="store_true")
   return result
 
 
@@ -391,8 +386,6 @@
   global filter_xcodebuild_output
   start_time = time.time()
   os.environ['DART_BUILD_MODE'] = mode
-  if options.use_bootstrap_for_observatory != False:
-    os.environ['DART_USE_BOOTSTRAP_BIN'] = '1'
   build_config = utils.GetBuildConf(mode, arch, target_os)
   if HOST_OS == 'macos':
     filter_xcodebuild_output = True
diff --git a/tools/dart2js/angular2_testing_deps/CURRENT_ANGULAR_DEPS b/tools/dart2js/angular2_testing_deps/CURRENT_ANGULAR_DEPS
index 844cf2e..82a82d9 100644
--- a/tools/dart2js/angular2_testing_deps/CURRENT_ANGULAR_DEPS
+++ b/tools/dart2js/angular2_testing_deps/CURRENT_ANGULAR_DEPS
@@ -1 +1 @@
-be0739085976bbdbcf8f560475e87b07343f464d
+63e785902fbc6d5edbc1a4ed135f65d1cdf00acd
diff --git a/tools/observatory_tool.py b/tools/observatory_tool.py
index 6626143..90c2aa27 100755
--- a/tools/observatory_tool.py
+++ b/tools/observatory_tool.py
@@ -6,13 +6,16 @@
 
 import argparse
 import os
+import platform
 import shutil
 import subprocess
 import sys
+import utils
 
 SCRIPT_DIR = os.path.dirname(sys.argv[0])
 DART_ROOT = os.path.realpath(os.path.join(SCRIPT_DIR, '..'))
-RUN_PUB = os.path.join(DART_ROOT, 'tools/run_pub.py')
+PUB_PATH = os.path.join(DART_ROOT, 'third_party', 'pkg',
+                        'pub', 'bin', 'pub.dart')
 IGNORE_PATTERNS = shutil.ignore_patterns(
     '*.map',
     '*.concat.js',
@@ -24,7 +27,7 @@
     '*.log',
     '*~')
 
-usage = """obs_tool.py [options]"""
+usage = """observatory_tool.py [options]"""
 
 def BuildArguments():
   result = argparse.ArgumentParser(usage=usage)
@@ -34,64 +37,74 @@
   result.add_argument("--directory", help="observatory root", default=None)
   result.add_argument("--command", help="[get, build, deploy]", default=None)
   result.add_argument("--silent", help="silence all output", default=False)
+  result.add_argument("--sdk", help="Use prebuilt sdk", default=False)
   return result
 
 def ProcessOptions(options, args):
   # Required options.
-  if (options.command == None) or (options.directory == None):
+  if options.command is None or options.directory is None:
     return False
-  # If we have a pub executable, we are running from the dart-sdk.
-  if (options.pub_executable != None):
-    return True
-  # Otherwise, we need a dart executable and a package root.
-  return ((options.package_root != None) and
-          (options.dart_executable != None))
+  # If we have a working pub executable, try and use that.
+  # TODO(whesse): Drop the pub-executable option if it isn't used.
+  if options.pub_executable is not None:
+    try:
+      if 0 == subprocess.call([options.pub_executable, '--version']):
+        return True
+    except OSError as e:
+      pass
+  options.pub_executable = None
+
+  if options.sdk is not None and utils.CheckedInSdkCheckExecutable():
+    # Use the checked in pub executable.
+    options.pub_snapshot = os.path.join(utils.CheckedInSdkPath(),
+                                        'bin',
+                                        'snapshots',
+                                        'pub.dart.snapshot');
+    try:
+      if 0 == subprocess.call([utils.CheckedInSdkExecutable(),
+                               options.pub_snapshot,
+                               '--version']):
+        return True
+    except OSError as e:
+      pass
+  options.pub_snapshot = None
+
+  # We need a dart executable and a package root.
+  return (options.package_root is not None and
+          options.dart_executable is not None)
 
 def ChangeDirectory(directory):
   os.chdir(directory);
 
-def PubGet(dart_executable, pub_executable, pkg_root, silent):
-  # Always remove pubspec.lock before running 'pub get'.
-  try:
-    os.remove('pubspec.lock');
-  except OSError as e:
-    pass
-  with open(os.devnull, 'wb') as silent_sink:
-    if (pub_executable != None):
-      return subprocess.call([pub_executable,
-                              'get',
-                              '--offline'],
-                              stdout=silent_sink if silent else None,
-                              stderr=silent_sink if silent else None)
-    else:
-      return subprocess.call(['python',
-                              RUN_PUB,
-                              '--package-root=' + pkg_root,
-                              '--dart-executable=' + dart_executable,
-                              'get',
-                              '--offline'],
-                              stdout=silent_sink if silent else None,
-                              stderr=silent_sink if silent else None,)
+def DisplayBootstrapWarning():
+  print """\
 
-def PubBuild(dart_executable, pub_executable, pkg_root, silent, output_dir):
+
+WARNING: Your system cannot run the checked-in Dart SDK. Using the
+bootstrap Dart executable will make debug builds slow.
+Please see the Wiki for instructions on replacing the checked-in Dart SDK.
+
+https://github.com/dart-lang/sdk/wiki/The-checked-in-SDK-in--tools
+
+"""
+
+def PubCommand(dart_executable,
+               pub_executable,
+               pub_snapshot,
+               pkg_root,
+               command,
+               silent):
   with open(os.devnull, 'wb') as silent_sink:
-    if (pub_executable != None):
-      return subprocess.call([pub_executable,
-                              'build',
-                              '--output',
-                              output_dir],
-                              stdout=silent_sink if silent else None,
-                              stderr=silent_sink if silent else None,)
+    if pub_executable is not None:
+      executable = [pub_executable]
+    elif pub_snapshot is not None:
+      executable = [utils.CheckedInSdkExecutable(), pub_snapshot]
     else:
-      return subprocess.call(['python',
-                              RUN_PUB,
-                              '--package-root=' + pkg_root,
-                              '--dart-executable=' + dart_executable,
-                              'build',
-                              '--output',
-                              output_dir],
-                              stdout=silent_sink if silent else None,
-                              stderr=silent_sink if silent else None,)
+      DisplayBootstrapWarning()
+      executable = [dart_executable, '--package-root=' + pkg_root, PUB_PATH]
+    return subprocess.call(executable + command,
+                           stdout=silent_sink if silent else None,
+                           stderr=silent_sink if silent else None)
 
 def Deploy(input_dir, output_dir):
   shutil.rmtree(output_dir)
@@ -110,16 +123,24 @@
 def ExecuteCommand(options, args):
   cmd = options.command
   if (cmd == 'get'):
-    return PubGet(options.dart_executable,
-                  options.pub_executable,
-                  options.package_root,
-                  options.silent)
+    # Always remove pubspec.lock before running 'pub get'.
+    try:
+      os.remove('pubspec.lock');
+    except OSError as e:
+      pass
+    return PubCommand(options.dart_executable,
+                      options.pub_executable,
+                      options.pub_snapshot,
+                      options.package_root,
+                      ['get', '--offline'],
+                      options.silent)
   elif (cmd == 'build'):
-    return PubBuild(options.dart_executable,
-                    options.pub_executable,
-                    options.package_root,
-                    options.silent,
-                    args[0])
+    return PubCommand(options.dart_executable,
+                      options.pub_executable,
+                      options.pub_snapshot,
+                      options.package_root,
+                      ['build', '--output', args[0]],
+                      options.silent)
   elif (cmd == 'deploy'):
     Deploy('build', 'deployed')
   elif (cmd == 'rewrite'):
@@ -135,8 +156,6 @@
   if not ProcessOptions(options, args):
     parser.print_help()
     return 1
-  if os.getenv('DART_USE_BOOTSTRAP_BIN') != None:
-    dart_executable = options.dart_executable
   # Calculate absolute paths before changing directory.
   if (options.package_root != None):
     options.package_root = os.path.abspath(options.package_root)
@@ -144,6 +163,8 @@
     options.dart_executable = os.path.abspath(options.dart_executable)
   if (options.pub_executable != None):
     options.pub_executable = os.path.abspath(options.pub_executable)
+  if (options.pub_snapshot != None):
+    options.pub_snapshot = os.path.abspath(options.pub_snapshot)
   if len(args) == 1:
     args[0] = os.path.abspath(args[0])
   # Pub must be run from the project's root directory.
@@ -151,4 +172,4 @@
   return ExecuteCommand(options, args)
 
 if __name__ == '__main__':
-  sys.exit(main());
\ No newline at end of file
+  sys.exit(main());
diff --git a/tools/promote.py b/tools/promote.py
index 81ab402..d3013ab 100644
--- a/tools/promote.py
+++ b/tools/promote.py
@@ -131,10 +131,11 @@
     remove_gs_directory(to_loc)
     Gsutil(['-m', 'cp', '-a', 'public-read', '-R', from_loc, to_loc])
 
-    # Copy api-docs zipfile.
-    from_loc = raw_namer.apidocs_zipfilepath(revision)
-    to_loc = release_namer.apidocs_zipfilepath(to_revision)
-    Gsutil(['-m', 'cp', '-a', 'public-read', from_loc, to_loc])
+    # Copy api-docs directory.
+    from_loc = raw_namer.apidocs_directory(revision)
+    to_loc = release_namer.apidocs_directory(to_revision)
+    remove_gs_directory(to_loc)
+    Gsutil(['-m', 'cp', '-a', 'public-read', '-R', from_loc, to_loc])
 
     # Copy dartium directory.
     from_loc = raw_namer.dartium_directory(revision)
diff --git a/tools/run_pub.py b/tools/run_pub.py
deleted file mode 100755
index f54a411..0000000
--- a/tools/run_pub.py
+++ /dev/null
@@ -1,104 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2015, 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.
-"""Used to run pub before the SDK has been built"""
-
-import argparse
-import os
-import platform
-import subprocess
-import sys
-
-SCRIPT_DIR = os.path.dirname(sys.argv[0])
-DART_ROOT = os.path.realpath(os.path.join(SCRIPT_DIR, '..'))
-PUB_PATH = os.path.join(DART_ROOT, 'third_party/pkg/pub/bin/pub.dart')
-CANARY_PATH = os.path.join(DART_ROOT, 'tools', 'canary.dart')
-
-usage = """run_pub.py --package-root=<package root>"""
-
-def BuildArguments():
-  result = argparse.ArgumentParser(usage=usage)
-  result.add_argument("--package-root", help="package root", default=None)
-  result.add_argument("--dart-executable", help="dart binary", default=None)
-  return result
-
-def ProcessOptions(options, args):
-  return ((options.package_root != None) and
-          (options.dart_executable != None))
-
-def GetPrebuiltDartExecutablePath(suffix):
-  osdict = {'Darwin':'macos', 'Linux':'linux', 'Windows':'windows'}
-  system = platform.system()
-  executable_name = 'dart'
-  if system == 'Windows':
-    executable_name = 'dart.exe'
-  try:
-    osname = osdict[system]
-  except KeyError:
-    print >>sys.stderr, ('WARNING: platform "%s" not supported') % (system)
-    return None;
-  return os.path.join(DART_ROOT,
-                      'tools',
-                      'testing',
-                      'bin',
-                      osname,
-                      executable_name + suffix)
-
-def RunPub(dart, pkg_root, args):
-  return subprocess.call([dart, '--package-root=' + pkg_root, PUB_PATH] + args)
-
-def TryRunningExecutable(dart_executable, pkg_root):
-  try:
-    return subprocess.call([dart_executable,
-                            '--package-root=' + pkg_root,
-                            CANARY_PATH]) == 42
-  except:
-    return False;
-
-def DisplayBootstrapWarning():
-  print """\
-
-
-WARNING: Your system cannot run the prebuilt Dart executable. Using the
-bootstrap Dart executable will make Debug builds long.
-Please see Wiki for instructions on replacing prebuilt Dart executable.
-
-https://code.google.com/p/dart/wiki/ReplacingPrebuiltDartExecutable
-
-"""
-
-def FindDartExecutable(fallback_executable, package_root):
-  # If requested, use the bootstrap binary instead of the prebuilt
-  # executable.
-  if os.getenv('DART_USE_BOOTSTRAP_BIN') != None:
-    return fallback_executable
-  # Try to find a working prebuilt dart executable.
-  dart_executable = GetPrebuiltDartExecutablePath('')
-  if TryRunningExecutable(dart_executable, package_root):
-    return dart_executable
-  dart_executable = GetPrebuiltDartExecutablePath('-arm')
-  if TryRunningExecutable(dart_executable, package_root):
-    return dart_executable
-  dart_executable = GetPrebuiltDartExecutablePath('-mips')
-  if TryRunningExecutable(dart_executable, package_root):
-    return dart_executable
-  # If the system cannot execute a prebuilt dart executable, use the bootstrap
-  # executable instead.
-  DisplayBootstrapWarning()
-  return fallback_executable
-
-def main():
-  # Parse the options.
-  parser = BuildArguments()
-  (options, args) = parser.parse_known_args()
-  if not ProcessOptions(options, args):
-    parser.print_help()
-    return 1
-  dart_executable = FindDartExecutable(options.dart_executable,
-                                       options.package_root)
-  return RunPub(dart_executable, options.package_root, args)
-
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/tools/testing/dart/compiler_configuration.dart b/tools/testing/dart/compiler_configuration.dart
index fc1d536..9ec90f0 100644
--- a/tools/testing/dart/compiler_configuration.dart
+++ b/tools/testing/dart/compiler_configuration.dart
@@ -155,7 +155,12 @@
       List<String> sharedOptions,
       List<String> originalArguments,
       CommandArtifact artifact) {
-    return <String>[]
+    List<String> args = [];
+    if (isChecked) {
+      args.add('--enable_asserts');
+      args.add('--enable_type_checks');
+    }
+    return args
         ..addAll(vmOptions)
         ..addAll(sharedOptions)
         ..addAll(originalArguments);
@@ -315,6 +320,10 @@
       CommandBuilder commandBuilder,
       List arguments,
       Map<String, String> environmentOverrides) {
+    arguments = new List.from(arguments);
+    if (isChecked) {
+      arguments.add('--enable_type_checks');
+    }
     return new CommandArtifact(
         <Command>[
             commandBuilder.getAnalysisCommand(
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index aef5b3f..b4e7b53 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -2225,10 +2225,6 @@
 
   static List<String> standardOptions(Map configuration) {
     List args = ["--ignore-unrecognized-flags"];
-    if (configuration["checked"]) {
-      args.add('--enable_asserts');
-      args.add("--enable_type_checks");
-    }
     String compiler = configuration["compiler"];
     if (compiler == "dart2js") {
       args = ['--generate-code-with-compile-time-errors', '--test-mode'];
diff --git a/tools/utils.py b/tools/utils.py
index 2301d9b..4b7fae5 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -565,6 +565,7 @@
 
 
 def DartBinary():
+  # TODO(24311): Replace all uses of this with CheckedInSdk[Fix]Executable().
   tools_dir = os.path.dirname(os.path.realpath(__file__))
   dart_binary_prefix = os.path.join(tools_dir, 'testing', 'bin')
   if IsWindows():
@@ -591,6 +592,51 @@
   dart_binary_prefix = os.path.join(tools_dir, '..', 'sdk' , 'bin')
   return os.path.join(dart_binary_prefix, 'dart')
 
+
+# The checked-in SDKs are documented at
+#     https://github.com/dart-lang/sdk/wiki/The-checked-in-SDK-in-tools
+def CheckedInSdkPath():
+  # We don't use the normal macos, linux, win32 directory names here, instead,
+  # we use the names that the download_from_google_storage script uses.
+  osdict = {'Darwin':'mac', 'Linux':'linux', 'Windows':'win'}
+  system = platform.system()
+  try:
+    osname = osdict[system]
+  except KeyError:
+    print >>sys.stderr, ('WARNING: platform "%s" not supported') % (system)
+    return None;
+  tools_dir = os.path.dirname(os.path.realpath(__file__))
+  return os.path.join(tools_dir,
+                      'sdks',
+                      osname,
+                      'dart-sdk')
+
+
+def CheckedInSdkExecutable():
+  name = 'dart'
+  if IsWindows():
+    name = 'dart.exe'
+  elif GuessOS() == 'linux':
+    arch = GuessArchitecture()
+    if arch == 'mips':
+      name = 'dart-mips'
+    elif arch == 'arm':
+      name = 'dart-arm'
+  return os.path.join(CheckedInSdkPath(), 'bin', name)
+
+
+def CheckedInSdkCheckExecutable():
+  executable = CheckedInSdkExecutable()
+  canary_script = os.path.join(os.path.dirname(os.path.realpath(__file__)),
+                               'canary.dart')
+  try:
+    if 42 == subprocess.call([executable, canary_script]):
+      return True
+  except OSError as e:
+    pass
+  return False
+
+
 class TempDir(object):
   def __init__(self, prefix=''):
     self._temp_dir = None