Version 1.17.0-dev.4.0

Merge branch 'fa1a40c4ee6fc8d28f6902dcd5a55d6b8308b055' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4daba9f..1476317 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,9 @@
 ## 1.17.0
 
 ### Core library changes
+* `dart:convert`
+  * Deprecate `ChunkedConverter` which was erroneously added in 1.16.
+
 * `dart:core`
   * `Uri.replace` supports iterables as values for the query parameters.
   * `Uri.parseIPv6Address` returns a `Uint8List`.
@@ -25,6 +28,9 @@
   * A bug has been fixed in which a lockfile was considered up-to-date when it
     actually wasn't.
 
+  * A bug has been fixed in which `pub get --offline` would crash when a
+    prerelease version was selected.
+
 ## 1.16.0 - 2016-04-26
 
 ### Core library changes
diff --git a/DEPS b/DEPS
index 1339596..7753d5f 100644
--- a/DEPS
+++ b/DEPS
@@ -49,7 +49,7 @@
   "dart_services_rev" : "@7aea2574e6f3924bf409a80afb8ad52aa2be4f97",
   "dart_style_tag": "@0.2.4",
   "dartdoc_tag" : "@v0.9.0",
-  "dev_compiler_rev": "@a0557e2f76fc85a6e71fe8391d1beda69905a548",
+  "dev_compiler_rev": "@1f00327fdf8fe11ab8e9b3d5b0fc958025ede592",
   "fixnum_tag": "@0.10.5",
   "func_rev": "@8d4aea75c21be2179cb00dc2b94a71414653094e",
   "glob_rev": "@704cf75e4f26b417505c5c611bdaacd8808467dd",
@@ -62,7 +62,7 @@
   "intl_rev": "@a8b480b9c436f6c0ec16730804c914bdb4e30d53",
   "jinja2_rev": "@2222b31554f03e62600cd7e383376a7c187967a1",
   "json_rpc_2_tag": "@2.0.0",
-  "linter_rev": "@ecfaed3ea52ea2b5a7d9e0a7db94cf1f92208280",
+  "linter_rev": "@8e1873ba689fbb0064cbd27c238c898106938dcd",
   "logging_rev": "@85d83e002670545e9039ad3985f0018ab640e597",
   "markdown_rev": "@4aaadf3d940bb172e1f6285af4d2b1710d309982",
   "matcher_tag": "@0.12.0",
@@ -74,12 +74,12 @@
   "observe_rev": "@eee2b8ec34236fa46982575fbccff84f61202ac6",
   "package_config_rev": "@0.1.3",
   "path_tag": "@1.3.6",
-  "plugin_tag": "@0.1.0",
+  "plugin_tag": "@0.2.0",
   "ply_rev": "@604b32590ffad5cbb82e4afef1d305512d06ae93",
   "pool_tag": "@1.2.1",
   "protobuf_tag": "@0.5.1+1",
   "pub_cache_tag": "@v0.1.0",
-  "pub_rev": "@0b96a97d61673cea04f69eb47b2ef2b5b37337d3",
+  "pub_rev": "@488ab539770512a234f0a01b74882dcbb3f1a4da",
   "pub_semver_tag": "@1.2.1",
   "quiver_tag": "@0.21.4",
   "resource_rev":"@a49101ba2deb29c728acba6fb86000a8f730f4b1",
diff --git a/docs/language/dartLangSpec.tex b/docs/language/dartLangSpec.tex
index 25a0c0d..886d65b 100644
--- a/docs/language/dartLangSpec.tex
+++ b/docs/language/dartLangSpec.tex
@@ -1807,9 +1807,9 @@
 \item \label{requiredParams}
 If two members override each other, it is a static warning if the overriding member has more required parameters  than the overridden one (\ref{instanceMethods}). 
 \item  \label{optionalPositionals}
-If two members override each other, it is a static warning if the overriding member has fewer  positional parameters than the the overridden one (\ref{instanceMethods}).
+If two members override each other, it is a static warning if the overriding member has fewer  positional parameters than the overridden one (\ref{instanceMethods}).
 \item  \label{namedParams}
-If two members override each other, it is a static warning if the overriding member does not have all the named parameters that the the overridden one has (\ref{instanceMethods}).
+If two members override each other, it is a static warning if the overriding member does not have all the named parameters that the overridden one has (\ref{instanceMethods}).
 \item Setters, getters and operators never have optional parameters of any kind; it's a compile-time error (\ref{operators}, \ref{getters}, \ref{setters}).
 \item It is a compile-time error if a member has the same name as its enclosing class (\ref{classes}).
 \item A class has an implicit interface (\ref{classes}). 
@@ -1839,7 +1839,7 @@
 % what about rules about classes that fail to implement their interfaces?
 
 \LMHash{}
-A class has a set of direct superinterfaces. This set includes the interface of its superclass and the interfaces specified in the the \IMPLEMENTS{}  clause of the class.
+A class has a set of direct superinterfaces. This set includes the interface of its superclass and the interfaces specified in the \IMPLEMENTS{}  clause of the class.
 % and any superinterfaces specified by interface injection (\ref{interfaceInjection}).  \Q{The latter needs to be worded carefully - when do interface injection clauses execute and in what scope?}
 
 \begin{grammar}
@@ -2815,7 +2815,7 @@
 \LMLabel{stringInterpolation}
 
 \LMHash{}
-It is possible to embed expressions within non-raw string literals, such that the these expressions are evaluated, and the resulting values are converted into strings and concatenated with the enclosing string. This process is known as {\em string interpolation}.
+It is possible to embed expressions within non-raw string literals, such that these expressions are evaluated, and the resulting values are converted into strings and concatenated with the enclosing string. This process is known as {\em string interpolation}.
 
  \begin{grammar}
 {\bf stringInterpolation:}`\$' IDENTIFIER\_NO\_DOLLAR;
@@ -3059,7 +3059,7 @@
 }
 
 \LMHash{}
-If the object being thrown is an instance of class \code{Error} or a subclass thereof, its \code{stackTrace} getter will return the stack trace current at the point where the the object was first thrown.
+If the object being thrown is an instance of class \code{Error} or a subclass thereof, its \code{stackTrace} getter will return the stack trace current at the point where the object was first thrown.
 
 \LMHash{}
 The static type of a throw expression is $\bot$.
@@ -5683,7 +5683,7 @@
 \LMHash{}
 It is a static warning if the static type of $c$ may not be assigned to \cd{bool}.
 
-%A for statement of the form \code{ \FOR{} ($d$ ; $c$; $e$) $s$} is equivalent to the the following code:
+%A for statement of the form \code{ \FOR{} ($d$ ; $c$; $e$) $s$} is equivalent to the following code:
 
 %\code{
 %\{$d$;
@@ -6306,7 +6306,7 @@
  \end{grammar}
  
 \LMHash{}
-Let $s_b$ be a \BREAK{} statement. If $s_b$ is of the form  \code{\BREAK{} $L$;}, then let $s_E$ be the the innermost labeled statement with label $L$ enclosing $s_b$. If $s_b$ is of the form \code{\BREAK{};},  then let $s_E$ be the the innermost  \DO{} (\ref{do}), \FOR{} (\ref{for}), \SWITCH{} (\ref{switch}) or \WHILE{} (\ref{while}) statement enclosing  $s_b$. It is a compile-time error if no such statement $s_E$ exists within the innermost function in which  $s_b$ occurs.  Furthermore, let $s_1, \ldots, s_n$ be those \TRY{} statements that are both enclosed in $s_E$ and that enclose  $s_b$, and that have a \FINALLY{} clause. Lastly, let $f_j$ be the \FINALLY{} clause of $s_j, 1 \le j \le n$.   Executing  $s_b$ first executes $f_1, \ldots,  f_n$ in innermost-clause-first  order and then terminates $s_E$. 
+Let $s_b$ be a \BREAK{} statement. If $s_b$ is of the form  \code{\BREAK{} $L$;}, then let $s_E$ be the innermost labeled statement with label $L$ enclosing $s_b$. If $s_b$ is of the form \code{\BREAK{};},  then let $s_E$ be the innermost  \DO{} (\ref{do}), \FOR{} (\ref{for}), \SWITCH{} (\ref{switch}) or \WHILE{} (\ref{while}) statement enclosing  $s_b$. It is a compile-time error if no such statement $s_E$ exists within the innermost function in which  $s_b$ occurs.  Furthermore, let $s_1, \ldots, s_n$ be those \TRY{} statements that are both enclosed in $s_E$ and that enclose  $s_b$, and that have a \FINALLY{} clause. Lastly, let $f_j$ be the \FINALLY{} clause of $s_j, 1 \le j \le n$.   Executing  $s_b$ first executes $f_1, \ldots,  f_n$ in innermost-clause-first  order and then terminates $s_E$. 
 
 \LMHash{}
 If $s_E$ is an asynchronous for loop (\ref{asynchronousFor-in}), its associated stream subscription is canceled. Furthermore, let $a_k$ be the set of asynchronous for loops  and yield-each statements (\ref{yieldEach}) enclosing $s_b$ that are enclosed in $s_E , 1 \le k \le m$, where $a_k$ is enclosed in $a_{k+1}$.   The stream subscriptions associated with $a_j$ are canceled, $1 \le j \le m$, innermost first, so that $a_j$ is canceled before $a_{j+1}$. 
@@ -6326,7 +6326,7 @@
  \end{grammar}      
  
 \LMHash{}
- Let $s_c$ be a \CONTINUE{} statement. If $s_c$ is of the form  \code{\CONTINUE{} $L$;}, then let $s_E$ be the the innermost labeled \DO{} (\ref{do}), \FOR{} (\ref{for}) or \WHILE{} (\ref{while}) statement or case clause with label $L$ enclosing $s_c$. If $s_c$ is of the form \code{\CONTINUE{};}  then let $s_E$ be the the innermost  \DO{} (\ref{do}), \FOR{} (\ref{for}) or \WHILE{} (\ref{while}) statement enclosing  $s_c$. It is a compile-time error if no such statement or case clause $s_E$ exists within the innermost function in which  $s_c$ occurs.  Furthermore, let $s_1, \ldots, s_n$ be those \TRY{} statements that are both enclosed in $s_E$ and that enclose  $s_c$, and that have a \FINALLY{} clause. Lastly, let $f_j$ be the \FINALLY{} clause of $s_j, 1 \le j \le n$.   Executing  $s_c$ first executes $f_1, \ldots,  f_n$ in innermost-clause-first  order. Then, if $s_E$ is a case clause, control is transferred to the case clause. Otherwise, $s_E$ is necessarily a loop and execution resumes after the last statement in the loop body.
+ Let $s_c$ be a \CONTINUE{} statement. If $s_c$ is of the form  \code{\CONTINUE{} $L$;}, then let $s_E$ be the innermost labeled \DO{} (\ref{do}), \FOR{} (\ref{for}) or \WHILE{} (\ref{while}) statement or case clause with label $L$ enclosing $s_c$. If $s_c$ is of the form \code{\CONTINUE{};}  then let $s_E$ be the innermost  \DO{} (\ref{do}), \FOR{} (\ref{for}) or \WHILE{} (\ref{while}) statement enclosing  $s_c$. It is a compile-time error if no such statement or case clause $s_E$ exists within the innermost function in which  $s_c$ occurs.  Furthermore, let $s_1, \ldots, s_n$ be those \TRY{} statements that are both enclosed in $s_E$ and that enclose  $s_c$, and that have a \FINALLY{} clause. Lastly, let $f_j$ be the \FINALLY{} clause of $s_j, 1 \le j \le n$.   Executing  $s_c$ first executes $f_1, \ldots,  f_n$ in innermost-clause-first  order. Then, if $s_E$ is a case clause, control is transferred to the case clause. Otherwise, $s_E$ is necessarily a loop and execution resumes after the last statement in the loop body.
  
  \commentary{
  In a while loop, that would be the boolean expression before the body. In a do loop, it would be the boolean expression after the body. In a for loop, it would be the increment clause.  In other words, execution continues to the next iteration of the loop.
@@ -6980,7 +6980,7 @@
 }
 
 \LMHash{}
-Otherwise, any relative URI is interpreted as relative to the the location of the current library. All further interpretation of URIs is implementation dependent. 
+Otherwise, any relative URI is interpreted as relative to the location of the current library. All further interpretation of URIs is implementation dependent. 
 
 \commentary{This means it is dependent on the embedder.}
 
diff --git a/pkg/analysis_server/benchmark/integration/input_converter.dart b/pkg/analysis_server/benchmark/integration/input_converter.dart
index d743d6c..14ffd96 100644
--- a/pkg/analysis_server/benchmark/integration/input_converter.dart
+++ b/pkg/analysis_server/benchmark/integration/input_converter.dart
@@ -271,8 +271,7 @@
  * into a series of operations to be sent to the analysis server.
  * The input stream can be either an instrumenation or log file.
  */
-class InputConverter
-    extends ChunkedConverter<String, Operation, String, Operation> {
+class InputConverter extends Converter<String, Operation> {
 
   final Logger logger = new Logger('InputConverter');
 
diff --git a/pkg/analysis_server/lib/src/channel/channel.dart b/pkg/analysis_server/lib/src/channel/channel.dart
index bee6f35..21bd3ca 100644
--- a/pkg/analysis_server/lib/src/channel/channel.dart
+++ b/pkg/analysis_server/lib/src/channel/channel.dart
@@ -85,8 +85,7 @@
  * Instances of the class [JsonStreamDecoder] convert JSON strings to JSON
  * maps.
  */
-class JsonStreamDecoder extends
-    ChunkedConverter<String, Map, String, Map> {
+class JsonStreamDecoder extends Converter<String, Map> {
   @override
   Map convert(String text) => JSON.decode(text);
 
@@ -99,8 +98,7 @@
  * Instances of the class [NotificationConverter] convert JSON maps to
  * [Notification]s.
  */
-class NotificationConverter extends
-    ChunkedConverter<Map, Notification, Map, Notification> {
+class NotificationConverter extends Converter<Map, Notification> {
   @override
   Notification convert(Map json) => new Notification.fromJson(json);
 
@@ -112,8 +110,7 @@
 /**
  * Instances of the class [ResponseConverter] convert JSON maps to [Response]s.
  */
-class ResponseConverter extends
-    ChunkedConverter<Map, Response, Map, Response> {
+class ResponseConverter extends Converter<Map, Response> {
   @override
   Response convert(Map json) => new Response.fromJson(json);
 
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 181eeac..44c3595 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -611,7 +611,7 @@
         p.optionsProcessed(info.context, options);
       } catch (e, stacktrace) {
         AnalysisEngine.instance.logger.logError(
-            'Error processing .analysis_options',
+            'Error processing analysis options',
             new CaughtException(e, stacktrace));
       }
     });
diff --git a/pkg/analysis_server/lib/src/plugin/server_plugin.dart b/pkg/analysis_server/lib/src/plugin/server_plugin.dart
index 91ecb32..049ef3e 100644
--- a/pkg/analysis_server/lib/src/plugin/server_plugin.dart
+++ b/pkg/analysis_server/lib/src/plugin/server_plugin.dart
@@ -109,48 +109,49 @@
    * The extension point that allows plugins to register file patterns that will
    * cause files to be analyzed.
    */
-  ExtensionPoint analyzedFilePatternsExtensionPoint;
+  ExtensionPoint<List<String>> analyzedFilePatternsExtensionPoint;
 
   /**
    * The extension point that allows plugins to register assist contributors.
    */
-  ExtensionPoint assistContributorExtensionPoint;
+  ExtensionPoint<AssistContributor> assistContributorExtensionPoint;
 
   /**
    * The extension point that allows plugins to register completion
    * contributors.
    */
-  ExtensionPoint completionContributorExtensionPoint;
+  ExtensionPoint<CompletionContributorFactory>
+      completionContributorExtensionPoint;
 
   /**
    * The extension point that allows plugins to register domains with the
    * server.
    */
-  ExtensionPoint domainExtensionPoint;
+  ExtensionPoint<RequestHandlerFactory> domainExtensionPoint;
 
   /**
    * The extension point that allows plugins to register fix contributors with
    * the server.
    */
-  ExtensionPoint fixContributorExtensionPoint;
+  ExtensionPoint<FixContributor> fixContributorExtensionPoint;
 
   /**
    * The extension point that allows plugins to register navigation
    * contributors.
    */
-  ExtensionPoint navigationContributorExtensionPoint;
+  ExtensionPoint<NavigationContributor> navigationContributorExtensionPoint;
 
   /**
    * The extension point that allows plugins to register occurrences
    * contributors.
    */
-  ExtensionPoint occurrencesContributorExtensionPoint;
+  ExtensionPoint<OccurrencesContributor> occurrencesContributorExtensionPoint;
 
   /**
    * The extension point that allows plugins to get access to the `analysis`
    * domain.
    */
-  ExtensionPoint setAnalysisDomainExtensionPoint;
+  ExtensionPoint<SetAnalysisDomain> setAnalysisDomainExtensionPoint;
 
   /**
    * Initialize a newly created plugin.
@@ -230,28 +231,33 @@
 
   @override
   void registerExtensionPoints(RegisterExtensionPoint registerExtensionPoint) {
-    setAnalysisDomainExtensionPoint = registerExtensionPoint(
-        SET_ANALISYS_DOMAIN_EXTENSION_POINT,
-        _validateSetAnalysisDomainFunction);
-    analyzedFilePatternsExtensionPoint = registerExtensionPoint(
-        ANALYZED_FILE_PATTERNS_EXTENSION_POINT,
-        _validateAnalyzedFilePatternsExtension);
-    assistContributorExtensionPoint = registerExtensionPoint(
-        ASSIST_CONTRIBUTOR_EXTENSION_POINT,
-        _validateAssistContributorExtension);
-    completionContributorExtensionPoint = registerExtensionPoint(
-        COMPLETION_CONTRIBUTOR_EXTENSION_POINT,
-        _validateCompletionContributorExtension);
-    domainExtensionPoint = registerExtensionPoint(
-        DOMAIN_EXTENSION_POINT, _validateDomainExtension);
-    fixContributorExtensionPoint = registerExtensionPoint(
-        FIX_CONTRIBUTOR_EXTENSION_POINT, _validateFixContributorExtension);
-    navigationContributorExtensionPoint = registerExtensionPoint(
-        NAVIGATION_CONTRIBUTOR_EXTENSION_POINT,
-        _validateNavigationContributorExtension);
-    occurrencesContributorExtensionPoint = registerExtensionPoint(
-        OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT,
-        _validateOccurrencesContributorExtension);
+    analyzedFilePatternsExtensionPoint = new ExtensionPoint<List<String>>(
+        this, ANALYZED_FILE_PATTERNS_EXTENSION_POINT, null);
+    registerExtensionPoint(analyzedFilePatternsExtensionPoint);
+    assistContributorExtensionPoint = new ExtensionPoint<AssistContributor>(
+        this, ASSIST_CONTRIBUTOR_EXTENSION_POINT, null);
+    registerExtensionPoint(assistContributorExtensionPoint);
+    completionContributorExtensionPoint =
+        new ExtensionPoint<CompletionContributorFactory>(
+            this, COMPLETION_CONTRIBUTOR_EXTENSION_POINT, null);
+    registerExtensionPoint(completionContributorExtensionPoint);
+    domainExtensionPoint = new ExtensionPoint<RequestHandlerFactory>(
+        this, DOMAIN_EXTENSION_POINT, null);
+    registerExtensionPoint(domainExtensionPoint);
+    fixContributorExtensionPoint = new ExtensionPoint<FixContributor>(
+        this, FIX_CONTRIBUTOR_EXTENSION_POINT, null);
+    registerExtensionPoint(fixContributorExtensionPoint);
+    navigationContributorExtensionPoint =
+        new ExtensionPoint<NavigationContributor>(
+            this, NAVIGATION_CONTRIBUTOR_EXTENSION_POINT, null);
+    registerExtensionPoint(navigationContributorExtensionPoint);
+    occurrencesContributorExtensionPoint =
+        new ExtensionPoint<OccurrencesContributor>(
+            this, OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT, null);
+    registerExtensionPoint(occurrencesContributorExtensionPoint);
+    setAnalysisDomainExtensionPoint = new ExtensionPoint<SetAnalysisDomain>(
+        this, SET_ANALISYS_DOMAIN_EXTENSION_POINT, null);
+    registerExtensionPoint(setAnalysisDomainExtensionPoint);
   }
 
   @override
@@ -263,7 +269,8 @@
       '**/*.${AnalysisEngine.SUFFIX_DART}',
       '**/*.${AnalysisEngine.SUFFIX_HTML}',
       '**/*.${AnalysisEngine.SUFFIX_HTM}',
-      '**/${AnalysisEngine.ANALYSIS_OPTIONS_FILE}'
+      '**/${AnalysisEngine.ANALYSIS_OPTIONS_FILE}',
+      '**/${AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE}'
     ];
     registerExtension(ANALYZED_FILE_PATTERNS_EXTENSION_POINT_ID, patterns);
     //
@@ -307,111 +314,4 @@
     registerExtension(
         FIX_CONTRIBUTOR_EXTENSION_POINT_ID, new DefaultFixContributor());
   }
-
-  /**
-   * Return `true` if the list being used as an [extension] contains any
-   * elements that are not strings.
-   */
-  bool _containsNonString(List extension) {
-    for (Object element in extension) {
-      if (element is! String) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /**
-   * Validate the given extension by throwing an [ExtensionError] if it is not a
-   * valid list of analyzed file patterns.
-   */
-  void _validateAnalyzedFilePatternsExtension(Object extension) {
-    if (extension is! List || _containsNonString(extension)) {
-      String id = analyzedFilePatternsExtensionPoint.uniqueIdentifier;
-      throw new ExtensionError('Extensions to $id must be a List of Strings');
-    }
-  }
-
-  /**
-   * Validate the given extension by throwing an [ExtensionError] if it is not a
-   * valid assist contributor.
-   */
-  void _validateAssistContributorExtension(Object extension) {
-    if (extension is! AssistContributor) {
-      String id = assistContributorExtensionPoint.uniqueIdentifier;
-      throw new ExtensionError(
-          'Extensions to $id must be an AssistContributor');
-    }
-  }
-
-  /**
-   * Validate the given extension by throwing an [ExtensionError] if it is not a
-   * valid completion contributor.
-   */
-  void _validateCompletionContributorExtension(Object extension) {
-    if (extension is! CompletionContributorFactory) {
-      String id = completionContributorExtensionPoint.uniqueIdentifier;
-      throw new ExtensionError(
-          'Extensions to $id must be an CompletionContributorFactory');
-    }
-  }
-
-  /**
-   * Validate the given extension by throwing an [ExtensionError] if it is not a
-   * valid domain.
-   */
-  void _validateDomainExtension(Object extension) {
-    if (extension is! RequestHandlerFactory) {
-      String id = domainExtensionPoint.uniqueIdentifier;
-      throw new ExtensionError(
-          'Extensions to $id must be a RequestHandlerFactory');
-    }
-  }
-
-  /**
-   * Validate the given extension by throwing an [ExtensionError] if it is not a
-   * valid fix contributor.
-   */
-  void _validateFixContributorExtension(Object extension) {
-    if (extension is! FixContributor) {
-      String id = fixContributorExtensionPoint.uniqueIdentifier;
-      throw new ExtensionError('Extensions to $id must be a FixContributor');
-    }
-  }
-
-  /**
-   * Validate the given extension by throwing an [ExtensionError] if it is not a
-   * valid navigation contributor.
-   */
-  void _validateNavigationContributorExtension(Object extension) {
-    if (extension is! NavigationContributor) {
-      String id = navigationContributorExtensionPoint.uniqueIdentifier;
-      throw new ExtensionError(
-          'Extensions to $id must be an NavigationContributor');
-    }
-  }
-
-  /**
-   * 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) {
-    if (extension is! SetAnalysisDomain) {
-      String id = setAnalysisDomainExtensionPoint.uniqueIdentifier;
-      throw new ExtensionError(
-          'Extensions to $id must be a SetAnalysisDomain function');
-    }
-  }
 }
diff --git a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
index 97a162e..b25375ad 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
@@ -20,7 +20,7 @@
 const int DART_RELEVANCE_COMMON_USAGE = 1200;
 const int DART_RELEVANCE_DEFAULT = 1000;
 const int DART_RELEVANCE_HIGH = 2000;
-const int DART_RELEVANCE_INCREMENT = 20;
+const int DART_RELEVANCE_INCREMENT = 100;
 const int DART_RELEVANCE_INHERITED_ACCESSOR = 1057;
 const int DART_RELEVANCE_INHERITED_FIELD = 1058;
 const int DART_RELEVANCE_INHERITED_METHOD = 1057;
diff --git a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_plugin.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_plugin.dart
index cf34c94..8338c92 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_plugin.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_plugin.dart
@@ -50,7 +50,7 @@
    * The extension point that allows plugins to register Dart specific
    * completion contributor factories.
    */
-  ExtensionPoint _contributorExtensionPoint;
+  ExtensionPoint<DartCompletionContributorFactory> _contributorExtensionPoint;
 
   /**
    * Return a list containing all of the Dart specific completion contributors.
@@ -64,9 +64,10 @@
 
   @override
   void registerExtensionPoints(RegisterExtensionPoint registerExtensionPoint) {
-    _contributorExtensionPoint = registerExtensionPoint(
-        CONTRIBUTOR_EXTENSION_POINT,
-        _validateDartCompletionContributorExtension);
+    _contributorExtensionPoint =
+        new ExtensionPoint<DartCompletionContributorFactory>(
+            this, CONTRIBUTOR_EXTENSION_POINT, null);
+    registerExtensionPoint(_contributorExtensionPoint);
   }
 
   @override
@@ -119,16 +120,4 @@
     registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
         () => new VariableNameContributor());
   }
-
-  /**
-   * Validate the given extension by throwing an [ExtensionError] if it is not a
-   * valid Dart specific completion contributor.
-   */
-  void _validateDartCompletionContributorExtension(Object extension) {
-    if (extension is! DartCompletionContributorFactory) {
-      String id = _contributorExtensionPoint.uniqueIdentifier;
-      throw new ExtensionError(
-          'Extensions to $id must be a DartCompletionContributorFactory');
-    }
-  }
 }
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 6ccf8ae..ae8c50f 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -313,7 +313,7 @@
    * If this flag is `true`, then single analysis context should be used for
    * analysis of multiple analysis roots, special files that could otherwise
    * cause creating additional contexts, such as `pubspec.yaml`, or `.packages`,
-   * or `.analysis_options` are ignored.
+   * or analysis options are ignored.
    */
   bool useSingleContextManager = false;
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
index 833b0ec..6b328b2 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
@@ -265,7 +265,7 @@
       // Actual: if (x i^)
       // Parsed: if (x) i^
       _addSuggestion(Keyword.IS, DART_RELEVANCE_HIGH);
-    } else if (entity == node.thenStatement) {
+    } else if (entity == node.thenStatement || entity == node.elseStatement) {
       _addStatementKeywords(node);
     } else if (entity == node.condition) {
       _addExpressionKeywords(node);
@@ -502,6 +502,9 @@
     if (_inSwitch(node)) {
       _addSuggestions([Keyword.BREAK]);
     }
+    if (_isEntityAfterIfWithoutElse(node)) {
+      _addSuggestions([Keyword.ELSE]);
+    }
     _addSuggestions([
       Keyword.ASSERT,
       Keyword.CONST,
@@ -584,6 +587,30 @@
   bool _inWhileLoop(AstNode node) =>
       node.getAncestor((p) => p is WhileStatement) != null;
 
+  bool _isEntityAfterIfWithoutElse(AstNode node) {
+    Block block = node?.getAncestor((n) => n is Block);
+    if (block == null) {
+      return false;
+    }
+    Object entity = this.entity;
+    if (entity is Statement) {
+      int entityIndex = block.statements.indexOf(entity);
+      if (entityIndex > 0) {
+        Statement prevStatement = block.statements[entityIndex - 1];
+        return prevStatement is IfStatement &&
+            prevStatement.elseStatement == null;
+      }
+    }
+    if (entity is Token) {
+      for (Statement statement in block.statements) {
+        if (statement.endToken.next == entity) {
+          return statement is IfStatement && statement.elseStatement == null;
+        }
+      }
+    }
+    return false;
+  }
+
   static bool _isNextTokenSynthetic(Object entity, TokenType type) {
     if (entity is AstNode) {
       Token token = entity.beginToken;
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
index d9778a5..7687117 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
@@ -256,6 +256,13 @@
       _addLocalSuggestion_includeTypeNameSuggestions(
           declaration.name, NO_RETURN_TYPE, protocol.ElementKind.ENUM,
           isDeprecated: _isDeprecated(declaration));
+      for (EnumConstantDeclaration enumConstant in declaration.constants) {
+        if (!enumConstant.isSynthetic) {
+          _addLocalSuggestion_includeReturnValueSuggestions_enumConstant(
+              enumConstant, declaration,
+              isDeprecated: _isDeprecated(declaration));
+        }
+      }
     }
   }
 
@@ -419,6 +426,42 @@
     }
   }
 
+  void _addLocalSuggestion_enumConstant(
+      EnumConstantDeclaration constantDeclaration,
+      EnumDeclaration enumDeclaration,
+      {bool isAbstract: false,
+      bool isDeprecated: false,
+      ClassDeclaration classDecl,
+      int relevance: DART_RELEVANCE_DEFAULT}) {
+    String completion =
+        '${enumDeclaration.name.name}.${constantDeclaration.name.name}';
+    CompletionSuggestion suggestion = new CompletionSuggestion(
+        CompletionSuggestionKind.INVOCATION,
+        isDeprecated ? DART_RELEVANCE_LOW : relevance,
+        completion,
+        completion.length,
+        0,
+        isDeprecated,
+        false,
+        returnType: enumDeclaration.name.name);
+
+    suggestionMap.putIfAbsent(suggestion.completion, () => suggestion);
+    int flags = protocol.Element.makeFlags(
+        isAbstract: isAbstract,
+        isDeprecated: isDeprecated,
+        isPrivate: Identifier.isPrivateName(constantDeclaration.name.name));
+    suggestion.element = new protocol.Element(
+        protocol.ElementKind.ENUM_CONSTANT,
+        constantDeclaration.name.name,
+        flags,
+        location: new Location(
+            request.source.fullName,
+            constantDeclaration.name.offset,
+            constantDeclaration.name.length,
+            0,
+            0));
+  }
+
   void _addLocalSuggestion_includeReturnValueSuggestions(
       SimpleIdentifier id, TypeName typeName, protocol.ElementKind elemKind,
       {bool isAbstract: false,
@@ -438,6 +481,22 @@
     }
   }
 
+  void _addLocalSuggestion_includeReturnValueSuggestions_enumConstant(
+      EnumConstantDeclaration constantDeclaration,
+      EnumDeclaration enumDeclaration,
+      {bool isAbstract: false,
+      bool isDeprecated: false,
+      int relevance: DART_RELEVANCE_DEFAULT}) {
+    relevance = optype.returnValueSuggestionsFilter(
+        enumDeclaration.element.type, relevance);
+    if (relevance != null) {
+      _addLocalSuggestion_enumConstant(constantDeclaration, enumDeclaration,
+          isAbstract: isAbstract,
+          isDeprecated: isDeprecated,
+          relevance: relevance);
+    }
+  }
+
   void _addLocalSuggestion_includeTypeNameSuggestions(
       SimpleIdentifier id, TypeName typeName, protocol.ElementKind elemKind,
       {bool isAbstract: false,
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/optype.dart b/pkg/analysis_server/lib/src/services/completion/dart/optype.dart
index 3ddc75d..3a5608c 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/optype.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/optype.dart
@@ -641,6 +641,16 @@
       optype.includeReturnValueSuggestions = true;
       optype.returnValueSuggestionsFilter = (DartType dartType, int relevance) {
         DartType type = node.element?.type;
+        bool isEnum = type != null &&
+            type.element is ClassElement &&
+            (type.element as ClassElement).isEnum;
+        if (isEnum) {
+          if (type == dartType) {
+            return relevance + DART_RELEVANCE_INCREMENT;
+          } else {
+            return null;
+          }
+        }
         if (type != null &&
             dartType != null &&
             !type.isDynamic &&
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 49d616d..20ca00f 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -70,6 +70,7 @@
     errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1 ||
     errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2 ||
     errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS ||
+    errorCode == StaticWarningCode.FUNCTION_WITHOUT_CALL ||
     errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER ||
     errorCode ==
         CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE ||
@@ -154,6 +155,8 @@
       const FixKind('CREATE_LOCAL_VARIABLE', 50, "Create local variable '{0}'");
   static const CREATE_METHOD =
       const FixKind('CREATE_METHOD', 50, "Create method '{0}'");
+  static const CREATE_MISSING_METHOD_CALL =
+      const FixKind('CREATE_MISSING_METHOD_CALL', 49, "Create method 'call'.");
   static const CREATE_MISSING_OVERRIDES = const FixKind(
       'CREATE_MISSING_OVERRIDES', 49, "Create {0} missing override(s)");
   static const CREATE_NO_SUCH_METHOD = const FixKind(
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 f855a29..117884d 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -245,6 +245,9 @@
       _addFix_createConstructor_insteadOfSyntheticDefault();
       _addFix_addMissingParameter();
     }
+    if (errorCode == StaticWarningCode.FUNCTION_WITHOUT_CALL) {
+      _addFix_addMissingMethodCall();
+    }
     if (errorCode == StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR) {
       _addFix_createConstructor_named();
     }
@@ -415,6 +418,32 @@
     }
   }
 
+  void _addFix_addMissingMethodCall() {
+    ClassDeclaration targetClass = node.parent as ClassDeclaration;
+    // prepare SourceBuilder
+    int insertOffset = targetClass.end - 1;
+    SourceBuilder sb = new SourceBuilder(file, insertOffset);
+    // prepare environment
+    String prefix = utils.getIndent(1);
+    String prefix2 = utils.getIndent(2);
+    // start method
+    sb.append(prefix);
+    sb.append('call() {');
+    // TO-DO
+    sb.append(eol);
+    sb.append(prefix2);
+    sb.append('// TODO: implement call');
+    sb.append(eol);
+    // close method
+    sb.append(prefix);
+    sb.append('}');
+    sb.append(eol);
+    // add proposal
+    exitPosition = new Position(file, insertOffset);
+    _insertBuilder(sb, unitElement);
+    _addFix(DartFixKind.CREATE_MISSING_METHOD_CALL, []);
+  }
+
   void _addFix_addMissingParameter() {
     if (node is ArgumentList && node.parent is MethodInvocation) {
       ArgumentList argumentList = node;
diff --git a/pkg/analysis_server/lib/src/single_context_manager.dart b/pkg/analysis_server/lib/src/single_context_manager.dart
index 0a8c9f1..058d77e 100644
--- a/pkg/analysis_server/lib/src/single_context_manager.dart
+++ b/pkg/analysis_server/lib/src/single_context_manager.dart
@@ -22,7 +22,7 @@
  * Implementation of [ContextManager] that supports only one [AnalysisContext].
  * So, sources from all analysis roots are added to this single context. All
  * features that could otherwise cause creating additional contexts, such as
- * presence of `pubspec.yaml` or `.packages` files, or `.analysis_options` files
+ * presence of `pubspec.yaml` or `.packages` files, or analysis options files
  * are ignored.
  */
 class SingleContextManager implements ContextManager {
diff --git a/pkg/analysis_server/pubspec.yaml b/pkg/analysis_server/pubspec.yaml
index dff1fd7..03722a1 100644
--- a/pkg/analysis_server/pubspec.yaml
+++ b/pkg/analysis_server/pubspec.yaml
@@ -9,10 +9,10 @@
   analyzer: ^0.27.0
   args: '>=0.13.0 <0.14.0'
   dart_style: '>=0.2.0 <0.3.0'
-  linter: ^0.1.10
+  linter: ^0.1.16
   logging: any
   path: any
-  plugin: <0.2.0
+  plugin: ^0.2.0
   watcher: any
   yaml: any
 dev_dependencies:
diff --git a/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart b/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart
index e8cf7c4..b2d1add 100644
--- a/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_analysis_options_test.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 test.analysis.notification.analysis_options;
+library test.analysis.notification_analysis_options_test;
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
 import 'package:analysis_server/src/constants.dart';
@@ -18,11 +18,12 @@
 
 main() {
   initializeTestEnvironment();
-  defineReflectiveTests(AnalysisOptionsFileNotificationTest);
+  defineReflectiveTests(NewAnalysisOptionsFileNotificationTest);
+  defineReflectiveTests(OldAnalysisOptionsFileNotificationTest);
 }
 
-@reflectiveTest
-class AnalysisOptionsFileNotificationTest extends AbstractAnalysisTest {
+abstract class AnalysisOptionsFileNotificationTest
+    extends AbstractAnalysisTest {
   Map<String, List<AnalysisError>> filesErrors = {};
 
   final testSource = '''
@@ -36,7 +37,7 @@
 
   List<AnalysisError> get optionsFileErrors => filesErrors[optionsFilePath];
 
-  String get optionsFilePath => '$projectPath/.analysis_options';
+  String get optionsFilePath;
 
   AnalysisContext get testContext => server.getContainingContext(testFile);
 
@@ -306,3 +307,15 @@
     }
   }
 }
+
+@reflectiveTest
+class NewAnalysisOptionsFileNotificationTest
+    extends AnalysisOptionsFileNotificationTest {
+  String get optionsFilePath => '$projectPath/analysis_options.yaml';
+}
+
+@reflectiveTest
+class OldAnalysisOptionsFileNotificationTest
+    extends AnalysisOptionsFileNotificationTest {
+  String get optionsFilePath => '$projectPath/.analysis_options';
+}
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index 8527528e..c238d59 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -471,7 +471,28 @@
     });
   }
 
-  test_setAnalysisSubscriptions_fileInIgnoredFolder() async {
+  test_setAnalysisSubscriptions_fileInIgnoredFolder_newOptions() async {
+    String path = '/project/samples/sample.dart';
+    resourceProvider.newFile(path, '');
+    resourceProvider.newFile(
+        '/project/analysis_options.yaml',
+        r'''
+analyzer:
+  exclude:
+    - 'samples/**'
+''');
+    server.setAnalysisRoots('0', ['/project'], [], {});
+    server.setAnalysisSubscriptions(<AnalysisService, Set<String>>{
+      AnalysisService.NAVIGATION: new Set<String>.from([path])
+    });
+    // the file is excluded, so no navigation notification
+    await server.onAnalysisComplete;
+    expect(channel.notificationsReceived.any((notification) {
+      return notification.event == ANALYSIS_NAVIGATION;
+    }), isFalse);
+  }
+
+  test_setAnalysisSubscriptions_fileInIgnoredFolder_oldOptions() async {
     String path = '/project/samples/sample.dart';
     resourceProvider.newFile(path, '');
     resourceProvider.newFile(
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index 9f00603..db85fcd 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -35,352 +35,12 @@
 main() {
   initializeTestEnvironment();
   defineReflectiveTests(AbstractContextManagerTest);
+  defineReflectiveTests(ContextManagerWithNewOptionsTest);
+  defineReflectiveTests(ContextManagerWithOldOptionsTest);
 }
 
 @reflectiveTest
-class AbstractContextManagerTest {
-  /**
-   * The name of the 'bin' directory.
-   */
-  static const String BIN_NAME = 'bin';
-
-  /**
-   * The name of the 'example' directory.
-   */
-  static const String EXAMPLE_NAME = 'example';
-
-  /**
-   * The name of the 'lib' directory.
-   */
-  static const String LIB_NAME = 'lib';
-
-  /**
-   * The name of the 'src' directory.
-   */
-  static const String SRC_NAME = 'src';
-
-  /**
-   * The name of the 'test' directory.
-   */
-  static const String TEST_NAME = 'test';
-
-  ContextManagerImpl manager;
-
-  TestContextManagerCallbacks callbacks;
-
-  MemoryResourceProvider resourceProvider;
-
-  MockPackageMapProvider packageMapProvider;
-
-  UriResolver packageResolver = null;
-
-  UriResolver embeddedUriResolver = null;
-
-  String projPath = '/my/proj';
-
-  AnalysisError missing_required_param = new AnalysisError(
-      new TestSource(), 0, 1, HintCode.MISSING_REQUIRED_PARAM, [
-    ['x']
-  ]);
-
-  AnalysisError missing_return =
-      new AnalysisError(new TestSource(), 0, 1, HintCode.MISSING_RETURN, [
-    ['x']
-  ]);
-
-  AnalysisError invalid_assignment_error =
-      new AnalysisError(new TestSource(), 0, 1, HintCode.INVALID_ASSIGNMENT, [
-    ['x'],
-    ['y']
-  ]);
-
-  AnalysisError unused_local_variable = new AnalysisError(
-      new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [
-    ['x']
-  ]);
-
-  List<Glob> get analysisFilesGlobs {
-    List<String> patterns = <String>[
-      '**/*.${AnalysisEngine.SUFFIX_DART}',
-      '**/*.${AnalysisEngine.SUFFIX_HTML}',
-      '**/*.${AnalysisEngine.SUFFIX_HTM}',
-      '**/${AnalysisEngine.ANALYSIS_OPTIONS_FILE}'
-    ];
-    return patterns
-        .map((pattern) => new Glob(JavaFile.pathContext.separator, pattern))
-        .toList();
-  }
-
-  List<ErrorProcessor> get errorProcessors => callbacks.currentContext
-      .getConfigurationData(CONFIGURED_ERROR_PROCESSORS);
-
-  List<Linter> get lints => getLints(callbacks.currentContext);
-
-  AnalysisOptions get options => callbacks.currentContext.analysisOptions;
-
-  Map<String, List<Folder>> get _currentPackageMap => _packageMap(projPath);
-
-  void deleteFile(List<String> pathComponents) {
-    String filePath = posix.joinAll(pathComponents);
-    resourceProvider.deleteFile(filePath);
-  }
-
-  ErrorProcessor getProcessor(AnalysisError error) =>
-      ErrorProcessor.getProcessor(callbacks.currentContext, error);
-
-  String newFile(List<String> pathComponents, [String content = '']) {
-    String filePath = posix.joinAll(pathComponents);
-    resourceProvider.newFile(filePath, content);
-    return filePath;
-  }
-
-  String newFolder(List<String> pathComponents) {
-    String folderPath = posix.joinAll(pathComponents);
-    resourceProvider.newFolder(folderPath);
-    return folderPath;
-  }
-
-  void processRequiredPlugins() {
-    List<Plugin> plugins = <Plugin>[];
-    plugins.addAll(AnalysisEngine.instance.requiredPlugins);
-    plugins.add(AnalysisEngine.instance.commandLinePlugin);
-    plugins.add(AnalysisEngine.instance.optionsPlugin);
-    plugins.add(linterPlugin);
-    ExtensionManager manager = new ExtensionManager();
-    manager.processPlugins(plugins);
-  }
-
-  EmbedderUriResolver provideEmbeddedUriResolver(Folder folder) =>
-      embeddedUriResolver;
-
-  UriResolver providePackageResolver(Folder folder) => packageResolver;
-
-  void setUp() {
-    processRequiredPlugins();
-    resourceProvider = new MemoryResourceProvider();
-    packageMapProvider = new MockPackageMapProvider();
-    DartSdkManager sdkManager = new DartSdkManager((_) {
-      return new MockSdk();
-    });
-    manager = new ContextManagerImpl(
-        resourceProvider,
-        sdkManager,
-        providePackageResolver,
-        provideEmbeddedUriResolver,
-        packageMapProvider,
-        analysisFilesGlobs,
-        InstrumentationService.NULL_SERVICE,
-        new AnalysisOptionsImpl());
-    callbacks = new TestContextManagerCallbacks(resourceProvider);
-    manager.callbacks = callbacks;
-    resourceProvider.newFolder(projPath);
-  }
-
-  test_analysis_options_file_delete() async {
-    // Setup .analysis_options
-    newFile(
-        [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
-        r'''
-embedded_libs:
-  "dart:foobar": "../sdk_ext/entry.dart"
-analyzer:
-  language:
-    enableGenericMethods: true
-  errors:
-    unused_local_variable: false
-linter:
-  rules:
-    - camel_case_types
-''');
-
-    // Setup context.
-    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-    await pumpEventQueue();
-
-    // Verify options were set.
-    expect(errorProcessors, hasLength(1));
-    expect(lints, hasLength(1));
-    expect(options.enableGenericMethods, isTrue);
-
-    // Remove options.
-    deleteFile([projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE]);
-    await pumpEventQueue();
-
-    // Verify defaults restored.
-    expect(errorProcessors, isEmpty);
-    expect(lints, isEmpty);
-    expect(options.enableGenericMethods, isFalse);
-  }
-
-  test_analysis_options_file_delete_with_embedder() async {
-    // Setup _embedder.yaml.
-    String libPath = newFolder([projPath, LIB_NAME]);
-    newFile(
-        [libPath, '_embedder.yaml'],
-        r'''
-analyzer:
-  strong-mode: true
-  errors:
-    missing_return: false
-linter:
-  rules:
-    - avoid_as
-''');
-
-    // Setup .packages file
-    newFile(
-        [projPath, '.packages'],
-        r'''
-test_pack:lib/''');
-
-    // Setup .analysis_options
-    newFile(
-        [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
-        r'''
-analyzer:
-  language:
-    enableGenericMethods: true
-  errors:
-    unused_local_variable: false
-linter:
-  rules:
-    - camel_case_types
-''');
-
-    // Setup context.
-    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-    await pumpEventQueue();
-
-    // Verify options were set.
-    expect(options.enableGenericMethods, isTrue);
-    expect(options.strongMode, isTrue);
-    expect(errorProcessors, hasLength(2));
-    expect(lints, hasLength(2));
-
-    // Remove options.
-    deleteFile([projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE]);
-    await pumpEventQueue();
-
-    // Verify defaults restored.
-    expect(options.enableGenericMethods, isFalse);
-    expect(lints, hasLength(1));
-    expect(lints.first, new isInstanceOf<AvoidAs>());
-    expect(errorProcessors, hasLength(1));
-    expect(getProcessor(missing_return).severity, isNull);
-  }
-
-  test_analysis_options_parse_failure() async {
-    // Create files.
-    String libPath = newFolder([projPath, LIB_NAME]);
-    newFile([libPath, 'main.dart']);
-    String sdkExtPath = newFolder([projPath, 'sdk_ext']);
-    newFile([sdkExtPath, 'entry.dart']);
-    String sdkExtSrcPath = newFolder([projPath, 'sdk_ext', 'src']);
-    newFile([sdkExtSrcPath, 'part.dart']);
-    // Setup analysis options file with ignore list.
-    newFile(
-        [projPath, '.analysis_options'],
-        r'''
-;
-''');
-    // Setup context.
-    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-
-    // No error means success.
-  }
-
-  test_configed_options() async {
-    // Create files.
-    String libPath = newFolder([projPath, LIB_NAME]);
-    newFile([projPath, 'test', 'test.dart']);
-    newFile(
-        [projPath, 'pubspec.yaml'],
-        r'''
-dependencies:
-  test_pack: any
-analyzer:
-  configuration: test_pack/config
-''');
-
-    // Setup .packages file
-    newFile(
-        [projPath, '.packages'],
-        r'''
-test_pack:lib/''');
-
-    // Setup config.yaml.
-    newFile(
-        [libPath, 'config', 'config.yaml'],
-        r'''
-analyzer:
-  strong-mode: true
-  language:
-    enableSuperMixins: true
-  errors:
-    missing_return: false
-linter:
-  rules:
-    - avoid_as
-''');
-
-    // Setup .analysis_options
-    newFile(
-        [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
-        r'''
-analyzer:
-  exclude:
-    - 'test/**'
-  language:
-    enableGenericMethods: true
-    enableAsync: false
-  errors:
-    unused_local_variable: false
-linter:
-  rules:
-    - camel_case_types
-''');
-
-    // Setup context.
-    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-    await pumpEventQueue();
-
-    // Confirm that one context was created.
-    var contexts =
-        manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
-    expect(contexts, isNotNull);
-    expect(contexts, hasLength(1));
-
-    var context = contexts.first;
-
-    // Verify options.
-    // * from `config.yaml`:
-    expect(context.analysisOptions.strongMode, isTrue);
-    expect(context.analysisOptions.enableSuperMixins, isTrue);
-    expect(context.analysisOptions.enableAsync, isFalse);
-    // * from `.analysis_options`:
-    expect(context.analysisOptions.enableGenericMethods, isTrue);
-
-    // * verify tests are excluded
-    expect(callbacks.currentContextFilePaths[projPath].keys,
-        unorderedEquals(['/my/proj/.analysis_options']));
-
-    // Verify filter setup.
-    expect(errorProcessors, hasLength(2));
-
-    // * (config.)
-    expect(getProcessor(missing_return).severity, isNull);
-
-    // * (options.)
-    expect(getProcessor(unused_local_variable).severity, isNull);
-
-    // Verify lints.
-    var lintNames = lints.map((lint) => lint.name);
-    expect(
-        lintNames,
-        unorderedEquals(
-            ['avoid_as' /* config */, 'camel_case_types' /* options */]));
-  }
-
+class AbstractContextManagerTest extends ContextManagerTest {
   void test_contextsInAnalysisRoot_nestedContext() {
     String subProjPath = posix.join(projPath, 'subproj');
     Folder subProjFolder = resourceProvider.newFolder(subProjPath);
@@ -408,7 +68,7 @@
 
   test_embedder_added() async {
     // Create files.
-    String libPath = newFolder([projPath, LIB_NAME]);
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
     newFile([libPath, 'main.dart']);
     newFile([libPath, 'nope.dart']);
     String embedderPath = newFolder([projPath, 'embedder']);
@@ -459,227 +119,9 @@
     expect(contexts.first.sourceFactory.forUri('dart:typed_data'), isNotNull);
   }
 
-  test_embedder_and_configed_options() async {
-    // Create files.
-    String libPath = newFolder([projPath, LIB_NAME]);
-    String sdkExtPath = newFolder([projPath, 'sdk_ext']);
-    newFile([projPath, 'test', 'test.dart']);
-    newFile([sdkExtPath, 'entry.dart']);
-
-    // Setup pubspec with configuration.
-    newFile(
-        [projPath, 'pubspec.yaml'],
-        r'''
-dependencies:
-  test_pack: any
-analyzer:
-  configuration: test_pack/config
-''');
-
-    // Setup _embedder.yaml.
-    newFile(
-        [libPath, '_embedder.yaml'],
-        r'''
-embedded_libs:
-  "dart:foobar": "../sdk_ext/entry.dart"
-analyzer:
-  strong-mode: true
-  language:
-    enableSuperMixins: true
-  errors:
-    missing_return: false
-linter:
-  rules:
-    - avoid_as
-''');
-
-    // Setup .packages file
-    newFile(
-        [projPath, '.packages'],
-        r'''
-test_pack:lib/''');
-
-    // Setup .analysis_options
-    newFile(
-        [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
-        r'''
-analyzer:
-  exclude:
-    - 'test/**'
-  language:
-    enableGenericMethods: true
-    enableAsync: false
-  errors:
-    unused_local_variable: false
-linter:
-  rules:
-    - camel_case_types
-''');
-
-    // Setup config.yaml.
-    newFile(
-        [libPath, 'config', 'config.yaml'],
-        r'''
-analyzer:
-  errors:
-    missing_required_param: error
-linter:
-  rules:
-    - always_specify_types
-''');
-
-    // Setup context.
-    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-    await pumpEventQueue();
-
-    // Confirm that one context was created.
-    var contexts =
-        manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
-    expect(contexts, isNotNull);
-    expect(contexts, hasLength(1));
-    var context = contexts[0];
-
-    // Verify options.
-    // * from `_embedder.yaml`:
-    expect(context.analysisOptions.strongMode, isTrue);
-    expect(context.analysisOptions.enableSuperMixins, isTrue);
-    expect(context.analysisOptions.enableAsync, isFalse);
-    // * from `.analysis_options`:
-    expect(context.analysisOptions.enableGenericMethods, isTrue);
-
-    // * verify tests are excluded
-    expect(
-        callbacks.currentContextFilePaths[projPath].keys,
-        unorderedEquals(
-            ['/my/proj/sdk_ext/entry.dart', '/my/proj/.analysis_options']));
-
-    // Verify filter setup.
-    expect(errorProcessors, hasLength(3));
-
-    // * (embedder.)
-    expect(getProcessor(missing_return).severity, isNull);
-
-    // * (config.)
-    expect(getProcessor(missing_required_param).severity, ErrorSeverity.ERROR);
-
-    // * (options.)
-    expect(getProcessor(unused_local_variable).severity, isNull);
-
-    // Verify lints.
-    var lintNames = lints.map((lint) => lint.name);
-
-    expect(
-        lintNames,
-        unorderedEquals([
-          'avoid_as' /* embedder */,
-          'always_specify_types' /* config*/,
-          'camel_case_types' /* options */
-        ]));
-
-    // Sanity check embedder libs.
-    var source = context.sourceFactory.forUri('dart:foobar');
-    expect(source, isNotNull);
-    expect(source.fullName,
-        '/my/proj/sdk_ext/entry.dart'.replaceAll('/', JavaFile.separator));
-  }
-
-  test_embedder_options() async {
-    // Create files.
-    String libPath = newFolder([projPath, LIB_NAME]);
-    String sdkExtPath = newFolder([projPath, 'sdk_ext']);
-    newFile([projPath, 'test', 'test.dart']);
-    newFile([sdkExtPath, 'entry.dart']);
-    // Setup _embedder.yaml.
-    newFile(
-        [libPath, '_embedder.yaml'],
-        r'''
-embedded_libs:
-  "dart:foobar": "../sdk_ext/entry.dart"
-analyzer:
-  strong-mode: true
-  language:
-    enableSuperMixins: true
-  errors:
-    missing_return: false
-linter:
-  rules:
-    - avoid_as
-''');
-    // Setup .packages file
-    newFile(
-        [projPath, '.packages'],
-        r'''
-test_pack:lib/''');
-
-    // Setup .analysis_options
-    newFile(
-        [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
-        r'''
-analyzer:
-  exclude:
-    - 'test/**'
-  language:
-    enableGenericMethods: true
-    enableAsync: false
-  errors:
-    unused_local_variable: false
-linter:
-  rules:
-    - camel_case_types
-''');
-
-    // Setup context.
-    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-    await pumpEventQueue();
-
-    // Confirm that one context was created.
-    var contexts =
-        manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
-    expect(contexts, isNotNull);
-    expect(contexts, hasLength(1));
-    var context = contexts[0];
-
-    // Verify options.
-    // * from `_embedder.yaml`:
-    expect(context.analysisOptions.strongMode, isTrue);
-    expect(context.analysisOptions.enableSuperMixins, isTrue);
-    expect(context.analysisOptions.enableAsync, isFalse);
-    // * from `.analysis_options`:
-    expect(context.analysisOptions.enableGenericMethods, isTrue);
-
-    // * verify tests are excluded
-    expect(
-        callbacks.currentContextFilePaths[projPath].keys,
-        unorderedEquals(
-            ['/my/proj/sdk_ext/entry.dart', '/my/proj/.analysis_options']));
-
-    // Verify filter setup.
-    expect(errorProcessors, hasLength(2));
-
-    // * (embedder.)
-    expect(getProcessor(missing_return).severity, isNull);
-
-    // * (options.)
-    expect(getProcessor(unused_local_variable).severity, isNull);
-
-    // Verify lints.
-    var lintNames = lints.map((lint) => lint.name);
-
-    expect(
-        lintNames,
-        unorderedEquals(
-            ['avoid_as' /* embedder */, 'camel_case_types' /* options */]));
-
-    // Sanity check embedder libs.
-    var source = context.sourceFactory.forUri('dart:foobar');
-    expect(source, isNotNull);
-    expect(source.fullName,
-        '/my/proj/sdk_ext/entry.dart'.replaceAll('/', JavaFile.separator));
-  }
-
   test_embedder_packagespec() async {
     // Create files.
-    String libPath = newFolder([projPath, LIB_NAME]);
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
     newFile([libPath, 'main.dart']);
     newFile([libPath, 'nope.dart']);
     String sdkExtPath = newFolder([projPath, 'sdk_ext']);
@@ -721,77 +163,6 @@
     expect(context.sourceFactory.forUri('dart:typed_data'), isNotNull);
   }
 
-  test_error_filter_analysis_option() async {
-    // Create files.
-    newFile(
-        [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
-        r'''
-analyzer:
-  errors:
-    unused_local_variable: ignore
-''');
-    // Setup context.
-    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-
-    // Verify filter setup.
-    expect(errorProcessors, hasLength(1));
-    expect(getProcessor(unused_local_variable).severity, isNull);
-  }
-
-  test_error_filter_analysis_option_multiple_filters() async {
-    // Create files.
-    newFile(
-        [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
-        r'''
-analyzer:
-  errors:
-    invalid_assignment: ignore
-    unused_local_variable: error
-''');
-    // Setup context.
-    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-
-    // Verify filter setup.
-    expect(errorProcessors, hasLength(2));
-
-    expect(getProcessor(invalid_assignment_error).severity, isNull);
-    expect(getProcessor(unused_local_variable).severity, ErrorSeverity.ERROR);
-  }
-
-  test_error_filter_analysis_option_synonyms() async {
-    // Create files.
-    newFile(
-        [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
-        r'''
-analyzer:
-  errors:
-    unused_local_variable: ignore
-    ambiguous_import: false
-''');
-    // Setup context.
-    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-
-    // Verify filter setup.
-    expect(errorProcessors, isNotNull);
-    expect(errorProcessors, hasLength(2));
-  }
-
-  test_error_filter_analysis_option_unpsecified() async {
-    // Create files.
-    newFile(
-        [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
-        r'''
-analyzer:
-#  errors:
-#    unused_local_variable: ignore
-''');
-    // Setup context.
-    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-
-    // Verify filter setup.
-    expect(errorProcessors, isEmpty);
-  }
-
   test_ignoreFilesInPackagesFolder() {
     // create a context with a pubspec.yaml file
     String pubspecPath = posix.join(projPath, 'pubspec.yaml');
@@ -860,7 +231,7 @@
         rootInfo, ['sdk_ext/**', 'lib/ignoreme.dart']);
     // Start creating files.
     newFile([projPath, ContextManagerImpl.PUBSPEC_NAME]);
-    String libPath = newFolder([projPath, LIB_NAME]);
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
     newFile([libPath, 'main.dart']);
     newFile([libPath, 'ignoreme.dart']);
     String sdkExtPath = newFolder([projPath, 'sdk_ext']);
@@ -878,145 +249,6 @@
     expect(files[0], equals('/my/proj/lib/main.dart'));
   }
 
-  test_path_filter_analysis_option() async {
-    // Create files.
-    String libPath = newFolder([projPath, LIB_NAME]);
-    newFile([libPath, 'main.dart']);
-    newFile([libPath, 'nope.dart']);
-    String sdkExtPath = newFolder([projPath, 'sdk_ext']);
-    newFile([sdkExtPath, 'entry.dart']);
-    String sdkExtSrcPath = newFolder([projPath, 'sdk_ext', 'src']);
-    newFile([sdkExtSrcPath, 'part.dart']);
-    // Setup analysis options file with ignore list.
-    newFile(
-        [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
-        r'''
-analyzer:
-  exclude:
-    - lib/nope.dart
-    - 'sdk_ext/**'
-''');
-    // Setup context.
-    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-    // Verify that analysis options was parsed and the ignore patterns applied.
-    Map<String, int> fileTimestamps =
-        callbacks.currentContextFilePaths[projPath];
-    expect(fileTimestamps, isNotEmpty);
-    List<String> files = fileTimestamps.keys.toList();
-    expect(
-        files,
-        unorderedEquals(
-            ['/my/proj/lib/main.dart', '/my/proj/.analysis_options']));
-  }
-
-  test_path_filter_child_contexts_option() async {
-    // Create files.
-    String libPath = newFolder([projPath, LIB_NAME]);
-    newFile([libPath, 'main.dart']);
-    newFile(
-        [libPath, 'pubspec.yaml'],
-        r'''
-name: foobar
-''');
-    String otherLibPath = newFolder([projPath, 'other_lib']);
-    newFile([otherLibPath, 'entry.dart']);
-    newFile(
-        [otherLibPath, 'pubspec.yaml'],
-        r'''
-name: other_lib
-''');
-    // Setup analysis options file with ignore list that ignores the 'other_lib'
-    // directory by name.
-    newFile(
-        [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
-        r'''
-analyzer:
-  exclude:
-    - 'other_lib'
-''');
-    // Setup context.
-    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-    // Verify that the context in other_lib wasn't created and that the
-    // context in lib was created.
-    var contexts =
-        manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
-    expect(contexts.length, 2);
-    expect(contexts[0].name, equals('/my/proj'));
-    expect(contexts[1].name, equals('/my/proj/lib'));
-  }
-
-  test_path_filter_recursive_wildcard_child_contexts_option() async {
-    // Create files.
-    String libPath = newFolder([projPath, LIB_NAME]);
-    newFile([libPath, 'main.dart']);
-    newFile(
-        [libPath, 'pubspec.yaml'],
-        r'''
-  name: foobar
-  ''');
-    String otherLibPath = newFolder([projPath, 'other_lib']);
-    newFile([otherLibPath, 'entry.dart']);
-    newFile(
-        [otherLibPath, 'pubspec.yaml'],
-        r'''
-  name: other_lib
-  ''');
-    // Setup analysis options file with ignore list that ignores 'other_lib'
-    // and all descendants.
-    newFile(
-        [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
-        r'''
-analyzer:
-  exclude:
-    - 'other_lib/**'
-  ''');
-    // Setup context.
-    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-    // Verify that the context in other_lib wasn't created and that the
-    // context in lib was created.
-    var contexts =
-        manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
-    expect(contexts.length, 2);
-    expect(contexts[0].name, equals('/my/proj'));
-    expect(contexts[1].name, equals('/my/proj/lib'));
-  }
-
-  test_path_filter_wildcard_child_contexts_option() async {
-    // Create files.
-    String libPath = newFolder([projPath, LIB_NAME]);
-    newFile([libPath, 'main.dart']);
-    newFile(
-        [libPath, 'pubspec.yaml'],
-        r'''
-name: foobar
-''');
-    String otherLibPath = newFolder([projPath, 'other_lib']);
-    newFile([otherLibPath, 'entry.dart']);
-    newFile(
-        [otherLibPath, 'pubspec.yaml'],
-        r'''
-name: other_lib
-''');
-    // Setup analysis options file with ignore list that ignores 'other_lib'
-    // and all immediate children.
-    newFile(
-        [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
-        r'''
-analyzer:
-  exclude:
-    - 'other_lib/*'
-''');
-    // Setup context.
-    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-    // Verify that the context in other_lib wasn't created and that the
-    // context in lib was created.
-    var contexts =
-        manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
-    expect(contexts.length, 2);
-    expect(contexts[0].name, equals('/my/proj'));
-    expect(contexts[1].name, equals('/my/proj/lib'));
-  }
-
   test_refresh_folder_with_packagespec() {
     // create a context with a .packages file
     String packagespecFile = posix.join(projPath, '.packages');
@@ -1129,7 +361,7 @@
 
   test_sdk_ext_packagespec() async {
     // Create files.
-    String libPath = newFolder([projPath, LIB_NAME]);
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
     newFile([libPath, 'main.dart']);
     newFile([libPath, 'nope.dart']);
     String sdkExtPath = newFolder([projPath, 'sdk_ext']);
@@ -1199,8 +431,8 @@
   }
 
   void test_setRoots_addFolderWithNestedPackageSpec() {
-    String examplePath = newFolder([projPath, EXAMPLE_NAME]);
-    String libPath = newFolder([projPath, LIB_NAME]);
+    String examplePath = newFolder([projPath, ContextManagerTest.EXAMPLE_NAME]);
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
 
     newFile([projPath, ContextManagerImpl.PACKAGE_SPEC_NAME]);
     newFile([libPath, 'main.dart']);
@@ -1228,8 +460,8 @@
   }
 
   void test_setRoots_addFolderWithNestedPubspec() {
-    String examplePath = newFolder([projPath, EXAMPLE_NAME]);
-    String libPath = newFolder([projPath, LIB_NAME]);
+    String examplePath = newFolder([projPath, ContextManagerTest.EXAMPLE_NAME]);
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
 
     newFile([projPath, ContextManagerImpl.PUBSPEC_NAME]);
     newFile([libPath, 'main.dart']);
@@ -1269,7 +501,7 @@
     String packagespecPath = posix.join(projPath, '.packages');
     resourceProvider.newFile(packagespecPath,
         'unittest:file:///home/somebody/.pub/cache/unittest-0.9.9/lib/');
-    String libPath = newFolder([projPath, LIB_NAME]);
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
     File mainFile =
         resourceProvider.newFile(posix.join(libPath, 'main.dart'), '');
     Source source = mainFile.createSource();
@@ -1324,10 +556,10 @@
   }
 
   void test_setRoots_addFolderWithPubspecAndLib() {
-    String binPath = newFolder([projPath, BIN_NAME]);
-    String libPath = newFolder([projPath, LIB_NAME]);
-    String srcPath = newFolder([libPath, SRC_NAME]);
-    String testPath = newFolder([projPath, TEST_NAME]);
+    String binPath = newFolder([projPath, ContextManagerTest.BIN_NAME]);
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+    String srcPath = newFolder([libPath, ContextManagerTest.SRC_NAME]);
+    String testPath = newFolder([projPath, ContextManagerTest.TEST_NAME]);
 
     newFile([projPath, ContextManagerImpl.PUBSPEC_NAME]);
     String appPath = newFile([binPath, 'app.dart']);
@@ -1584,77 +816,6 @@
     callbacks.assertContextFiles(project, [fileA, fileB]);
   }
 
-  void test_setRoots_nested_excludedByOuter() {
-    String project = '/project';
-    String projectPubspec = '$project/pubspec.yaml';
-    String example = '$project/example';
-    String examplePubspec = '$example/pubspec.yaml';
-    // create files
-    resourceProvider.newFile(projectPubspec, 'name: project');
-    resourceProvider.newFile(examplePubspec, 'name: example');
-    newFile(
-        [project, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
-        r'''
-analyzer:
-  exclude:
-    - 'example'
-''');
-    manager
-        .setRoots(<String>[project, example], <String>[], <String, String>{});
-    // verify
-    {
-      ContextInfo rootInfo = manager.rootInfo;
-      expect(rootInfo.children, hasLength(1));
-      {
-        ContextInfo projectInfo = rootInfo.children[0];
-        expect(projectInfo.folder.path, project);
-        expect(projectInfo.children, hasLength(1));
-        {
-          ContextInfo exampleInfo = projectInfo.children[0];
-          expect(exampleInfo.folder.path, example);
-          expect(exampleInfo.children, isEmpty);
-        }
-      }
-    }
-    expect(callbacks.currentContextPaths, hasLength(2));
-    expect(callbacks.currentContextPaths, unorderedEquals([project, example]));
-  }
-
-  void test_setRoots_nested_excludedByOuter_deep() {
-    String a = '/a';
-    String c = '$a/b/c';
-    String aPubspec = '$a/pubspec.yaml';
-    String cPubspec = '$c/pubspec.yaml';
-    // create files
-    resourceProvider.newFile(aPubspec, 'name: aaa');
-    resourceProvider.newFile(cPubspec, 'name: ccc');
-    newFile(
-        [a, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
-        r'''
-analyzer:
-  exclude:
-    - 'b**'
-''');
-    manager.setRoots(<String>[a, c], <String>[], <String, String>{});
-    // verify
-    {
-      ContextInfo rootInfo = manager.rootInfo;
-      expect(rootInfo.children, hasLength(1));
-      {
-        ContextInfo aInfo = rootInfo.children[0];
-        expect(aInfo.folder.path, a);
-        expect(aInfo.children, hasLength(1));
-        {
-          ContextInfo cInfo = aInfo.children[0];
-          expect(cInfo.folder.path, c);
-          expect(cInfo.children, isEmpty);
-        }
-      }
-    }
-    expect(callbacks.currentContextPaths, hasLength(2));
-    expect(callbacks.currentContextPaths, unorderedEquals([a, c]));
-  }
-
   void test_setRoots_nested_includedByOuter_innerFirst() {
     String project = '/project';
     String projectPubspec = '$project/pubspec.yaml';
@@ -1953,25 +1114,6 @@
     callbacks.assertContextFiles(project, [fileA]);
   }
 
-  test_strong_mode_analysis_option() async {
-    // Create files.
-    newFile(
-        [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
-        r'''
-analyzer:
-  strong-mode: true
-''');
-    String libPath = newFolder([projPath, LIB_NAME]);
-    newFile([libPath, 'main.dart']);
-    // Setup context.
-    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-    // Verify that analysis options was parsed and strong-mode set.
-    Map<String, int> fileTimestamps =
-        callbacks.currentContextFilePaths[projPath];
-    expect(fileTimestamps, isNotEmpty);
-    expect(callbacks.currentContext.analysisOptions.strongMode, true);
-  }
-
   test_watch_addDummyLink() {
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
     // empty folder initially
@@ -2560,6 +1702,902 @@
   }
 }
 
+abstract class ContextManagerTest {
+  /**
+   * The name of the 'bin' directory.
+   */
+  static const String BIN_NAME = 'bin';
+
+  /**
+   * The name of the 'example' directory.
+   */
+  static const String EXAMPLE_NAME = 'example';
+
+  /**
+   * The name of the 'lib' directory.
+   */
+  static const String LIB_NAME = 'lib';
+
+  /**
+   * The name of the 'src' directory.
+   */
+  static const String SRC_NAME = 'src';
+
+  /**
+   * The name of the 'test' directory.
+   */
+  static const String TEST_NAME = 'test';
+
+  ContextManagerImpl manager;
+
+  TestContextManagerCallbacks callbacks;
+
+  MemoryResourceProvider resourceProvider;
+
+  MockPackageMapProvider packageMapProvider;
+
+  UriResolver packageResolver = null;
+
+  UriResolver embeddedUriResolver = null;
+
+  String projPath = '/my/proj';
+
+  AnalysisError missing_required_param = new AnalysisError(
+      new TestSource(), 0, 1, HintCode.MISSING_REQUIRED_PARAM, [
+    ['x']
+  ]);
+
+  AnalysisError missing_return =
+      new AnalysisError(new TestSource(), 0, 1, HintCode.MISSING_RETURN, [
+    ['x']
+  ]);
+
+  AnalysisError invalid_assignment_error =
+      new AnalysisError(new TestSource(), 0, 1, HintCode.INVALID_ASSIGNMENT, [
+    ['x'],
+    ['y']
+  ]);
+
+  AnalysisError unused_local_variable = new AnalysisError(
+      new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [
+    ['x']
+  ]);
+
+  List<Glob> get analysisFilesGlobs {
+    List<String> patterns = <String>[
+      '**/*.${AnalysisEngine.SUFFIX_DART}',
+      '**/*.${AnalysisEngine.SUFFIX_HTML}',
+      '**/*.${AnalysisEngine.SUFFIX_HTM}',
+      '**/${AnalysisEngine.ANALYSIS_OPTIONS_FILE}',
+      '**/${AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE}'
+    ];
+    return patterns
+        .map((pattern) => new Glob(JavaFile.pathContext.separator, pattern))
+        .toList();
+  }
+
+  List<ErrorProcessor> get errorProcessors => callbacks.currentContext
+      .getConfigurationData(CONFIGURED_ERROR_PROCESSORS);
+
+  List<Linter> get lints => getLints(callbacks.currentContext);
+
+  AnalysisOptions get options => callbacks.currentContext.analysisOptions;
+
+  Map<String, List<Folder>> get _currentPackageMap => _packageMap(projPath);
+
+  void deleteFile(List<String> pathComponents) {
+    String filePath = posix.joinAll(pathComponents);
+    resourceProvider.deleteFile(filePath);
+  }
+
+  ErrorProcessor getProcessor(AnalysisError error) =>
+      ErrorProcessor.getProcessor(callbacks.currentContext, error);
+
+  String newFile(List<String> pathComponents, [String content = '']) {
+    String filePath = posix.joinAll(pathComponents);
+    resourceProvider.newFile(filePath, content);
+    return filePath;
+  }
+
+  String newFolder(List<String> pathComponents) {
+    String folderPath = posix.joinAll(pathComponents);
+    resourceProvider.newFolder(folderPath);
+    return folderPath;
+  }
+
+  void processRequiredPlugins() {
+    List<Plugin> plugins = <Plugin>[];
+    plugins.addAll(AnalysisEngine.instance.requiredPlugins);
+    plugins.add(AnalysisEngine.instance.commandLinePlugin);
+    plugins.add(AnalysisEngine.instance.optionsPlugin);
+    plugins.add(linterPlugin);
+    ExtensionManager manager = new ExtensionManager();
+    manager.processPlugins(plugins);
+  }
+
+  EmbedderUriResolver provideEmbeddedUriResolver(Folder folder) =>
+      embeddedUriResolver;
+
+  UriResolver providePackageResolver(Folder folder) => packageResolver;
+
+  void setUp() {
+    processRequiredPlugins();
+    resourceProvider = new MemoryResourceProvider();
+    packageMapProvider = new MockPackageMapProvider();
+    DartSdkManager sdkManager = new DartSdkManager((_) {
+      return new MockSdk();
+    });
+    manager = new ContextManagerImpl(
+        resourceProvider,
+        sdkManager,
+        providePackageResolver,
+        provideEmbeddedUriResolver,
+        packageMapProvider,
+        analysisFilesGlobs,
+        InstrumentationService.NULL_SERVICE,
+        new AnalysisOptionsImpl());
+    callbacks = new TestContextManagerCallbacks(resourceProvider);
+    manager.callbacks = callbacks;
+    resourceProvider.newFolder(projPath);
+  }
+
+  /**
+   * Verify that package URI's for source files in [path] will be resolved
+   * using a package root matching [expectation].
+   */
+  void _checkPackageRoot(String path, expectation) {
+    // TODO(brianwilkerson) Figure out how to test this. Possibly by comparing
+    // the contents of the package map (although that approach doesn't work at
+    // the moment).
+//    FolderDisposition disposition = callbacks.currentContextDispositions[path];
+//    expect(disposition.packageRoot, expectation);
+    // TODO(paulberry): we should also verify that the package map itself is
+    // correct.  See dartbug.com/23909.
+  }
+
+  Map<String, List<Folder>> _packageMap(String contextPath) {
+    Folder folder = resourceProvider.getFolder(contextPath);
+    return manager.folderMap[folder]?.sourceFactory?.packageMap;
+  }
+}
+
+@reflectiveTest
+class ContextManagerWithNewOptionsTest extends ContextManagerWithOptionsTest {
+  String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE;
+}
+
+@reflectiveTest
+class ContextManagerWithOldOptionsTest extends ContextManagerWithOptionsTest {
+  String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_FILE;
+}
+
+abstract class ContextManagerWithOptionsTest extends ContextManagerTest {
+  String get optionsFileName;
+
+  test_analysis_options_file_delete() async {
+    // Setup analysis options
+    newFile(
+        [projPath, optionsFileName],
+        r'''
+embedded_libs:
+  "dart:foobar": "../sdk_ext/entry.dart"
+analyzer:
+  language:
+    enableGenericMethods: true
+  errors:
+    unused_local_variable: false
+linter:
+  rules:
+    - camel_case_types
+''');
+
+    // Setup context.
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+    await pumpEventQueue();
+
+    // Verify options were set.
+    expect(errorProcessors, hasLength(1));
+    expect(lints, hasLength(1));
+    expect(options.enableGenericMethods, isTrue);
+
+    // Remove options.
+    deleteFile([projPath, optionsFileName]);
+    await pumpEventQueue();
+
+    // Verify defaults restored.
+    expect(errorProcessors, isEmpty);
+    expect(lints, isEmpty);
+    expect(options.enableGenericMethods, isFalse);
+  }
+
+  test_analysis_options_file_delete_with_embedder() async {
+    // Setup _embedder.yaml.
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+    newFile(
+        [libPath, '_embedder.yaml'],
+        r'''
+analyzer:
+  strong-mode: true
+  errors:
+    missing_return: false
+linter:
+  rules:
+    - avoid_as
+''');
+
+    // Setup .packages file
+    newFile(
+        [projPath, '.packages'],
+        r'''
+test_pack:lib/''');
+
+    // Setup analysis options
+    newFile(
+        [projPath, optionsFileName],
+        r'''
+analyzer:
+  language:
+    enableGenericMethods: true
+  errors:
+    unused_local_variable: false
+linter:
+  rules:
+    - camel_case_types
+''');
+
+    // Setup context.
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+    await pumpEventQueue();
+
+    // Verify options were set.
+    expect(options.enableGenericMethods, isTrue);
+    expect(options.strongMode, isTrue);
+    expect(errorProcessors, hasLength(2));
+    expect(lints, hasLength(2));
+
+    // Remove options.
+    deleteFile([projPath, optionsFileName]);
+    await pumpEventQueue();
+
+    // Verify defaults restored.
+    expect(options.enableGenericMethods, isFalse);
+    expect(lints, hasLength(1));
+    expect(lints.first, new isInstanceOf<AvoidAs>());
+    expect(errorProcessors, hasLength(1));
+    expect(getProcessor(missing_return).severity, isNull);
+  }
+
+  test_analysis_options_parse_failure() async {
+    // Create files.
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+    newFile([libPath, 'main.dart']);
+    String sdkExtPath = newFolder([projPath, 'sdk_ext']);
+    newFile([sdkExtPath, 'entry.dart']);
+    String sdkExtSrcPath = newFolder([projPath, 'sdk_ext', 'src']);
+    newFile([sdkExtSrcPath, 'part.dart']);
+    // Setup analysis options file with ignore list.
+    newFile(
+        [projPath, optionsFileName],
+        r'''
+;
+''');
+    // Setup context.
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+
+    // No error means success.
+  }
+
+  test_configed_options() async {
+    // Create files.
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+    newFile([projPath, 'test', 'test.dart']);
+    newFile(
+        [projPath, 'pubspec.yaml'],
+        r'''
+dependencies:
+  test_pack: any
+analyzer:
+  configuration: test_pack/config
+''');
+
+    // Setup .packages file
+    newFile(
+        [projPath, '.packages'],
+        r'''
+test_pack:lib/''');
+
+    // Setup config.yaml.
+    newFile(
+        [libPath, 'config', 'config.yaml'],
+        r'''
+analyzer:
+  strong-mode: true
+  language:
+    enableSuperMixins: true
+  errors:
+    missing_return: false
+linter:
+  rules:
+    - avoid_as
+''');
+
+    // Setup analysis options
+    newFile(
+        [projPath, optionsFileName],
+        r'''
+analyzer:
+  exclude:
+    - 'test/**'
+  language:
+    enableGenericMethods: true
+    enableAsync: false
+  errors:
+    unused_local_variable: false
+linter:
+  rules:
+    - camel_case_types
+''');
+
+    // Setup context.
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+    await pumpEventQueue();
+
+    // Confirm that one context was created.
+    var contexts =
+        manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
+    expect(contexts, isNotNull);
+    expect(contexts, hasLength(1));
+
+    var context = contexts.first;
+
+    // Verify options.
+    // * from `config.yaml`:
+    expect(context.analysisOptions.strongMode, isTrue);
+    expect(context.analysisOptions.enableSuperMixins, isTrue);
+    expect(context.analysisOptions.enableAsync, isFalse);
+    // * from analysis options:
+    expect(context.analysisOptions.enableGenericMethods, isTrue);
+
+    // * verify tests are excluded
+    expect(callbacks.currentContextFilePaths[projPath].keys,
+        unorderedEquals(['/my/proj/$optionsFileName']));
+
+    // Verify filter setup.
+    expect(errorProcessors, hasLength(2));
+
+    // * (config.)
+    expect(getProcessor(missing_return).severity, isNull);
+
+    // * (options.)
+    expect(getProcessor(unused_local_variable).severity, isNull);
+
+    // Verify lints.
+    var lintNames = lints.map((lint) => lint.name);
+    expect(
+        lintNames,
+        unorderedEquals(
+            ['avoid_as' /* config */, 'camel_case_types' /* options */]));
+  }
+
+  test_embedder_and_configed_options() async {
+    // Create files.
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+    String sdkExtPath = newFolder([projPath, 'sdk_ext']);
+    newFile([projPath, 'test', 'test.dart']);
+    newFile([sdkExtPath, 'entry.dart']);
+
+    // Setup pubspec with configuration.
+    newFile(
+        [projPath, 'pubspec.yaml'],
+        r'''
+dependencies:
+  test_pack: any
+analyzer:
+  configuration: test_pack/config
+''');
+
+    // Setup _embedder.yaml.
+    newFile(
+        [libPath, '_embedder.yaml'],
+        r'''
+embedded_libs:
+  "dart:foobar": "../sdk_ext/entry.dart"
+analyzer:
+  strong-mode: true
+  language:
+    enableSuperMixins: true
+  errors:
+    missing_return: false
+linter:
+  rules:
+    - avoid_as
+''');
+
+    // Setup .packages file
+    newFile(
+        [projPath, '.packages'],
+        r'''
+test_pack:lib/''');
+
+    // Setup analysis options
+    newFile(
+        [projPath, optionsFileName],
+        r'''
+analyzer:
+  exclude:
+    - 'test/**'
+  language:
+    enableGenericMethods: true
+    enableAsync: false
+  errors:
+    unused_local_variable: false
+linter:
+  rules:
+    - camel_case_types
+''');
+
+    // Setup config.yaml.
+    newFile(
+        [libPath, 'config', 'config.yaml'],
+        r'''
+analyzer:
+  errors:
+    missing_required_param: error
+linter:
+  rules:
+    - always_specify_types
+''');
+
+    // Setup context.
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+    await pumpEventQueue();
+
+    // Confirm that one context was created.
+    var contexts =
+        manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
+    expect(contexts, isNotNull);
+    expect(contexts, hasLength(1));
+    var context = contexts[0];
+
+    // Verify options.
+    // * from `_embedder.yaml`:
+    expect(context.analysisOptions.strongMode, isTrue);
+    expect(context.analysisOptions.enableSuperMixins, isTrue);
+    expect(context.analysisOptions.enableAsync, isFalse);
+    // * from analysis options:
+    expect(context.analysisOptions.enableGenericMethods, isTrue);
+
+    // * verify tests are excluded
+    expect(
+        callbacks.currentContextFilePaths[projPath].keys,
+        unorderedEquals(
+            ['/my/proj/sdk_ext/entry.dart', '/my/proj/$optionsFileName']));
+
+    // Verify filter setup.
+    expect(errorProcessors, hasLength(3));
+
+    // * (embedder.)
+    expect(getProcessor(missing_return).severity, isNull);
+
+    // * (config.)
+    expect(getProcessor(missing_required_param).severity, ErrorSeverity.ERROR);
+
+    // * (options.)
+    expect(getProcessor(unused_local_variable).severity, isNull);
+
+    // Verify lints.
+    var lintNames = lints.map((lint) => lint.name);
+
+    expect(
+        lintNames,
+        unorderedEquals([
+          'avoid_as' /* embedder */,
+          'always_specify_types' /* config*/,
+          'camel_case_types' /* options */
+        ]));
+
+    // Sanity check embedder libs.
+    var source = context.sourceFactory.forUri('dart:foobar');
+    expect(source, isNotNull);
+    expect(source.fullName,
+        '/my/proj/sdk_ext/entry.dart'.replaceAll('/', JavaFile.separator));
+  }
+
+  test_embedder_options() async {
+    // Create files.
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+    String sdkExtPath = newFolder([projPath, 'sdk_ext']);
+    newFile([projPath, 'test', 'test.dart']);
+    newFile([sdkExtPath, 'entry.dart']);
+    // Setup _embedder.yaml.
+    newFile(
+        [libPath, '_embedder.yaml'],
+        r'''
+embedded_libs:
+  "dart:foobar": "../sdk_ext/entry.dart"
+analyzer:
+  strong-mode: true
+  language:
+    enableSuperMixins: true
+  errors:
+    missing_return: false
+linter:
+  rules:
+    - avoid_as
+''');
+    // Setup .packages file
+    newFile(
+        [projPath, '.packages'],
+        r'''
+test_pack:lib/''');
+
+    // Setup analysis options
+    newFile(
+        [projPath, optionsFileName],
+        r'''
+analyzer:
+  exclude:
+    - 'test/**'
+  language:
+    enableGenericMethods: true
+    enableAsync: false
+  errors:
+    unused_local_variable: false
+linter:
+  rules:
+    - camel_case_types
+''');
+
+    // Setup context.
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+    await pumpEventQueue();
+
+    // Confirm that one context was created.
+    var contexts =
+        manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
+    expect(contexts, isNotNull);
+    expect(contexts, hasLength(1));
+    var context = contexts[0];
+
+    // Verify options.
+    // * from `_embedder.yaml`:
+    expect(context.analysisOptions.strongMode, isTrue);
+    expect(context.analysisOptions.enableSuperMixins, isTrue);
+    expect(context.analysisOptions.enableAsync, isFalse);
+    // * from analysis options:
+    expect(context.analysisOptions.enableGenericMethods, isTrue);
+
+    // * verify tests are excluded
+    expect(
+        callbacks.currentContextFilePaths[projPath].keys,
+        unorderedEquals(
+            ['/my/proj/sdk_ext/entry.dart', '/my/proj/$optionsFileName']));
+
+    // Verify filter setup.
+    expect(errorProcessors, hasLength(2));
+
+    // * (embedder.)
+    expect(getProcessor(missing_return).severity, isNull);
+
+    // * (options.)
+    expect(getProcessor(unused_local_variable).severity, isNull);
+
+    // Verify lints.
+    var lintNames = lints.map((lint) => lint.name);
+
+    expect(
+        lintNames,
+        unorderedEquals(
+            ['avoid_as' /* embedder */, 'camel_case_types' /* options */]));
+
+    // Sanity check embedder libs.
+    var source = context.sourceFactory.forUri('dart:foobar');
+    expect(source, isNotNull);
+    expect(source.fullName,
+        '/my/proj/sdk_ext/entry.dart'.replaceAll('/', JavaFile.separator));
+  }
+
+  test_error_filter_analysis_option() async {
+    // Create files.
+    newFile(
+        [projPath, optionsFileName],
+        r'''
+analyzer:
+  errors:
+    unused_local_variable: ignore
+''');
+    // Setup context.
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+
+    // Verify filter setup.
+    expect(errorProcessors, hasLength(1));
+    expect(getProcessor(unused_local_variable).severity, isNull);
+  }
+
+  test_error_filter_analysis_option_multiple_filters() async {
+    // Create files.
+    newFile(
+        [projPath, optionsFileName],
+        r'''
+analyzer:
+  errors:
+    invalid_assignment: ignore
+    unused_local_variable: error
+''');
+    // Setup context.
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+
+    // Verify filter setup.
+    expect(errorProcessors, hasLength(2));
+
+    expect(getProcessor(invalid_assignment_error).severity, isNull);
+    expect(getProcessor(unused_local_variable).severity, ErrorSeverity.ERROR);
+  }
+
+  test_error_filter_analysis_option_synonyms() async {
+    // Create files.
+    newFile(
+        [projPath, optionsFileName],
+        r'''
+analyzer:
+  errors:
+    unused_local_variable: ignore
+    ambiguous_import: false
+''');
+    // Setup context.
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+
+    // Verify filter setup.
+    expect(errorProcessors, isNotNull);
+    expect(errorProcessors, hasLength(2));
+  }
+
+  test_error_filter_analysis_option_unpsecified() async {
+    // Create files.
+    newFile(
+        [projPath, optionsFileName],
+        r'''
+analyzer:
+#  errors:
+#    unused_local_variable: ignore
+''');
+    // Setup context.
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+
+    // Verify filter setup.
+    expect(errorProcessors, isEmpty);
+  }
+
+  test_path_filter_analysis_option() async {
+    // Create files.
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+    newFile([libPath, 'main.dart']);
+    newFile([libPath, 'nope.dart']);
+    String sdkExtPath = newFolder([projPath, 'sdk_ext']);
+    newFile([sdkExtPath, 'entry.dart']);
+    String sdkExtSrcPath = newFolder([projPath, 'sdk_ext', 'src']);
+    newFile([sdkExtSrcPath, 'part.dart']);
+    // Setup analysis options file with ignore list.
+    newFile(
+        [projPath, optionsFileName],
+        r'''
+analyzer:
+  exclude:
+    - lib/nope.dart
+    - 'sdk_ext/**'
+''');
+    // Setup context.
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+    // Verify that analysis options was parsed and the ignore patterns applied.
+    Map<String, int> fileTimestamps =
+        callbacks.currentContextFilePaths[projPath];
+    expect(fileTimestamps, isNotEmpty);
+    List<String> files = fileTimestamps.keys.toList();
+    expect(
+        files,
+        unorderedEquals(
+            ['/my/proj/lib/main.dart', '/my/proj/$optionsFileName']));
+  }
+
+  test_path_filter_child_contexts_option() async {
+    // Create files.
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+    newFile([libPath, 'main.dart']);
+    newFile(
+        [libPath, 'pubspec.yaml'],
+        r'''
+name: foobar
+''');
+    String otherLibPath = newFolder([projPath, 'other_lib']);
+    newFile([otherLibPath, 'entry.dart']);
+    newFile(
+        [otherLibPath, 'pubspec.yaml'],
+        r'''
+name: other_lib
+''');
+    // Setup analysis options file with ignore list that ignores the 'other_lib'
+    // directory by name.
+    newFile(
+        [projPath, optionsFileName],
+        r'''
+analyzer:
+  exclude:
+    - 'other_lib'
+''');
+    // Setup context.
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+    // Verify that the context in other_lib wasn't created and that the
+    // context in lib was created.
+    var contexts =
+        manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
+    expect(contexts.length, 2);
+    expect(contexts[0].name, equals('/my/proj'));
+    expect(contexts[1].name, equals('/my/proj/lib'));
+  }
+
+  test_path_filter_recursive_wildcard_child_contexts_option() async {
+    // Create files.
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+    newFile([libPath, 'main.dart']);
+    newFile(
+        [libPath, 'pubspec.yaml'],
+        r'''
+  name: foobar
+  ''');
+    String otherLibPath = newFolder([projPath, 'other_lib']);
+    newFile([otherLibPath, 'entry.dart']);
+    newFile(
+        [otherLibPath, 'pubspec.yaml'],
+        r'''
+  name: other_lib
+  ''');
+    // Setup analysis options file with ignore list that ignores 'other_lib'
+    // and all descendants.
+    newFile(
+        [projPath, optionsFileName],
+        r'''
+analyzer:
+  exclude:
+    - 'other_lib/**'
+  ''');
+    // Setup context.
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+    // Verify that the context in other_lib wasn't created and that the
+    // context in lib was created.
+    var contexts =
+        manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
+    expect(contexts.length, 2);
+    expect(contexts[0].name, equals('/my/proj'));
+    expect(contexts[1].name, equals('/my/proj/lib'));
+  }
+
+  test_path_filter_wildcard_child_contexts_option() async {
+    // Create files.
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+    newFile([libPath, 'main.dart']);
+    newFile(
+        [libPath, 'pubspec.yaml'],
+        r'''
+name: foobar
+''');
+    String otherLibPath = newFolder([projPath, 'other_lib']);
+    newFile([otherLibPath, 'entry.dart']);
+    newFile(
+        [otherLibPath, 'pubspec.yaml'],
+        r'''
+name: other_lib
+''');
+    // Setup analysis options file with ignore list that ignores 'other_lib'
+    // and all immediate children.
+    newFile(
+        [projPath, optionsFileName],
+        r'''
+analyzer:
+  exclude:
+    - 'other_lib/*'
+''');
+    // Setup context.
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+    // Verify that the context in other_lib wasn't created and that the
+    // context in lib was created.
+    var contexts =
+        manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
+    expect(contexts.length, 2);
+    expect(contexts[0].name, equals('/my/proj'));
+    expect(contexts[1].name, equals('/my/proj/lib'));
+  }
+
+  void test_setRoots_nested_excludedByOuter() {
+    String project = '/project';
+    String projectPubspec = '$project/pubspec.yaml';
+    String example = '$project/example';
+    String examplePubspec = '$example/pubspec.yaml';
+    // create files
+    resourceProvider.newFile(projectPubspec, 'name: project');
+    resourceProvider.newFile(examplePubspec, 'name: example');
+    newFile(
+        [project, optionsFileName],
+        r'''
+analyzer:
+  exclude:
+    - 'example'
+''');
+    manager
+        .setRoots(<String>[project, example], <String>[], <String, String>{});
+    // verify
+    {
+      ContextInfo rootInfo = manager.rootInfo;
+      expect(rootInfo.children, hasLength(1));
+      {
+        ContextInfo projectInfo = rootInfo.children[0];
+        expect(projectInfo.folder.path, project);
+        expect(projectInfo.children, hasLength(1));
+        {
+          ContextInfo exampleInfo = projectInfo.children[0];
+          expect(exampleInfo.folder.path, example);
+          expect(exampleInfo.children, isEmpty);
+        }
+      }
+    }
+    expect(callbacks.currentContextPaths, hasLength(2));
+    expect(callbacks.currentContextPaths, unorderedEquals([project, example]));
+  }
+
+  void test_setRoots_nested_excludedByOuter_deep() {
+    String a = '/a';
+    String c = '$a/b/c';
+    String aPubspec = '$a/pubspec.yaml';
+    String cPubspec = '$c/pubspec.yaml';
+    // create files
+    resourceProvider.newFile(aPubspec, 'name: aaa');
+    resourceProvider.newFile(cPubspec, 'name: ccc');
+    newFile(
+        [a, optionsFileName],
+        r'''
+analyzer:
+  exclude:
+    - 'b**'
+''');
+    manager.setRoots(<String>[a, c], <String>[], <String, String>{});
+    // verify
+    {
+      ContextInfo rootInfo = manager.rootInfo;
+      expect(rootInfo.children, hasLength(1));
+      {
+        ContextInfo aInfo = rootInfo.children[0];
+        expect(aInfo.folder.path, a);
+        expect(aInfo.children, hasLength(1));
+        {
+          ContextInfo cInfo = aInfo.children[0];
+          expect(cInfo.folder.path, c);
+          expect(cInfo.children, isEmpty);
+        }
+      }
+    }
+    expect(callbacks.currentContextPaths, hasLength(2));
+    expect(callbacks.currentContextPaths, unorderedEquals([a, c]));
+  }
+
+  test_strong_mode_analysis_option() async {
+    // Create files.
+    newFile(
+        [projPath, optionsFileName],
+        r'''
+analyzer:
+  strong-mode: true
+''');
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+    newFile([libPath, 'main.dart']);
+    // Setup context.
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+    // Verify that analysis options was parsed and strong-mode set.
+    Map<String, int> fileTimestamps =
+        callbacks.currentContextFilePaths[projPath];
+    expect(fileTimestamps, isNotEmpty);
+    expect(callbacks.currentContext.analysisOptions.strongMode, true);
+  }
+}
+
 class TestContextManagerCallbacks extends ContextManagerCallbacks {
   /**
    * Source of timestamps stored in [currentContextFilePaths].
diff --git a/pkg/analysis_server/test/integration/analysis/analysis_options_test.dart b/pkg/analysis_server/test/integration/analysis/analysis_options_test.dart
index 33ad500..4c55f82 100644
--- a/pkg/analysis_server/test/integration/analysis/analysis_options_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/analysis_options_test.dart
@@ -2,9 +2,10 @@
 // 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 test.integration.analysis.analysis_options;
+library test.integration.analysis.analysis_options_test;
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 import 'package:unittest/unittest.dart';
 
@@ -18,8 +19,35 @@
 
 @reflectiveTest
 class OptionsIntegrationTest extends AbstractAnalysisServerIntegrationTest {
-  test_option_warning() async {
-    String options = sourcePath('.analysis_options');
+  test_option_warning_newOptionFile() async {
+    String options = sourcePath(AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
+    writeFile(
+        options,
+        '''
+linter:
+  rules:
+    - camel_case_typo # :)
+''');
+
+    standardAnalysisSetup();
+
+    await analysisFinished;
+
+    expect(currentAnalysisErrors[options], isList);
+    List<AnalysisError> errors = currentAnalysisErrors[options];
+    expect(errors, hasLength(1));
+    AnalysisError error = errors[0];
+    expect(error.location.file, options);
+    expect(error.severity, AnalysisErrorSeverity.WARNING);
+    expect(error.type, AnalysisErrorType.STATIC_WARNING);
+    expect(error.location.offset, 23);
+    expect(error.location.length, 'camel_case_typo'.length);
+    expect(error.location.startLine, 3);
+    expect(error.location.startColumn, 7);
+  }
+
+  test_option_warning_oldOptionFile() async {
+    String options = sourcePath(AnalysisEngine.ANALYSIS_OPTIONS_FILE);
     writeFile(
         options,
         '''
diff --git a/pkg/analysis_server/test/integration/analysis/lint_test.dart b/pkg/analysis_server/test/integration/analysis/lint_test.dart
index e75120c..a1cfeb6 100644
--- a/pkg/analysis_server/test/integration/analysis/lint_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/lint_test.dart
@@ -5,6 +5,7 @@
 library test.integration.analysis.lint;
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 import 'package:unittest/unittest.dart';
 
@@ -29,14 +30,43 @@
 
     await analysisFinished;
     expect(currentAnalysisErrors[source], isList);
-    // Should be empty without .analysis_options.
+    // Should be empty without an analysis options file.
     List<AnalysisError> errors = currentAnalysisErrors[source];
     expect(errors, hasLength(0));
   }
 
-  test_simple_lint() async {
+  test_simple_lint_newOptionsFile() async {
     writeFile(
-        sourcePath('.analysis_options'),
+        sourcePath(AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE),
+        '''
+linter:
+  rules:
+    - camel_case_types
+''');
+
+    String source = sourcePath('test.dart');
+    writeFile(
+        source,
+        '''
+class a { // lint: not CamelCase
+}''');
+
+    standardAnalysisSetup();
+
+    await analysisFinished;
+
+    expect(currentAnalysisErrors[source], isList);
+    List<AnalysisError> errors = currentAnalysisErrors[source];
+    expect(errors, hasLength(1));
+    AnalysisError error = errors[0];
+    expect(error.location.file, source);
+    expect(error.severity, AnalysisErrorSeverity.INFO);
+    expect(error.type, AnalysisErrorType.LINT);
+  }
+
+  test_simple_lint_oldOptionsFile() async {
+    writeFile(
+        sourcePath(AnalysisEngine.ANALYSIS_OPTIONS_FILE),
         '''
 linter:
   rules:
diff --git a/pkg/analysis_server/test/mocks.dart b/pkg/analysis_server/test/mocks.dart
index 2dddbf9..04d3d0e 100644
--- a/pkg/analysis_server/test/mocks.dart
+++ b/pkg/analysis_server/test/mocks.dart
@@ -24,7 +24,7 @@
 import 'package:unittest/unittest.dart';
 
 /**
- * Answer the absolute path the the SDK relative to the currently running
+ * Answer the absolute path the SDK relative to the currently running
  * script or throw an exception if it cannot be found.
  */
 String get sdkPath {
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
index 08c83de..0bf8a6d 100644
--- a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
+++ b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
@@ -216,9 +216,10 @@
   }
 
   CompletionSuggestion assertSuggestEnumConst(String completion,
-      {bool isDeprecated: false}) {
+      {int relevance: DART_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
     CompletionSuggestion suggestion =
-        assertSuggest(completion, isDeprecated: isDeprecated);
+        assertSuggest(completion, relevance: relevance, isDeprecated: isDeprecated);
+    expect(suggestion.completion, completion);
     expect(suggestion.isDeprecated, isDeprecated);
     expect(suggestion.element.kind, protocol.ElementKind.ENUM_CONSTANT);
     return suggestion;
diff --git a/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
index a52a862..e51ed5f 100644
--- a/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
@@ -870,6 +870,34 @@
         pseudoKeywords: ['await', 'yield', 'yield*']);
   }
 
+  test_if_after_else() async {
+    addTestSource('main() { if (true) {} else ^ }');
+    await computeSuggestions();
+    assertSuggestKeywords(STMT_START_OUTSIDE_CLASS,
+        relevance: DART_RELEVANCE_KEYWORD);
+  }
+
+  test_if_afterThen_nextCloseCurlyBrace0() async {
+    addTestSource('main() { if (true) {} ^ }');
+    await computeSuggestions();
+    assertSuggestKeywords(STMT_START_OUTSIDE_CLASS.toList()..add(Keyword.ELSE),
+        relevance: DART_RELEVANCE_KEYWORD);
+  }
+
+  test_if_afterThen_nextCloseCurlyBrace1() async {
+    addTestSource('main() { if (true) {} e^ }');
+    await computeSuggestions();
+    assertSuggestKeywords(STMT_START_OUTSIDE_CLASS.toList()..add(Keyword.ELSE),
+        relevance: DART_RELEVANCE_KEYWORD);
+  }
+
+  test_if_afterThen_nextStatement0() async {
+    addTestSource('main() { if (true) {} ^ print(0); }');
+    await computeSuggestions();
+    assertSuggestKeywords(STMT_START_OUTSIDE_CLASS.toList()..add(Keyword.ELSE),
+        relevance: DART_RELEVANCE_KEYWORD);
+  }
+
   test_if_condition_isKeyword() async {
     addTestSource('main() { if (v i^) {} }');
     await computeSuggestions();
diff --git a/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
index ef90952..5740cad 100644
--- a/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
@@ -355,21 +355,19 @@
     expect(replacementLength, 0);
     assertSuggestTopLevelVar('a', 'A',
         relevance:
-        DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE + DART_RELEVANCE_INCREMENT);
+            DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE + DART_RELEVANCE_INCREMENT);
     assertSuggestTopLevelVar('b', 'B',
         relevance:
-        DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE + DART_RELEVANCE_INCREMENT);
+            DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE + DART_RELEVANCE_INCREMENT);
     assertSuggestTopLevelVar('c', 'C',
         relevance:
-        DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE + DART_RELEVANCE_INCREMENT);
+            DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE + DART_RELEVANCE_INCREMENT);
     assertSuggestTopLevelVar('d', 'D',
         relevance: DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE);
     assertSuggestTopLevelVar('e', 'E',
         relevance: DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE);
   }
 
-
-
   test_AsExpression_type() async {
     // SimpleIdentifier  TypeName  AsExpression
     addTestSource('''
@@ -1929,6 +1927,8 @@
     addTestSource('enum E { one, two } main() {^}');
     await computeSuggestions();
     assertSuggestEnum('E');
+    assertSuggestEnumConst('E.one');
+    assertSuggestEnumConst('E.two');
     assertNotSuggested('one');
     assertNotSuggested('two');
   }
@@ -1937,10 +1937,38 @@
     addTestSource('@deprecated enum E { one, two } main() {^}');
     await computeSuggestions();
     assertSuggestEnum('E', isDeprecated: true);
+    assertSuggestEnumConst('E.one', isDeprecated: true);
+    assertSuggestEnumConst('E.two', isDeprecated: true);
     assertNotSuggested('one');
     assertNotSuggested('two');
   }
 
+  test_enum_filter() async {
+    // SimpleIdentifier  NamedExpression  ArgumentList
+    // InstanceCreationExpression
+    addTestSource('''
+        enum E { one, two }
+        enum F { three, four }
+        class A {}
+        class B {
+          B({E someE});
+        }
+        A a = new A();
+        B b = new B(someE: ^);
+  ''');
+    await computeSuggestions();
+
+    expect(replacementOffset, completionOffset);
+    expect(replacementLength, 0);
+    assertSuggestEnumConst('E.one',
+        relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_INCREMENT);
+    assertSuggestEnumConst('E.two',
+        relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_INCREMENT);
+    assertNotSuggested('a');
+    assertNotSuggested('F.three');
+    assertNotSuggested('F.four');
+  }
+
   test_ExpressionStatement_identifier() async {
     // SimpleIdentifier  ExpressionStatement  Block
     addSource(
diff --git a/pkg/analysis_server/test/services/correction/fix_test.dart b/pkg/analysis_server/test/services/correction/fix_test.dart
index d793539..4ec437f 100644
--- a/pkg/analysis_server/test/services/correction/fix_test.dart
+++ b/pkg/analysis_server/test/services/correction/fix_test.dart
@@ -2254,6 +2254,22 @@
 ''');
   }
 
+  test_createMissingMethodCall() async {
+    resolveTestUnit('''
+class C implements Function {
+}
+''');
+    await assertHasFix(
+        DartFixKind.CREATE_MISSING_METHOD_CALL,
+        '''
+class C implements Function {
+  call() {
+    // TODO: implement call
+  }
+}
+''');
+  }
+
   test_createMissingOverrides_field_untyped() async {
     resolveTestUnit('''
 class A {
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index d7e871c..3e049b7 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.27.4
+
+* Added support for 'analysis_options.yaml' files as an alternative to '.analysis_options' files.
+
 ## 0.27.1
 * Moved the public and private API's for the element model into their proper places.
 * Added back support for auto-processing of plugins.
diff --git a/pkg/analyzer/README.md b/pkg/analyzer/README.md
index 18dd9b2..6915a58 100644
--- a/pkg/analyzer/README.md
+++ b/pkg/analyzer/README.md
@@ -15,22 +15,19 @@
 
 ## Configuring the analyzer
 
-Both `dartanalyzer` and Dart Analysis Server can be configured
-with a `.analysis_options` file. This YAML file can control which files
-and paths are analyzed, which lints are applied, and more.
+Both `dartanalyzer` and Dart Analysis Server can be configured with either an
+`analysis_options.yaml` or `.analysis_options` file. This YAML file can control
+which files and paths are analyzed, which lints are applied, and more.
 
-If you are embedding the analyzer library in your project, you are
-responsible for finding the `.analysis_options` file, parsing it,
-and configuring the analyzer.
+If you are embedding the analyzer library in your project, you are responsible
+for finding the analysis options file, parsing it, and configuring the analyzer.
 
-The `.analysis_options` file should live
-at the root of your project (for example, next to your `pubspec.yaml`).
-Different embedders of analyzer, such as `dartanalyzer` or Dart Analysis Server,
-may choose to find the file in various different ways. Consult their
-documentation to learn more.
+The analysis options file should live at the root of your project (for example,
+next to your `pubspec.yaml`). Different embedders of analyzer, such as
+`dartanalyzer` or Dart Analysis Server, may choose to find the file in various
+different ways. Consult their documentation to learn more.
 
-Here is an example file that instructs the analyzer
-to ignore two files:
+Here is an example file that instructs the analyzer to ignore two files:
 
 ```yaml
 analyzer:
diff --git a/pkg/analyzer/doc/tasks.html b/pkg/analyzer/doc/tasks.html
index 4fdabc9..b8b2e568 100644
--- a/pkg/analyzer/doc/tasks.html
+++ b/pkg/analyzer/doc/tasks.html
@@ -44,6 +44,7 @@
   CONSTANT_EXPRESSION_RESOLVED [shape=box]
   CONSTANT_VALUE -> ComputeConstantValueTask
   CONSTANT_VALUE -> EvaluateUnitConstantsTask
+  CONSTANT_VALUE -> VerifyUnitTask
   CONSTANT_VALUE [shape=box]
   CONTAINING_LIBRARIES -> DartErrorsTask
   CONTAINING_LIBRARIES [shape=box]
@@ -78,6 +79,8 @@
   ComputeLibraryCycleTask -> LIBRARY_CYCLE_DEPENDENCIES
   ComputeLibraryCycleTask -> LIBRARY_CYCLE_UNITS
   ComputePropagableVariableDependenciesTask -> PROPAGABLE_VARIABLE_DEPENDENCIES
+  ComputeRequiredConstantsTask -> PENDING_ERRORS
+  ComputeRequiredConstantsTask -> REQUIRED_CONSTANTS
   ContainingLibrariesTask -> CONTAINING_LIBRARIES
   DART_ERRORS -> LibraryErrorsReadyTask
   DART_ERRORS [shape=box]
@@ -195,6 +198,8 @@
   PARSED_UNIT [shape=box]
   PARSE_ERRORS -> dartErrorsForSource
   PARSE_ERRORS [shape=box]
+  PENDING_ERRORS -> VerifyUnitTask
+  PENDING_ERRORS [shape=box]
   PROPAGABLE_VARIABLES_IN_UNIT -> PropagateVariableTypesInUnitTask
   PROPAGABLE_VARIABLES_IN_UNIT [shape=box]
   PROPAGABLE_VARIABLE_DEPENDENCIES -> PropagateVariableTypeTask
@@ -237,6 +242,9 @@
   REFERENCED_SOURCES -> BuildDirectiveElementsTask
   REFERENCED_SOURCES -> VerifyUnitTask
   REFERENCED_SOURCES [shape=box]
+  REQUIRED_CONSTANTS -> VerifyUnitTask
+  REQUIRED_CONSTANTS [shape=box]
+  RESOLVED_UNIT -> ComputeRequiredConstantsTask
   RESOLVED_UNIT -> GenerateHintsTask
   RESOLVED_UNIT -> GenerateLintsTask
   RESOLVED_UNIT -> ReadyResolvedUnitTask
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index c33b26d..7b645cc 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -598,13 +598,14 @@
    * returns `true`, or `null` if there is no such ancestor. Note that this node
    * will never be returned.
    */
-  AstNode getAncestor(Predicate<AstNode> predicate);
+  AstNode/*=E*/ getAncestor/*<E extends AstNode>*/(
+      Predicate<AstNode> predicate);
 
   /**
    * Return the value of the property with the given [name], or `null` if this
    * node does not have a property with the given name.
    */
-  Object getProperty(String name);
+  Object/*=E*/ getProperty/*<E>*/(String name);
 
   /**
    * Set the value of the property with the given [name] to the given [value].
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index 1a73457..e7091ab 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -757,7 +757,8 @@
    * [predicate] returns `true`, or `null` if there is no such ancestor. Note
    * that this element will never be returned.
    */
-  Element getAncestor(Predicate<Element> predicate);
+  Element/*=E*/ getAncestor/*<E extends Element >*/(
+      Predicate<Element> predicate);
 
   /**
    * Return a display name for the given element that includes the path to the
@@ -852,6 +853,13 @@
    * required.
    */
   bool get isRequired;
+
+  /**
+   * Return a representation of the value of this annotation, forcing the value
+   * to be computed if it had not previously been computed, or `null` if the
+   * value of this annotation could not be computed because of errors.
+   */
+  DartObject computeConstantValue();
 }
 
 /**
@@ -2001,4 +2009,12 @@
    * 'var').
    */
   DartType get type;
+
+  /**
+   * Return a representation of the value of this variable, forcing the value
+   * to be computed if it had not previously been computed, or `null` if either
+   * this variable was not declared with the 'const' modifier or if the value of
+   * this variable could not be computed because of errors.
+   */
+  DartObject computeConstantValue();
 }
diff --git a/pkg/analyzer/lib/source/analysis_options_provider.dart b/pkg/analyzer/lib/source/analysis_options_provider.dart
index 3b6e330..2acab1d 100644
--- a/pkg/analyzer/lib/source/analysis_options_provider.dart
+++ b/pkg/analyzer/lib/source/analysis_options_provider.dart
@@ -12,14 +12,19 @@
 import 'package:source_span/source_span.dart';
 import 'package:yaml/yaml.dart';
 
-/// Provide the options found in the `.analysis_options` file.
+/// Provide the options found in the analysis options file.
 class AnalysisOptionsProvider {
-  /// Provide the options found in [root]/[ANALYSIS_OPTIONS_FILE].
+  /// Provide the options found in either [root]/[ANALYSIS_OPTIONS_FILE] or
+  /// [root]/[ANALYSIS_OPTIONS_YAML_FILE].
   /// Return an empty options map if the file does not exist.
   Map<String, YamlNode> getOptions(Folder root, {bool crawlUp: false}) {
     Resource resource;
     for (Folder folder = root; folder != null; folder = folder.parent) {
       resource = folder.getChild(AnalysisEngine.ANALYSIS_OPTIONS_FILE);
+      if (resource.exists) {
+        break;
+      }
+      resource = folder.getChild(AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
       if (resource.exists || !crawlUp) {
         break;
       }
diff --git a/pkg/analyzer/lib/source/config.dart b/pkg/analyzer/lib/source/config.dart
index 376c189..0ca954a 100644
--- a/pkg/analyzer/lib/source/config.dart
+++ b/pkg/analyzer/lib/source/config.dart
@@ -19,8 +19,7 @@
 /// Return configuration associated with this [context], or `null` if there is
 /// none.
 AnalysisConfiguration getConfiguration(AnalysisContext context) =>
-    context.getConfigurationData(ANALYSIS_CONFIGURATION)
-    as AnalysisConfiguration;
+    context.getConfigurationData(ANALYSIS_CONFIGURATION);
 
 /// Associate this [config] with the given [context].
 void setConfiguration(AnalysisContext context, AnalysisConfiguration config) {
@@ -47,6 +46,7 @@
 class AnalysisConfigurationDescriptor {
   /// The name of the package hosting the configuration.
   String package;
+
   /// The name of the configuration "pragma".
   String pragma;
 
diff --git a/pkg/analyzer/lib/source/error_processor.dart b/pkg/analyzer/lib/source/error_processor.dart
index ddd0679..1fd9577 100644
--- a/pkg/analyzer/lib/source/error_processor.dart
+++ b/pkg/analyzer/lib/source/error_processor.dart
@@ -96,8 +96,7 @@
 
     // Let the user configure how specific errors are processed.
     List<ErrorProcessor> processors =
-        context.getConfigurationData(CONFIGURED_ERROR_PROCESSORS)
-        as List<ErrorProcessor>;
+        context.getConfigurationData(CONFIGURED_ERROR_PROCESSORS);
 
     // Give strong mode a chance to upgrade it.
     if (context.analysisOptions.strongMode) {
diff --git a/pkg/analyzer/lib/src/context/cache.dart b/pkg/analyzer/lib/src/context/cache.dart
index c5641a9..7dbe398 100644
--- a/pkg/analyzer/lib/src/context/cache.dart
+++ b/pkg/analyzer/lib/src/context/cache.dart
@@ -179,7 +179,7 @@
     if (entry == null) {
       return result.defaultValue;
     }
-    return entry.getValue(result) as Object/*=V*/;
+    return entry.getValue(result);
   }
 
   /**
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index 7540c0f..f5464b1 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -1016,7 +1016,7 @@
   @override
   Object/*=V*/ getResult/*<V>*/(
       AnalysisTarget target, ResultDescriptor/*<V>*/ result) {
-    return _cache.getValue(target, result) as Object/*=V*/;
+    return _cache.getValue(target, result);
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/context/source.dart b/pkg/analyzer/lib/src/context/source.dart
index 32792df..dcd413a 100644
--- a/pkg/analyzer/lib/src/context/source.dart
+++ b/pkg/analyzer/lib/src/context/source.dart
@@ -4,6 +4,8 @@
 
 library analyzer.src.context.source;
 
+import 'dart:collection';
+
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/source/package_map_resolver.dart';
@@ -48,6 +50,12 @@
   LocalSourcePredicate _localSourcePredicate = LocalSourcePredicate.NOT_SDK;
 
   /**
+   * Cache of mapping of absolute [Uri]s to [Source]s.
+   */
+  final HashMap<Uri, Source> _absoluteUriToSourceCache =
+      new HashMap<Uri, Source>();
+
+  /**
    * Initialize a newly created source factory with the given absolute URI
    * [resolvers] and optional [packages] resolution helper.
    */
@@ -310,13 +318,14 @@
       }
     }
 
-    for (UriResolver resolver in resolvers) {
-      Source result = resolver.resolveAbsolute(containedUri, actualUri);
-      if (result != null) {
-        return result;
+    return _absoluteUriToSourceCache.putIfAbsent(containedUri, () {
+      for (UriResolver resolver in resolvers) {
+        Source result = resolver.resolveAbsolute(containedUri, actualUri);
+        if (result != null) {
+          return result;
+        }
       }
-    }
-
-    return null;
+      return null;
+    });
   }
 }
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index e5509f1..2ed3515 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -895,21 +895,22 @@
   }
 
   @override
-  AstNode getAncestor(Predicate<AstNode> predicate) {
+  AstNode/*=E*/ getAncestor/*<E extends AstNode>*/(
+      Predicate<AstNode> predicate) {
     // TODO(brianwilkerson) It is a bug that this method can return `this`.
     AstNode node = this;
     while (node != null && !predicate(node)) {
       node = node.parent;
     }
-    return node;
+    return node as AstNode/*=E*/;
   }
 
   @override
-  Object getProperty(String name) {
+  Object/*=E*/ getProperty/*<E>*/(String name) {
     if (_propertyMap == null) {
       return null;
     }
-    return _propertyMap[name];
+    return _propertyMap[name] as Object/*=E*/;
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index cde4825..e3e379f 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -2317,7 +2317,7 @@
       Object key = entry.key.accept(this);
       Object value = entry.value.accept(this);
       if (key is String && !identical(value, NOT_A_CONSTANT)) {
-        map[(key as String)] = value;
+        map[key] = value;
       } else {
         return NOT_A_CONSTANT;
       }
@@ -5611,7 +5611,9 @@
   bool visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
     FunctionExpressionInvocation toNode =
         this._toNode as FunctionExpressionInvocation;
-    if (_and(_isEqualNodes(node.function, toNode.function),
+    if (_and(
+        _isEqualNodes(node.function, toNode.function),
+        _isEqualNodes(node.typeArguments, toNode.typeArguments),
         _isEqualNodes(node.argumentList, toNode.argumentList))) {
       toNode.propagatedElement = node.propagatedElement;
       toNode.propagatedInvokeType = node.propagatedInvokeType;
@@ -5876,6 +5878,7 @@
     if (_and(
         _isEqualNodes(node.target, toNode.target),
         _isEqualTokens(node.operator, toNode.operator),
+        _isEqualNodes(node.typeArguments, toNode.typeArguments),
         _isEqualNodes(node.methodName, toNode.methodName),
         _isEqualNodes(node.argumentList, toNode.argumentList))) {
       toNode.propagatedInvokeType = node.propagatedInvokeType;
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index bcac6b1..ddcad2b 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -27,6 +27,8 @@
 import 'package:analyzer/src/generated/utilities_collection.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:analyzer/src/generated/utilities_general.dart';
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/task/dart.dart';
 
 /**
  * For AST nodes that could be in both the getter and setter contexts
@@ -59,7 +61,14 @@
 /**
  * A concrete implementation of a [ClassElement].
  */
-class ClassElementImpl extends ElementImpl implements ClassElement {
+class ClassElementImpl extends ElementImpl
+    with TypeParameterizedElementMixin
+    implements ClassElement {
+  /**
+   * The unlinked representation of the class in the summary.
+   */
+  final UnlinkedClass _unlinkedClass;
+
   /**
    * A list containing all of the accessors (getters and setters) contained in
    * this class.
@@ -128,17 +137,29 @@
    * Initialize a newly created class element to have the given [name] at the
    * given [offset] in the file that contains the declaration of this element.
    */
-  ClassElementImpl(String name, int offset) : super(name, offset);
+  ClassElementImpl(String name, int offset)
+      : _unlinkedClass = null,
+        super(name, offset);
 
   /**
    * Initialize a newly created class element to have the given [name].
    */
-  ClassElementImpl.forNode(Identifier name) : super.forNode(name);
+  ClassElementImpl.forNode(Identifier name)
+      : _unlinkedClass = null,
+        super.forNode(name);
+
+  /**
+   * Initialize using the given serialized information.
+   */
+  ClassElementImpl.forSerialized(
+      this._unlinkedClass, CompilationUnitElementImpl enclosingUnit)
+      : super.forSerialized(enclosingUnit);
 
   /**
    * Set whether this class is abstract.
    */
   void set abstract(bool isAbstract) {
+    assert(_unlinkedClass == null);
     setModifier(Modifier.ABSTRACT, isAbstract);
   }
 
@@ -163,6 +184,22 @@
   }
 
   @override
+  int get codeLength {
+    if (_unlinkedClass != null) {
+      return _unlinkedClass.codeRange?.length;
+    }
+    return super.codeLength;
+  }
+
+  @override
+  int get codeOffset {
+    if (_unlinkedClass != null) {
+      return _unlinkedClass.codeRange?.offset;
+    }
+    return super.codeOffset;
+  }
+
+  @override
   List<ConstructorElement> get constructors {
     if (!isMixinApplication) {
       assert(_constructors != null);
@@ -184,6 +221,29 @@
     this._constructors = constructors;
   }
 
+  @override
+  String get displayName => name;
+
+  @override
+  SourceRange get docRange {
+    if (_unlinkedClass != null) {
+      UnlinkedDocumentationComment comment =
+          _unlinkedClass.documentationComment;
+      return comment != null
+          ? new SourceRange(comment.offset, comment.length)
+          : null;
+    }
+    return super.docRange;
+  }
+
+  @override
+  String get documentationComment {
+    if (_unlinkedClass != null) {
+      return _unlinkedClass?.documentationComment?.text;
+    }
+    return super.documentationComment;
+  }
+
   /**
    * Return `true` if [CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS] should
    * be reported for this class.
@@ -228,6 +288,9 @@
     return !nearestNonMixinClass.constructors.any(isSuperConstructorAccessible);
   }
 
+  @override
+  TypeParameterizedElementMixin get enclosingTypeParameterContext => null;
+
   /**
    * Set whether this class is defined by an enum declaration.
    */
@@ -310,13 +373,23 @@
   }
 
   @override
-  bool get isAbstract => hasModifier(Modifier.ABSTRACT);
+  bool get isAbstract {
+    if (_unlinkedClass != null) {
+      return _unlinkedClass.isAbstract;
+    }
+    return hasModifier(Modifier.ABSTRACT);
+  }
 
   @override
   bool get isEnum => hasModifier(Modifier.ENUM);
 
   @override
-  bool get isMixinApplication => hasModifier(Modifier.MIXIN_APPLICATION);
+  bool get isMixinApplication {
+    if (_unlinkedClass != null) {
+      return _unlinkedClass.isMixinApplication;
+    }
+    return hasModifier(Modifier.MIXIN_APPLICATION);
+  }
 
   @override
   bool get isOrInheritsProxy =>
@@ -354,6 +427,16 @@
   ElementKind get kind => ElementKind.CLASS;
 
   @override
+  List<ElementAnnotation> get metadata {
+    if (_unlinkedClass != null) {
+      return _metadata ??= _unlinkedClass.annotations
+          .map(enclosingUnit.resynthesizerContext.buildAnnotation)
+          .toList();
+    }
+    return super.metadata;
+  }
+
+  @override
   List<MethodElement> get methods => _methods;
 
   /**
@@ -370,17 +453,40 @@
    * Set whether this class is a mixin application.
    */
   void set mixinApplication(bool isMixinApplication) {
+    assert(_unlinkedClass == null);
     setModifier(Modifier.MIXIN_APPLICATION, isMixinApplication);
   }
 
   @override
-  List<TypeParameterElement> get typeParameters => _typeParameters;
+  String get name {
+    if (_unlinkedClass != null) {
+      return _unlinkedClass.name;
+    }
+    return super.name;
+  }
+
+  @override
+  int get nameOffset {
+    if (_unlinkedClass != null) {
+      return _unlinkedClass.nameOffset;
+    }
+    return super.nameOffset;
+  }
+
+  @override
+  List<TypeParameterElement> get typeParameters {
+    if (_unlinkedClass != null) {
+      return super.typeParameters;
+    }
+    return _typeParameters;
+  }
 
   /**
    * Set the type parameters defined for this class to the given
    * [typeParameters].
    */
   void set typeParameters(List<TypeParameterElement> typeParameters) {
+    assert(_unlinkedClass == null);
     for (TypeParameterElement typeParameter in typeParameters) {
       (typeParameter as TypeParameterElementImpl).enclosingElement = this;
     }
@@ -388,6 +494,10 @@
   }
 
   @override
+  List<UnlinkedTypeParam> get unlinkedTypeParams =>
+      _unlinkedClass.typeParameters;
+
+  @override
   ConstructorElement get unnamedConstructor {
     for (ConstructorElement element in constructors) {
       String name = element.displayName;
@@ -921,6 +1031,7 @@
    */
   static ClassElementImpl getImpl(ClassElement classElement) {
     if (classElement is ClassElementHandle) {
+      classElement.ensureActualElementComplete();
       return getImpl(classElement.actualElement);
     }
     return classElement as ClassElementImpl;
@@ -933,6 +1044,22 @@
 class CompilationUnitElementImpl extends UriReferencedElementImpl
     implements CompilationUnitElement {
   /**
+   * The context in which this unit is resynthesized, or `null` if the
+   * element is not resynthesized a summary.
+   */
+  final ResynthesizerContext resynthesizerContext;
+
+  /**
+   * The unlinked representation of the unit in the summary.
+   */
+  final UnlinkedUnit _unlinkedUnit;
+
+  /**
+   * The unlinked representation of the part in the summary.
+   */
+  final UnlinkedPart _unlinkedPart;
+
+  /**
    * The source that corresponds to this compilation unit.
    */
   @override
@@ -997,7 +1124,26 @@
    * Initialize a newly created compilation unit element to have the given
    * [name].
    */
-  CompilationUnitElementImpl(String name) : super(name, -1);
+  CompilationUnitElementImpl(String name)
+      : resynthesizerContext = null,
+        _unlinkedUnit = null,
+        _unlinkedPart = null,
+        super(name, -1);
+
+  /**
+   * Initialize using the given serialized information.
+   */
+  CompilationUnitElementImpl.forSerialized(
+      LibraryElementImpl enclosingLibrary,
+      this.resynthesizerContext,
+      this._unlinkedUnit,
+      this._unlinkedPart,
+      String name)
+      : super.forSerialized(null) {
+    _enclosingElement = enclosingLibrary;
+    _name = name;
+    _nameOffset = -1;
+  }
 
   @override
   List<PropertyAccessorElement> get accessors => _accessors;
@@ -1014,10 +1160,31 @@
   }
 
   @override
+  int get codeLength {
+    if (_unlinkedUnit != null) {
+      return _unlinkedUnit.codeRange?.length;
+    }
+    return super.codeLength;
+  }
+
+  @override
+  int get codeOffset {
+    if (_unlinkedUnit != null) {
+      return _unlinkedUnit.codeRange?.offset;
+    }
+    return super.codeOffset;
+  }
+
+  @override
   LibraryElement get enclosingElement =>
       super.enclosingElement as LibraryElement;
 
   @override
+  CompilationUnitElementImpl get enclosingUnit {
+    return this;
+  }
+
+  @override
   List<ClassElement> get enums => _enums;
 
   /**
@@ -1067,6 +1234,18 @@
   ElementKind get kind => ElementKind.COMPILATION_UNIT;
 
   @override
+  List<ElementAnnotation> get metadata {
+    if (_unlinkedPart != null) {
+      CompilationUnitElementImpl definingUnit =
+          library.definingCompilationUnit as CompilationUnitElementImpl;
+      return _metadata ??= _unlinkedPart.annotations
+          .map(definingUnit.resynthesizerContext.buildAnnotation)
+          .toList();
+    }
+    return super.metadata;
+  }
+
+  @override
   List<TopLevelVariableElement> get topLevelVariables => _variables;
 
   /**
@@ -1143,9 +1322,9 @@
    */
   List<ElementAnnotation> getAnnotations(int offset) {
     if (annotationMap == null) {
-      return ElementAnnotation.EMPTY_LIST;
+      return const <ElementAnnotation>[];
     }
-    return annotationMap[offset] ?? ElementAnnotation.EMPTY_LIST;
+    return annotationMap[offset] ?? const <ElementAnnotation>[];
   }
 
   @override
@@ -1264,11 +1443,6 @@
  */
 class ConstFieldElementImpl extends FieldElementImpl with ConstVariableElement {
   /**
-   * The result of evaluating this variable's initializer.
-   */
-  EvaluationResultImpl _result;
-
-  /**
    * Initialize a newly created synthetic field element to have the given
    * [name] and [offset].
    */
@@ -1278,17 +1452,6 @@
    * Initialize a newly created field element to have the given [name].
    */
   ConstFieldElementImpl.forNode(Identifier name) : super.forNode(name);
-
-  @override
-  DartObject get constantValue => _result?.value;
-
-  @override
-  EvaluationResultImpl get evaluationResult => _result;
-
-  @override
-  void set evaluationResult(EvaluationResultImpl result) {
-    this._result = result;
-  }
 }
 
 /**
@@ -1298,11 +1461,6 @@
 class ConstLocalVariableElementImpl extends LocalVariableElementImpl
     with ConstVariableElement {
   /**
-   * The result of evaluating this variable's initializer.
-   */
-  EvaluationResultImpl _result;
-
-  /**
    * Initialize a newly created local variable element to have the given [name]
    * and [offset].
    */
@@ -1313,16 +1471,12 @@
    */
   ConstLocalVariableElementImpl.forNode(Identifier name) : super.forNode(name);
 
-  @override
-  DartObject get constantValue => _result?.value;
-
-  @override
-  EvaluationResultImpl get evaluationResult => _result;
-
-  @override
-  void set evaluationResult(EvaluationResultImpl result) {
-    this._result = result;
-  }
+  /**
+   * Initialize using the given serialized information.
+   */
+  ConstLocalVariableElementImpl.forSerialized(UnlinkedVariable unlinkedVariable,
+      ExecutableElementImpl enclosingExecutable)
+      : super.forSerialized(unlinkedVariable, enclosingExecutable);
 }
 
 /**
@@ -1370,9 +1524,17 @@
   ConstructorElementImpl.forNode(Identifier name) : super.forNode(name);
 
   /**
+   * Initialize using the given serialized information.
+   */
+  ConstructorElementImpl.forSerialized(
+      UnlinkedExecutable serializedExecutable, ClassElementImpl enclosingClass)
+      : super.forSerialized(serializedExecutable, enclosingClass);
+
+  /**
    * Set whether this constructor represents a 'const' constructor.
    */
   void set const2(bool isConst) {
+    assert(serializedExecutable == null);
     setModifier(Modifier.CONST, isConst);
   }
 
@@ -1383,11 +1545,17 @@
    * Set whether this constructor represents a factory method.
    */
   void set factory(bool isFactory) {
+    assert(serializedExecutable == null);
     setModifier(Modifier.FACTORY, isFactory);
   }
 
   @override
-  bool get isConst => hasModifier(Modifier.CONST);
+  bool get isConst {
+    if (serializedExecutable != null) {
+      return serializedExecutable.isConst;
+    }
+    return hasModifier(Modifier.CONST);
+  }
 
   @override
   bool get isDefaultConstructor {
@@ -1407,7 +1575,12 @@
   }
 
   @override
-  bool get isFactory => hasModifier(Modifier.FACTORY);
+  bool get isFactory {
+    if (serializedExecutable != null) {
+      return serializedExecutable.isFactory;
+    }
+    return hasModifier(Modifier.FACTORY);
+  }
 
   @override
   bool get isStatic => false;
@@ -1454,11 +1627,6 @@
 class ConstTopLevelVariableElementImpl extends TopLevelVariableElementImpl
     with ConstVariableElement {
   /**
-   * The result of evaluating this variable's initializer.
-   */
-  EvaluationResultImpl _result;
-
-  /**
    * Initialize a newly created synthetic top-level variable element to have the
    * given [name] and [offset].
    */
@@ -1471,17 +1639,6 @@
    */
   ConstTopLevelVariableElementImpl.forNode(Identifier name)
       : super.forNode(name);
-
-  @override
-  DartObject get constantValue => _result?.value;
-
-  @override
-  EvaluationResultImpl get evaluationResult => _result;
-
-  @override
-  void set evaluationResult(EvaluationResultImpl result) {
-    this._result = result;
-  }
 }
 
 /**
@@ -1495,7 +1652,7 @@
  *
  * This class is not intended to be part of the public API for analyzer.
  */
-abstract class ConstVariableElement {
+abstract class ConstVariableElement implements ConstantEvaluationTarget {
   /**
    * If this element represents a constant variable, and it has an initializer,
    * a copy of the initializer for the constant.  Otherwise `null`.
@@ -1506,6 +1663,22 @@
    * initializers.
    */
   Expression constantInitializer;
+
+  @override
+  EvaluationResultImpl evaluationResult;
+
+  /**
+   * Return a representation of the value of this variable, forcing the value
+   * to be computed if it had not previously been computed, or `null` if either
+   * this variable was not declared with the 'const' modifier or if the value of
+   * this variable could not be computed because of errors.
+   */
+  DartObject computeConstantValue() {
+    if (evaluationResult == null) {
+      context?.computeResult(this, CONSTANT_VALUE);
+    }
+    return evaluationResult?.value;
+  }
 }
 
 /**
@@ -1514,11 +1687,6 @@
 class DefaultFieldFormalParameterElementImpl
     extends FieldFormalParameterElementImpl with ConstVariableElement {
   /**
-   * The result of evaluating this variable's initializer.
-   */
-  EvaluationResultImpl _result;
-
-  /**
    * Initialize a newly created parameter element to have the given [name] and
    * [nameOffset].
    */
@@ -1530,17 +1698,6 @@
    */
   DefaultFieldFormalParameterElementImpl.forNode(Identifier name)
       : super.forNode(name);
-
-  @override
-  DartObject get constantValue => _result?.value;
-
-  @override
-  EvaluationResultImpl get evaluationResult => _result;
-
-  @override
-  void set evaluationResult(EvaluationResultImpl result) {
-    this._result = result;
-  }
 }
 
 /**
@@ -1549,11 +1706,6 @@
 class DefaultParameterElementImpl extends ParameterElementImpl
     with ConstVariableElement {
   /**
-   * The result of evaluating this variable's initializer.
-   */
-  EvaluationResultImpl _result;
-
-  /**
    * Initialize a newly created parameter element to have the given [name] and
    * [nameOffset].
    */
@@ -1565,15 +1717,30 @@
    */
   DefaultParameterElementImpl.forNode(Identifier name) : super.forNode(name);
 
-  @override
-  DartObject get constantValue => _result?.value;
+  /**
+   * Initialize using the given serialized information.
+   */
+  DefaultParameterElementImpl.forSerialized(
+      UnlinkedParam unlinkedParam, ExecutableElementImpl enclosingExecutable)
+      : super.forSerialized(unlinkedParam, enclosingExecutable);
 
   @override
-  EvaluationResultImpl get evaluationResult => _result;
+  Expression get constantInitializer {
+    if (_unlinkedParam != null) {
+      UnlinkedConst defaultValue = _unlinkedParam.defaultValue;
+      if (defaultValue == null) {
+        return null;
+      }
+      return super.constantInitializer ??=
+          enclosingUnit.resynthesizerContext.buildExpression(defaultValue);
+    }
+    return super.constantInitializer;
+  }
 
   @override
-  void set evaluationResult(EvaluationResultImpl result) {
-    this._result = result;
+  void set constantInitializer(Expression initializer) {
+    assert(_unlinkedParam == null);
+    super.constantInitializer = initializer;
   }
 
   @override
@@ -1772,6 +1939,14 @@
   Source get source => compilationUnit.source;
 
   @override
+  DartObject computeConstantValue() {
+    if (evaluationResult == null) {
+      context?.computeResult(this, CONSTANT_VALUE);
+    }
+    return constantValue;
+  }
+
+  @override
   String toString() => '@$element';
 }
 
@@ -1813,7 +1988,7 @@
   /**
    * A list containing all of the metadata associated with this element.
    */
-  List<ElementAnnotation> metadata = ElementAnnotation.EMPTY_LIST;
+  List<ElementAnnotation> _metadata;
 
   /**
    * A cached copy of the calculated hashCode for this element.
@@ -1867,6 +2042,11 @@
       : this(name == null ? "" : name.name, name == null ? -1 : name.offset);
 
   /**
+   * Initialize from serialized information.
+   */
+  ElementImpl.forSerialized(this._enclosingElement);
+
+  /**
    * The length of the element's code, or `null` if the element is synthetic.
    */
   int get codeLength => _codeLength;
@@ -1903,6 +2083,7 @@
    * The documentation comment source for this element.
    */
   void set documentationComment(String doc) {
+    assert(!isResynthesized);
     _docComment = doc?.replaceAll('\r\n', '\n');
   }
 
@@ -1919,6 +2100,14 @@
     _updateCaches();
   }
 
+  /**
+   * Return the enclosing unit element (which might be the same as `this`), or
+   * `null` if this element is not contained in any compilation unit.
+   */
+  CompilationUnitElementImpl get enclosingUnit {
+    return _enclosingElement?.enclosingUnit;
+  }
+
   @override
   int get hashCode {
     // TODO: We might want to re-visit this optimization in the future.
@@ -1997,6 +2186,11 @@
     return false;
   }
 
+  /**
+   * Return `true` if this element is resynthesized from a summary.
+   */
+  bool get isResynthesized => enclosingUnit?.resynthesizerContext != null;
+
   @override
   bool get isSynthetic => hasModifier(Modifier.SYNTHETIC);
 
@@ -2015,6 +2209,15 @@
     return _cachedLocation;
   }
 
+  List<ElementAnnotation> get metadata {
+    return _metadata ?? const <ElementAnnotation>[];
+  }
+
+  void set metadata(List<ElementAnnotation> metadata) {
+    assert(!isResynthesized);
+    _metadata = metadata;
+  }
+
   @override
   String get name => _name;
 
@@ -2121,12 +2324,13 @@
   }
 
   @override
-  Element getAncestor(Predicate<Element> predicate) {
+  Element/*=E*/ getAncestor/*<E extends Element >*/(
+      Predicate<Element> predicate) {
     Element ancestor = _enclosingElement;
     while (ancestor != null && !predicate(ancestor)) {
       ancestor = ancestor.enclosingElement;
     }
-    return ancestor;
+    return ancestor as Element/*=E*/;
   }
 
   /**
@@ -2171,7 +2375,7 @@
 
   @override
   bool isAccessibleIn(LibraryElement library) {
-    if (Identifier.isPrivateName(_name)) {
+    if (Identifier.isPrivateName(name)) {
       return library == this.library;
     }
     return true;
@@ -2192,6 +2396,7 @@
    * Set the code range for this element.
    */
   void setCodeRange(int offset, int length) {
+    assert(!isResynthesized);
     _codeOffset = offset;
     _codeLength = length;
   }
@@ -2200,6 +2405,7 @@
    * Set the documentation comment source range for this element.
    */
   void setDocRange(int offset, int length) {
+    assert(!isResynthesized);
     _docRangeOffset = offset;
     _docRangeLength = length;
   }
@@ -2411,6 +2617,11 @@
 abstract class ExecutableElementImpl extends ElementImpl
     implements ExecutableElement {
   /**
+   * The unlinked representation of the executable in the summary.
+   */
+  final UnlinkedExecutable serializedExecutable;
+
+  /**
    * A list containing all of the functions defined within this executable
    * element.
    */
@@ -2452,24 +2663,81 @@
    * Initialize a newly created executable element to have the given [name] and
    * [offset].
    */
-  ExecutableElementImpl(String name, int offset) : super(name, offset);
+  ExecutableElementImpl(String name, int offset)
+      : serializedExecutable = null,
+        super(name, offset);
 
   /**
    * Initialize a newly created executable element to have the given [name].
    */
-  ExecutableElementImpl.forNode(Identifier name) : super.forNode(name);
+  ExecutableElementImpl.forNode(Identifier name)
+      : serializedExecutable = null,
+        super.forNode(name);
+
+  /**
+   * Initialize using the given serialized information.
+   */
+  ExecutableElementImpl.forSerialized(
+      this.serializedExecutable, ElementImpl enclosingElement)
+      : super.forSerialized(enclosingElement);
 
   /**
    * Set whether this executable element's body is asynchronous.
    */
   void set asynchronous(bool isAsynchronous) {
+    assert(serializedExecutable == null);
     setModifier(Modifier.ASYNCHRONOUS, isAsynchronous);
   }
 
+  @override
+  int get codeLength {
+    if (serializedExecutable != null) {
+      return serializedExecutable.codeRange?.length;
+    }
+    return super.codeLength;
+  }
+
+  @override
+  int get codeOffset {
+    if (serializedExecutable != null) {
+      return serializedExecutable.codeRange?.offset;
+    }
+    return super.codeOffset;
+  }
+
+  @override
+  String get displayName {
+    if (serializedExecutable != null) {
+      return serializedExecutable.name;
+    }
+    return super.displayName;
+  }
+
+  @override
+  SourceRange get docRange {
+    if (serializedExecutable != null) {
+      UnlinkedDocumentationComment comment =
+          serializedExecutable.documentationComment;
+      return comment != null
+          ? new SourceRange(comment.offset, comment.length)
+          : null;
+    }
+    return super.docRange;
+  }
+
+  @override
+  String get documentationComment {
+    if (serializedExecutable != null) {
+      return serializedExecutable?.documentationComment?.text;
+    }
+    return super.documentationComment;
+  }
+
   /**
    * Set whether this executable element is external.
    */
   void set external(bool isExternal) {
+    assert(serializedExecutable == null);
     setModifier(Modifier.EXTERNAL, isExternal);
   }
 
@@ -2491,36 +2759,64 @@
    * Set whether this method's body is a generator.
    */
   void set generator(bool isGenerator) {
+    assert(serializedExecutable == null);
     setModifier(Modifier.GENERATOR, isGenerator);
   }
 
   @override
-  bool get hasImplicitReturnType => hasModifier(Modifier.IMPLICIT_TYPE);
+  bool get hasImplicitReturnType {
+    if (serializedExecutable != null) {
+      return serializedExecutable.returnType == null &&
+          serializedExecutable.kind != UnlinkedExecutableKind.constructor;
+    }
+    return hasModifier(Modifier.IMPLICIT_TYPE);
+  }
 
   /**
    * Set whether this executable element has an implicit return type.
    */
   void set hasImplicitReturnType(bool hasImplicitReturnType) {
+    assert(serializedExecutable == null);
     setModifier(Modifier.IMPLICIT_TYPE, hasImplicitReturnType);
   }
 
   @override
-  bool get isAbstract => hasModifier(Modifier.ABSTRACT);
+  bool get isAbstract {
+    if (serializedExecutable != null) {
+      return serializedExecutable.isAbstract;
+    }
+    return hasModifier(Modifier.ABSTRACT);
+  }
 
   @override
-  bool get isAsynchronous => hasModifier(Modifier.ASYNCHRONOUS);
+  bool get isAsynchronous {
+    if (serializedExecutable != null) {
+      return serializedExecutable.isAsynchronous;
+    }
+    return hasModifier(Modifier.ASYNCHRONOUS);
+  }
 
   @override
-  bool get isExternal => hasModifier(Modifier.EXTERNAL);
+  bool get isExternal {
+    if (serializedExecutable != null) {
+      return serializedExecutable.isExternal;
+    }
+    return hasModifier(Modifier.EXTERNAL);
+  }
 
   @override
-  bool get isGenerator => hasModifier(Modifier.GENERATOR);
+  bool get isGenerator {
+    if (serializedExecutable != null) {
+      return serializedExecutable.isGenerator;
+    }
+    return hasModifier(Modifier.GENERATOR);
+  }
 
   @override
   bool get isOperator => false;
 
   @override
-  bool get isSynchronous => !hasModifier(Modifier.ASYNCHRONOUS);
+  bool get isSynchronous => !isAsynchronous;
 
   @override
   List<LabelElement> get labels => _labels;
@@ -2551,6 +2847,32 @@
   }
 
   @override
+  List<ElementAnnotation> get metadata {
+    if (serializedExecutable != null) {
+      return _metadata ??= serializedExecutable.annotations
+          .map(enclosingUnit.resynthesizerContext.buildAnnotation)
+          .toList();
+    }
+    return super.metadata;
+  }
+
+  @override
+  String get name {
+    if (serializedExecutable != null) {
+      return serializedExecutable.name;
+    }
+    return super.name;
+  }
+
+  @override
+  int get nameOffset {
+    if (serializedExecutable != null) {
+      return serializedExecutable.nameOffset;
+    }
+    return super.nameOffset;
+  }
+
+  @override
   List<ParameterElement> get parameters => _parameters;
 
   /**
@@ -2830,6 +3152,13 @@
   FunctionElementImpl.forOffset(int nameOffset) : super("", nameOffset);
 
   /**
+   * Initialize using the given serialized information.
+   */
+  FunctionElementImpl.forSerialized(
+      UnlinkedExecutable serializedExecutable, ElementImpl enclosingElement)
+      : super.forSerialized(serializedExecutable, enclosingElement);
+
+  /**
    * Synthesize an unnamed function element that takes [parameters] and returns
    * [returnType].
    */
@@ -2920,8 +3249,14 @@
  * A concrete implementation of a [FunctionTypeAliasElement].
  */
 class FunctionTypeAliasElementImpl extends ElementImpl
+    with TypeParameterizedElementMixin
     implements FunctionTypeAliasElement {
   /**
+   * The unlinked representation of the type in the summary.
+   */
+  final UnlinkedTypedef _unlinkedTypedef;
+
+  /**
    * A list containing all of the parameters defined by this type alias.
    */
   List<ParameterElement> _parameters = ParameterElement.EMPTY_LIST;
@@ -2949,21 +3284,103 @@
    *    contains the declaration of this element
    */
   FunctionTypeAliasElementImpl(String name, int nameOffset)
-      : super(name, nameOffset);
+      : _unlinkedTypedef = null,
+        super(name, nameOffset);
 
   /**
    * Initialize a newly created type alias element to have the given [name].
    */
-  FunctionTypeAliasElementImpl.forNode(Identifier name) : super.forNode(name);
+  FunctionTypeAliasElementImpl.forNode(Identifier name)
+      : _unlinkedTypedef = null,
+        super.forNode(name);
+
+  /**
+   * Initialize using the given serialized information.
+   */
+  FunctionTypeAliasElementImpl.forSerialized(
+      this._unlinkedTypedef, CompilationUnitElementImpl enclosingUnit)
+      : super.forSerialized(enclosingUnit);
+
+  @override
+  int get codeLength {
+    if (_unlinkedTypedef != null) {
+      return _unlinkedTypedef.codeRange?.length;
+    }
+    return super.codeLength;
+  }
+
+  @override
+  int get codeOffset {
+    if (_unlinkedTypedef != null) {
+      return _unlinkedTypedef.codeRange?.offset;
+    }
+    return super.codeOffset;
+  }
+
+  @override
+  String get displayName => name;
+
+  @override
+  SourceRange get docRange {
+    if (_unlinkedTypedef != null) {
+      UnlinkedDocumentationComment comment =
+          _unlinkedTypedef.documentationComment;
+      return comment != null
+          ? new SourceRange(comment.offset, comment.length)
+          : null;
+    }
+    return super.docRange;
+  }
+
+  @override
+  String get documentationComment {
+    if (_unlinkedTypedef != null) {
+      return _unlinkedTypedef?.documentationComment?.text;
+    }
+    return super.documentationComment;
+  }
 
   @override
   CompilationUnitElement get enclosingElement =>
       super.enclosingElement as CompilationUnitElement;
 
   @override
+  TypeParameterizedElementMixin get enclosingTypeParameterContext => null;
+
+  @override
+  CompilationUnitElementImpl get enclosingUnit =>
+      _enclosingElement as CompilationUnitElementImpl;
+
+  @override
   ElementKind get kind => ElementKind.FUNCTION_TYPE_ALIAS;
 
   @override
+  List<ElementAnnotation> get metadata {
+    if (_unlinkedTypedef != null) {
+      return _metadata ??= _unlinkedTypedef.annotations
+          .map(enclosingUnit.resynthesizerContext.buildAnnotation)
+          .toList();
+    }
+    return super.metadata;
+  }
+
+  @override
+  String get name {
+    if (_unlinkedTypedef != null) {
+      return _unlinkedTypedef.name;
+    }
+    return super.name;
+  }
+
+  @override
+  int get nameOffset {
+    if (_unlinkedTypedef != null) {
+      return _unlinkedTypedef.nameOffset;
+    }
+    return super.nameOffset;
+  }
+
+  @override
   List<ParameterElement> get parameters => _parameters;
 
   /**
@@ -2979,13 +3396,19 @@
   }
 
   @override
-  List<TypeParameterElement> get typeParameters => _typeParameters;
+  List<TypeParameterElement> get typeParameters {
+    if (_unlinkedTypedef != null) {
+      return super.typeParameters;
+    }
+    return _typeParameters;
+  }
 
   /**
    * Set the type parameters defined for this type to the given
    * [typeParameters].
    */
   void set typeParameters(List<TypeParameterElement> typeParameters) {
+    assert(_unlinkedTypedef == null);
     for (TypeParameterElement typeParameter in typeParameters) {
       (typeParameter as TypeParameterElementImpl).enclosingElement = this;
     }
@@ -2993,6 +3416,10 @@
   }
 
   @override
+  List<UnlinkedTypeParam> get unlinkedTypeParams =>
+      _unlinkedTypedef.typeParameters;
+
+  @override
   accept(ElementVisitor visitor) => visitor.visitFunctionTypeAliasElement(this);
 
   @override
@@ -3450,6 +3877,13 @@
   }
 
   @override
+  bool get isResynthesized {
+    CompilationUnitElement definingUnit = _definingCompilationUnit;
+    return definingUnit is CompilationUnitElementImpl &&
+        definingUnit.resynthesizerContext != null;
+  }
+
+  @override
   ElementKind get kind => ElementKind.LIBRARY;
 
   @override
@@ -3692,7 +4126,7 @@
     // represents a new back edge.  It would be sufficient to invalidate the
     // cycle information for all nodes that are between the target and the
     // node in the topological order.  For simplicity, we simply invalidate
-    // all nodes which are reachable from the the source node.
+    // all nodes which are reachable from the source node.
     // Note that in the invalidation phase, we do not cut off when we encounter
     // a node with no library cycle information, since we do not know whether
     // we are in the case where invalidation has already been performed, or we
@@ -3801,7 +4235,7 @@
 /**
  * A concrete implementation of a [LocalVariableElement].
  */
-class LocalVariableElementImpl extends VariableElementImpl
+class LocalVariableElementImpl extends NonParameterVariableElementImpl
     implements LocalVariableElement {
   /**
    * The offset to the beginning of the visible range for this element.
@@ -3825,6 +4259,13 @@
    */
   LocalVariableElementImpl.forNode(Identifier name) : super.forNode(name);
 
+  /**
+   * Initialize using the given serialized information.
+   */
+  LocalVariableElementImpl.forSerialized(UnlinkedVariable unlinkedVariable,
+      ExecutableElementImpl enclosingExecutable)
+      : super.forSerialized(unlinkedVariable, enclosingExecutable);
+
   @override
   String get identifier {
     int enclosingOffset =
@@ -3890,9 +4331,17 @@
   MethodElementImpl.forNode(Identifier name) : super.forNode(name);
 
   /**
+   * Initialize using the given serialized information.
+   */
+  MethodElementImpl.forSerialized(
+      UnlinkedExecutable serializedExecutable, ClassElementImpl enclosingClass)
+      : super.forSerialized(serializedExecutable, enclosingClass);
+
+  /**
    * Set whether this method is abstract.
    */
   void set abstract(bool isAbstract) {
+    assert(serializedExecutable == null);
     setModifier(Modifier.ABSTRACT, isAbstract);
   }
 
@@ -3922,7 +4371,12 @@
   }
 
   @override
-  bool get isStatic => hasModifier(Modifier.STATIC);
+  bool get isStatic {
+    if (serializedExecutable != null) {
+      return serializedExecutable.isStatic;
+    }
+    return hasModifier(Modifier.STATIC);
+  }
 
   @override
   ElementKind get kind => ElementKind.METHOD;
@@ -3940,6 +4394,7 @@
    * Set whether this method is static.
    */
   void set static(bool isStatic) {
+    assert(serializedExecutable == null);
     setModifier(Modifier.STATIC, isStatic);
   }
 
@@ -4177,7 +4632,7 @@
   ElementLocation get location => null;
 
   @override
-  List<ElementAnnotation> get metadata => ElementAnnotation.EMPTY_LIST;
+  List<ElementAnnotation> get metadata => const <ElementAnnotation>[];
 
   @override
   String get name => _name;
@@ -4207,7 +4662,9 @@
   AstNode computeNode() => null;
 
   @override
-  Element getAncestor(Predicate<Element> predicate) => null;
+  Element/*=E*/ getAncestor/*<E extends Element >*/(
+          Predicate<Element> predicate) =>
+      null;
 
   @override
   String getExtendedDisplayName(String shortName) {
@@ -4346,12 +4803,133 @@
 }
 
 /**
+ * A [VariableElementImpl], which is not a parameter.
+ */
+abstract class NonParameterVariableElementImpl extends VariableElementImpl {
+  /**
+   * The unlinked representation of the variable in the summary.
+   */
+  final UnlinkedVariable _unlinkedVariable;
+
+  /**
+   * Initialize a newly created variable element to have the given [name] and
+   * [offset].
+   */
+  NonParameterVariableElementImpl(String name, int offset)
+      : _unlinkedVariable = null,
+        super(name, offset);
+
+  /**
+   * Initialize a newly created variable element to have the given [name].
+   */
+  NonParameterVariableElementImpl.forNode(Identifier name)
+      : _unlinkedVariable = null,
+        super.forNode(name);
+
+  /**
+   * Initialize using the given serialized information.
+   */
+  NonParameterVariableElementImpl.forSerialized(
+      this._unlinkedVariable, ElementImpl enclosingElement)
+      : super.forSerialized(enclosingElement);
+
+  @override
+  int get codeLength {
+    if (_unlinkedVariable != null) {
+      return _unlinkedVariable.codeRange?.length;
+    }
+    return super.codeLength;
+  }
+
+  @override
+  int get codeOffset {
+    if (_unlinkedVariable != null) {
+      return _unlinkedVariable.codeRange?.offset;
+    }
+    return super.codeOffset;
+  }
+
+  @override
+  void set const3(bool isConst) {
+    assert(_unlinkedVariable == null);
+    super.const3 = isConst;
+  }
+
+  @override
+  void set final2(bool isFinal) {
+    assert(_unlinkedVariable == null);
+    super.final2 = isFinal;
+  }
+
+  @override
+  bool get hasImplicitType {
+    if (_unlinkedVariable != null) {
+      return _unlinkedVariable.type == null;
+    }
+    return super.hasImplicitType;
+  }
+
+  @override
+  void set hasImplicitType(bool hasImplicitType) {
+    assert(_unlinkedVariable == null);
+    super.hasImplicitType = hasImplicitType;
+  }
+
+  @override
+  bool get isConst {
+    if (_unlinkedVariable != null) {
+      return _unlinkedVariable.isConst;
+    }
+    return super.isConst;
+  }
+
+  @override
+  bool get isFinal {
+    if (_unlinkedVariable != null) {
+      return _unlinkedVariable.isFinal;
+    }
+    return super.isFinal;
+  }
+
+  @override
+  List<ElementAnnotation> get metadata {
+    if (_unlinkedVariable != null) {
+      return _metadata ??= _unlinkedVariable.annotations
+          .map(enclosingUnit.resynthesizerContext.buildAnnotation)
+          .toList();
+    }
+    return super.metadata;
+  }
+
+  @override
+  String get name {
+    if (_unlinkedVariable != null) {
+      return _unlinkedVariable.name;
+    }
+    return super.name;
+  }
+
+  @override
+  int get nameOffset {
+    if (_unlinkedVariable != null) {
+      return _unlinkedVariable.nameOffset;
+    }
+    return super.nameOffset;
+  }
+}
+
+/**
  * A concrete implementation of a [ParameterElement].
  */
 class ParameterElementImpl extends VariableElementImpl
     with ParameterElementMixin
     implements ParameterElement {
   /**
+   * The unlinked representation of the parameter in the summary.
+   */
+  final UnlinkedParam _unlinkedParam;
+
+  /**
    * A list containing all of the parameters defined by this parameter element.
    * There will only be parameters if this parameter is a function typed
    * parameter.
@@ -4390,12 +4968,23 @@
    * Initialize a newly created parameter element to have the given [name] and
    * [nameOffset].
    */
-  ParameterElementImpl(String name, int nameOffset) : super(name, nameOffset);
+  ParameterElementImpl(String name, int nameOffset)
+      : _unlinkedParam = null,
+        super(name, nameOffset);
 
   /**
    * Initialize a newly created parameter element to have the given [name].
    */
-  ParameterElementImpl.forNode(Identifier name) : super.forNode(name);
+  ParameterElementImpl.forNode(Identifier name)
+      : _unlinkedParam = null,
+        super.forNode(name);
+
+  /**
+   * Initialize using the given serialized information.
+   */
+  ParameterElementImpl.forSerialized(
+      this._unlinkedParam, ElementImpl enclosingExecutable)
+      : super.forSerialized(enclosingExecutable);
 
   /**
    * Creates a synthetic parameter with [name], [type] and [kind].
@@ -4410,16 +4999,83 @@
   }
 
   @override
-  String get defaultValueCode => _defaultValueCode;
+  int get codeLength {
+    if (_unlinkedParam != null) {
+      return _unlinkedParam.codeRange?.length;
+    }
+    return super.codeLength;
+  }
+
+  @override
+  int get codeOffset {
+    if (_unlinkedParam != null) {
+      return _unlinkedParam.codeRange?.offset;
+    }
+    return super.codeOffset;
+  }
+
+  @override
+  void set const3(bool isConst) {
+    assert(_unlinkedParam == null);
+    super.const3 = isConst;
+  }
+
+  @override
+  String get defaultValueCode {
+    if (_unlinkedParam != null) {
+      if (_unlinkedParam.defaultValue == null) {
+        return null;
+      }
+      return _unlinkedParam.defaultValueCode;
+    }
+    return _defaultValueCode;
+  }
 
   /**
    * Set Dart code of the default value.
    */
   void set defaultValueCode(String defaultValueCode) {
+    assert(_unlinkedParam == null);
     this._defaultValueCode = StringUtilities.intern(defaultValueCode);
   }
 
   @override
+  void set final2(bool isFinal) {
+    assert(_unlinkedParam == null);
+    super.final2 = isFinal;
+  }
+
+  @override
+  bool get hasImplicitType {
+    if (_unlinkedParam != null) {
+      return _unlinkedParam.type == null;
+    }
+    return super.hasImplicitType;
+  }
+
+  @override
+  void set hasImplicitType(bool hasImplicitType) {
+    assert(_unlinkedParam == null);
+    super.hasImplicitType = hasImplicitType;
+  }
+
+  @override
+  bool get isConst {
+    if (_unlinkedParam != null) {
+      return false;
+    }
+    return super.isConst;
+  }
+
+  @override
+  bool get isFinal {
+    if (_unlinkedParam != null) {
+      return false;
+    }
+    return super.isFinal;
+  }
+
+  @override
   bool get isInitializingFormal => false;
 
   @override
@@ -4432,6 +5088,38 @@
   ElementKind get kind => ElementKind.PARAMETER;
 
   @override
+  List<ElementAnnotation> get metadata {
+    if (_unlinkedParam != null) {
+      if (_unlinkedParam.annotations.isEmpty) {
+        return const <ElementAnnotation>[];
+      }
+      return _metadata ??= _unlinkedParam.annotations
+          .map(enclosingUnit.resynthesizerContext.buildAnnotation)
+          .toList();
+    }
+    return super.metadata;
+  }
+
+  @override
+  String get name {
+    if (_unlinkedParam != null) {
+      return _unlinkedParam.name;
+    }
+    return super.name;
+  }
+
+  @override
+  int get nameOffset {
+    if (_unlinkedParam != null) {
+      if (isSynthetic) {
+        return -1;
+      }
+      return _unlinkedParam.nameOffset;
+    }
+    return super.nameOffset;
+  }
+
+  @override
   List<ParameterElement> get parameters => _parameters;
 
   /**
@@ -4461,6 +5149,13 @@
 
   @override
   SourceRange get visibleRange {
+    if (_unlinkedParam != null) {
+      if (_unlinkedParam.visibleLength == 0) {
+        return null;
+      }
+      return new SourceRange(
+          _unlinkedParam.visibleOffset, _unlinkedParam.visibleLength);
+    }
     if (_visibleRangeLength < 0) {
       return null;
     }
@@ -4509,6 +5204,7 @@
    * [offset] with the given [length].
    */
   void setVisibleRange(int offset, int length) {
+    assert(_unlinkedParam == null);
     _visibleRangeOffset = offset;
     _visibleRangeLength = length;
   }
@@ -4603,6 +5299,13 @@
   PropertyAccessorElementImpl.forNode(Identifier name) : super.forNode(name);
 
   /**
+   * Initialize using the given serialized information.
+   */
+  PropertyAccessorElementImpl.forSerialized(
+      UnlinkedExecutable serializedExecutable, ElementImpl enclosingElement)
+      : super.forSerialized(serializedExecutable, enclosingElement);
+
+  /**
    * Initialize a newly created synthetic property accessor element to be
    * associated with the given [variable].
    */
@@ -4617,6 +5320,7 @@
    * Set whether this accessor is abstract.
    */
   void set abstract(bool isAbstract) {
+    assert(serializedExecutable == null);
     setModifier(Modifier.ABSTRACT, isAbstract);
   }
 
@@ -4636,10 +5340,21 @@
     return variable.setter;
   }
 
+  @override
+  String get displayName {
+    if (serializedExecutable != null && isSetter) {
+      String name = serializedExecutable.name;
+      assert(name.endsWith('='));
+      return name.substring(0, name.length - 1);
+    }
+    return super.displayName;
+  }
+
   /**
    * Set whether this accessor is a getter.
    */
   void set getter(bool isGetter) {
+    assert(serializedExecutable == null);
     setModifier(Modifier.GETTER, isGetter);
   }
 
@@ -4654,13 +5369,29 @@
   }
 
   @override
-  bool get isGetter => hasModifier(Modifier.GETTER);
+  bool get isGetter {
+    if (serializedExecutable != null) {
+      return serializedExecutable.kind == UnlinkedExecutableKind.getter;
+    }
+    return hasModifier(Modifier.GETTER);
+  }
 
   @override
-  bool get isSetter => hasModifier(Modifier.SETTER);
+  bool get isSetter {
+    if (serializedExecutable != null) {
+      return serializedExecutable.kind == UnlinkedExecutableKind.setter;
+    }
+    return hasModifier(Modifier.SETTER);
+  }
 
   @override
-  bool get isStatic => hasModifier(Modifier.STATIC);
+  bool get isStatic {
+    if (serializedExecutable != null) {
+      return serializedExecutable.isStatic ||
+          variable is TopLevelVariableElement;
+    }
+    return hasModifier(Modifier.STATIC);
+  }
 
   @override
   ElementKind get kind {
@@ -4672,6 +5403,9 @@
 
   @override
   String get name {
+    if (serializedExecutable != null) {
+      return serializedExecutable.name;
+    }
     if (isSetter) {
       return "${super.name}=";
     }
@@ -4682,6 +5416,7 @@
    * Set whether this accessor is a setter.
    */
   void set setter(bool isSetter) {
+    assert(serializedExecutable == null);
     setModifier(Modifier.SETTER, isSetter);
   }
 
@@ -4689,6 +5424,7 @@
    * Set whether this accessor is static.
    */
   void set static(bool isStatic) {
+    assert(serializedExecutable == null);
     setModifier(Modifier.STATIC, isStatic);
   }
 
@@ -4724,8 +5460,8 @@
 /**
  * A concrete implementation of a [PropertyInducingElement].
  */
-abstract class PropertyInducingElementImpl extends VariableElementImpl
-    implements PropertyInducingElement {
+abstract class PropertyInducingElementImpl
+    extends NonParameterVariableElementImpl implements PropertyInducingElement {
   /**
    * The getter associated with this element.
    */
@@ -4757,6 +5493,32 @@
 }
 
 /**
+ * The context in which elements are resynthesized.
+ */
+abstract class ResynthesizerContext {
+  /**
+   * Build [ElementAnnotationImpl] for the given [UnlinkedConst].
+   */
+  ElementAnnotationImpl buildAnnotation(UnlinkedConst uc);
+
+  /**
+   * Build [Expression] for the given [UnlinkedConst].
+   */
+  Expression buildExpression(UnlinkedConst uc);
+
+  /**
+   * Resolve an [EntityRef] into a type.  If the reference is
+   * unresolved, return [DynamicTypeImpl.instance].
+   *
+   * TODO(paulberry): or should we have a class representing an
+   * unresolved type, for consistency with the full element model?
+   */
+  DartType resolveTypeRef(
+      EntityRef type, TypeParameterizedElementMixin typeParameterContext,
+      {bool defaultVoid: false, bool instantiateToBoundsAllowed: true});
+}
+
+/**
  * A concrete implementation of a [ShowElementCombinator].
  */
 class ShowElementCombinatorImpl implements ShowElementCombinator {
@@ -4829,39 +5591,160 @@
 class TypeParameterElementImpl extends ElementImpl
     implements TypeParameterElement {
   /**
+   * The unlinked representation of the type parameter in the summary.
+   */
+  final UnlinkedTypeParam _unlinkedTypeParam;
+
+  /**
+   * The [TypeParameterizedElement] enclosing this one.
+   */
+  final TypeParameterizedElementMixin _enclosingTypeParameterizedElement;
+
+  /**
+   * The number of type parameters whose scope overlaps this one, and which are
+   * declared earlier in the file.
+   *
+   * TODO(scheglov) make private?
+   */
+  final int nestingLevel;
+
+  /**
    * The type defined by this type parameter.
    */
-  TypeParameterType type;
+  TypeParameterType _type;
 
   /**
    * The type representing the bound associated with this parameter, or `null`
    * if this parameter does not have an explicit bound.
    */
-  DartType bound;
+  DartType _bound;
 
   /**
    * Initialize a newly created method element to have the given [name] and
    * [offset].
    */
-  TypeParameterElementImpl(String name, int offset) : super(name, offset);
+  TypeParameterElementImpl(String name, int offset)
+      : _unlinkedTypeParam = null,
+        nestingLevel = null,
+        _enclosingTypeParameterizedElement = null,
+        super(name, offset);
 
   /**
    * Initialize a newly created type parameter element to have the given [name].
    */
-  TypeParameterElementImpl.forNode(Identifier name) : super.forNode(name);
+  TypeParameterElementImpl.forNode(Identifier name)
+      : _unlinkedTypeParam = null,
+        nestingLevel = null,
+        _enclosingTypeParameterizedElement = null,
+        super.forNode(name);
+
+  /**
+   * Initialize using the given serialized information.
+   */
+  TypeParameterElementImpl.forSerialized(
+      this._unlinkedTypeParam,
+      ElementImpl enclosingElement,
+      this._enclosingTypeParameterizedElement,
+      this.nestingLevel)
+      : super.forSerialized(enclosingElement);
 
   /**
    * Initialize a newly created synthetic type parameter element to have the
    * given [name], and with [synthetic] set to true.
    */
-  TypeParameterElementImpl.synthetic(String name) : super(name, -1) {
+  TypeParameterElementImpl.synthetic(String name)
+      : _unlinkedTypeParam = null,
+        nestingLevel = null,
+        _enclosingTypeParameterizedElement = null,
+        super(name, -1) {
     synthetic = true;
   }
 
+  DartType get bound {
+    if (_unlinkedTypeParam != null) {
+      if (_unlinkedTypeParam.bound == null) {
+        return null;
+      }
+      return _bound ??= enclosingUnit.resynthesizerContext.resolveTypeRef(
+          _unlinkedTypeParam.bound, enclosingElement,
+          instantiateToBoundsAllowed: false);
+    }
+    return _bound;
+  }
+
+  void set bound(DartType bound) {
+    assert(_unlinkedTypeParam == null);
+    _bound = bound;
+  }
+
+  @override
+  int get codeLength {
+    if (_unlinkedTypeParam != null) {
+      return _unlinkedTypeParam.codeRange?.length;
+    }
+    return super.codeLength;
+  }
+
+  @override
+  int get codeOffset {
+    if (_unlinkedTypeParam != null) {
+      return _unlinkedTypeParam.codeRange?.offset;
+    }
+    return super.codeOffset;
+  }
+
+  @override
+  String get displayName => name;
+
+  @override
+  Element get enclosingElement {
+    if (_unlinkedTypeParam != null) {
+      return _enclosingTypeParameterizedElement;
+    }
+    return super.enclosingElement;
+  }
+
   @override
   ElementKind get kind => ElementKind.TYPE_PARAMETER;
 
   @override
+  List<ElementAnnotation> get metadata {
+    if (_unlinkedTypeParam != null) {
+      return _metadata ??= _unlinkedTypeParam.annotations
+          .map(enclosingUnit.resynthesizerContext.buildAnnotation)
+          .toList();
+    }
+    return super.metadata;
+  }
+
+  @override
+  String get name {
+    if (_unlinkedTypeParam != null) {
+      return _unlinkedTypeParam.name;
+    }
+    return super.name;
+  }
+
+  @override
+  int get nameOffset {
+    if (_unlinkedTypeParam != null) {
+      return _unlinkedTypeParam.nameOffset;
+    }
+    return super.nameOffset;
+  }
+
+  TypeParameterType get type {
+    if (_unlinkedTypeParam != null) {
+      _type ??= new TypeParameterTypeImpl(this);
+    }
+    return _type;
+  }
+
+  void set type(TypeParameterType type) {
+    _type = type;
+  }
+
+  @override
   accept(ElementVisitor visitor) => visitor.visitTypeParameterElement(this);
 
   @override
@@ -4875,6 +5758,99 @@
 }
 
 /**
+ * Mixin representing an element which can have type parameters.
+ */
+abstract class TypeParameterizedElementMixin
+    implements TypeParameterizedElement, ElementImpl {
+  List<TypeParameterType> _typeParameterTypes;
+  List<TypeParameterElement> _typeParameterElements;
+  int _nestingLevel;
+
+  /**
+   * Get the type parameter context enclosing this one, if any.
+   */
+  TypeParameterizedElementMixin get enclosingTypeParameterContext;
+
+  /**
+   * The unit in which this element is resynthesized.
+   */
+  CompilationUnitElementImpl get enclosingUnit;
+
+  /**
+   * Find out how many type parameters are in scope in this context.
+   */
+  int get typeParameterNestingLevel =>
+      _nestingLevel ??= unlinkedTypeParams.length +
+          (enclosingTypeParameterContext?.typeParameterNestingLevel ?? 0);
+
+  List<TypeParameterElement> get typeParameters {
+    if (_typeParameterElements == null) {
+      int enclosingNestingLevel =
+          enclosingTypeParameterContext?.typeParameterNestingLevel ?? 0;
+      int numTypeParameters = unlinkedTypeParams.length;
+      _typeParameterElements =
+          new List<TypeParameterElement>(numTypeParameters);
+      for (int i = 0; i < numTypeParameters; i++) {
+        _typeParameterElements[i] = new TypeParameterElementImpl.forSerialized(
+            unlinkedTypeParams[i], this, this, enclosingNestingLevel + i);
+      }
+    }
+    return _typeParameterElements;
+  }
+
+  /**
+   * Get a list of [TypeParameterType] objects corresponding to the
+   * element's type parameters.
+   */
+  List<TypeParameterType> get typeParameterTypes {
+    if (_typeParameterTypes == null) {
+      _typeParameterTypes =
+          typeParameters.map((TypeParameterElement e) => e.type).toList();
+    }
+    return _typeParameterTypes;
+  }
+
+  /**
+   * Get the [UnlinkedTypeParam]s representing the type parameters declared by
+   * this element.
+   *
+   * TODO(scheglov) make private after switching linker to Impl
+   */
+  List<UnlinkedTypeParam> get unlinkedTypeParams;
+
+  /**
+   * Convert the given [index] into a type parameter type.
+   */
+  TypeParameterType getTypeParameterType(int index) {
+    List<TypeParameterType> types = typeParameterTypes;
+    if (index <= types.length) {
+      return types[types.length - index];
+    } else if (enclosingTypeParameterContext != null) {
+      return enclosingTypeParameterContext
+          .getTypeParameterType(index - types.length);
+    } else {
+      // If we get here, it means that a summary contained a type parameter index
+      // that was out of range.
+      throw new RangeError('Invalid type parameter index');
+    }
+  }
+
+  /**
+   * Find out if the given [typeParameter] is in scope in this context.
+   */
+  bool isTypeParameterInScope(TypeParameterElement typeParameter) {
+    if (typeParameter.enclosingElement == this) {
+      return true;
+    } else if (enclosingTypeParameterContext != null) {
+      return enclosingTypeParameterContext
+          .isTypeParameterInScope(typeParameter);
+    } else {
+      return false;
+    }
+  }
+}
+
+/**
  * A concrete implementation of a [UriReferencedElement].
  */
 abstract class UriReferencedElementImpl extends ElementImpl
@@ -4900,6 +5876,12 @@
    * [offset]. The offset may be `-1` if the element is synthetic.
    */
   UriReferencedElementImpl(String name, int offset) : super(name, offset);
+
+  /**
+   * Initialize using the given serialized information.
+   */
+  UriReferencedElementImpl.forSerialized(ElementImpl enclosingElement)
+      : super.forSerialized(enclosingElement);
 }
 
 /**
@@ -4930,6 +5912,12 @@
   VariableElementImpl.forNode(Identifier name) : super.forNode(name);
 
   /**
+   * Initialize using the given serialized information.
+   */
+  VariableElementImpl.forSerialized(ElementImpl enclosingElement)
+      : super.forSerialized(enclosingElement);
+
+  /**
    * Set whether this variable is const.
    */
   void set const3(bool isConst) {
@@ -4948,7 +5936,10 @@
   Expression get constantInitializer => null;
 
   @override
-  DartObject get constantValue => null;
+  DartObject get constantValue => evaluationResult?.value;
+
+  @override
+  String get displayName => name;
 
   /**
    * Return the result of evaluating this variable's initializer as a
@@ -4975,7 +5966,9 @@
   }
 
   @override
-  bool get hasImplicitType => hasModifier(Modifier.IMPLICIT_TYPE);
+  bool get hasImplicitType {
+    return hasModifier(Modifier.IMPLICIT_TYPE);
+  }
 
   /**
    * Set whether this variable element has an implicit type.
@@ -4999,10 +5992,14 @@
   }
 
   @override
-  bool get isConst => hasModifier(Modifier.CONST);
+  bool get isConst {
+    return hasModifier(Modifier.CONST);
+  }
 
   @override
-  bool get isFinal => hasModifier(Modifier.FINAL);
+  bool get isFinal {
+    return hasModifier(Modifier.FINAL);
+  }
 
   @override
   bool get isPotentiallyMutatedInClosure => false;
@@ -5021,6 +6018,9 @@
   }
 
   @override
+  DartObject computeConstantValue() => null;
+
+  @override
   void visitChildren(ElementVisitor visitor) {
     super.visitChildren(visitor);
     _initializer?.accept(visitor);
diff --git a/pkg/analyzer/lib/src/dart/element/handle.dart b/pkg/analyzer/lib/src/dart/element/handle.dart
index b922a4c..0e71499 100644
--- a/pkg/analyzer/lib/src/dart/element/handle.dart
+++ b/pkg/analyzer/lib/src/dart/element/handle.dart
@@ -98,29 +98,67 @@
   List<TypeParameterElement> get typeParameters => actualElement.typeParameters;
 
   @override
-  ConstructorElement get unnamedConstructor => actualElement.unnamedConstructor;
+  ConstructorElement get unnamedConstructor {
+    ensureConstructorsReady();
+    return actualElement.unnamedConstructor;
+  }
 
   @override
   NamedCompilationUnitMember computeNode() => super.computeNode();
 
-  @override
-  FieldElement getField(String fieldName) => actualElement.getField(fieldName);
+  /**
+   * Ensure that [ClassElement.accessors] and [ClassElement.fields] are ready
+   * in [actualElement].
+   */
+  void ensureAccessorsReady() {}
+
+  /**
+   * The method is called by [ClassElementImpl.getImpl] before returning
+   * the [actualElement] as [ClassElementImpl]. At this moment we must ensure
+   * that [ClassElementImpl] is fully complete, we cannot continue filling it
+   * lazily.
+   */
+  void ensureActualElementComplete() {}
+
+  /**
+   * Ensure that [ClassElement.constructors] are ready in [actualElement].
+   */
+  void ensureConstructorsReady() {}
+
+  /**
+   * Ensure that [ClassElement.methods] are ready in [actualElement].
+   */
+  void ensureMethodsReady() {}
 
   @override
-  PropertyAccessorElement getGetter(String getterName) =>
-      actualElement.getGetter(getterName);
+  FieldElement getField(String fieldName) {
+    ensureAccessorsReady();
+    return actualElement.getField(fieldName);
+  }
 
   @override
-  MethodElement getMethod(String methodName) =>
-      actualElement.getMethod(methodName);
+  PropertyAccessorElement getGetter(String getterName) {
+    ensureAccessorsReady();
+    return actualElement.getGetter(getterName);
+  }
 
   @override
-  ConstructorElement getNamedConstructor(String name) =>
-      actualElement.getNamedConstructor(name);
+  MethodElement getMethod(String methodName) {
+    ensureMethodsReady();
+    return actualElement.getMethod(methodName);
+  }
 
   @override
-  PropertyAccessorElement getSetter(String setterName) =>
-      actualElement.getSetter(setterName);
+  ConstructorElement getNamedConstructor(String name) {
+    ensureConstructorsReady();
+    return actualElement.getNamedConstructor(name);
+  }
+
+  @override
+  PropertyAccessorElement getSetter(String setterName) {
+    ensureAccessorsReady();
+    return actualElement.getSetter(setterName);
+  }
 
   @override
   bool isSuperConstructorAccessible(ConstructorElement constructor) =>
@@ -128,8 +166,10 @@
 
   @override
   MethodElement lookUpConcreteMethod(
-          String methodName, LibraryElement library) =>
-      actualElement.lookUpConcreteMethod(methodName, library);
+      String methodName, LibraryElement library) {
+    ensureMethodsReady();
+    return actualElement.lookUpConcreteMethod(methodName, library);
+  }
 
   @override
   PropertyAccessorElement lookUpGetter(
@@ -138,32 +178,44 @@
 
   @override
   PropertyAccessorElement lookUpInheritedConcreteGetter(
-          String methodName, LibraryElement library) =>
-      actualElement.lookUpInheritedConcreteGetter(methodName, library);
+      String methodName, LibraryElement library) {
+    ensureAccessorsReady();
+    return actualElement.lookUpInheritedConcreteGetter(methodName, library);
+  }
 
   @override
   MethodElement lookUpInheritedConcreteMethod(
-          String methodName, LibraryElement library) =>
-      actualElement.lookUpInheritedConcreteMethod(methodName, library);
+      String methodName, LibraryElement library) {
+    ensureMethodsReady();
+    return actualElement.lookUpInheritedConcreteMethod(methodName, library);
+  }
 
   @override
   PropertyAccessorElement lookUpInheritedConcreteSetter(
-          String methodName, LibraryElement library) =>
-      actualElement.lookUpInheritedConcreteSetter(methodName, library);
+      String methodName, LibraryElement library) {
+    ensureAccessorsReady();
+    return actualElement.lookUpInheritedConcreteSetter(methodName, library);
+  }
 
   @override
   MethodElement lookUpInheritedMethod(
-          String methodName, LibraryElement library) =>
-      actualElement.lookUpInheritedMethod(methodName, library);
+      String methodName, LibraryElement library) {
+    ensureMethodsReady();
+    return actualElement.lookUpInheritedMethod(methodName, library);
+  }
 
   @override
-  MethodElement lookUpMethod(String methodName, LibraryElement library) =>
-      actualElement.lookUpMethod(methodName, library);
+  MethodElement lookUpMethod(String methodName, LibraryElement library) {
+    ensureMethodsReady();
+    return actualElement.lookUpMethod(methodName, library);
+  }
 
   @override
   PropertyAccessorElement lookUpSetter(
-          String setterName, LibraryElement library) =>
-      actualElement.lookUpSetter(setterName, library);
+      String setterName, LibraryElement library) {
+    ensureAccessorsReady();
+    return actualElement.lookUpSetter(setterName, library);
+  }
 }
 
 /**
@@ -415,7 +467,8 @@
   AstNode computeNode() => actualElement.computeNode();
 
   @override
-  Element getAncestor(Predicate<Element> predicate) =>
+  Element/*=E*/ getAncestor/*<E extends Element >*/(
+          Predicate<Element> predicate) =>
       actualElement.getAncestor(predicate);
 
   @override
@@ -1111,4 +1164,7 @@
 
   @override
   DartType get type => actualElement.type;
+
+  @override
+  DartObject computeConstantValue() => actualElement.computeConstantValue();
 }
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index efb778f..025c7c5 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -515,7 +515,7 @@
   AstNode computeNode() => _baseElement.computeNode();
 
   @override
-  Element getAncestor(Predicate<Element> predicate) =>
+  Element/*=E*/ getAncestor/*<E extends Element >*/(Predicate<Element> predicate) =>
       baseElement.getAncestor(predicate);
 
   @override
@@ -700,20 +700,19 @@
   FormalParameter computeNode() => baseElement.computeNode();
 
   @override
-  Element getAncestor(Predicate<Element> predicate) {
+  Element/*=E*/ getAncestor/*<E extends Element>*/(Predicate<Element> predicate) {
     Element element = baseElement.getAncestor(predicate);
     ParameterizedType definingType = this.definingType;
     if (definingType is InterfaceType) {
-      InterfaceType definingInterfaceType = definingType;
       if (element is ConstructorElement) {
-        return ConstructorMember.from(element, definingInterfaceType);
+        return ConstructorMember.from(element, definingType) as Element/*=E*/;
       } else if (element is MethodElement) {
-        return MethodMember.from(element, definingInterfaceType);
+        return MethodMember.from(element, definingType) as Element/*=E*/;
       } else if (element is PropertyAccessorElement) {
-        return PropertyAccessorMember.from(element, definingInterfaceType);
+        return PropertyAccessorMember.from(element, definingType) as Element/*=E*/;
       }
     }
-    return element;
+    return element as Element/*=E*/;
   }
 
   @override
@@ -1036,6 +1035,9 @@
   bool get isStatic => baseElement.isStatic;
 
   @override
+  DartObject computeConstantValue() => baseElement.computeConstantValue();
+
+  @override
   void visitChildren(ElementVisitor visitor) {
     // TODO(brianwilkerson) We need to finish implementing the accessors used
     // below so that we can safely invoke them.
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index f2e9a15..42c8498 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -1139,6 +1139,21 @@
   final List<FunctionTypeAliasElement> prunedTypedefs;
 
   /**
+   * Cached [ConstructorElement]s - members or raw elements.
+   */
+  List<ConstructorElement> _constructors;
+
+  /**
+   * Cached [PropertyAccessorElement]s - members or raw elements.
+   */
+  List<PropertyAccessorElement> _accessors;
+
+  /**
+   * Cached [MethodElement]s - members or raw elements.
+   */
+  List<MethodElement> _methods;
+
+  /**
    * Initialize a newly created type to be declared by the given [element].
    */
   InterfaceTypeImpl(ClassElement element, [this.prunedTypedefs])
@@ -1169,26 +1184,34 @@
   InterfaceTypeImpl._(Element element, String name, this.prunedTypedefs)
       : super(element, name);
 
+
   @override
   List<PropertyAccessorElement> get accessors {
-    List<PropertyAccessorElement> accessors = element.accessors;
-    List<PropertyAccessorElement> members =
-        new List<PropertyAccessorElement>(accessors.length);
-    for (int i = 0; i < accessors.length; i++) {
-      members[i] = PropertyAccessorMember.from(accessors[i], this);
+    if (_accessors == null) {
+      List<PropertyAccessorElement> accessors = element.accessors;
+      List<PropertyAccessorElement> members =
+      new List<PropertyAccessorElement>(accessors.length);
+      for (int i = 0; i < accessors.length; i++) {
+        members[i] = PropertyAccessorMember.from(accessors[i], this);
+      }
+      _accessors = members;
     }
-    return members;
+    return _accessors;
   }
 
+
   @override
   List<ConstructorElement> get constructors {
-    List<ConstructorElement> constructors = element.constructors;
-    List<ConstructorElement> members =
-        new List<ConstructorElement>(constructors.length);
-    for (int i = 0; i < constructors.length; i++) {
-      members[i] = ConstructorMember.from(constructors[i], this);
+    if (_constructors == null) {
+      List<ConstructorElement> constructors = element.constructors;
+      List<ConstructorElement> members =
+          new List<ConstructorElement>(constructors.length);
+      for (int i = 0; i < constructors.length; i++) {
+        members[i] = ConstructorMember.from(constructors[i], this);
+      }
+      _constructors = members;
     }
-    return members;
+    return _constructors;
   }
 
   @override
@@ -1273,12 +1296,15 @@
 
   @override
   List<MethodElement> get methods {
-    List<MethodElement> methods = element.methods;
-    List<MethodElement> members = new List<MethodElement>(methods.length);
-    for (int i = 0; i < methods.length; i++) {
-      members[i] = MethodMember.from(methods[i], this);
+    if (_methods == null) {
+      List<MethodElement> methods = element.methods;
+      List<MethodElement> members = new List<MethodElement>(methods.length);
+      for (int i = 0; i < methods.length; i++) {
+        members[i] = MethodMember.from(methods[i], this);
+      }
+      _methods = members;
     }
-    return members;
+    return _methods;
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/error/pending_error.dart b/pkg/analyzer/lib/src/error/pending_error.dart
new file mode 100644
index 0000000..6562166
--- /dev/null
+++ b/pkg/analyzer/lib/src/error/pending_error.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2016, 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 analyzer.src.error.pending_error;
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/generated/constant.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+/**
+ * A pending error is an analysis error that could not be reported at the time
+ * it was discovered because some piece of information might be missing. After
+ * the information has been computed, the pending error can be converted into a
+ * real error.
+ */
+abstract class PendingError {
+  /**
+   * Create an analysis error based on the information in the pending error.
+   */
+  AnalysisError toAnalysisError();
+}
+
+/**
+ * A pending error used to compute either a [HintCode.MISSING_REQUIRED_PARAM] or
+ * [HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS] analysis error. These errors
+ * require that the value of the `@required` annotation be computed, which is
+ * not always true when the error is discovered.
+ */
+class PendingMissingRequiredParameterError implements PendingError {
+  /**
+   * The source against which the error will be reported.
+   */
+  final Source source;
+
+  /**
+   * The name of the parameter that is required.
+   */
+  final String parameterName;
+
+  /**
+   * The offset of the name of the method / function at the invocation site.
+   */
+  final int offset;
+
+  /**
+   * The length of the name of the method / function at the invocation site.
+   */
+  final int length;
+
+  /**
+   * The `@required` annotation whose value is used to compose the error message.
+   */
+  final ElementAnnotation annotation;
+
+  /**
+   * Initialize a newly created pending error.
+   */
+  PendingMissingRequiredParameterError(
+      this.source, this.parameterName, AstNode node, this.annotation)
+      : offset = node.offset,
+        length = node.length;
+
+  @override
+  AnalysisError toAnalysisError() {
+    HintCode errorCode;
+    List<String> arguments;
+    DartObject constantValue = annotation.constantValue;
+    String reason = constantValue?.getField('reason')?.toStringValue();
+    if (reason != null) {
+      errorCode = HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS;
+      arguments = [parameterName, reason];
+    } else {
+      errorCode = HintCode.MISSING_REQUIRED_PARAM;
+      arguments = [parameterName];
+    }
+    return new AnalysisError(source, offset, length, errorCode, arguments);
+  }
+}
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 8db8ee0..972043a 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -729,11 +729,16 @@
   static const String SUFFIX_HTML = "html";
 
   /**
-   * The file name used for analysis options files.
+   * The deprecated file name used for analysis options files.
    */
   static const String ANALYSIS_OPTIONS_FILE = '.analysis_options';
 
   /**
+   * The file name used for analysis options files.
+   */
+  static const String ANALYSIS_OPTIONS_YAML_FILE = 'analysis_options.yaml';
+
+  /**
    * The unique instance of this class.
    */
   static final AnalysisEngine instance = new AnalysisEngine._();
@@ -876,8 +881,9 @@
     if (fileName == null) {
       return false;
     }
-    return (context ?? pathos.posix).basename(fileName) ==
-        ANALYSIS_OPTIONS_FILE;
+    String basename = (context ?? pathos.posix).basename(fileName);
+    return basename == ANALYSIS_OPTIONS_FILE ||
+        basename == ANALYSIS_OPTIONS_YAML_FILE;
   }
 
   /**
diff --git a/pkg/analyzer/lib/src/generated/error.dart b/pkg/analyzer/lib/src/generated/error.dart
index 5d0cee2..c21e7e6 100644
--- a/pkg/analyzer/lib/src/generated/error.dart
+++ b/pkg/analyzer/lib/src/generated/error.dart
@@ -50,7 +50,7 @@
 
   /**
    * A [Comparator] that sorts error codes first by their severity (errors
-   * first, warnings second), and then by the the error code type.
+   * first, warnings second), and then by the error code type.
    */
   static Comparator<AnalysisError> ERROR_CODE_COMPARATOR =
       (AnalysisError o1, AnalysisError o2) {
@@ -3595,7 +3595,8 @@
    * 1: message details
    */
   static const HintCode MISSING_REQUIRED_PARAM_WITH_DETAILS = const HintCode(
-      'MISSING_REQUIRED_PARAM', "The parameter '{0}' is required. {1}");
+      'MISSING_REQUIRED_PARAM_WITH_DETAILS',
+      "The parameter '{0}' is required. {1}");
 
   /**
    * Generate a hint for an element that is annotated with `@JS(...)` whose
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 537ca31..d201e96 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -18,6 +18,7 @@
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
+import 'package:analyzer/src/error/pending_error.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/element_resolver.dart';
 import 'package:analyzer/src/generated/engine.dart';
@@ -26,7 +27,9 @@
 import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/sdk.dart' show DartSdk, SdkLibrary;
+import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/task/dart.dart';
 import 'package:analyzer/src/task/strong/info.dart' show StaticInfo;
 
 /**
@@ -829,8 +832,6 @@
       if (type is InterfaceType) {
         _checkForConstOrNewWithAbstractClass(node, typeName, type);
         _checkForConstOrNewWithEnum(node, typeName, type);
-        _checkForMissingRequiredParam(
-            node.staticElement?.type, node.argumentList, node.constructorName);
         if (_isInConstInstanceCreation) {
           _checkForConstWithNonConst(node);
           _checkForConstWithUndefinedConstructor(
@@ -942,8 +943,6 @@
     } else {
       _checkForUnqualifiedReferenceToNonLocalStaticMember(methodName);
     }
-    _checkForMissingRequiredParam(
-        node.staticInvokeType, node.argumentList, methodName);
     _checkTypeArguments(
         node.methodName.staticElement, node.typeArguments, target?.staticType);
     return super.visitMethodInvocation(node);
@@ -4246,34 +4245,6 @@
     }
   }
 
-  void _checkForMissingRequiredParam(
-      DartType type, ArgumentList argumentList, AstNode node) {
-    if (type is FunctionType) {
-      List<ParameterElement> parameters = type.parameters;
-      for (ParameterElement param in parameters) {
-        if (param.parameterKind == ParameterKind.NAMED) {
-          ElementAnnotationImpl annotation = _getRequiredAnnotation(param);
-          if (annotation != null) {
-            String paramName = param.name;
-            if (!_containsNamedExpression(argumentList, paramName)) {
-              DartObject constantValue = annotation.constantValue;
-              String reason = constantValue.getField('reason')?.toStringValue();
-              if (reason != null) {
-                _errorReporter.reportErrorForNode(
-                    HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS,
-                    node,
-                    [paramName, reason]);
-              } else {
-                _errorReporter.reportErrorForNode(
-                    HintCode.MISSING_REQUIRED_PARAM, node, [paramName]);
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
   /**
    * Verify that the given function [body] does not contain return statements
    * that both have and do not have return values.
@@ -5040,7 +5011,7 @@
   }
 
   /**
-   * Check that if the the given constructor [declaration] is generative, then
+   * Check that if the given constructor [declaration] is generative, then
    * it does not have an expression function body.
    *
    * See [CompileTimeErrorCode.RETURN_IN_GENERATIVE_CONSTRUCTOR].
@@ -5235,8 +5206,8 @@
       NodeList<TypeName> typeNameArgList = typeName.typeArguments.arguments;
       int loopThroughIndex =
           math.min(typeNameArgList.length, parameterElements.length);
-      bool shouldSubstitute = arguments.length != 0 &&
-          arguments.length == parameterTypes.length;
+      bool shouldSubstitute =
+          arguments.length != 0 && arguments.length == parameterTypes.length;
       for (int i = 0; i < loopThroughIndex; i++) {
         TypeName argTypeName = typeNameArgList[i];
         DartType argType = argTypeName.type;
@@ -5760,17 +5731,6 @@
     return staticReturnType;
   }
 
-  bool _containsNamedExpression(ArgumentList args, String name) {
-    for (Expression expression in args.arguments) {
-      if (expression is NamedExpression) {
-        if (expression.name.label.name == name) {
-          return true;
-        }
-      }
-    }
-    return false;
-  }
-
   bool _expressionIsAssignableAtType(Expression expression,
       DartType actualStaticType, DartType expectedStaticType) {
     bool concrete =
@@ -5864,10 +5824,6 @@
     return _inheritanceManager.lookupInheritance(classElement, member.name);
   }
 
-  ElementAnnotationImpl _getRequiredAnnotation(ParameterElement param) => param
-      .metadata
-      .firstWhere((ElementAnnotation e) => e.isRequired, orElse: () => null);
-
   /**
    * Return the type of the first and only parameter of the given [setter].
    */
@@ -6228,6 +6184,88 @@
 }
 
 /**
+ * A class used to compute a list of the constants whose value needs to be
+ * computed before errors can be computed by the [VerifyUnitTask].
+ */
+class RequiredConstantsComputer extends RecursiveAstVisitor {
+  /**
+   * The source with which any pending errors will be associated.
+   */
+  final Source source;
+
+  /**
+   * A list of the pending errors that were computed.
+   */
+  final List<PendingError> pendingErrors = <PendingError>[];
+
+  /**
+   * A list of the constants whose value needs to be computed before the pending
+   * errors can be used to compute an analysis error.
+   */
+  final List<ConstantEvaluationTarget> requiredConstants =
+      <ConstantEvaluationTarget>[];
+
+  /**
+   * Initialize a newly created computer to compute required constants within
+   * the given [source].
+   */
+  RequiredConstantsComputer(this.source);
+
+  @override
+  Object visitInstanceCreationExpression(InstanceCreationExpression node) {
+    DartType type = node.constructorName.type.type;
+    if (type is InterfaceType) {
+      _checkForMissingRequiredParam(
+          node.staticElement?.type, node.argumentList, node.constructorName);
+    }
+    return super.visitInstanceCreationExpression(node);
+  }
+
+  @override
+  Object visitMethodInvocation(MethodInvocation node) {
+    _checkForMissingRequiredParam(
+        node.staticInvokeType, node.argumentList, node.methodName);
+    return super.visitMethodInvocation(node);
+  }
+
+  void _checkForMissingRequiredParam(
+      DartType type, ArgumentList argumentList, AstNode node) {
+    if (type is FunctionType) {
+      for (ParameterElement parameter in type.parameters) {
+        if (parameter.parameterKind == ParameterKind.NAMED) {
+          ElementAnnotationImpl annotation = _getRequiredAnnotation(parameter);
+          if (annotation != null) {
+            String parameterName = parameter.name;
+            if (!_containsNamedExpression(argumentList, parameterName)) {
+              requiredConstants.add(annotation);
+              pendingErrors.add(new PendingMissingRequiredParameterError(
+                  source, parameterName, node, annotation));
+            }
+          }
+        }
+      }
+    }
+  }
+
+  bool _containsNamedExpression(ArgumentList args, String name) {
+    NodeList<Expression> arguments = args.arguments;
+    for (int i = arguments.length - 1; i >= 0; i--) {
+      Expression expression = arguments[i];
+      if (expression is NamedExpression) {
+        if (expression.name.label.name == name) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  ElementAnnotationImpl _getRequiredAnnotation(ParameterElement param) => param
+      .metadata
+      .firstWhere((ElementAnnotation e) => e.isRequired, orElse: () => null);
+}
+
+/**
  * Recursively visits an AST, looking for method invocations.
  */
 class _InvocationCollector extends RecursiveAstVisitor {
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 777d130..7f9657f 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -3577,17 +3577,17 @@
     bool outerBreakValue = _enclosingBlockContainsBreak;
     _enclosingBlockContainsBreak = false;
     try {
+      if (_nodeExits(node.body)) {
+        return true;
+      }
       Expression conditionExpression = node.condition;
       if (_nodeExits(conditionExpression)) {
         return true;
       }
       // TODO(jwren) Do we want to take all constant expressions into account?
       if (conditionExpression is BooleanLiteral) {
-        // If do {} while (true), and the body doesn't return or the body
-        // doesn't have a break, then return true.
-        bool blockReturns = _nodeExits(node.body);
-        if (conditionExpression.value &&
-            (blockReturns || !_enclosingBlockContainsBreak)) {
+        // If do {} while (true), and the body doesn't break, then return true.
+        if (conditionExpression.value && !_enclosingBlockContainsBreak) {
           return true;
         }
       }
diff --git a/pkg/analyzer/lib/src/generated/sdk_io.dart b/pkg/analyzer/lib/src/generated/sdk_io.dart
index 9bf52bf..0d053f6b 100644
--- a/pkg/analyzer/lib/src/generated/sdk_io.dart
+++ b/pkg/analyzer/lib/src/generated/sdk_io.dart
@@ -284,8 +284,9 @@
       if (_useSummary) {
         PackageBundle sdkBundle = getSummarySdkBundle();
         if (sdkBundle != null) {
-          _analysisContext.resultProvider =
-              new SdkSummaryResultProvider(_analysisContext, sdkBundle);
+          bool strongMode = _analysisOptions?.strongMode ?? false;
+          _analysisContext.resultProvider = new SdkSummaryResultProvider(
+              _analysisContext, sdkBundle, strongMode);
         }
       }
     }
@@ -414,6 +415,11 @@
   List<String> get uris => _libraryMap.uris;
 
   /**
+   * Whether an SDK summary should be used.
+   */
+  bool get useSummary => _useSummary;
+
+  /**
    * Specify whether SDK summary should be used.
    */
   void set useSummary(bool use) {
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 3032565..4ba4c51 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -441,7 +441,7 @@
   /**
    * Get the contents and timestamp of this source.
    *
-   * Clients should consider using the the method [AnalysisContext.getContents]
+   * Clients should consider using the method [AnalysisContext.getContents]
    * because contexts can have local overrides of the content of a source that the source is not
    * aware of.
    *
@@ -492,7 +492,7 @@
    * will be returned, but if the contents of the source have been modified one
    * or more times (even if the net change is zero) the stamps will be different.
    *
-   * Clients should consider using the the method
+   * Clients should consider using the method
    * [AnalysisContext.getModificationStamp] because contexts can have local
    * overrides of the content of a source that the source is not aware of.
    */
@@ -541,7 +541,7 @@
   /**
    * Return `true` if this source exists.
    *
-   * Clients should consider using the the method [AnalysisContext.exists] because
+   * Clients should consider using the method [AnalysisContext.exists] because
    * contexts can have local overrides of the content of a source that the source is not aware of
    * and a source with local content is considered to exist even if there is no file on disk.
    *
diff --git a/pkg/analyzer/lib/src/generated/source_io.dart b/pkg/analyzer/lib/src/generated/source_io.dart
index 5b25c2c..491e3eb 100644
--- a/pkg/analyzer/lib/src/generated/source_io.dart
+++ b/pkg/analyzer/lib/src/generated/source_io.dart
@@ -191,7 +191,7 @@
   /**
    * Get the contents and timestamp of the underlying file.
    *
-   * Clients should consider using the the method [AnalysisContext.getContents]
+   * Clients should consider using the method [AnalysisContext.getContents]
    * because contexts can have local overrides of the content of a source that the source is not
    * aware of.
    *
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index 877944a..19b5be5 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -752,7 +752,7 @@
    *    to #2.
    *
    * It's not immediately obvious why this is symmetric in the case that both
-   * of the them are type parameters.  For #1, symmetry holds since subtype
+   * of them are type parameters.  For #1, symmetry holds since subtype
    * is antisymmetric.  For #2, it's clearly not symmetric if upper bounds of
    * bottom are allowed.  Ignoring this (for various reasons, not least
    * of which that there's no way to write it), there's an informal
@@ -1330,18 +1330,13 @@
     if (t1 is TypeParameterType) {
       _TypeParameterBound bound = _bounds[t1];
       if (bound != null) {
-        _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf);
-
-        DartType newUpper = t2;
-        if (guardedSubtype(bound.upper, newUpper, visited)) {
-          // upper bound already covers this. Nothing to do.
-        } else if (guardedSubtype(newUpper, bound.upper, visited)) {
-          // update to the new, more precise upper bound.
-          bound.upper = newUpper;
-        } else {
-          // Failed to find an upper bound. Use bottom to signal no solution.
-          bound.upper = BottomTypeImpl.instance;
-        }
+        // Ensure T1 <: T2, where T1 is a type parameter we are inferring.
+        // T2 is an upper bound, so merge it with our existing upper bound.
+        //
+        // We already know T1 <: U, for some U.
+        // So update U to reflect the new constraint T1 <: GLB(U, T2)
+        //
+        bound.upper = getGreatestLowerBound(_typeProvider, bound.upper, t2);
         // Optimistically assume we will be able to satisfy the constraint.
         return true;
       }
@@ -1349,6 +1344,12 @@
     if (t2 is TypeParameterType) {
       _TypeParameterBound bound = _bounds[t2];
       if (bound != null) {
+        // Ensure T1 <: T2, where T2 is a type parameter we are inferring.
+        // T1 is a lower bound, so merge it with our existing lower bound.
+        //
+        // We already know L <: T2, for some L.
+        // So update L to reflect the new constraint LUB(L, T1) <: T2
+        //
         bound.lower = getLeastUpperBound(_typeProvider, bound.lower, t1);
         // Optimistically assume we will be able to satisfy the constraint.
         return true;
@@ -1430,7 +1431,7 @@
   void _visitFunctionType(
       TypeParameterType typeParam, FunctionType type, bool paramIn) {
     for (ParameterElement p in type.parameters) {
-      // If a lambda L is passed in to a function F, the the parameters are
+      // If a lambda L is passed in to a function F, the parameters are
       // "passed out" of F into L. Thus we invert the "passedIn" state.
       _visitType(typeParam, p.type, !paramIn);
     }
diff --git a/pkg/analyzer/lib/src/plugin/command_line_plugin.dart b/pkg/analyzer/lib/src/plugin/command_line_plugin.dart
index ffd43be..b2f8c58 100644
--- a/pkg/analyzer/lib/src/plugin/command_line_plugin.dart
+++ b/pkg/analyzer/lib/src/plugin/command_line_plugin.dart
@@ -33,12 +33,12 @@
    * The extension point that allows plugins to register new parser
    * contributors.
    */
-  ExtensionPoint parserContributorExtensionPoint;
+  ExtensionPoint<ArgParserContributor> parserContributorExtensionPoint;
 
   /**
    * The extension point that allows plugins to register new result processors.
    */
-  ExtensionPoint resultProcessorExtensionPoint;
+  ExtensionPoint<ArgResultsProcessor> resultProcessorExtensionPoint;
 
   /**
    * Initialize a newly created plugin.
@@ -64,39 +64,16 @@
 
   @override
   void registerExtensionPoints(RegisterExtensionPoint registerExtensionPoint) {
-    parserContributorExtensionPoint = registerExtensionPoint(
-        PARSER_CONTRIBUTOR_EXTENSION_POINT,
-        _validateParserContributorExtension);
-    resultProcessorExtensionPoint = registerExtensionPoint(
-        RESULT_PROCESSOR_EXTENSION_POINT, _validateResultProcessorExtension);
+    parserContributorExtensionPoint = new ExtensionPoint<ArgParserContributor>(
+        this, PARSER_CONTRIBUTOR_EXTENSION_POINT, null);
+    registerExtensionPoint(parserContributorExtensionPoint);
+    resultProcessorExtensionPoint = new ExtensionPoint<ArgResultsProcessor>(
+        this, RESULT_PROCESSOR_EXTENSION_POINT, null);
+    registerExtensionPoint(resultProcessorExtensionPoint);
   }
 
   @override
   void registerExtensions(RegisterExtension registerExtension) {
     // There are no default extensions.
   }
-
-  /**
-   * Validate the given extension by throwing an [ExtensionError] if it is not a
-   * valid parser contributor.
-   */
-  void _validateParserContributorExtension(Object extension) {
-    if (extension is! ArgParserContributor) {
-      String id = parserContributorExtensionPoint.uniqueIdentifier;
-      throw new ExtensionError(
-          'Extensions to $id must be an ArgParserContributor');
-    }
-  }
-
-  /**
-   * Validate the given extension by throwing an [ExtensionError] if it is not a
-   * valid result processor.
-   */
-  void _validateResultProcessorExtension(Object extension) {
-    if (extension is! ArgResultsProcessor) {
-      String id = resultProcessorExtensionPoint.uniqueIdentifier;
-      throw new ExtensionError(
-          'Extensions to $id must be an ArgResultsProcessor');
-    }
-  }
 }
diff --git a/pkg/analyzer/lib/src/plugin/engine_plugin.dart b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
index 69b74c6..8e47707 100644
--- a/pkg/analyzer/lib/src/plugin/engine_plugin.dart
+++ b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
@@ -66,31 +66,33 @@
    * The extension point that allows plugins to register new analysis error
    * results for a Dart source.
    */
-  ExtensionPoint dartErrorsForSourceExtensionPoint;
+  ExtensionPoint<ListResultDescriptor<AnalysisError>>
+      dartErrorsForSourceExtensionPoint;
 
   /**
    * The extension point that allows plugins to register new analysis error
    * results for a Dart library specific unit.
    */
-  ExtensionPoint dartErrorsForUnitExtensionPoint;
+  ExtensionPoint<ListResultDescriptor<AnalysisError>>
+      dartErrorsForUnitExtensionPoint;
 
   /**
    * The extension point that allows plugins to register new analysis error
    * results for an HTML source.
    */
-  ExtensionPoint htmlErrorsExtensionPoint;
+  ExtensionPoint<ListResultDescriptor<AnalysisError>> htmlErrorsExtensionPoint;
 
   /**
    * The extension point that allows plugins to register new analysis tasks with
    * the analysis engine.
    */
-  ExtensionPoint taskExtensionPoint;
+  ExtensionPoint<TaskDescriptor> taskExtensionPoint;
 
   /**
    * The extension point that allows plugins to register new work manager
    * factories with the analysis engine.
    */
-  ExtensionPoint workManagerFactoryExtensionPoint;
+  ExtensionPoint<WorkManagerFactory> workManagerFactoryExtensionPoint;
 
   /**
    * Initialize a newly created plugin.
@@ -137,20 +139,24 @@
 
   @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);
+    dartErrorsForSourceExtensionPoint =
+        new ExtensionPoint<ListResultDescriptor<AnalysisError>>(
+            this, DART_ERRORS_FOR_SOURCE_EXTENSION_POINT, null);
+    registerExtensionPoint(dartErrorsForSourceExtensionPoint);
+    dartErrorsForUnitExtensionPoint =
+        new ExtensionPoint<ListResultDescriptor<AnalysisError>>(
+            this, DART_ERRORS_FOR_UNIT_EXTENSION_POINT, null);
+    registerExtensionPoint(dartErrorsForUnitExtensionPoint);
+    htmlErrorsExtensionPoint =
+        new ExtensionPoint<ListResultDescriptor<AnalysisError>>(
+            this, HTML_ERRORS_EXTENSION_POINT, null);
+    registerExtensionPoint(htmlErrorsExtensionPoint);
     taskExtensionPoint =
-        registerExtensionPoint(TASK_EXTENSION_POINT, _validateTaskExtension);
-    workManagerFactoryExtensionPoint = registerExtensionPoint(
-        WORK_MANAGER_FACTORY_EXTENSION_POINT,
-        _validateWorkManagerFactoryExtension);
+        new ExtensionPoint<TaskDescriptor>(this, TASK_EXTENSION_POINT, null);
+    registerExtensionPoint(taskExtensionPoint);
+    workManagerFactoryExtensionPoint = new ExtensionPoint<WorkManagerFactory>(
+        this, WORK_MANAGER_FACTORY_EXTENSION_POINT, null);
+    registerExtensionPoint(workManagerFactoryExtensionPoint);
   }
 
   @override
@@ -198,6 +204,7 @@
     registerExtension(
         taskId, ComputeInferableStaticVariableDependenciesTask.DESCRIPTOR);
     registerExtension(taskId, ComputeLibraryCycleTask.DESCRIPTOR);
+    registerExtension(taskId, ComputeRequiredConstantsTask.DESCRIPTOR);
     registerExtension(
         taskId, ComputePropagableVariableDependenciesTask.DESCRIPTOR);
     registerExtension(taskId, ContainingLibrariesTask.DESCRIPTOR);
@@ -259,41 +266,6 @@
     registerExtension(taskId,
         (InternalAnalysisContext context) => new OptionsWorkManager(context));
   }
-
-  /**
-   * 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) {
-      String id = taskExtensionPoint.uniqueIdentifier;
-      throw new ExtensionError('Extensions to $id must be a TaskDescriptor');
-    }
-  }
-
-  /**
-   * Validate the given extension by throwing an [ExtensionError] if it is not
-   * a [WorkManagerFactory].
-   */
-  void _validateWorkManagerFactoryExtension(Object extension) {
-    if (extension is! WorkManagerFactory) {
-      String id = taskExtensionPoint.uniqueIdentifier;
-      throw new ExtensionError(
-          'Extensions to $id must be a WorkManagerFactory');
-    }
-  }
 }
 
 /**
diff --git a/pkg/analyzer/lib/src/plugin/options_plugin.dart b/pkg/analyzer/lib/src/plugin/options_plugin.dart
index 9a4fc01..aceaf3b 100644
--- a/pkg/analyzer/lib/src/plugin/options_plugin.dart
+++ b/pkg/analyzer/lib/src/plugin/options_plugin.dart
@@ -26,31 +26,31 @@
 
   /// The extension point that allows plugins to register new options
   /// processors.
-  ExtensionPoint optionsProcessorExtensionPoint;
+  ExtensionPoint<OptionsProcessor> optionsProcessorExtensionPoint;
 
   /// The extension point that allows plugins to register new options
   /// validators.
-  ExtensionPoint optionsValidatorExtensionPoint;
+  ExtensionPoint<OptionsValidator> optionsValidatorExtensionPoint;
 
   /// All contributed options processors.
   List<OptionsProcessor> get optionsProcessors =>
-      optionsProcessorExtensionPoint?.extensions as List<OptionsProcessor> ??
-      const <OptionsProcessor>[];
+      optionsProcessorExtensionPoint?.extensions ?? const <OptionsProcessor>[];
 
   /// All contributed options validators.
   List<OptionsValidator> get optionsValidators =>
-      optionsValidatorExtensionPoint?.extensions as List<OptionsValidator> ??
-      const <OptionsValidator>[];
+      optionsValidatorExtensionPoint?.extensions ?? const <OptionsValidator>[];
 
   @override
   String get uniqueIdentifier => UNIQUE_IDENTIFIER;
 
   @override
   void registerExtensionPoints(RegisterExtensionPoint registerExtensionPoint) {
-    optionsProcessorExtensionPoint = registerExtensionPoint(
-        OPTIONS_PROCESSOR_EXTENSION_POINT, _validateOptionsProcessorExtension);
-    optionsValidatorExtensionPoint = registerExtensionPoint(
-        OPTIONS_VALIDATOR_EXTENSION_POINT, _validateOptionsValidatorExtension);
+    optionsProcessorExtensionPoint = new ExtensionPoint<OptionsProcessor>(
+        this, OPTIONS_PROCESSOR_EXTENSION_POINT, null);
+    registerExtensionPoint(optionsProcessorExtensionPoint);
+    optionsValidatorExtensionPoint = new ExtensionPoint<OptionsValidator>(
+        this, OPTIONS_VALIDATOR_EXTENSION_POINT, null);
+    registerExtensionPoint(optionsValidatorExtensionPoint);
   }
 
   @override
@@ -62,22 +62,4 @@
     registerExtension(
         OPTIONS_VALIDATOR_EXTENSION_POINT_ID, new AnalyzerOptionsValidator());
   }
-
-  /// Validate the given extension by throwing an [ExtensionError] if it is not
-  /// a valid options processor.
-  void _validateOptionsProcessorExtension(Object extension) {
-    if (extension is! OptionsProcessor) {
-      String id = optionsProcessorExtensionPoint.uniqueIdentifier;
-      throw new ExtensionError('Extensions to $id must be an OptionsProcessor');
-    }
-  }
-
-  /// Validate the given extension by throwing an [ExtensionError] if it is not
-  /// a valid options validator.
-  void _validateOptionsValidatorExtension(Object extension) {
-    if (extension is! OptionsValidator) {
-      String id = optionsValidatorExtensionPoint.uniqueIdentifier;
-      throw new ExtensionError('Extensions to $id must be an OptionsValidator');
-    }
-  }
 }
diff --git a/pkg/analyzer/lib/src/services/lint.dart b/pkg/analyzer/lib/src/services/lint.dart
index 3b36457..3eea1b7 100644
--- a/pkg/analyzer/lib/src/services/lint.dart
+++ b/pkg/analyzer/lib/src/services/lint.dart
@@ -25,8 +25,7 @@
 /// Return lints associated with this [context], or an empty list if there are
 /// none.
 List<Linter> getLints(AnalysisContext context) =>
-    context.getConfigurationData(CONFIGURED_LINTS_KEY) as List<Linter> ??
-    _noLints;
+    context.getConfigurationData(CONFIGURED_LINTS_KEY) ?? _noLints;
 
 /// Associate these [lints] with the given [context].
 void setLints(AnalysisContext context, List<Linter> lints) {
diff --git a/pkg/analyzer/lib/src/summary/link.dart b/pkg/analyzer/lib/src/summary/link.dart
index bc2fc0d..6dc797a 100644
--- a/pkg/analyzer/lib/src/summary/link.dart
+++ b/pkg/analyzer/lib/src/summary/link.dart
@@ -160,7 +160,7 @@
 EntityRefBuilder _createLinkedType(
     DartType type,
     CompilationUnitElementInBuildUnit compilationUnit,
-    TypeParameterizedElementForLink typeParameterContext,
+    TypeParameterizedElementMixin typeParameterContext,
     {int slot}) {
   EntityRefBuilder result = new EntityRefBuilder(slot: slot);
   if (type is InterfaceType) {
@@ -179,7 +179,7 @@
     result.reference = compilationUnit.addRawReference('*bottom*');
     return result;
   } else if (type is TypeParameterType) {
-    TypeParameterElementForLink element = type.element;
+    TypeParameterElementImpl element = type.element;
     if (typeParameterContext.isTypeParameterInScope(element)) {
       result.paramReference =
           typeParameterContext.typeParameterNestingLevel - element.nestingLevel;
@@ -251,7 +251,7 @@
 UnlinkedParamBuilder _serializeSyntheticParam(
     ParameterElement parameter,
     CompilationUnitElementInBuildUnit compilationUnit,
-    TypeParameterizedElementForLink typeParameterContext) {
+    TypeParameterizedElementMixin typeParameterContext) {
   UnlinkedParamBuilder b = new UnlinkedParamBuilder();
   b.name = parameter.name;
   switch (parameter.parameterKind) {
@@ -290,7 +290,7 @@
     List<DartType> typeArguments,
     EntityRefBuilder encodedType,
     CompilationUnitElementInBuildUnit compilationUnit,
-    TypeParameterizedElementForLink typeParameterContext) {
+    TypeParameterizedElementMixin typeParameterContext) {
   int count = typeArguments.length;
   List<EntityRefBuilder> encodedTypeArguments =
       new List<EntityRefBuilder>(count);
@@ -317,8 +317,9 @@
  * Element representing a class or enum resynthesized from a summary
  * during linking.
  */
-abstract class ClassElementForLink
-    implements ClassElementImpl, ReferenceableElementForLink {
+abstract class ClassElementForLink extends Object
+    with ReferenceableElementForLink
+    implements ClassElementImpl {
   Map<String, ReferenceableElementForLink> _containedNames;
 
   @override
@@ -338,21 +339,10 @@
   ConstructorElementForLink get asConstructor => unnamedConstructor;
 
   @override
-  ConstVariableNode get asConstVariable {
-    // When a class name is used as a constant variable, it doesn't depend on
-    // anything, so it is not necessary to include it in the constant
-    // dependency graph.
-    return null;
-  }
-
-  @override
   DartType get asStaticType =>
       enclosingElement.enclosingElement._linker.typeProvider.typeType;
 
   @override
-  TypeInferenceNode get asTypeInferenceNode => null;
-
-  @override
   List<ConstructorElementForLink> get constructors;
 
   @override
@@ -373,6 +363,9 @@
   String get name;
 
   @override
+  ResynthesizerContext get resynthesizerContext => enclosingElement;
+
+  @override
   ConstructorElementForLink get unnamedConstructor;
 
   @override
@@ -384,14 +377,10 @@
         _containedNames[constructor.name] = constructor;
       }
       for (PropertyAccessorElementForLink accessor in accessors) {
-        if (accessor.isStatic) {
-          _containedNames[accessor.name] = accessor;
-        }
+        _containedNames[accessor.name] = accessor;
       }
       for (MethodElementForLink method in methods) {
-        if (method.isStatic) {
-          _containedNames[method.name] = method;
-        }
+        _containedNames[method.name] = method;
       }
     }
     return _containedNames.putIfAbsent(
@@ -413,7 +402,7 @@
  * linking.
  */
 class ClassElementForLink_Class extends ClassElementForLink
-    with TypeParameterizedElementForLink {
+    with TypeParameterizedElementMixin {
   /**
    * The unlinked representation of the class in the summary.
    */
@@ -473,9 +462,6 @@
   }
 
   @override
-  CompilationUnitElementForLink get compilationUnit => enclosingElement;
-
-  @override
   List<ConstructorElementForLink> get constructors {
     if (_constructors == null) {
       _constructors = <ConstructorElementForLink>[];
@@ -499,7 +485,7 @@
   String get displayName => _unlinkedClass.name;
 
   @override
-  TypeParameterizedElementForLink get enclosingTypeParameterContext => null;
+  TypeParameterizedElementMixin get enclosingTypeParameterContext => null;
 
   @override
   List<FieldElementForLink_ClassField> get fields {
@@ -563,6 +549,10 @@
       _type ??= buildType((int i) => typeParameterTypes[i], null);
 
   @override
+  List<UnlinkedTypeParam> get unlinkedTypeParams =>
+      _unlinkedClass.typeParameters;
+
+  @override
   ConstructorElementForLink get unnamedConstructor {
     if (!_unnamedConstructorComputed) {
       for (ConstructorElementForLink constructor in constructors) {
@@ -577,10 +567,6 @@
   }
 
   @override
-  List<UnlinkedTypeParam> get _unlinkedTypeParams =>
-      _unlinkedClass.typeParameters;
-
-  @override
   DartType buildType(
       DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) {
     int numTypeParameters = _unlinkedClass.typeParameters.length;
@@ -644,7 +630,7 @@
    */
   InterfaceType _computeInterfaceType(EntityRef typeRef) {
     if (typeRef != null) {
-      DartType type = enclosingElement._resolveTypeRef(typeRef, this);
+      DartType type = enclosingElement.resolveTypeRef(typeRef, this);
       if (type is InterfaceType) {
         return type;
       }
@@ -754,7 +740,7 @@
  * summary during linking.
  */
 abstract class CompilationUnitElementForLink
-    implements CompilationUnitElementImpl {
+    implements CompilationUnitElementImpl, ResynthesizerContext {
   /**
    * The unlinked representation of the compilation unit in the
    * summary.
@@ -886,6 +872,9 @@
   LibraryElementForLink get library => enclosingElement;
 
   @override
+  ResynthesizerContext get resynthesizerContext => this;
+
+  @override
   List<TopLevelVariableElementForLink> get topLevelVariables {
     if (_topLevelVariables == null) {
       _topLevelVariables = <TopLevelVariableElementForLink>[];
@@ -951,12 +940,45 @@
    * given slot, `dynamic` is returned.
    */
   DartType getLinkedType(
-      int slot, TypeParameterizedElementForLink typeParameterContext);
+      int slot, TypeParameterizedElementMixin typeParameterContext);
 
   @override
   noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 
   @override
+  DartType resolveTypeRef(
+      EntityRef type, TypeParameterizedElementMixin typeParameterContext,
+      {bool defaultVoid: false, bool instantiateToBoundsAllowed: true}) {
+    if (type == null) {
+      if (defaultVoid) {
+        return VoidTypeImpl.instance;
+      } else {
+        return DynamicTypeImpl.instance;
+      }
+    }
+    if (type.paramReference != 0) {
+      return typeParameterContext.getTypeParameterType(type.paramReference);
+    } else if (type.syntheticReturnType != null) {
+      // TODO(paulberry): implement.
+      throw new UnimplementedError();
+    } else if (type.implicitFunctionTypeIndices.isNotEmpty) {
+      // TODO(paulberry): implement.
+      throw new UnimplementedError();
+    } else {
+      DartType getTypeArgument(int i) {
+        if (i < type.typeArguments.length) {
+          return resolveTypeRef(type.typeArguments[i], typeParameterContext);
+        } else {
+          return DynamicTypeImpl.instance;
+        }
+      }
+      ReferenceableElementForLink element = _resolveRef(type.reference);
+      return element.buildType(
+          getTypeArgument, type.implicitFunctionTypeIndices);
+    }
+  }
+
+  @override
   String toString() => enclosingElement.toString();
 
   /**
@@ -980,8 +1002,15 @@
       if (containingReference != 0 &&
           _linkedUnit.references[containingReference].kind !=
               ReferenceKind.prefix) {
-        _references[index] =
-            _resolveRef(containingReference).getContainedName(name);
+        if (linkedReference.kind == ReferenceKind.function) {
+          // Local function
+          _references[index] = _resolveRef(containingReference)
+                  .getLocalFunction(linkedReference.localIndex) ??
+              UndefinedElementForLink.instance;
+        } else {
+          _references[index] =
+              _resolveRef(containingReference).getContainedName(name);
+        }
       } else if (linkedReference.dependency == 0) {
         if (name == 'void') {
           _references[index] = enclosingElement._linker.voidElement;
@@ -1000,45 +1029,6 @@
     }
     return _references[index];
   }
-
-  /**
-   * Resolve an [EntityRef] into a type.  If the reference is
-   * unresolved, return [DynamicTypeImpl.instance].
-   *
-   * TODO(paulberry): or should we have a class representing an
-   * unresolved type, for consistency with the full element model?
-   */
-  DartType _resolveTypeRef(
-      EntityRef type, TypeParameterizedElementForLink typeParameterContext,
-      {bool defaultVoid: false}) {
-    if (type == null) {
-      if (defaultVoid) {
-        return VoidTypeImpl.instance;
-      } else {
-        return DynamicTypeImpl.instance;
-      }
-    }
-    if (type.paramReference != 0) {
-      return typeParameterContext.getTypeParameterType(type.paramReference);
-    } else if (type.syntheticReturnType != null) {
-      // TODO(paulberry): implement.
-      throw new UnimplementedError();
-    } else if (type.implicitFunctionTypeIndices.isNotEmpty) {
-      // TODO(paulberry): implement.
-      throw new UnimplementedError();
-    } else {
-      DartType getTypeArgument(int i) {
-        if (i < type.typeArguments.length) {
-          return _resolveTypeRef(type.typeArguments[i], typeParameterContext);
-        } else {
-          return DynamicTypeImpl.instance;
-        }
-      }
-      ReferenceableElementForLink element = _resolveRef(type.reference);
-      return element.buildType(
-          getTypeArgument, type.implicitFunctionTypeIndices);
-    }
-  }
 }
 
 /**
@@ -1136,7 +1126,20 @@
           numTypeParameters: element.typeParameters.length,
           unitNum: element.enclosingElement.unitNum,
           kind: ReferenceKind.typedef);
-    } else if (element is ExecutableElementForLink) {
+    } else if (element is FunctionElementForLink_Initializer) {
+      return addRawReference('',
+          containingReference: addReference(element.enclosingElement),
+          kind: ReferenceKind.function,
+          localIndex: 0);
+    } else if (element is FunctionElementForLink_Local_NonSynthetic) {
+      ExecutableElementForLink parent = element.enclosingElement;
+      int localIndex = parent.functions.indexOf(element);
+      assert(localIndex != -1);
+      return addRawReference(element.name,
+          containingReference: addReference(parent),
+          kind: ReferenceKind.function,
+          localIndex: localIndex);
+    } else if (element is ExecutableElementForLink_NonLocal) {
       ClassElementForLink_Class enclosingClass = element.enclosingClass;
       ReferenceKind kind;
       switch (element._unlinkedExecutable.kind) {
@@ -1156,21 +1159,17 @@
           numTypeParameters: element.typeParameters.length,
           containingReference:
               enclosingClass != null ? addReference(enclosingClass) : null,
+          dependency: enclosingClass != null
+              ? null
+              : library.addDependency(element.library),
           kind: kind);
-    } else if (element is FunctionElementForLink_Local) {
-      FunctionElementImpl parent = element.enclosingElement;
-      int localIndex = parent.functions.indexOf(element);
-      assert(localIndex != -1);
-      return addRawReference(element.name,
-          containingReference: addReference(parent),
-          kind: ReferenceKind.function,
-          localIndex: localIndex);
     } else if (element is FunctionElementForLink_Initializer) {
       return addRawReference('',
           containingReference: addReference(element.enclosingElement),
           kind: ReferenceKind.function);
     } else if (element is TopLevelVariableElementForLink) {
       return addRawReference(element.name,
+          dependency: library.addDependency(element.library),
           kind: ReferenceKind.topLevelPropertyAccessor);
     } else if (element is FieldElementForLink_ClassField) {
       ClassElementForLink_Class enclosingClass = element.enclosingElement;
@@ -1186,7 +1185,7 @@
 
   @override
   DartType getLinkedType(
-      int slot, TypeParameterizedElementForLink typeParameterContext) {
+      int slot, TypeParameterizedElementMixin typeParameterContext) {
     // This method should only be called on compilation units that come from
     // dependencies, never on compilation units that are part of the current
     // build unit.
@@ -1235,7 +1234,7 @@
    * unit's linked type list.
    */
   void _storeLinkedType(int slot, DartType linkedType,
-      TypeParameterizedElementForLink typeParameterContext) {
+      TypeParameterizedElementMixin typeParameterContext) {
     if (slot != 0) {
       if (linkedType != null && !linkedType.isDynamic) {
         _linkedUnit.types.add(_createLinkedType(
@@ -1292,9 +1291,9 @@
 
   @override
   DartType getLinkedType(
-      int slot, TypeParameterizedElementForLink typeParameterContext) {
+      int slot, TypeParameterizedElementMixin typeParameterContext) {
     if (slot < _linkedTypeRefs.length) {
-      return _resolveTypeRef(_linkedTypeRefs[slot], typeParameterContext);
+      return resolveTypeRef(_linkedTypeRefs[slot], typeParameterContext);
     } else {
       return DynamicTypeImpl.instance;
     }
@@ -1522,8 +1521,9 @@
  * Element representing a constructor resynthesized from a summary
  * during linking.
  */
-class ConstructorElementForLink extends ExecutableElementForLink
-    implements ConstructorElementImpl, ReferenceableElementForLink {
+class ConstructorElementForLink extends ExecutableElementForLink_NonLocal
+    with ReferenceableElementForLink
+    implements ConstructorElementImpl {
   /**
    * If this is a `const` constructor and the enclosing library is
    * part of the build unit being linked, the constructor's node in
@@ -1546,19 +1546,6 @@
   ConstructorElementForLink get asConstructor => this;
 
   @override
-  ConstVariableNode get asConstVariable => null;
-
-  @override
-  DartType get asStaticType {
-    // Referring to a constructor directly is an error, so just use
-    // `dynamic`.
-    return DynamicTypeImpl.instance;
-  }
-
-  @override
-  TypeInferenceNode get asTypeInferenceNode => null;
-
-  @override
   bool get isCycleFree {
     if (!_constNode.isEvaluated) {
       new ConstDependencyWalker().walk(_constNode);
@@ -1566,15 +1553,6 @@
     return _constNode.isCycleFree;
   }
 
-  @override
-  DartType buildType(DartType getTypeArgument(int i),
-          List<int> implicitFunctionTypeIndices) =>
-      DynamicTypeImpl.instance;
-
-  @override
-  ReferenceableElementForLink getContainedName(String name) =>
-      UndefinedElementForLink.instance;
-
   /**
    * Perform const cycle detection on this constructor.
    */
@@ -1775,7 +1753,7 @@
  * linking.
  */
 abstract class ExecutableElementForLink extends Object
-    with TypeParameterizedElementForLink, ParameterParentElementForLink
+    with TypeParameterizedElementMixin, ParameterParentElementForLink
     implements ExecutableElementImpl {
   /**
    * The unlinked representation of the method in the summary.
@@ -1788,17 +1766,10 @@
   String _name;
   String _displayName;
 
-  /**
-   * Return the class in which this executable appears, maybe `null` for a
-   * top-level function.
-   */
-  final ClassElementForLink_Class enclosingClass;
-
   @override
   final CompilationUnitElementForLink compilationUnit;
 
-  ExecutableElementForLink(
-      this.compilationUnit, this.enclosingClass, this._unlinkedExecutable);
+  ExecutableElementForLink(this.compilationUnit, this._unlinkedExecutable);
 
   /**
    * If the executable element had an explicitly declared return type, return
@@ -1809,7 +1780,7 @@
       return null;
     } else {
       return _declaredReturnType ??=
-          compilationUnit._resolveTypeRef(_unlinkedExecutable.returnType, this);
+          compilationUnit.resolveTypeRef(_unlinkedExecutable.returnType, this);
     }
   }
 
@@ -1825,11 +1796,7 @@
   }
 
   @override
-  Element get enclosingElement => enclosingClass ?? compilationUnit;
-
-  @override
-  TypeParameterizedElementForLink get enclosingTypeParameterContext =>
-      enclosingClass;
+  CompilationUnitElementImpl get enclosingUnit => compilationUnit;
 
   @override
   bool get hasImplicitReturnType => _unlinkedExecutable.returnType == null;
@@ -1899,13 +1866,13 @@
   FunctionTypeImpl get type => _type ??= new FunctionTypeImpl(this);
 
   @override
-  TypeParameterizedElementForLink get typeParameterContext => this;
+  TypeParameterizedElementMixin get typeParameterContext => this;
 
   @override
   List<UnlinkedParam> get unlinkedParameters => _unlinkedExecutable.parameters;
 
   @override
-  List<UnlinkedTypeParam> get _unlinkedTypeParams =>
+  List<UnlinkedTypeParam> get unlinkedTypeParams =>
       _unlinkedExecutable.typeParameters;
 
   @override
@@ -1913,19 +1880,6 @@
       !Identifier.isPrivateName(name) || identical(this.library, library);
 
   /**
-   * Store the results of type inference for this method in [compilationUnit].
-   */
-  void link(CompilationUnitElementInBuildUnit compilationUnit) {
-    if (_unlinkedExecutable.returnType == null) {
-      compilationUnit._storeLinkedType(
-          _unlinkedExecutable.inferredReturnTypeSlot, inferredReturnType, this);
-    }
-    for (ParameterElementForLink parameterElement in parameters) {
-      parameterElement.link(compilationUnit);
-    }
-  }
-
-  /**
    * Compute the default return type for this type of executable element (if no
    * return type is declared and strong mode type inference cannot infer a
    * better return type).
@@ -1942,6 +1896,45 @@
   }
 }
 
+/**
+ * Base class for executable elements that are resynthesized from a summary
+ * during linking and are not local functions.
+ */
+abstract class ExecutableElementForLink_NonLocal
+    extends ExecutableElementForLink {
+  /**
+   * Return the class in which this executable appears, maybe `null` for a
+   * top-level function.
+   */
+  final ClassElementForLink_Class enclosingClass;
+
+  ExecutableElementForLink_NonLocal(
+      CompilationUnitElementForLink compilationUnit,
+      this.enclosingClass,
+      UnlinkedExecutable unlinkedExecutable)
+      : super(compilationUnit, unlinkedExecutable);
+
+  @override
+  Element get enclosingElement => enclosingClass ?? compilationUnit;
+
+  @override
+  TypeParameterizedElementMixin get enclosingTypeParameterContext =>
+      enclosingClass;
+
+  /**
+   * Store the results of type inference for this method in [compilationUnit].
+   */
+  void link(CompilationUnitElementInBuildUnit compilationUnit) {
+    if (_unlinkedExecutable.returnType == null) {
+      compilationUnit._storeLinkedType(
+          _unlinkedExecutable.inferredReturnTypeSlot, inferredReturnType, this);
+    }
+    for (ParameterElementForLink parameterElement in parameters) {
+      parameterElement.link(compilationUnit);
+    }
+  }
+}
+
 class ExprTypeComputer {
   VariableElementForLink variable;
   FunctionElementForLink_Initializer initializer;
@@ -2282,7 +2275,7 @@
       stack.add(enclosingClass.buildType((int i) {
         // Type argument explicitly specified.
         if (i < ref.typeArguments.length) {
-          return unit._resolveTypeRef(
+          return unit.resolveTypeRef(
               ref.typeArguments[i], variable._typeParameterContext);
         }
         // In strong mode, type argument defaults to bound (if any).
@@ -2422,7 +2415,7 @@
 
   DartType _getNextTypeRef() {
     EntityRef ref = _getNextRef();
-    return unit._resolveTypeRef(ref, variable._typeParameterContext);
+    return unit.resolveTypeRef(ref, variable._typeParameterContext);
   }
 
   /**
@@ -2609,7 +2602,7 @@
   }
 
   @override
-  TypeParameterizedElementForLink get _typeParameterContext => enclosingElement;
+  TypeParameterizedElementMixin get _typeParameterContext => enclosingElement;
 
   /**
    * Store the results of type inference for this field in
@@ -2683,7 +2676,7 @@
   final ParameterElementForLink enclosingElement;
 
   @override
-  final TypeParameterizedElementForLink typeParameterContext;
+  final TypeParameterizedElementMixin typeParameterContext;
 
   @override
   final List<UnlinkedParam> unlinkedParameters;
@@ -2711,7 +2704,7 @@
       if (enclosingElement._unlinkedParam.type == null) {
         _returnType = DynamicTypeImpl.instance;
       } else {
-        _returnType = enclosingElement.compilationUnit._resolveTypeRef(
+        _returnType = enclosingElement.compilationUnit.resolveTypeRef(
             enclosingElement._unlinkedParam.type, typeParameterContext);
       }
     }
@@ -2728,25 +2721,33 @@
 /**
  * Element representing the initializer expression of a variable.
  */
-class FunctionElementForLink_Initializer implements FunctionElementImpl {
+class FunctionElementForLink_Initializer extends Object
+    with ReferenceableElementForLink
+    implements FunctionElementForLink_Local {
   /**
    * The variable for which this element is the initializer.
    */
   final VariableElementForLink _variable;
 
-  List<FunctionElementForLink_Local> _functions;
+  List<FunctionElementForLink_Local_NonSynthetic> _functions;
 
   FunctionElementForLink_Initializer(this._variable);
 
   @override
   VariableElementForLink get enclosingElement => _variable;
 
+  TypeParameterizedElementMixin get enclosingTypeParameterContext =>
+      _variable.enclosingElement is ClassElementForLink
+          ? _variable.enclosingElement
+          : null;
+
   @override
-  List<FunctionElementForLink_Local> get functions => _functions ??= _variable
-      .unlinkedVariable.initializer.localFunctions
-      .map(
-          (UnlinkedExecutable ex) => new FunctionElementForLink_Local(this, ex))
-      .toList();
+  List<FunctionElementForLink_Local_NonSynthetic> get functions =>
+      _functions ??= _variable.unlinkedVariable.initializer.localFunctions
+          .map((UnlinkedExecutable ex) =>
+              new FunctionElementForLink_Local_NonSynthetic(
+                  _variable.compilationUnit, this, ex))
+          .toList();
 
   @override
   DartType get returnType {
@@ -2770,31 +2771,62 @@
   }
 
   @override
+  int get typeParameterNestingLevel =>
+      enclosingTypeParameterContext?.typeParameterNestingLevel ?? 0;
+
+  List<TypeParameterElement> get typeParameters => const [];
+
+  @override
+  FunctionElementForLink_Local getLocalFunction(int index) {
+    List<FunctionElementForLink_Local_NonSynthetic> functions = this.functions;
+    return index < functions.length ? functions[index] : null;
+  }
+
+  @override
   noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 }
 
 /**
+ * Element representing a local function (possibly a closure).
+ */
+abstract class FunctionElementForLink_Local
+    implements
+        ExecutableElementForLink,
+        FunctionElementImpl,
+        ReferenceableElementForLink {}
+
+/**
  * Element representing a local function (possibly a closure) inside another
  * executable.
  */
-class FunctionElementForLink_Local implements FunctionElementImpl {
-  /**
-   * The unlinked representation of the local function in the summary.
-   */
-  final UnlinkedExecutable _executable;
+class FunctionElementForLink_Local_NonSynthetic extends ExecutableElementForLink
+    with ReferenceableElementForLink
+    implements FunctionElementForLink_Local {
+  @override
+  final ExecutableElementForLink enclosingElement;
+
+  FunctionElementForLink_Local_NonSynthetic(
+      CompilationUnitElementForLink compilationUnit,
+      this.enclosingElement,
+      UnlinkedExecutable unlinkedExecutable)
+      : super(compilationUnit, unlinkedExecutable);
 
   @override
-  final FunctionElementImpl enclosingElement;
-
-  DartType _type;
-
-  FunctionElementForLink_Local(this.enclosingElement, this._executable);
+  TypeParameterizedElementMixin get enclosingTypeParameterContext =>
+      enclosingElement;
 
   @override
-  String get name => _executable.name;
+  DartType buildType(
+      DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) {
+    assert(implicitFunctionTypeIndices.isEmpty);
+    return type;
+  }
 
   @override
-  DartType get type => _type ??= new FunctionTypeImpl(this);
+  FunctionElementForLink_Local getLocalFunction(int index) {
+    // TODO(paulberry): implement.
+    throw new UnimplementedError();
+  }
 
   @override
   noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
@@ -2804,11 +2836,11 @@
  * Element representing a typedef resynthesized from a summary during linking.
  */
 class FunctionTypeAliasElementForLink extends Object
-    with TypeParameterizedElementForLink, ParameterParentElementForLink
-    implements
-        FunctionTypeAliasElement,
-        ReferenceableElementForLink,
-        ElementImpl {
+    with
+        TypeParameterizedElementMixin,
+        ParameterParentElementForLink,
+        ReferenceableElementForLink
+    implements FunctionTypeAliasElement, ElementImpl {
   @override
   final CompilationUnitElementForLink enclosingElement;
 
@@ -2823,29 +2855,15 @@
   FunctionTypeAliasElementForLink(this.enclosingElement, this._unlinkedTypedef);
 
   @override
-  ConstructorElementForLink get asConstructor => null;
-
-  @override
-  ConstVariableNode get asConstVariable {
-    // When a typedef name is used as a constant variable, it doesn't depend on
-    // anything, so it is not necessary to include it in the constant
-    // dependency graph.
-    return null;
-  }
-
-  @override
   DartType get asStaticType {
     return enclosingElement.enclosingElement._linker.typeProvider.typeType;
   }
 
   @override
-  TypeInferenceNode get asTypeInferenceNode => null;
+  TypeParameterizedElementMixin get enclosingTypeParameterContext => null;
 
   @override
-  CompilationUnitElementForLink get compilationUnit => enclosingElement;
-
-  @override
-  TypeParameterizedElementForLink get enclosingTypeParameterContext => null;
+  CompilationUnitElementInBuildUnit get enclosingUnit => enclosingElement;
 
   @override
   String get identifier => _unlinkedTypedef.name;
@@ -2864,16 +2882,16 @@
 
   @override
   DartType get returnType => _returnType ??=
-      enclosingElement._resolveTypeRef(_unlinkedTypedef.returnType, this);
+      enclosingElement.resolveTypeRef(_unlinkedTypedef.returnType, this);
 
   @override
-  TypeParameterizedElementForLink get typeParameterContext => this;
+  TypeParameterizedElementMixin get typeParameterContext => this;
 
   @override
   List<UnlinkedParam> get unlinkedParameters => _unlinkedTypedef.parameters;
 
   @override
-  List<UnlinkedTypeParam> get _unlinkedTypeParams =>
+  List<UnlinkedTypeParam> get unlinkedTypeParams =>
       _unlinkedTypedef.typeParameters;
 
   @override
@@ -2893,12 +2911,6 @@
   }
 
   @override
-  ReferenceableElementForLink getContainedName(String name) {
-    // TODO(paulberry): implement.
-    throw new UnimplementedError();
-  }
-
-  @override
   noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 }
 
@@ -3447,40 +3459,27 @@
 /**
  * Element representing a method resynthesized from a summary during linking.
  */
-class MethodElementForLink extends ExecutableElementForLink
-    implements MethodElementImpl, ReferenceableElementForLink {
+class MethodElementForLink extends ExecutableElementForLink_NonLocal
+    with ReferenceableElementForLink
+    implements MethodElementImpl {
   MethodElementForLink(ClassElementForLink_Class enclosingClass,
       UnlinkedExecutable unlinkedExecutable)
       : super(enclosingClass.enclosingElement, enclosingClass,
             unlinkedExecutable);
 
   @override
-  ConstructorElementForLink get asConstructor => null;
-
-  @override
-  ConstVariableNode get asConstVariable => null;
-
-  @override
   DartType get asStaticType => type;
 
   @override
-  TypeInferenceNode get asTypeInferenceNode => null;
-
-  @override
   String get identifier => name;
 
   @override
   ElementKind get kind => ElementKind.METHOD;
 
   @override
-  DartType buildType(DartType getTypeArgument(int i),
-          List<int> implicitFunctionTypeIndices) =>
-      DynamicTypeImpl.instance;
-
-  @override
-  ReferenceableElementForLink getContainedName(String name) {
-    // TODO(paulberry): handle references to `call`.
-    return UndefinedElementForLink.instance;
+  FunctionElementForLink_Local getLocalFunction(int index) {
+    // TODO(paulberry): implement.
+    return null;
   }
 
   @override
@@ -3538,7 +3537,8 @@
  * creating a [NonstaticMemberElementForLink] that points to another
  * [NonstaticMemberElementForLink], to whatever nesting level is necessary.
  */
-class NonstaticMemberElementForLink implements ReferenceableElementForLink {
+class NonstaticMemberElementForLink extends Object
+    with ReferenceableElementForLink {
   /**
    * The [ReferenceableElementForLink] which is the target of the non-static
    * reference.
@@ -3559,9 +3559,6 @@
   NonstaticMemberElementForLink(this._library, this._target, this._name);
 
   @override
-  ConstructorElementForLink get asConstructor => null;
-
-  @override
   ConstVariableNode get asConstVariable => _target.asConstVariable;
 
   @override
@@ -3590,11 +3587,6 @@
   TypeInferenceNode get asTypeInferenceNode => _target.asTypeInferenceNode;
 
   @override
-  DartType buildType(DartType getTypeArgument(int i),
-          List<int> implicitFunctionTypeIndices) =>
-      DynamicTypeImpl.instance;
-
-  @override
   ReferenceableElementForLink getContainedName(String name) {
     return new NonstaticMemberElementForLink(_library, this, name);
   }
@@ -3613,7 +3605,7 @@
   /**
    * The innermost enclosing element that can declare type parameters.
    */
-  final TypeParameterizedElementForLink _typeParameterContext;
+  final TypeParameterizedElementMixin _typeParameterContext;
 
   /**
    * If this parameter has a default value and the enclosing library
@@ -3685,7 +3677,7 @@
           _declaredType = DynamicTypeImpl.instance;
         }
       } else {
-        _declaredType = compilationUnit._resolveTypeRef(
+        _declaredType = compilationUnit.resolveTypeRef(
             _unlinkedParam.type, _typeParameterContext);
       }
     }
@@ -3762,8 +3754,13 @@
       _parameters = new List<ParameterElementForLink>(numParameters);
       for (int i = 0; i < numParameters; i++) {
         UnlinkedParam unlinkedParam = unlinkedParameters[i];
-        _parameters[i] = new ParameterElementForLink(this, unlinkedParam,
-            typeParameterContext, typeParameterContext.compilationUnit, i);
+        _parameters[i] = new ParameterElementForLink(
+            this,
+            unlinkedParam,
+            typeParameterContext,
+            typeParameterContext.enclosingUnit.resynthesizerContext
+            as CompilationUnitElementForLink,
+            i);
       }
     }
     return _parameters;
@@ -3774,7 +3771,7 @@
    * may be [this], or may be a parent when there are function-typed
    * parameters).
    */
-  TypeParameterizedElementForLink get typeParameterContext;
+  TypeParameterizedElementMixin get typeParameterContext;
 
   /**
    * Get the list of unlinked parameters of this element.
@@ -3795,7 +3792,8 @@
  * Specialization of [PropertyAccessorElementForLink] for synthetic accessors
  * implied by the synthetic fields of an enum declaration.
  */
-class PropertyAccessorElementForLink_EnumField
+class PropertyAccessorElementForLink_EnumField extends Object
+    with ReferenceableElementForLink
     implements PropertyAccessorElementForLink {
   @override
   final FieldElementForLink_EnumField variable;
@@ -3805,18 +3803,9 @@
   PropertyAccessorElementForLink_EnumField(this.variable);
 
   @override
-  ConstructorElementForLink get asConstructor => null;
-
-  @override
-  ConstVariableNode get asConstVariable => null;
-
-  @override
   DartType get asStaticType => returnType;
 
   @override
-  TypeInferenceNode get asTypeInferenceNode => null;
-
-  @override
   Element get enclosingElement => variable.enclosingElement;
 
   @override
@@ -3854,16 +3843,18 @@
   List<TypeParameterElement> get typeParameters => const [];
 
   @override
-  DartType buildType(DartType getTypeArgument(int i),
-          List<int> implicitFunctionTypeIndices) =>
-      DynamicTypeImpl.instance;
-
-  @override
   ReferenceableElementForLink getContainedName(String name) {
     return new NonstaticMemberElementForLink(library, this, name);
   }
 
   @override
+  FunctionElementForLink_Local getLocalFunction(int index) {
+    // TODO(paulberry): implement (should return the synthetic function element
+    // for the enum field's initializer).
+    return null;
+  }
+
+  @override
   bool isAccessibleIn(LibraryElement library) =>
       !Identifier.isPrivateName(name) || identical(this.library, library);
 
@@ -3881,7 +3872,9 @@
  * Specialization of [PropertyAccessorElementForLink] for non-synthetic
  * accessors explicitly declared in the source code.
  */
-class PropertyAccessorElementForLink_Executable extends ExecutableElementForLink
+class PropertyAccessorElementForLink_Executable
+    extends ExecutableElementForLink_NonLocal
+    with ReferenceableElementForLink
     implements PropertyAccessorElementForLink {
   @override
   SyntheticVariableElementForLink variable;
@@ -3894,18 +3887,9 @@
       : super(enclosingUnit, enclosingClass, unlinkedExecutable);
 
   @override
-  ConstructorElementForLink get asConstructor => null;
-
-  @override
-  ConstVariableNode get asConstVariable => null;
-
-  @override
   DartType get asStaticType => returnType;
 
   @override
-  TypeInferenceNode get asTypeInferenceNode => null;
-
-  @override
   PropertyAccessorElementForLink_Executable get correspondingGetter =>
       variable.getter;
 
@@ -3918,20 +3902,24 @@
       _unlinkedExecutable.kind == UnlinkedExecutableKind.setter;
 
   @override
+  bool get isStatic => enclosingClass == null || super.isStatic;
+
+  @override
   ElementKind get kind => _unlinkedExecutable.kind ==
       UnlinkedExecutableKind.getter ? ElementKind.GETTER : ElementKind.SETTER;
 
   @override
-  DartType buildType(DartType getTypeArgument(int i),
-          List<int> implicitFunctionTypeIndices) =>
-      DynamicTypeImpl.instance;
-
-  @override
   ReferenceableElementForLink getContainedName(String name) {
     return new NonstaticMemberElementForLink(library, this, name);
   }
 
   @override
+  FunctionElementForLink_Local getLocalFunction(int index) {
+    // TODO(paulberry): implement
+    return null;
+  }
+
+  @override
   noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 
   @override
@@ -3942,7 +3930,8 @@
  * Specialization of [PropertyAccessorElementForLink] for synthetic accessors
  * implied by a field or variable declaration.
  */
-class PropertyAccessorElementForLink_Variable
+class PropertyAccessorElementForLink_Variable extends Object
+    with ReferenceableElementForLink
     implements PropertyAccessorElementForLink {
   @override
   final bool isSetter;
@@ -3954,9 +3943,6 @@
   PropertyAccessorElementForLink_Variable(this.variable, this.isSetter);
 
   @override
-  ConstructorElementForLink get asConstructor => null;
-
-  @override
   ConstVariableNode get asConstVariable => variable._constNode;
 
   @override
@@ -4016,11 +4002,6 @@
     return const [];
   }
 
-  @override
-  DartType buildType(DartType getTypeArgument(int i),
-          List<int> implicitFunctionTypeIndices) =>
-      DynamicTypeImpl.instance;
-
   /**
    * Compute the type of the corresponding variable, which may depend on the
    * progress of type inference.
@@ -4045,6 +4026,15 @@
   }
 
   @override
+  FunctionElementForLink_Local getLocalFunction(int index) {
+    if (index == 0) {
+      return variable.initializer;
+    } else {
+      return null;
+    }
+  }
+
+  @override
   bool isAccessibleIn(LibraryElement library) =>
       !Identifier.isPrivateName(name) || identical(this.library, library);
 
@@ -4059,44 +4049,46 @@
 }
 
 /**
- * Abstract base class representing an element which can be the target
- * of a reference.
+ * Base class representing an element which can be the target of a reference.
+ * When used as a mixin, implements the default behavior shared by most
+ * elements.
  */
-abstract class ReferenceableElementForLink {
+class ReferenceableElementForLink {
   /**
    * If this element can be used in a constructor invocation context,
    * return the associated constructor (which may be `this` or some
    * other element).  Otherwise return `null`.
    */
-  ConstructorElementForLink get asConstructor;
+  ConstructorElementForLink get asConstructor => null;
 
   /**
    * If this element can be used in a getter context to refer to a
    * constant variable, return the [ConstVariableNode] for the
    * constant value.  Otherwise return `null`.
    */
-  ConstVariableNode get asConstVariable;
+  ConstVariableNode get asConstVariable => null;
 
   /**
    * Return the static type (possibly inferred) of the entity referred to by
    * this element.
    */
-  DartType get asStaticType;
+  DartType get asStaticType => DynamicTypeImpl.instance;
 
   /**
    * If this element can be used in a getter context as a type inference
    * dependency, return the [TypeInferenceNode] for the inferred type.
    * Otherwise return `null`.
    */
-  TypeInferenceNode get asTypeInferenceNode;
+  TypeInferenceNode get asTypeInferenceNode => null;
 
   /**
    * Return the type indicated by this element when it is used in a
    * type instantiation context.  If this element can't legally be
    * instantiated as a type, return the dynamic type.
    */
-  DartType buildType(
-      DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices);
+  DartType buildType(DartType getTypeArgument(int i),
+          List<int> implicitFunctionTypeIndices) =>
+      DynamicTypeImpl.instance;
 
   /**
    * If this element contains other named elements, return the
@@ -4105,40 +4097,37 @@
    * with the given name, return the singleton of
    * [UndefinedElementForLink].
    */
-  ReferenceableElementForLink getContainedName(String name);
+  ReferenceableElementForLink getContainedName(String name) {
+    // TODO(paulberry): handle references to `call` for function types.
+    return UndefinedElementForLink.instance;
+  }
+
+  /**
+   * If this element contains local functions, return the contained local
+   * function having the given [index].  If this element doesn't contain local
+   * functions, or the index is out of range, return `null`.
+   */
+  FunctionElementForLink_Local getLocalFunction(int index) => null;
 }
 
 /**
  * Element used for references to special types such as `void`.
  */
-class SpecialTypeElementForLink extends ReferenceableElementForLink {
+class SpecialTypeElementForLink extends Object
+    with ReferenceableElementForLink {
   final Linker linker;
   final DartType type;
 
   SpecialTypeElementForLink(this.linker, this.type);
 
   @override
-  ConstructorElementForLink get asConstructor => null;
-
-  @override
-  ConstVariableNode get asConstVariable => null;
-
-  @override
   DartType get asStaticType => linker.typeProvider.typeType;
 
   @override
-  TypeInferenceNode get asTypeInferenceNode => null;
-
-  @override
   DartType buildType(
       DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) {
     return type;
   }
-
-  @override
-  ReferenceableElementForLink getContainedName(String name) {
-    return UndefinedElementForLink.instance;
-  }
 }
 
 /**
@@ -4168,8 +4157,9 @@
 /**
  * Element representing a top-level function.
  */
-class TopLevelFunctionElementForLink extends ExecutableElementForLink
-    implements FunctionElementImpl, ReferenceableElementForLink {
+class TopLevelFunctionElementForLink extends ExecutableElementForLink_NonLocal
+    with ReferenceableElementForLink
+    implements FunctionElementImpl {
   DartType _returnType;
 
   TopLevelFunctionElementForLink(
@@ -4177,29 +4167,21 @@
       : super(enclosingUnit, null, _buf);
 
   @override
-  ConstructorElementForLink get asConstructor => null;
-
-  @override
-  ConstVariableNode get asConstVariable => null;
-
-  @override
   DartType get asStaticType => type;
 
   @override
-  TypeInferenceNode get asTypeInferenceNode => null;
+  String get identifier => _unlinkedExecutable.name;
+
+  @override
+  bool get isStatic => true;
 
   @override
   ElementKind get kind => ElementKind.FUNCTION;
 
   @override
-  DartType buildType(DartType getTypeArgument(int i),
-          List<int> implicitFunctionTypeIndices) =>
-      DynamicTypeImpl.instance;
-
-  @override
-  ReferenceableElementForLink getContainedName(String name) {
-    // TODO(paulberry): handle references to `call`.
-    return UndefinedElementForLink.instance;
+  FunctionElementForLink_Local getLocalFunction(int index) {
+    // TODO(paulberry): implement.
+    return null;
   }
 
   @override
@@ -4226,7 +4208,7 @@
   LibraryElementForLink get library => compilationUnit.library;
 
   @override
-  TypeParameterizedElementForLink get _typeParameterContext => null;
+  TypeParameterizedElementMixin get _typeParameterContext => null;
 
   /**
    * Store the results of type inference for this variable in
@@ -4355,154 +4337,6 @@
   String toString() => 'TypeInferenceNode($variableElement)';
 }
 
-/**
- * Element representing a type parameter resynthesized from a summary during
- * linking.
- */
-class TypeParameterElementForLink implements TypeParameterElementImpl {
-  /**
-   * The unlinked representation of the type parameter in the summary.
-   */
-  final UnlinkedTypeParam _unlinkedTypeParam;
-
-  /**
-   * The number of type parameters whose scope overlaps this one, and which are
-   * declared earlier in the file.
-   */
-  final int nestingLevel;
-
-  @override
-  final TypeParameterizedElementForLink enclosingElement;
-
-  TypeParameterTypeImpl _type;
-  ElementLocation _location;
-
-  DartType _bound;
-
-  TypeParameterElementForLink(
-      this.enclosingElement, this._unlinkedTypeParam, this.nestingLevel);
-
-  @override
-  DartType get bound {
-    if (_unlinkedTypeParam.bound == null) {
-      return null;
-    }
-    return _bound ??= enclosingElement.compilationUnit
-        ._resolveTypeRef(_unlinkedTypeParam.bound, enclosingElement);
-  }
-
-  @override
-  String get identifier => name;
-
-  @override
-  ElementKind get kind => ElementKind.TYPE_PARAMETER;
-
-  @override
-  ElementLocation get location =>
-      _location ??= new ElementLocationImpl.con1(this);
-
-  @override
-  String get name => _unlinkedTypeParam.name;
-
-  @override
-  TypeParameterTypeImpl get type => _type ??= new TypeParameterTypeImpl(this);
-
-  @override
-  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
-
-/**
- * Mixin representing an element which can have type parameters.
- */
-abstract class TypeParameterizedElementForLink
-    implements TypeParameterizedElement {
-  List<TypeParameterType> _typeParameterTypes;
-  List<TypeParameterElementForLink> _typeParameters;
-  int _nestingLevel;
-
-  /**
-   * Get the compilation unit in which this element is declared.
-   */
-  CompilationUnitElementForLink get compilationUnit;
-
-  /**
-   * Get the type parameter context enclosing this one, if any.
-   */
-  TypeParameterizedElementForLink get enclosingTypeParameterContext;
-
-  /**
-   * Find out how many type parameters are in scope in this context.
-   */
-  int get typeParameterNestingLevel =>
-      _nestingLevel ??= _unlinkedTypeParams.length +
-          (enclosingTypeParameterContext?.typeParameterNestingLevel ?? 0);
-
-  List<TypeParameterElementForLink> get typeParameters {
-    if (_typeParameters == null) {
-      int enclosingNestingLevel =
-          enclosingTypeParameterContext?.typeParameterNestingLevel ?? 0;
-      int numTypeParameters = _unlinkedTypeParams.length;
-      _typeParameters =
-          new List<TypeParameterElementForLink>(numTypeParameters);
-      for (int i = 0; i < numTypeParameters; i++) {
-        _typeParameters[i] = new TypeParameterElementForLink(
-            this, _unlinkedTypeParams[i], enclosingNestingLevel + i);
-      }
-    }
-    return _typeParameters;
-  }
-
-  /**
-   * Get a list of [TypeParameterType] objects corresponding to the
-   * element's type parameters.
-   */
-  List<TypeParameterType> get typeParameterTypes {
-    if (_typeParameterTypes == null) {
-      _typeParameterTypes = typeParameters
-          .map((TypeParameterElementForLink e) => e.type)
-          .toList();
-    }
-    return _typeParameterTypes;
-  }
-
-  /**
-   * Get the [UnlinkedTypeParam]s representing the type parameters declared by
-   * this element.
-   */
-  List<UnlinkedTypeParam> get _unlinkedTypeParams;
-
-  /**
-   * Convert the given [index] into a type parameter type.
-   */
-  TypeParameterType getTypeParameterType(int index) {
-    List<TypeParameterType> types = typeParameterTypes;
-    if (index <= types.length) {
-      return types[types.length - index];
-    } else if (enclosingTypeParameterContext != null) {
-      return enclosingTypeParameterContext
-          .getTypeParameterType(index - types.length);
-    } else {
-      // If we get here, it means that a summary contained a type parameter index
-      // that was out of range.
-      throw new RangeError('Invalid type parameter index');
-    }
-  }
-
-  /**
-   * Find out if the given [typeParameter] is in scope in this context.
-   */
-  bool isTypeParameterInScope(TypeParameterElementForLink typeParameter) {
-    if (typeParameter.enclosingElement == this) {
-      return true;
-    } else if (enclosingTypeParameterContext != null) {
-      return enclosingTypeParameterContext
-          .isTypeParameterInScope(typeParameter);
-    } else {
-      return false;
-    }
-  }
-}
-
 class TypeProviderForLink implements TypeProvider {
   final Linker _linker;
 
@@ -4652,31 +4486,11 @@
 /**
  * Singleton element used for unresolved references.
  */
-class UndefinedElementForLink implements ReferenceableElementForLink {
-  static const UndefinedElementForLink instance =
-      const UndefinedElementForLink._();
+class UndefinedElementForLink extends Object with ReferenceableElementForLink {
+  static final UndefinedElementForLink instance =
+      new UndefinedElementForLink._();
 
-  const UndefinedElementForLink._();
-
-  @override
-  ConstructorElementForLink get asConstructor => null;
-
-  @override
-  ConstVariableNode get asConstVariable => null;
-
-  @override
-  DartType get asStaticType => DynamicTypeImpl.instance;
-
-  @override
-  TypeInferenceNode get asTypeInferenceNode => null;
-
-  @override
-  DartType buildType(DartType getTypeArgument(int i),
-          List<int> implicitFunctionTypeIndices) =>
-      DynamicTypeImpl.instance;
-
-  @override
-  ReferenceableElementForLink getContainedName(String name) => this;
+  UndefinedElementForLink._();
 }
 
 /**
@@ -4684,7 +4498,7 @@
  * summary during linking.
  */
 abstract class VariableElementForLink
-    implements VariableElementImpl, PropertyInducingElement {
+    implements NonParameterVariableElementImpl, PropertyInducingElement {
   /**
    * The unlinked representation of the variable in the summary.
    */
@@ -4732,7 +4546,7 @@
     if (unlinkedVariable.type == null) {
       return null;
     } else {
-      return _declaredType ??= compilationUnit._resolveTypeRef(
+      return _declaredType ??= compilationUnit.resolveTypeRef(
           unlinkedVariable.type, _typeParameterContext);
     }
   }
@@ -4774,7 +4588,7 @@
 
   @override
   FunctionElementForLink_Initializer get initializer {
-    if (unlinkedVariable.constExpr == null) {
+    if (unlinkedVariable.initializer == null) {
       return null;
     } else {
       return _initializer ??= new FunctionElementForLink_Initializer(this);
@@ -4824,7 +4638,7 @@
    * The context in which type parameters should be interpreted, or `null` if
    * there are no type parameters in scope.
    */
-  TypeParameterizedElementForLink get _typeParameterContext;
+  TypeParameterizedElementMixin get _typeParameterContext;
 
   @override
   noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
diff --git a/pkg/analyzer/lib/src/summary/package_bundle_reader.dart b/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
index eb6020f..7c6ee32 100644
--- a/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
@@ -134,6 +134,8 @@
 /**
  * The [UriResolver] that knows about sources that are served from their
  * summaries.
+ *
+ * TODO(scheglov) rename to `InSummaryUriResolver` - it's not `package:` specific.
  */
 class InSummaryPackageUriResolver extends UriResolver {
   final SummaryDataStore _dataStore;
@@ -143,9 +145,10 @@
   @override
   Source resolveAbsolute(Uri uri, [Uri actualUri]) {
     actualUri ??= uri;
-    UnlinkedUnit unit = _dataStore.unlinkedMap[uri.toString()];
+    String uriString = uri.toString();
+    UnlinkedUnit unit = _dataStore.unlinkedMap[uriString];
     if (unit != null) {
-      String summaryPath = _dataStore.uriToSummaryPath[uri.toString()];
+      String summaryPath = _dataStore.uriToSummaryPath[uriString];
       if (unit.fallbackModePath.isNotEmpty) {
         return new _InSummaryFallbackSource(
             new JavaFile(unit.fallbackModePath), actualUri, summaryPath);
@@ -185,7 +188,7 @@
   int get hashCode => uri.hashCode;
 
   @override
-  bool get isInSystemLibrary => false;
+  bool get isInSystemLibrary => uri.scheme == DartUriResolver.DART_SCHEME;
 
   @override
   int get modificationStamp => 0;
@@ -214,6 +217,11 @@
  */
 class SummaryDataStore {
   /**
+   * List of all [PackageBundle]s.
+   */
+  final List<PackageBundle> bundles = <PackageBundle>[];
+
+  /**
    * Map from the URI of a compilation unit to the unlinked summary of that
    * compilation unit.
    */
@@ -237,6 +245,7 @@
    * Add the given [bundle] loaded from the file with the given [path].
    */
   void addBundle(String path, PackageBundle bundle) {
+    bundles.add(bundle);
     for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
       String uri = bundle.unlinkedUnitUris[i];
       uriToSummaryPath[uri] = path;
diff --git a/pkg/analyzer/lib/src/summary/resynthesize.dart b/pkg/analyzer/lib/src/summary/resynthesize.dart
index acc6ff3..dfcaa98 100644
--- a/pkg/analyzer/lib/src/summary/resynthesize.dart
+++ b/pkg/analyzer/lib/src/summary/resynthesize.dart
@@ -548,7 +548,8 @@
    */
   TypeName _newTypeName() {
     EntityRef typeRef = uc.references[refPtr++];
-    DartType type = resynthesizer.buildType(typeRef);
+    DartType type = resynthesizer.buildType(
+        typeRef, resynthesizer._currentTypeParameterizedElement);
     return _buildTypeAst(type);
   }
 
@@ -577,7 +578,7 @@
 
   void _pushInstanceCreation() {
     EntityRef ref = uc.references[refPtr++];
-    _ReferenceInfo info = resynthesizer.referenceInfos[ref.reference];
+    _ReferenceInfo info = resynthesizer.getReferenceInfo(ref.reference);
     // prepare ConstructorElement
     TypeName typeNode;
     String constructorName;
@@ -645,7 +646,7 @@
   void _pushInvokeMethodRef() {
     List<Expression> arguments = _buildArguments();
     EntityRef ref = uc.references[refPtr++];
-    _ReferenceInfo info = resynthesizer.referenceInfos[ref.reference];
+    _ReferenceInfo info = resynthesizer.getReferenceInfo(ref.reference);
     Expression node = _buildIdentifierSequence(info);
     if (node is SimpleIdentifier) {
       _push(new MethodInvocation(
@@ -686,7 +687,7 @@
 
   void _pushReference() {
     EntityRef ref = uc.references[refPtr++];
-    _ReferenceInfo info = resynthesizer.referenceInfos[ref.reference];
+    _ReferenceInfo info = resynthesizer.getReferenceInfo(ref.reference);
     Expression node = _buildIdentifierSequence(info);
     _push(node);
   }
@@ -701,6 +702,25 @@
 }
 
 /**
+ * Temporary [TypeParameterizedElementMixin] implementation.
+ *
+ * TODO(scheglov) remove after moving resynthesize logic to Impl.
+ */
+class _CurrentTypeParameterizedElement
+    implements TypeParameterizedElementMixin {
+  final _UnitResynthesizer unitResynthesizer;
+
+  _CurrentTypeParameterizedElement(this.unitResynthesizer);
+
+  @override
+  TypeParameterType getTypeParameterType(int index) {
+    return unitResynthesizer.getTypeParameterFromScope(index);
+  }
+
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
  * A class element that has been resynthesized from a summary.  The actual
  * element won't be constructed until it is requested.  But properties
  * [context],  [displayName], [enclosingElement] and [name] can be used without
@@ -714,6 +734,12 @@
 
   ClassElementImpl _actualElement;
 
+  /**
+   * We don't resynthesize executables of classes until they are requested.
+   * TODO(scheglov) Check whether we need separate flags for separate kinds.
+   */
+  bool _executablesResynthesized = false;
+
   @override
   final String name;
 
@@ -733,15 +759,27 @@
       : super(null, location);
 
   @override
+  List<PropertyAccessorElement> get accessors {
+    _ensureExecutables();
+    return actualElement.accessors;
+  }
+
+  @override
   ClassElementImpl get actualElement {
     if (_actualElement == null) {
-      _actualElement = unitResynthesizer.buildClassImpl(serializedClass);
+      _actualElement = unitResynthesizer.buildClassImpl(serializedClass, this);
       _actualElement.enclosingElement = unitElement;
     }
     return _actualElement;
   }
 
   @override
+  List<ConstructorElement> get constructors {
+    _ensureExecutables();
+    return actualElement.constructors;
+  }
+
+  @override
   AnalysisContext get context => unitElement.context;
 
   @override
@@ -751,6 +789,48 @@
   CompilationUnitElement get enclosingElement {
     return unitElement;
   }
+
+  @override
+  List<FieldElement> get fields {
+    _ensureExecutables();
+    return actualElement.fields;
+  }
+
+  @override
+  List<MethodElement> get methods {
+    _ensureExecutables();
+    return actualElement.methods;
+  }
+
+  @override
+  void ensureAccessorsReady() {
+    _ensureExecutables();
+  }
+
+  @override
+  void ensureActualElementComplete() {
+    _ensureExecutables();
+  }
+
+  @override
+  void ensureConstructorsReady() {
+    _ensureExecutables();
+  }
+
+  @override
+  void ensureMethodsReady() {
+    _ensureExecutables();
+  }
+
+  /**
+   * Ensure that we have [actualElement], and it has all executables.
+   */
+  void _ensureExecutables() {
+    if (!_executablesResynthesized) {
+      _executablesResynthesized = true;
+      unitResynthesizer.buildClassExecutables(actualElement, serializedClass);
+    }
+  }
 }
 
 /**
@@ -921,11 +1001,21 @@
   final Source librarySource;
 
   /**
+   * The URI of [librarySource].
+   */
+  String libraryUri;
+
+  /**
    * Indicates whether [librarySource] is the `dart:core` library.
    */
   bool isCoreLibrary;
 
   /**
+   * The resynthesized library.
+   */
+  LibraryElementImpl library;
+
+  /**
    * Classes which should have their supertype set to "object" once
    * resynthesis is complete.  Only used if [isCoreLibrary] is `true`.
    */
@@ -955,7 +1045,8 @@
 
   _LibraryResynthesizer(this.summaryResynthesizer, this.linkedLibrary,
       this.unlinkedUnits, this.librarySource) {
-    isCoreLibrary = librarySource.uri.toString() == 'dart:core';
+    libraryUri = librarySource.uri.toString();
+    isCoreLibrary = libraryUri == 'dart:core';
   }
 
   /**
@@ -1109,17 +1200,17 @@
    * Main entry point.  Resynthesize the [LibraryElement] and return it.
    */
   LibraryElement buildLibrary() {
-    CompilationUnitElementImpl definingUnit =
-        new CompilationUnitElementImpl(librarySource.shortName);
-    _UnitResynthesizer definingUnitResynthesizer =
-        createUnitResynthesizer(definingUnit, 0);
     // Create LibraryElementImpl.
     bool hasName = unlinkedUnits[0].libraryName.isNotEmpty;
-    LibraryElementImpl library = new LibraryElementImpl(
+    library = new LibraryElementImpl(
         summaryResynthesizer.context,
         unlinkedUnits[0].libraryName,
         hasName ? unlinkedUnits[0].libraryNameOffset : -1,
         unlinkedUnits[0].libraryNameLength);
+    // Create the defining unit.
+    _UnitResynthesizer definingUnitResynthesizer =
+        createUnitResynthesizer(0, librarySource, null);
+    CompilationUnitElementImpl definingUnit = definingUnitResynthesizer.unit;
     definingUnitResynthesizer.buildDocumentation(
         library, unlinkedUnits[0].libraryDocumentationComment);
     definingUnitResynthesizer.buildAnnotations(
@@ -1128,19 +1219,19 @@
     definingUnit.source = librarySource;
     definingUnit.librarySource = librarySource;
     // Create parts.
-    List<CompilationUnitElement> partUnits = <CompilationUnitElement>[];
+    List<_UnitResynthesizer> partResynthesizers = <_UnitResynthesizer>[];
     UnlinkedUnit unlinkedDefiningUnit = unlinkedUnits[0];
     assert(unlinkedDefiningUnit.publicNamespace.parts.length + 1 ==
         linkedLibrary.units.length);
     for (int i = 1; i < linkedLibrary.units.length; i++) {
-      CompilationUnitElementImpl part = buildPart(
+      _UnitResynthesizer partResynthesizer = buildPart(
           definingUnitResynthesizer,
           unlinkedDefiningUnit.publicNamespace.parts[i - 1],
           unlinkedDefiningUnit.parts[i - 1],
           i);
-      partUnits.add(part);
+      partResynthesizers.add(partResynthesizer);
     }
-    library.parts = partUnits;
+    library.parts = partResynthesizers.map((r) => r.unit).toList();
     // Create imports.
     List<ImportElement> imports = <ImportElement>[];
     for (int i = 0; i < unlinkedDefiningUnit.imports.length; i++) {
@@ -1164,9 +1255,7 @@
     library.exports = exports;
     // Populate units.
     populateUnit(definingUnitResynthesizer);
-    for (int i = 0; i < partUnits.length; i++) {
-      _UnitResynthesizer partResynthesizer =
-          createUnitResynthesizer(partUnits[i], i + 1);
+    for (_UnitResynthesizer partResynthesizer in partResynthesizers) {
       populateUnit(partResynthesizer);
     }
     BuildLibraryElementUtils.patchTopLevelAccessors(library);
@@ -1206,32 +1295,30 @@
    * Create, but do not populate, the [CompilationUnitElement] for a part other
    * than the defining compilation unit.
    */
-  CompilationUnitElementImpl buildPart(
-      _UnitResynthesizer definingUnitResynthesizer,
-      String uri,
-      UnlinkedPart partDecl,
-      int unitNum) {
+  _UnitResynthesizer buildPart(_UnitResynthesizer definingUnitResynthesizer,
+      String uri, UnlinkedPart partDecl, int unitNum) {
     Source unitSource =
         summaryResynthesizer.sourceFactory.resolveUri(librarySource, uri);
-    CompilationUnitElementImpl partUnit =
-        new CompilationUnitElementImpl(unitSource.shortName);
+    _UnitResynthesizer partResynthesizer =
+        createUnitResynthesizer(unitNum, unitSource, partDecl);
+    CompilationUnitElementImpl partUnit = partResynthesizer.unit;
     partUnit.uriOffset = partDecl.uriOffset;
     partUnit.uriEnd = partDecl.uriEnd;
     partUnit.source = unitSource;
     partUnit.librarySource = librarySource;
     partUnit.uri = uri;
-    definingUnitResynthesizer.buildAnnotations(partUnit, partDecl.annotations);
-    return partUnit;
+    return partResynthesizer;
   }
 
   /**
    * Set up data structures for deserializing a compilation unit.
    */
   _UnitResynthesizer createUnitResynthesizer(
-      CompilationUnitElementImpl unit, int unitNum) {
+      int unitNum, Source unitSource, UnlinkedPart unlinkedPart) {
     LinkedUnit linkedUnit = linkedLibrary.units[unitNum];
     UnlinkedUnit unlinkedUnit = unlinkedUnits[unitNum];
-    return new _UnitResynthesizer(this, unlinkedUnit, linkedUnit, unit);
+    return new _UnitResynthesizer(
+        this, unlinkedUnit, linkedUnit, unitSource, unlinkedPart);
   }
 
   /**
@@ -1242,7 +1329,7 @@
   List<String> getReferencedLocationComponents(
       int dependencyIndex, int unit, String name) {
     if (dependencyIndex == 0) {
-      String referencedLibraryUri = librarySource.uri.toString();
+      String referencedLibraryUri = libraryUri;
       String partUri;
       if (unit != 0) {
         String uri = unlinkedUnits[0].publicNamespace.parts[unit - 1];
@@ -1465,6 +1552,31 @@
   }
 }
 
+class _ResynthesizerContext implements ResynthesizerContext {
+  final _UnitResynthesizer _unitResynthesizer;
+
+  _ResynthesizerContext(this._unitResynthesizer);
+
+  @override
+  ElementAnnotationImpl buildAnnotation(UnlinkedConst uc) {
+    return _unitResynthesizer.buildAnnotation(uc);
+  }
+
+  @override
+  Expression buildExpression(UnlinkedConst uc) {
+    return _unitResynthesizer._buildConstExpression(uc);
+  }
+
+  @override
+  DartType resolveTypeRef(
+      EntityRef type, TypeParameterizedElementMixin typeParameterContext,
+      {bool defaultVoid: false, bool instantiateToBoundsAllowed: true}) {
+    return _unitResynthesizer.buildType(type, typeParameterContext,
+        defaultVoid: defaultVoid,
+        instantiateToBoundsAllowed: instantiateToBoundsAllowed);
+  }
+}
+
 /**
  * An instance of [_UnitResynthesizer] is responsible for resynthesizing the
  * elements in a single unit from that unit's summary.
@@ -1489,7 +1601,7 @@
    * The [CompilationUnitElementImpl] for the compilation unit currently being
    * resynthesized.
    */
-  final CompilationUnitElementImpl unit;
+  CompilationUnitElementImpl unit;
 
   /**
    * [ElementHolder] into which resynthesized elements should be placed.  This
@@ -1549,19 +1661,44 @@
    */
   Map<String, ConstructorElementImpl> constructors;
 
+  int numLinkedReferences;
+  int numUnlinkedReferences;
+
   /**
    * List of [_ReferenceInfo] objects describing the references in the current
-   * compilation unit.
+   * compilation unit.  This list is works as a lazily filled cache, use
+   * [getReferenceInfo] to get the [_ReferenceInfo] for an index.
    */
   List<_ReferenceInfo> referenceInfos;
 
+  /**
+   * The [ResynthesizerContext] for this resynthesize session.
+   */
+  ResynthesizerContext _resynthesizerContext;
+
+  /**
+   * TODO(scheglov) clean up after moving resynthesize logic to Impl.
+   */
+  TypeParameterizedElementMixin _currentTypeParameterizedElement;
+
   _UnitResynthesizer(this.libraryResynthesizer, this.unlinkedUnit,
-      this.linkedUnit, this.unit) {
+      this.linkedUnit, Source unitSource, UnlinkedPart unlinkedPart) {
+    _resynthesizerContext = new _ResynthesizerContext(this);
+    unit = new CompilationUnitElementImpl.forSerialized(
+        libraryResynthesizer.library,
+        _resynthesizerContext,
+        unlinkedUnit,
+        unlinkedPart,
+        unitSource.shortName);
     for (EntityRef t in linkedUnit.types) {
       linkedTypeMap[t.slot] = t;
     }
     constCycles = linkedUnit.constCycles.toSet();
-    populateReferenceInfos();
+    numLinkedReferences = linkedUnit.references.length;
+    numUnlinkedReferences = unlinkedUnit.references.length;
+    referenceInfos = new List<_ReferenceInfo>(numLinkedReferences);
+    _currentTypeParameterizedElement =
+        new _CurrentTypeParameterizedElement(this);
   }
 
   SummaryResynthesizer get summaryResynthesizer =>
@@ -1570,36 +1707,40 @@
   TypeProvider get typeProvider => summaryResynthesizer.typeProvider;
 
   /**
+   * Build [ElementAnnotationImpl] for the given [UnlinkedConst].
+   */
+  ElementAnnotationImpl buildAnnotation(UnlinkedConst uc) {
+    ElementAnnotationImpl elementAnnotation = new ElementAnnotationImpl(unit);
+    Expression constExpr = _buildConstExpression(uc);
+    if (constExpr is Identifier) {
+      elementAnnotation.element = constExpr.staticElement;
+      elementAnnotation.annotationAst = AstFactory.annotation(constExpr);
+    } else if (constExpr is InstanceCreationExpression) {
+      elementAnnotation.element = constExpr.staticElement;
+      Identifier typeName = constExpr.constructorName.type.name;
+      SimpleIdentifier constructorName = constExpr.constructorName.name;
+      if (typeName is SimpleIdentifier && constructorName != null) {
+        // E.g. `@cls.ctor()`.  Since `cls.ctor` would have been parsed as
+        // a PrefixedIdentifier, we need to resynthesize it as one.
+        typeName = AstFactory.identifier(typeName, constructorName);
+        constructorName = null;
+      }
+      elementAnnotation.annotationAst = AstFactory.annotation2(
+          typeName, constructorName, constExpr.argumentList);
+    } else {
+      throw new StateError(
+          'Unexpected annotation type: ${constExpr.runtimeType}');
+    }
+    return elementAnnotation;
+  }
+
+  /**
    * Build the annotations for the given [element].
    */
   void buildAnnotations(
       ElementImpl element, List<UnlinkedConst> serializedAnnotations) {
     if (serializedAnnotations.isNotEmpty) {
-      element.metadata = serializedAnnotations.map((UnlinkedConst a) {
-        ElementAnnotationImpl elementAnnotation =
-            new ElementAnnotationImpl(this.unit);
-        Expression constExpr = _buildConstExpression(a);
-        if (constExpr is Identifier) {
-          elementAnnotation.element = constExpr.staticElement;
-          elementAnnotation.annotationAst = AstFactory.annotation(constExpr);
-        } else if (constExpr is InstanceCreationExpression) {
-          elementAnnotation.element = constExpr.staticElement;
-          Identifier typeName = constExpr.constructorName.type.name;
-          SimpleIdentifier constructorName = constExpr.constructorName.name;
-          if (typeName is SimpleIdentifier && constructorName != null) {
-            // E.g. `@cls.ctor()`.  Since `cls.ctor` would have been parsed as
-            // a PrefixedIdentifier, we need to resynthesize it as one.
-            typeName = AstFactory.identifier(typeName, constructorName);
-            constructorName = null;
-          }
-          elementAnnotation.annotationAst = AstFactory.annotation2(
-              typeName, constructorName, constExpr.argumentList);
-        } else {
-          throw new StateError(
-              'Unexpected annotation type: ${constExpr.runtimeType}');
-        }
-        return elementAnnotation;
-      }).toList();
+      element.metadata = serializedAnnotations.map(buildAnnotation).toList();
     }
   }
 
@@ -1610,7 +1751,7 @@
     ClassElement classElement;
     if (libraryResynthesizer.isCoreLibrary &&
         serializedClass.supertype == null) {
-      classElement = buildClassImpl(serializedClass);
+      classElement = buildClassImpl(serializedClass, null);
       if (!serializedClass.hasNoSupertype) {
         libraryResynthesizer.delayedObjectSubclasses.add(classElement);
       }
@@ -1621,25 +1762,11 @@
   }
 
   /**
-   * Resynthesize a [ClassElementImpl].
+   * Fill the given [ClassElementImpl] with executable elements and fields.
    */
-  ClassElementImpl buildClassImpl(UnlinkedClass serializedClass) {
-    ClassElementImpl classElement =
-        new ClassElementImpl(serializedClass.name, serializedClass.nameOffset);
-    classElement.hasBeenInferred = summaryResynthesizer.strongMode;
-    classElement.typeParameters =
-        buildTypeParameters(serializedClass.typeParameters);
-    classElement.abstract = serializedClass.isAbstract;
-    classElement.mixinApplication = serializedClass.isMixinApplication;
-    InterfaceTypeImpl correspondingType = new InterfaceTypeImpl(classElement);
-    if (serializedClass.supertype != null) {
-      classElement.supertype = buildType(serializedClass.supertype);
-    } else if (!libraryResynthesizer.isCoreLibrary) {
-      classElement.supertype = typeProvider.objectType;
-    }
-    classElement.interfaces =
-        serializedClass.interfaces.map(buildType).toList();
-    classElement.mixins = serializedClass.mixins.map(buildType).toList();
+  void buildClassExecutables(
+      ClassElementImpl classElement, UnlinkedClass serializedClass) {
+    currentTypeParameters.add(classElement.typeParameters);
     ElementHolder memberHolder = new ElementHolder();
     fields = <String, FieldElementImpl>{};
     for (UnlinkedVariable serializedVariable in serializedClass.fields) {
@@ -1652,8 +1779,7 @@
       switch (serializedExecutable.kind) {
         case UnlinkedExecutableKind.constructor:
           constructorFound = true;
-          buildConstructor(
-              serializedExecutable, memberHolder, correspondingType);
+          buildConstructor(serializedExecutable, classElement, memberHolder);
           break;
         case UnlinkedExecutableKind.functionOrMethod:
         case UnlinkedExecutableKind.getter:
@@ -1661,7 +1787,7 @@
           if (serializedExecutable.isStatic) {
             currentTypeParameters.removeLast();
           }
-          buildExecutable(serializedExecutable, memberHolder);
+          buildExecutable(serializedExecutable, classElement, memberHolder);
           if (serializedExecutable.isStatic) {
             currentTypeParameters.add(classElement.typeParameters);
           }
@@ -1673,7 +1799,7 @@
         // Synthesize implicit constructors.
         ConstructorElementImpl constructor = new ConstructorElementImpl('', -1);
         constructor.synthetic = true;
-        constructor.returnType = correspondingType;
+        constructor.returnType = classElement.type;
         constructor.type = new FunctionTypeImpl.elementWithNameAndArgs(
             constructor, null, getCurrentTypeArguments(), false);
         memberHolder.addConstructor(constructor);
@@ -1683,14 +1809,44 @@
     classElement.accessors = memberHolder.accessors;
     classElement.fields = memberHolder.fields;
     classElement.methods = memberHolder.methods;
-    correspondingType.typeArguments = getCurrentTypeArguments();
-    classElement.type = correspondingType;
-    buildDocumentation(classElement, serializedClass.documentationComment);
-    buildAnnotations(classElement, serializedClass.annotations);
-    buildCodeRange(classElement, serializedClass.codeRange);
     resolveConstructorInitializers(classElement);
     currentTypeParameters.removeLast();
     assert(currentTypeParameters.isEmpty);
+  }
+
+  /**
+   * Resynthesize a [ClassElementImpl].  If [handle] is not `null`, then
+   * executables are not resynthesized, and [InterfaceTypeImpl] is created
+   * around the [handle], so that executables are resynthesized lazily.
+   */
+  ClassElementImpl buildClassImpl(
+      UnlinkedClass serializedClass, ClassElementHandle handle) {
+    ClassElementImpl classElement =
+        new ClassElementImpl.forSerialized(serializedClass, unit);
+    classElement.hasBeenInferred = summaryResynthesizer.strongMode;
+    InterfaceTypeImpl correspondingType =
+        new InterfaceTypeImpl(handle ?? classElement);
+    if (serializedClass.supertype != null) {
+      classElement.supertype =
+          buildType(serializedClass.supertype, classElement);
+    } else if (!libraryResynthesizer.isCoreLibrary) {
+      classElement.supertype = typeProvider.objectType;
+    }
+    classElement.interfaces = serializedClass.interfaces
+        .map((EntityRef t) => buildType(t, classElement))
+        .toList();
+    classElement.mixins = serializedClass.mixins
+        .map((EntityRef t) => buildType(t, classElement))
+        .toList();
+    // TODO(scheglov) move to ClassElementImpl
+    correspondingType.typeArguments = classElement.typeParameterTypes;
+    classElement.type = correspondingType;
+    assert(currentTypeParameters.isEmpty);
+    // TODO(scheglov) Somehow Observatory shows too much time spent here
+    // during DDC run on the large codebase. I would expect only Object here.
+    if (handle == null) {
+      buildClassExecutables(classElement, serializedClass);
+    }
     fields = null;
     constructors = null;
     return classElement;
@@ -1729,24 +1885,22 @@
    * constructor.
    */
   void buildConstructor(UnlinkedExecutable serializedExecutable,
-      ElementHolder holder, InterfaceType classType) {
+      ClassElementImpl classElement, ElementHolder holder) {
     assert(serializedExecutable.kind == UnlinkedExecutableKind.constructor);
-    currentConstructor = new ConstructorElementImpl(
-        serializedExecutable.name, serializedExecutable.nameOffset);
+    currentConstructor = new ConstructorElementImpl.forSerialized(
+        serializedExecutable, classElement);
     currentConstructor.isCycleFree = serializedExecutable.isConst &&
         !constCycles.contains(serializedExecutable.constCycleSlot);
     if (serializedExecutable.name.isEmpty) {
       currentConstructor.nameEnd =
-          serializedExecutable.nameOffset + classType.name.length;
+          serializedExecutable.nameOffset + classElement.name.length;
     } else {
       currentConstructor.nameEnd = serializedExecutable.nameEnd;
       currentConstructor.periodOffset = serializedExecutable.periodOffset;
     }
     constructors[serializedExecutable.name] = currentConstructor;
-    currentConstructor.returnType = classType;
+    currentConstructor.returnType = classElement.type;
     buildExecutableCommonParts(currentConstructor, serializedExecutable);
-    currentConstructor.factory = serializedExecutable.isFactory;
-    currentConstructor.const2 = serializedExecutable.isConst;
     currentConstructor.constantInitializers = serializedExecutable
         .constantInitializers
         .map(buildConstructorInitializer)
@@ -1755,17 +1909,17 @@
       if (serializedExecutable.isFactory) {
         EntityRef redirectedConstructor =
             serializedExecutable.redirectedConstructor;
-        _ReferenceInfo info = referenceInfos[redirectedConstructor.reference];
+        _ReferenceInfo info = getReferenceInfo(redirectedConstructor.reference);
         List<EntityRef> typeArguments = redirectedConstructor.typeArguments;
         currentConstructor.redirectedConstructor = _createConstructorElement(
             _createConstructorDefiningType(info, typeArguments), info);
       } else {
         List<String> locationComponents = unit.location.components.toList();
-        locationComponents.add(classType.name);
+        locationComponents.add(classElement.name);
         locationComponents.add(serializedExecutable.redirectedConstructorName);
         currentConstructor.redirectedConstructor =
             new _DeferredConstructorElement._(
-                classType,
+                classElement.type,
                 serializedExecutable.redirectedConstructorName,
                 new ElementLocationImpl.con3(locationComponents));
       }
@@ -1889,7 +2043,8 @@
   /**
    * Resynthesize an [ExecutableElement] and place it in the given [holder].
    */
-  void buildExecutable(UnlinkedExecutable serializedExecutable,
+  void buildExecutable(
+      UnlinkedExecutable serializedExecutable, ElementImpl enclosingElement,
       [ElementHolder holder]) {
     bool isTopLevel = holder == null;
     if (holder == null) {
@@ -1905,36 +2060,28 @@
       case UnlinkedExecutableKind.functionOrMethod:
         if (isTopLevel) {
           FunctionElementImpl executableElement =
-              new FunctionElementImpl(name, serializedExecutable.nameOffset);
+              new FunctionElementImpl.forSerialized(
+                  serializedExecutable, enclosingElement);
           buildExecutableCommonParts(executableElement, serializedExecutable);
           holder.addFunction(executableElement);
         } else {
           MethodElementImpl executableElement =
-              new MethodElementImpl(name, serializedExecutable.nameOffset);
-          executableElement.abstract = serializedExecutable.isAbstract;
+              new MethodElementImpl.forSerialized(
+                  serializedExecutable, enclosingElement);
           buildExecutableCommonParts(executableElement, serializedExecutable);
-          executableElement.static = serializedExecutable.isStatic;
           holder.addMethod(executableElement);
         }
         break;
       case UnlinkedExecutableKind.getter:
       case UnlinkedExecutableKind.setter:
         PropertyAccessorElementImpl executableElement =
-            new PropertyAccessorElementImpl(
-                name, serializedExecutable.nameOffset);
-        if (isTopLevel) {
-          executableElement.static = true;
-        } else {
-          executableElement.static = serializedExecutable.isStatic;
-          executableElement.abstract = serializedExecutable.isAbstract;
-        }
+            new PropertyAccessorElementImpl.forSerialized(
+                serializedExecutable, enclosingElement);
         buildExecutableCommonParts(executableElement, serializedExecutable);
         DartType type;
         if (kind == UnlinkedExecutableKind.getter) {
-          executableElement.getter = true;
           type = executableElement.returnType;
         } else {
-          executableElement.setter = true;
           type = executableElement.parameters[0].type;
         }
         holder.addAccessor(executableElement);
@@ -1969,36 +2116,32 @@
       UnlinkedExecutable serializedExecutable) {
     executableElement.typeParameters =
         buildTypeParameters(serializedExecutable.typeParameters);
-    executableElement.parameters =
-        serializedExecutable.parameters.map(buildParameter).toList();
+    executableElement.parameters = serializedExecutable.parameters
+        .map((p) => buildParameter(p, executableElement))
+        .toList();
     if (serializedExecutable.kind == UnlinkedExecutableKind.constructor) {
       // Caller handles setting the return type.
       assert(serializedExecutable.returnType == null);
     } else {
       bool isSetter =
           serializedExecutable.kind == UnlinkedExecutableKind.setter;
-      executableElement.returnType =
-          buildLinkedType(serializedExecutable.inferredReturnTypeSlot) ??
-              buildType(serializedExecutable.returnType,
-                  defaultVoid: isSetter && summaryResynthesizer.strongMode);
-      executableElement.hasImplicitReturnType =
-          serializedExecutable.returnType == null;
+      executableElement.returnType = buildLinkedType(
+              serializedExecutable.inferredReturnTypeSlot,
+              _currentTypeParameterizedElement) ??
+          buildType(
+              serializedExecutable.returnType, _currentTypeParameterizedElement,
+              defaultVoid: isSetter && summaryResynthesizer.strongMode);
     }
     executableElement.type = new FunctionTypeImpl.elementWithNameAndArgs(
         executableElement, null, getCurrentTypeArguments(skipLevels: 1), false);
-    executableElement.asynchronous = serializedExecutable.isAsynchronous;
-    executableElement.external = serializedExecutable.isExternal;
-    executableElement.generator = serializedExecutable.isGenerator;
-    buildDocumentation(
-        executableElement, serializedExecutable.documentationComment);
-    buildAnnotations(executableElement, serializedExecutable.annotations);
-    buildCodeRange(executableElement, serializedExecutable.codeRange);
-    executableElement.functions =
-        serializedExecutable.localFunctions.map(buildLocalFunction).toList();
+    executableElement.functions = serializedExecutable.localFunctions
+        .map((f) => buildLocalFunction(f, executableElement))
+        .toList();
     executableElement.labels =
         serializedExecutable.localLabels.map(buildLocalLabel).toList();
-    executableElement.localVariables =
-        serializedExecutable.localVariables.map(buildLocalVariable).toList();
+    executableElement.localVariables = serializedExecutable.localVariables
+        .map((v) => buildLocalVariable(v, executableElement))
+        .toList();
     currentTypeParameters.removeLast();
   }
 
@@ -2086,7 +2229,8 @@
    * Build the appropriate [DartType] object corresponding to a slot id in the
    * [LinkedUnit.types] table.
    */
-  DartType buildLinkedType(int slot) {
+  DartType buildLinkedType(
+      int slot, TypeParameterizedElementMixin typeParameterContext) {
     if (slot == 0) {
       // A slot id of 0 means there is no [DartType] object to build.
       return null;
@@ -2097,16 +2241,16 @@
       // stored in this slot.
       return null;
     }
-    return buildType(type);
+    return buildType(type, typeParameterContext);
   }
 
   /**
    * Resynthesize a local [FunctionElement].
    */
   FunctionElementImpl buildLocalFunction(
-      UnlinkedExecutable serializedExecutable) {
-    FunctionElementImpl element = new FunctionElementImpl(
-        serializedExecutable.name, serializedExecutable.nameOffset);
+      UnlinkedExecutable serializedExecutable, ElementImpl enclosingElement) {
+    FunctionElementImpl element = new FunctionElementImpl.forSerialized(
+        serializedExecutable, enclosingElement);
     if (serializedExecutable.visibleOffset != 0) {
       element.setVisibleRange(serializedExecutable.visibleOffset,
           serializedExecutable.visibleLength);
@@ -2129,33 +2273,37 @@
   /**
    * Resynthesize a [LocalVariableElement].
    */
-  LocalVariableElement buildLocalVariable(UnlinkedVariable serializedVariable) {
+  LocalVariableElement buildLocalVariable(UnlinkedVariable serializedVariable,
+      ExecutableElementImpl enclosingExecutable) {
     LocalVariableElementImpl element;
     if (serializedVariable.constExpr != null && serializedVariable.isConst) {
       ConstLocalVariableElementImpl constElement =
-          new ConstLocalVariableElementImpl(
-              serializedVariable.name, serializedVariable.nameOffset);
+          new ConstLocalVariableElementImpl.forSerialized(
+              serializedVariable, enclosingExecutable);
       element = constElement;
       constElement.constantInitializer =
           _buildConstExpression(serializedVariable.constExpr);
     } else {
-      element = new LocalVariableElementImpl(
-          serializedVariable.name, serializedVariable.nameOffset);
+      element = new LocalVariableElementImpl.forSerialized(
+          serializedVariable, enclosingExecutable);
     }
     if (serializedVariable.visibleOffset != 0) {
       element.setVisibleRange(
           serializedVariable.visibleOffset, serializedVariable.visibleLength);
     }
-    buildVariableCommonParts(element, serializedVariable);
+    buildVariableCommonParts(element, serializedVariable,
+        isLazilyResynthesized: true);
     return element;
   }
 
   /**
    * Resynthesize a [ParameterElement].
    */
-  ParameterElement buildParameter(UnlinkedParam serializedParameter,
+  ParameterElement buildParameter(
+      UnlinkedParam serializedParameter, ElementImpl enclosingElement,
       {bool synthetic: false}) {
     ParameterElementImpl parameterElement;
+    bool isLazilyResynthesized = false;
     int nameOffset = synthetic ? -1 : serializedParameter.nameOffset;
     if (serializedParameter.isInitializingFormal) {
       FieldFormalParameterElementImpl initializingParameter;
@@ -2178,30 +2326,29 @@
       initializingParameter.field = fields[serializedParameter.name];
     } else {
       if (serializedParameter.kind == UnlinkedParamKind.required) {
-        parameterElement =
-            new ParameterElementImpl(serializedParameter.name, nameOffset);
+        parameterElement = new ParameterElementImpl.forSerialized(
+            serializedParameter, enclosingElement);
+        isLazilyResynthesized = true;
       } else {
         DefaultParameterElementImpl defaultParameter =
-            new DefaultParameterElementImpl(
-                serializedParameter.name, nameOffset);
+            new DefaultParameterElementImpl.forSerialized(
+                serializedParameter, enclosingElement);
+        isLazilyResynthesized = true;
         parameterElement = defaultParameter;
-        if (serializedParameter.defaultValue != null) {
-          defaultParameter.constantInitializer =
-              _buildConstExpression(serializedParameter.defaultValue);
-          defaultParameter.defaultValueCode =
-              serializedParameter.defaultValueCode;
-        }
       }
     }
     parameterElement.synthetic = synthetic;
-    buildAnnotations(parameterElement, serializedParameter.annotations);
-    buildCodeRange(parameterElement, serializedParameter.codeRange);
+    if (!isLazilyResynthesized) {
+      buildAnnotations(parameterElement, serializedParameter.annotations);
+      buildCodeRange(parameterElement, serializedParameter.codeRange);
+    }
     if (serializedParameter.isFunctionTyped) {
       FunctionElementImpl parameterTypeElement =
           new FunctionElementImpl('', -1);
       parameterTypeElement.synthetic = true;
       List<ParameterElement> subParameters = serializedParameter.parameters
-          .map((UnlinkedParam p) => buildParameter(p, synthetic: synthetic))
+          .map((UnlinkedParam p) =>
+              buildParameter(p, parameterTypeElement, synthetic: synthetic))
           .toList();
       if (synthetic) {
         parameterTypeElement.parameters = subParameters;
@@ -2210,7 +2357,8 @@
         parameterTypeElement.shareParameters(subParameters);
         parameterTypeElement.enclosingElement = parameterElement;
       }
-      parameterTypeElement.returnType = buildType(serializedParameter.type);
+      parameterTypeElement.returnType =
+          buildType(serializedParameter.type, _currentTypeParameterizedElement);
       parameterElement.type = new FunctionTypeImpl.elementWithNameAndArgs(
           parameterTypeElement, null, getCurrentTypeArguments(), false);
       parameterTypeElement.type = parameterElement.type;
@@ -2221,11 +2369,15 @@
         parameterElement.type =
             fields[serializedParameter.name]?.type ?? DynamicTypeImpl.instance;
       } else {
-        parameterElement.type =
-            buildLinkedType(serializedParameter.inferredTypeSlot) ??
-                buildType(serializedParameter.type);
+        parameterElement.type = buildLinkedType(
+                serializedParameter.inferredTypeSlot,
+                _currentTypeParameterizedElement) ??
+            buildType(
+                serializedParameter.type, _currentTypeParameterizedElement);
       }
-      parameterElement.hasImplicitType = serializedParameter.type == null;
+      if (!isLazilyResynthesized) {
+        parameterElement.hasImplicitType = serializedParameter.type == null;
+      }
     }
     buildVariableInitializer(parameterElement, serializedParameter.initializer);
     switch (serializedParameter.kind) {
@@ -2239,9 +2391,11 @@
         parameterElement.parameterKind = ParameterKind.REQUIRED;
         break;
     }
-    if (serializedParameter.visibleOffset != 0) {
-      parameterElement.setVisibleRange(
-          serializedParameter.visibleOffset, serializedParameter.visibleLength);
+    if (!isLazilyResynthesized) {
+      if (serializedParameter.visibleOffset != 0) {
+        parameterElement.setVisibleRange(serializedParameter.visibleOffset,
+            serializedParameter.visibleLength);
+      }
     }
     return parameterElement;
   }
@@ -2253,8 +2407,9 @@
       PropertyInducingElementImpl element,
       UnlinkedVariable serializedVariable) {
     buildVariableCommonParts(element, serializedVariable);
-    element.propagatedType =
-        buildLinkedType(serializedVariable.propagatedTypeSlot);
+    element.propagatedType = buildLinkedType(
+        serializedVariable.propagatedTypeSlot,
+        _currentTypeParameterizedElement);
   }
 
   /**
@@ -2263,7 +2418,8 @@
    * deserialized, so handles are used to avoid having to deserialize other
    * libraries in the process.
    */
-  DartType buildType(EntityRef type,
+  DartType buildType(
+      EntityRef type, TypeParameterizedElementMixin typeParameterContext,
       {bool defaultVoid: false, bool instantiateToBoundsAllowed: true}) {
     if (type == null) {
       if (defaultVoid) {
@@ -2273,14 +2429,16 @@
       }
     }
     if (type.paramReference != 0) {
-      return getTypeParameterFromScope(type.paramReference);
+      return typeParameterContext.getTypeParameterType(type.paramReference);
     } else if (type.syntheticReturnType != null) {
       FunctionElementImpl element = new FunctionElementImpl('', -1);
       element.synthetic = true;
       element.parameters = type.syntheticParams
-          .map((UnlinkedParam param) => buildParameter(param, synthetic: true))
+          .map((UnlinkedParam param) =>
+              buildParameter(param, element, synthetic: true))
           .toList();
-      element.returnType = buildType(type.syntheticReturnType);
+      element.returnType =
+          buildType(type.syntheticReturnType, typeParameterContext);
       FunctionTypeImpl result = new FunctionTypeImpl.elementWithNameAndArgs(
           element, null, null, false);
       element.type = result;
@@ -2288,12 +2446,12 @@
     } else {
       DartType getTypeArgument(int i) {
         if (i < type.typeArguments.length) {
-          return buildType(type.typeArguments[i]);
+          return buildType(type.typeArguments[i], typeParameterContext);
         } else {
           return DynamicTypeImpl.instance;
         }
       }
-      _ReferenceInfo referenceInfo = referenceInfos[type.reference];
+      _ReferenceInfo referenceInfo = getReferenceInfo(type.reference);
       return referenceInfo.buildType(
           instantiateToBoundsAllowed,
           type.typeArguments.length,
@@ -2308,21 +2466,18 @@
    */
   void buildTypedef(UnlinkedTypedef serializedTypedef) {
     FunctionTypeAliasElementImpl functionTypeAliasElement =
-        new FunctionTypeAliasElementImpl(
-            serializedTypedef.name, serializedTypedef.nameOffset);
-    functionTypeAliasElement.typeParameters =
-        buildTypeParameters(serializedTypedef.typeParameters);
-    functionTypeAliasElement.parameters =
-        serializedTypedef.parameters.map(buildParameter).toList();
+        new FunctionTypeAliasElementImpl.forSerialized(serializedTypedef, unit);
+    // TODO(scheglov) remove this after delaying parameters and their types
+    currentTypeParameters.add(functionTypeAliasElement.typeParameters);
+    functionTypeAliasElement.parameters = serializedTypedef.parameters
+        .map((p) => buildParameter(p, functionTypeAliasElement))
+        .toList();
     functionTypeAliasElement.returnType =
-        buildType(serializedTypedef.returnType);
+        buildType(serializedTypedef.returnType, functionTypeAliasElement);
     functionTypeAliasElement.type =
         new FunctionTypeImpl.forTypedef(functionTypeAliasElement);
-    buildDocumentation(
-        functionTypeAliasElement, serializedTypedef.documentationComment);
-    buildAnnotations(functionTypeAliasElement, serializedTypedef.annotations);
-    buildCodeRange(functionTypeAliasElement, serializedTypedef.codeRange);
     unitHolder.addTypeAlias(functionTypeAliasElement);
+    // TODO(scheglov) remove this after delaying parameters and their types
     currentTypeParameters.removeLast();
     assert(currentTypeParameters.isEmpty);
   }
@@ -2409,16 +2564,20 @@
    * Handle the parts that are common to variables.
    */
   void buildVariableCommonParts(
-      VariableElementImpl element, UnlinkedVariable serializedVariable) {
-    element.type = buildLinkedType(serializedVariable.inferredTypeSlot) ??
-        buildType(serializedVariable.type);
-    element.const3 = serializedVariable.isConst;
-    element.final2 = serializedVariable.isFinal;
-    element.hasImplicitType = serializedVariable.type == null;
+      VariableElementImpl element, UnlinkedVariable serializedVariable,
+      {bool isLazilyResynthesized: false}) {
+    element.type = buildLinkedType(serializedVariable.inferredTypeSlot,
+            _currentTypeParameterizedElement) ??
+        buildType(serializedVariable.type, _currentTypeParameterizedElement);
+    if (!isLazilyResynthesized) {
+      element.const3 = serializedVariable.isConst;
+      element.final2 = serializedVariable.isFinal;
+      element.hasImplicitType = serializedVariable.type == null;
+      buildDocumentation(element, serializedVariable.documentationComment);
+      buildAnnotations(element, serializedVariable.annotations);
+      buildCodeRange(element, serializedVariable.codeRange);
+    }
     buildVariableInitializer(element, serializedVariable.initializer);
-    buildDocumentation(element, serializedVariable.documentationComment);
-    buildAnnotations(element, serializedVariable.annotations);
-    buildCodeRange(element, serializedVariable.codeRange);
   }
 
   /**
@@ -2431,9 +2590,8 @@
       return null;
     }
     FunctionElementImpl initializerElement =
-        buildLocalFunction(serializedInitializer);
+        buildLocalFunction(serializedInitializer, variable);
     initializerElement.synthetic = true;
-    initializerElement.setCodeRange(null, null);
     variable.initializer = initializerElement;
   }
 
@@ -2443,7 +2601,8 @@
   void finishTypeParameter(UnlinkedTypeParam serializedTypeParameter,
       TypeParameterElementImpl typeParameterElement) {
     if (serializedTypeParameter.bound != null) {
-      typeParameterElement.bound = buildType(serializedTypeParameter.bound,
+      typeParameterElement.bound = buildType(
+          serializedTypeParameter.bound, _currentTypeParameterizedElement,
           instantiateToBoundsAllowed: false);
     }
   }
@@ -2468,44 +2627,24 @@
   }
 
   /**
-   * Get the type parameter from the surrounding scope whose De Bruijn index is
-   * [index].
+   * Return [_ReferenceInfo] with the given [index], lazily resolving it.
    */
-  DartType getTypeParameterFromScope(int index) {
-    for (int i = currentTypeParameters.length - 1; i >= 0; i--) {
-      List<TypeParameterElement> paramsAtThisNestingLevel =
-          currentTypeParameters[i];
-      int numParamsAtThisNestingLevel = paramsAtThisNestingLevel.length;
-      if (index <= numParamsAtThisNestingLevel) {
-        return paramsAtThisNestingLevel[numParamsAtThisNestingLevel - index]
-            .type;
-      }
-      index -= numParamsAtThisNestingLevel;
-    }
-    throw new StateError('Type parameter not found');
-  }
-
-  /**
-   * Populate [referenceInfos] with the correct information for the current
-   * compilation unit.
-   */
-  void populateReferenceInfos() {
-    int numLinkedReferences = linkedUnit.references.length;
-    int numUnlinkedReferences = unlinkedUnit.references.length;
-    referenceInfos = new List<_ReferenceInfo>(numLinkedReferences);
-    for (int i = 0; i < numLinkedReferences; i++) {
-      LinkedReference linkedReference = linkedUnit.references[i];
+  _ReferenceInfo getReferenceInfo(int index) {
+    _ReferenceInfo result = referenceInfos[index];
+    if (result == null) {
+      LinkedReference linkedReference = linkedUnit.references[index];
       String name;
       int containingReference;
-      if (i < numUnlinkedReferences) {
-        name = unlinkedUnit.references[i].name;
-        containingReference = unlinkedUnit.references[i].prefixReference;
+      if (index < numUnlinkedReferences) {
+        name = unlinkedUnit.references[index].name;
+        containingReference = unlinkedUnit.references[index].prefixReference;
       } else {
-        name = linkedUnit.references[i].name;
-        containingReference = linkedUnit.references[i].containingReference;
+        name = linkedUnit.references[index].name;
+        containingReference = linkedUnit.references[index].containingReference;
       }
-      _ReferenceInfo enclosingInfo =
-          containingReference != 0 ? referenceInfos[containingReference] : null;
+      _ReferenceInfo enclosingInfo = containingReference != 0
+          ? getReferenceInfo(containingReference)
+          : null;
       Element element;
       DartType type;
       int numTypeParameters = linkedReference.numTypeParameters;
@@ -2596,9 +2735,29 @@
             break;
         }
       }
-      referenceInfos[i] = new _ReferenceInfo(libraryResynthesizer,
-          enclosingInfo, name, element, type, numTypeParameters);
+      result = new _ReferenceInfo(libraryResynthesizer, enclosingInfo, name,
+          element, type, numTypeParameters);
+      referenceInfos[index] = result;
     }
+    return result;
+  }
+
+  /**
+   * Get the type parameter from the surrounding scope whose De Bruijn index is
+   * [index].
+   */
+  DartType getTypeParameterFromScope(int index) {
+    for (int i = currentTypeParameters.length - 1; i >= 0; i--) {
+      List<TypeParameterElement> paramsAtThisNestingLevel =
+          currentTypeParameters[i];
+      int numParamsAtThisNestingLevel = paramsAtThisNestingLevel.length;
+      if (index <= numParamsAtThisNestingLevel) {
+        return paramsAtThisNestingLevel[numParamsAtThisNestingLevel - index]
+            .type;
+      }
+      index -= numParamsAtThisNestingLevel;
+    }
+    throw new StateError('Type parameter not found');
   }
 
   /**
@@ -2608,7 +2767,7 @@
   void populateUnit() {
     unlinkedUnit.classes.forEach(buildClass);
     unlinkedUnit.enums.forEach(buildEnum);
-    unlinkedUnit.executables.forEach(buildExecutable);
+    unlinkedUnit.executables.forEach((e) => buildExecutable(e, unit));
     unlinkedUnit.typedefs.forEach(buildTypedef);
     unlinkedUnit.variables.forEach(buildVariable);
     unit.accessors = unitHolder.accessors;
@@ -2638,7 +2797,6 @@
     for (PropertyAccessorElementImpl accessor in unit.accessors) {
       elementMap[accessor.identifier] = accessor;
     }
-    buildCodeRange(unit, unlinkedUnit.codeRange);
     assert(currentTypeParameters.isEmpty);
   }
 
@@ -2682,7 +2840,9 @@
       _ReferenceInfo info, List<EntityRef> typeArgumentRefs) {
     bool isClass = info.element is ClassElement;
     _ReferenceInfo classInfo = isClass ? info : info.enclosing;
-    List<DartType> typeArguments = typeArgumentRefs.map(buildType).toList();
+    List<DartType> typeArguments = typeArgumentRefs
+        .map((t) => buildType(t, _currentTypeParameterizedElement))
+        .toList();
     return classInfo.buildType(true, typeArguments.length, (i) {
       if (i < typeArguments.length) {
         return typeArguments[i];
diff --git a/pkg/analyzer/lib/src/summary/summarize_ast.dart b/pkg/analyzer/lib/src/summary/summarize_ast.dart
index 8349428..f5dd314 100644
--- a/pkg/analyzer/lib/src/summary/summarize_ast.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_ast.dart
@@ -388,7 +388,9 @@
       return const <UnlinkedConstBuilder>[];
     }
     return annotations.map((Annotation a) {
-      Map<int, int> localClosureIndexMap = null; // TODO(paulberry): fix.
+      // Closures can't appear inside annotations, so we don't need a
+      // localClosureIndexMap.
+      Map<int, int> localClosureIndexMap = null;
       _ConstExprSerializer serializer =
           new _ConstExprSerializer(this, localClosureIndexMap, null);
       serializer.serializeAnnotation(a);
@@ -641,7 +643,7 @@
     }
     b.visibleOffset = enclosingBlock?.offset;
     b.visibleLength = enclosingBlock?.length;
-    serializeFunctionBody(b, body);
+    serializeFunctionBody(b, null, body);
     scopes.removeLast();
     assert(scopes.length == oldScopesLength);
     return b;
@@ -651,8 +653,12 @@
    * Record local functions and variables into the given executable. The given
    * [body] is usually an actual [FunctionBody], but may be an [Expression]
    * when we process a synthetic variable initializer function.
+   *
+   * If [initializers] is non-`null`, closures occurring inside the initializers
+   * are serialized first.
    */
-  void serializeFunctionBody(UnlinkedExecutableBuilder b, AstNode body) {
+  void serializeFunctionBody(UnlinkedExecutableBuilder b,
+      List<ConstructorInitializer> initializers, AstNode body) {
     if (body is BlockFunctionBody || body is ExpressionFunctionBody) {
       for (UnlinkedParamBuilder parameter in b.parameters) {
         parameter.visibleOffset = body.offset;
@@ -665,6 +671,11 @@
     executables = <UnlinkedExecutableBuilder>[];
     labels = <UnlinkedLabelBuilder>[];
     variables = <UnlinkedVariableBuilder>[];
+    if (initializers != null) {
+      for (ConstructorInitializer initializer in initializers) {
+        initializer.accept(this);
+      }
+    }
     body.accept(this);
     b.localFunctions = executables;
     b.localLabels = labels;
@@ -700,7 +711,7 @@
     }
     UnlinkedExecutableBuilder initializer =
         new UnlinkedExecutableBuilder(nameOffset: expression.offset);
-    serializeFunctionBody(initializer, expression);
+    serializeFunctionBody(initializer, null, expression);
     initializer.inferredReturnTypeSlot = assignSlot();
     return initializer;
   }
@@ -987,7 +998,9 @@
       if (node.redirectedConstructor != null) {
         b.isRedirectedConstructor = true;
         TypeName typeName = node.redirectedConstructor.type;
-        Map<int, int> localClosureIndexMap = null; // TODO(paulberry): fix.
+        // Closures can't appear inside factory constructor redirections, so we
+        // don't need a localClosureIndexMap.
+        Map<int, int> localClosureIndexMap = null;
         b.redirectedConstructor =
             new _ConstExprSerializer(this, localClosureIndexMap, null)
                 .serializeConstructorRef(null, typeName.name,
@@ -1009,10 +1022,12 @@
     b.documentationComment = serializeDocumentation(node.documentationComment);
     b.annotations = serializeAnnotations(node.metadata);
     b.codeRange = serializeCodeRange(node);
+    Map<int, int> localClosureIndexMap = _withLocalClosureIndexMap(() {
+      serializeFunctionBody(b, node.initializers, node.body);
+    });
     if (node.constKeyword != null) {
       Set<String> constructorParameterNames =
           node.parameters.parameters.map((p) => p.identifier.name).toSet();
-      Map<int, int> localClosureIndexMap = null; // TODO(paulberry): fix.
       b.constantInitializers = node.initializers
           .map((ConstructorInitializer initializer) =>
               serializeConstructorInitializer(initializer, (Expression expr) {
@@ -1021,7 +1036,6 @@
               }))
           .toList();
     }
-    serializeFunctionBody(b, node.body);
     executables.add(b);
   }
 
@@ -1030,7 +1044,9 @@
       DefaultFormalParameter node) {
     UnlinkedParamBuilder b = node.parameter.accept(this);
     if (node.defaultValue != null) {
-      Map<int, int> localClosureIndexMap = null; // TODO(paulberry): fix.
+      // Closures can't appear inside default values, so we don't need a
+      // localClosureIndexMap.
+      Map<int, int> localClosureIndexMap = null;
       b.defaultValue =
           serializeConstExpr(localClosureIndexMap, node.defaultValue);
       b.defaultValueCode = node.defaultValue.toSource();
diff --git a/pkg/analyzer/lib/src/summary/summary_sdk.dart b/pkg/analyzer/lib/src/summary/summary_sdk.dart
index 2dfa154..ec9c988 100644
--- a/pkg/analyzer/lib/src/summary/summary_sdk.dart
+++ b/pkg/analyzer/lib/src/summary/summary_sdk.dart
@@ -13,9 +13,11 @@
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart'
-    show Source, SourceFactory, SourceKind;
+    show DartUriResolver, Source, SourceFactory, SourceKind;
 import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/package_bundle_reader.dart';
 import 'package:analyzer/src/summary/resynthesize.dart';
 import 'package:analyzer/src/task/dart.dart';
 import 'package:analyzer/task/dart.dart';
@@ -30,9 +32,9 @@
   @override
   SummaryResynthesizer resynthesizer;
 
-  SdkSummaryResultProvider(this.context, this.bundle) {
+  SdkSummaryResultProvider(this.context, this.bundle, bool strongMode) {
     resynthesizer = new SdkSummaryResynthesizer(
-        context, typeProvider, context.sourceFactory, bundle);
+        context, typeProvider, context.sourceFactory, bundle, strongMode);
     _buildCoreLibrary();
     _buildAsyncLibrary();
     resynthesizer.finalizeCoreAsyncLibraries();
@@ -119,6 +121,11 @@
           return true;
         }
       }
+    } else if (target is VariableElement) {
+      if (result == PROPAGATED_VARIABLE || result == INFERRED_STATIC_VARIABLE) {
+        entry.setValue(result, target, TargetedResult.EMPTY_LIST);
+        return true;
+      }
     }
     return false;
   }
@@ -156,10 +163,8 @@
   final Map<String, LinkedLibrary> linkedSummaries = <String, LinkedLibrary>{};
 
   SdkSummaryResynthesizer(AnalysisContext context, TypeProvider typeProvider,
-      SourceFactory sourceFactory, this.bundle)
-      : super(null, context, typeProvider, sourceFactory, false) {
-    // TODO(paulberry): we always resynthesize the summary in weak mode.  Is
-    // this ok?
+      SourceFactory sourceFactory, this.bundle, bool strongMode)
+      : super(null, context, typeProvider, sourceFactory, strongMode) {
     for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
       unlinkedSummaries[bundle.unlinkedUnitUris[i]] = bundle.unlinkedUnits[i];
     }
@@ -185,6 +190,82 @@
 }
 
 /**
+ * An implementation of [DartSdk] which provides analysis results for `dart:`
+ * libraries from the given summary file.  This implementation is limited and
+ * suitable only for command-line tools, but not for IDEs - it does not
+ * implement [sdkLibraries], [sdkVersion], [uris] and [fromFileUri].
+ */
+class SummaryBasedDartSdk implements DartSdk {
+  final bool strongMode;
+  SummaryDataStore _dataStore;
+  InSummaryPackageUriResolver _uriResolver;
+  PackageBundle _bundle;
+
+  /**
+   * The [AnalysisContext] which is used for all of the sources in this sdk.
+   */
+  InternalAnalysisContext _analysisContext;
+
+  SummaryBasedDartSdk(String summaryPath, this.strongMode) {
+    _dataStore = new SummaryDataStore(<String>[summaryPath]);
+    _uriResolver = new InSummaryPackageUriResolver(_dataStore);
+    _bundle = _dataStore.bundles.single;
+  }
+
+  /**
+   * Return the [PackageBundle] for this SDK, not `null`.
+   */
+  PackageBundle get bundle => _bundle;
+
+  @override
+  AnalysisContext get context {
+    if (_analysisContext == null) {
+      AnalysisOptionsImpl analysisOptions = new AnalysisOptionsImpl()
+        ..strongMode = strongMode;
+      _analysisContext = new SdkAnalysisContext(analysisOptions);
+      SourceFactory factory = new SourceFactory([new DartUriResolver(this)]);
+      _analysisContext.sourceFactory = factory;
+      _analysisContext.resultProvider =
+          new SdkSummaryResultProvider(_analysisContext, _bundle, strongMode);
+    }
+    return _analysisContext;
+  }
+
+  @override
+  List<SdkLibrary> get sdkLibraries {
+    throw new UnimplementedError();
+  }
+
+  @override
+  String get sdkVersion {
+    throw new UnimplementedError();
+  }
+
+  @override
+  List<String> get uris {
+    throw new UnimplementedError();
+  }
+
+  @override
+  Source fromFileUri(Uri uri) {
+    return null;
+  }
+
+  @override
+  SdkLibrary getSdkLibrary(String uri) {
+    // This is not quite correct, but currently it's used only in
+    // to report errors on importing or exporting of internal libraries.
+    return null;
+  }
+
+  @override
+  Source mapDartUri(String uriStr) {
+    Uri uri = Uri.parse(uriStr);
+    return _uriResolver.resolveAbsolute(uri);
+  }
+}
+
+/**
  * Provider for analysis results.
  */
 abstract class SummaryResultProvider extends ResultProvider {
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index b1b6d95..3d9d552 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -19,6 +19,7 @@
 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
 import 'package:analyzer/src/dart/scanner/reader.dart';
 import 'package:analyzer/src/dart/scanner/scanner.dart';
+import 'package:analyzer/src/error/pending_error.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
@@ -563,6 +564,15 @@
         'PARSE_ERRORS', AnalysisError.NO_ERRORS);
 
 /**
+ * The list of [PendingError]s for a compilation unit.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<PendingError> PENDING_ERRORS =
+    new ListResultDescriptor<PendingError>(
+        'PENDING_ERRORS', const <PendingError>[]);
+
+/**
  * A list of the [VariableElement]s whose type should be known to propagate
  * the type of another variable (the target).
  *
@@ -648,6 +658,15 @@
     new ListResultDescriptor<Source>('REFERENCED_SOURCES', Source.EMPTY_LIST);
 
 /**
+ * The list of [ConstantEvaluationTarget]s on which error verification depends.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<ConstantEvaluationTarget> REQUIRED_CONSTANTS =
+    new ListResultDescriptor<ConstantEvaluationTarget>(
+        'REQUIRED_CONSTANTS', const <ConstantEvaluationTarget>[]);
+
+/**
  * The errors produced while resolving bounds of type parameters of classes,
  * class and function aliases.
  *
@@ -2247,6 +2266,73 @@
 }
 
 /**
+ * A task that builds [REQUIRED_CONSTANTS] for a unit.
+ */
+class ComputeRequiredConstantsTask extends SourceBasedAnalysisTask {
+  /**
+   * The name of the [RESOLVED_UNIT] input.
+   */
+  static const String UNIT_INPUT = 'UNIT_INPUT';
+
+  /**
+   * The task descriptor describing this kind of task.
+   */
+  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+      'ComputeRequiredConstantsTask',
+      createTask,
+      buildInputs,
+      <ResultDescriptor>[PENDING_ERRORS, REQUIRED_CONSTANTS]);
+
+  ComputeRequiredConstantsTask(
+      InternalAnalysisContext context, AnalysisTarget target)
+      : super(context, target);
+
+  @override
+  TaskDescriptor get descriptor => DESCRIPTOR;
+
+  @override
+  void internalPerform() {
+    Source source = getRequiredSource();
+    //
+    // Prepare inputs.
+    //
+    CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+    //
+    // Use the ErrorVerifier to compute errors.
+    //
+    RequiredConstantsComputer computer = new RequiredConstantsComputer(source);
+    unit.accept(computer);
+    List<PendingError> pendingErrors = computer.pendingErrors;
+    List<ConstantEvaluationTarget> requiredConstants =
+        computer.requiredConstants;
+    //
+    // Record outputs.
+    //
+    outputs[PENDING_ERRORS] = pendingErrors;
+    outputs[REQUIRED_CONSTANTS] = requiredConstants;
+  }
+
+  /**
+   * Return a map from the names of the inputs of this kind of task to the task
+   * input descriptors describing those inputs for a task with the
+   * given [target].
+   */
+  static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+    LibrarySpecificUnit unit = target;
+    return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT.of(unit)};
+  }
+
+  /**
+   * Create a [ComputeRequiredConstantsTask] based on the given [target] in
+   * the given [context].
+   */
+  static ComputeRequiredConstantsTask createTask(
+      AnalysisContext context, AnalysisTarget target) {
+    return new ComputeRequiredConstantsTask(context, target);
+  }
+}
+
+/**
  * A base class for analysis tasks whose target is expected to be a
  * [ConstantEvaluationTarget].
  */
@@ -5547,9 +5633,9 @@
  */
 class VerifyUnitTask extends SourceBasedAnalysisTask {
   /**
-   * The name of the [RESOLVED_UNIT] input.
+   * The name of the [PENDING_ERRORS] input.
    */
-  static const String UNIT_INPUT = 'UNIT_INPUT';
+  static const String PENDING_ERRORS_INPUT = 'PENDING_ERRORS_INPUT';
 
   /**
    * The name of the input of a mapping from [REFERENCED_SOURCES] to their
@@ -5564,6 +5650,11 @@
   static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
 
   /**
+   * The name of the [RESOLVED_UNIT] input.
+   */
+  static const String UNIT_INPUT = 'UNIT_INPUT';
+
+  /**
    * The task descriptor describing this kind of task.
    */
   static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('VerifyUnitTask',
@@ -5594,10 +5685,7 @@
     //
     // Prepare inputs.
     //
-    TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
     CompilationUnit unit = getRequiredInput(UNIT_INPUT);
-    sourceTimeMap =
-        getRequiredInput(REFERENCED_SOURCE_MODIFICATION_TIME_MAP_INPUT);
     CompilationUnitElement unitElement = unit.element;
     LibraryElement libraryElement = unitElement.library;
     if (libraryElement == null) {
@@ -5605,6 +5693,10 @@
           'VerifyUnitTask verifying a unit with no library: '
           '${unitElement.source.fullName}');
     }
+    List<PendingError> pendingErrors = getRequiredInput(PENDING_ERRORS_INPUT);
+    sourceTimeMap =
+        getRequiredInput(REFERENCED_SOURCE_MODIFICATION_TIME_MAP_INPUT);
+    TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
     //
     // Validate the directives.
     //
@@ -5626,7 +5718,12 @@
         context.analysisOptions.enableSuperMixins,
         context.analysisOptions.enableAssertMessage);
     unit.accept(errorVerifier);
-
+    //
+    // Convert the pending errors into actual errors.
+    //
+    for (PendingError pendingError in pendingErrors) {
+      errorListener.onError(pendingError.toAnalysisError());
+    }
     //
     // Record outputs.
     //
@@ -5682,6 +5779,8 @@
       UNIT_INPUT: RESOLVED_UNIT.of(unit),
       REFERENCED_SOURCE_MODIFICATION_TIME_MAP_INPUT:
           REFERENCED_SOURCES.of(unit.library).toMapOf(MODIFICATION_TIME),
+      PENDING_ERRORS_INPUT: PENDING_ERRORS.of(unit),
+      'requiredConstants': REQUIRED_CONSTANTS.of(unit).toListOf(CONSTANT_VALUE),
       TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
     };
   }
diff --git a/pkg/analyzer/lib/src/task/options.dart b/pkg/analyzer/lib/src/task/options.dart
index 47acf37..fd1c224 100644
--- a/pkg/analyzer/lib/src/task/options.dart
+++ b/pkg/analyzer/lib/src/task/options.dart
@@ -21,7 +21,7 @@
 import 'package:source_span/source_span.dart';
 import 'package:yaml/yaml.dart';
 
-/// The errors produced while parsing `.analysis_options` files.
+/// The errors produced while parsing an analysis options file.
 ///
 /// The list will be empty if there were no errors, but will not be `null`.
 final ListResultDescriptor<AnalysisError> ANALYSIS_OPTIONS_ERRORS =
@@ -204,7 +204,7 @@
   }
 }
 
-/// A task that generates errors for an `.analysis_options` file.
+/// A task that generates errors for an analysis options file.
 class GenerateOptionsErrorsTask extends SourceBasedAnalysisTask {
   /// The name of the input whose value is the content of the file.
   static const String CONTENT_INPUT_NAME = 'CONTENT_INPUT_NAME';
@@ -276,7 +276,8 @@
    */
   static TaskSuitability suitabilityFor(AnalysisTarget target) {
     if (target is Source &&
-        target.shortName == AnalysisEngine.ANALYSIS_OPTIONS_FILE) {
+        (target.shortName == AnalysisEngine.ANALYSIS_OPTIONS_FILE ||
+            target.shortName == AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE)) {
       return TaskSuitability.HIGHEST;
     }
     return TaskSuitability.NONE;
@@ -324,7 +325,7 @@
   LinterOptionsValidator() : super('linter', const ['rules']);
 }
 
-/// Validates options defined in an `.analysis_options` file.
+/// Validates options defined in an analysis options file.
 class OptionsFileValidator {
   // TODO(pq): move to an extension point.
   final List<OptionsValidator> _validators = [
diff --git a/pkg/analyzer/lib/src/task/options_work_manager.dart b/pkg/analyzer/lib/src/task/options_work_manager.dart
index 2074eb0..7956a8a 100644
--- a/pkg/analyzer/lib/src/task/options_work_manager.dart
+++ b/pkg/analyzer/lib/src/task/options_work_manager.dart
@@ -14,7 +14,7 @@
 import 'package:analyzer/src/task/options.dart';
 import 'package:analyzer/task/model.dart';
 
-/// The manager for `.analysis_options` specific analysis.
+/// The manager for analysis options specific analysis.
 class OptionsWorkManager implements WorkManager {
   /// The context for which work is being managed.
   final InternalAnalysisContext context;
@@ -162,7 +162,7 @@
     return state != CacheState.VALID && state != CacheState.ERROR;
   }
 
-  /// Return `true` if the given target is an `.analysis_options` source.
+  /// Return `true` if the given target is an analysis options source.
   static bool _isOptionsSource(AnalysisTarget target) =>
       target is Source &&
       AnalysisEngine.isAnalysisOptionsFileName(target.fullName);
diff --git a/pkg/analyzer/lib/src/task/strong/info.dart b/pkg/analyzer/lib/src/task/strong/info.dart
index 39885cd..408c05d 100644
--- a/pkg/analyzer/lib/src/task/strong/info.dart
+++ b/pkg/analyzer/lib/src/task/strong/info.dart
@@ -469,7 +469,7 @@
 abstract class StaticInfo {
   /// Strong-mode error code names.
   ///
-  /// Used for error code configuration validation in `.analysis_options`.
+  /// Used for error code configuration validation in an analysis options file.
   static const List<String> names = const [
     //
     // Manually populated.
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 9e15c290..541d5fc 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 0.27.4-alpha.2
+version: 0.27.4-alpha.6
 author: Dart Team <misc@dartlang.org>
 description: Static analyzer for Dart.
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer
@@ -12,7 +12,7 @@
   html: ^0.12.0
   package_config: ^0.1.1
   path: '>=0.9.0 <2.0.0'
-  plugin: ^0.1.0
+  plugin: ^0.2.0
   watcher: '>=0.9.6 <0.10.0'
   yaml: ^2.1.2
 dev_dependencies:
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index f032daf..04481ef 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -3483,6 +3483,10 @@
     _assertTrue("{ do {} while (throw ''); }");
   }
 
+  void test_doStatement_return() {
+    _assertTrue("{ do { return null; } while (1 == 2); }");
+  }
+
   void test_doStatement_true_break() {
     _assertFalse("{ do { break; } while (true); }");
   }
diff --git a/pkg/analyzer/test/generated/hint_code_test.dart b/pkg/analyzer/test/generated/hint_code_test.dart
index 7a05a39..3975270 100644
--- a/pkg/analyzer/test/generated/hint_code_test.dart
+++ b/pkg/analyzer/test/generated/hint_code_test.dart
@@ -1738,6 +1738,29 @@
     verify([source]);
   }
 
+  void test_required_method_param_in_other_lib() {
+    addNamedSource(
+        '/a_lib.dart',
+        r'''
+library a_lib;
+import 'package:meta/meta.dart';
+class A {
+  void m({@Required('must specify an `a`') int a}) {}
+}
+''');
+
+    Source source = addSource(r'''
+import "a_lib.dart";
+f() {
+  new A().m();
+}
+''');
+
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS]);
+    verify([source]);
+  }
+
   void test_typeCheck_type_is_Null() {
     Source source = addSource(r'''
 m(i) {
@@ -1765,8 +1788,7 @@
     addNamedSource("/lib1.dart", "library lib1;");
     computeLibrarySourceErrors(source);
     assertErrors(
-        source,
-        [HintCode.UNUSED_IMPORT, HintCode.UNDEFINED_HIDDEN_NAME]);
+        source, [HintCode.UNUSED_IMPORT, HintCode.UNDEFINED_HIDDEN_NAME]);
     verify([source]);
   }
 
@@ -1777,8 +1799,7 @@
     addNamedSource("/lib1.dart", "library lib1;");
     computeLibrarySourceErrors(source);
     assertErrors(
-        source,
-        [HintCode.UNUSED_IMPORT, HintCode.UNDEFINED_SHOWN_NAME]);
+        source, [HintCode.UNUSED_IMPORT, HintCode.UNDEFINED_SHOWN_NAME]);
     verify([source]);
   }
 
diff --git a/pkg/analyzer/test/source/analysis_options_provider_test.dart b/pkg/analyzer/test/source/analysis_options_provider_test.dart
index ee9f0e0..07a7ff6 100644
--- a/pkg/analyzer/test/source/analysis_options_provider_test.dart
+++ b/pkg/analyzer/test/source/analysis_options_provider_test.dart
@@ -9,6 +9,7 @@
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/source/analysis_options_provider.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:unittest/unittest.dart';
 import 'package:yaml/yaml.dart';
 
@@ -18,7 +19,8 @@
 
 main() {
   initializeTestEnvironment();
-  runReflectiveTests(AnalysisOptionsProviderTest);
+  runReflectiveTests(AnalysisOptionsProviderOldTest);
+  runReflectiveTests(AnalysisOptionsProviderNewTest);
   group('AnalysisOptionsProvider', () {
     void expectMergesTo(String defaults, String overrides, String expected) {
       var optionsProvider = new AnalysisOptionsProvider();
@@ -100,12 +102,23 @@
 }
 
 @reflectiveTest
-class AnalysisOptionsProviderTest {
+class AnalysisOptionsProviderNewTest extends AnalysisOptionsProviderTest {
+  String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE;
+}
+
+@reflectiveTest
+class AnalysisOptionsProviderOldTest extends AnalysisOptionsProviderTest {
+  String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_FILE;
+}
+
+abstract class AnalysisOptionsProviderTest {
   TestPathTranslator pathTranslator;
   ResourceProvider resourceProvider;
 
   AnalysisOptionsProvider provider = new AnalysisOptionsProvider();
 
+  String get optionsFileName;
+
   void setUp() {
     var rawProvider = new MemoryResourceProvider(isWindows: isWindows);
     resourceProvider = new TestResourceProvider(rawProvider);
@@ -115,14 +128,14 @@
   void test_getOptions_crawlUp_hasInFolder() {
     pathTranslator.newFolder('/foo/bar');
     pathTranslator.newFile(
-        '/foo/.analysis_options',
+        '/foo/$optionsFileName',
         r'''
 analyzer:
   ignore:
     - foo
 ''');
     pathTranslator.newFile(
-        '/foo/bar/.analysis_options',
+        '/foo/bar/$optionsFileName',
         r'''
 analyzer:
   ignore:
@@ -140,14 +153,14 @@
   void test_getOptions_crawlUp_hasInParent() {
     pathTranslator.newFolder('/foo/bar/baz');
     pathTranslator.newFile(
-        '/foo/.analysis_options',
+        '/foo/$optionsFileName',
         r'''
 analyzer:
   ignore:
     - foo
 ''');
     pathTranslator.newFile(
-        '/foo/bar/.analysis_options',
+        '/foo/bar/$optionsFileName',
         r'''
 analyzer:
   ignore:
@@ -169,14 +182,14 @@
   }
 
   void test_getOptions_empty() {
-    pathTranslator.newFile('/.analysis_options', r'''#empty''');
+    pathTranslator.newFile('/$optionsFileName', r'''#empty''');
     Map<String, YamlNode> options = _getOptions('/');
     expect(options, isNotNull);
     expect(options, isEmpty);
   }
 
   void test_getOptions_invalid() {
-    pathTranslator.newFile('/.analysis_options', r''':''');
+    pathTranslator.newFile('/$optionsFileName', r''':''');
     expect(() {
       _getOptions('/');
     }, throws);
@@ -184,7 +197,7 @@
 
   void test_getOptions_simple() {
     pathTranslator.newFile(
-        '/.analysis_options',
+        '/$optionsFileName',
         r'''
 analyzer:
   ignore:
diff --git a/pkg/analyzer/test/src/dart/ast/utilities_test.dart b/pkg/analyzer/test/src/dart/ast/utilities_test.dart
index ce4b499..6653c20 100644
--- a/pkg/analyzer/test/src/dart/ast/utilities_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/utilities_test.dart
@@ -664,6 +664,11 @@
     fromNode.staticElement = staticElement;
     FunctionExpressionInvocation toNode =
         AstFactory.functionExpressionInvocation(AstFactory.identifier3("f"));
+    ClassElement elementT = ElementFactory.classElement2('T');
+    fromNode.typeArguments =
+        AstFactory.typeArgumentList(<TypeName>[AstFactory.typeName(elementT)]);
+    toNode.typeArguments =
+        AstFactory.typeArgumentList(<TypeName>[AstFactory.typeName4('T')]);
 
     _copyAndVerifyInvocation(fromNode, toNode);
 
@@ -791,6 +796,11 @@
   void test_visitMethodInvocation() {
     MethodInvocation fromNode = AstFactory.methodInvocation2("m");
     MethodInvocation toNode = AstFactory.methodInvocation2("m");
+    ClassElement elementT = ElementFactory.classElement2('T');
+    fromNode.typeArguments =
+        AstFactory.typeArgumentList(<TypeName>[AstFactory.typeName(elementT)]);
+    toNode.typeArguments =
+        AstFactory.typeArgumentList(<TypeName>[AstFactory.typeName4('T')]);
     _copyAndVerifyInvocation(fromNode, toNode);
   }
 
@@ -1086,6 +1096,15 @@
     expect(toNode.staticType, same(staticType));
     expect(toNode.propagatedInvokeType, same(propagatedInvokeType));
     expect(toNode.staticInvokeType, same(staticInvokeType));
+    List<TypeName> fromTypeArguments = toNode.typeArguments.arguments;
+    List<TypeName> toTypeArguments = fromNode.typeArguments.arguments;
+    if (fromTypeArguments != null) {
+      for (int i = 0; i < fromTypeArguments.length; i++) {
+        TypeName toArgument = fromTypeArguments[i];
+        TypeName fromArgument = toTypeArguments[i];
+        expect(toArgument.type, same(fromArgument.type));
+      }
+    }
   }
 }
 
diff --git a/pkg/analyzer/test/src/dart/element/element_test.dart b/pkg/analyzer/test/src/dart/element/element_test.dart
index 4b5ee12..ff2f9568 100644
--- a/pkg/analyzer/test/src/dart/element/element_test.dart
+++ b/pkg/analyzer/test/src/dart/element/element_test.dart
@@ -5,6 +5,7 @@
 library analyzer.test.src.dart.element.element_test;
 
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/constant/value.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/element.dart';
@@ -21,12 +22,14 @@
 
 import '../../../generated/analysis_context_factory.dart'
     show AnalysisContextHelper;
+import '../../../generated/resolver_test_case.dart';
 import '../../../generated/test_support.dart';
 import '../../../reflective_tests.dart';
 import '../../../utils.dart';
 
 main() {
   initializeTestEnvironment();
+  runReflectiveTests(ElementAnnotationImplTest);
   runReflectiveTests(FieldElementImplTest);
   runReflectiveTests(FunctionTypeImplTest);
   runReflectiveTests(InterfaceTypeImplTest);
@@ -41,6 +44,7 @@
   runReflectiveTests(MethodElementImplTest);
   runReflectiveTests(MultiplyDefinedElementImplTest);
   runReflectiveTests(ParameterElementImplTest);
+  runReflectiveTests(TopLevelVariableElementImplTest);
 }
 
 @reflectiveTest
@@ -1091,6 +1095,41 @@
 }
 
 @reflectiveTest
+class ElementAnnotationImplTest extends ResolverTestCase {
+  void test_computeConstantValue() {
+    addNamedSource(
+        '/a.dart',
+        r'''
+class A {
+  final String f;
+  const A(this.f);
+}
+void f(@A('x') int p) {}
+''');
+    Source source = addSource(r'''
+import 'a.dart';
+main() {
+  f(3);
+}
+''');
+    LibraryElement library = resolve2(source);
+    CompilationUnit unit = resolveCompilationUnit(source, library);
+    FunctionDeclaration main = unit.declarations[0];
+    BlockFunctionBody body = main.functionExpression.body;
+    ExpressionStatement statement = body.block.statements[0];
+    MethodInvocation invocation = statement.expression;
+    ParameterElement parameter =
+        invocation.argumentList.arguments[0].bestParameterElement;
+    ElementAnnotation annotation = parameter.metadata[0];
+    expect(annotation.constantValue, isNull);
+    DartObject value = annotation.computeConstantValue();
+    expect(value, isNotNull);
+    expect(value.getField('f').toStringValue(), 'x');
+    expect(annotation.constantValue, value);
+  }
+}
+
+@reflectiveTest
 class ElementImplTest extends EngineTestCase {
   void test_equals() {
     LibraryElementImpl library =
@@ -4158,6 +4197,37 @@
 }
 
 @reflectiveTest
+class TopLevelVariableElementImplTest extends ResolverTestCase {
+  void test_computeConstantValue() {
+    addNamedSource(
+        '/a.dart',
+        r'''
+const int C = 42;
+''');
+    Source source = addSource(r'''
+import 'a.dart';
+main() {
+  print(C);
+}
+''');
+    LibraryElement library = resolve2(source);
+    CompilationUnit unit = resolveCompilationUnit(source, library);
+    FunctionDeclaration main = unit.declarations[0];
+    BlockFunctionBody body = main.functionExpression.body;
+    ExpressionStatement statement = body.block.statements[0];
+    MethodInvocation invocation = statement.expression;
+    SimpleIdentifier argument = invocation.argumentList.arguments[0];
+    PropertyAccessorElementImpl getter = argument.bestElement;
+    TopLevelVariableElement constant = getter.variable;
+    expect(constant.constantValue, isNull);
+    DartObject value = constant.computeConstantValue();
+    expect(value, isNotNull);
+    expect(value.toIntValue(), 42);
+    expect(constant.constantValue, value);
+  }
+}
+
+@reflectiveTest
 class TypeParameterTypeImplTest extends EngineTestCase {
   void test_creation() {
     expect(
diff --git a/pkg/analyzer/test/src/summary/linker_test.dart b/pkg/analyzer/test/src/summary/linker_test.dart
index 3883876..c067a9e 100644
--- a/pkg/analyzer/test/src/summary/linker_test.dart
+++ b/pkg/analyzer/test/src/summary/linker_test.dart
@@ -3,7 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary/link.dart';
 import 'package:unittest/unittest.dart';
 
@@ -24,6 +26,8 @@
   @override
   bool get allowMissingFiles => false;
 
+  Matcher get isUndefined => new isInstanceOf<UndefinedElementForLink>();
+
   LibraryElementInBuildUnit get testLibrary => _testLibrary ??=
       linker.getLibrary(linkerInputs.testDartUri) as LibraryElementInBuildUnit;
 
@@ -150,6 +154,56 @@
     expect(classC.unnamedConstructor.isCycleFree, false);
   }
 
+  void test_getContainedName_nonStaticField() {
+    createLinker('class C { var f; }');
+    LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+    ClassElementForLink_Class c = library.getContainedName('C');
+    expect(c.getContainedName('f'), isNot(isUndefined));
+  }
+
+  void test_getContainedName_nonStaticGetter() {
+    createLinker('class C { get g => null; }');
+    LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+    ClassElementForLink_Class c = library.getContainedName('C');
+    expect(c.getContainedName('g'), isNot(isUndefined));
+  }
+
+  void test_getContainedName_nonStaticMethod() {
+    createLinker('class C { m() {} }');
+    LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+    ClassElementForLink_Class c = library.getContainedName('C');
+    expect(c.getContainedName('m'), isNot(isUndefined));
+  }
+
+  void test_getContainedName_nonStaticSetter() {
+    createLinker('class C { void set s(value) {} }');
+    LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+    ClassElementForLink_Class c = library.getContainedName('C');
+    expect(c.getContainedName('s='), isNot(isUndefined));
+  }
+
+  void test_inferredType_closure_fromBundle() {
+    var bundle = createPackageBundle(
+        '''
+var x = () {};
+''',
+        path: '/a.dart');
+    addBundle(bundle);
+    createLinker('''
+import 'a.dart';
+var y = x;
+''');
+    LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+    expect(
+        library
+            .getContainedName('y')
+            .asTypeInferenceNode
+            .variableElement
+            .inferredType
+            .toString(),
+        '() → dynamic');
+  }
+
   void test_inferredType_instanceField_dynamic() {
     createLinker('''
 var x;
@@ -552,6 +606,34 @@
     expect(libraryCycle.libraries, [testLibrary]);
   }
 
+  void test_malformed_function_reference() {
+    // Create a corrupted package bundle in which the inferred type of `x`
+    // refers to a non-existent local function.
+    var bundle = createPackageBundle('var x = () {}', path: '/a.dart');
+    expect(bundle.linkedLibraries, hasLength(1));
+    expect(bundle.linkedLibraries[0].units, hasLength(1));
+    for (LinkedReferenceBuilder ref
+        in bundle.linkedLibraries[0].units[0].references) {
+      if (ref.kind == ReferenceKind.function) {
+        ref.localIndex = 1234;
+      }
+    }
+    addBundle(bundle);
+    createLinker('''
+import 'a.dart';
+var y = x;
+''');
+    LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+    expect(
+        library
+            .getContainedName('y')
+            .asTypeInferenceNode
+            .variableElement
+            .inferredType
+            .toString(),
+        'dynamic');
+  }
+
   void test_multiplyInheritedExecutable_differentSignatures() {
     createLinker('''
 class B {
@@ -598,11 +680,41 @@
     expect(hTypeElement.typeParameterContext, same(f));
   }
 
+  void test_topLevelFunction_isStatic() {
+    createLinker('f() {}');
+    LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+    TopLevelFunctionElementForLink f = library.getContainedName('f');
+    expect(f.isStatic, true);
+  }
+
+  void test_topLevelGetter_isStatic() {
+    createLinker('get x => null;');
+    LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+    PropertyAccessorElementForLink_Executable x = library.getContainedName('x');
+    expect(x.isStatic, true);
+  }
+
+  void test_topLevelSetter_isStatic() {
+    createLinker('void set x(value) {}');
+    LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+    PropertyAccessorElementForLink_Executable x =
+        library.getContainedName('x=');
+    expect(x.isStatic, true);
+  }
+
+  void test_topLevelVariable_isStatic() {
+    createLinker('var x;');
+    LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+    PropertyAccessorElementForLink_Variable x = library.getContainedName('x');
+    expect(x.isStatic, true);
+    expect(x.variable.isStatic, true);
+  }
+
   void test_typeParameter_isTypeParameterInScope_direct() {
     createLinker('class C<T, U> {}');
     ClassElementForLink_Class c = testLibrary.getContainedName('C');
-    TypeParameterElementForLink t = c.typeParameters[0];
-    TypeParameterElementForLink u = c.typeParameters[1];
+    TypeParameterElementImpl t = c.typeParameters[0];
+    TypeParameterElementImpl u = c.typeParameters[1];
     expect(c.isTypeParameterInScope(t), true);
     expect(c.isTypeParameterInScope(u), true);
   }
@@ -611,8 +723,8 @@
     createLinker('class C<T, U> { f<V, W>() {} }');
     ClassElementForLink_Class c = testLibrary.getContainedName('C');
     MethodElementForLink f = c.methods[0];
-    TypeParameterElementForLink t = c.typeParameters[0];
-    TypeParameterElementForLink u = c.typeParameters[1];
+    TypeParameterElementImpl t = c.typeParameters[0];
+    TypeParameterElementImpl u = c.typeParameters[1];
     expect(f.isTypeParameterInScope(t), true);
     expect(f.isTypeParameterInScope(u), true);
   }
@@ -621,8 +733,8 @@
     createLinker('class C<T, U> { f<V, W>() {} }');
     ClassElementForLink_Class c = testLibrary.getContainedName('C');
     MethodElementForLink f = c.methods[0];
-    TypeParameterElementForLink v = f.typeParameters[0];
-    TypeParameterElementForLink w = f.typeParameters[1];
+    TypeParameterElementImpl v = f.typeParameters[0];
+    TypeParameterElementImpl w = f.typeParameters[1];
     expect(c.isTypeParameterInScope(v), false);
     expect(c.isTypeParameterInScope(w), false);
   }
@@ -631,13 +743,34 @@
     createLinker('class C<T, U> {} class D<V, W> {}');
     ClassElementForLink_Class c = testLibrary.getContainedName('C');
     ClassElementForLink_Class d = testLibrary.getContainedName('D');
-    TypeParameterElementForLink t = c.typeParameters[0];
-    TypeParameterElementForLink u = c.typeParameters[1];
-    TypeParameterElementForLink v = d.typeParameters[0];
-    TypeParameterElementForLink w = d.typeParameters[1];
+    TypeParameterElementImpl t = c.typeParameters[0];
+    TypeParameterElementImpl u = c.typeParameters[1];
+    TypeParameterElementImpl v = d.typeParameters[0];
+    TypeParameterElementImpl w = d.typeParameters[1];
     expect(c.isTypeParameterInScope(v), false);
     expect(c.isTypeParameterInScope(w), false);
     expect(d.isTypeParameterInScope(t), false);
     expect(d.isTypeParameterInScope(u), false);
   }
+
+  void test_variable_initializer_presence() {
+    // Any variable declaration with an initializer should have a non-null value
+    // for `initializer`, regardless of whether it is constant and regardless of
+    // whether it has an explicit type.
+    createLinker('''
+const int c = 0;
+int i = 0;
+int j;
+var v = 0;
+''');
+    LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+    PropertyAccessorElementForLink_Variable c = library.getContainedName('c');
+    expect(c.variable.initializer, isNotNull);
+    PropertyAccessorElementForLink_Variable i = library.getContainedName('i');
+    expect(i.variable.initializer, isNotNull);
+    PropertyAccessorElementForLink_Variable j = library.getContainedName('j');
+    expect(j.variable.initializer, isNull);
+    PropertyAccessorElementForLink_Variable v = library.getContainedName('v');
+    expect(v.variable.initializer, isNotNull);
+  }
 }
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
index 47faf81..cf9d727 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
@@ -564,12 +564,6 @@
   TestSummaryResynthesizer encodeDecodeLibrarySource(Source source) {
     return _encodeLibrary(source);
   }
-
-  @override
-  @failingTest
-  void test_inferred_function_type_in_generic_class_constructor() {
-    super.test_inferred_function_type_in_generic_class_constructor();
-  }
 }
 
 /**
diff --git a/pkg/analyzer/test/src/summary/resynthesize_test.dart b/pkg/analyzer/test/src/summary/resynthesize_test.dart
index 30221bb..e4f296e 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_test.dart
@@ -211,8 +211,8 @@
 
   void compareClassElements(
       ClassElement resynthesized, ClassElement original, String desc) {
-    ClassElementImpl r = getActualElement(resynthesized, desc);
-    ClassElementImpl o = getActualElement(original, desc);
+    ClassElementImpl r = ClassElementImpl.getImpl(resynthesized);
+    ClassElementImpl o = ClassElementImpl.getImpl(original);
     compareElements(r, o, desc);
     expect(r.fields.length, o.fields.length, reason: '$desc fields.length');
     for (int i = 0; i < r.fields.length; i++) {
@@ -675,11 +675,11 @@
         reason: desc);
     expect(resynthesized.docRange, original.docRange, reason: desc);
     compareMetadata(resynthesized.metadata, original.metadata, desc);
-    // Modifiers are a pain to test via handles.  So just test them via the
-    // actual element.
+
+    // Validate modifiers.
     for (Modifier modifier in Modifier.persistedValues) {
-      bool got = rImpl.hasModifier(modifier);
-      bool want = oImpl.hasModifier(modifier);
+      bool got = _hasModifier(resynthesized, modifier);
+      bool want = _hasModifier(original, modifier);
       expect(got, want,
           reason: 'Mismatch in $desc.$modifier: got $got, want $want');
     }
@@ -1221,6 +1221,97 @@
     SimpleIdentifier identifier = initializer;
     expect(identifier.staticElement, isNull, reason: desc);
   }
+
+  bool _hasModifier(Element element, Modifier modifier) {
+    if (modifier == Modifier.ABSTRACT) {
+      if (element is ClassElement) {
+        return element.isAbstract;
+      }
+      if (element is ExecutableElement) {
+        return element.isAbstract;
+      }
+      return false;
+    } else if (modifier == Modifier.ASYNCHRONOUS) {
+      if (element is ExecutableElement) {
+        return element.isAsynchronous;
+      }
+      return false;
+    } else if (modifier == Modifier.CONST) {
+      if (element is VariableElement) {
+        return element.isConst;
+      }
+      return false;
+    } else if (modifier == Modifier.DEFERRED) {
+      if (element is ImportElement) {
+        return element.isDeferred;
+      }
+      return false;
+    } else if (modifier == Modifier.ENUM) {
+      if (element is ClassElement) {
+        return element.isEnum;
+      }
+      return false;
+    } else if (modifier == Modifier.EXTERNAL) {
+      if (element is ExecutableElement) {
+        return element.isExternal;
+      }
+      return false;
+    } else if (modifier == Modifier.FACTORY) {
+      if (element is ConstructorElement) {
+        return element.isFactory;
+      }
+      return false;
+    } else if (modifier == Modifier.FINAL) {
+      if (element is VariableElement) {
+        return element.isFinal;
+      }
+      return false;
+    } else if (modifier == Modifier.GENERATOR) {
+      if (element is ExecutableElement) {
+        return element.isGenerator;
+      }
+      return false;
+    } else if (modifier == Modifier.GETTER) {
+      if (element is PropertyAccessorElement) {
+        return element.isGetter;
+      }
+      return false;
+    } else if (modifier == Modifier.HAS_EXT_URI) {
+      if (element is LibraryElement) {
+        return element.hasExtUri;
+      }
+      return false;
+    } else if (modifier == Modifier.IMPLICIT_TYPE) {
+      if (element is ExecutableElement) {
+        return element.hasImplicitReturnType;
+      }
+      return false;
+    } else if (modifier == Modifier.MIXIN_APPLICATION) {
+      if (element is ClassElement) {
+        return element.isMixinApplication;
+      }
+      return false;
+    } else if (modifier == Modifier.REFERENCES_SUPER) {
+      if (element is ClassElement) {
+        return element.hasReferenceToSuper;
+      }
+      return false;
+    } else if (modifier == Modifier.SETTER) {
+      if (element is PropertyAccessorElement) {
+        return element.isSetter;
+      }
+      return false;
+    } else if (modifier == Modifier.STATIC) {
+      if (element is ExecutableElement) {
+        return element.isStatic;
+      }
+      return false;
+    } else if (modifier == Modifier.SYNTHETIC) {
+      return element.isSynthetic;
+    }
+    throw new UnimplementedError(
+        'Modifier $modifier for ${element?.runtimeType}');
+  }
 }
 
 @reflectiveTest
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index 0abc4de..9c50c86 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -1823,6 +1823,27 @@
     ]);
   }
 
+  test_constExpr_functionExpression_inConstructorInitializers() {
+    // Even though function expressions are not allowed in constant
+    // declarations, they might occur due to erroneous code, so make sure they
+    // function correctly.
+    UnlinkedExecutable executable = serializeClassText('''
+class C {
+  final x, y;
+  const C() : x = (() => 42), y = (() => 43);
+}
+''').executables[0];
+    expect(executable.localFunctions, hasLength(2));
+    _assertUnlinkedConst(executable.constantInitializers[0].expression,
+        isValidConst: false,
+        operators: [UnlinkedConstOperation.pushLocalFunctionReference],
+        ints: [0, 0]);
+    _assertUnlinkedConst(executable.constantInitializers[1].expression,
+        isValidConst: false,
+        operators: [UnlinkedConstOperation.pushLocalFunctionReference],
+        ints: [0, 1]);
+  }
+
   test_constExpr_invokeConstructor_generic_named() {
     UnlinkedVariable variable = serializeVariableText('''
 class C<K, V> {
@@ -3471,6 +3492,33 @@
         operators: [UnlinkedConstOperation.pushInt], ints: [42]);
   }
 
+  test_constructor_initializers_superInvocation_namedExpression() {
+    UnlinkedExecutable executable =
+        findExecutable('', executables: serializeClassText(r'''
+class A {
+  const A(a, {int b, int c});
+}
+class C extends A {
+  const C() : super(1, b: 2, c: 3);
+}
+''').executables);
+    expect(executable.constantInitializers, hasLength(1));
+    UnlinkedConstructorInitializer initializer =
+        executable.constantInitializers[0];
+    expect(
+        initializer.kind, UnlinkedConstructorInitializerKind.superInvocation);
+    expect(initializer.name, '');
+    expect(initializer.expression, isNull);
+    expect(initializer.arguments, hasLength(3));
+    _assertUnlinkedConst(initializer.arguments[0],
+        operators: [UnlinkedConstOperation.pushInt], ints: [1]);
+    _assertUnlinkedConst(initializer.arguments[1],
+        operators: [UnlinkedConstOperation.pushInt], ints: [2]);
+    _assertUnlinkedConst(initializer.arguments[2],
+        operators: [UnlinkedConstOperation.pushInt], ints: [3]);
+    expect(initializer.argumentNames, ['b', 'c']);
+  }
+
   test_constructor_initializers_superInvocation_unnamed() {
     UnlinkedExecutable executable =
         findExecutable('ccc', executables: serializeClassText(r'''
@@ -3538,33 +3586,6 @@
     expect(initializer.argumentNames, ['b', 'c']);
   }
 
-  test_constructor_initializers_superInvocation_namedExpression() {
-    UnlinkedExecutable executable =
-        findExecutable('', executables: serializeClassText(r'''
-class A {
-  const A(a, {int b, int c});
-}
-class C extends A {
-  const C() : super(1, b: 2, c: 3);
-}
-''').executables);
-    expect(executable.constantInitializers, hasLength(1));
-    UnlinkedConstructorInitializer initializer =
-        executable.constantInitializers[0];
-    expect(
-        initializer.kind, UnlinkedConstructorInitializerKind.superInvocation);
-    expect(initializer.name, '');
-    expect(initializer.expression, isNull);
-    expect(initializer.arguments, hasLength(3));
-    _assertUnlinkedConst(initializer.arguments[0],
-        operators: [UnlinkedConstOperation.pushInt], ints: [1]);
-    _assertUnlinkedConst(initializer.arguments[1],
-        operators: [UnlinkedConstOperation.pushInt], ints: [2]);
-    _assertUnlinkedConst(initializer.arguments[2],
-        operators: [UnlinkedConstOperation.pushInt], ints: [3]);
-    expect(initializer.argumentNames, ['b', 'c']);
-  }
-
   test_constructor_initializers_thisInvocation_unnamed() {
     UnlinkedExecutable executable =
         findExecutable('named', executables: serializeClassText(r'''
diff --git a/pkg/analyzer/test/src/task/options_test.dart b/pkg/analyzer/test/src/task/options_test.dart
index 880479d..f65c3fb 100644
--- a/pkg/analyzer/test/src/task/options_test.dart
+++ b/pkg/analyzer/test/src/task/options_test.dart
@@ -23,7 +23,8 @@
 main() {
   initializeTestEnvironment();
   runReflectiveTests(ContextConfigurationTest);
-  runReflectiveTests(GenerateOptionsErrorsTaskTest);
+  runReflectiveTests(GenerateNewOptionsErrorsTaskTest);
+  runReflectiveTests(GenerateOldOptionsErrorsTaskTest);
   runReflectiveTests(OptionsFileValidatorTest);
 }
 
@@ -104,8 +105,7 @@
 ''');
 
     List<ErrorProcessor> processors =
-        context.getConfigurationData(CONFIGURED_ERROR_PROCESSORS)
-        as List<ErrorProcessor>;
+        context.getConfigurationData(CONFIGURED_ERROR_PROCESSORS);
     expect(processors, hasLength(2));
 
     var unused_local = new AnalysisError(
@@ -146,10 +146,19 @@
 }
 
 @reflectiveTest
-class GenerateOptionsErrorsTaskTest extends AbstractContextTest {
-  final optionsFilePath = '/${AnalysisEngine.ANALYSIS_OPTIONS_FILE}';
+class GenerateNewOptionsErrorsTaskTest extends GenerateOptionsErrorsTaskTest {
+  String get optionsFilePath => '/${AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE}';
+}
 
+@reflectiveTest
+class GenerateOldOptionsErrorsTaskTest extends GenerateOptionsErrorsTaskTest {
+  String get optionsFilePath => '/${AnalysisEngine.ANALYSIS_OPTIONS_FILE}';
+}
+
+abstract class GenerateOptionsErrorsTaskTest extends AbstractContextTest {
   Source source;
+
+  String get optionsFilePath;
   LineInfo lineInfo(String source) =>
       GenerateOptionsErrorsTask.computeLineInfo(source);
 
diff --git a/pkg/analyzer/test/src/task/options_work_manager_test.dart b/pkg/analyzer/test/src/task/options_work_manager_test.dart
index cf6cac0..64baa5c 100644
--- a/pkg/analyzer/test/src/task/options_work_manager_test.dart
+++ b/pkg/analyzer/test/src/task/options_work_manager_test.dart
@@ -31,27 +31,37 @@
 
 main() {
   initializeTestEnvironment();
-  runReflectiveTests(OptionsWorkManagerTest);
+  runReflectiveTests(OptionsWorkManagerNewFileTest);
+  runReflectiveTests(OptionsWorkManagerOldFileTest);
 }
 
 @reflectiveTest
-class OptionsWorkManagerTest {
-  static final optionsFile = AnalysisEngine.ANALYSIS_OPTIONS_FILE;
+class OptionsWorkManagerNewFileTest extends OptionsWorkManagerTest {
+  String get optionsFile => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE;
+}
+
+@reflectiveTest
+class OptionsWorkManagerOldFileTest extends OptionsWorkManagerTest {
+  String get optionsFile => AnalysisEngine.ANALYSIS_OPTIONS_FILE;
+}
+
+abstract class OptionsWorkManagerTest {
   InternalAnalysisContext context = new _InternalAnalysisContextMock();
   AnalysisCache cache;
-
   OptionsWorkManager manager;
 
   CaughtException caughtException = new CaughtException(null, null);
 
-  Source source1 = new TestSource('test1/$optionsFile');
-  Source source2 = new TestSource('test2/$optionsFile');
-  Source source3 = new TestSource('test3/$optionsFile');
-  Source source4 = new TestSource('test4/$optionsFile');
+  Source source1;
+
+  Source source2;
+  Source source3;
+  Source source4;
   CacheEntry entry1;
   CacheEntry entry2;
   CacheEntry entry3;
   CacheEntry entry4;
+  String get optionsFile;
 
   void expect_sourceQueue(List<Source> sources) {
     expect(manager.sourceQueue, unorderedEquals(sources));
@@ -60,6 +70,10 @@
   void setUp() {
     cache = context.analysisCache;
     manager = new OptionsWorkManager(context);
+    source1 = new TestSource('test1/$optionsFile');
+    source2 = new TestSource('test2/$optionsFile');
+    source3 = new TestSource('test3/$optionsFile');
+    source4 = new TestSource('test4/$optionsFile');
     entry1 = context.getCacheEntry(source1);
     entry2 = context.getCacheEntry(source2);
     entry3 = context.getCacheEntry(source3);
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index 83d6485..a4bc6b7 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -1571,6 +1571,19 @@
 ''');
   }
 
+  void test_genericMethods_usesGreatestLowerBound() {
+    var mainUnit = checkFile(r'''
+typedef Iterable<num> F(int x);
+typedef List<int> G(double x);
+
+/*=T*/ generic/*<T>*/(a(/*=T*/ _), b(/*=T*/ _)) => null;
+
+var v = generic((F f) => null, (G g) => null);
+''');
+    var v = mainUnit.topLevelVariables[0];
+    expect(v.type.toString(), '(num) → List<int>');
+  }
+
   void test_infer_assignToIndex() {
     checkFile(r'''
 List<double> a = <double>[];
@@ -2305,6 +2318,14 @@
     expect(f.type.toString(), '() → dynamic');
   }
 
+  void test_inferredType_fromTopLevelExecutableTearoff() {
+    var mainUnit = checkFile('''
+var v = print;
+''');
+    var v = mainUnit.topLevelVariables[0];
+    expect(v.type.toString(), '(Object) → void');
+  }
+
   void test_inferredType_isEnum() {
     var mainUnit = checkFile('''
 enum E { v1 }
diff --git a/pkg/analyzer/tool/summary/build_sdk_summaries.dart b/pkg/analyzer/tool/summary/build_sdk_summaries.dart
index 8a9adb8..9d1c34b 100644
--- a/pkg/analyzer/tool/summary/build_sdk_summaries.dart
+++ b/pkg/analyzer/tool/summary/build_sdk_summaries.dart
@@ -19,7 +19,10 @@
     return;
   }
   String command = args[0];
-  if (command == 'multiple-outputs' && args.length >= 2 && args.length <= 3) {
+  if ((command == 'multiple-outputs' || command == 'strong-outputs') &&
+      args.length >= 2 &&
+      args.length <= 3) {
+    bool includeSpec = command != 'strong-outputs';
     //
     // Prepare the output path.
     //
@@ -34,7 +37,7 @@
     // Prepare results.
     //
     String sdkPath = args.length > 2 ? args[2] : null;
-    _Output output = _buildMultipleOutputs(sdkPath);
+    _Output output = _buildMultipleOutputs(sdkPath, includeSpec);
     if (output == null) {
       exitCode = 1;
       return;
@@ -42,7 +45,9 @@
     //
     // Write results.
     //
-    output.spec.writeMultiple(outputDirectoryPath, 'spec');
+    if (includeSpec) {
+      output.spec.writeMultiple(outputDirectoryPath, 'spec');
+    }
     output.strong.writeMultiple(outputDirectoryPath, 'strong');
   } else if (command == 'single-output' &&
       args.length >= 2 &&
@@ -52,7 +57,7 @@
     //
     // Prepare results.
     //
-    _Output output = _buildMultipleOutputs(sdkPath);
+    _Output output = _buildMultipleOutputs(sdkPath, true);
     if (output == null) {
       exitCode = 1;
       return;
@@ -106,7 +111,7 @@
 const int _FIELD_STRONG_INDEX = 3;
 const int _FIELD_STRONG_SUM = 2;
 
-_Output _buildMultipleOutputs(String sdkPath) {
+_Output _buildMultipleOutputs(String sdkPath, bool includeSpec) {
   //
   // Validate the SDK path.
   //
@@ -122,7 +127,8 @@
   //
   // Build spec and strong outputs.
   //
-  _BuilderOutput spec = new _Builder(sdkPath, false).build();
+  _BuilderOutput spec =
+      includeSpec ? new _Builder(sdkPath, false).build() : null;
   _BuilderOutput strong = new _Builder(sdkPath, true).build();
   return new _Output(spec, strong);
 }
@@ -148,6 +154,8 @@
   print('Where command can be one of the following:');
   print('  multiple-outputs output_directory_path [sdk_path]');
   print('    Generate separate summary and index files.');
+  print('  strong-outputs output_directory_path [sdk_path]');
+  print('    Generate separate summary and index files (strong mode only).');
   print('  single-output output_file_path [sdk_path]');
   print('    Generate a single file with summary and index.');
   print('  extract-spec-sum input_file output_file');
diff --git a/pkg/analyzer/tool/summary/dump_inferred_types.dart b/pkg/analyzer/tool/summary/dump_inferred_types.dart
index a964675..135783e 100644
--- a/pkg/analyzer/tool/summary/dump_inferred_types.dart
+++ b/pkg/analyzer/tool/summary/dump_inferred_types.dart
@@ -8,20 +8,16 @@
 import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:analyzer/src/summary/base.dart';
 import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/package_bundle_reader.dart';
 
 /**
  * Collect the inferred types from all the summary files listed in [args] and
  * print them in alphabetical order.
  */
 main(List<String> args) {
+  SummaryDataStore summaryDataStore = new SummaryDataStore(args);
   InferredTypeCollector collector = new InferredTypeCollector();
-  for (String arg in args) {
-    PackageBundle bundle =
-        new PackageBundle.fromBuffer(new File(arg).readAsBytesSync());
-    collector.visitPackageBundle(bundle, arg);
-  }
-  collector.dumpLibraryIndex();
-  collector.dumpPartIndex();
+  collector.visitSummaryDataStore(summaryDataStore);
   collector.dumpCollectedTypes();
 }
 
@@ -34,8 +30,6 @@
   LinkedUnit linkedUnit;
   final Map<String, String> inferredTypes = <String, String>{};
   List<String> typeParamsInScope = <String>[];
-  final Map<String, Set<String>> libraryIndex = <String, Set<String>>{};
-  final Map<String, Set<String>> partIndex = <String, Set<String>>{};
 
   /**
    * If an inferred type exists matching the given [slot], record that it is the
@@ -94,38 +88,6 @@
   }
 
   /**
-   * Print out an index mapping library names to the summary files containing
-   * them.
-   */
-  void dumpLibraryIndex() {
-    print('Library index:');
-    List<String> libraryNames = libraryIndex.keys.toList();
-    libraryNames.sort();
-    for (String libraryName in libraryNames) {
-      List<String> summaryFiles = libraryIndex[libraryName].toList();
-      summaryFiles.sort();
-      print('$libraryName -> ${summaryFiles.join(', ')}');
-    }
-    print('');
-  }
-
-  /**
-   * Print out an index mapping part file names to the summary files containing
-   * them.
-   */
-  void dumpPartIndex() {
-    print('Part index:');
-    List<String> partNames = partIndex.keys.toList();
-    partNames.sort();
-    for (String partName in partNames) {
-      List<String> summaryFiles = partIndex[partName].toList();
-      summaryFiles.sort();
-      print('$partName -> ${summaryFiles.join(', ')}');
-    }
-    print('');
-  }
-
-  /**
    * Interpret the given [param] as a parameter in a synthetic typedef, and
    * format it as a string.
    */
@@ -278,25 +240,14 @@
   }
 
   /**
-   * Collect all the inferred types contained in [bundle].
+   * Collect all the inferred types contained in [summaryDataStore].
    */
-  void visitPackageBundle(PackageBundle bundle, String summaryPath) {
-    Map<String, LinkedLibrary> linkedLibraries = <String, LinkedLibrary>{};
-    Map<String, UnlinkedUnit> unlinkedUnits = <String, UnlinkedUnit>{};
-    for (int i = 0; i < bundle.linkedLibraryUris.length; i++) {
-      linkedLibraries[bundle.linkedLibraryUris[i]] = bundle.linkedLibraries[i];
-    }
-    for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
-      String unitUriString = bundle.unlinkedUnitUris[i];
-      partIndex
-          .putIfAbsent(unitUriString, () => new Set<String>())
-          .add(summaryPath);
-      unlinkedUnits[unitUriString] = bundle.unlinkedUnits[i];
-    }
+  void visitSummaryDataStore(SummaryDataStore summaryDataStore) {
     // Figure out which unlinked units are a part of another library so we won't
     // visit them redundantly.
     Set<String> partOfUris = new Set<String>();
-    unlinkedUnits.forEach((String unitUriString, UnlinkedUnit unlinkedUnit) {
+    summaryDataStore.unlinkedMap
+        .forEach((String unitUriString, UnlinkedUnit unlinkedUnit) {
       Uri unitUri = Uri.parse(unitUriString);
       for (String relativePartUriString in unlinkedUnit.publicNamespace.parts) {
         partOfUris.add(
@@ -304,16 +255,14 @@
                 .toString());
       }
     });
-    linkedLibraries
+    summaryDataStore.linkedMap
         .forEach((String libraryUriString, LinkedLibrary linkedLibrary) {
       if (partOfUris.contains(libraryUriString)) {
         return;
       }
-      libraryIndex
-          .putIfAbsent(libraryUriString, () => new Set<String>())
-          .add(summaryPath);
       Uri libraryUri = Uri.parse(libraryUriString);
-      UnlinkedUnit definingUnlinkedUnit = unlinkedUnits[libraryUriString];
+      UnlinkedUnit definingUnlinkedUnit =
+          summaryDataStore.unlinkedMap[libraryUriString];
       if (definingUnlinkedUnit != null) {
         visitUnit(
             definingUnlinkedUnit, linkedLibrary.units[0], libraryUriString);
@@ -324,7 +273,8 @@
               Uri.parse(definingUnlinkedUnit.publicNamespace.parts[i]);
           String unitUriString =
               resolveRelativeUri(libraryUri, relativePartUri).toString();
-          UnlinkedUnit unlinkedUnit = unlinkedUnits[unitUriString];
+          UnlinkedUnit unlinkedUnit =
+              summaryDataStore.unlinkedMap[unitUriString];
           if (unlinkedUnit != null) {
             visitUnit(
                 unlinkedUnit, linkedLibrary.units[i + 1], libraryUriString);
diff --git a/pkg/analyzer/tool/task_dependency_graph/tasks.dot b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
index 212dc2b..402efa5 100644
--- a/pkg/analyzer/tool/task_dependency_graph/tasks.dot
+++ b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
@@ -39,6 +39,7 @@
   CONSTANT_EXPRESSION_RESOLVED [shape=box]
   CONSTANT_VALUE -> ComputeConstantValueTask
   CONSTANT_VALUE -> EvaluateUnitConstantsTask
+  CONSTANT_VALUE -> VerifyUnitTask
   CONSTANT_VALUE [shape=box]
   CONTAINING_LIBRARIES -> DartErrorsTask
   CONTAINING_LIBRARIES [shape=box]
@@ -73,6 +74,8 @@
   ComputeLibraryCycleTask -> LIBRARY_CYCLE_DEPENDENCIES
   ComputeLibraryCycleTask -> LIBRARY_CYCLE_UNITS
   ComputePropagableVariableDependenciesTask -> PROPAGABLE_VARIABLE_DEPENDENCIES
+  ComputeRequiredConstantsTask -> PENDING_ERRORS
+  ComputeRequiredConstantsTask -> REQUIRED_CONSTANTS
   ContainingLibrariesTask -> CONTAINING_LIBRARIES
   DART_ERRORS -> LibraryErrorsReadyTask
   DART_ERRORS [shape=box]
@@ -190,6 +193,8 @@
   PARSED_UNIT [shape=box]
   PARSE_ERRORS -> dartErrorsForSource
   PARSE_ERRORS [shape=box]
+  PENDING_ERRORS -> VerifyUnitTask
+  PENDING_ERRORS [shape=box]
   PROPAGABLE_VARIABLES_IN_UNIT -> PropagateVariableTypesInUnitTask
   PROPAGABLE_VARIABLES_IN_UNIT [shape=box]
   PROPAGABLE_VARIABLE_DEPENDENCIES -> PropagateVariableTypeTask
@@ -232,6 +237,9 @@
   REFERENCED_SOURCES -> BuildDirectiveElementsTask
   REFERENCED_SOURCES -> VerifyUnitTask
   REFERENCED_SOURCES [shape=box]
+  REQUIRED_CONSTANTS -> VerifyUnitTask
+  REQUIRED_CONSTANTS [shape=box]
+  RESOLVED_UNIT -> ComputeRequiredConstantsTask
   RESOLVED_UNIT -> GenerateHintsTask
   RESOLVED_UNIT -> GenerateLintsTask
   RESOLVED_UNIT -> ReadyResolvedUnitTask
diff --git a/pkg/analyzer_cli/lib/src/boot_loader.dart b/pkg/analyzer_cli/lib/src/boot_loader.dart
index 6df71ae..5b03f40 100644
--- a/pkg/analyzer_cli/lib/src/boot_loader.dart
+++ b/pkg/analyzer_cli/lib/src/boot_loader.dart
@@ -7,6 +7,7 @@
 import 'dart:async';
 import 'dart:isolate';
 
+import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/source/analysis_options_provider.dart';
 import 'package:analyzer/src/context/context.dart';
@@ -108,7 +109,7 @@
     errorSink.writeln('Plugin configuration skipped: $details');
   };
 
-  /// Reads plugin config info from `.analysis_options`.
+  /// Reads plugin config info from the analysis options file.
   PluginConfigOptionsProcessor _pluginOptionsProcessor =
       new PluginConfigOptionsProcessor(_pluginConfigErrorHandler);
 
@@ -126,12 +127,26 @@
         args: args, packageRootPath: options.packageRootPath);
   }
 
-  void _processAnalysisOptions(CommandLineOptions options) {
+  File _getOptionsFile(
+      CommandLineOptions options, ResourceProvider resourceProvider) {
+    String analysisOptionsFile = options.analysisOptionsFile;
+    if (analysisOptionsFile != null) {
+      return resourceProvider.getFile(analysisOptionsFile);
+    }
+    File file =
+        resourceProvider.getFile(engine.AnalysisEngine.ANALYSIS_OPTIONS_FILE);
+    if (!file.exists) {
+      file = resourceProvider
+          .getFile(engine.AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
+    }
+    return file;
+  }
+
+  void _processAnalysisOptions(CommandLineOptions commandLineOptions) {
     // Determine options file path.
-    var filePath = options.analysisOptionsFile ??
-        engine.AnalysisEngine.ANALYSIS_OPTIONS_FILE;
     try {
-      var file = PhysicalResourceProvider.INSTANCE.getFile(filePath);
+      File file = _getOptionsFile(
+          commandLineOptions, PhysicalResourceProvider.INSTANCE);
       AnalysisOptionsProvider analysisOptionsProvider =
           new AnalysisOptionsProvider();
       Map<String, YamlNode> options =
diff --git a/pkg/analyzer_cli/lib/src/build_mode.dart b/pkg/analyzer_cli/lib/src/build_mode.dart
index d49a519..f6b3ddd 100644
--- a/pkg/analyzer_cli/lib/src/build_mode.dart
+++ b/pkg/analyzer_cli/lib/src/build_mode.dart
@@ -14,6 +14,7 @@
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/java_io.dart';
+import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/sdk_io.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/source_io.dart';
@@ -23,6 +24,7 @@
 import 'package:analyzer/src/summary/package_bundle_reader.dart';
 import 'package:analyzer/src/summary/summarize_ast.dart';
 import 'package:analyzer/src/summary/summarize_elements.dart';
+import 'package:analyzer/src/summary/summary_sdk.dart' show SummaryBasedDartSdk;
 import 'package:analyzer/task/dart.dart';
 import 'package:analyzer_cli/src/analyzer_impl.dart';
 import 'package:analyzer_cli/src/driver.dart';
@@ -60,6 +62,7 @@
   /**
    * Perform a single loop step.
    */
+  @override
   WorkResponse performRequest(WorkRequest request) {
     errorBuffer.clear();
     outBuffer.clear();
@@ -237,18 +240,29 @@
   }
 
   void _createContext() {
-    DirectoryBasedDartSdk sdk =
-        new DirectoryBasedDartSdk(new JavaFile(options.dartSdkPath));
-    sdk.analysisOptions =
-        Driver.createAnalysisOptionsForCommandLineOptions(options);
-    sdk.useSummary = !options.buildSummaryOnlyAst;
-
     // Read the summaries.
     summaryDataStore = new SummaryDataStore(options.buildSummaryInputs);
 
+    DartSdk sdk;
+    PackageBundle sdkBundle;
+    if (options.dartSdkSummaryPath != null) {
+      SummaryBasedDartSdk summarySdk = new SummaryBasedDartSdk(
+          options.dartSdkSummaryPath, options.strongMode);
+      sdk = summarySdk;
+      sdkBundle = summarySdk.bundle;
+    } else {
+      DirectoryBasedDartSdk directorySdk =
+          new DirectoryBasedDartSdk(new JavaFile(options.dartSdkPath));
+      directorySdk.analysisOptions =
+          Driver.createAnalysisOptionsForCommandLineOptions(options);
+      directorySdk.useSummary = !options.buildSummaryOnlyAst;
+      sdk = directorySdk;
+      sdkBundle = directorySdk.getSummarySdkBundle();
+    }
+
     // In AST mode include SDK bundle to avoid parsing SDK sources.
     if (options.buildSummaryOnlyAst) {
-      summaryDataStore.addBundle(null, sdk.getSummarySdkBundle());
+      summaryDataStore.addBundle(null, sdkBundle);
     }
 
     // Create the context.
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index aaff20d..4d80c61 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -8,7 +8,7 @@
 import 'dart:convert';
 import 'dart:io';
 
-import 'package:analyzer/file_system/file_system.dart' as fileSystem;
+import 'package:analyzer/file_system/file_system.dart' as file_system;
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/plugin/embedded_resolver_provider.dart';
 import 'package:analyzer/plugin/options.dart';
@@ -25,12 +25,14 @@
 import 'package:analyzer/src/generated/interner.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/java_io.dart';
+import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/sdk_io.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/source_io.dart';
 import 'package:analyzer/src/generated/utilities_general.dart'
     show PerformanceTag;
 import 'package:analyzer/src/services/lint.dart';
+import 'package:analyzer/src/summary/summary_sdk.dart' show SummaryBasedDartSdk;
 import 'package:analyzer/src/task/options.dart';
 import 'package:analyzer_cli/src/analyzer_impl.dart';
 import 'package:analyzer_cli/src/build_mode.dart';
@@ -39,7 +41,7 @@
 import 'package:analyzer_cli/src/perf_report.dart';
 import 'package:analyzer_cli/starter.dart';
 import 'package:linter/src/plugin/linter_plugin.dart';
-import 'package:package_config/discovery.dart' as pkgDiscovery;
+import 'package:package_config/discovery.dart' as pkg_discovery;
 import 'package:package_config/packages.dart' show Packages;
 import 'package:package_config/packages_file.dart' as pkgfile show parse;
 import 'package:package_config/src/packages_impl.dart' show MapPackages;
@@ -91,7 +93,7 @@
   ResolverProvider packageResolverProvider;
 
   /// SDK instance.
-  DirectoryBasedDartSdk sdk;
+  DartSdk sdk;
 
   /// Collected analysis statistics.
   final AnalysisStats stats = new AnalysisStats();
@@ -328,15 +330,11 @@
   /// Decide on the appropriate method for resolving URIs based on the given
   /// [options] and [customUrlMappings] settings, and return a
   /// [SourceFactory] that has been configured accordingly.
-  SourceFactory _chooseUriResolutionPolicy(
-      CommandLineOptions options, EmbedderYamlLocator yamlLocator) {
-    Packages packages;
-    Map<String, List<fileSystem.Folder>> packageMap;
-    UriResolver packageUriResolver;
-
+  SourceFactory _chooseUriResolutionPolicy(CommandLineOptions options,
+      Map<file_system.Folder, YamlMap> embedderMap, _PackageInfo packageInfo) {
     // Create a custom package resolver if one has been specified.
     if (packageResolverProvider != null) {
-      fileSystem.Folder folder =
+      file_system.Folder folder =
           PhysicalResourceProvider.INSTANCE.getResource('.');
       UriResolver resolver = packageResolverProvider(folder);
       if (resolver != null) {
@@ -354,7 +352,7 @@
         // Default to a Dart URI resolver if no embedder is found.
         sdkResolver ??= new DartUriResolver(sdk);
 
-        // TODO(brianwilkerson) This doesn't sdk extensions.
+        // TODO(brianwilkerson) This doesn't handle sdk extensions.
         List<UriResolver> resolvers = <UriResolver>[
           sdkResolver,
           resolver,
@@ -363,43 +361,24 @@
         return new SourceFactory(resolvers);
       }
     }
-    // Process options, caching package resolution details.
-    if (options.packageConfigPath != null) {
-      String packageConfigPath = options.packageConfigPath;
-      Uri fileUri = new Uri.file(packageConfigPath);
-      try {
-        File configFile = new File.fromUri(fileUri).absolute;
-        List<int> bytes = configFile.readAsBytesSync();
-        Map<String, Uri> map = pkgfile.parse(bytes, configFile.uri);
-        packages = new MapPackages(map);
-        packageMap = _getPackageMap(packages);
-      } catch (e) {
-        printAndFail(
-            'Unable to read package config data from $packageConfigPath: $e');
-      }
-    } else if (options.packageRootPath != null) {
-      packageMap = _PackageRootPackageMapBuilder
-          .buildPackageMap(options.packageRootPath);
 
+    UriResolver packageUriResolver;
+
+    if (options.packageRootPath != null) {
       JavaFile packageDirectory = new JavaFile(options.packageRootPath);
       packageUriResolver = new PackageUriResolver([packageDirectory]);
-    } else {
-      fileSystem.Resource cwd =
-          PhysicalResourceProvider.INSTANCE.getResource('.');
-
-      // Look for .packages.
-      packages = _discoverPackagespec(new Uri.directory(cwd.path));
-
-      if (packages != null) {
-        packageMap = _getPackageMap(packages);
-      } else {
+    } else if (options.packageConfigPath == null) {
+      // TODO(pq): remove?
+      if (packageInfo.packageMap == null) {
         // Fall back to pub list-package-dirs.
-
         PubPackageMapProvider pubPackageMapProvider =
             new PubPackageMapProvider(PhysicalResourceProvider.INSTANCE, sdk);
+        file_system.Resource cwd =
+            PhysicalResourceProvider.INSTANCE.getResource('.');
         PackageMapInfo packageMapInfo =
             pubPackageMapProvider.computePackageMap(cwd);
-        packageMap = packageMapInfo.packageMap;
+        Map<String, List<file_system.Folder>> packageMap =
+            packageMapInfo.packageMap;
 
         // Only create a packageUriResolver if pub list-package-dirs succeeded.
         // If it failed, that's not a problem; it simply means we have no way
@@ -417,10 +396,8 @@
     // 'dart:' URIs come first.
 
     // Setup embedding.
-    yamlLocator.refresh(packageMap);
-
     EmbedderUriResolver embedderUriResolver =
-        new EmbedderUriResolver(yamlLocator.embedderYamls);
+        new EmbedderUriResolver(embedderMap);
     if (embedderUriResolver.length == 0) {
       // The embedder uri resolver has no mappings. Use the default Dart SDK
       // uri resolver.
@@ -432,8 +409,8 @@
     }
 
     // Next SdkExts.
-    if (packageMap != null) {
-      resolvers.add(new SdkExtUriResolver(packageMap));
+    if (packageInfo.packageMap != null) {
+      resolvers.add(new SdkExtUriResolver(packageInfo.packageMap));
     }
 
     // Then package URIs.
@@ -444,7 +421,7 @@
     // Finally files.
     resolvers.add(new FileUriResolver());
 
-    return new SourceFactory(resolvers, packages);
+    return new SourceFactory(resolvers, packageInfo.packages);
   }
 
   /// Collect all analyzable files at [filePath], recursively if it's a
@@ -511,13 +488,26 @@
       contextOptions.analyzeFunctionBodiesPredicate = dietParsingPolicy;
     });
 
-    // Once options are processed, setup the SDK.
-    _setupSdk(options);
+    // Find package info.
+    _PackageInfo packageInfo = _findPackages(options);
+
+    // Process embedders.
+    Map<file_system.Folder, YamlMap> embedderMap =
+        _findEmbedders(packageInfo.packageMap);
+
+    // Scan for SDK extenders.
+    bool hasSdkExt = _hasSdkExt(packageInfo.packageMap?.values);
+
+    // No summaries in the presence of embedders or extenders.
+    bool useSummaries = embedderMap.isEmpty && !hasSdkExt;
+
+    // Once options and embedders are processed, setup the SDK.
+    _setupSdk(options, useSummaries);
 
     // Choose a package resolution policy and a diet parsing policy based on
     // the command-line options.
-    SourceFactory sourceFactory = _chooseUriResolutionPolicy(
-        options, (_context as InternalAnalysisContext).embedderYamlLocator);
+    SourceFactory sourceFactory =
+        _chooseUriResolutionPolicy(options, embedderMap, packageInfo);
 
     _context.sourceFactory = sourceFactory;
   }
@@ -525,7 +515,7 @@
   /// Return discovered packagespec, or `null` if none is found.
   Packages _discoverPackagespec(Uri root) {
     try {
-      Packages packages = pkgDiscovery.findPackagesFromFile(root);
+      Packages packages = pkg_discovery.findPackagesFromFile(root);
       if (packages != Packages.noPackages) {
         return packages;
       }
@@ -536,13 +526,57 @@
     return null;
   }
 
-  Map<String, List<fileSystem.Folder>> _getPackageMap(Packages packages) {
+  Map<file_system.Folder, YamlMap> _findEmbedders(
+      Map<String, List<file_system.Folder>> packageMap) {
+    EmbedderYamlLocator locator =
+        (_context as InternalAnalysisContext).embedderYamlLocator;
+    locator.refresh(packageMap);
+    return locator.embedderYamls;
+  }
+
+  _PackageInfo _findPackages(CommandLineOptions options) {
+    if (packageResolverProvider != null) {
+      // The resolver provider will do all the work later.
+      return null;
+    }
+
+    Packages packages;
+    Map<String, List<file_system.Folder>> packageMap;
+
+    if (options.packageConfigPath != null) {
+      String packageConfigPath = options.packageConfigPath;
+      Uri fileUri = new Uri.file(packageConfigPath);
+      try {
+        File configFile = new File.fromUri(fileUri).absolute;
+        List<int> bytes = configFile.readAsBytesSync();
+        Map<String, Uri> map = pkgfile.parse(bytes, configFile.uri);
+        packages = new MapPackages(map);
+        packageMap = _getPackageMap(packages);
+      } catch (e) {
+        printAndFail(
+            'Unable to read package config data from $packageConfigPath: $e');
+      }
+    } else if (options.packageRootPath != null) {
+      packageMap = _PackageRootPackageMapBuilder
+          .buildPackageMap(options.packageRootPath);
+    } else {
+      file_system.Resource cwd =
+          PhysicalResourceProvider.INSTANCE.getResource('.');
+      // Look for .packages.
+      packages = _discoverPackagespec(new Uri.directory(cwd.path));
+      packageMap = _getPackageMap(packages);
+    }
+
+    return new _PackageInfo(packages, packageMap);
+  }
+
+  Map<String, List<file_system.Folder>> _getPackageMap(Packages packages) {
     if (packages == null) {
       return null;
     }
 
-    Map<String, List<fileSystem.Folder>> folderMap =
-        new Map<String, List<fileSystem.Folder>>();
+    Map<String, List<file_system.Folder>> folderMap =
+        new Map<String, List<file_system.Folder>>();
     packages.asMap().forEach((String packagePath, Uri uri) {
       folderMap[packagePath] = [
         PhysicalResourceProvider.INSTANCE.getFolder(path.fromUri(uri))
@@ -551,6 +585,19 @@
     return folderMap;
   }
 
+  bool _hasSdkExt(Iterable<List<file_system.Folder>> folders) {
+    if (folders != null) {
+      //TODO: ideally share this traversal with SdkExtUriResolver
+      for (Iterable<file_system.Folder> libDirs in folders) {
+        if (libDirs.any((file_system.Folder libDir) =>
+            libDir.getChild(SdkExtUriResolver.SDK_EXT_NAME).exists)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
   /// Returns `true` if this relative path is a hidden directory.
   bool _isInHiddenDir(String relative) =>
       path.split(relative).any((part) => part.startsWith("."));
@@ -582,16 +629,25 @@
     return errorSeverity;
   }
 
-  void _setupSdk(CommandLineOptions options) {
+  void _setupSdk(CommandLineOptions options, bool useSummaries) {
     if (sdk == null) {
-      String dartSdkPath = options.dartSdkPath;
-      sdk = new DirectoryBasedDartSdk(new JavaFile(dartSdkPath));
-      sdk.useSummary = options.sourceFiles.every((String sourcePath) {
-            sourcePath = path.absolute(sourcePath);
-            sourcePath = path.normalize(sourcePath);
-            return !path.isWithin(dartSdkPath, sourcePath);
-          });
-      sdk.analysisOptions = context.analysisOptions;
+      if (options.dartSdkSummaryPath != null) {
+        sdk = new SummaryBasedDartSdk(
+            options.dartSdkSummaryPath, options.strongMode);
+      } else {
+        String dartSdkPath = options.dartSdkPath;
+        DirectoryBasedDartSdk directorySdk = new DirectoryBasedDartSdk(
+            new JavaFile(dartSdkPath), options.strongMode);
+        directorySdk.useSummary = useSummaries &&
+            options.sourceFiles.every((String sourcePath) {
+              sourcePath = path.absolute(sourcePath);
+              sourcePath = path.normalize(sourcePath);
+              return !path.isWithin(dartSdkPath, sourcePath);
+            });
+
+        directorySdk.analysisOptions = context.analysisOptions;
+        sdk = directorySdk;
+      }
     }
   }
 
@@ -613,7 +669,7 @@
       CommandLineOptions options,
       void configureContextOptions(AnalysisOptionsImpl contextOptions)) {
     Map<String, String> definedVariables = options.definedVariables;
-    if (!definedVariables.isEmpty) {
+    if (definedVariables.isNotEmpty) {
       DeclaredVariables declaredVariables = context.declaredVariables;
       definedVariables.forEach((String variableName, String value) {
         declaredVariables.define(variableName, value);
@@ -649,8 +705,8 @@
     return true;
   }
 
-  static fileSystem.File _getOptionsFile(CommandLineOptions options) {
-    fileSystem.File file;
+  static file_system.File _getOptionsFile(CommandLineOptions options) {
+    file_system.File file;
     String filePath = options.analysisOptionsFile;
     if (filePath != null) {
       file = PhysicalResourceProvider.INSTANCE.getFile(filePath);
@@ -661,6 +717,10 @@
     } else {
       filePath = AnalysisEngine.ANALYSIS_OPTIONS_FILE;
       file = PhysicalResourceProvider.INSTANCE.getFile(filePath);
+      if (!file.exists) {
+        filePath = AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE;
+        file = PhysicalResourceProvider.INSTANCE.getFile(filePath);
+      }
     }
     return file;
   }
@@ -671,7 +731,7 @@
 
   static void _processAnalysisOptions(
       AnalysisContext context, CommandLineOptions options) {
-    fileSystem.File file = _getOptionsFile(options);
+    file_system.File file = _getOptionsFile(options);
     List<OptionsProcessor> optionsProcessors =
         AnalysisEngine.instance.optionsPlugin.optionsProcessors;
     try {
@@ -761,13 +821,19 @@
   _DriverError(this.msg);
 }
 
+class _PackageInfo {
+  Packages packages;
+  Map<String, List<file_system.Folder>> packageMap;
+  _PackageInfo(this.packages, this.packageMap);
+}
+
 /// [SdkExtUriResolver] needs a Map from package name to folder. In the case
 /// that the analyzer is invoked with a --package-root option, we need to
 /// manually create this mapping. Given [packageRootPath],
 /// [_PackageRootPackageMapBuilder] creates a simple mapping from package name
 /// to full path on disk (resolving any symbolic links).
 class _PackageRootPackageMapBuilder {
-  static Map<String, List<fileSystem.Folder>> buildPackageMap(
+  static Map<String, List<file_system.Folder>> buildPackageMap(
       String packageRootPath) {
     var packageRoot = new Directory(packageRootPath);
     if (!packageRoot.existsSync()) {
@@ -775,7 +841,7 @@
           'Package root directory ($packageRootPath) does not exist.');
     }
     var packages = packageRoot.listSync(followLinks: false);
-    var result = new Map<String, List<fileSystem.Folder>>();
+    var result = new Map<String, List<file_system.Folder>>();
     for (var package in packages) {
       var packageName = path.basename(package.path);
       var realPath = package.resolveSymbolicLinksSync();
diff --git a/pkg/analyzer_cli/lib/src/options.dart b/pkg/analyzer_cli/lib/src/options.dart
index ae8466c..5a2e939 100644
--- a/pkg/analyzer_cli/lib/src/options.dart
+++ b/pkg/analyzer_cli/lib/src/options.dart
@@ -68,9 +68,12 @@
   /// Whether to suppress a nonzero exit code in build mode.
   final bool buildSuppressExitCode;
 
-  /// The path to the dart SDK
+  /// The path to the dart SDK.
   String dartSdkPath;
 
+  /// The path to the dart SDK summary file.
+  String dartSdkSummaryPath;
+
   /// A table mapping the names of defined variables to their values.
   final Map<String, String> definedVariables;
 
@@ -159,6 +162,7 @@
         buildSummaryOutput = args['build-summary-output'],
         buildSuppressExitCode = args['build-suppress-exit-code'],
         dartSdkPath = args['dart-sdk'],
+        dartSdkSummaryPath = args['dart-sdk-summary'],
         definedVariables = definedVariables,
         analysisOptionsFile = args['options'],
         disableHints = args['no-hints'],
@@ -193,7 +197,7 @@
       [printAndFail(String msg) = printAndFail]) {
     CommandLineOptions options = _parse(args);
     // Check SDK.
-    {
+    if (!options.buildModePersistentWorker) {
       // Infer if unspecified.
       if (options.dartSdkPath == null) {
         Directory sdkDir = getSdkDir(args);
@@ -273,6 +277,8 @@
           defaultsTo: false,
           negatable: false)
       ..addOption('dart-sdk', help: 'The path to the Dart SDK.')
+      ..addOption('dart-sdk-summary',
+          help: 'The path to the Dart SDK summary file.', hide: true)
       ..addOption('packages',
           help:
               'Path to the package resolution configuration file, which supplies '
diff --git a/pkg/analyzer_cli/lib/src/plugin/plugin_manager.dart b/pkg/analyzer_cli/lib/src/plugin/plugin_manager.dart
index 13a8202..7c819fd 100644
--- a/pkg/analyzer_cli/lib/src/plugin/plugin_manager.dart
+++ b/pkg/analyzer_cli/lib/src/plugin/plugin_manager.dart
@@ -11,9 +11,9 @@
 
 const _manifestFileName = 'plugins.yaml';
 
-/// Given a local configuration (as defined in `.analysis_options`)
-/// and information from a plugin manifest, return plugin info
-/// appropriate for configuring this plugin.
+/// Given a local configuration (as defined in an analysis options file) and
+/// information from a plugin manifest, return plugin info appropriate for
+/// configuring this plugin.
 PluginInfo combine(PluginInfo localConfig, PluginInfo manifestInfo) {
   return new PluginInfo(
       name: localConfig.name,
diff --git a/pkg/analyzer_cli/pubspec.yaml b/pkg/analyzer_cli/pubspec.yaml
index dbccd97..a0ded9b 100644
--- a/pkg/analyzer_cli/pubspec.yaml
+++ b/pkg/analyzer_cli/pubspec.yaml
@@ -10,9 +10,9 @@
   args: ^0.13.0
   bazel_worker: ^0.1.0
   cli_util: ^0.0.1
-  linter: ^0.1.10
+  linter: ^0.1.16
   package_config: ^0.1.1
-  plugin: ^0.1.0
+  plugin: '>=0.1.0 <0.3.0'
   protobuf: ^0.5.0
   yaml: ^2.1.2
 dev_dependencies:
diff --git a/pkg/analyzer_cli/test/all.dart b/pkg/analyzer_cli/test/all.dart
index 13f72d1..5764922 100644
--- a/pkg/analyzer_cli/test/all.dart
+++ b/pkg/analyzer_cli/test/all.dart
@@ -5,23 +5,25 @@
 import 'boot_loader_test.dart' as boot_loader;
 import 'build_mode_test.dart' as build_mode_test;
 import 'driver_test.dart' as driver;
+import 'embedder_test.dart' as embedder;
 import 'error_test.dart' as error;
 import 'options_test.dart' as options;
 import 'package_prefix_test.dart' as package_prefix;
 import 'perf_report_test.dart' as perf;
 import 'plugin_manager_test.dart' as plugin_manager;
 import 'reporter_test.dart' as reporter;
+import 'sdk_ext_test.dart' as sdk_ext;
 import 'super_mixin_test.dart' as super_mixin;
-//import 'sdk_ext_test.dart' as sdk_ext;
 //import 'strong_mode_test.dart' as strong_mode;
 
 main() {
   boot_loader.main();
   build_mode_test.main();
   driver.main();
+  embedder.main();
+  sdk_ext.main();
   // TODO(pq): fix tests to run safely on the bots
   // https://github.com/dart-lang/sdk/issues/25001
-  //sdk_ext.main();
   //strong_mode.main();
   error.main();
   options.main();
diff --git a/pkg/analyzer_cli/test/data/linter_project/analysis_options.yaml b/pkg/analyzer_cli/test/data/linter_project/analysis_options.yaml
new file mode 100644
index 0000000..6af57a5
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/linter_project/analysis_options.yaml
@@ -0,0 +1,3 @@
+linter:
+  rules:
+    - camel_case_types
diff --git a/pkg/analyzer_cli/test/data/no_lints_project/analysis_options.yaml b/pkg/analyzer_cli/test/data/no_lints_project/analysis_options.yaml
new file mode 100644
index 0000000..1bb8bf6
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/no_lints_project/analysis_options.yaml
@@ -0,0 +1 @@
+# empty
diff --git a/pkg/analyzer_cli/test/data/options_tests_project/analysis_options.yaml b/pkg/analyzer_cli/test/data/options_tests_project/analysis_options.yaml
new file mode 100644
index 0000000..c0f4f1c
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/options_tests_project/analysis_options.yaml
@@ -0,0 +1,8 @@
+analyzer:
+  strong-mode: true
+  errors:
+    unused_local_variable: ignore
+    missing_return: error
+    undefined_function: warning
+  language:
+    enableSuperMixins: true
diff --git a/pkg/analyzer_cli/test/data/packages_file/_packages b/pkg/analyzer_cli/test/data/packages_file/_packages
new file mode 100644
index 0000000..c863897
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/packages_file/_packages
@@ -0,0 +1 @@
+package_with_sdk_extension:../package_with_sdk_extension/lib/
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart
index 6c85880..e549603 100644
--- a/pkg/analyzer_cli/test/driver_test.dart
+++ b/pkg/analyzer_cli/test/driver_test.dart
@@ -134,74 +134,78 @@
     });
 
     group('linter', () {
-      group('lints in options', () {
-        // Shared lint command.
-        var runLinter = () => drive('data/linter_project/test_file.dart',
-            options: 'data/linter_project/.analysis_options',
-            args: ['--lints']);
+      void createTests(String designator, String optionsFileName) {
+        group('lints in options - $designator', () {
+          // Shared lint command.
+          void runLinter() => drive('data/linter_project/test_file.dart',
+              options: 'data/linter_project/$optionsFileName',
+              args: ['--lints']);
 
-        test('gets analysis options', () {
-          runLinter();
+          test('gets analysis options', () {
+            runLinter();
 
-          /// Lints should be enabled.
-          expect(driver.context.analysisOptions.lint, isTrue);
+            /// Lints should be enabled.
+            expect(driver.context.analysisOptions.lint, isTrue);
 
-          /// The .analysis_options file only specifies 'camel_case_types'.
-          var lintNames = getLints(driver.context).map((r) => r.name);
-          expect(lintNames, orderedEquals(['camel_case_types']));
+            /// The analysis options file only specifies 'camel_case_types'.
+            var lintNames = getLints(driver.context).map((r) => r.name);
+            expect(lintNames, orderedEquals(['camel_case_types']));
+          });
+
+          test('generates lints', () {
+            runLinter();
+            expect(outSink.toString(),
+                contains('[lint] Name types using UpperCamelCase.'));
+          });
         });
 
-        test('generates lints', () {
-          runLinter();
-          expect(outSink.toString(),
-              contains('[lint] Name types using UpperCamelCase.'));
-        });
-      });
+        group('default lints - $designator', () {
+          // Shared lint command.
+          void runLinter() => drive('data/linter_project/test_file.dart',
+              options: 'data/linter_project/$optionsFileName',
+              args: ['--lints']);
 
-      group('default lints', () {
-        // Shared lint command.
-        var runLinter = () => drive('data/linter_project/test_file.dart',
-            options: 'data/linter_project/.analysis_options',
-            args: ['--lints']);
+          test('gets default lints', () {
+            runLinter();
 
-        test('gets default lints', () {
-          runLinter();
+            /// Lints should be enabled.
+            expect(driver.context.analysisOptions.lint, isTrue);
 
-          /// Lints should be enabled.
-          expect(driver.context.analysisOptions.lint, isTrue);
+            /// Default list should include camel_case_types.
+            var lintNames = getLints(driver.context).map((r) => r.name);
+            expect(lintNames, contains('camel_case_types'));
+          });
 
-          /// Default list should include camel_case_types.
-          var lintNames = getLints(driver.context).map((r) => r.name);
-          expect(lintNames, contains('camel_case_types'));
+          test('generates lints', () {
+            runLinter();
+            expect(outSink.toString(),
+                contains('[lint] Name types using UpperCamelCase.'));
+          });
         });
 
-        test('generates lints', () {
-          runLinter();
-          expect(outSink.toString(),
-              contains('[lint] Name types using UpperCamelCase.'));
-        });
-      });
+        group('no `--lints` flag (none in options) - $designator', () {
+          // Shared lint command.
+          void runLinter() => drive('data/no_lints_project/test_file.dart',
+              options: 'data/no_lints_project/$optionsFileName');
 
-      group('no `--lints` flag (none in options)', () {
-        // Shared lint command.
-        var runLinter = () => drive('data/no_lints_project/test_file.dart',
-            options: 'data/no_lints_project/.analysis_options');
+          test('lints disabled', () {
+            runLinter();
+            expect(driver.context.analysisOptions.lint, isFalse);
+          });
 
-        test('lints disabled', () {
-          runLinter();
-          expect(driver.context.analysisOptions.lint, isFalse);
-        });
+          test('no registered lints', () {
+            runLinter();
+            expect(getLints(driver.context), isEmpty);
+          });
 
-        test('no registered lints', () {
-          runLinter();
-          expect(getLints(driver.context), isEmpty);
+          test('no generated warnings', () {
+            runLinter();
+            expect(outSink.toString(), contains('No issues found'));
+          });
         });
-
-        test('no generated warnings', () {
-          runLinter();
-          expect(outSink.toString(), contains('No issues found'));
-        });
-      });
+      }
+      createTests('old', AnalysisEngine.ANALYSIS_OPTIONS_FILE);
+      createTests('new', AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
     });
 
     test('containsLintRuleEntry', () {
@@ -230,116 +234,126 @@
     });
 
     group('options processing', () {
-      group('basic config', () {
-        // Shared driver command.
-        var doDrive = () => drive('data/options_tests_project/test_file.dart',
-            options: 'data/options_tests_project/.analysis_options');
+      void createTests(String designator, String optionsFileName) {
+        group('basic config - $designator', () {
+          // Shared driver command.
+          void doDrive() => drive('data/options_tests_project/test_file.dart',
+              options: 'data/options_tests_project/$optionsFileName');
 
-        test('filters', () {
-          doDrive();
-          expect(processors, hasLength(3));
+          test('filters', () {
+            doDrive();
+            expect(processors, hasLength(3));
 
-          // unused_local_variable: ignore
-          var unused_local_variable = new AnalysisError(
-              new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [
-            ['x']
-          ]);
-          expect(processorFor(unused_local_variable).severity, isNull);
+            // unused_local_variable: ignore
+            var unused_local_variable = new AnalysisError(
+                new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [
+              ['x']
+            ]);
+            expect(processorFor(unused_local_variable).severity, isNull);
 
-          // missing_return: error
-          var missing_return = new AnalysisError(
-              new TestSource(), 0, 1, HintCode.MISSING_RETURN, [
-            ['x']
-          ]);
-          expect(processorFor(missing_return).severity, ErrorSeverity.ERROR);
-          expect(
-              outSink.toString(),
-              contains(
-                  "[error] This function declares a return type of 'int'"));
-          expect(outSink.toString(), contains("1 error and 1 warning found."));
+            // missing_return: error
+            var missing_return = new AnalysisError(
+                new TestSource(), 0, 1, HintCode.MISSING_RETURN, [
+              ['x']
+            ]);
+            expect(processorFor(missing_return).severity, ErrorSeverity.ERROR);
+            expect(
+                outSink.toString(),
+                contains(
+                    "[error] This function declares a return type of 'int'"));
+            expect(
+                outSink.toString(), contains("1 error and 1 warning found."));
+          });
+
+          test('language', () {
+            doDrive();
+            expect(driver.context.analysisOptions.enableSuperMixins, isTrue);
+          });
+
+          test('strongMode', () {
+            doDrive();
+            expect(driver.context.analysisOptions.strongMode, isTrue);
+            //https://github.com/dart-lang/sdk/issues/26129
+            AnalysisContext sdkContext =
+                driver.context.sourceFactory.dartSdk.context;
+            expect(sdkContext.analysisOptions.strongMode, isTrue);
+          });
         });
 
-        test('language', () {
-          doDrive();
-          expect(driver.context.analysisOptions.enableSuperMixins, isTrue);
+        group('with flags - $designator', () {
+          // Shared driver command.
+          void doDrive() => drive('data/options_tests_project/test_file.dart',
+              args: ['--fatal-warnings'],
+              options: 'data/options_tests_project/$optionsFileName');
+
+          test('override fatal warning', () {
+            doDrive();
+            // missing_return: error
+            var undefined_function = new AnalysisError(new TestSource(), 0, 1,
+                StaticTypeWarningCode.UNDEFINED_FUNCTION, [
+              ['x']
+            ]);
+            expect(processorFor(undefined_function).severity,
+                ErrorSeverity.WARNING);
+            // Should not be made fatal by `--fatal-warnings`.
+            expect(outSink.toString(),
+                contains("[warning] The function 'baz' is not defined"));
+            expect(
+                outSink.toString(), contains("1 error and 1 warning found."));
+          });
         });
-
-        test('strongMode', () {
-          doDrive();
-          expect(driver.context.analysisOptions.strongMode, isTrue);
-          //https://github.com/dart-lang/sdk/issues/26129
-          AnalysisContext sdkContext =
-              driver.context.sourceFactory.dartSdk.context;
-          expect(sdkContext.analysisOptions.strongMode, isTrue);
-        });
-      });
-
-      group('with flags', () {
-        // Shared driver command.
-        var doDrive = () => drive('data/options_tests_project/test_file.dart',
-            args: ['--fatal-warnings'],
-            options: 'data/options_tests_project/.analysis_options');
-
-        test('override fatal warning', () {
-          doDrive();
-          // missing_return: error
-          var undefined_function = new AnalysisError(new TestSource(), 0, 1,
-              StaticTypeWarningCode.UNDEFINED_FUNCTION, [
-            ['x']
-          ]);
-          expect(
-              processorFor(undefined_function).severity, ErrorSeverity.WARNING);
-          // Should not be made fatal by `--fatal-warnings`.
-          expect(outSink.toString(),
-              contains("[warning] The function 'baz' is not defined"));
-          expect(outSink.toString(), contains("1 error and 1 warning found."));
-        });
-      });
-    });
-
-    group('build-mode', () {
-      // Shared driver command.
-      void doDrive(String filePath, {List<String> additionalArgs: const []}) {
-        drive('file:///test_file.dart|$filePath',
-            args: [
-              '--dart-sdk',
-              findSdkDirForSummaries(),
-              '--build-mode',
-              '--machine'
-            ]..addAll(additionalArgs),
-            options: 'data/options_tests_project/.analysis_options');
       }
-
-      test('no stats', () {
-        doDrive('data/test_file.dart');
-        // Should not print stat summary.
-        expect(outSink.toString(), isEmpty);
-        expect(errorSink.toString(), isEmpty);
-        expect(exitCode, 0);
-      });
-
-      test(
-          'Fails if file not found, even when --build-suppress-exit-code is given',
-          () {
-        doDrive('data/non_existent_file.dart',
-            additionalArgs: ['--build-suppress-exit-code']);
-        expect(exitCode, isNot(0));
-      });
-
-      test('Fails if there are errors', () {
-        doDrive('data/file_with_error.dart');
-        expect(exitCode, isNot(0));
-      });
-
-      test(
-          'Succeeds if there are errors, when --build-suppress-exit-code is given',
-          () {
-        doDrive('data/file_with_error.dart',
-            additionalArgs: ['--build-suppress-exit-code']);
-        expect(exitCode, 0);
-      });
+      createTests('old', AnalysisEngine.ANALYSIS_OPTIONS_FILE);
+      createTests('new', AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
     });
 
+    void createTests(String designator, String optionsFileName) {
+      group('build-mode - $designator', () {
+        // Shared driver command.
+        void doDrive(String filePath, {List<String> additionalArgs: const []}) {
+          drive('file:///test_file.dart|$filePath',
+              args: [
+                '--dart-sdk',
+                findSdkDirForSummaries(),
+                '--build-mode',
+                '--machine'
+              ]..addAll(additionalArgs),
+              options: 'data/options_tests_project/$optionsFileName');
+        }
+
+        test('no stats', () {
+          doDrive('data/test_file.dart');
+          // Should not print stat summary.
+          expect(outSink.toString(), isEmpty);
+          expect(errorSink.toString(), isEmpty);
+          expect(exitCode, 0);
+        });
+
+        test(
+            'Fails if file not found, even when --build-suppress-exit-code is given',
+            () {
+          doDrive('data/non_existent_file.dart',
+              additionalArgs: ['--build-suppress-exit-code']);
+          expect(exitCode, isNot(0));
+        });
+
+        test('Fails if there are errors', () {
+          doDrive('data/file_with_error.dart');
+          expect(exitCode, isNot(0));
+        });
+
+        test(
+            'Succeeds if there are errors, when --build-suppress-exit-code is given',
+            () {
+          doDrive('data/file_with_error.dart',
+              additionalArgs: ['--build-suppress-exit-code']);
+          expect(exitCode, 0);
+        });
+      });
+    }
+    createTests('old', AnalysisEngine.ANALYSIS_OPTIONS_FILE);
+    createTests('new', AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
+
 //TODO(pq): fix to be bot-friendly (sdk#25258).
 //    group('in temp directory', () {
 //      Directory savedCurrentDirectory;
diff --git a/pkg/analyzer_cli/test/embedder_test.dart b/pkg/analyzer_cli/test/embedder_test.dart
index ded83fd..5a57c2d 100644
--- a/pkg/analyzer_cli/test/embedder_test.dart
+++ b/pkg/analyzer_cli/test/embedder_test.dart
@@ -4,6 +4,7 @@
 
 import 'dart:io';
 
+import 'package:analyzer/src/generated/sdk_io.dart';
 import 'package:analyzer_cli/src/driver.dart' show Driver, errorSink, outSink;
 import 'package:path/path.dart' as path;
 import 'package:unittest/unittest.dart';
@@ -41,6 +42,19 @@
       expect(exitCode, 0);
       expect(outSink.toString(), contains('No issues found'));
     }));
+
+    test('sdk setup', wrap(() {
+      var testDir = path.join(testDirectory, 'data', 'embedder_client');
+      Driver driver = new Driver();
+      driver.start([
+        '--packages',
+        path.join(testDir, '_packages'),
+        path.join(testDir, 'embedder_yaml_user.dart')
+      ]);
+
+      DirectoryBasedDartSdk sdk = driver.sdk;
+      expect(sdk.useSummary, false);
+    }));
   });
 }
 
diff --git a/pkg/analyzer_cli/test/sdk_ext_test.dart b/pkg/analyzer_cli/test/sdk_ext_test.dart
index e7aa5ce..1376d46 100644
--- a/pkg/analyzer_cli/test/sdk_ext_test.dart
+++ b/pkg/analyzer_cli/test/sdk_ext_test.dart
@@ -7,48 +7,47 @@
 
 import 'dart:io';
 
+import 'package:analyzer/src/generated/sdk_io.dart';
 import 'package:analyzer_cli/src/driver.dart' show Driver, errorSink, outSink;
+import 'package:analyzer_cli/src/options.dart';
 import 'package:path/path.dart' as path;
 import 'package:unittest/unittest.dart';
 
 import 'utils.dart';
 
-// TODO(pq): fix tests to run safely on the bots
-// https://github.com/dart-lang/sdk/issues/25001
-main() {}
-not_main() {
+main() {
   group('Sdk extensions', () {
     StringSink savedOutSink, savedErrorSink;
     int savedExitCode;
-    Directory savedCurrentDirectory;
+    ExitHandler savedExitHandler;
+
     setUp(() {
       savedOutSink = outSink;
       savedErrorSink = errorSink;
+      savedExitHandler = exitHandler;
       savedExitCode = exitCode;
+      exitHandler = (code) => exitCode = code;
       outSink = new StringBuffer();
       errorSink = new StringBuffer();
-      savedCurrentDirectory = Directory.current;
     });
     tearDown(() {
       outSink = savedOutSink;
       errorSink = savedErrorSink;
       exitCode = savedExitCode;
-      Directory.current = savedCurrentDirectory;
+      exitHandler = savedExitHandler;
     });
 
-    test('--packages option supplied', () async {
-      var testDir = path.join(testDirectory, 'data', 'no_packages_file');
-      Directory.current = new Directory(testDir);
-      var packagesPath = path.join('..', 'packages_file', '.packages');
-      new Driver().start(['--packages', packagesPath, 'sdk_ext_user.dart']);
+    test('.packages file specified', () async {
+      String testDir = path.join(testDirectory, 'data', 'packages_file');
+      Driver driver = new Driver()
+        ..start([
+          '--packages',
+          path.join(testDir, '_packages'),
+          path.join(testDir, 'sdk_ext_user.dart')
+        ]);
 
-      expect(exitCode, 0);
-    });
-
-    test('.packages file present', () async {
-      var testDir = path.join(testDirectory, 'data', 'packages_file');
-      Directory.current = new Directory(testDir);
-      new Driver().start(['sdk_ext_user.dart']);
+      DirectoryBasedDartSdk sdk = driver.sdk;
+      expect(sdk.useSummary, isFalse);
 
       expect(exitCode, 0);
     });
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index e802bd4..631d29b 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -26,6 +26,7 @@
 import 'platform_configuration.dart' as platform_configuration;
 import 'resolved_uri_translator.dart';
 import 'script.dart';
+import 'serialization/system.dart';
 
 /// Implements the [Compiler] using a [api.CompilerInput] for supplying the
 /// sources.
@@ -112,17 +113,8 @@
     // TODO(johnniwinther): Wrap the result from [provider] in a specialized
     // [Future] to ensure that we never execute an asynchronous action without
     // setting up the current element of the compiler.
-    return new Future.sync(() => callUserProvider(resourceUri)).then((data) {
-      SourceFile sourceFile;
-      if (data is List<int>) {
-        sourceFile = new Utf8BytesSourceFile(resourceUri, data);
-      } else if (data is String) {
-        sourceFile = new StringSourceFile.fromUri(resourceUri, data);
-      } else {
-        String message = "Expected a 'String' or a 'List<int>' from the input "
-            "provider, but got: ${Error.safeToString(data)}.";
-        reportReadError(message);
-      }
+    return new Future.sync(() => callUserProvider(resourceUri))
+        .then((SourceFile sourceFile) {
       // We use [readableUri] as the URI for the script since need to preserve
       // the scheme in the script because [Script.uri] is used for resolving
       // relative URIs mentioned in the script. See the comment on
@@ -182,10 +174,9 @@
       // and we can't depend on 'dart:io' classes.
       packages = new NonFilePackagesDirectoryPackages(options.packageRoot);
     } else if (options.packageConfig != null) {
-      return callUserProvider(options.packageConfig).then((configContents) {
-        if (configContents is String) {
-          configContents = UTF8.encode(configContents);
-        }
+      return callUserProvider(options.packageConfig)
+          .then((SourceFile sourceFile) {
+        List<int> configContents = sourceFile.slowUtf8ZeroTerminatedBytes();
         // The input provider may put a trailing 0 byte when it reads a source
         // file, which confuses the package config parser.
         if (configContents.length > 0 && configContents.last == 0) {
@@ -213,18 +204,27 @@
   }
 
   Future<Null> setupSdk() {
-    if (resolvedUriTranslator.isNotSet) {
-      return platform_configuration
-          .load(options.platformConfigUri, provider)
-          .then((Map<String, Uri> mapping) {
-        resolvedUriTranslator.resolvedUriTranslator =
-            new ResolvedUriTranslator(mapping, reporter);
+    Future future = new Future.value(null);
+    if (options.resolutionInput != null) {
+      reporter.log('Reading serialized data from ${options.resolutionInput}');
+      future = callUserProvider(options.resolutionInput)
+          .then((SourceFile sourceFile) {
+        serialization.deserializeFromText(sourceFile.slowText());
       });
-    } else {
-      // The incremental compiler sets up the sdk before run.
-      // Therefore this will be called a second time.
-      return new Future.value(null);
     }
+    if (resolvedUriTranslator.isNotSet) {
+      future = future.then((_) {
+        return platform_configuration
+            .load(options.platformConfigUri, provider)
+            .then((Map<String, Uri> mapping) {
+          resolvedUriTranslator.resolvedUriTranslator =
+              new ResolvedUriTranslator(mapping, reporter);
+        });
+      });
+    }
+    // The incremental compiler sets up the sdk before run.
+    // Therefore this will be called a second time.
+    return future;
   }
 
   Future<bool> run(Uri uri) {
@@ -316,9 +316,22 @@
     }
   }
 
-  Future callUserProvider(Uri uri) {
+  Future<SourceFile> callUserProvider(Uri uri) {
     try {
-      return userProviderTask.measureIo(() => provider.readFromUri(uri));
+      return userProviderTask
+          .measureIo(() => provider.readFromUri(uri))
+          .then((data) {
+        SourceFile sourceFile;
+        if (data is List<int>) {
+          sourceFile = new Utf8BytesSourceFile(uri, data);
+        } else if (data is String) {
+          sourceFile = new StringSourceFile.fromUri(uri, data);
+        } else {
+          throw "Expected a 'String' or a 'List<int>' from the input "
+              "provider, but got: ${Error.safeToString(data)}.";
+        }
+        return sourceFile;
+      });
     } catch (ex, s) {
       reportCrashInUserCode('Uncaught exception in input provider', ex, s);
       rethrow;
diff --git a/pkg/compiler/lib/src/closure.dart b/pkg/compiler/lib/src/closure.dart
index 0e9f37f..4e0c2ef 100644
--- a/pkg/compiler/lib/src/closure.dart
+++ b/pkg/compiler/lib/src/closure.dart
@@ -36,37 +36,42 @@
       if (resolvedAst.kind != ResolvedAstKind.PARSED) {
         return new ClosureClassMap(null, null, null, new ThisLocal(element));
       }
-      Node node = resolvedAst.node;
-      TreeElements elements = resolvedAst.elements;
+      return reporter.withCurrentElement(element.implementation, () {
+        Node node = resolvedAst.node;
+        TreeElements elements = resolvedAst.elements;
 
-      ClosureClassMap cached = closureMappingCache[node];
-      if (cached != null) return cached;
+        ClosureClassMap cached = closureMappingCache[node];
+        if (cached != null) return cached;
 
-      ClosureTranslator translator =
-          new ClosureTranslator(compiler, elements, closureMappingCache);
+        ClosureTranslator translator =
+            new ClosureTranslator(compiler, elements, closureMappingCache);
 
-      // The translator will store the computed closure-mappings inside the
-      // cache. One for given node and one for each nested closure.
-      if (node is FunctionExpression) {
-        translator.translateFunction(element, node);
-      } else if (element.isSynthesized) {
-        reporter.internalError(
-            element, "Unexpected synthesized element: $element");
-        return new ClosureClassMap(null, null, null, new ThisLocal(element));
-      } else {
-        assert(element.isField);
-        Node initializer = resolvedAst.body;
-        if (initializer != null) {
-          // The lazy initializer of a static.
-          translator.translateLazyInitializer(element, node, initializer);
+        // The translator will store the computed closure-mappings inside the
+        // cache. One for given node and one for each nested closure.
+        if (node is FunctionExpression) {
+          translator.translateFunction(element, node);
+        } else if (element.isSynthesized) {
+          reporter.internalError(
+              element, "Unexpected synthesized element: $element");
+          return new ClosureClassMap(null, null, null, new ThisLocal(element));
         } else {
-          assert(element.isInstanceMember);
-          closureMappingCache[node] =
-              new ClosureClassMap(null, null, null, new ThisLocal(element));
+          assert(invariant(element, element.isField,
+              message: "Expected $element to be a field."));
+          Node initializer = resolvedAst.body;
+          if (initializer != null) {
+            // The lazy initializer of a static.
+            translator.translateLazyInitializer(element, node, initializer);
+          } else {
+            assert(invariant(element, element.isInstanceMember,
+                message: "Expected $element (${element
+                    .runtimeType}) to be an instance field."));
+            closureMappingCache[node] =
+                new ClosureClassMap(null, null, null, new ThisLocal(element));
+          }
         }
-      }
-      assert(closureMappingCache[node] != null);
-      return closureMappingCache[node];
+        assert(closureMappingCache[node] != null);
+        return closureMappingCache[node];
+      });
     });
   }
 
@@ -96,6 +101,7 @@
 
 /// Common interface for [BoxFieldElement] and [ClosureFieldElement] as
 /// non-elements.
+// TODO(johnniwinther): Remove `implements Element`.
 abstract class CapturedVariable implements Element {}
 
 // TODO(ahe): These classes continuously cause problems.  We need to
@@ -243,6 +249,8 @@
   final ExecutableElement executableContext;
 
   BoxLocal(this.name, this.executableContext);
+
+  String toString() => 'BoxLocal($name)';
 }
 
 // TODO(ngeoffray, ahe): These classes continuously cause problems.  We need to
@@ -348,6 +356,8 @@
 
   Element get analyzableElement => closureClass.methodElement.analyzableElement;
 
+  bool get hasResolvedAst => true;
+
   ResolvedAst get resolvedAst {
     return new ParsedResolvedAst(this, node, node.body, treeElements,
         expression.compilationUnit.script.resourceUri);
@@ -433,7 +443,7 @@
   ///
   /// Also parameters to a `sync*` generator must be boxed, because of the way
   /// we rewrite sync* functions. See also comments in [useLocal].
-  /// TODO(johnniwinter): Add variables to this only if the variable is mutated.
+  // TODO(johnniwinther): Add variables to this only if the variable is mutated.
   final Set<Local> variablesUsedInTryOrGenerator = new Set<Local>();
 
   ClosureClassMap(this.closureElement, this.closureClassElement,
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 9c0c244..fba8401 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -53,9 +53,13 @@
 
   // Experimental flags.
   static const String genericMethodSyntax = '--generic-method-syntax';
+  static const String resolveOnly = '--resolve-only';
 }
 
 class Option {
   static const String showPackageWarnings =
       '${Flags.showPackageWarnings}|${Flags.showPackageWarnings}=.*';
+
+  // Experimental options.
+  static const String resolutionInput = '--resolution-input=.+';
 }
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index 8ad503c..9860b08 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -234,9 +234,9 @@
     // missing call of form registry.registerXXX. Alternatively, the code
     // generation could spuriously be adding dependencies on things we know we
     // don't need.
-    assert(invariant(element, compiler.backend.frontend.hasResolvedAst(element),
+    assert(invariant(element, element.hasResolvedAst,
         message: "$element has no resolved ast."));
-    ResolvedAst resolvedAst = compiler.backend.frontend.getResolvedAst(element);
+    ResolvedAst resolvedAst = element.resolvedAst;
     return new CodegenWorkItem.internal(resolvedAst, compilationContext);
   }
 
diff --git a/pkg/compiler/lib/src/common/resolution.dart b/pkg/compiler/lib/src/common/resolution.dart
index 250a038..53f6190 100644
--- a/pkg/compiler/lib/src/common/resolution.dart
+++ b/pkg/compiler/lib/src/common/resolution.dart
@@ -191,12 +191,6 @@
 /// Interface for the accessing the front-end analysis.
 // TODO(johnniwinther): Find a better name for this.
 abstract class Frontend {
-  /// Returns `true` if [element] has a [ResolvedAst].
-  bool hasResolvedAst(ExecutableElement element);
-
-  /// Returns the `ResolvedAst` for the [element].
-  ResolvedAst getResolvedAst(ExecutableElement element);
-
   /// Returns the [ResolutionImpact] for [element].
   ResolutionImpact getResolutionImpact(Element element);
 }
diff --git a/pkg/compiler/lib/src/compile_time_constants.dart b/pkg/compiler/lib/src/compile_time_constants.dart
index 724e6f6..82cc6de 100644
--- a/pkg/compiler/lib/src/compile_time_constants.dart
+++ b/pkg/compiler/lib/src/compile_time_constants.dart
@@ -1187,7 +1187,8 @@
    * the [fieldValues] map.
    */
   void evaluateConstructorInitializers() {
-    if (constructor.isSynthesized) {
+    ResolvedAst resolvedAst = constructor.resolvedAst;
+    if (resolvedAst.kind != ResolvedAstKind.PARSED) {
       List<AstConstant> compiledArguments = <AstConstant>[];
 
       Function compileArgument = (element) => definitions[element];
@@ -1198,7 +1199,7 @@
       evaluateSuperOrRedirectSend(compiledArguments, target);
       return;
     }
-    FunctionExpression functionNode = constructor.node;
+    FunctionExpression functionNode = resolvedAst.node;
     NodeList initializerList = functionNode.initializers;
 
     bool foundSuperOrRedirect = false;
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 7dbee2a..de80e0b 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -364,6 +364,9 @@
       reuseLibraryTask = new GenericTask('Reuse library', this),
       selfTask = new GenericTask('self', this),
     ];
+    if (options.resolveOnly) {
+      serialization.supportSerialization = true;
+    }
 
     _parsingContext =
         new ParsingContext(reporter, options, parser, patchParser, backend);
@@ -858,6 +861,12 @@
           }
         }
 
+        if (options.resolveOnly) {
+          reporter.log('Serializing to ${options.resolutionOutput}');
+          serialization.serializeToSink(
+              userOutputProvider.createEventSink('', 'data'),
+              libraryLoader.libraries);
+        }
         if (options.analyzeOnly) {
           if (!analyzeAll && !compilationFailed) {
             // No point in reporting unused code when [analyzeAll] is true: all
@@ -1934,9 +1943,6 @@
         message: "Element $element must be the declaration."));
     assert(invariant(element, hasResolvedAst(element),
         message: "ResolvedAst not available for $element."));
-    if (compiler.serialization.isDeserialized(element)) {
-      return compiler.serialization.getResolvedAst(element);
-    }
     return element.resolvedAst;
   }
 
diff --git a/pkg/compiler/lib/src/cps_ir/cps_fragment.dart b/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
index 992ae55..4e22d0e 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
@@ -270,7 +270,7 @@
   ///
   /// Returns a primitive containing the function's return value.
   ///
-  /// The new hole is the the point after [target] has returned. The fragment
+  /// The new hole is the point after [target] has returned. The fragment
   /// remains open, even if [target] never returns.
   ///
   /// The [target] function is destroyed and should not be reused.
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
index c382e4e..29b516d 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
@@ -291,6 +291,7 @@
     assert(constructor.isGenerativeConstructor);
     assert(constructor.isImplementation);
     if (constructor.isSynthesized) return null;
+    ResolvedAst resolvedAst = constructor.resolvedAst;
     ast.FunctionExpression node = constructor.node;
     // If we know the body doesn't have any code, we don't generate it.
     if (!node.hasBody) return null;
@@ -306,14 +307,14 @@
       }
     });
     if (bodyElement == null) {
-      bodyElement = new ConstructorBodyElementX(constructor);
+      bodyElement = new ConstructorBodyElementX(resolvedAst, constructor);
       classElement.addBackendMember(bodyElement);
 
       if (constructor.isPatch) {
         // Create origin body element for patched constructors.
         ConstructorBodyElementX patch = bodyElement;
         ConstructorBodyElementX origin =
-            new ConstructorBodyElementX(constructor.origin);
+            new ConstructorBodyElementX(resolvedAst, constructor.origin);
         origin.applyPatch(patch);
         classElement.origin.addBackendMember(bodyElement.origin);
       }
@@ -502,7 +503,7 @@
   /// Every visitor can only be applied to nodes in one context, because
   /// the [elements] field is specific to that context.
   IrBuilderVisitor makeVisitorForContext(AstElement context) {
-    ResolvedAst resolvedAst = backend.frontend.getResolvedAst(context);
+    ResolvedAst resolvedAst = context.resolvedAst;
     return new IrBuilderVisitor(resolvedAst, compiler,
         sourceInformationBuilder.forContext(resolvedAst), typeMaskSystem);
   }
diff --git a/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart b/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
index 35d9b76..60129af 100644
--- a/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
+++ b/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
@@ -134,7 +134,7 @@
     return _markInnerLoop(target, catchLoop);
   }
 
-  /// Returns the the innermost loop that effectively encloses both
+  /// Returns the innermost loop that effectively encloses both
   /// c1 and c2 (or `null` if there is no such loop).
   Continuation lowestCommonAncestor(Continuation c1, Continuation c2) {
     int d1 = getDepth(c1), d2 = getDepth(c2);
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 336dfc6..5dffdf7de 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -4,16 +4,20 @@
 
 library dart2js.cmdline;
 
-import 'dart:async' show Future;
+import 'dart:async' show EventSink, Future;
 import 'dart:convert' show UTF8, LineSplitter;
 import 'dart:io' show exit, File, FileMode, Platform, stdin, stderr;
 
 import 'package:package_config/discovery.dart' show findPackages;
 
-import '../compiler.dart' as api;
+import '../compiler_new.dart' as api;
+import 'apiimpl.dart';
+import 'common/names.dart' show Uris;
 import 'commandline_options.dart';
 import 'filenames.dart';
 import 'io/source_file.dart';
+import 'null_compiler_output.dart';
+import 'options.dart' show CompilerOptions;
 import 'source_file_provider.dart';
 import 'util/command_line.dart';
 import 'util/uri_extras.dart';
@@ -104,16 +108,19 @@
   Uri libraryRoot = currentDirectory;
   Uri out = currentDirectory.resolve('out.js');
   Uri sourceMapOut = currentDirectory.resolve('out.js.map');
+  Uri resolutionInput;
   Uri packageConfig = null;
   Uri packageRoot = null;
   List<String> options = new List<String>();
-  bool explicitOut = false;
+  List<String> explicitOutputArguments = <String>[];
   bool wantHelp = false;
   bool wantVersion = false;
   String outputLanguage = 'JavaScript';
   bool stripArgumentSet = false;
   bool analyzeOnly = false;
   bool analyzeAll = false;
+  bool resolveOnly = false;
+  Uri resolutionOutput = currentDirectory.resolve('out.data');
   bool dumpInfo = false;
   bool allowNativeExtensions = false;
   bool trustTypeAnnotations = false;
@@ -127,47 +134,47 @@
   diagnosticHandler = new FormattingDiagnosticHandler(inputProvider);
   Map<String, dynamic> environment = new Map<String, dynamic>();
 
-  passThrough(String argument) => options.add(argument);
+  void passThrough(String argument) => options.add(argument);
 
   if (BUILD_ID != null) {
     passThrough("--build-id=$BUILD_ID");
   }
 
-  setLibraryRoot(String argument) {
+  void setLibraryRoot(String argument) {
     libraryRoot = currentDirectory.resolve(extractPath(argument));
   }
 
-  setPackageRoot(String argument) {
+  void setPackageRoot(String argument) {
     packageRoot = currentDirectory.resolve(extractPath(argument));
   }
 
-  setPackageConfig(String argument) {
+  void setPackageConfig(String argument) {
     packageConfig =
         currentDirectory.resolve(extractPath(argument, isDirectory: false));
   }
 
-  setOutput(Iterator<String> arguments) {
-    optionsImplyCompilation.add(arguments.current);
+  void setOutput(Iterator<String> arguments) {
+    explicitOutputArguments.add(arguments.current);
     String path;
     if (arguments.current == '-o') {
       if (!arguments.moveNext()) {
         helpAndFail('Error: Missing file after -o option.');
       }
+      explicitOutputArguments.add(arguments.current);
       path = arguments.current;
     } else {
       path = extractParameter(arguments.current);
     }
-    explicitOut = true;
-    out = currentDirectory.resolve(nativeToUriPath(path));
+    resolutionOutput = out = currentDirectory.resolve(nativeToUriPath(path));
     sourceMapOut = Uri.parse('$out.map');
   }
 
-  setOutputType(String argument) {
+  void setOutputType(String argument) {
     optionsImplyCompilation.add(argument);
     if (argument == '--output-type=dart' ||
         argument == '--output-type=dart-multi') {
       outputLanguage = OUTPUT_LANGUAGE_DART;
-      if (!explicitOut) {
+      if (explicitOutputArguments.isNotEmpty) {
         out = currentDirectory.resolve('out.dart');
         sourceMapOut = currentDirectory.resolve('out.dart.map');
       }
@@ -182,75 +189,84 @@
     passThrough(argument);
   }
 
+  void setResolutionInput(String argument) {
+    resolutionInput =
+        currentDirectory.resolve(extractPath(argument, isDirectory: false));
+  }
+
+  void setResolveOnly(String argument) {
+    resolveOnly = true;
+    passThrough(argument);
+  }
+
   String getDepsOutput(Map<Uri, SourceFile> sourceFiles) {
     var filenames = sourceFiles.keys.map((uri) => '$uri').toList();
     filenames.sort();
     return filenames.join("\n");
   }
 
-  setStrip(String argument) {
+  void implyCompilation(String argument) {
     optionsImplyCompilation.add(argument);
-    stripArgumentSet = true;
     passThrough(argument);
   }
 
-  setAnalyzeOnly(String argument) {
+  void setStrip(String argument) {
+    stripArgumentSet = true;
+    implyCompilation(argument);
+  }
+
+  void setAnalyzeOnly(String argument) {
     analyzeOnly = true;
     passThrough(argument);
   }
 
-  setAnalyzeAll(String argument) {
+  void setAnalyzeAll(String argument) {
     analyzeAll = true;
     passThrough(argument);
   }
 
-  setAllowNativeExtensions(String argument) {
+  void setAllowNativeExtensions(String argument) {
     allowNativeExtensions = true;
     passThrough(argument);
   }
 
-  setVerbose(_) {
+  void setVerbose(_) {
     diagnosticHandler.verbose = true;
     passThrough('--verbose');
   }
 
-  implyCompilation(String argument) {
-    optionsImplyCompilation.add(argument);
-    passThrough(argument);
-  }
-
-  setDumpInfo(String argument) {
+  void setDumpInfo(String argument) {
     implyCompilation(argument);
     dumpInfo = true;
   }
 
-  setTrustTypeAnnotations(String argument) {
+  void setTrustTypeAnnotations(String argument) {
     trustTypeAnnotations = true;
     implyCompilation(argument);
   }
 
-  setTrustJSInteropTypeAnnotations(String argument) {
+  void setTrustJSInteropTypeAnnotations(String argument) {
     trustJSInteropTypeAnnotations = true;
     implyCompilation(argument);
   }
 
-  setTrustPrimitives(String argument) {
+  void setTrustPrimitives(String argument) {
     implyCompilation(argument);
   }
 
-  setCheckedMode(String argument) {
+  void setCheckedMode(String argument) {
     checkedMode = true;
     passThrough(argument);
   }
 
-  addInEnvironment(String argument) {
+  void addInEnvironment(String argument) {
     int eqIndex = argument.indexOf('=');
     String name = argument.substring(2, eqIndex);
     String value = argument.substring(eqIndex + 1);
     environment[name] = value;
   }
 
-  setCategories(String argument) {
+  void setCategories(String argument) {
     List<String> categories = extractParameter(argument).split(',');
     if (categories.contains('all')) {
       categories = ["Client", "Server"];
@@ -273,7 +289,7 @@
     }
   }
 
-  handleShortOptions(String argument) {
+  void handleShortOptions(String argument) {
     var shortOptions = argument.substring(1).split("");
     for (var shortOption in shortOptions) {
       switch (shortOption) {
@@ -342,6 +358,8 @@
     new OptionHandler(Flags.analyzeAll, setAnalyzeAll),
     new OptionHandler(Flags.analyzeOnly, setAnalyzeOnly),
     new OptionHandler(Flags.noSourceMaps, passThrough),
+    new OptionHandler(Option.resolutionInput, setResolutionInput),
+    new OptionHandler(Flags.resolveOnly, setResolveOnly),
     new OptionHandler(Flags.analyzeSignaturesOnly, setAnalyzeOnly),
     new OptionHandler(Flags.disableNativeLiveTypeAnalysis, passThrough),
     new OptionHandler('--categories=.*', setCategories),
@@ -355,6 +373,7 @@
     new OptionHandler(Flags.useContentSecurityPolicy, passThrough),
     new OptionHandler(Flags.enableExperimentalMirrors, passThrough),
     new OptionHandler(Flags.enableAssertMessage, passThrough),
+
     // TODO(floitsch): remove conditional directives flag.
     // We don't provide the info-message yet, since we haven't publicly
     // launched the feature yet.
@@ -427,18 +446,31 @@
     helpAndFail("Cannot specify both '--package-root' and '--packages.");
   }
 
-  if ((analyzeOnly || analyzeAll) && !optionsImplyCompilation.isEmpty) {
-    if (!analyzeOnly) {
+  List<String> optionsImplyOutput = <String>[]
+    ..addAll(optionsImplyCompilation)
+    ..addAll(explicitOutputArguments);
+  if (resolveOnly && !optionsImplyCompilation.isEmpty) {
+    diagnosticHandler.info(
+        "Options $optionsImplyCompilation indicate that compilation is "
+        "expected, but compilation is turned off by the option "
+        "'${Flags.resolveOnly}'.",
+        api.Diagnostic.INFO);
+  } else if ((analyzeOnly || analyzeAll) && !optionsImplyOutput.isEmpty) {
+    if (analyzeAll && !analyzeOnly) {
       diagnosticHandler.info(
           "Option '${Flags.analyzeAll}' implies '${Flags.analyzeOnly}'.",
           api.Diagnostic.INFO);
     }
     diagnosticHandler.info(
-        "Options $optionsImplyCompilation indicate that output is expected, "
+        "Options $optionsImplyOutput indicate that output is expected, "
         "but compilation is turned off by the option '${Flags.analyzeOnly}'.",
         api.Diagnostic.INFO);
   }
-  if (analyzeAll) analyzeOnly = true;
+  if (resolveOnly) {
+    analyzeOnly = analyzeAll = true;
+  } else if (analyzeAll) {
+    analyzeOnly = true;
+  }
   if (!analyzeOnly) {
     if (allowNativeExtensions) {
       helpAndFail("Option '${Flags.allowNativeExtensions}' is only supported "
@@ -455,7 +487,9 @@
 
   RandomAccessFileOutputProvider outputProvider =
       new RandomAccessFileOutputProvider(out, sourceMapOut,
-          onInfo: diagnosticHandler.info, onFailure: fail);
+          onInfo: diagnosticHandler.info,
+          onFailure: fail,
+          resolutionOutput: resolveOnly ? resolutionOutput : null);
 
   api.CompilationResult compilationDone(api.CompilationResult result) {
     if (analyzeOnly) return result;
@@ -476,7 +510,7 @@
       for (String filename in outputProvider.allOutputFiles) {
         print("  $filename");
       }
-    } else if (!explicitOut) {
+    } else if (explicitOutputArguments.isNotEmpty) {
       String input = uriPathToNative(arguments[0]);
       String output = relativize(currentDirectory, out, Platform.isWindows);
       print('Dart file ($input) compiled to $outputLanguage: $output');
@@ -484,18 +518,19 @@
     return result;
   }
 
-  Uri uri = currentDirectory.resolve(arguments[0]);
+  Uri script = currentDirectory.resolve(arguments[0]);
+  CompilerOptions compilerOptions = new CompilerOptions.parse(
+      entryPoint: script,
+      libraryRoot: libraryRoot,
+      packageRoot: packageRoot,
+      packageConfig: packageConfig,
+      packagesDiscoveryProvider: findPackages,
+      resolutionInput: resolutionInput,
+      resolutionOutput: resolutionOutput,
+      options: options,
+      environment: environment);
   return compileFunc(
-          uri,
-          libraryRoot,
-          packageRoot,
-          inputProvider,
-          diagnosticHandler,
-          options,
-          outputProvider,
-          environment,
-          packageConfig,
-          findPackages)
+          compilerOptions, inputProvider, diagnosticHandler, outputProvider)
       .then(compilationDone);
 }
 
@@ -706,8 +741,15 @@
   internalMain(arguments);
 }
 
-var exitFunc = exit;
-var compileFunc = api.compile;
+typedef void ExitFunc(int exitCode);
+typedef Future<api.CompilationResult> CompileFunc(
+    CompilerOptions compilerOptions,
+    api.CompilerInput compilerInput,
+    api.CompilerDiagnostics compilerDiagnostics,
+    api.CompilerOutput compilerOutput);
+
+ExitFunc exitFunc = exit;
+CompileFunc compileFunc = api.compile;
 
 Future<api.CompilationResult> internalMain(List<String> arguments) {
   Future onError(exception, trace) {
@@ -754,6 +796,10 @@
     throw _EXIT_SIGNAL;
   };
 
+  if (USE_SERIALIZED_DART_CORE) {
+    _useSerializedDataForDartCore(compileFunc);
+  }
+
   var stream = stdin.transform(UTF8.decoder).transform(new LineSplitter());
   var subscription;
   subscription = stream.listen((line) {
@@ -784,3 +830,84 @@
     });
   });
 }
+
+final bool USE_SERIALIZED_DART_CORE =
+    Platform.environment['USE_SERIALIZED_DART_CORE'] == 'true';
+
+void _useSerializedDataForDartCore(CompileFunc oldCompileFunc) {
+  String serializedData;
+
+  Future<api.CompilationResult> compileWithSerializedData(
+      CompilerOptions compilerOptions,
+      api.CompilerInput compilerInput,
+      api.CompilerDiagnostics compilerDiagnostics,
+      api.CompilerOutput compilerOutput) async {
+    CompilerImpl compiler = new CompilerImpl(
+        compilerInput, compilerOutput, compilerDiagnostics, compilerOptions);
+    compiler.serialization.deserializeFromText(serializedData);
+    return compiler.run(compilerOptions.entryPoint).then((bool success) {
+      return new api.CompilationResult(compiler, isSuccess: success);
+    });
+  }
+
+  Future<api.CompilationResult> generateSerializedDataForDartCore(
+      CompilerOptions compilerOptions,
+      api.CompilerInput compilerInput,
+      api.CompilerDiagnostics compilerDiagnostics,
+      api.CompilerOutput compilerOutput) async {
+    _CompilerOutput output = new _CompilerOutput();
+    api.CompilationResult result = await oldCompileFunc(
+        new CompilerOptions.parse(
+            entryPoint: Uris.dart_core,
+            libraryRoot: compilerOptions.libraryRoot,
+            packageRoot: compilerOptions.packageRoot,
+            packageConfig: compilerOptions.packageConfig,
+            packagesDiscoveryProvider:
+                compilerOptions.packagesDiscoveryProvider,
+            environment: compilerOptions.environment,
+            resolutionOutput: Uri.parse('file:fake.data'),
+            options: [Flags.resolveOnly]),
+        compilerInput,
+        compilerDiagnostics,
+        output);
+    serializedData = output.serializedData;
+    compileFunc = compileWithSerializedData;
+    return compileWithSerializedData(
+        compilerOptions, compilerInput, compilerDiagnostics, compilerOutput);
+  }
+
+  compileFunc = generateSerializedDataForDartCore;
+}
+
+class _CompilerOutput extends NullCompilerOutput {
+  _BufferedEventSink sink;
+
+  @override
+  EventSink<String> createEventSink(String name, String extension) {
+    if (name == '' && extension == 'data') {
+      return sink = new _BufferedEventSink();
+    }
+    return super.createEventSink(name, extension);
+  }
+
+  String get serializedData => sink.sb.toString();
+}
+
+class _BufferedEventSink implements EventSink<String> {
+  StringBuffer sb = new StringBuffer();
+
+  @override
+  void add(String event) {
+    sb.write(event);
+  }
+
+  @override
+  void close() {
+    // Do nothing.
+  }
+
+  @override
+  void addError(errorEvent, [StackTrace stackTrace]) {
+    // Ignore
+  }
+}
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index bbd91ae..c34c06e 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -351,13 +351,13 @@
                 backend.constants.getConstantValue(expression);
             assert(invariant(node, value != null,
                 message: "Constant expression without value: "
-                         "${expression.toStructuredText()}."));
+                    "${expression.toStructuredText()}."));
             constants.add(value);
           } else {
-            assert(invariant(node,
-                expression.isImplicit || expression.isPotential,
-                message: "Unexpected unevaluated constant expression: "
-                    "${expression.toStructuredText()}."));
+            assert(
+                invariant(node, expression.isImplicit || expression.isPotential,
+                    message: "Unexpected unevaluated constant expression: "
+                        "${expression.toStructuredText()}."));
           }
         });
       }
diff --git a/pkg/compiler/lib/src/elements/modelx.dart b/pkg/compiler/lib/src/elements/modelx.dart
index 74ac6ad..3e14846 100644
--- a/pkg/compiler/lib/src/elements/modelx.dart
+++ b/pkg/compiler/lib/src/elements/modelx.dart
@@ -778,7 +778,7 @@
   Map<Element, List<ImportElement>> importers =
       new Map<Element, List<ImportElement>>();
 
-  /// Returns the the list of [ImportElement]s through which [element] was
+  /// Returns the list of [ImportElement]s through which [element] was
   /// imported.
   List<ImportElement> getImports(Element element) {
     List<ImportElement> imports = importers[element];
@@ -2284,18 +2284,32 @@
 
 class ConstructorBodyElementX extends BaseFunctionElementX
     implements ConstructorBodyElement {
-  ConstructorElementX constructor;
+  final ResolvedAst _resolvedAst;
+  final ConstructorElement constructor;
 
-  ConstructorBodyElementX(ConstructorElementX constructor)
-      : this.constructor = constructor,
+  ConstructorBodyElementX(
+      ResolvedAst resolvedAst, ConstructorElement constructor)
+      : this._resolvedAst = resolvedAst,
+        this.constructor = constructor,
         super(constructor.name, ElementKind.GENERATIVE_CONSTRUCTOR_BODY,
             Modifiers.EMPTY, constructor.enclosingElement) {
     functionSignature = constructor.functionSignature;
   }
 
-  bool get hasNode => constructor.hasNode;
+  bool get hasNode => _resolvedAst.kind == ResolvedAstKind.PARSED;
 
-  FunctionExpression get node => constructor.node;
+  FunctionExpression get node => _resolvedAst.node;
+
+  bool get hasResolvedAst => true;
+
+  ResolvedAst get resolvedAst {
+    if (_resolvedAst.kind == ResolvedAstKind.PARSED) {
+      return new ParsedResolvedAst(declaration, _resolvedAst.node,
+          _resolvedAst.body, _resolvedAst.elements, _resolvedAst.sourceUri);
+    } else {
+      return new SynthesizedResolvedAst(declaration, _resolvedAst.kind);
+    }
+  }
 
   List<MetadataAnnotation> get metadata => constructor.metadata;
 
@@ -2307,6 +2321,8 @@
     return null;
   }
 
+  int get sourceOffset => constructor.sourceOffset;
+
   Token get position => constructor.position;
 
   Element get outermostEnclosingMemberOrTopLevel => constructor;
diff --git a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
index e800c0f..a65d3e3 100644
--- a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
@@ -47,10 +47,6 @@
 
   CoreTypes get coreTypes => compiler.coreTypes;
 
-  ResolvedAst getResolvedAst(Element element) {
-    return compiler.backend.frontend.getResolvedAst(element.declaration);
-  }
-
   /**
    * Records the default type of parameter [parameter].
    */
@@ -268,7 +264,7 @@
       throw "updateSelector for IR node $node";
     }
     ast.Node astNode = node;
-    TreeElements elements = getResolvedAst(owner).elements;
+    TreeElements elements = owner.resolvedAst.elements;
     if (astNode.asSendSet() != null) {
       if (selector.isSetter || selector.isIndexSet) {
         elements.setTypeMask(node, mask);
@@ -359,12 +355,9 @@
             compiler,
             handler);
 
-  ResolvedAst getResolvedAst(Element element) {
-    return compiler.backend.frontend.getResolvedAst(element.declaration);
-  }
-
-  void analyzeSuperConstructorCall(Element target, ArgumentsTypes arguments) {
-    ResolvedAst resolvedAst = getResolvedAst(target);
+  void analyzeSuperConstructorCall(
+      AstElement target, ArgumentsTypes arguments) {
+    ResolvedAst resolvedAst = target.resolvedAst;
     inferrer.analyze(resolvedAst, arguments);
     isThisExposed = isThisExposed || inferrer.checkIfExposesThis(target);
   }
@@ -487,7 +480,7 @@
         cls.forEachInstanceField((_, FieldElement field) {
           if (field.isFinal) return;
           T type = locals.fieldScope.readField(field);
-          ResolvedAst resolvedAst = getResolvedAst(field);
+          ResolvedAst resolvedAst = field.resolvedAst;
           if (type == null && resolvedAst.body == null) {
             inferrer.recordTypeOfNonFinalField(
                 spannable, field, types.nullType);
@@ -565,7 +558,7 @@
     LocalsHandler closureLocals =
         new LocalsHandler<T>.from(locals, node, useOtherTryBlock: false);
     SimpleTypeInferrerVisitor visitor = new SimpleTypeInferrerVisitor<T>(
-        element, getResolvedAst(element), compiler, inferrer, closureLocals);
+        element, element.resolvedAst, compiler, inferrer, closureLocals);
     visitor.run();
     inferrer.recordReturnType(element, visitor.returnType);
 
@@ -667,16 +660,17 @@
     if (isThisExposed) return;
     inferrer.forEachElementMatching(selector, mask, (element) {
       if (element.isField) {
+        ResolvedAst elementResolvedAst = element.resolvedAst;
         if (!selector.isSetter &&
             isInClassOrSubclass(element) &&
-            !element.modifiers.isFinal &&
+            !element.isFinal &&
             locals.fieldScope.readField(element) == null &&
-            element.initializer == null) {
+            elementResolvedAst.body == null) {
           // If the field is being used before this constructor
           // actually had a chance to initialize it, say it can be
           // null.
           inferrer.recordTypeOfNonFinalField(
-              analyzedElement.node, element, types.nullType);
+              resolvedAst.node, element, types.nullType);
         }
         // Accessing a field does not expose [:this:].
         return true;
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
index 1cac7aa..f81a6ca 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
@@ -858,7 +858,7 @@
                   compiler.backend.constants.getConstantValue(constant);
               assert(invariant(fieldElement, value != null,
                   message: "Constant expression without value: "
-                           "${constant.toStructuredText()}."));
+                      "${constant.toStructuredText()}."));
               if (value.isFunction) {
                 FunctionConstantValue functionConstant = value;
                 type = types.allocateClosure(node, functionConstant.element);
@@ -1242,7 +1242,7 @@
       // TODO(ngeoffray): Not sure why the resolver would put a null
       // mapping.
       if (!compiler.enqueuer.resolution.hasBeenProcessed(element)) return;
-      ResolvedAst resolvedAst = getResolvedAst(element);
+      ResolvedAst resolvedAst = element.resolvedAst;
       element = element.implementation;
       if (element.impliesType) return;
       assert(invariant(
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 15b8de4..5f334e3 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -2508,41 +2508,6 @@
   ResolutionImpact getResolutionImpact(Element element) {
     return resolution.getResolutionImpact(element);
   }
-
-  @override
-  bool hasResolvedAst(ExecutableElement element) {
-    if (element is SynthesizedCallMethodElementX) {
-      return true;
-    } else if (element is ConstructorBodyElementX) {
-      return true;
-    } else if (element is FieldElementX) {
-      return true;
-    } else if (element is DeferredLoaderGetterElementX) {
-      return true;
-    } else {
-      return resolution.hasResolvedAst(element);
-    }
-  }
-
-  @override
-  ResolvedAst getResolvedAst(ExecutableElement element) {
-    if (element is SynthesizedCallMethodElementX) {
-      return element.resolvedAst;
-    } else if (element is ConstructorBodyElementX) {
-      return element.resolvedAst;
-    } else if (element is DeferredLoaderGetterElementX) {
-      return element.resolvedAst;
-    } else if (element is FieldElementX) {
-      // TODO(johnniwinther): Find a good invariant for resolution of fields.
-      // Currently some but not all are resolved (maybe it has to do with
-      // initializers?)
-      return element.resolvedAst;
-    } else {
-      assert(invariant(element, resolution.hasResolvedAst(element.declaration),
-          message: 'No ResolvedAst for $element'));
-      return resolution.getResolvedAst(element.declaration);
-    }
-  }
 }
 
 /// Handling of special annotations for tests.
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 4e8fe30..c0f21c5 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -478,6 +478,10 @@
         return asName('${callPrefix}\$2');
       case JsGetName.CALL_PREFIX3:
         return asName('${callPrefix}\$3');
+      case JsGetName.CALL_PREFIX4:
+        return asName('${callPrefix}\$4');
+      case JsGetName.CALL_PREFIX5:
+        return asName('${callPrefix}\$5');
       case JsGetName.CALL_CATCH_ALL:
         return asName(callCatchAllName);
       case JsGetName.REFLECTABLE:
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart
index 3eb4c8c..7df112d 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart
@@ -403,7 +403,7 @@
         // that we have a string.
         if (!superclass || typeof superclass != "string") {
           // Inlined special case of InheritFrom here for performance reasons.
-          // Fix up the the Dart Object class' prototype.
+          // Fix up the Dart Object class' prototype.
           var constructor = allClasses[cls];
           var prototype = constructor.prototype;
           prototype.constructor = constructor;
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index da33e20..b779ef7 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -428,11 +428,11 @@
                   // Check whether the arity matches this member.
                   var argumentCount = selector.argumentCount;
                   // JS interop does not support named arguments.
-                  if (selector.namedArgumentCount > 0) break;
-                  if (argumentCount < minArgs) break;
-                  if (argumentCount > maxArgs) break;
+                  if (selector.namedArgumentCount > 0) continue;
+                  if (argumentCount < minArgs) continue;
+                  if (argumentCount > maxArgs) continue;
                   var stubName = namer.invocationName(selector);
-                  if (!stubNames.add(stubName.key)) break;
+                  if (!stubNames.add(stubName.key)) continue;
                   var parameters =
                       new List<String>.generate(argumentCount, (i) => 'p$i');
 
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 84c8a80..93af700 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -187,6 +187,15 @@
   /// Whether to emit URIs in the reflection metadata.
   final bool preserveUris;
 
+  /// The location of serialized data used for resolution.
+  final Uri resolutionInput;
+
+  /// The location of the serialized data from resolution.
+  final Uri resolutionOutput;
+
+  // If `true`, sources are resolved and serialized.
+  final bool resolveOnly;
+
   /// URI where the compiler should generate the output source map file.
   final Uri sourceMapUri;
 
@@ -247,6 +256,8 @@
       Uri libraryRoot,
       Uri packageRoot,
       Uri packageConfig,
+      Uri resolutionInput,
+      Uri resolutionOutput,
       PackagesDiscoveryProvider packagesDiscoveryProvider,
       Map<String, dynamic> environment: const <String, dynamic>{},
       List<String> options}) {
@@ -298,6 +309,9 @@
             _resolvePlatformConfigFromOptions(libraryRoot, options),
         preserveComments: _hasOption(options, Flags.preserveComments),
         preserveUris: _hasOption(options, Flags.preserveUris),
+        resolutionInput: resolutionInput,
+        resolutionOutput: resolutionOutput,
+        resolveOnly: _hasOption(options, Flags.resolveOnly),
         sourceMapUri: _extractUriOption(options, '--source-map='),
         strips: _extractCsvOption(options, '--force-strip='),
         testMode: _hasOption(options, Flags.testMode),
@@ -359,6 +373,9 @@
       Uri platformConfigUri: null,
       bool preserveComments: false,
       bool preserveUris: false,
+      Uri resolutionInput: null,
+      Uri resolutionOutput: null,
+      bool resolveOnly: false,
       Uri sourceMapUri: null,
       List<String> strips: const [],
       bool testMode: false,
@@ -398,9 +415,10 @@
         packageConfig, packagesDiscoveryProvider, environment,
         allowMockCompilation: allowMockCompilation,
         allowNativeExtensions: allowNativeExtensions,
-        analyzeAll: analyzeAll,
+        analyzeAll: analyzeAll || resolveOnly,
         analyzeMain: analyzeMain,
-        analyzeOnly: analyzeOnly || analyzeSignaturesOnly || analyzeAll,
+        analyzeOnly:
+            analyzeOnly || analyzeSignaturesOnly || analyzeAll || resolveOnly,
         analyzeSignaturesOnly: analyzeSignaturesOnly,
         buildId: buildId,
         dart2dartMultiFile: dart2dartMultiFile,
@@ -430,6 +448,9 @@
                 libraryRoot, null, !emitJavaScript, const []),
         preserveComments: preserveComments,
         preserveUris: preserveUris,
+        resolutionInput: resolutionInput,
+        resolutionOutput: resolutionOutput,
+        resolveOnly: resolveOnly,
         sourceMapUri: sourceMapUri,
         strips: strips,
         testMode: testMode,
@@ -478,6 +499,9 @@
       this.platformConfigUri: null,
       this.preserveComments: false,
       this.preserveUris: false,
+      this.resolutionInput: null,
+      this.resolutionOutput: null,
+      this.resolveOnly: false,
       this.sourceMapUri: null,
       this.strips: const [],
       this.testMode: false,
diff --git a/pkg/compiler/lib/src/resolution/class_hierarchy.dart b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
index 4079c78..1150c96 100644
--- a/pkg/compiler/lib/src/resolution/class_hierarchy.dart
+++ b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
@@ -248,7 +248,7 @@
     return enumType;
   }
 
-  /// Resolves the mixed type for [mixinNode] and checks that the the mixin type
+  /// Resolves the mixed type for [mixinNode] and checks that the mixin type
   /// is a valid, non-blacklisted interface type. The mixin type is returned.
   DartType checkMixinType(TypeAnnotation mixinNode) {
     DartType mixinType = resolveType(mixinNode);
@@ -444,7 +444,6 @@
       previous = current;
       current = currentMixinApplication.mixin;
     }
-    registry.registerMixinUse(mixinApplication, mixin);
     return mixinType;
   }
 
diff --git a/pkg/compiler/lib/src/resolution/constructors.dart b/pkg/compiler/lib/src/resolution/constructors.dart
index 0f9f099..17bd6e0 100644
--- a/pkg/compiler/lib/src/resolution/constructors.dart
+++ b/pkg/compiler/lib/src/resolution/constructors.dart
@@ -249,7 +249,7 @@
   /// reported and an [ErroneousConstructorElement] is returned.
   ConstructorElement verifyThatConstructorMatchesCall(
       Node node,
-      ConstructorElementX lookedupConstructor,
+      ConstructorElement lookedupConstructor,
       CallStructure callStructure,
       String className,
       {String constructorName: '',
diff --git a/pkg/compiler/lib/src/resolution/registry.dart b/pkg/compiler/lib/src/resolution/registry.dart
index 7de89c2..6d56c8e 100644
--- a/pkg/compiler/lib/src/resolution/registry.dart
+++ b/pkg/compiler/lib/src/resolution/registry.dart
@@ -22,7 +22,6 @@
 import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse;
 import '../universe/world_impact.dart' show WorldImpact, WorldImpactBuilder;
 import '../util/enumset.dart' show EnumSet;
-import '../world.dart' show World;
 
 import 'send_structure.dart';
 
@@ -170,10 +169,6 @@
 
   bool get isForResolution => true;
 
-  ResolutionEnqueuer get world => compiler.enqueuer.resolution;
-
-  World get universe => compiler.world;
-
   Backend get backend => compiler.backend;
 
   String toString() => 'ResolutionRegistry for ${mapping.analyzedElement}';
@@ -399,11 +394,6 @@
     return backend.defaultSuperclass(element);
   }
 
-  void registerMixinUse(
-      MixinApplicationElement mixinApplication, ClassElement mixin) {
-    universe.registerMixinUse(mixinApplication, mixin);
-  }
-
   void registerInstantiation(InterfaceType type) {
     worldImpact.registerTypeUse(new TypeUse.instantiation(type));
   }
diff --git a/pkg/compiler/lib/src/serialization/equivalence.dart b/pkg/compiler/lib/src/serialization/equivalence.dart
index be8ff7f..ab8f78e 100644
--- a/pkg/compiler/lib/src/serialization/equivalence.dart
+++ b/pkg/compiler/lib/src/serialization/equivalence.dart
@@ -6,6 +6,7 @@
 
 library dart2js.serialization.equivalence;
 
+import '../closure.dart';
 import '../common.dart';
 import '../common/resolution.dart';
 import '../constants/expressions.dart';
@@ -405,6 +406,14 @@
   }
 
   @override
+  bool visitBoxFieldElement(
+      BoxFieldElement element1, BoxFieldElement element2) {
+    return element1.box.name == element2.box.name &&
+        visit(element1.box.executableContext, element2.box.executableContext) &&
+        visit(element1.variableElement, element2.variableElement);
+  }
+
+  @override
   bool visitConstructorElement(
       ConstructorElement element1, ConstructorElement element2) {
     return checkMembers(element1, element2);
@@ -822,7 +831,11 @@
   TreeElementsEquivalenceVisitor visitor = new TreeElementsEquivalenceVisitor(
       indices1, indices2, elements1, elements2, strategy);
   resolvedAst1.node.accept(visitor);
-  return visitor.success;
+  if (visitor.success) {
+    return strategy.test(elements1, elements2, 'containsTryStatement',
+        elements1.containsTryStatement, elements2.containsTryStatement);
+  }
+  return false;
 }
 
 /// Visitor that checks the equivalence of [TreeElements] data.
diff --git a/pkg/compiler/lib/src/serialization/keys.dart b/pkg/compiler/lib/src/serialization/keys.dart
index de805fe..179b727 100644
--- a/pkg/compiler/lib/src/serialization/keys.dart
+++ b/pkg/compiler/lib/src/serialization/keys.dart
@@ -22,6 +22,7 @@
   static const Key CONSTANT = const Key('constant');
   static const Key CONSTANTS = const Key('constants');
   static const Key CONSTRUCTOR = const Key('constructor');
+  static const Key CONTAINS_TRY = const Key('containsTryStatement');
   static const Key DATA = const Key('data');
   static const Key DEFAULT = const Key('default');
   static const Key DEFAULTS = const Key('defaults');
diff --git a/pkg/compiler/lib/src/serialization/modelz.dart b/pkg/compiler/lib/src/serialization/modelz.dart
index 7772956..3c10292 100644
--- a/pkg/compiler/lib/src/serialization/modelz.dart
+++ b/pkg/compiler/lib/src/serialization/modelz.dart
@@ -82,13 +82,13 @@
   bool get isClosure => false;
 
   @override
-  bool get isConst => _unsupported('isConst');
+  bool get isConst => false;
 
   @override
   bool get isDeferredLoaderGetter => false;
 
   @override
-  bool get isFinal => _unsupported('isFinal');
+  bool get isFinal => false;
 
   @override
   bool get isInstanceMember => false;
@@ -249,20 +249,32 @@
   TreeElements get treeElements => _unsupported('treeElements');
 }
 
-abstract class AstElementMixin implements AstElement, ElementZ {
+abstract class AstElementMixinZ implements AstElement, ElementZ {
+  ResolvedAst _resolvedAst;
+
   // TODO(johnniwinther): This is needed for the token invariant assertion. Find
   // another way to bypass the test for modelz.
   @override
   bool get hasNode => false;
 
   @override
-  bool get hasResolvedAst => _unsupported('hasResolvedAst');
+  bool get hasResolvedAst => _resolvedAst != null;
 
   @override
   get node => _unsupported('node');
 
   @override
-  ResolvedAst get resolvedAst => _unsupported('resolvedAst');
+  ResolvedAst get resolvedAst {
+    assert(invariant(this, _resolvedAst != null,
+        message: "ResolvedAst has not been set for $this."));
+    return _resolvedAst;
+  }
+
+  void set resolvedAst(ResolvedAst value) {
+    assert(invariant(this, _resolvedAst == null,
+        message: "ResolvedAst has already been set for $this."));
+    _resolvedAst = value;
+  }
 }
 
 abstract class ContainerMixin
@@ -801,7 +813,7 @@
 class ClassElementZ extends DeserializedElementZ
     with
         AnalyzableElementMixin,
-        AstElementMixin,
+        AstElementMixinZ,
         ClassElementCommon,
         class_members.ClassMemberMixin,
         ContainerMixin,
@@ -922,7 +934,7 @@
         class_members.ClassMemberMixin,
         TypeDeclarationMixin<InterfaceType>,
         AnalyzableElementMixin,
-        AstElementMixin,
+        AstElementMixinZ,
         MixinApplicationElementCommon,
         MixinApplicationElementMixin {
   final String name;
@@ -943,6 +955,9 @@
   CompilationUnitElement get compilationUnit => _subclass.compilationUnit;
 
   @override
+  bool get isTopLevel => true;
+
+  @override
   bool get isUnnamedMixinApplication => true;
 
   Link<ConstructorElement> get constructors {
@@ -1040,7 +1055,7 @@
 abstract class ConstructorElementZ extends DeserializedElementZ
     with
         AnalyzableElementMixin,
-        AstElementMixin,
+        AstElementMixinZ,
         ClassMemberMixin,
         FunctionTypedElementMixin,
         ParametersMixin,
@@ -1221,7 +1236,7 @@
 }
 
 class ForwardingConstructorElementZ extends ElementZ
-    with AnalyzableElementMixin, AstElementMixin
+    with AnalyzableElementMixin, AstElementMixinZ
     implements ConstructorElement {
   final MixinApplicationElement enclosingClass;
   final ConstructorElement definingConstructor;
@@ -1261,7 +1276,9 @@
 
   @override
   FunctionSignature get functionSignature {
-    return _unsupported('functionSignature');
+    // TODO(johnniwinther): Ensure that the function signature (and with it the
+    // function type) substitutes type variables correctly.
+    return definingConstructor.functionSignature;
   }
 
   @override
@@ -1354,7 +1371,7 @@
 abstract class FieldElementZ extends DeserializedElementZ
     with
         AnalyzableElementMixin,
-        AstElementMixin,
+        AstElementMixinZ,
         TypedElementMixin,
         MemberElementMixin
     implements FieldElement {
@@ -1421,7 +1438,7 @@
 abstract class FunctionElementZ extends DeserializedElementZ
     with
         AnalyzableElementMixin,
-        AstElementMixin,
+        AstElementMixinZ,
         ParametersMixin,
         FunctionTypedElementMixin,
         TypedElementMixin,
@@ -1500,7 +1517,7 @@
 class LocalFunctionElementZ extends DeserializedElementZ
     with
         LocalExecutableMixin,
-        AstElementMixin,
+        AstElementMixinZ,
         ParametersMixin,
         FunctionTypedElementMixin,
         TypedElementMixin
@@ -1524,7 +1541,7 @@
 abstract class GetterElementZ extends DeserializedElementZ
     with
         AnalyzableElementMixin,
-        AstElementMixin,
+        AstElementMixinZ,
         FunctionTypedElementMixin,
         ParametersMixin,
         TypedElementMixin,
@@ -1564,7 +1581,7 @@
 abstract class SetterElementZ extends DeserializedElementZ
     with
         AnalyzableElementMixin,
-        AstElementMixin,
+        AstElementMixinZ,
         FunctionTypedElementMixin,
         ParametersMixin,
         TypedElementMixin,
@@ -1656,7 +1673,7 @@
 class TypedefElementZ extends DeserializedElementZ
     with
         AnalyzableElementMixin,
-        AstElementMixin,
+        AstElementMixinZ,
         LibraryMemberMixin,
         ParametersMixin,
         TypeDeclarationMixin<TypedefType>
@@ -1698,7 +1715,7 @@
 }
 
 class TypeVariableElementZ extends DeserializedElementZ
-    with AnalyzableElementMixin, AstElementMixin, TypedElementMixin
+    with AnalyzableElementMixin, AstElementMixinZ, TypedElementMixin
     implements TypeVariableElement {
   TypeDeclarationElement _typeDeclaration;
   TypeVariableType _type;
@@ -1756,7 +1773,7 @@
 }
 
 class SyntheticTypeVariableElementZ extends ElementZ
-    with AnalyzableElementMixin, AstElementMixin
+    with AnalyzableElementMixin, AstElementMixinZ
     implements TypeVariableElement {
   final TypeDeclarationElement typeDeclaration;
   final int index;
@@ -1820,7 +1837,7 @@
 }
 
 abstract class ParameterElementZ extends DeserializedElementZ
-    with AnalyzableElementMixin, AstElementMixin, TypedElementMixin
+    with AnalyzableElementMixin, AstElementMixinZ, TypedElementMixin
     implements ParameterElement {
   FunctionElement _functionDeclaration;
   ConstantExpression _constant;
@@ -1901,6 +1918,9 @@
   }
 
   @override
+  bool get isLocal => true;
+
+  @override
   ElementKind get kind => ElementKind.PARAMETER;
 }
 
@@ -1930,7 +1950,7 @@
 class LocalVariableElementZ extends DeserializedElementZ
     with
         AnalyzableElementMixin,
-        AstElementMixin,
+        AstElementMixinZ,
         LocalExecutableMixin,
         TypedElementMixin
     implements LocalVariableElement {
diff --git a/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart b/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart
index 633b65e..9b4e0d3 100644
--- a/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart
+++ b/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart
@@ -25,6 +25,7 @@
 import 'modelz.dart';
 import 'serialization.dart';
 import 'serialization_util.dart';
+import 'modelz.dart';
 
 /// Visitor that computes a node-index mapping.
 class AstIndexComputer extends Visitor {
@@ -146,11 +147,12 @@
     }
     objectEncoder.setEnum(Key.SUB_KIND, kind);
     root.accept(indexComputer);
+    objectEncoder.setBool(Key.CONTAINS_TRY, elements.containsTryStatement);
     if (resolvedAst.body != null) {
       int index = nodeIndices[resolvedAst.body];
       assert(invariant(element, index != null,
-          message:
-              "No index for body of $element: ${resolvedAst.body} ($nodeIndices)."));
+          message: "No index for body of $element: "
+              "${resolvedAst.body} ($nodeIndices)."));
       objectEncoder.setInt(Key.BODY, index);
     }
     root.accept(this);
@@ -343,18 +345,18 @@
       ObjectDecoder objectDecoder,
       ParsingContext parsing,
       Token getBeginToken(Uri uri, int charOffset),
-      DeserializerPlugin nativeDataDeserializer,
-      Map<Element, ResolvedAst> resolvedAstMap) {
+      DeserializerPlugin nativeDataDeserializer) {
     ResolvedAstKind kind =
         objectDecoder.getEnum(Key.KIND, ResolvedAstKind.values);
     switch (kind) {
       case ResolvedAstKind.PARSED:
         deserializeParsed(element, objectDecoder, parsing, getBeginToken,
-            nativeDataDeserializer, resolvedAstMap);
+            nativeDataDeserializer);
         break;
       case ResolvedAstKind.DEFAULT_CONSTRUCTOR:
       case ResolvedAstKind.FORWARDING_CONSTRUCTOR:
-        resolvedAstMap[element] = new SynthesizedResolvedAst(element, kind);
+        (element as AstElementMixinZ).resolvedAst =
+            new SynthesizedResolvedAst(element, kind);
         break;
     }
   }
@@ -363,12 +365,11 @@
   /// method, or field) and its nested closures. The [ResolvedAst]s are added
   /// to [resolvedAstMap].
   static void deserializeParsed(
-      Element element,
+      AstElementMixinZ element,
       ObjectDecoder objectDecoder,
       ParsingContext parsing,
       Token getBeginToken(Uri uri, int charOffset),
-      DeserializerPlugin nativeDataDeserializer,
-      Map<Element, ResolvedAst> resolvedAstMap) {
+      DeserializerPlugin nativeDataDeserializer) {
     CompilationUnitElement compilationUnit = element.compilationUnit;
     DiagnosticReporter reporter = parsing.reporter;
     Uri uri = objectDecoder.getUri(Key.URI);
@@ -479,7 +480,7 @@
               builder.emptyStatement());
           return constructorNode;
         case AstKind.ENUM_CONSTANT:
-          EnumConstantElement enumConstant = element;
+          EnumConstantElementZ enumConstant = element;
           EnumClassElement enumClass = element.enclosingClass;
           int index = enumConstant.index;
           AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
@@ -528,6 +529,8 @@
     Map<Node, int> nodeIndices = indexComputer.nodeIndices;
     List<Node> nodeList = indexComputer.nodeList;
     root.accept(indexComputer);
+    elements.containsTryStatement = objectDecoder.getBool(Key.CONTAINS_TRY);
+
     Node body;
     int bodyNodeIndex = objectDecoder.getInt(Key.BODY, isOptional: true);
     if (bodyNodeIndex != null) {
@@ -657,13 +660,11 @@
             elements.registerNativeData(node, nativeData);
           }
         }
-        FunctionElement function =
+        LocalFunctionElementZ function =
             objectDecoder.getElement(Key.FUNCTION, isOptional: true);
         if (function != null) {
           FunctionExpression functionExpression = node;
-          assert(invariant(function, !resolvedAstMap.containsKey(function),
-              message: "ResolvedAst has already been computed for $function."));
-          resolvedAstMap[function] = new ParsedResolvedAst(function,
+          function.resolvedAst = new ParsedResolvedAst(function,
               functionExpression, functionExpression.body, elements, uri);
         }
         // TODO(johnniwinther): Remove these when inference doesn't need `.node`
@@ -680,9 +681,7 @@
         }
       }
     }
-    assert(invariant(element, !resolvedAstMap.containsKey(element),
-        message: "ResolvedAst has already been computed for $element."));
-    resolvedAstMap[element] =
+    element.resolvedAst =
         new ParsedResolvedAst(element, root, body, elements, uri);
   }
 }
diff --git a/pkg/compiler/lib/src/serialization/system.dart b/pkg/compiler/lib/src/serialization/system.dart
new file mode 100644
index 0000000..8db5c4b
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/system.dart
@@ -0,0 +1,255 @@
+// Copyright (c) 2016, 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.serialization_system;
+
+import 'dart:async';
+import '../commandline_options.dart';
+import '../common.dart';
+import '../common/backend_api.dart';
+import '../common/names.dart';
+import '../common/resolution.dart';
+import '../compiler.dart';
+import '../elements/elements.dart';
+import '../io/source_file.dart';
+import '../scanner/scanner.dart';
+import '../script.dart';
+import '../serialization/impact_serialization.dart';
+import '../tokens/token.dart';
+import '../universe/call_structure.dart';
+import '../universe/world_impact.dart';
+import '../universe/use.dart';
+import 'json_serializer.dart';
+import 'modelz.dart';
+import 'resolved_ast_serialization.dart';
+import 'serialization.dart';
+import 'task.dart';
+
+class DeserializerSystemImpl extends DeserializerSystem {
+  final Compiler _compiler;
+  final Deserializer _deserializer;
+  final List<LibraryElement> deserializedLibraries = <LibraryElement>[];
+  final ResolutionImpactDeserializer _resolutionImpactDeserializer;
+  final ResolvedAstDeserializerPlugin _resolvedAstDeserializer;
+  final ImpactTransformer _impactTransformer;
+
+  factory DeserializerSystemImpl(Compiler compiler, Deserializer deserializer,
+      ImpactTransformer impactTransformer) {
+    List<DeserializerPlugin> plugins = <DeserializerPlugin>[];
+    DeserializerPlugin backendDeserializer =
+        compiler.backend.serialization.deserializer;
+    deserializer.plugins.add(backendDeserializer);
+    ResolutionImpactDeserializer resolutionImpactDeserializer =
+        new ResolutionImpactDeserializer(backendDeserializer);
+    deserializer.plugins.add(resolutionImpactDeserializer);
+    ResolvedAstDeserializerPlugin resolvedAstDeserializer =
+        new ResolvedAstDeserializerPlugin(
+            compiler.parsingContext, backendDeserializer);
+    deserializer.plugins.add(resolvedAstDeserializer);
+    return new DeserializerSystemImpl._(
+        compiler,
+        deserializer,
+        impactTransformer,
+        resolutionImpactDeserializer,
+        resolvedAstDeserializer);
+  }
+
+  DeserializerSystemImpl._(
+      this._compiler,
+      this._deserializer,
+      this._impactTransformer,
+      this._resolutionImpactDeserializer,
+      this._resolvedAstDeserializer);
+
+  @override
+  Future<LibraryElement> readLibrary(Uri resolvedUri) {
+    LibraryElement library = _deserializer.lookupLibrary(resolvedUri);
+    if (library != null) {
+      deserializedLibraries.add(library);
+      return Future.forEach(library.compilationUnits,
+          (CompilationUnitElement compilationUnit) {
+        ScriptZ script = compilationUnit.script;
+        return _compiler
+            .readScript(script.readableUri)
+            .then((Script newScript) {
+          script.file = newScript.file;
+          _resolvedAstDeserializer.sourceFiles[script.resourceUri] =
+              newScript.file;
+        });
+      }).then((_) => library);
+    }
+    return new Future<LibraryElement>.value(library);
+  }
+
+  // TODO(johnniwinther): Remove the need for this method.
+  @override
+  bool hasResolvedAst(ExecutableElement element) {
+    return getResolvedAst(element) != null;
+  }
+
+  @override
+  ResolvedAst getResolvedAst(ExecutableElement element) {
+    return _resolvedAstDeserializer.getResolvedAst(element);
+  }
+
+  @override
+  bool hasResolutionImpact(Element element) {
+    if (element.isConstructor &&
+        element.enclosingClass.isUnnamedMixinApplication) {
+      return true;
+    }
+    return _resolutionImpactDeserializer.impactMap.containsKey(element);
+  }
+
+  @override
+  ResolutionImpact getResolutionImpact(Element element) {
+    if (element.isConstructor &&
+        element.enclosingClass.isUnnamedMixinApplication) {
+      ClassElement superclass = element.enclosingClass.superclass;
+      ConstructorElement superclassConstructor =
+          superclass.lookupConstructor(element.name);
+      assert(invariant(element, superclassConstructor != null,
+          message: "Superclass constructor '${element.name}' called from "
+              "${element} not found in ${superclass}."));
+      // TODO(johnniwinther): Compute callStructure. Currently not used.
+      CallStructure callStructure;
+      return _resolutionImpactDeserializer.impactMap.putIfAbsent(element, () {
+        return new DeserializedResolutionImpact(staticUses: <StaticUse>[
+          new StaticUse.superConstructorInvoke(
+              superclassConstructor, callStructure)
+        ]);
+      });
+    }
+    return _resolutionImpactDeserializer.impactMap[element];
+  }
+
+  @override
+  WorldImpact computeWorldImpact(Element element) {
+    ResolutionImpact resolutionImpact = getResolutionImpact(element);
+    assert(invariant(element, resolutionImpact != null,
+        message: 'No impact found for $element (${element.library})'));
+    if (element is ExecutableElement) {
+      getResolvedAst(element);
+    }
+    return _impactTransformer.transformResolutionImpact(resolutionImpact);
+  }
+
+  @override
+  bool isDeserialized(Element element) {
+    return deserializedLibraries.contains(element.library);
+  }
+}
+
+const String WORLD_IMPACT_TAG = 'worldImpact';
+
+class ResolutionImpactSerializer extends SerializerPlugin {
+  final Resolution resolution;
+  final SerializerPlugin nativeDataSerializer;
+
+  ResolutionImpactSerializer(this.resolution, this.nativeDataSerializer);
+
+  @override
+  void onElement(Element element, ObjectEncoder createEncoder(String tag)) {
+    if (resolution.hasBeenResolved(element)) {
+      ResolutionImpact impact = resolution.getResolutionImpact(element);
+      ObjectEncoder encoder = createEncoder(WORLD_IMPACT_TAG);
+      new ImpactSerializer(element, encoder, nativeDataSerializer)
+          .serialize(impact);
+    }
+  }
+}
+
+class ResolutionImpactDeserializer extends DeserializerPlugin {
+  Map<Element, ResolutionImpact> impactMap = <Element, ResolutionImpact>{};
+  final DeserializerPlugin nativeDataDeserializer;
+
+  ResolutionImpactDeserializer(this.nativeDataDeserializer);
+
+  @override
+  void onElement(Element element, ObjectDecoder getDecoder(String tag)) {
+    ObjectDecoder decoder = getDecoder(WORLD_IMPACT_TAG);
+    if (decoder != null) {
+      impactMap[element] = ImpactDeserializer.deserializeImpact(
+          element, decoder, nativeDataDeserializer);
+    }
+  }
+}
+
+const String RESOLVED_AST_TAG = 'resolvedAst';
+
+class ResolvedAstSerializerPlugin extends SerializerPlugin {
+  final Resolution resolution;
+  final SerializerPlugin nativeDataSerializer;
+
+  ResolvedAstSerializerPlugin(this.resolution, this.nativeDataSerializer);
+
+  @override
+  void onElement(Element element, ObjectEncoder createEncoder(String tag)) {
+    assert(invariant(element, element.isDeclaration,
+        message: "Element $element must be the declaration"));
+    if (element is MemberElement) {
+      assert(invariant(element, resolution.hasResolvedAst(element),
+          message: "Element $element must have a resolved ast"));
+      ResolvedAst resolvedAst = resolution.getResolvedAst(element);
+      ObjectEncoder objectEncoder = createEncoder(RESOLVED_AST_TAG);
+      new ResolvedAstSerializer(
+              objectEncoder, resolvedAst, nativeDataSerializer)
+          .serialize();
+    }
+  }
+}
+
+class ResolvedAstDeserializerPlugin extends DeserializerPlugin {
+  final ParsingContext parsingContext;
+  final DeserializerPlugin nativeDataDeserializer;
+  final Map<Uri, SourceFile> sourceFiles = <Uri, SourceFile>{};
+
+  Map<MemberElement, ObjectDecoder> _decoderMap =
+      <MemberElement, ObjectDecoder>{};
+  Map<Uri, Token> beginTokenMap = <Uri, Token>{};
+
+  ResolvedAstDeserializerPlugin(
+      this.parsingContext, this.nativeDataDeserializer);
+
+  bool hasResolvedAst(ExecutableElement element) {
+    return getResolvedAst(element) != null;
+  }
+
+  ResolvedAst getResolvedAst(ExecutableElement element) {
+    if (element.hasResolvedAst) {
+      return element.resolvedAst;
+    }
+
+    ObjectDecoder decoder = _decoderMap[element.memberContext];
+    if (decoder != null) {
+      ResolvedAstDeserializer.deserialize(element.memberContext, decoder,
+          parsingContext, findToken, nativeDataDeserializer);
+      _decoderMap.remove(element);
+      assert(invariant(element, element.hasResolvedAst,
+          message: "ResolvedAst not computed for $element."));
+      return element.resolvedAst;
+    }
+    return null;
+  }
+
+  Token findToken(Uri uri, int offset) {
+    Token beginToken = beginTokenMap.putIfAbsent(uri, () {
+      SourceFile sourceFile = sourceFiles[uri];
+      if (sourceFile == null) {
+        throw 'No source file found for $uri in:\n '
+            '${sourceFiles.keys.join('\n ')}';
+      }
+      return new Scanner(sourceFile).tokenize();
+    });
+    return ResolvedAstDeserializer.findTokenInStream(beginToken, offset);
+  }
+
+  @override
+  void onElement(Element element, ObjectDecoder getDecoder(String tag)) {
+    ObjectDecoder decoder = getDecoder(RESOLVED_AST_TAG);
+    if (decoder != null) {
+      _decoderMap[element] = decoder;
+    }
+  }
+}
diff --git a/pkg/compiler/lib/src/serialization/task.dart b/pkg/compiler/lib/src/serialization/task.dart
index 6ca4636..f0cd00e 100644
--- a/pkg/compiler/lib/src/serialization/task.dart
+++ b/pkg/compiler/lib/src/serialization/task.dart
@@ -4,7 +4,7 @@
 
 library dart2js.serialization.task;
 
-import 'dart:async' show Future;
+import 'dart:async' show EventSink, Future;
 import '../common/resolution.dart' show ResolutionImpact, ResolutionWorkItem;
 import '../common/tasks.dart' show CompilerTask;
 import '../common/work.dart' show ItemCompilationContext;
@@ -12,6 +12,9 @@
 import '../elements/elements.dart';
 import '../enqueue.dart' show ResolutionEnqueuer;
 import '../universe/world_impact.dart' show WorldImpact;
+import 'json_serializer.dart';
+import 'serialization.dart';
+import 'system.dart';
 
 /// A deserializer that can load a library element by reading it's information
 /// from a serialized form.
@@ -75,6 +78,48 @@
   ResolvedAst getResolvedAst(ExecutableElement element) {
     return deserializer != null ? deserializer.getResolvedAst(element) : null;
   }
+
+  Serializer createSerializer(Iterable<LibraryElement> libraries) {
+    return measure(() {
+      assert(supportSerialization);
+
+      Serializer serializer = new Serializer();
+      SerializerPlugin backendSerializer =
+          compiler.backend.serialization.serializer;
+      serializer.plugins.add(backendSerializer);
+      serializer.plugins.add(new ResolutionImpactSerializer(
+          compiler.resolution, backendSerializer));
+      serializer.plugins.add(new ResolvedAstSerializerPlugin(
+          compiler.resolution, backendSerializer));
+
+      for (LibraryElement library in libraries) {
+        serializer.serialize(library);
+      }
+      return serializer;
+    });
+  }
+
+  void serializeToSink(
+      EventSink<String> sink, Iterable<LibraryElement> libraries) {
+    measure(() {
+      sink
+        ..add(createSerializer(libraries)
+            .toText(const JsonSerializationEncoder()))
+        ..close();
+    });
+  }
+
+  void deserializeFromText(String serializedData) {
+    measure(() {
+      Deserializer dataDeserializer = new Deserializer.fromText(
+          new DeserializationContext(),
+          serializedData,
+          const JsonSerializationDecoder());
+      dataDeserializer.plugins.add(compiler.backend.serialization.deserializer);
+      deserializer = new DeserializerSystemImpl(
+          compiler, dataDeserializer, compiler.backend.impactTransformer);
+    });
+  }
 }
 
 /// A [ResolutionWorkItem] for a deserialized element.
diff --git a/pkg/compiler/lib/src/source_file_provider.dart b/pkg/compiler/lib/src/source_file_provider.dart
index da15419..57bc9d3 100644
--- a/pkg/compiler/lib/src/source_file_provider.dart
+++ b/pkg/compiler/lib/src/source_file_provider.dart
@@ -238,9 +238,10 @@
 
 typedef void MessageCallback(String message);
 
-class RandomAccessFileOutputProvider {
+class RandomAccessFileOutputProvider implements CompilerOutput {
   final Uri out;
   final Uri sourceMapOut;
+  final Uri resolutionOutput;
   final MessageCallback onInfo;
   final MessageCallback onFailure;
 
@@ -248,7 +249,7 @@
   List<String> allOutputFiles = new List<String>();
 
   RandomAccessFileOutputProvider(this.out, this.sourceMapOut,
-      {this.onInfo, this.onFailure});
+      {this.onInfo, this.onFailure, this.resolutionOutput});
 
   static Uri computePrecompiledUri(Uri out) {
     String extension = 'precompiled.js';
@@ -262,6 +263,10 @@
   }
 
   EventSink<String> call(String name, String extension) {
+    return createEventSink(name, extension);
+  }
+
+  EventSink<String> createEventSink(String name, String extension) {
     Uri uri;
     bool isPrimaryOutput = false;
     // TODO (johnniwinther, sigurdm): Make a better interface for
@@ -278,9 +283,14 @@
             " \"Content-Security-Policy: script-src 'self'\"");
       } else if (extension == 'js.map' || extension == 'dart.map') {
         uri = sourceMapOut;
-      } else if (extension == "info.json") {
+      } else if (extension == 'info.json') {
         String outName = out.path.substring(out.path.lastIndexOf('/') + 1);
         uri = out.resolve('$outName.$extension');
+      } else if (extension == 'data') {
+        if (resolutionOutput == null) {
+          onFailure('Serialization target unspecified.');
+        }
+        uri = resolutionOutput;
       } else {
         onFailure('Unknown extension: $extension');
       }
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 50db1bf..f8c3ad0 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -327,8 +327,8 @@
   void startFunction(AstElement element, ast.Node node) {
     assert(invariant(element, element.isImplementation));
     Compiler compiler = builder.compiler;
-    closureData = compiler.closureToClassMapper.computeClosureToClassMapping(
-        compiler.backend.frontend.getResolvedAst(element.declaration));
+    closureData = compiler.closureToClassMapper
+        .computeClosureToClassMapping(element.resolvedAst);
 
     if (element is FunctionElement) {
       FunctionElement functionElement = element;
@@ -512,7 +512,12 @@
     // it could then have another name than the real parameter. And
     // the other one would not know it is just a copy of the real
     // parameter.
-    if (local is ParameterElement) return builder.parameters[local];
+    if (local is ParameterElement) {
+      assert(invariant(local, builder.parameters.containsKey(local),
+          message: "No local value for parameter $local in "
+              "${builder.parameters}."));
+      return builder.parameters[local];
+    }
 
     return builder.activationVariables.putIfAbsent(local, () {
       JavaScriptBackend backend = builder.backend;
@@ -1378,7 +1383,7 @@
     if (compiler.elementHasCompileTimeError(element)) return false;
 
     FunctionElement function = element;
-    ResolvedAst functionResolvedAst = backend.frontend.getResolvedAst(function);
+    ResolvedAst functionResolvedAst = function.resolvedAst;
     bool insideLoop = loopNesting > 0 || graph.calledInLoop;
 
     // Bail out early if the inlining decision is in the cache and we can't
@@ -1801,14 +1806,15 @@
       }
     });
     if (bodyElement == null) {
-      bodyElement = new ConstructorBodyElementX(constructor);
+      bodyElement =
+          new ConstructorBodyElementX(constructorResolvedAst, constructor);
       classElement.addBackendMember(bodyElement);
 
       if (constructor.isPatch) {
         // Create origin body element for patched constructors.
         ConstructorBodyElementX patch = bodyElement;
-        ConstructorBodyElementX origin =
-            new ConstructorBodyElementX(constructor.origin);
+        ConstructorBodyElementX origin = new ConstructorBodyElementX(
+            constructorResolvedAst, constructor.origin);
         origin.applyPatch(patch);
         classElement.origin.addBackendMember(bodyElement.origin);
       }
@@ -1841,8 +1847,7 @@
   void setupStateForInlining(
       FunctionElement function, List<HInstruction> compiledArguments,
       {InterfaceType instanceType}) {
-    ResolvedAst resolvedAst =
-        compiler.backend.frontend.getResolvedAst(function.declaration);
+    ResolvedAst resolvedAst = function.resolvedAst;
     assert(resolvedAst != null);
     localsHandler = new LocalsHandler(this, function, instanceType);
     localsHandler.closureData =
@@ -2018,7 +2023,7 @@
 
       // Build the initializers in the context of the new constructor.
       ResolvedAst oldResolvedAst = resolvedAst;
-      resolvedAst = backend.frontend.getResolvedAst(callee);
+      resolvedAst = callee.resolvedAst;
       ClosureClassMap oldClosureData = localsHandler.closureData;
       ClosureClassMap newClosureData = compiler.closureToClassMapper
           .computeClosureToClassMapping(resolvedAst);
@@ -2059,7 +2064,7 @@
       return localsHandler.readLocal(parameter);
     }
 
-    Element target = constructor.definingConstructor.implementation;
+    ConstructorElement target = constructor.definingConstructor.implementation;
     bool match = !target.isMalformed &&
         CallStructure.addForwardingElementArgumentsToList(
             constructor,
@@ -2078,7 +2083,7 @@
       reporter.internalError(
           constructor, 'forwarding constructor call does not match');
     }
-    inlineSuperOrRedirect(backend.frontend.getResolvedAst(target), arguments,
+    inlineSuperOrRedirect(target.resolvedAst, arguments,
         constructorResolvedAsts, fieldValues, constructor);
   }
 
@@ -2125,12 +2130,8 @@
             compiledArguments =
                 makeStaticArgumentList(callStructure, arguments, target);
           });
-          inlineSuperOrRedirect(
-              backend.frontend.getResolvedAst(target.declaration),
-              compiledArguments,
-              constructorResolvedAsts,
-              fieldValues,
-              constructor);
+          inlineSuperOrRedirect(target.resolvedAst, compiledArguments,
+              constructorResolvedAsts, fieldValues, constructor);
         } else {
           // A field initializer.
           ast.SendSet init = link.head;
@@ -2163,12 +2164,8 @@
             target.implementation,
             null,
             handleConstantForOptionalParameter);
-        inlineSuperOrRedirect(
-            backend.frontend.getResolvedAst(target.declaration),
-            arguments,
-            constructorResolvedAsts,
-            fieldValues,
-            constructor);
+        inlineSuperOrRedirect(target.resolvedAst, arguments,
+            constructorResolvedAsts, fieldValues, constructor);
       }
     }
   }
@@ -2186,7 +2183,7 @@
         (ClassElement enclosingClass, FieldElement member) {
       if (compiler.elementHasCompileTimeError(member)) return;
       reporter.withCurrentElement(member, () {
-        ResolvedAst fieldResolvedAst = backend.frontend.getResolvedAst(member);
+        ResolvedAst fieldResolvedAst = member.resolvedAst;
         ast.Node node = fieldResolvedAst.node;
         ast.Expression initializer = fieldResolvedAst.body;
         if (initializer == null) {
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 8b9ab16..74cd875 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -2205,7 +2205,7 @@
       Element element = work.element;
       if (element is FunctionElement && element.asyncMarker.isYielding) {
         // `return <expr>;` is illegal in a sync* or async* function.
-        // To have the the async-translator working, we avoid introducing
+        // To have the async-translator working, we avoid introducing
         // `return` nodes.
         pushStatement(new js.ExpressionStatement(value)
             .withSourceInformation(sourceInformation));
diff --git a/pkg/compiler/lib/src/string_validator.dart b/pkg/compiler/lib/src/string_validator.dart
index 70a90b9..1965695 100644
--- a/pkg/compiler/lib/src/string_validator.dart
+++ b/pkg/compiler/lib/src/string_validator.dart
@@ -52,7 +52,7 @@
 
       // Check if a multiline string starts with optional whitespace followed by
       // a newline (CR, LF or CR+LF).
-      // We also accept if the these characters are escaped by a backslash.
+      // We also accept if these characters are escaped by a backslash.
       int newLineLength = 1;
       while (true) {
         // Due to string-interpolations we are not guaranteed to see the
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
index bb025f0..a1fe55e 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
@@ -396,7 +396,7 @@
 
 /// An && or || expression. The operator is internally represented as a boolean
 /// [isAnd] to simplify rewriting of logical operators.
-/// Note the the result of && and || is one of the arguments, which might not be
+/// Note the result of && and || is one of the arguments, which might not be
 /// boolean. 'ShortCircuitOperator' might have been a better name.
 class LogicalOperator extends Expression {
   Expression left;
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index f217263..bfa2100 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -460,7 +460,7 @@
           if (isInstantiated(mixinApplication)) {
             uses.add(mixinApplication);
           } else if (mixinApplication.isNamedMixinApplication) {
-            List<MixinApplicationElement> next = _mixinUses[mixinApplication];
+            Set<MixinApplicationElement> next = _mixinUses[mixinApplication];
             if (next != null) {
               next.forEach(addLiveUse);
             }
@@ -511,8 +511,8 @@
 
   final Set<TypedefElement> allTypedefs = new Set<TypedefElement>();
 
-  final Map<ClassElement, List<MixinApplicationElement>> _mixinUses =
-      new Map<ClassElement, List<MixinApplicationElement>>();
+  final Map<ClassElement, Set<MixinApplicationElement>> _mixinUses =
+      new Map<ClassElement, Set<MixinApplicationElement>>();
   Map<ClassElement, List<MixinApplicationElement>> _liveMixinUses;
 
   final Map<ClassElement, Set<ClassElement>> _typesImplementedBySubclasses =
@@ -605,6 +605,15 @@
         ClassSet subtypeSet = _ensureClassSet(type.element);
         subtypeSet.addSubtype(node);
       }
+      if (cls.isMixinApplication) {
+        // TODO(johnniwinther): Store this in the [ClassSet].
+        MixinApplicationElement mixinApplication = cls;
+        if (mixinApplication.mixin != null) {
+          // If [mixinApplication] is malformed [mixin] is `null`.
+          registerMixinUse(mixinApplication, mixinApplication.mixin);
+        }
+      }
+
       return classSet;
     });
   }
@@ -687,8 +696,8 @@
     // TODO(johnniwinther): Add map restricted to live classes.
     // We don't support patch classes as mixin.
     assert(mixin.isDeclaration);
-    List<MixinApplicationElement> users = _mixinUses.putIfAbsent(
-        mixin, () => new List<MixinApplicationElement>());
+    Set<MixinApplicationElement> users =
+        _mixinUses.putIfAbsent(mixin, () => new Set<MixinApplicationElement>());
     users.add(mixinApplication);
   }
 
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index ad030b8..e6794ec 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -104,6 +104,11 @@
   if (dart_target_arch != "") {
     if (dart_target_arch == "arm") {
       defines += [ "TARGET_ARCH_ARM" ]
+      if (target_os == "mac" || target_os == "ios") {
+        defines += [ "TARGET_ABI_IOS" ]
+      } else {
+        defines += [ "TARGET_ABI_EABI" ]
+      }
     } else if (dart_target_arch == "arm64") {
       defines += [ "TARGET_ARCH_ARM64" ]
     } else if (dart_target_arch == "mips") {
diff --git a/runtime/bin/directory.cc b/runtime/bin/directory.cc
index bb3173f..a9b2331 100644
--- a/runtime/bin/directory.cc
+++ b/runtime/bin/directory.cc
@@ -115,28 +115,20 @@
 }
 
 
-void FUNCTION_NAME(Directory_List)(Dart_NativeArguments args) {
-  Dart_Handle path = Dart_GetNativeArgument(args, 0);
-  Dart_Handle recursive = Dart_GetNativeArgument(args, 1);
-  // Create the list to hold the directory listing here, and pass it to the
+void FUNCTION_NAME(Directory_FillWithDirectoryListing)(
+    Dart_NativeArguments args) {
+  // The list that we should fill.
+  Dart_Handle results = Dart_GetNativeArgument(args, 0);
+  Dart_Handle path = Dart_GetNativeArgument(args, 1);
+  Dart_Handle recursive = Dart_GetNativeArgument(args, 2);
+  Dart_Handle follow_links = Dart_GetNativeArgument(args, 3);
+  // Pass the list that should hold the directory listing to the
   // SyncDirectoryListing object, which adds elements to it.
-  Dart_Handle follow_links = Dart_GetNativeArgument(args, 2);
-  // Create the list to hold the directory listing here, and pass it to the
-  // SyncDirectoryListing object, which adds elements to it.
-  Dart_Handle results =
-      Dart_New(DartUtils::GetDartType(DartUtils::kCoreLibURL, "List"),
-               Dart_Null(),
-               0,
-               NULL);
-  if (Dart_IsError(results)) {
-    Dart_PropagateError(results);
-  }
   SyncDirectoryListing sync_listing(results,
                                     DartUtils::GetStringValue(path),
                                     DartUtils::GetBooleanValue(recursive),
                                     DartUtils::GetBooleanValue(follow_links));
   Directory::List(&sync_listing);
-  Dart_SetReturnValue(args, results);
 }
 
 
@@ -407,7 +399,10 @@
   Dart_Handle dir_name_dart = DartUtils::NewString(dir_name);
   Dart_Handle dir =
       Dart_New(directory_type_, Dart_Null(), 1, &dir_name_dart);
-  Dart_Invoke(results_, add_string_, 1, &dir);
+  Dart_Handle result = Dart_Invoke(results_, add_string_, 1, &dir);
+  if (Dart_IsError(result)) {
+    Dart_PropagateError(result);
+  }
   return true;
 }
 
@@ -416,7 +411,10 @@
   Dart_Handle link_name_dart = DartUtils::NewString(link_name);
   Dart_Handle link =
       Dart_New(link_type_, Dart_Null(), 1, &link_name_dart);
-  Dart_Invoke(results_, add_string_, 1, &link);
+  Dart_Handle result = Dart_Invoke(results_, add_string_, 1, &link);
+  if (Dart_IsError(result)) {
+    Dart_PropagateError(result);
+  }
   return true;
 }
 
@@ -425,7 +423,10 @@
   Dart_Handle file_name_dart = DartUtils::NewString(file_name);
   Dart_Handle file =
       Dart_New(file_type_, Dart_Null(), 1, &file_name_dart);
-  Dart_Invoke(results_, add_string_, 1, &file);
+  Dart_Handle result = Dart_Invoke(results_, add_string_, 1, &file);
+  if (Dart_IsError(result)) {
+    Dart_PropagateError(result);
+  }
   return true;
 }
 
diff --git a/runtime/bin/directory_patch.dart b/runtime/bin/directory_patch.dart
index f98a52e..9f4a265 100644
--- a/runtime/bin/directory_patch.dart
+++ b/runtime/bin/directory_patch.dart
@@ -13,8 +13,10 @@
       native "Directory_Delete";
   /* patch */ static _rename(String path, String newPath)
       native "Directory_Rename";
-  /* patch */ static List _list(String path, bool recursive, bool followLinks)
-      native "Directory_List";
+  /* patch */ static void _fillWithDirectoryListing(
+      List<FileSystemEntity> list, String path, bool recursive,
+      bool followLinks)
+      native "Directory_FillWithDirectoryListing";
 }
 
 patch class _AsyncDirectoryListerOps {
diff --git a/runtime/bin/directory_unsupported.cc b/runtime/bin/directory_unsupported.cc
index 1b1abd2..c4398bb 100644
--- a/runtime/bin/directory_unsupported.cc
+++ b/runtime/bin/directory_unsupported.cc
@@ -59,7 +59,8 @@
 }
 
 
-void FUNCTION_NAME(Directory_List)(Dart_NativeArguments args) {
+void FUNCTION_NAME(Directory_FillWithDirectoryListing)(
+    Dart_NativeArguments args) {
   Dart_ThrowException(DartUtils::NewInternalError(
         "Directory is not supported on this platform"));
 }
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index dfd4985..f125bb8 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -126,6 +126,7 @@
       last_error_(NOERROR),
       flags_(0),
       read_thread_id_(Thread::kInvalidThreadId),
+      read_thread_handle_(NULL),
       read_thread_starting_(false),
       read_thread_finished_(false),
       monitor_(new Monitor()) {
@@ -188,8 +189,7 @@
 
 
 void Handle::WaitForReadThreadFinished() {
-  // Join the Reader thread if there is one.
-  ThreadId to_join = Thread::kInvalidThreadId;
+  HANDLE to_join = NULL;
   {
     MonitorLocker ml(monitor_);
     if (read_thread_id_ != Thread::kInvalidThreadId) {
@@ -197,12 +197,16 @@
         ml.Wait();
       }
       read_thread_finished_ = false;
-      to_join = read_thread_id_;
       read_thread_id_ = Thread::kInvalidThreadId;
+      to_join = read_thread_handle_;
+      read_thread_handle_ = NULL;
     }
   }
-  if (to_join != Thread::kInvalidThreadId) {
-    Thread::Join(to_join);
+  if (to_join != NULL) {
+    // Join the read thread.
+    DWORD res = WaitForSingleObject(to_join, INFINITE);
+    CloseHandle(to_join);
+    ASSERT(res == WAIT_OBJECT_0);
   }
 }
 
@@ -250,10 +254,12 @@
   ASSERT(read_thread_starting_);
   ASSERT(read_thread_id_ == Thread::kInvalidThreadId);
   read_thread_id_ = Thread::GetCurrentThreadId();
+  read_thread_handle_ = OpenThread(SYNCHRONIZE, false, read_thread_id_);
   read_thread_starting_ = false;
   ml.Notify();
 }
 
+
 void Handle::NotifyReadThreadFinished() {
   MonitorLocker ml(monitor_);
   ASSERT(!read_thread_finished_);
@@ -750,6 +756,7 @@
   MonitorLocker ml(monitor_);
   write_thread_running_ = true;
   thread_id_ = Thread::GetCurrentThreadId();
+  thread_handle_ = OpenThread(SYNCHRONIZE, false, thread_id_);
   // Notify we have started.
   ml.Notify();
 
@@ -839,7 +846,10 @@
     while (write_thread_exists_) {
       ml.Wait(Monitor::kNoTimeout);
     }
-    Thread::Join(thread_id_);
+    // Join the thread.
+    DWORD res = WaitForSingleObject(thread_handle_, INFINITE);
+    CloseHandle(thread_handle_);
+    ASSERT(res == WAIT_OBJECT_0);
   }
   Handle::DoClose();
 }
@@ -1366,6 +1376,7 @@
 EventHandlerImplementation::EventHandlerImplementation() {
   startup_monitor_ = new Monitor();
   handler_thread_id_ = Thread::kInvalidThreadId;
+  handler_thread_handle_ = NULL;
   completion_port_ =
       CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1);
   if (completion_port_ == NULL) {
@@ -1376,7 +1387,10 @@
 
 
 EventHandlerImplementation::~EventHandlerImplementation() {
-  Thread::Join(handler_thread_id_);
+  // Join the handler thread.
+  DWORD res = WaitForSingleObject(handler_thread_handle_, INFINITE);
+  CloseHandle(handler_thread_handle_);
+  ASSERT(res == WAIT_OBJECT_0);
   delete startup_monitor_;
   CloseHandle(completion_port_);
 }
@@ -1415,6 +1429,8 @@
   {
     MonitorLocker ml(handler_impl->startup_monitor_);
     handler_impl->handler_thread_id_ = Thread::GetCurrentThreadId();
+    handler_impl->handler_thread_handle_ =
+        OpenThread(SYNCHRONIZE, false, handler_impl->handler_thread_id_);
     ml.Notify();
   }
 
diff --git a/runtime/bin/eventhandler_win.h b/runtime/bin/eventhandler_win.h
index edb5c48..9daff93 100644
--- a/runtime/bin/eventhandler_win.h
+++ b/runtime/bin/eventhandler_win.h
@@ -263,6 +263,7 @@
   DWORD last_error_;
 
   ThreadId read_thread_id_;
+  HANDLE read_thread_handle_;
   bool read_thread_starting_;
   bool read_thread_finished_;
 
@@ -298,6 +299,7 @@
   explicit StdHandle(HANDLE handle)
       : FileHandle(handle),
         thread_id_(Thread::kInvalidThreadId),
+        thread_handle_(NULL),
         thread_wrote_(0),
         write_thread_exists_(false),
         write_thread_running_(false) {
@@ -312,6 +314,7 @@
 
  private:
   ThreadId thread_id_;
+  HANDLE thread_handle_;
   intptr_t thread_wrote_;
   bool write_thread_exists_;
   bool write_thread_running_;
@@ -538,6 +541,7 @@
 
   Monitor* startup_monitor_;
   ThreadId handler_thread_id_;
+  HANDLE handler_thread_handle_;
 
   TimeoutQueue timeout_queue_;  // Time for next timeout.
   bool shutdown_;
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 7783422..3e18248 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -154,7 +154,6 @@
     memmove(name_chars, utf8_array, utf8_len);
     name_chars[utf8_len] = '\0';
     const char* value = NULL;
-    printf("Looking for %s\n", name_chars);
     if (environment != NULL) {
       HashMap::Entry* entry = environment->Lookup(
           GetHashmapKeyFromString(name_chars),
diff --git a/runtime/bin/hashmap_test.cc b/runtime/bin/hashmap_test.cc
index b51d1cf..3a74138 100644
--- a/runtime/bin/hashmap_test.cc
+++ b/runtime/bin/hashmap_test.cc
@@ -146,7 +146,7 @@
     EXPECT(!set.Present(x));
     x = x * factor + offset;
 
-    // Verify the the expected values are still there.
+    // Verify the expected values are still there.
     int y = start;
     for (uint32_t j = 0; j < n; j++) {
       if (j <= i) {
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index 4c55b6f..609bbef 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -28,7 +28,7 @@
   V(Directory_CreateTemp, 1)                                                   \
   V(Directory_Delete, 2)                                                       \
   V(Directory_Rename, 2)                                                       \
-  V(Directory_List, 3)                                                         \
+  V(Directory_FillWithDirectoryListing, 4)                                     \
   V(Directory_GetAsyncDirectoryListerPointer, 1)                               \
   V(Directory_SetAsyncDirectoryListerPointer, 2)                               \
   V(EventHandler_SendData, 3)                                                  \
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index ab45b95..5ab2826 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -384,7 +384,7 @@
                         DEFAULT_VM_SERVICE_SERVER_PORT,
                         DEFAULT_VM_SERVICE_SERVER_IP)) {
     Log::PrintErr("unrecognized --enable-vm-service option syntax. "
-                  "Use --enable-vm-service[:<port number>[/<IPv4 address>]]\n");
+                  "Use --enable-vm-service[=<port number>[/<IPv4 address>]]\n");
     return false;
   }
 
@@ -402,10 +402,11 @@
                         DEFAULT_VM_SERVICE_SERVER_PORT,
                         DEFAULT_VM_SERVICE_SERVER_IP)) {
     Log::PrintErr("unrecognized --observe option syntax. "
-                  "Use --observe[:<port number>[/<IPv4 address>]]\n");
+                  "Use --observe[=<port number>[/<IPv4 address>]]\n");
     return false;
   }
 
+  // These options should also be documented in the help message.
   vm_options->AddArgument("--pause-isolates-on-exit");
   vm_options->AddArgument("--pause-isolates-on-unhandled-exceptions");
   vm_options->AddArgument("--warn-on-pause-with-no-debugger");
@@ -855,11 +856,15 @@
 "--packages=<path>\n"
 "  Where to find a package spec file.\n"
 "--observe[=<port>[/<bind-address>]]\n"
-"  The observe flag is used to run a program with a default set of options\n"
-"  for debugging under Observatory. With the default options, Observatory\n"
-"  will be available at http://127.0.0.1:8181/ (default port is 8181,\n"
-"  default bind address is 127.0.0.1).  Isolates will pause at exit and\n"
-"  when they throw unhandled exceptions.\n"
+"  The observe flag is a convenience flag used to run a program with a\n"
+"  set of options which are often useful for debugging under Observatory.\n"
+"  These options are currently:\n"
+"      --enable-vm-service[=<port>[/<bind-address>]]\n"
+"      --pause-isolates-on-exit\n"
+"      --pause-isolates-on-unhandled-exceptions\n"
+"      --warn-on-pause-with-no-debugger\n"
+"  This set is subject to change.\n"
+"  Please see these options (--help --verbose) for further documentation.\n"
 "--version\n"
 "  Print the VM version.\n");
   } else {
@@ -875,11 +880,15 @@
 "--packages=<path>\n"
 "  Where to find a package spec file.\n"
 "--observe[=<port>[/<bind-address>]]\n"
-"  The observe flag is used to run a program with a default set of options\n"
-"  for debugging under Observatory. With the default options, Observatory\n"
-"  will be available at http://127.0.0.1:8181/ (default port is 8181,\n"
-"  default bind address is 127.0.0.1).  Isolates will pause at exit and\n"
-"  when they throw unhandled exceptions.\n"
+"  The observe flag is a convenience flag used to run a program with a\n"
+"  set of options which are often useful for debugging under Observatory.\n"
+"  These options are currently:\n"
+"      --enable-vm-service[=<port>[/<bind-address>]]\n"
+"      --pause-isolates-on-exit\n"
+"      --pause-isolates-on-unhandled-exceptions\n"
+"      --warn-on-pause-with-no-debugger\n"
+"  This set is subject to change.\n"
+"  Please see these options for further documentation.\n"
 "--version\n"
 "  Print the VM version.\n"
 "\n"
@@ -889,7 +898,7 @@
 "--trace-loading\n"
 "  enables tracing of library and script loading\n"
 "\n"
-"--enable-vm-service[:<port>[/<bind-address>]]\n"
+"--enable-vm-service[=<port>[/<bind-address>]]\n"
 "  enables the VM service and listens on specified port for connections\n"
 "  (default port number is 8181, default bind address is 127.0.0.1).\n"
 "\n"
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index 8025ab4..2d3ba73 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -46,6 +46,11 @@
       String host, {InternetAddressType type: InternetAddressType.ANY}) {
     return _NativeSocket.lookup(host, type: type);
   }
+
+  /* patch */ static InternetAddress _cloneWithNewHost(
+      InternetAddress address, String host) {
+    return (address as _InternetAddress)._cloneWithNewHost(host);
+  }
 }
 
 patch class NetworkInterface {
@@ -1250,7 +1255,7 @@
     if (fd != null) _getStdioHandle(native, fd);
     var result = new _RawSocket(native);
     if (fd != null) {
-      var socketType = _StdIOUtils._socketType(result._socket);
+      var socketType = _StdIOUtils._nativeSocketType(result._socket);
       result._isMacOSTerminalInput =
           Platform.isMacOS && socketType == _STDIO_HANDLE_TYPE_TERMINAL;
     }
diff --git a/runtime/bin/stdio_patch.dart b/runtime/bin/stdio_patch.dart
index 7e66009..cf02819 100644
--- a/runtime/bin/stdio_patch.dart
+++ b/runtime/bin/stdio_patch.dart
@@ -29,10 +29,16 @@
     }
   }
 
-  static int _socketType(nativeSocket) {
+  static int _socketType(Socket socket) {
+    if (socket is _Socket) return _nativeSocketType(socket._nativeSocket);
+    return null;
+  }
+
+  static int _nativeSocketType(_NativeSocket nativeSocket) {
     var result = _getSocketType(nativeSocket);
     if (result is OSError) {
-      throw new FileSystemException("Error retrieving socket type", "", result);
+      throw new FileSystemException(
+          "Error retrieving socket type", "", result);
     }
     return result;
   }
diff --git a/runtime/bin/thread.h b/runtime/bin/thread.h
index d95675d..979c77f 100644
--- a/runtime/bin/thread.h
+++ b/runtime/bin/thread.h
@@ -51,7 +51,6 @@
   static void SetThreadLocal(ThreadLocalKey key, uword value);
   static intptr_t GetMaxStackSize();
   static ThreadId GetCurrentThreadId();
-  static bool Join(ThreadId id);
   static intptr_t ThreadIdToIntPtr(ThreadId id);
   static bool Compare(ThreadId a, ThreadId b);
   static void GetThreadCpuUsage(ThreadId thread_id, int64_t* cpu_usage);
diff --git a/runtime/bin/thread_android.cc b/runtime/bin/thread_android.cc
index 4f5c547..ce27ea3 100644
--- a/runtime/bin/thread_android.cc
+++ b/runtime/bin/thread_android.cc
@@ -155,11 +155,6 @@
 }
 
 
-bool Thread::Join(ThreadId id) {
-  return false;
-}
-
-
 intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
   ASSERT(sizeof(id) == sizeof(intptr_t));
   return static_cast<intptr_t>(id);
diff --git a/runtime/bin/thread_linux.cc b/runtime/bin/thread_linux.cc
index 7a2a92a..6ea923e 100644
--- a/runtime/bin/thread_linux.cc
+++ b/runtime/bin/thread_linux.cc
@@ -156,11 +156,6 @@
 }
 
 
-bool Thread::Join(ThreadId id) {
-  return false;
-}
-
-
 intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
   ASSERT(sizeof(id) == sizeof(intptr_t));
   return static_cast<intptr_t>(id);
diff --git a/runtime/bin/thread_macos.cc b/runtime/bin/thread_macos.cc
index 8286835..9477e8ab 100644
--- a/runtime/bin/thread_macos.cc
+++ b/runtime/bin/thread_macos.cc
@@ -148,11 +148,6 @@
 }
 
 
-bool Thread::Join(ThreadId id) {
-  return false;
-}
-
-
 intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
   ASSERT(sizeof(id) == sizeof(intptr_t));
   return reinterpret_cast<intptr_t>(id);
diff --git a/runtime/bin/thread_win.cc b/runtime/bin/thread_win.cc
index db41196..92a9801 100644
--- a/runtime/bin/thread_win.cc
+++ b/runtime/bin/thread_win.cc
@@ -103,27 +103,6 @@
 }
 
 
-bool Thread::Join(ThreadId id) {
-  HANDLE handle = OpenThread(SYNCHRONIZE, false, id);
-
-  // 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) {
-    return false;
-  }
-
-  DWORD res = WaitForSingleObject(handle, INFINITE);
-  CloseHandle(handle);
-  ASSERT(res == WAIT_OBJECT_0);
-  return true;
-}
-
-
 intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
   ASSERT(sizeof(id) <= sizeof(intptr_t));
   return static_cast<intptr_t>(id);
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index c7390e7..bc8c474 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -2658,7 +2658,8 @@
 typedef enum {
   Dart_kImportTag = 0,
   Dart_kSourceTag,
-  Dart_kCanonicalizeUrl
+  Dart_kCanonicalizeUrl,
+  Dart_kScriptTag,
 } Dart_LibraryTag;
 
 /* TODO(turnidge): Document. */
diff --git a/runtime/lib/convert_patch.dart b/runtime/lib/convert_patch.dart
index 3c50f2a..d4acc18a 100644
--- a/runtime/lib/convert_patch.dart
+++ b/runtime/lib/convert_patch.dart
@@ -23,12 +23,14 @@
 
 patch class Utf8Decoder {
   /* patch */
-  Converter<List<int>, dynamic> fuse(Converter<String, dynamic> next) {
+  Converter<List<int>, dynamic/*=T*/> fuse/*<T>*/(
+      Converter<String, dynamic/*=T*/> next) {
     if (next is JsonDecoder) {
-      return new _JsonUtf8Decoder(next._reviver, this._allowMalformed);
+      return new _JsonUtf8Decoder(next._reviver, this._allowMalformed)
+          as dynamic/*=Converter<List<int>, T>*/;
     }
     // TODO(lrn): Recognize a fused decoder where the next step is JsonDecoder.
-    return super.fuse(next);
+    return super.fuse/*<T>*/(next);
   }
 
   // Allow intercepting of UTF-8 decoding when built-in lists are passed.
@@ -39,8 +41,7 @@
   }
 }
 
-class _JsonUtf8Decoder extends
-    ChunkedConverter<List<int>, Object, List<int>, Object> {
+class _JsonUtf8Decoder extends Converter<List<int>, Object> {
   final _Reviver _reviver;
   final bool _allowMalformed;
 
diff --git a/runtime/lib/developer.cc b/runtime/lib/developer.cc
index e47e8ef..a2811ee 100644
--- a/runtime/lib/developer.cc
+++ b/runtime/lib/developer.cc
@@ -13,11 +13,11 @@
 #include "vm/object.h"
 #include "vm/object_store.h"
 #include "vm/service.h"
+#include "vm/service_isolate.h"
 
 namespace dart {
 
 // Native implementations for the dart:developer library.
-
 DEFINE_NATIVE_ENTRY(Developer_debugger, 2) {
   GET_NON_NULL_NATIVE_ARGUMENT(Bool, when, arguments->NativeArgAt(0));
   GET_NATIVE_ARGUMENT(String, msg, arguments->NativeArgAt(1));
@@ -26,7 +26,7 @@
     return when.raw();
   }
   if (when.value()) {
-    debugger->BreakHere(msg);
+    debugger->PauseDeveloper(msg);
   }
   return when.raw();
 }
@@ -92,7 +92,13 @@
   }
   GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Instance, handler, arguments->NativeArgAt(1));
-  isolate->RegisterServiceExtensionHandler(name, handler);
+  // We don't allow service extensions to be registered for the
+  // service isolate.  This can happen, for example, because the
+  // service isolate uses dart:io.  If we decide that we want to start
+  // supporting this in the future, it will take some work.
+  if (!ServiceIsolate::IsServiceIsolateDescendant(isolate)) {
+    isolate->RegisterServiceExtensionHandler(name, handler);
+  }
   return Object::null();
 }
 
diff --git a/runtime/lib/double.dart b/runtime/lib/double.dart
index 06cd324..cbf955d 100644
--- a/runtime/lib/double.dart
+++ b/runtime/lib/double.dart
@@ -63,28 +63,28 @@
   }
   bool _greaterThan(double other) native "Double_greaterThan";
   bool operator >=(num other) {
-    return (this == other) ||  (this > other);
+    return (this == other) || (this > other);
   }
   bool operator <=(num other) {
-    return (this == other) ||  (this < other);
+    return (this == other) || (this < other);
   }
   double _addFromInteger(int other) {
-    return new _Double.fromInteger(other) + this;
+    return new _Double.fromInteger(other)._add(this);
   }
   double _subFromInteger(int other) {
-    return new _Double.fromInteger(other) - this;
+    return new _Double.fromInteger(other)._sub(this);
   }
   double _mulFromInteger(int other) {
-    return new _Double.fromInteger(other) * this;
+    return new _Double.fromInteger(other)._mul(this);
   }
   int _truncDivFromInteger(int other) {
-    return new _Double.fromInteger(other) ~/ this;
+    return new _Double.fromInteger(other)._trunc_div(this);
   }
   double _moduloFromInteger(int other) {
-    return new _Double.fromInteger(other) % this;
+    return new _Double.fromInteger(other)._modulo(this);
   }
   double _remainderFromInteger(int other) {
-    return new _Double.fromInteger(other).remainder(this);
+    return new _Double.fromInteger(other)._remainder(this);
   }
   bool _greaterThanFromInteger(int other)
       native "Double_greaterThanFromInteger";
@@ -117,8 +117,12 @@
   double truncateToDouble() native "Double_truncate";
 
   num clamp(num lowerLimit, num upperLimit) {
-    if (lowerLimit is! num) throw new ArgumentError(lowerLimit);
-    if (upperLimit is! num) throw new ArgumentError(upperLimit);
+    if (lowerLimit is! num) {
+      throw new ArgumentError.value(lowerLimit, "lowerLimit", "not a number");
+    }
+    if (upperLimit is! num) {
+      throw new ArgumentError.value(upperLimit, "upperLimit", "not a number");
+    }
 
     if (lowerLimit.compareTo(upperLimit) > 0) {
       throw new ArgumentError(lowerLimit);
@@ -166,11 +170,12 @@
     // See ECMAScript-262, 15.7.4.5 for details.
 
     if (fractionDigits is! int) {
-      throw new ArgumentError(fractionDigits);
+      throw new ArgumentError.value(
+          fractionDigits, "fractionDigits", "not an integer");
     }
     // Step 2.
     if (fractionDigits < 0 || fractionDigits > 20) {
-      throw new RangeError(fractionDigits);
+      throw new RangeError.range(fractionDigits, 0, 20, "fractionDigits");
     }
 
     // Step 3.
@@ -200,10 +205,11 @@
     // Step 7.
     if (fractionDigits != null) {
       if (fractionDigits is! int) {
-        throw new ArgumentError(fractionDigits);
+        throw new ArgumentError.value(
+            fractionDigits, "fractionDigits", "not an integer");
       }
       if (fractionDigits < 0 || fractionDigits > 20) {
-        throw new RangeError(fractionDigits);
+        throw new RangeError.range(fractionDigits, 0, 20, "fractionDigits");
       }
     }
 
@@ -227,11 +233,12 @@
     // at the fractionDigits. In Dart we are consistent with toStringAsFixed and
     // look at the fractionDigits first.
 
-    if (precision is! int) throw new ArgumentError(precision);
-
+    if (precision is! int) {
+      throw new ArgumentError.value(precision, "precision", "not an integer");
+    }
     // Step 8.
     if (precision < 1 || precision > 21) {
-      throw new RangeError(precision);
+      throw new RangeError.range(precision, 1, 21, "precision");
     }
 
     if (isNaN) return "NaN";
diff --git a/runtime/lib/integers.cc b/runtime/lib/integers.cc
index a1aa3bd..351cbbf 100644
--- a/runtime/lib/integers.cc
+++ b/runtime/lib/integers.cc
@@ -206,14 +206,9 @@
     }
   }
 
-  Scanner scanner(value, Symbols::Empty());
-  const Scanner::GrowableTokenStream& tokens = scanner.GetStream();
   const String* int_string;
   bool is_positive;
-  if (Scanner::IsValidLiteral(tokens,
-                             Token::kINTEGER,
-                             &is_positive,
-                             &int_string)) {
+  if (Scanner::IsValidInteger(value, &is_positive, &int_string)) {
     if (is_positive) {
       return Integer::New(*int_string);
     }
diff --git a/runtime/lib/integers.dart b/runtime/lib/integers.dart
index a103f23..a7722b0 100644
--- a/runtime/lib/integers.dart
+++ b/runtime/lib/integers.dart
@@ -174,22 +174,21 @@
 
   num clamp(num lowerLimit, num upperLimit) {
     if (lowerLimit is! num) {
-      throw new ArgumentError.value(lowerLimit, "lowerLimit");
+      throw new ArgumentError.value(lowerLimit, "lowerLimit", "not a number");
     }
     if (upperLimit is! num) {
-      throw new ArgumentError.value(upperLimit, "upperLimit");
+      throw new ArgumentError.value(upperLimit, "upperLimit", "not a number");
     }
 
     // Special case for integers.
-    if (lowerLimit is int && upperLimit is int &&
-        lowerLimit <= upperLimit) {
+    if (lowerLimit is int && upperLimit is int && lowerLimit <= upperLimit) {
       if (this < lowerLimit) return lowerLimit;
       if (this > upperLimit) return upperLimit;
       return this;
     }
     // Generic case involving doubles, and invalid integer ranges.
     if (lowerLimit.compareTo(upperLimit) > 0) {
-      throw new RangeError.range(upperLimit, lowerLimit, null, "upperLimit");
+      throw new ArgumentError(lowerLimit);
     }
     if (lowerLimit.isNaN) return lowerLimit;
     // Note that we don't need to care for -0.0 for the lower limit.
diff --git a/runtime/lib/timeline.cc b/runtime/lib/timeline.cc
index d8bef45..b5b397d 100644
--- a/runtime/lib/timeline.cc
+++ b/runtime/lib/timeline.cc
@@ -15,6 +15,17 @@
 
 // Native implementations for the dart:developer library.
 
+DEFINE_NATIVE_ENTRY(Timeline_isDartStreamEnabled, 0) {
+  if (!FLAG_support_timeline) {
+    return Bool::False().raw();
+  }
+  if (Timeline::GetDartStream()->enabled()) {
+    return Bool::True().raw();
+  }
+  return Bool::False().raw();
+}
+
+
 DEFINE_NATIVE_ENTRY(Timeline_getIsolateNum, 0) {
   return Integer::New(static_cast<int64_t>(isolate->main_port()), Heap::kOld);
 }
diff --git a/runtime/lib/timeline.dart b/runtime/lib/timeline.dart
index b4ecd44..df43dec 100644
--- a/runtime/lib/timeline.dart
+++ b/runtime/lib/timeline.dart
@@ -4,6 +4,8 @@
 
 import 'dart:_internal';
 
+patch bool _isDartStreamEnabled() native "Timeline_isDartStreamEnabled";
+
 patch int _getTraceClock() native "Timeline_getTraceClock";
 
 patch int _getThreadCpuClock() native "Timeline_getThreadCpuClock";
diff --git a/runtime/observatory/lib/src/app/application.dart b/runtime/observatory/lib/src/app/application.dart
index e2d5126..0ffe385 100644
--- a/runtime/observatory/lib/src/app/application.dart
+++ b/runtime/observatory/lib/src/app/application.dart
@@ -101,6 +101,10 @@
         // Ignore for now.
         break;
 
+      case ServiceEvent.kIsolateReload:
+        notifications.add(new Notification.fromEvent(event));
+        break;
+
       case ServiceEvent.kIsolateExit:
       case ServiceEvent.kResume:
         removePauseEvents(event.isolate);
@@ -230,7 +234,7 @@
   void handleException(e, st) {
     if (e is ServerRpcException) {
       if (e.code == ServerRpcException.kFeatureDisabled) return;
-      if (e.code == ServerRpcException.kVMMustBePaused) return;
+      if (e.code == ServerRpcException.kIsolateMustBePaused) return;
       if (e.code == ServerRpcException.kCannotAddBreakpoint) return;
       Logger.root.fine('Dropping exception: ${e}\n${st}');
     }
diff --git a/runtime/observatory/lib/src/app/view_model.dart b/runtime/observatory/lib/src/app/view_model.dart
index 6562e1f..76033eb 100644
--- a/runtime/observatory/lib/src/app/view_model.dart
+++ b/runtime/observatory/lib/src/app/view_model.dart
@@ -6,7 +6,7 @@
 
 abstract class VirtualTreeRow {
   // Number of ems each subtree is indented.
-  static const subtreeIndent = 1.05;
+  static const subtreeIndent = 2.0;
 
   static const redColor = '#F44336';
   static const blueColor = '#3F51B5';
@@ -46,7 +46,7 @@
     }
   }
 
-  Element makeColorBar() {
+  Element makeColorBar(int depth) {
     var element = new SpanElement();
     element.style.paddingLeft = '2px';
     element.style.paddingRight = '2px';
@@ -78,7 +78,7 @@
     return element;
   }
 
-  Element makeIndenter({colored: true}) {
+  Element makeIndenter(int depth, {colored: true}) {
     SpanElement element = new SpanElement();
     element.style.paddingLeft = '${subtreeIndent * depth}em';
     element.style.flexBasis = '${subtreeIndent * depth}em';
@@ -93,7 +93,9 @@
     return element;
   }
 
-  Element makeText(String text, {String toolTip, String flexBasis: '7em'}) {
+  Element makeText(String text, {String toolTip,
+                                 String flexBasis: '4.5em',
+                                 String cssClass}) {
     SpanElement element = new SpanElement();
     element.text = text;
     if (toolTip != null) {
@@ -102,6 +104,9 @@
     if (flexBasis != null) {
       element.style.flexBasis = flexBasis;
     }
+    if (cssClass != null) {
+      element.classes.add(cssClass);
+    }
     return element;
   }
 
diff --git a/runtime/observatory/lib/src/elements/class_view.dart b/runtime/observatory/lib/src/elements/class_view.dart
index c13cbb3..b1ac3fc 100644
--- a/runtime/observatory/lib/src/elements/class_view.dart
+++ b/runtime/observatory/lib/src/elements/class_view.dart
@@ -20,7 +20,7 @@
   @observable ObservableList mostRetained;
   SampleBufferControlElement sampleBufferControlElement;
   StackTraceTreeConfigElement stackTraceTreeConfigElement;
-  CpuProfileTreeElement cpuProfileTreeElement;
+  CpuProfileVirtualTreeElement cpuProfileTreeElement;
 
   ClassViewElement.created() : super.created();
 
@@ -70,6 +70,7 @@
     assert(stackTraceTreeConfigElement != null);
     stackTraceTreeConfigElement.onTreeConfigChange = onTreeConfigChange;
     stackTraceTreeConfigElement.show = false;
+    stackTraceTreeConfigElement.showFilter = false;
     cpuProfileTreeElement = shadowRoot.querySelector('#cpuProfileTree');
     assert(cpuProfileTreeElement != null);
     cpuProfileTreeElement.profile = sampleBufferControlElement.profile;
@@ -94,7 +95,9 @@
     cpuProfileTreeElement.render();
   }
 
-  onTreeConfigChange(String modeSelector, String directionSelector) {
+  onTreeConfigChange(String modeSelector,
+                     String directionSelector,
+                     String filter) {
     ProfileTreeDirection direction = ProfileTreeDirection.Exclusive;
     if (directionSelector != 'Up') {
       direction = ProfileTreeDirection.Inclusive;
diff --git a/runtime/observatory/lib/src/elements/class_view.html b/runtime/observatory/lib/src/elements/class_view.html
index a40ef165d..086b96b 100644
--- a/runtime/observatory/lib/src/elements/class_view.html
+++ b/runtime/observatory/lib/src/elements/class_view.html
@@ -270,7 +270,7 @@
       <br>
       <div class="flex-row centered">
         <div class="flex-item-90-percent outlined" style="margin: 16px; margin-left: 8px; margin-right: 8px">
-          <cpu-profile-tree id="cpuProfileTree"></cpu-profile-tree>
+          <cpu-profile-virtual-tree id="cpuProfileTree"></cpu-profile-virtual-tree>
         </div>
       </div>
     </div>
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.dart b/runtime/observatory/lib/src/elements/cpu_profile.dart
index e9d9805..305706a 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile.dart
@@ -448,6 +448,11 @@
       onSampleBufferUpdate(profile);
       return profile;
     }
+    profileVM = isolate.vm.profileVM;
+    if (tagSelector == null) {
+      // Set default value.
+      tagSelector = profileVM ? 'UserVM' : 'None';
+    }
     await _changeState(kFetchingState);
     try {
       var response;
@@ -516,7 +521,7 @@
 
   Function onSampleBufferUpdate;
   @observable bool showTagSelector = true;
-
+  @observable bool profileVM = false;
   @observable String sampleCount = '';
   @observable String refreshTime = '';
   @observable String sampleRate = '';
@@ -524,7 +529,7 @@
   @observable String timeSpan = '';
   @observable String fetchTime = '';
   @observable String loadTime = '';
-  @observable String tagSelector = 'UserVM';
+  @observable String tagSelector;
   @observable String state = kFetchingState;
   @observable var exception;
   @observable var stackTrace;
@@ -608,31 +613,66 @@
 class FunctionCallTreeNodeRow extends VirtualTreeRow {
   final CpuProfile profile;
   final FunctionCallTreeNode node;
-  final String selfPercent;
-  final String totalPercent;
-  final String percent;
+  String selfPercent;
+  String totalPercent;
+  String percent;
+
+  static const kHotThreshold = 0.05;  // 5%.
+  static const kMediumThreshold = 0.02;  // 2%.
+
+  double _percent(bool self) {
+    if (self) {
+      return node.profileFunction.normalizedExclusiveTicks;
+    } else {
+      return node.profileFunction.normalizedInclusiveTicks;
+    }
+  }
+
+  bool isHot(bool self) => _percent(self) > kHotThreshold;
+  bool isMedium(bool self) => _percent(self) > kMediumThreshold;
+
+  String rowClass(bool self) {
+    if (isHot(self)) {
+      return 'hotProfile';
+    } else if (isMedium(self)) {
+      return 'mediumProfile';
+    } else {
+      return 'coldProfile';
+    }
+  }
 
   FunctionCallTreeNodeRow(VirtualTree tree,
                           int depth,
                           this.profile,
                           FunctionCallTreeNode node)
       : node = node,
-        selfPercent = Utils.formatPercentNormalized(node.profileFunction.normalizedExclusiveTicks),
-        totalPercent = Utils.formatPercentNormalized(node.profileFunction.normalizedInclusiveTicks),
-        percent = Utils.formatPercentNormalized(node.percentage),
         super(tree, depth) {
+    if ((node.profileFunction.function.kind == FunctionKind.kTag) &&
+        (node.profileFunction.normalizedExclusiveTicks == 0) &&
+        (node.profileFunction.normalizedInclusiveTicks == 0)) {
+    selfPercent = '';
+    totalPercent = '';
+    } else {
+      selfPercent = Utils.formatPercentNormalized(
+          node.profileFunction.normalizedExclusiveTicks);
+      totalPercent = Utils.formatPercentNormalized(
+          node.profileFunction.normalizedInclusiveTicks);
+    }
+    percent = Utils.formatPercentNormalized(node.percentage);
   }
 
   void onRender(DivElement rowDiv) {
     rowDiv.children.add(makeGap(ems:0.1));
     rowDiv.children.add(
-        makeText(totalPercent, toolTip: 'global % on stack'));
+        makeText(totalPercent,
+                 toolTip: 'global % on stack'));
     rowDiv.children.add(makeGap());
     rowDiv.children.add(
-        makeText(selfPercent, toolTip: 'global % executing'));
+        makeText(selfPercent,
+                 toolTip: 'global % executing'));
     rowDiv.children.add(makeGap());
-    rowDiv.children.add(makeIndenter(colored: false));
-    rowDiv.children.add(makeColorBar());
+    rowDiv.children.add(makeIndenter(depth, colored: false));
+    rowDiv.children.add(makeColorBar(depth));
     rowDiv.children.add(makeGap(ems: 1.0));
     rowDiv.children.add(makeExpander());
     rowDiv.children.add(
@@ -661,31 +701,66 @@
 class CodeCallTreeNodeRow extends VirtualTreeRow {
   final CpuProfile profile;
   final CodeCallTreeNode node;
-  final String selfPercent;
-  final String totalPercent;
-  final String percent;
+  String selfPercent;
+  String totalPercent;
+  String percent;
+
+  static const kHotThreshold = 0.05;  // 5%.
+  static const kMediumThreshold = 0.02;  // 2%.
+
+  double _percent(bool self) {
+    if (self) {
+      return node.profileCode.normalizedExclusiveTicks;
+    } else {
+      return node.profileCode.normalizedInclusiveTicks;
+    }
+  }
+
+  bool isHot(bool self) => _percent(self) > kHotThreshold;
+  bool isMedium(bool self) => _percent(self) > kMediumThreshold;
+
+  String rowClass(bool self) {
+    if (isHot(self)) {
+      return 'hotProfile';
+    } else if (isMedium(self)) {
+      return 'mediumProfile';
+    } else {
+      return 'coldProfile';
+    }
+  }
 
   CodeCallTreeNodeRow(VirtualTree tree,
                       int depth,
                       this.profile,
                       CodeCallTreeNode node)
       : node = node,
-        selfPercent = Utils.formatPercentNormalized(node.profileCode.normalizedExclusiveTicks),
-        totalPercent = Utils.formatPercentNormalized(node.profileCode.normalizedInclusiveTicks),
-        percent = Utils.formatPercentNormalized(node.percentage),
         super(tree, depth) {
+    if ((node.profileCode.code.kind == CodeKind.Tag) &&
+        (node.profileCode.normalizedExclusiveTicks == 0) &&
+        (node.profileCode.normalizedInclusiveTicks == 0)) {
+      selfPercent = '';
+      totalPercent = '';
+    } else {
+      selfPercent = Utils.formatPercentNormalized(
+          node.profileCode.normalizedExclusiveTicks);
+      totalPercent = Utils.formatPercentNormalized(
+          node.profileCode.normalizedInclusiveTicks);
+    }
+    percent = Utils.formatPercentNormalized(node.percentage);
   }
 
   void onRender(DivElement rowDiv) {
     rowDiv.children.add(makeGap(ems:0.1));
     rowDiv.children.add(
-        makeText(totalPercent, toolTip: 'global % on stack'));
+        makeText(totalPercent,
+                 toolTip: 'global % on stack'));
     rowDiv.children.add(makeGap());
     rowDiv.children.add(
-        makeText(selfPercent, toolTip: 'global % executing'));
+        makeText(selfPercent,
+                 toolTip: 'global % executing'));
     rowDiv.children.add(makeGap());
-    rowDiv.children.add(makeIndenter(colored: false));
-    rowDiv.children.add(makeColorBar());
+    rowDiv.children.add(makeIndenter(depth, colored: false));
+    rowDiv.children.add(makeColorBar(depth));
     rowDiv.children.add(makeGap(ems: 1.0));
     rowDiv.children.add(makeExpander());
     rowDiv.children.add(
@@ -1283,7 +1358,7 @@
   ///
   TableTree functionTree;
   _updateFunctionTreeView() {
-    cpuProfileTreeElement.functionFilter = (FunctionCallTreeNode node) {
+    cpuProfileTreeElement.filter = (FunctionCallTreeNode node) {
       return node.profileFunction.function == focusedFunction;
     };
     cpuProfileTreeElement.render();
@@ -1304,7 +1379,7 @@
   CpuProfile get profile => sampleBufferControlElement.profile;
   SampleBufferControlElement sampleBufferControlElement;
   StackTraceTreeConfigElement stackTraceTreeConfigElement;
-  CpuProfileTreeElement cpuProfileTreeElement;
+  CpuProfileVirtualTreeElement cpuProfileTreeElement;
 }
 
 enum ProfileTreeDirection {
@@ -1344,9 +1419,11 @@
   }
 
   showChanged(oldValue) {
-    var treeTable = shadowRoot.querySelector('#treeTable');
-    assert(treeTable != null);
-    treeTable.style.display = show ? 'table' : 'none';
+    if (show) {
+      virtualTree?.root?.style?.display = 'block';
+    } else {
+      virtualTree?.root?.style?.display = 'none';
+    }
   }
 
   void _updateView() {
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.html b/runtime/observatory/lib/src/elements/cpu_profile.html
index b5f2432..50db2db 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.html
+++ b/runtime/observatory/lib/src/elements/cpu_profile.html
@@ -91,13 +91,21 @@
             <div class="memberItem">
               <div class="memberName">Tag Order</div>
               <div class="memberValue">
-                <select value="{{tagSelector}}">
-                  <option value="UserVM">User &gt; VM</option>
-                  <option value="UserOnly">User</option>
-                  <option value="VMUser">VM &gt; User</option>
-                  <option value="VMOnly">VM</option>
-                  <option value="None">None</option>
-                </select>
+                <template if="{{ profileVM }}">
+                  <select value="{{tagSelector}}">
+                    <option value="UserVM">User &gt; VM</option>
+                    <option value="UserOnly">User</option>
+                    <option value="VMUser">VM &gt; User</option>
+                    <option value="VMOnly">VM</option>
+                    <option value="None">None</option>
+                  </select>
+                </template>
+                <template if="{{ !profileVM }}">
+                  <select value="{{tagSelector}}">
+                    <option value="UserOnly">User</option>
+                    <option value="None">None</option>
+                  </select>
+                </template>
               </div>
             </div>
           </template>
@@ -254,6 +262,15 @@
       height: 50%;
       width: 100%;
     }
+    .coldProfile {
+      background-color: #aea;
+    }
+    .mediumProfile {
+      background-color: #fe9;
+    }
+    .hotProfile {
+      background-color: #faa;
+    }
     </style>
     <div id="tree" class="full"></div>
   </template>
@@ -468,7 +485,7 @@
     <br>
     <div class="flex-row centered">
       <div class="flex-item-90-percent outlined" style="margin: 16px; margin-left: 8px; margin-right: 8px">
-        <cpu-profile-tree id="cpuProfileTree"></cpu-profile-tree>
+        <cpu-profile-virtual-tree id="cpuProfileTree"></cpu-profile-virtual-tree>
       </div>
     </div>
   </template>
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index 81541ef..61a8989 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -902,6 +902,7 @@
   IsolateCommand(Debugger debugger) : super(debugger, 'isolate', [
     new IsolateListCommand(debugger),
     new IsolateNameCommand(debugger),
+    new IsolateReloadCommand(debugger),
   ]) {
     alias = 'i';
   }
@@ -962,10 +963,10 @@
     }
     return new Future.value(result);
   }
-  String helpShort = 'Switch the current isolate';
+  String helpShort = 'Switch, list, rename, or reload isolates';
 
   String helpLong =
-      'Switch, list, or rename isolates.\n'
+      'Switch the current isolate.\n'
       '\n'
       'Syntax: isolate <number>\n'
       '        isolate <name>\n';
@@ -1042,14 +1043,36 @@
     return debugger.isolate.setName(args[0]);
   }
 
-  String helpShort = 'Rename an isolate';
+  String helpShort = 'Rename the current isolate';
 
   String helpLong =
-      'Rename an isolate.\n'
+      'Rename the current isolate.\n'
       '\n'
       'Syntax: isolate name <name>\n';
 }
 
+class IsolateReloadCommand extends DebuggerCommand {
+  IsolateReloadCommand(Debugger debugger) : super(debugger, 'reload', []);
+
+  Future run(List<String> args) async {
+    if (debugger.isolate == null) {
+      debugger.console.print('There is no current vm');
+      return;
+    }
+
+    await debugger.isolate.reloadSources();
+
+    debugger.console.print('Isolate reloading....');
+  }
+
+  String helpShort = 'Reload the sources for the current isolate.';
+
+  String helpLong =
+      'Reload the sources for the current isolate.\n'
+      '\n'
+      'Syntax: reload\n';
+}
+
 class InfoCommand extends DebuggerCommand {
   InfoCommand(Debugger debugger) : super(debugger, 'info', [
       new InfoBreakpointsCommand(debugger),
@@ -1650,6 +1673,15 @@
         console.print("Isolate ${iso.number} renamed to '${iso.name}'");
         break;
 
+      case ServiceEvent.kIsolateReload:
+        var reloadError = event.reloadError;
+        if (reloadError != null) {
+          console.print('Isolate reload failed: ${event.reloadError}');
+        } else {
+          console.print('Isolate reloaded.');
+        }
+        break;
+
       case ServiceEvent.kPauseStart:
       case ServiceEvent.kPauseExit:
       case ServiceEvent.kPauseBreakpoint:
diff --git a/runtime/observatory/lib/src/elements/instance_ref.dart b/runtime/observatory/lib/src/elements/instance_ref.dart
index 86727ae..cbf5eae 100644
--- a/runtime/observatory/lib/src/elements/instance_ref.dart
+++ b/runtime/observatory/lib/src/elements/instance_ref.dart
@@ -4,6 +4,7 @@
 
 library instance_ref_element;
 
+import 'dart:async';
 import 'package:polymer/polymer.dart';
 import 'package:observatory/service.dart';
 import 'service_ref.dart';
@@ -58,4 +59,15 @@
   String makeExpandKey(String key) {
     return '${expandKey}/${key}';
   }
+
+  Future showMore() async {
+    Instance instance = ref;
+    if (instance.isList) {
+      await instance.reload(count: instance.elements.length * 2);
+    } else if (instance.isMap) {
+      await instance.reload(count: instance.associations.length * 2);
+    } else if (instance.isTypedData) {
+      await instance.reload(count: instance.typedElements.length * 2);
+    }
+  }
 }
diff --git a/runtime/observatory/lib/src/elements/instance_ref.html b/runtime/observatory/lib/src/elements/instance_ref.html
index 385727b..311732b 100644
--- a/runtime/observatory/lib/src/elements/instance_ref.html
+++ b/runtime/observatory/lib/src/elements/instance_ref.html
@@ -88,7 +88,11 @@
               </any-service-ref><br>
             </template>
             <template if="{{ ref.length != ref.elements.length }}">
-              <div><em>{{ ref.length - ref.elements.length }} omitted elements</em></div>
+              <div>
+                <action-link callback="{{ showMore }}"
+                             label="show next {{ref.elements.length}}">
+                </action-link>
+              </div>
             </template>
           </div>
         </curly-block>
@@ -107,7 +111,9 @@
               </any-service-ref><br>
             </template>
             <template if="{{ ref.length != ref.associations.length }}">
-              <div><em>{{ ref.length - ref.associations.length }} omitted associations</em></div>
+              <action-link callback="{{ showMore }}"
+                           label="show next {{ref.associations.length}}">
+              </action-link>
             </template>
           </div>
         </curly-block>
@@ -122,7 +128,9 @@
               {{ ref.typedElements[index].toString() }}<br>
             </template>
             <template if="{{ ref.length != ref.typedElements.length }}">
-              <div><em>{{ ref.length - ref.typedElements.length }} omitted elements</em></div>
+              <action-link callback="{{ showMore }}"
+                           label="show next {{ref.typedElements.length}}">
+              </action-link>
             </template>
           </div>
         </curly-block>
diff --git a/runtime/observatory/lib/src/elements/isolate_view.dart b/runtime/observatory/lib/src/elements/isolate_view.dart
index 40738a1..c45acfa 100644
--- a/runtime/observatory/lib/src/elements/isolate_view.dart
+++ b/runtime/observatory/lib/src/elements/isolate_view.dart
@@ -33,4 +33,8 @@
       await isolate.topFrame.function.load();
     }
   }
+
+  Future reloadSources() {
+    return isolate.reloadSources();
+  }
 }
diff --git a/runtime/observatory/lib/src/elements/isolate_view.html b/runtime/observatory/lib/src/elements/isolate_view.html
index a2fe66d..69c30ed 100644
--- a/runtime/observatory/lib/src/elements/isolate_view.html
+++ b/runtime/observatory/lib/src/elements/isolate_view.html
@@ -94,7 +94,16 @@
               <div class="memberName">service protocol extensions</div>
               <div class="memberValue">{{ isolate.extensionRPCs }}</div>
             </div>
+
+            <div class="memberItem">
+              <div class="memberName">
+                <action-link callback="{{ reloadSources }}"
+                             label="reload sources">
+                </action-link>
+              </div>
+            </div>
           </div>
+
         </div>
       </div>
     </div>
diff --git a/runtime/observatory/lib/src/elements/nav_bar.html b/runtime/observatory/lib/src/elements/nav_bar.html
index 983f8af..c97b1d1 100644
--- a/runtime/observatory/lib/src/elements/nav_bar.html
+++ b/runtime/observatory/lib/src/elements/nav_bar.html
@@ -298,6 +298,10 @@
         animation: fadein 1s;
       }
 
+      .wide-item {
+        width: 50vw;
+      }
+
       @keyframes fadein {
         from { opacity: 0; }
         to   { opacity: 1; }
@@ -328,6 +332,9 @@
       a.boxclose:hover {
         background: rgba(255,255,255,0.5);
       }
+      .error {
+        white-space: pre;
+      }
     </style>
     <template if="{{ event != null }}">
       <template if="{{ notifyOnPause && event.isPauseEvent }}">
@@ -372,6 +379,21 @@
           <a class="boxclose" on-click="{{ closeItem }}">&times;</a>
         </div>
       </template>
+      <template if="{{ event.kind == 'IsolateReload' }}">
+        <div class="wide-item item">
+          Isolate reload
+          <template if="{{ event.reloadError != null }}">
+            failed:
+            <br>
+            <br>
+            <div class="indent error">{{ event.reloadError.message.toString() }}</div><br>
+          </template>
+          <template if="{{ event.reloadError == null }}">
+            succeeded
+          </template>
+          <a class="boxclose" on-click="{{ closeItem }}">&times;</a>
+        </div>
+      </template>
     </template>
   </template>
 </polymer-element>
diff --git a/runtime/observatory/lib/src/elements/script_view.html b/runtime/observatory/lib/src/elements/script_view.html
index c65fa49..e5aec18 100644
--- a/runtime/observatory/lib/src/elements/script_view.html
+++ b/runtime/observatory/lib/src/elements/script_view.html
@@ -21,6 +21,13 @@
     <object-common object="{{ script }}"></object-common>
     <br>
 
+    <div class="memberList">
+      <div class="memberItem">
+        <div class="memberName">loaded at</div>
+        <div class="memberValue">{{ script.loadTime.toString() }}</div>
+      </div>
+    </div>
+
     <hr>
     <script-inset id="scriptInset" script="{{ script }}"
                   currentPos="{{ app.locationManager.internalArguments['pos'] | parseInt }}">
diff --git a/runtime/observatory/lib/src/elements/timeline_page.dart b/runtime/observatory/lib/src/elements/timeline_page.dart
index cc66f9a..28f3046 100644
--- a/runtime/observatory/lib/src/elements/timeline_page.dart
+++ b/runtime/observatory/lib/src/elements/timeline_page.dart
@@ -15,15 +15,14 @@
 
 @CustomTag('timeline-page')
 class TimelinePageElement extends ObservatoryElement {
-  TimelinePageElement.created() : super.created();
+  TimelinePageElement.created() : super.created() {
+  }
 
   attached() {
     super.attached();
     _resizeSubscription = window.onResize.listen((_) => _updateSize());
     _updateSize();
-    // Click refresh button.
-    NavRefreshElement refreshButton = $['refresh'];
-    refreshButton.buttonClick(null, null, null);
+    _setupInitialState();
   }
 
   detached() {
@@ -50,6 +49,131 @@
     return null;
   }
 
+  void _processFlags(ServiceMap response) {
+    // Grab the recorder name.
+    recorderName = response['recorderName'];
+    // Update the set of available streams.
+    _availableStreams.clear();
+    response['availableStreams'].forEach(
+        (String streamName) => _availableStreams.add(streamName));
+    // Update the set of recorded streams.
+    _recordedStreams.clear();
+    response['recordedStreams'].forEach(
+        (String streamName) => _recordedStreams.add(streamName));
+  }
+
+  Future _applyStreamChanges() {
+    return app.vm.invokeRpc('_setVMTimelineFlags', {
+      'recordedStreams': '[${_recordedStreams.join(', ')}]',
+    });
+  }
+
+  HtmlElement _makeStreamToggle(String streamName) {
+    LabelElement label = new LabelElement();
+    label.style.paddingLeft = '8px';
+    SpanElement span = new SpanElement();
+    span.text = streamName;
+    InputElement checkbox = new InputElement();
+    checkbox.onChange.listen((_) {
+      if (checkbox.checked) {
+        _recordedStreams.add(streamName);
+      } else {
+        _recordedStreams.remove(streamName);
+      }
+      _applyStreamChanges();
+      _updateRecorderUI();
+    });
+    checkbox.type = 'checkbox';
+    checkbox.checked = _recordedStreams.contains(streamName);
+    label.children.add(checkbox);
+    label.children.add(span);
+    return label;
+  }
+
+  void _refreshRecorderUI() {
+    DivElement e = $['streamList'];
+    e.children.clear();
+
+    for (String streamName in _availableStreams) {
+      e.children.add(_makeStreamToggle(streamName));
+    }
+
+    streamPresetSelector = streamPresetFromRecordedStreams();
+  }
+
+  // Dart developers care about the following streams:
+  List<String> _dartPreset =
+      ['GC', 'Compiler', 'Dart'];
+
+  // VM developers care about the following streams:
+  List<String> _vmPreset =
+      ['GC', 'Compiler', 'Dart', 'Debugger', 'Embedder', 'Isolate', 'VM'];
+
+  String streamPresetFromRecordedStreams() {
+    if (_availableStreams.length == 0) {
+      return 'None';
+    }
+    if (_recordedStreams.length == 0) {
+      return 'None';
+    }
+    if (_recordedStreams.length == _availableStreams.length) {
+      return 'All';
+    }
+    if ((_vmPreset.length == _recordedStreams.length) &&
+        _recordedStreams.containsAll(_vmPreset)) {
+      return 'VM';
+    }
+    if ((_dartPreset.length == _recordedStreams.length) &&
+        _recordedStreams.containsAll(_dartPreset)) {
+      return 'Dart';
+    }
+    return 'Custom';
+  }
+
+  void _applyPreset() {
+    switch (streamPresetSelector) {
+      case 'None':
+        _recordedStreams.clear();
+        break;
+      case 'All':
+        _recordedStreams.clear();
+        _recordedStreams.addAll(_availableStreams);
+        break;
+      case 'VM':
+        _recordedStreams.clear();
+        _recordedStreams.addAll(_vmPreset);
+        break;
+      case 'Dart':
+        _recordedStreams.clear();
+        _recordedStreams.addAll(_dartPreset);
+        break;
+      case 'Custom':
+        return;
+    }
+    _applyStreamChanges();
+    _updateRecorderUI();
+  }
+
+  Future _updateRecorderUI() async {
+    // Grab the current timeline flags.
+    ServiceMap response = await app.vm.invokeRpc('_getVMTimelineFlags', {});
+    assert(response['type'] == 'TimelineFlags');
+    // Process them so we know available streams.
+    _processFlags(response);
+    // Refresh the UI.
+    _refreshRecorderUI();
+  }
+
+  Future _setupInitialState() async {
+    await _updateRecorderUI();
+    SelectElement e = $['selectPreset'];
+    e.onChange.listen((_) {
+      _applyPreset();
+    });
+    // Finally, trigger a reload so we start with the latest timeline.
+    await refresh();
+  }
+
   Future refresh() async {
     await app.vm.reload();
     await app.vm.reloadIsolates();
@@ -61,18 +185,6 @@
     return postMessage('clear');
   }
 
-  Future recordOn() async {
-    return app.vm.invokeRpc('_setVMTimelineFlags', {
-      'recordedStreams': ['all'],
-    });
-  }
-
-  Future recordOff() async {
-    return app.vm.invokeRpc('_setVMTimelineFlags', {
-      'recordedStreams': [],
-    });
-  }
-
   Future saveTimeline() async {
     return postMessage('save');
   }
@@ -93,4 +205,8 @@
 
 
   StreamSubscription _resizeSubscription;
+  @observable String recorderName;
+  @observable String streamPresetSelector = 'None';
+  final Set<String> _availableStreams = new Set<String>();
+  final Set<String> _recordedStreams = new Set<String>();
 }
diff --git a/runtime/observatory/lib/src/elements/timeline_page.html b/runtime/observatory/lib/src/elements/timeline_page.html
index d142088..433c242 100644
--- a/runtime/observatory/lib/src/elements/timeline_page.html
+++ b/runtime/observatory/lib/src/elements/timeline_page.html
@@ -5,19 +5,41 @@
 <polymer-element name="timeline-page" extends="observatory-element">
   <template>
     <link rel="stylesheet" href="css/shared.css">
-    <style>
-    </style>
     <nav-bar>
       <top-nav-menu></top-nav-menu>
       <vm-nav-menu vm="{{ app.vm }}"></vm-nav-menu>
       <nav-menu link="{{ makeLink('/timeline') }}" anchor="timeline" last="{{ true }}"></nav-menu>
-      <nav-refresh id="refresh" callback="{{ refresh }}"></nav-refresh>
+      <nav-refresh id="refresh" callback="{{ refresh }}" label="Refresh"></nav-refresh>
       <nav-refresh callback="{{ clear }}" label="Clear"></nav-refresh>
-      <nav-refresh callback="{{ recordOn }}" label="Start recording"></nav-refresh>
-      <nav-refresh callback="{{ recordOff }}" label="Stop recording"></nav-refresh>
       <nav-refresh callback="{{ saveTimeline }}" label="Save"></nav-refresh>
       <nav-refresh callback="{{ loadTimeline }}" label="Load"></nav-refresh>
     </nav-bar>
+    <div id="control" class="content-centered-big">
+      <h2>Timeline settings</h2>
+      <div class="memberList">
+        <div class="memberItem">
+          <div class="memberName">Recorder:</div>
+          <div class="memberValue">{{ recorderName }}</div>
+        </div>
+        <div class="memberItem">
+          <div class="memberName">Recorded Streams Profile:</div>
+          <div class="memberValue">
+            <select id="selectPreset" value="{{ streamPresetSelector }}">
+              <option value="None">None</option>
+              <option value="Dart">Dart Developer</option>
+              <option value="VM">VM Developer</option>
+              <option value="All">All</option>
+              <option value="Custom">Custom</option>
+            </select>
+          </div>
+        </div>
+        <div class="memberItem">
+          <div class="memberName">Recorded Streams:</div>
+          <div id="streamList" class="memberValue"></div>
+        </div>
+      </div>
+      <br>
+    </div>
     <iframe id="root" frameborder="0" src="../../../../timeline.html">
     </iframe>
   </template>
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 0797007..b0be812 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -37,11 +37,12 @@
   static const kInvalidParams  = -32602;
   static const kInternalError  = -32603;
   static const kFeatureDisabled         = 100;
-  static const kVMMustBePaused          = 101;
   static const kCannotAddBreakpoint     = 102;
   static const kStreamAlreadySubscribed = 103;
   static const kStreamNotSubscribed     = 104;
   static const kIsolateMustBeRunnable   = 105;
+  static const kIsolateMustBePaused     = 106;
+  static const kIsolateIsReloading      = 107;
 
   int code;
   Map data;
@@ -287,17 +288,17 @@
 
   Future<ServiceObject> _inProgressReload;
 
-  Future<ObservableMap> _fetchDirect() {
+  Future<ObservableMap> _fetchDirect({int count: kDefaultFieldLimit}) {
     Map params = {
       'objectId': id,
-      'count': kDefaultFieldLimit,
+      'count': count,
     };
     return isolate.invokeRpcNoUpgrade('getObject', params);
   }
 
   /// Reload [this]. Returns a future which completes to [this] or
   /// an exception.
-  Future<ServiceObject> reload() {
+  Future<ServiceObject> reload({int count: kDefaultFieldLimit}) {
     // TODO(turnidge): Checking for a null id should be part of the
     // "immmutable" check.
     bool hasId = (id != null) && (id != '');
@@ -312,7 +313,7 @@
     if (_inProgressReload == null) {
       var completer = new Completer<ServiceObject>();
       _inProgressReload = completer.future;
-      _fetchDirect().then((ObservableMap map) {
+      _fetchDirect(count: count).then((ObservableMap map) {
         var mapType = _stripRef(map['type']);
         if (mapType == 'Sentinel') {
           // An object may have been collected, etc.
@@ -622,6 +623,7 @@
   @observable bool assertsEnabled = false;
   @observable bool typeChecksEnabled = false;
   @observable int pid = 0;
+  @observable bool profileVM = false;
   @observable DateTime startTime;
   @observable DateTime refreshTime;
   @observable Duration get upTime {
@@ -805,7 +807,7 @@
     return invokeRpc('_restartVM', {});
   }
 
-  Future<ObservableMap> _fetchDirect() async {
+  Future<ObservableMap> _fetchDirect({int count: kDefaultFieldLimit}) async {
     if (!loaded) {
       // The vm service relies on these events to keep the VM and
       // Isolate types up to date.
@@ -897,6 +899,7 @@
     refreshTime = new DateTime.now();
     notifyPropertyChange(#upTime, 0, 1);
     pid = map['pid'];
+    profileVM = map['_profilerMode'] == 'VM';
     assertsEnabled = map['_assertsEnabled'];
     typeChecksEnabled = map['_typeChecksEnabled'];
     _removeDeadIsolates(map['isolates']);
@@ -1147,6 +1150,7 @@
   @observable bool loading = true;
   @observable bool runnable = false;
   @observable bool ioEnabled = false;
+  @observable bool reloading = false;
 
   final List<String> extensionRPCs = new List<String>();
 
@@ -1190,6 +1194,22 @@
     return invokeRpc('getSourceReport', params);
   }
 
+  Future<ServiceMap> reloadSources() {
+    return invokeRpc('_reloadSources', {}).then((_) {
+      reloading = true;
+    });
+  }
+
+  void _handleIsolateReloadEvent(ServiceEvent event) {
+    reloading = false;
+    if (event.reloadError != null) {
+      // Failure.
+      print('Reload failed: ${event.reloadError}');
+    } else {
+      _cache.clear();
+    }
+  }
+
   /// Fetches and builds the class hierarchy for this isolate. Returns the
   /// Object class object.
   Future<Class> getClassHierarchy() {
@@ -1286,24 +1306,26 @@
     });
   }
 
-  Future<ServiceObject> getObject(String objectId, {bool reload: true}) {
+  Future<ServiceObject> getObject(String objectId,
+                                  {bool reload: true,
+                                   int count: kDefaultFieldLimit}) {
     assert(objectId != null && objectId != '');
     var obj = _cache[objectId];
     if (obj != null) {
       if (reload) {
-        return obj.reload();
+        return obj.reload(count: count);
       }
       // Returned cached object.
       return new Future.value(obj);
     }
     Map params = {
       'objectId': objectId,
-      'count': kDefaultFieldLimit,
+      'count': count,
     };
     return isolate.invokeRpc('getObject', params);
   }
 
-  Future<ObservableMap> _fetchDirect() {
+  Future<ObservableMap> _fetchDirect({int count: kDefaultFieldLimit}) async {
     return invokeRpcNoUpgrade('getIsolate', {});
   }
 
@@ -1495,7 +1517,9 @@
       case ServiceEvent.kInspect:
         // Handled elsewhere.
         break;
-
+      case ServiceEvent.kIsolateReload:
+        _handleIsolateReloadEvent(event);
+        break;
       case ServiceEvent.kBreakpointAdded:
         _addBreakpoint(event.breakpoint);
         break;
@@ -1819,6 +1843,7 @@
   static const kIsolateRunnable        = 'IsolateRunnable';
   static const kIsolateExit            = 'IsolateExit';
   static const kIsolateUpdate          = 'IsolateUpdate';
+  static const kIsolateReload          = 'IsolateReload';
   static const kServiceExtensionAdded  = 'ServiceExtensionAdded';
   static const kPauseStart             = 'PauseStart';
   static const kPauseExit              = 'PauseExit';
@@ -1850,6 +1875,7 @@
   @observable Frame topFrame;
   @observable String extensionRPC;
   @observable Instance exception;
+  @observable Instance reloadError;
   @observable bool atAsyncSuspension;
   @observable ServiceObject inspectee;
   @observable ByteData data;
@@ -1921,6 +1947,7 @@
     if (map['count'] != null) {
       count = map['count'];
     }
+    reloadError = map['reloadError'];
     if (map['_debuggerSettings'] != null &&
         map['_debuggerSettings']['_exceptions'] != null) {
       exceptions = map['_debuggerSettings']['_exceptions'];
@@ -2853,6 +2880,7 @@
   final lines = new ObservableList<ScriptLine>();
   @observable String uri;
   @observable String kind;
+  @observable DateTime loadTime;
   @observable int firstTokenPos;
   @observable int lastTokenPos;
   @observable int lineOffset;
@@ -2955,6 +2983,8 @@
       return;
     }
     _loaded = true;
+    int loadTimeMillis = map['_loadTime'];
+    loadTime = new DateTime.fromMillisecondsSinceEpoch(loadTimeMillis);
     lineOffset = map['lineOffset'];
     columnOffset = map['columnOffset'];
     _parseTokenPosTable(map['tokenPosTable']);
@@ -3558,11 +3588,11 @@
 
   /// Reload [this]. Returns a future which completes to [this] or an
   /// exception.
-  Future<ServiceObject> reload() {
+  Future<ServiceObject> reload({int count: kDefaultFieldLimit}) {
     assert(kind != null);
     if (isDartCode) {
       // We only reload Dart code.
-      return super.reload();
+      return super.reload(count: count);
     }
     return new Future.value(this);
   }
@@ -3843,7 +3873,7 @@
     _removeOld();
   }
 
-  Future<ObservableMap> _fetchDirect() {
+  Future<ObservableMap> _fetchDirect({int count: kDefaultFieldLimit}) {
     assert(owner is Isolate);
     return isolate.invokeRpcNoUpgrade('_getIsolateMetric', { 'metricId': id });
   }
diff --git a/runtime/observatory/tests/service/get_allocation_samples_test.dart b/runtime/observatory/tests/service/get_allocation_samples_test.dart
index 87615c9..85626ee 100644
--- a/runtime/observatory/tests/service/get_allocation_samples_test.dart
+++ b/runtime/observatory/tests/service/get_allocation_samples_test.dart
@@ -67,7 +67,7 @@
     var tree = cpuProfile.loadCodeTree('exclusive');
     var node = tree.root;
     var expected =
-        ['Root', 'test', 'test', '_Closure.call'];
+        ['Root', 'DRT_AllocateObject', 'test', 'test', '_Closure.call'];
     for (var i = 0; i < expected.length; i++) {
       expect(node.profileCode.code.name, equals(expected[i]));
       // Depth first traversal.
diff --git a/runtime/observatory/web/timeline.html b/runtime/observatory/web/timeline.html
index ebcc46e..dba2b26 100644
--- a/runtime/observatory/web/timeline.html
+++ b/runtime/observatory/web/timeline.html
@@ -3,8 +3,9 @@
 <head>
   <meta charset="utf-8">
   <title>Dart VM Observatory Timeline</title>
-  <script src="timeline.js"></script>
+  <script src="timeline_message_handler.js"></script>
   <link rel="import" href="third_party/trace_viewer_full.html">
+  <script src="timeline.js"></script>
   <style>
 html, body {
   box-sizing: border-box;
diff --git a/runtime/observatory/web/timeline.js b/runtime/observatory/web/timeline.js
index dea5542..56de01d 100644
--- a/runtime/observatory/web/timeline.js
+++ b/runtime/observatory/web/timeline.js
@@ -2,17 +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.
 
-// Used to delay the initial timeline load until the timeline has finished
-// loading.
-timeline_loaded = false;
-timeline_vm_address = undefined;
-timeline_isolates = undefined;
-
-function registerForMessages() {
-  window.addEventListener("message", onMessage, false);
-}
-
-registerForMessages();
+// See also timeline_message_handler.js.
 
 function onModelLoaded() {
   viewer.globalMode = true;
@@ -38,8 +28,6 @@
   p.then(onModelLoaded, onImportFail);
 }
 
-
-
 function fetchUri(uri, onLoad, onError) {
   var xhr = new XMLHttpRequest();
   xhr.open('GET', uri, true);
@@ -50,22 +38,37 @@
   console.log('GET ' + uri);
 }
 
-
 var traceObject;
 var pendingRequests;
+var loadingOverlay;
+
+function showLoadingOverlay(msg) {
+  if (!loadingOverlay) {
+    loadingOverlay = new tr.ui.b.Overlay();
+  }
+  loadingOverlay.textContent = msg;
+  loadingOverlay.title = 'Loading...';
+  loadingOverlay.visible = true;
+}
+
+function hideLoadingOverlay() {
+  if (!loadingOverlay) {
+    return;
+  }
+  loadingOverlay.visible = false;
+  loadingOverlay = undefined;
+}
 
 function gotReponse() {
   pendingRequests--;
   if (pendingRequests == 0) {
     console.log("Got all timeline parts");
     updateTimeline(traceObject);
+    hideLoadingOverlay();
   }
 }
 
-function fetchTimelineOnLoad(event) {
-  var xhr = event.target;
-  var response = JSON.parse(xhr.responseText);
-
+function processTimelineResponse(response) {
   if (response.error) {
     // Maybe profiling is disabled.
     console.log("ERROR " + response.error.message);
@@ -86,20 +89,46 @@
   gotReponse();
 }
 
+function fetchTimelineOnLoad(event) {
+  var xhr = event.target;
+  var response = JSON.parse(xhr.responseText);
+  processTimelineResponse(response);
+}
+
 function fetchTimelineOnError(event) {
   var xhr = event.target;
   console.log(xhr.statusText);
   gotReponse();
 }
 
+function fetchCPUProfile(vmAddress, isolateIds, timeOrigin, timeExtent) {
+  showLoadingOverlay('Fetching CPU profile(s) from Dart VM');
+  var parser = document.createElement('a');
+  parser.href = vmAddress;
+  pendingRequests += isolateIds.length;
+  for (var i = 0; i < isolateIds.length; i++) {
+    var isolateId = isolateIds[i];
+    var requestUri = 'http://' +
+                     parser.hostname +
+                     ':' +
+                     parser.port +
+                     '/_getCpuProfileTimeline?tags=VMUser&isolateId=' +
+                     isolateId +
+                     '&timeOriginMicros=' + timeOrigin +
+                     '&timeExtentMicros=' + timeExtent;
+    fetchUri(requestUri, fetchTimelineOnLoad, fetchTimelineOnError);
+  }
+}
+
 function fetchTimeline(vmAddress, isolateIds) {
   // Reset combined timeline.
   traceObject = {
     'stackFrames': {},
     'traceEvents': []
   };
-  pendingRequests = 1 + isolateIds.length;
+  pendingRequests = 1;
 
+  showLoadingOverlay('Fetching timeline from Dart VM');
   var parser = document.createElement('a');
   parser.href = vmAddress;
   var requestUri = 'http://' +
@@ -107,18 +136,22 @@
                    ':' +
                    parser.port +
                    '/_getVMTimeline';
-  fetchUri(requestUri, fetchTimelineOnLoad, fetchTimelineOnError);
-
-  for (var i = 0; i < isolateIds.length; i++) {
-    var isolateId = isolateIds[i];
-    var requestUri = 'http://' +
-                     parser.hostname +
-                     ':' +
-                     parser.port +
-                     '/_getCpuProfileTimeline?tags=VMUser&isolateId=' +
-                     isolateId;
-    fetchUri(requestUri, fetchTimelineOnLoad, fetchTimelineOnError);
-  }
+  fetchUri(requestUri, function(event) {
+    // Grab the response.
+    var xhr = event.target;
+    var response = JSON.parse(xhr.responseText);
+    // Extract the time origin and extent.
+    var timeOrigin = response['result']['timeOriginMicros'];
+    var timeExtent = response['result']['timeExtentMicros'];
+    console.assert(Number.isInteger(timeOrigin), timeOrigin);
+    console.assert(Number.isInteger(timeExtent), timeExtent);
+    console.log(timeOrigin);
+    console.log(timeExtent);
+    // fetchCPUProfile.
+    fetchCPUProfile(vmAddress, isolateIds, timeOrigin, timeExtent);
+    // This must happen after 'fetchCPUProfile';
+    processTimelineResponse(response);
+  }, fetchTimelineOnError);
 }
 
 function saveTimeline() {
@@ -200,35 +233,7 @@
   inputElement.click();
 }
 
-function onMessage(event) {
-  var request = JSON.parse(event.data);
-  var method = request['method'];
-  var params = request['params'];
-  switch (method) {
-    case 'refresh':
-      if (!timeline_loaded) {
-        timeline_vm_address = params['vmAddress'];
-        timeline_isolates = params['isolateIds'];
-        console.log('Delaying timeline refresh until loaded.');
-      } else {
-        fetchTimeline(params['vmAddress'], params['isolateIds']);
-      }
-    break;
-    case 'clear':
-      clearTimeline();
-    break;
-    case 'save':
-      saveTimeline();
-    break;
-    case 'load':
-      loadTimeline();
-    break;
-    default:
-      console.log('Unknown method:' + method + '.');
-  }
-}
-
-document.addEventListener('DOMContentLoaded', function() {
+window.addEventListener('DOMContentLoaded', function() {
   var container = document.createElement('track-view-container');
   container.id = 'track_view_container';
   viewer = document.createElement('tr-ui-timeline-view');
@@ -238,6 +243,7 @@
   viewer.globalMode = true;
   document.body.appendChild(viewer);
   timeline_loaded = true;
+  console.log('DOMContentLoaded');
   if (timeline_vm_address != undefined) {
     console.log('Triggering delayed timeline refresh.');
     fetchTimeline(timeline_vm_address, timeline_isolates);
@@ -246,4 +252,4 @@
   }
 });
 
-console.log('loaded');
+console.log('timeline.js loaded');
diff --git a/runtime/observatory/web/timeline_message_handler.js b/runtime/observatory/web/timeline_message_handler.js
new file mode 100644
index 0000000..7ae238d
--- /dev/null
+++ b/runtime/observatory/web/timeline_message_handler.js
@@ -0,0 +1,49 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This file is loaded before the about:tracing code is loaded so that we have
+// an event listener registered early.
+
+// Used to delay the initial timeline load until the timeline has finished
+// loading.
+timeline_loaded = false;
+timeline_vm_address = undefined;
+timeline_isolates = undefined;
+
+function registerForMessages() {
+  window.addEventListener("message", onMessage, false);
+}
+
+registerForMessages();
+
+function onMessage(event) {
+  var request = JSON.parse(event.data);
+  var method = request['method'];
+  var params = request['params'];
+  console.log('method: ' + method)
+  switch (method) {
+    case 'refresh':
+      if (!timeline_loaded) {
+        timeline_vm_address = params['vmAddress'];
+        timeline_isolates = params['isolateIds'];
+        console.log('Delaying timeline refresh until loaded.');
+      } else {
+        fetchTimeline(params['vmAddress'], params['isolateIds']);
+      }
+    break;
+    case 'clear':
+      clearTimeline();
+    break;
+    case 'save':
+      saveTimeline();
+    break;
+    case 'load':
+      loadTimeline();
+    break;
+    default:
+      console.log('Unknown method:' + method + '.');
+  }
+}
+
+console.log('message handler registered');
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index a0dfdd0..e3d1a34 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -2,8 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-#ifndef RUNTIME_PLATFORM_GLOBALS_H_
-#define RUNTIME_PLATFORM_GLOBALS_H_
+#ifndef PLATFORM_GLOBALS_H_
+#define PLATFORM_GLOBALS_H_
 
 // __STDC_FORMAT_MACROS has to be defined before including <inttypes.h> to
 // enable platform independent printf format specifiers.
@@ -359,6 +359,25 @@
 #error Unknown architecture.
 #endif
 
+// Disable background threads by default on armv5te. The relevant
+// implementations are uniprocessors.
+#if !defined(TARGET_ARCH_ARM_5TE)
+#define ARCH_IS_MULTI_CORE 1
+#endif
+
+
+#if defined(TARGET_ARCH_ARM)
+#if defined(TARGET_ABI_IOS) && defined(TARGET_ABI_EABI)
+#error Both TARGET_ABI_IOS and TARGET_ABI_EABI defined.
+#elif !defined(TARGET_ABI_IOS) && !defined(TARGET_ABI_EABI)
+#if defined(TARGET_OS_MAC)
+#define TARGET_ABI_IOS 1
+#else
+#define TARGET_ABI_EABI 1
+#endif
+#endif
+#endif  // TARGET_ARCH_ARM
+
 
 // Short form printf format specifiers
 #define Pd PRIdPTR
@@ -678,4 +697,4 @@
 
 }  // namespace dart
 
-#endif  // RUNTIME_PLATFORM_GLOBALS_H_
+#endif  // PLATFORM_GLOBALS_H_
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 025a0f4..0fa725f 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -2,6 +2,13 @@
 # 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.
 
+cc/IsolateReload_PendingUnqualifiedCall_InstanceToStatic: Fail, Crash
+cc/IsolateReload_PendingUnqualifiedCall_StaticToInstance: Fail, Crash
+cc/IsolateReload_PendingConstructorCall_AbstractToConcrete: Fail, Crash
+cc/IsolateReload_PendingConstructorCall_ConcreteToAbstract: Fail, Crash
+cc/IsolateReload_PendingStaticCall_DefinedToNSM: Fail, Crash
+cc/IsolateReload_PendingStaticCall_NSMToDefined: Fail, Crash
+
 # These tests are expected to crash on all platforms.
 cc/ArrayNew_Overflow_Crash: Crash, Timeout
 cc/AllocGeneric_Overflow: Crash, Timeout
@@ -78,11 +85,18 @@
 [ $builder_tag == asan ]
 cc/CodeImmutability: Fail,OK # Address Sanitizer turns a crash into a failure.
 
+[ $arch == ia32 && $builder_tag == asan ]
+cc/Dart2JSCompileAll: Crash # Issue 26487 - stack overflow
+cc/Dart2JSCompilerStats: Crash # Issue 26487 - stack overflow
+
 [ $noopt ]
 dart/byte_array_test: Crash # Incompatible flag --disable_alloc_stubs_after_gc
 
 [ $noopt || $compiler == precompiler || $mode == product ]
-dart/redirection_type_shuffling_test: CompileTimeError # Imports dart:mirrors
+dart/redirection_type_shuffling_test: SkipByDesign # Imports dart:mirrors
+cc/CreateMirrorSystem: SkipByDesign # Imports dart:mirrors
+cc/CoreSnapshotSize: SkipByDesign # Imports dart:mirrors
+cc/StandaloneSnapshotSize: SkipByDesign # Imports dart:mirrors
 
 [ $noopt || $runtime == dart_precompiled ]
 # Stacktraces in precompilation omit inlined frames.
@@ -95,8 +109,9 @@
 
 [ $runtime == vm && $mode == product ]
 cc/IsolateSetCheckedMode: Fail,OK  # Expects exact type name.
-cc/LibraryGetClassNames: Fail,OK  # Expects exact type name.
 cc/StackTraceFormat: Fail,OK  # Expects exact type name.
+cc/String_ScrubName: Fail,OK  # Expects exact type name.
+cc/GetFunctionNames: Fail,OK  # Expects exact type name.
 
 [ $arch == simdbc || $arch == simdbc64 ]
 # TODO(vegorov) Profiler is completely disabled in SIMDBC builds.
diff --git a/runtime/vm/BUILD.gn b/runtime/vm/BUILD.gn
index b6e64db..f1c2da4 100644
--- a/runtime/vm/BUILD.gn
+++ b/runtime/vm/BUILD.gn
@@ -126,6 +126,7 @@
       "../tools/gen_library_src_paths.py",
       "../lib/libgen_in.cc",
     ]
+    inputs += lib_sources
     outputs = [ invoker.output, ]
     args = [
       "--output", rebase_path(invoker.output, root_build_dir),
diff --git a/runtime/vm/aot_optimizer.cc b/runtime/vm/aot_optimizer.cc
index 0318786..e81ddfc 100644
--- a/runtime/vm/aot_optimizer.cc
+++ b/runtime/vm/aot_optimizer.cc
@@ -123,6 +123,12 @@
 }
 
 
+// Returns named function that is a unique dynamic target, i.e.,
+// - the target is identified by its name alone, since it occurs only once.
+// - target's class has no subclasses, and neither is subclassed, i.e.,
+//   the receiver type can be only the function's class.
+// Returns Function::null() if there is no unique dynamic target for
+// given 'fname'. 'fname' must be a symbol.
 static void GetUniqueDynamicTarget(Isolate* isolate,
                                    const String& fname,
                                    Object* function) {
@@ -217,11 +223,10 @@
     Function& target_function = Function::Handle(Z);
     GetUniqueDynamicTarget(isolate(), call->function_name(), &target_function);
     // Calls with named arguments must be resolved/checked at runtime.
-    String& error_message = String::Handle(Z);
     if (!target_function.IsNull() &&
         !target_function.HasOptionalNamedParameters() &&
         target_function.AreValidArgumentCounts(call->ArgumentCount(), 0,
-                                               &error_message)) {
+                                               /* error_message = */ NULL)) {
       const intptr_t cid = Class::Handle(Z, target_function.Owner()).id();
       const ICData& ic_data = ICData::ZoneHandle(Z,
           ICData::NewFrom(*call->ic_data(), 1));
diff --git a/runtime/vm/become.cc b/runtime/vm/become.cc
new file mode 100644
index 0000000..0f4586f
--- /dev/null
+++ b/runtime/vm/become.cc
@@ -0,0 +1,238 @@
+// Copyright (c) 2016, 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.
+
+#include "vm/become.h"
+
+#include "platform/assert.h"
+#include "platform/utils.h"
+
+#include "vm/dart_api_state.h"
+#include "vm/freelist.h"
+#include "vm/isolate_reload.h"
+#include "vm/object.h"
+#include "vm/raw_object.h"
+#include "vm/safepoint.h"
+#include "vm/timeline.h"
+#include "vm/visitor.h"
+
+namespace dart {
+
+DECLARE_FLAG(bool, trace_reload);
+
+// Free list elements are used as a marker for forwarding objects. This is
+// safe because we cannot reach free list elements from live objects. Ideally
+// forwarding objects would have their own class id. See TODO below.
+static bool IsForwardingObject(RawObject* object) {
+  return object->IsHeapObject() && object->IsFreeListElement();
+}
+
+
+static RawObject* GetForwardedObject(RawObject* object) {
+  ASSERT(IsForwardingObject(object));
+  uword addr = reinterpret_cast<uword>(object) - kHeapObjectTag;
+  FreeListElement* forwarder = reinterpret_cast<FreeListElement*>(addr);
+  RawObject* new_target = reinterpret_cast<RawObject*>(forwarder->next());
+  return new_target;
+}
+
+
+static void ForwardObjectTo(RawObject* before_obj, RawObject* after_obj) {
+  const intptr_t size_before = before_obj->Size();
+
+  // TODO(rmacnak): We should use different cids for forwarding corpses and
+  // free list elements.
+  uword corpse_addr = reinterpret_cast<uword>(before_obj) - kHeapObjectTag;
+  FreeListElement* forwarder = FreeListElement::AsElement(corpse_addr,
+                                                          size_before);
+  forwarder->set_next(reinterpret_cast<FreeListElement*>(after_obj));
+  if (!IsForwardingObject(before_obj)) {
+    FATAL("become: ForwardObjectTo failure.");
+  }
+  // Still need to be able to iterate over the forwarding corpse.
+  const intptr_t size_after = before_obj->Size();
+  if (size_before != size_after) {
+    FATAL("become: Before and after sizes do not match.");
+  }
+}
+
+
+class ForwardPointersVisitor : public ObjectPointerVisitor {
+ public:
+  explicit ForwardPointersVisitor(Isolate* isolate)
+      : ObjectPointerVisitor(isolate), visiting_object_(NULL), count_(0) { }
+
+  virtual void VisitPointers(RawObject** first, RawObject** last) {
+    for (RawObject** p = first; p <= last; p++) {
+      RawObject* old_target = *p;
+      if (IsForwardingObject(old_target)) {
+        RawObject* new_target = GetForwardedObject(old_target);
+        if (visiting_object_ == NULL) {
+          *p = new_target;
+        } else {
+          visiting_object_->StorePointer(p, new_target);
+        }
+        count_++;
+      }
+    }
+  }
+
+  void VisitingObject(RawObject* obj) { visiting_object_ = obj; }
+
+  intptr_t count() const { return count_; }
+
+ private:
+  RawObject* visiting_object_;
+  intptr_t count_;
+
+  DISALLOW_COPY_AND_ASSIGN(ForwardPointersVisitor);
+};
+
+
+class ForwardHeapPointersVisitor : public ObjectVisitor {
+ public:
+  explicit ForwardHeapPointersVisitor(ForwardPointersVisitor* pointer_visitor)
+      : pointer_visitor_(pointer_visitor) { }
+
+  virtual void VisitObject(RawObject* obj) {
+    pointer_visitor_->VisitingObject(obj);
+    obj->VisitPointers(pointer_visitor_);
+  }
+
+ private:
+  ForwardPointersVisitor* pointer_visitor_;
+
+  DISALLOW_COPY_AND_ASSIGN(ForwardHeapPointersVisitor);
+};
+
+
+class ForwardHeapPointersHandleVisitor : public HandleVisitor {
+ public:
+  ForwardHeapPointersHandleVisitor()
+      : HandleVisitor(Thread::Current()), count_(0) { }
+
+  virtual void VisitHandle(uword addr) {
+    FinalizablePersistentHandle* handle =
+        reinterpret_cast<FinalizablePersistentHandle*>(addr);
+    if (IsForwardingObject(handle->raw())) {
+      *handle->raw_addr() = GetForwardedObject(handle->raw());
+      count_++;
+    }
+  }
+
+  intptr_t count() const { return count_; }
+
+ private:
+  int count_;
+
+  DISALLOW_COPY_AND_ASSIGN(ForwardHeapPointersHandleVisitor);
+};
+
+
+#if defined(DEBUG)
+class NoFreeListTargetsVisitor : public ObjectPointerVisitor {
+ public:
+  explicit NoFreeListTargetsVisitor(Isolate* isolate)
+      : ObjectPointerVisitor(isolate) { }
+
+  virtual void VisitPointers(RawObject** first, RawObject** last) {
+    for (RawObject** p = first; p <= last; p++) {
+      RawObject* target = *p;
+      if (target->IsHeapObject()) {
+        ASSERT(!target->IsFreeListElement());
+      }
+    }
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NoFreeListTargetsVisitor);
+};
+#endif
+
+
+void Become::ElementsForwardIdentity(const Array& before, const Array& after) {
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
+  Heap* heap = isolate->heap();
+
+  {
+    // TODO(rmacnak): Investigate why this is necessary.
+    heap->CollectGarbage(Heap::kNew);
+  }
+
+  TIMELINE_FUNCTION_GC_DURATION(thread, "Become::ElementsForwardIdentity");
+  HeapIterationScope his;
+
+#if defined(DEBUG)
+  {
+    // There should be no pointers to free list elements / forwarding corpses.
+    NoFreeListTargetsVisitor visitor(isolate);
+    isolate->VisitObjectPointers(&visitor, true);
+    heap->VisitObjectPointers(&visitor);
+  }
+#endif
+
+  // Setup forwarding pointers.
+  ASSERT(before.Length() == after.Length());
+  for (intptr_t i = 0; i < before.Length(); i++) {
+    RawObject* before_obj = before.At(i);
+    RawObject* after_obj = after.At(i);
+
+    if (before_obj == after_obj) {
+      FATAL("become: Cannot self-forward");
+    }
+    if (!before_obj->IsHeapObject()) {
+      FATAL("become: Cannot forward immediates");
+    }
+    if (!after_obj->IsHeapObject()) {
+      FATAL("become: Cannot become an immediates");
+    }
+    if (before_obj->IsVMHeapObject()) {
+      FATAL("become: Cannot forward VM heap objects");
+    }
+    if (after_obj->IsFreeListElement()) {
+      // The Smalltalk become does allow this, and for very special cases
+      // it is important (shape changes to Class or Mixin), but as these
+      // cases do not arise in Dart, better to prohibit it.
+      FATAL("become: No indirect chains of forwarding");
+    }
+
+    ForwardObjectTo(before_obj, after_obj);
+  }
+
+  {
+    // Follow forwarding pointers.
+
+    // C++ pointers
+    ForwardPointersVisitor pointer_visitor(isolate);
+    isolate->VisitObjectPointers(&pointer_visitor, true);
+
+    // Weak persistent handles.
+    ForwardHeapPointersHandleVisitor handle_visitor;
+    isolate->VisitWeakPersistentHandles(&handle_visitor);
+
+    //   Heap pointers (may require updating the remembered set)
+    ForwardHeapPointersVisitor object_visitor(&pointer_visitor);
+    heap->VisitObjects(&object_visitor);
+    pointer_visitor.VisitingObject(NULL);
+
+    TIR_Print("Performed %" Pd " heap and %" Pd " handle replacements\n",
+              pointer_visitor.count(),
+              handle_visitor.count());
+  }
+
+#if defined(DEBUG)
+  for (intptr_t i = 0; i < before.Length(); i++) {
+    ASSERT(before.At(i) == after.At(i));
+  }
+
+  {
+    // There should be no pointers to forwarding corpses.
+    NoFreeListTargetsVisitor visitor(isolate);
+    isolate->VisitObjectPointers(&visitor, true);
+    heap->VisitObjectPointers(&visitor);
+  }
+#endif
+}
+
+}  // namespace dart
diff --git a/runtime/vm/become.h b/runtime/vm/become.h
new file mode 100644
index 0000000..9773553
--- /dev/null
+++ b/runtime/vm/become.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2016, 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.
+
+#ifndef VM_BECOME_H_
+#define VM_BECOME_H_
+
+#include "vm/allocation.h"
+
+namespace dart {
+
+class Array;
+
+// TODO(johnmccutchan): Refactor this class so that it is not all static and
+// provides utility methods for building the mapping of before and after.
+class Become : public AllStatic {
+ public:
+  // Smalltalk's one-way bulk become (Array>>#elementsForwardIdentityTo:).
+  // Redirects all pointers to elements of 'before' to the corresponding element
+  // in 'after'. Every element in 'before' is guaranteed to be not reachable.
+  // Useful for atomically applying behavior and schema changes.
+  static void ElementsForwardIdentity(const Array& before, const Array& after);
+};
+
+}  // namespace dart
+
+#endif  // VM_BECOME_H_
diff --git a/runtime/vm/block_scheduler.cc b/runtime/vm/block_scheduler.cc
index 9c00cfb..d792551 100644
--- a/runtime/vm/block_scheduler.cc
+++ b/runtime/vm/block_scheduler.cc
@@ -64,7 +64,10 @@
     Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId,
         "BlockScheduler: ICData array cleared");
   }
-  ASSERT(!ic_data_array.IsNull());
+  if (ic_data_array.IsNull()) {
+    ASSERT(Isolate::Current()->HasAttemptedReload());
+    return;
+  }
   Array& edge_counters = Array::Handle();
   edge_counters ^= ic_data_array.At(0);
 
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 31b800c..3855eaa 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -162,6 +162,7 @@
   V(Timeline_getNextAsyncId, 0)                                                \
   V(Timeline_getTraceClock, 0)                                                 \
   V(Timeline_getThreadCpuClock, 0)                                             \
+  V(Timeline_isDartStreamEnabled, 0)                                           \
   V(Timeline_reportCompleteEvent, 5)                                           \
   V(Timeline_reportInstantEvent, 4)                                            \
   V(Timeline_reportTaskEvent, 6)                                               \
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 81cd85c..027072b 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -1923,7 +1923,7 @@
     inserted_class_name = Symbols::New(thread, inserted_class_name);
     const Script& script = Script::Handle(zone, mixin_app_class.script());
     inserted_class = Class::New(
-        inserted_class_name, script, mixin_app_class.token_pos());
+        library, inserted_class_name, script, mixin_app_class.token_pos());
     inserted_class.set_is_synthesized_class();
     library.AddClass(inserted_class);
 
@@ -2814,7 +2814,8 @@
     mixin_app_class = library.LookupLocalClass(mixin_app_class_name);
     if (mixin_app_class.IsNull()) {
       mixin_app_class_name = Symbols::New(thread, mixin_app_class_name);
-      mixin_app_class = Class::New(mixin_app_class_name,
+      mixin_app_class = Class::New(library,
+                                   mixin_app_class_name,
                                    script,
                                    mixin_type.token_pos());
       mixin_app_class.set_super_type(mixin_super_type);
diff --git a/runtime/vm/class_finalizer_test.cc b/runtime/vm/class_finalizer_test.cc
index eb4447c..8de73e5 100644
--- a/runtime/vm/class_finalizer_test.cc
+++ b/runtime/vm/class_finalizer_test.cc
@@ -15,7 +15,8 @@
                                                          name));
   const Script& script = Script::Handle();
   const Class& cls = Class::Handle(
-      Class::New(class_name, script, TokenPosition::kNoSource));
+      Class::New(Library::Handle(), class_name, script,
+                 TokenPosition::kNoSource));
   cls.set_interfaces(Object::empty_array());
   cls.SetFunctions(Object::empty_array());
   cls.SetFields(Object::empty_array());
diff --git a/runtime/vm/class_table.h b/runtime/vm/class_table.h
index 97e475a..af774a0 100644
--- a/runtime/vm/class_table.h
+++ b/runtime/vm/class_table.h
@@ -156,6 +156,10 @@
     return table_[index];
   }
 
+  void SetAt(intptr_t index, RawClass* raw_cls) {
+    table_[index] = raw_cls;
+  }
+
   bool IsValidIndex(intptr_t index) const {
     return (index > 0) && (index < top_);
   }
@@ -167,6 +171,12 @@
 
   intptr_t NumCids() const { return top_; }
 
+  // Used to drop recently added classes.
+  void SetNumCids(intptr_t num_cids) {
+    ASSERT(num_cids <= top_);
+    top_ = num_cids;
+  }
+
   void Register(const Class& cls);
 
   void RegisterAt(intptr_t index, const Class& cls);
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 3f01605..3a8cf41 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -20,6 +20,7 @@
 #include "vm/parser.h"
 #include "vm/resolver.h"
 #include "vm/runtime_entry.h"
+#include "vm/service_isolate.h"
 #include "vm/stack_frame.h"
 #include "vm/symbols.h"
 #include "vm/thread_registry.h"
@@ -60,6 +61,9 @@
 DEFINE_FLAG(charp, deoptimize_filter, NULL,
             "Deoptimize in named function on stack overflow checks");
 
+DECLARE_FLAG(int, reload_every);
+DECLARE_FLAG(bool, reload_every_optimized);
+
 #ifdef DEBUG
 DEFINE_FLAG(charp, gc_at_instance_allocation, NULL,
             "Perform a GC before allocation of instances of "
@@ -668,7 +672,7 @@
   const Code& orig_stub = Code::Handle(
       zone, isolate->debugger()->GetPatchedStubAddress(caller_frame->pc()));
   const Error& error =
-      Error::Handle(zone, isolate->debugger()->SignalBpReached());
+      Error::Handle(zone, isolate->debugger()->PauseBreakpoint());
   if (!error.IsNull()) {
     Exceptions::PropagateError(error);
     UNREACHABLE();
@@ -682,7 +686,7 @@
     UNREACHABLE();
     return;
   }
-  const Error& error = Error::Handle(isolate->debugger()->SignalBpReached());
+  const Error& error = Error::Handle(isolate->debugger()->PauseBreakpoint());
   if (!error.IsNull()) {
     Exceptions::PropagateError(error);
     UNREACHABLE();
@@ -697,7 +701,7 @@
     return;
   }
   const Error& error =
-      Error::Handle(zone, isolate->debugger()->DebuggerStepCallback());
+      Error::Handle(zone, isolate->debugger()->PauseStepping());
   if (!error.IsNull()) {
     Exceptions::PropagateError(error);
     UNREACHABLE();
@@ -1237,7 +1241,10 @@
   // debugger stack tracing.
   bool do_deopt = false;
   bool do_stacktrace = false;
-  if ((FLAG_deoptimize_every > 0) || (FLAG_stacktrace_every > 0)) {
+  bool do_reload = false;
+  if ((FLAG_deoptimize_every > 0) ||
+      (FLAG_stacktrace_every > 0) ||
+      (FLAG_reload_every > 0)) {
     // TODO(turnidge): To make --deoptimize_every and
     // --stacktrace-every faster we could move this increment/test to
     // the generated code.
@@ -1250,8 +1257,14 @@
         (count % FLAG_stacktrace_every) == 0) {
       do_stacktrace = true;
     }
+    if ((FLAG_reload_every > 0) &&
+        (count % FLAG_reload_every) == 0) {
+      do_reload = isolate->CanReload();
+    }
   }
-  if ((FLAG_deoptimize_filter != NULL) || (FLAG_stacktrace_filter != NULL)) {
+  if ((FLAG_deoptimize_filter != NULL) ||
+      (FLAG_stacktrace_filter != NULL) ||
+      FLAG_reload_every_optimized) {
     DartFrameIterator iterator;
     StackFrame* frame = iterator.NextFrame();
     ASSERT(frame != NULL);
@@ -1261,6 +1274,10 @@
     ASSERT(!function.IsNull());
     const char* function_name = function.ToFullyQualifiedCString();
     ASSERT(function_name != NULL);
+    if (!code.is_optimized() && FLAG_reload_every_optimized) {
+      // Don't do the reload if we aren't inside optimized code.
+      do_reload = false;
+    }
     if (code.is_optimized() &&
         FLAG_deoptimize_filter != NULL &&
         strstr(function_name, FLAG_deoptimize_filter) != NULL) {
@@ -1279,6 +1296,9 @@
     // TODO(turnidge): Consider using DeoptimizeAt instead.
     DeoptimizeFunctionsOnStack();
   }
+  if (do_reload) {
+    NOT_IN_PRODUCT(isolate->OnStackReload();)
+  }
   if (FLAG_support_debugger && do_stacktrace) {
     String& var_name = String::Handle();
     Instance& var_value = Instance::Handle();
@@ -1414,20 +1434,22 @@
       if (FLAG_enable_inlining_annotations) {
         FATAL("Cannot enable inlining annotations and background compilation");
       }
-      if (FLAG_background_compilation_stop_alot) {
-        BackgroundCompiler::Stop(isolate);
+      if (!BackgroundCompiler::IsDisabled()) {
+        if (FLAG_background_compilation_stop_alot) {
+          BackgroundCompiler::Stop(isolate);
+        }
+        // Reduce the chance of triggering optimization while the function is
+        // being optimized in the background. INT_MIN should ensure that it
+        // takes long time to trigger optimization.
+        // Note that the background compilation queue rejects duplicate entries.
+        function.set_usage_counter(INT_MIN);
+        BackgroundCompiler::EnsureInit(thread);
+        ASSERT(isolate->background_compiler() != NULL);
+        isolate->background_compiler()->CompileOptimized(function);
+        // Continue in the same code.
+        arguments.SetReturn(Code::Handle(zone, function.CurrentCode()));
+        return;
       }
-      // Reduce the chance of triggering optimization while the function is
-      // being optimized in the background. INT_MIN should ensure that it takes
-      // long time to trigger optimization.
-      // Note that the background compilation queue rejects duplicate entries.
-      function.set_usage_counter(INT_MIN);
-      BackgroundCompiler::EnsureInit(thread);
-      ASSERT(isolate->background_compiler() != NULL);
-      isolate->background_compiler()->CompileOptimized(function);
-      // Continue in the same code.
-      arguments.SetReturn(Code::Handle(zone, function.CurrentCode()));
-      return;
     }
 
     // Reset usage counter for reoptimization before calling optimizer to
diff --git a/runtime/vm/code_patcher_arm64_test.cc b/runtime/vm/code_patcher_arm64_test.cc
index f11b00a..3b5e61e 100644
--- a/runtime/vm/code_patcher_arm64_test.cc
+++ b/runtime/vm/code_patcher_arm64_test.cc
@@ -24,8 +24,8 @@
   Thread* thread = Thread::Current();
   const String& class_name = String::Handle(Symbols::New(thread, "ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class = Class::Handle(
-      Class::New(class_name, script, TokenPosition::kNoSource));
+  const Class& owner_class = Class::Handle(Class::New(
+      Library::Handle(), class_name, script, TokenPosition::kNoSource));
   const String& function_name = String::Handle(Symbols::New(thread,
                                                             "callerFunction"));
   const Function& function = Function::Handle(
diff --git a/runtime/vm/code_patcher_arm_test.cc b/runtime/vm/code_patcher_arm_test.cc
index a4cdfe5..b1ca06f 100644
--- a/runtime/vm/code_patcher_arm_test.cc
+++ b/runtime/vm/code_patcher_arm_test.cc
@@ -24,8 +24,8 @@
   Thread* thread = Thread::Current();
   const String& class_name = String::Handle(Symbols::New(thread, "ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class = Class::Handle(
-      Class::New(class_name, script, TokenPosition::kNoSource));
+  const Class& owner_class = Class::Handle(Class::New(
+      Library::Handle(), class_name, script, TokenPosition::kNoSource));
   const String& function_name = String::Handle(Symbols::New(thread,
                                                             "callerFunction"));
   const Function& function = Function::Handle(
diff --git a/runtime/vm/code_patcher_ia32_test.cc b/runtime/vm/code_patcher_ia32_test.cc
index 55fe98f..c035345 100644
--- a/runtime/vm/code_patcher_ia32_test.cc
+++ b/runtime/vm/code_patcher_ia32_test.cc
@@ -24,8 +24,8 @@
   Thread* thread = Thread::Current();
   const String& class_name = String::Handle(Symbols::New(thread, "ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class = Class::Handle(
-      Class::New(class_name, script, TokenPosition::kNoSource));
+  const Class& owner_class = Class::Handle(Class::New(
+      Library::Handle(), class_name, script, TokenPosition::kNoSource));
   const String& function_name = String::Handle(Symbols::New(thread,
                                                             "callerFunction"));
   const Function& function = Function::Handle(
diff --git a/runtime/vm/code_patcher_mips_test.cc b/runtime/vm/code_patcher_mips_test.cc
index 0776083..c8d65bf 100644
--- a/runtime/vm/code_patcher_mips_test.cc
+++ b/runtime/vm/code_patcher_mips_test.cc
@@ -24,8 +24,8 @@
   Thread* thread = Thread::Current();
   const String& class_name = String::Handle(Symbols::New(thread, "ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class = Class::Handle(
-      Class::New(class_name, script, TokenPosition::kNoSource));
+  const Class& owner_class = Class::Handle(Class::New(
+      Library::Handle(), class_name, script, TokenPosition::kNoSource));
   const String& function_name = String::Handle(Symbols::New(thread,
                                                             "callerFunction"));
   const Function& function = Function::Handle(
diff --git a/runtime/vm/code_patcher_x64_test.cc b/runtime/vm/code_patcher_x64_test.cc
index 5102226..410ba1a 100644
--- a/runtime/vm/code_patcher_x64_test.cc
+++ b/runtime/vm/code_patcher_x64_test.cc
@@ -24,8 +24,8 @@
   Thread* thread = Thread::Current();
   const String& class_name = String::Handle(Symbols::New(thread, "ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class = Class::Handle(
-      Class::New(class_name, script, TokenPosition::kNoSource));
+  const Class& owner_class = Class::Handle(Class::New(
+      Library::Handle(), class_name, script, TokenPosition::kNoSource));
   const String& function_name = String::Handle(Symbols::New(thread,
                                                             "callerFunction"));
   const Function& function = Function::Handle(
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index e084f16..50e2e55 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -105,7 +105,7 @@
 }
 
 
-void DartCompilationPipeline::FinalizeCompilation() { }
+void DartCompilationPipeline::FinalizeCompilation(FlowGraph* flow_graph) { }
 
 
 void IrregexpCompilationPipeline::ParseFunction(
@@ -142,7 +142,7 @@
 }
 
 
-void IrregexpCompilationPipeline::FinalizeCompilation() {
+void IrregexpCompilationPipeline::FinalizeCompilation(FlowGraph* flow_graph) {
   backtrack_goto_->ComputeOffsetTable();
 }
 
@@ -1127,7 +1127,7 @@
                                                  compiler_timeline,
                                                  "CompileGraph"));
         graph_compiler.CompileGraph();
-        pipeline->FinalizeCompilation();
+        pipeline->FinalizeCompilation(flow_graph);
       }
       {
         NOT_IN_PRODUCT(TimelineDurationScope tds(thread(),
@@ -1452,10 +1452,12 @@
   TIMELINE_FUNCTION_COMPILATION_DURATION(thread, event_name, function);
 )  // !PRODUCT
 
-  // Optimization must happen in non-mutator/Dart thread if background
-  // compilation is on. OSR compilation still occurs in the main thread.
-  ASSERT((osr_id != kNoOSRDeoptId) || !FLAG_background_compilation ||
-         !thread->IsMutatorThread());
+  // If we are in the optimizing in the mutator/Dart thread, then
+  // this is either an OSR compilation or background compilation is
+  // not currently allowed.
+  ASSERT(!thread->IsMutatorThread() ||
+         (osr_id != kNoOSRDeoptId) ||
+         !FLAG_background_compilation || BackgroundCompiler::IsDisabled());
   CompilationPipeline* pipeline =
       CompilationPipeline::New(thread->zone(), function);
   return CompileFunctionHelper(pipeline,
@@ -1563,24 +1565,39 @@
   // evaluating the initializer value.
   ASSERT(field.StaticValue() == Object::transition_sentinel().raw());
   LongJumpScope jump;
+  Thread* thread = Thread::Current();
   if (setjmp(*jump.Set()) == 0) {
+    NoOOBMessageScope no_msg_scope(thread);
+    NoReloadScope no_reload_scope(thread->isolate(), thread);
     // Under lazy compilation initializer has not yet been created, so create
     // it now, but don't bother remembering it because it won't be used again.
     ASSERT(!field.HasPrecompiledInitializer());
     Thread* const thread = Thread::Current();
-    StackZone zone(thread);
-    ParsedFunction* parsed_function =
-        Parser::ParseStaticFieldInitializer(field);
+    Function& initializer = Function::Handle(thread->zone());
+    {
+      NOT_IN_PRODUCT(
+        VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId);
+        TimelineDurationScope tds(thread, Timeline::GetCompilerStream(),
+                                  "CompileStaticInitializer");
+        if (tds.enabled()) {
+          tds.SetNumArguments(1);
+          tds.CopyArgument(0, "field", field.ToCString());
+        }
+      )
 
-    parsed_function->AllocateVariables();
-    // Non-optimized code generator.
-    DartCompilationPipeline pipeline;
-    CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId);
-    helper.Compile(&pipeline);
-    const Function& initializer =
-        Function::Handle(parsed_function->function().raw());
-    Code::Handle(initializer.unoptimized_code()).set_var_descriptors(
-        Object::empty_var_descriptors());
+      StackZone zone(thread);
+      ParsedFunction* parsed_function =
+          Parser::ParseStaticFieldInitializer(field);
+
+      parsed_function->AllocateVariables();
+      // Non-optimized code generator.
+      DartCompilationPipeline pipeline;
+      CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId);
+      helper.Compile(&pipeline);
+      initializer = parsed_function->function().raw();
+      Code::Handle(initializer.unoptimized_code()).set_var_descriptors(
+          Object::empty_var_descriptors());
+    }
     // Invoke the function to evaluate the expression.
     return DartEntry::InvokeFunction(initializer, Object::empty_array());
   } else {
@@ -1609,6 +1626,10 @@
     // Don't allow message interrupts while executing constant
     // expressions.  They can cause bogus recursive compilation.
     NoOOBMessageScope no_msg_scope(thread);
+
+    // Don't allow reload requests to come in.
+    NoReloadScope no_reload_scope(thread->isolate(), thread);
+
     if (FLAG_trace_compiler) {
       THR_Print("compiling expression: ");
       if (FLAG_support_ast_printer) {
@@ -1963,6 +1984,41 @@
 }
 
 
+void BackgroundCompiler::Disable() {
+  Thread* thread = Thread::Current();
+  ASSERT(thread != NULL);
+  Isolate* isolate = thread->isolate();
+  MutexLocker ml(isolate->mutex());
+  BackgroundCompiler* task = isolate->background_compiler();
+  if (task != NULL) {
+    // We should only ever have to stop the task if this is the first call to
+    // Disable.
+    ASSERT(!isolate->is_background_compiler_disabled());
+    BackgroundCompiler::Stop(isolate);
+  }
+  ASSERT(isolate->background_compiler() == NULL);
+  isolate->disable_background_compiler();
+}
+
+
+bool BackgroundCompiler::IsDisabled() {
+  Thread* thread = Thread::Current();
+  ASSERT(thread != NULL);
+  Isolate* isolate = thread->isolate();
+  MutexLocker ml(isolate->mutex());
+  return isolate->is_background_compiler_disabled();
+}
+
+
+void BackgroundCompiler::Enable() {
+  Thread* thread = Thread::Current();
+  ASSERT(thread != NULL);
+  Isolate* isolate = thread->isolate();
+  MutexLocker ml(isolate->mutex());
+  isolate->enable_background_compiler();
+}
+
+
 void BackgroundCompiler::EnsureInit(Thread* thread) {
   ASSERT(thread->IsMutatorThread());
   // Finalize NoSuchMethodError, _Mint; occasionally needed in optimized
@@ -2114,6 +2170,22 @@
   UNREACHABLE();
 }
 
+
+void BackgroundCompiler::Disable() {
+  UNREACHABLE();
+}
+
+
+void BackgroundCompiler::Enable() {
+  UNREACHABLE();
+}
+
+
+bool BackgroundCompiler::IsDisabled() {
+  UNREACHABLE();
+  return true;
+}
+
 #endif  // DART_PRECOMPILED_RUNTIME
 
 }  // namespace dart
diff --git a/runtime/vm/compiler.h b/runtime/vm/compiler.h
index 4e2a550..1e8e3fc 100644
--- a/runtime/vm/compiler.h
+++ b/runtime/vm/compiler.h
@@ -38,7 +38,7 @@
       ParsedFunction* parsed_function,
       const ZoneGrowableArray<const ICData*>& ic_data_array,
       intptr_t osr_id) = 0;
-  virtual void FinalizeCompilation() = 0;
+  virtual void FinalizeCompilation(FlowGraph* flow_graph) = 0;
   virtual ~CompilationPipeline() { }
 };
 
@@ -53,7 +53,7 @@
       const ZoneGrowableArray<const ICData*>& ic_data_array,
       intptr_t osr_id);
 
-  virtual void FinalizeCompilation();
+  virtual void FinalizeCompilation(FlowGraph* flow_graph);
 };
 
 
@@ -69,7 +69,7 @@
       const ZoneGrowableArray<const ICData*>& ic_data_array,
       intptr_t osr_id);
 
-  virtual void FinalizeCompilation();
+  virtual void FinalizeCompilation(FlowGraph* flow_graph);
 
  private:
   IndirectGotoInstr* backtrack_goto_;
@@ -163,8 +163,15 @@
   static void EnsureInit(Thread* thread);
 
   // Stops background compiler of the given isolate.
+  // TODO(turnidge): Give Stop and Disable more distinct names.
   static void Stop(Isolate* isolate);
 
+  static void Disable();
+
+  static void Enable();
+
+  static bool IsDisabled();
+
   // Call to optimize a function in the background, enters the function in the
   // compilation queue.
   void CompileOptimized(const Function& function);
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index 5764745..5639af5 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -25,6 +25,41 @@
 #endif
 
 
+// The Linux/Android ABI and the iOS ABI differ in their choice of frame
+// pointer, their treatment of R9, and the interproduceral stack alignment.
+
+// EABI (Linux, Android)
+// See "Procedure Call Standard for the ARM Architecture".
+// R0-R1:  Argument / result / volatile
+// R2-R3:  Argument / volatile
+// R4-R10: Preserved
+// R11:    Frame pointer
+// R12:    Volatile
+// R13:    Stack pointer
+// R14:    Link register
+// R15:    Program counter
+// Stack alignment: 4 bytes always, 8 bytes at public interfaces
+
+// Linux (Debian armhf) and Android also differ in whether floating point
+// arguments are passed in registers. Linux uses hardfp and Android uses
+// softfp. See TargetCPUFeatures::hardfp_supported().
+
+// iOS ABI
+// See "iOS ABI Function Call Guide"
+// R0-R1: Argument / result / volatile
+// R2-R3: Argument / volatile
+// R4-R6: Preserved
+// R7:    Frame pointer
+// R8-R9: Preserved
+// R12:   Volatile
+// R13:   Stack pointer
+// R14:   Link register
+// R15:   Program counter
+// Stack alignment: 4 bytes always, 4 bytes at public interfaces
+
+// iOS passes floating point arguments in registers (hardfp)
+
+
 enum Register {
   R0  =  0,
   R1  =  1,
@@ -46,12 +81,14 @@
   kNoRegister = -1,  // Signals an illegal register.
 
   // Aliases.
-#if defined(TARGET_OS_MACOS)
+#if defined(TARGET_ABI_IOS)
   FP   = R7,
   NOTFP = R11,
-#else
+#elif defined(TARGET_ABI_EABI)
   FP   = R11,
   NOTFP = R7,
+#else
+#error Unknown ABI
 #endif
   IP  = R12,
   SP  = R13,
@@ -268,16 +305,18 @@
 // C++ ABI call registers.
 const RegList kAbiArgumentCpuRegs =
     (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3);
-#if defined(TARGET_OS_MACOS)
+#if defined(TARGET_ABI_IOS)
 const RegList kAbiPreservedCpuRegs =
     (1 << R4)  | (1 << R5) | (1 << R6) | (1 << R8) |
     (1 << R10) | (1 << R11);
 const int kAbiPreservedCpuRegCount = 6;
-#else
+#elif defined(TARGET_ABI_EABI)
 const RegList kAbiPreservedCpuRegs =
     (1 << R4) | (1 << R5) | (1 << R6) | (1 << R7) |
     (1 << R8) | (1 << R9) | (1 << R10);
 const int kAbiPreservedCpuRegCount = 7;
+#else
+#error Unknown ABI
 #endif
 const QRegister kAbiFirstPreservedFpuReg = Q4;
 const QRegister kAbiLastPreservedFpuReg = Q7;
@@ -296,9 +335,9 @@
 // Registers available to Dart that are not preserved by runtime calls.
 const RegList kDartVolatileCpuRegs =
     kDartAvailableCpuRegs & ~kAbiPreservedCpuRegs;
-#if defined(TARGET_OS_MACOS)
+#if defined(TARGET_ABI_IOS)
 const int kDartVolatileCpuRegCount = 6;
-#else
+#elif defined(TARGET_ABI_EABI)
 const int kDartVolatileCpuRegCount = 5;
 #endif
 const QRegister kDartFirstVolatileFpuReg = Q0;
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 0bc7a50..f4821e4 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -115,22 +115,22 @@
 }
 
 
-const char* Dart::InitOnce(const uint8_t* vm_isolate_snapshot,
-                           const uint8_t* instructions_snapshot,
-                           const uint8_t* data_snapshot,
-                           Dart_IsolateCreateCallback create,
-                           Dart_IsolateShutdownCallback shutdown,
-                           Dart_ThreadExitCallback thread_exit,
-                           Dart_FileOpenCallback file_open,
-                           Dart_FileReadCallback file_read,
-                           Dart_FileWriteCallback file_write,
-                           Dart_FileCloseCallback file_close,
-                           Dart_EntropySource entropy_source,
-                           Dart_GetVMServiceAssetsArchive get_service_assets) {
+char* Dart::InitOnce(const uint8_t* vm_isolate_snapshot,
+                     const uint8_t* instructions_snapshot,
+                     const uint8_t* data_snapshot,
+                     Dart_IsolateCreateCallback create,
+                     Dart_IsolateShutdownCallback shutdown,
+                     Dart_ThreadExitCallback thread_exit,
+                     Dart_FileOpenCallback file_open,
+                     Dart_FileReadCallback file_read,
+                     Dart_FileWriteCallback file_write,
+                     Dart_FileCloseCallback file_close,
+                     Dart_EntropySource entropy_source,
+                     Dart_GetVMServiceAssetsArchive get_service_assets) {
   CheckOffsets();
   // TODO(iposva): Fix race condition here.
   if (vm_isolate_ != NULL || !Flags::Initialized()) {
-    return "VM already initialized or flags not initialized.";
+    return strdup("VM already initialized or flags not initialized.");
   }
   set_thread_exit_callback(thread_exit);
   SetFileCallbacks(file_open, file_read, file_write, file_close);
@@ -195,42 +195,43 @@
                                                "VMIsolateSnapshot"));
       const Snapshot* snapshot = Snapshot::SetupFromBuffer(vm_isolate_snapshot);
       if (snapshot == NULL) {
-        return "Invalid vm isolate snapshot seen";
+        return strdup("Invalid vm isolate snapshot seen");
       }
       snapshot_kind_ = snapshot->kind();
+
       if (Snapshot::IncludesCode(snapshot_kind_)) {
         if (snapshot_kind_ == Snapshot::kAppNoJIT) {
 #if defined(DART_PRECOMPILED_RUNTIME)
           vm_isolate_->set_compilation_allowed(false);
           if (!FLAG_precompiled_runtime) {
-            return "Flag --precompilation was not specified";
+            return strdup("Flag --precompilation was not specified");
           }
 #else
-          return "JIT runtime cannot run a precompiled snapshot";
+          return strdup("JIT runtime cannot run a precompiled snapshot");
 #endif
         }
         if (instructions_snapshot == NULL) {
-          return "Missing instructions snapshot";
+          return strdup("Missing instructions snapshot");
         }
         if (data_snapshot == NULL) {
-          return "Missing rodata snapshot";
+          return strdup("Missing rodata snapshot");
         }
         vm_isolate_->SetupInstructionsSnapshotPage(instructions_snapshot);
         vm_isolate_->SetupDataSnapshotPage(data_snapshot);
       } else if (Snapshot::IsFull(snapshot_kind_)) {
 #if defined(DART_PRECOMPILED_RUNTIME)
-        return "Precompiled runtime requires a precompiled snapshot";
+        return strdup("Precompiled runtime requires a precompiled snapshot");
 #else
         if (instructions_snapshot != NULL) {
-          return "Unexpected instructions snapshot";
+          return strdup("Unexpected instructions snapshot");
         }
         if (data_snapshot != NULL) {
-          return "Unexpected rodata snapshot";
+          return strdup("Unexpected rodata snapshot");
         }
         StubCode::InitOnce();
 #endif
       } else {
-        return "Invalid vm isolate snapshot seen";
+        return strdup("Invalid vm isolate snapshot seen");
       }
       VmIsolateSnapshotReader reader(snapshot->kind(),
                                      snapshot->content(),
@@ -240,7 +241,8 @@
                                      T);
       const Error& error = Error::Handle(reader.ReadVmIsolateSnapshot());
       if (!error.IsNull()) {
-        return error.ToErrorCString();
+        // Must copy before leaving the zone.
+        return strdup(error.ToErrorCString());
       }
       NOT_IN_PRODUCT(if (tds.enabled()) {
         tds.SetNumArguments(2);
@@ -262,7 +264,7 @@
       }
     } else {
 #if defined(DART_PRECOMPILED_RUNTIME)
-      return "Precompiled runtime requires a precompiled snapshot";
+      return strdup("Precompiled runtime requires a precompiled snapshot");
 #else
       snapshot_kind_ = Snapshot::kNone;
       StubCode::InitOnce();
@@ -276,7 +278,7 @@
 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
     // Dart VM requires at least SSE2.
     if (!TargetCPUFeatures::sse2_supported()) {
-      return "SSE2 is required.";
+      return strdup("SSE2 is required.");
     }
 #endif
     {
@@ -595,6 +597,58 @@
 }
 
 
+const char* Dart::FeaturesString(Snapshot::Kind kind) {
+  TextBuffer buffer(64);
+
+  // Different fields are included for DEBUG/RELEASE/PRODUCT.
+#if defined(DEBUG)
+  buffer.AddString("debug");
+#elif defined(PRODUCT)
+  buffer.AddString("product");
+#else
+  buffer.AddString("release");
+#endif
+
+  if (Snapshot::IncludesCode(kind)) {
+    // Checked mode affects deopt ids.
+    buffer.AddString(FLAG_enable_asserts ? " asserts" : " no-asserts");
+    buffer.AddString(FLAG_enable_type_checks ? " type-checks"
+                                             : " no-type-checks");
+
+    // Generated code must match the host architecture and ABI.
+#if defined(TARGET_ARCH_ARM)
+#if defined(TARGET_ABI_IOS)
+    buffer.AddString(" arm-ios");
+#elif defined(TARGET_ABI_EABI)
+    buffer.AddString(" arm-eabi");
+#else
+#error Unknown ABI
+#endif
+    buffer.AddString(TargetCPUFeatures::hardfp_supported() ? " hardfp"
+                                                           : " softfp");
+#elif defined(TARGET_ARCH_ARM64)
+    buffer.AddString(" arm64");
+#elif defined(TARGET_ARCH_MIPS)
+    buffer.AddString(" mips");
+#elif defined(TARGET_ARCH_IA32)
+    buffer.AddString(" ia32");
+#elif defined(TARGET_ARCH_X64)
+#if defined(_WIN64)
+    buffer.AddString(" x64-win");
+#else
+    buffer.AddString(" x64-sysv");
+#endif
+#elif defined(TARGET_ARCH_DBC)
+    buffer.AddString(" dbc");
+#elif defined(TARGET_ARCH_DBC64)
+    buffer.AddString(" dbc64");
+#endif
+  }
+
+  return buffer.Steal();
+}
+
+
 void Dart::RunShutdownCallback() {
   Isolate* isolate = Isolate::Current();
   void* callback_data = isolate->init_callback_data();
diff --git a/runtime/vm/dart.h b/runtime/vm/dart.h
index a21dab2..ea40e43 100644
--- a/runtime/vm/dart.h
+++ b/runtime/vm/dart.h
@@ -21,7 +21,7 @@
 
 class Dart : public AllStatic {
  public:
-  static const char* InitOnce(
+  static char* InitOnce(
       const uint8_t* vm_isolate_snapshot,
       const uint8_t* instructions_snapshot,
       const uint8_t* data_snapshot,
@@ -61,6 +61,8 @@
   static uword AllocateReadOnlyHandle();
   static bool IsReadOnlyHandle(uword address);
 
+  static const char* FeaturesString(Snapshot::Kind kind);
+
   static Snapshot::Kind snapshot_kind() {
     return snapshot_kind_;
   }
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index e980f09..eed7789 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1156,18 +1156,14 @@
     return strdup("Dart_Initialize: "
                   "Setting of unhandled exception callback is not supported.");
   }
-  const char* err_msg = Dart::InitOnce(vm_isolate_snapshot,
-                                       instructions_snapshot,
-                                       data_snapshot,
-                                       create, shutdown,
-                                       thread_exit,
-                                       file_open, file_read, file_write,
-                                       file_close, entropy_source,
-                                       get_service_assets);
-  if (err_msg != NULL) {
-    return strdup(err_msg);
-  }
-  return NULL;
+  return Dart::InitOnce(vm_isolate_snapshot,
+                        instructions_snapshot,
+                        data_snapshot,
+                        create, shutdown,
+                        thread_exit,
+                        file_open, file_read, file_write, file_close,
+                        entropy_source,
+                        get_service_assets);
 }
 
 
@@ -1463,10 +1459,13 @@
     intptr_t* vm_isolate_snapshot_size,
     uint8_t** isolate_snapshot_buffer,
     intptr_t* isolate_snapshot_size) {
-  ASSERT(FLAG_load_deferred_eagerly);
   DARTSCOPE(Thread::Current());
   API_TIMELINE_DURATION;
   Isolate* I = T->isolate();
+  if (!FLAG_load_deferred_eagerly) {
+    return Dart_NewApiError(
+        "Creating full snapshots requires --load_deferred_eagerly");
+  }
   if (vm_isolate_snapshot_buffer != NULL &&
       vm_isolate_snapshot_size == NULL) {
     RETURN_NULL_ERROR(vm_isolate_snapshot_size);
@@ -5239,7 +5238,7 @@
     return Api::NewError("%s expects parameter 'buffer' to be a script type"
                          " snapshot with a valid length.", CURRENT_FUNC);
   }
-  if (!snapshot->IsScriptSnapshot()) {
+  if (snapshot->kind() != Snapshot::kScript) {
     return Api::NewError("%s expects parameter 'buffer' to be a script type"
                          " snapshot.", CURRENT_FUNC);
   }
@@ -5648,6 +5647,8 @@
     return state;
   }
 
+  I->DoneFinalizing();
+
   // Now that the newly loaded classes are finalized, notify the debugger
   // that new code has been loaded. If there are latent breakpoints in
   // the new code, the debugger convert them to unresolved source breakpoints.
@@ -6156,7 +6157,6 @@
     intptr_t* isolate_snapshot_size,
     uint8_t** assembly_buffer,
     intptr_t* assembly_size) {
-  ASSERT(FLAG_load_deferred_eagerly);
   API_TIMELINE_DURATION;
   DARTSCOPE(Thread::Current());
   Isolate* I = T->isolate();
@@ -6164,6 +6164,7 @@
     return Dart_NewApiError("Isolate is not precompiled. "
                             "Did you forget to call Dart_Precompile?");
   }
+  ASSERT(FLAG_load_deferred_eagerly);
   if (vm_isolate_snapshot_buffer == NULL) {
     RETURN_NULL_ERROR(vm_isolate_snapshot_buffer);
   }
@@ -6182,6 +6183,9 @@
   if (assembly_size == NULL) {
     RETURN_NULL_ERROR(assembly_size);
   }
+
+  NOT_IN_PRODUCT(TimelineDurationScope tds2(T, Timeline::GetIsolateStream(),
+                                            "WriteAppAOTSnapshot"));
   AssemblyInstructionsWriter instructions_writer(assembly_buffer,
                                                  ApiReallocate,
                                                  2 * MB /* initial_size */);
@@ -6209,7 +6213,6 @@
     intptr_t* instructions_blob_size,
     uint8_t** rodata_blob_buffer,
     intptr_t* rodata_blob_size) {
-  ASSERT(FLAG_load_deferred_eagerly);
   API_TIMELINE_DURATION;
   DARTSCOPE(Thread::Current());
   Isolate* I = T->isolate();
@@ -6217,6 +6220,7 @@
     return Dart_NewApiError("Isolate is not precompiled. "
                             "Did you forget to call Dart_Precompile?");
   }
+  ASSERT(FLAG_load_deferred_eagerly);
   if (vm_isolate_snapshot_buffer == NULL) {
     RETURN_NULL_ERROR(vm_isolate_snapshot_buffer);
   }
@@ -6241,6 +6245,9 @@
   if (rodata_blob_size == NULL) {
     RETURN_NULL_ERROR(instructions_blob_size);
   }
+
+  NOT_IN_PRODUCT(TimelineDurationScope tds2(T, Timeline::GetIsolateStream(),
+                                            "WriteAppAOTSnapshot"));
   BlobInstructionsWriter instructions_writer(instructions_blob_buffer,
                                              rodata_blob_buffer,
                                              ApiReallocate,
@@ -6303,10 +6310,13 @@
     intptr_t* instructions_blob_size,
     uint8_t** rodata_blob_buffer,
     intptr_t* rodata_blob_size) {
-  ASSERT(FLAG_load_deferred_eagerly);
   API_TIMELINE_DURATION;
   DARTSCOPE(Thread::Current());
   Isolate* I = T->isolate();
+  if (!FLAG_load_deferred_eagerly) {
+    return Dart_NewApiError(
+        "Creating full snapshots requires --load_deferred_eagerly");
+  }
   if (vm_isolate_snapshot_buffer == NULL) {
     RETURN_NULL_ERROR(vm_isolate_snapshot_buffer);
   }
@@ -6338,6 +6348,8 @@
   }
   I->StopBackgroundCompiler();
 
+  NOT_IN_PRODUCT(TimelineDurationScope tds2(T, Timeline::GetIsolateStream(),
+                                            "WriteAppJITSnapshot"));
   BlobInstructionsWriter instructions_writer(instructions_blob_buffer,
                                              rodata_blob_buffer,
                                              ApiReallocate,
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 3b0f238..f6e8bb7 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -9714,8 +9714,7 @@
   GlobalTimelineThreadData()
       : monitor_(new Monitor()),
         data_(new AppendData()),
-        running_(true),
-        join_id_(OSThread::kInvalidThreadJoinId) {
+        running_(true) {
   }
 
   ~GlobalTimelineThreadData() {
@@ -9733,16 +9732,13 @@
   AppendData* data() const { return data_; }
   uint8_t* buffer() const { return data_->buffer; }
   intptr_t buffer_length() const { return data_->buffer_length; }
-  ThreadJoinId join_id() const { return join_id_; }
 
   void set_running(bool running) { running_ = running; }
-  void set_join_id(ThreadJoinId join_id) { join_id_ = join_id; }
 
  private:
   Monitor* monitor_;
   AppendData* data_;
   bool running_;
-  ThreadJoinId join_id_;
 };
 
 
@@ -9758,7 +9754,6 @@
         Dart_GlobalTimelineGetTrace(AppendStreamConsumer, data->data());
     EXPECT(success);
     data->set_running(false);
-    data->set_join_id(OSThread::Current()->join_id());
     ml.Notify();
   }
 }
@@ -9805,7 +9800,6 @@
     }
     buffer = reinterpret_cast<char*>(data.buffer());
     buffer_length = data.buffer_length();
-    OSThread::Join(data.join_id());
   }
   EXPECT(buffer_length > 0);
   EXPECT(buffer != NULL);
@@ -9847,7 +9841,6 @@
     }
     buffer = reinterpret_cast<char*>(data2.buffer());
     buffer_length = data2.buffer_length();
-    OSThread::Join(data2.join_id());
   }
 
   EXPECT(buffer_length > 0);
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 6d11f18..64476a9 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -263,114 +263,51 @@
 }
 
 
-void DebuggerEvent::UpdateTimestamp() {
-  timestamp_ = OS::GetCurrentTimeMillis();
+bool Debugger::NeedsIsolateEvents() {
+  return ((isolate_ != Dart::vm_isolate()) &&
+          !ServiceIsolate::IsServiceIsolateDescendant(isolate_) &&
+          ((event_handler_ != NULL) || Service::isolate_stream.enabled()));
 }
 
 
-bool Debugger::HasAnyEventHandler() {
-  return ((event_handler_ != NULL) ||
-          Service::isolate_stream.enabled() ||
+bool Debugger::NeedsDebugEvents() {
+  ASSERT(isolate_ != Dart::vm_isolate() &&
+         !ServiceIsolate::IsServiceIsolateDescendant(isolate_));
+  return (FLAG_warn_on_pause_with_no_debugger ||
+          (event_handler_ != NULL) ||
           Service::debug_stream.enabled());
 }
 
 
-bool Debugger::HasDebugEventHandler() {
-  return ((event_handler_ != NULL) ||
-          Service::debug_stream.enabled());
-}
+void Debugger::InvokeEventHandler(ServiceEvent* event) {
+  ASSERT(!event->IsPause());  // For pause events, call Pause instead.
+  Service::HandleEvent(event);
 
-
-static bool ServiceNeedsDebuggerEvent(DebuggerEvent::EventType type) {
-  switch (type) {
-    case DebuggerEvent::kBreakpointResolved:
-      // kBreakpointResolved events are handled differently in the vm
-      // service, so suppress them here.
-      return false;
-
-    case DebuggerEvent::kBreakpointReached:
-    case DebuggerEvent::kExceptionThrown:
-    case DebuggerEvent::kIsolateInterrupted:
-      return (Service::debug_stream.enabled() ||
-              FLAG_warn_on_pause_with_no_debugger);
-
-    case DebuggerEvent::kIsolateCreated:
-    case DebuggerEvent::kIsolateShutdown:
-      return Service::isolate_stream.enabled();
-
-    default:
-      UNREACHABLE();
-      return false;
-  }
-}
-
-
-void Debugger::InvokeEventHandler(DebuggerEvent* event) {
-  // Give the event to the Service first, as the debugger event handler
-  // may go into a message loop and the Service will not.
-  //
-  // kBreakpointResolved events are handled differently in the vm
-  // service, so suppress them here.
-  if (ServiceNeedsDebuggerEvent(event->type())) {
-    ServiceEvent service_event(event);
-    Service::HandleEvent(&service_event);
-  }
-
-  {
+  // Call the embedder's event handler, if it exists.
+  if (event_handler_ != NULL) {
     TransitionVMToNative transition(Thread::Current());
-    if ((FLAG_steal_breakpoints || (event_handler_ == NULL)) &&
-        event->IsPauseEvent()) {
-      // We allow the embedder's default breakpoint handler to be overridden.
-      isolate_->PauseEventHandler();
-    } else if (event_handler_ != NULL) {
-      (*event_handler_)(event);
-    }
-  }
-
-  if (ServiceNeedsDebuggerEvent(event->type()) && event->IsPauseEvent()) {
-    // If we were paused, notify the service that we have resumed.
-    const Error& error =
-        Error::Handle(Thread::Current()->sticky_error());
-    ASSERT(error.IsNull() ||
-           error.IsUnwindError() ||
-           error.IsUnhandledException());
-
-    // Only send a resume event when the isolate is not unwinding.
-    if (!error.IsUnwindError()) {
-      ServiceEvent service_event(event->isolate(), ServiceEvent::kResume);
-      service_event.set_top_frame(event->top_frame());
-      Service::HandleEvent(&service_event);
-    }
+    (*event_handler_)(event);
   }
 }
 
 
-void Debugger::SignalIsolateEvent(DebuggerEvent::EventType type) {
-  if (HasAnyEventHandler()) {
-    DebuggerEvent event(isolate_, type);
-    ASSERT(event.isolate_id() != ILLEGAL_ISOLATE_ID);
-    if (type == DebuggerEvent::kIsolateInterrupted) {
-      DebuggerStackTrace* trace = CollectStackTrace();
-      if (trace->Length() > 0) {
-        event.set_top_frame(trace->FrameAt(0));
-      }
-      ASSERT(stack_trace_ == NULL);
-      stack_trace_ = trace;
-      resume_action_ = kContinue;
-      Pause(&event);
-      HandleSteppingRequest(trace);
-      stack_trace_ = NULL;
-    } else {
-      InvokeEventHandler(&event);
-    }
+RawError* Debugger::PauseInterrupted() {
+  if (ignore_breakpoints_ || IsPaused()) {
+    // We don't let the isolate get interrupted if we are already
+    // paused or ignoring breakpoints.
+    return Error::null();
   }
-}
-
-
-RawError* Debugger::SignalIsolateInterrupted() {
-  if (HasDebugEventHandler()) {
-    SignalIsolateEvent(DebuggerEvent::kIsolateInterrupted);
+  ServiceEvent event(isolate_, ServiceEvent::kPauseInterrupted);
+  DebuggerStackTrace* trace = CollectStackTrace();
+  if (trace->Length() > 0) {
+    event.set_top_frame(trace->FrameAt(0));
   }
+  ASSERT(stack_trace_ == NULL);
+  stack_trace_ = trace;
+  resume_action_ = kContinue;
+  Pause(&event);
+  HandleSteppingRequest(trace);
+  stack_trace_ = NULL;
 
   // If any error occurred while in the debug message loop, return it here.
   const Error& error = Error::Handle(Thread::Current()->sticky_error());
@@ -380,14 +317,14 @@
 }
 
 
-// The vm service handles breakpoint notifications in a different way
-// than the regular debugger breakpoint notifications.
-static void SendServiceBreakpointEvent(ServiceEvent::EventKind kind,
-                                       Breakpoint* bpt) {
-  if (Service::debug_stream.enabled()) {
-    ServiceEvent service_event(Isolate::Current(), kind);
-    service_event.set_breakpoint(bpt);
-    Service::HandleEvent(&service_event);
+void Debugger::SendBreakpointEvent(ServiceEvent::EventKind kind,
+                                   Breakpoint* bpt) {
+  if (NeedsDebugEvents()) {
+    // TODO(turnidge): Currently we send single-shot breakpoint events
+    // to the vm service.  Do we want to change this?
+    ServiceEvent event(isolate_, kind);
+    event.set_breakpoint(bpt);
+    InvokeEventHandler(&event);
   }
 }
 
@@ -397,11 +334,7 @@
   set_breakpoints(bpt);
 
   dbg->SyncBreakpointLocation(this);
-
-  if (IsResolved()) {
-    dbg->SignalBpResolved(bpt);
-  }
-  SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt);
+  dbg->SendBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt);
 }
 
 
@@ -1270,7 +1203,6 @@
     : isolate_(NULL),
       isolate_id_(ILLEGAL_ISOLATE_ID),
       initialized_(false),
-      creation_message_sent_(false),
       next_id_(1),
       latent_locations_(NULL),
       breakpoint_locations_(NULL),
@@ -1322,10 +1254,9 @@
     bpt->Disable();
     delete bpt;
   }
-  // Signal isolate shutdown event, but only if we previously sent the creation
-  // event.
-  if (creation_message_sent_) {
-    SignalIsolateEvent(DebuggerEvent::kIsolateShutdown);
+  if (NeedsIsolateEvents()) {
+    ServiceEvent event(isolate_, ServiceEvent::kIsolateExit);
+    InvokeEventHandler(&event);
   }
 }
 
@@ -1451,15 +1382,6 @@
 }
 
 
-void Debugger::SignalBpResolved(Breakpoint* bpt) {
-  if (HasDebugEventHandler() && !bpt->IsSingleShot()) {
-    DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointResolved);
-    event.set_breakpoint(bpt);
-    InvokeEventHandler(&event);
-  }
-}
-
-
 ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate,
                                             uword pc,
                                             StackFrame* frame,
@@ -1667,7 +1589,7 @@
 }
 
 
-void Debugger::SignalExceptionThrown(const Instance& exc) {
+void Debugger::PauseException(const Instance& exc) {
   // We ignore this exception event when the VM is executing code invoked
   // by the debugger to evaluate variables values, when we see a nested
   // breakpoint or exception event, or if the debugger is not
@@ -1681,7 +1603,7 @@
   if (!ShouldPauseOnException(stack_trace, exc)) {
     return;
   }
-  DebuggerEvent event(isolate_, DebuggerEvent::kExceptionThrown);
+  ServiceEvent event(isolate_, ServiceEvent::kPauseException);
   event.set_exception(&exc);
   if (stack_trace->Length() > 0) {
     event.set_top_frame(stack_trace->FrameAt(0));
@@ -2236,6 +2158,11 @@
 
 Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url,
                                           intptr_t line_number) {
+  // Prevent future tests from calling this function in the wrong
+  // execution state.  If you hit this assert, consider using
+  // Dart_SetBreakpoint instead.
+  ASSERT(Thread::Current()->execution_state() == Thread::kThreadInVM);
+
   BreakpointLocation* loc =
       BreakpointLocationAtLineCol(script_url, line_number, -1 /* no column */);
   if (loc != NULL) {
@@ -2248,6 +2175,11 @@
 Breakpoint* Debugger::SetBreakpointAtLineCol(const String& script_url,
                                              intptr_t line_number,
                                              intptr_t column_number) {
+  // Prevent future tests from calling this function in the wrong
+  // execution state.  If you hit this assert, consider using
+  // Dart_SetBreakpoint instead.
+  ASSERT(Thread::Current()->execution_state() == Thread::kThreadInVM);
+
   BreakpointLocation* loc = BreakpointLocationAtLineCol(script_url,
                                                         line_number,
                                                         column_number);
@@ -2558,23 +2490,52 @@
 }
 
 
-void Debugger::Pause(DebuggerEvent* event) {
-  ASSERT(!IsPaused());  // No recursive pausing.
+void Debugger::Pause(ServiceEvent* event) {
+  ASSERT(event->IsPause());      // Should call InvokeEventHandler instead.
+  ASSERT(!ignore_breakpoints_);  // We shouldn't get here when ignoring bpts.
+  ASSERT(!IsPaused());           // No recursive pausing.
   ASSERT(obj_cache_ == NULL);
 
   pause_event_ = event;
   pause_event_->UpdateTimestamp();
   obj_cache_ = new RemoteObjectCache(64);
 
-  // We are about to invoke the debuggers event handler. Disable interrupts
-  // for this thread while waiting for debug commands over the service protocol.
+  // We are about to invoke the debugger's event handler. Disable
+  // interrupts for this thread while waiting for debug commands over
+  // the service protocol.
   {
     Thread* thread = Thread::Current();
     DisableThreadInterruptsScope dtis(thread);
     TimelineDurationScope tds(thread,
                               Timeline::GetDebuggerStream(),
                               "Debugger Pause");
-    InvokeEventHandler(event);
+
+    // Send the pause event.
+    Service::HandleEvent(event);
+
+    {
+      TransitionVMToNative transition(Thread::Current());
+      if (FLAG_steal_breakpoints || (event_handler_ == NULL)) {
+        // We allow the embedder's default breakpoint handler to be overridden.
+        isolate_->PauseEventHandler();
+      } else if (event_handler_ != NULL) {
+        (*event_handler_)(event);
+      }
+    }
+
+    // Notify the service that we have resumed.
+    const Error& error =
+        Error::Handle(Thread::Current()->sticky_error());
+    ASSERT(error.IsNull() ||
+           error.IsUnwindError() ||
+           error.IsUnhandledException());
+
+    // Only send a resume event when the isolate is not unwinding.
+    if (!error.IsUnwindError()) {
+      ServiceEvent resume_event(event->isolate(), ServiceEvent::kResume);
+      resume_event.set_top_frame(event->top_frame());
+      Service::HandleEvent(&resume_event);
+    }
   }
 
   pause_event_ = NULL;
@@ -2657,7 +2618,7 @@
     bpt = NULL;
   }
 
-  DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointReached);
+  ServiceEvent event(isolate_, ServiceEvent::kPauseBreakpoint);
   event.set_top_frame(top_frame);
   event.set_breakpoint(bpt);
   event.set_at_async_jump(IsAtAsyncJump(top_frame));
@@ -2684,7 +2645,7 @@
   return false;
 }
 
-RawError* Debugger::DebuggerStepCallback() {
+RawError* Debugger::PauseStepping() {
   ASSERT(isolate_->single_step());
   // Don't pause recursively.
   if (IsPaused()) {
@@ -2741,7 +2702,7 @@
   ASSERT(stack_trace_ == NULL);
   stack_trace_ = CollectStackTrace();
   // If this step callback is part of stepping over an await statement,
-  // we saved the synthetic async breakpoint in SignalBpReached. We report
+  // we saved the synthetic async breakpoint in PauseBreakpoint. We report
   // that we are paused at that breakpoint and then delete it after continuing.
   SignalPausedEvent(frame, synthetic_async_breakpoint_);
   if (synthetic_async_breakpoint_ != NULL) {
@@ -2758,7 +2719,7 @@
 }
 
 
-RawError* Debugger::SignalBpReached() {
+RawError* Debugger::PauseBreakpoint() {
   // We ignore this breakpoint when the VM is executing code invoked
   // by the debugger to evaluate variables values, or when we see a nested
   // breakpoint or exception event.
@@ -2878,7 +2839,7 @@
 }
 
 
-void Debugger::BreakHere(const String& msg) {
+void Debugger::PauseDeveloper(const String& msg) {
   // We ignore this breakpoint when the VM is executing code invoked
   // by the debugger to evaluate variables values, or when we see a nested
   // breakpoint or exception event.
@@ -2886,7 +2847,7 @@
     return;
   }
 
-  if (!HasDebugEventHandler()) {
+  if (!NeedsDebugEvents()) {
     OS::Print("Hit debugger!");
   }
 
@@ -2897,9 +2858,9 @@
 
   // TODO(johnmccutchan): Send |msg| to Observatory.
 
-  // We are in the native call to Debugger_breakHere or Debugger_breakHereIf,
-  // the developer gets a better experience by not seeing this call. To
-  // accomplish this, we continue execution until the call exits (step out).
+  // We are in the native call to Developer_debugger.  the developer
+  // gets a better experience by not seeing this call. To accomplish
+  // this, we continue execution until the call exits (step out).
   SetStepOut();
   HandleSteppingRequest(stack_trace_);
 
@@ -2914,19 +2875,17 @@
   isolate_ = isolate;
 
   // Use the isolate's control port as the isolate_id for debugging.
-  // This port will be used as a unique ID to represent the isolate in the
-  // debugger wire protocol messages.
+  // This port will be used as a unique ID to represent the isolate in
+  // the debugger embedder api.
   isolate_id_ = isolate_->main_port();
   initialized_ = true;
 }
 
 
 void Debugger::NotifyIsolateCreated() {
-  // Signal isolate creation event.
-  if ((isolate_ != Dart::vm_isolate()) &&
-      !ServiceIsolate::IsServiceIsolateDescendant(isolate_)) {
-    SignalIsolateEvent(DebuggerEvent::kIsolateCreated);
-    creation_message_sent_ = true;
+  if (NeedsIsolateEvents()) {
+    ServiceEvent event(isolate_, ServiceEvent::kIsolateStart);
+    InvokeEventHandler(&event);
   }
 }
 
@@ -3028,8 +2987,7 @@
                       requested_end_pos.ToCString(),
                       loc->requested_column_number());
           }
-          SignalBpResolved(bpt);
-          SendServiceBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt);
+          SendBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt);
           bpt = bpt->next();
         }
       }
@@ -3218,12 +3176,10 @@
           prev_bpt->set_next(curr_bpt->next());
         }
 
-        SendServiceBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_bpt);
+        SendBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_bpt);
 
         // Remove references from the current debugger pause event.
-        if (pause_event_ != NULL &&
-            pause_event_->type() == DebuggerEvent::kBreakpointReached &&
-            pause_event_->breakpoint() == curr_bpt) {
+        if (pause_event_ != NULL && pause_event_->breakpoint() == curr_bpt) {
           pause_event_->set_breakpoint(NULL);
         }
         break;
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index ab83339..1d7e1ce 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -9,6 +9,7 @@
 
 #include "vm/object.h"
 #include "vm/port.h"
+#include "vm/service_event.h"
 
 namespace dart {
 
@@ -369,105 +370,9 @@
 };
 
 
-class DebuggerEvent {
- public:
-  enum EventType {
-    kBreakpointReached = 1,
-    kBreakpointResolved = 2,
-    kExceptionThrown = 3,
-    kIsolateCreated = 4,
-    kIsolateShutdown = 5,
-    kIsolateInterrupted = 6,
-  };
-
-  explicit DebuggerEvent(Isolate* isolate, EventType event_type)
-      : isolate_(isolate),
-        type_(event_type),
-        top_frame_(NULL),
-        breakpoint_(NULL),
-        exception_(NULL),
-        async_continuation_(NULL),
-        at_async_jump_(false),
-        timestamp_(-1) {}
-
-  Isolate* isolate() const { return isolate_; }
-
-  EventType type() const { return type_; }
-
-  bool IsPauseEvent() const {
-    return (type_ == kBreakpointReached ||
-            type_ == kIsolateInterrupted ||
-            type_ == kExceptionThrown);
-  }
-
-  ActivationFrame* top_frame() const {
-    ASSERT(IsPauseEvent());
-    return top_frame_;
-  }
-  void set_top_frame(ActivationFrame* frame) {
-    ASSERT(IsPauseEvent());
-    top_frame_ = frame;
-  }
-
-  Breakpoint* breakpoint() const {
-    ASSERT(type_ == kBreakpointReached || type_ == kBreakpointResolved);
-    return breakpoint_;
-  }
-  void set_breakpoint(Breakpoint* bpt) {
-    ASSERT(type_ == kBreakpointReached || type_ == kBreakpointResolved);
-    breakpoint_ = bpt;
-  }
-
-  const Object* exception() const {
-    ASSERT(type_ == kExceptionThrown);
-    return exception_;
-  }
-  void set_exception(const Object* exception) {
-    ASSERT(type_ == kExceptionThrown);
-    exception_ = exception;
-  }
-
-  const Object* async_continuation() const {
-    ASSERT(type_ == kBreakpointReached);
-    return async_continuation_;
-  }
-  void set_async_continuation(const Object* closure) {
-    ASSERT(type_ == kBreakpointReached);
-    async_continuation_ = closure;
-  }
-
-  bool at_async_jump() const {
-    return at_async_jump_;
-  }
-  void set_at_async_jump(bool value) {
-    at_async_jump_ = value;
-  }
-
-  Dart_Port isolate_id() const {
-    return isolate_->main_port();
-  }
-
-  void UpdateTimestamp();
-
-  int64_t timestamp() const {
-    return timestamp_;
-  }
-
- private:
-  Isolate* isolate_;
-  EventType type_;
-  ActivationFrame* top_frame_;
-  Breakpoint* breakpoint_;
-  const Object* exception_;
-  const Object* async_continuation_;
-  bool at_async_jump_;
-  int64_t timestamp_;
-};
-
-
 class Debugger {
  public:
-  typedef void EventHandler(DebuggerEvent* event);
+  typedef void EventHandler(ServiceEvent* event);
 
   Debugger();
   ~Debugger();
@@ -525,7 +430,7 @@
   // is not paused, this returns NULL.  Note that the debugger can be
   // paused for breakpoints, isolate interruption, and (sometimes)
   // exceptions.
-  const DebuggerEvent* PauseEvent() const { return pause_event_; }
+  const ServiceEvent* PauseEvent() const { return pause_event_; }
 
   void SetExceptionPauseInfo(Dart_ExceptionPauseInfo pause_info);
   Dart_ExceptionPauseInfo GetExceptionPauseInfo() const;
@@ -580,14 +485,21 @@
   RawObject* GetStaticField(const Class& cls,
                             const String& field_name);
 
-  RawError* SignalBpReached();
-  RawError* DebuggerStepCallback();
-  RawError* SignalIsolateInterrupted();
+  // Pause execution for a breakpoint.  Called from generated code.
+  RawError* PauseBreakpoint();
 
-  void BreakHere(const String& msg);
+  // Pause execution due to stepping.  Called from generated code.
+  RawError* PauseStepping();
 
-  void SignalExceptionThrown(const Instance& exc);
-  void SignalIsolateEvent(DebuggerEvent::EventType type);
+  // Pause execution due to isolate interrupt.
+  RawError* PauseInterrupted();
+
+  // Pause execution due to an uncaught exception.
+  void PauseException(const Instance& exc);
+
+  // Pause execution due to a call to the debugger() function from
+  // Dart.
+  void PauseDeveloper(const String& msg);
 
   RawCode* GetPatchedStubAddress(uword breakpoint_address);
 
@@ -606,9 +518,12 @@
     kSingleStep
   };
 
-  static bool HasAnyEventHandler();
-  static bool HasDebugEventHandler();
-  void InvokeEventHandler(DebuggerEvent* event);
+  bool NeedsIsolateEvents();
+  bool NeedsDebugEvents();
+  void InvokeEventHandler(ServiceEvent* event);
+
+  void SendBreakpointEvent(ServiceEvent::EventKind kind, Breakpoint* bpt);
+
   bool IsAtAsyncJump(ActivationFrame* top_frame);
   void FindCompiledFunctions(const Script& script,
                              TokenPosition start_pos,
@@ -655,7 +570,6 @@
                                      StackFrame* frame,
                                      const Code& code);
   static DebuggerStackTrace* CollectStackTrace();
-  void SignalBpResolved(Breakpoint *bpt);
   void SignalPausedEvent(ActivationFrame* top_frame,
                          Breakpoint* bpt);
 
@@ -671,7 +585,7 @@
 
   // Handles any events which pause vm execution.  Breakpoints,
   // interrupts, etc.
-  void Pause(DebuggerEvent* event);
+  void Pause(ServiceEvent* event);
 
   void HandleSteppingRequest(DebuggerStackTrace* stack_trace,
                              bool skip_next_step = false);
@@ -679,7 +593,6 @@
   Isolate* isolate_;
   Dart_Port isolate_id_;  // A unique ID for the isolate in the debugger.
   bool initialized_;
-  bool creation_message_sent_;  // The creation message has been sent.
 
   // ID number generator.
   intptr_t next_id_;
@@ -700,7 +613,7 @@
   // is not paused, this is NULL.  Note that the debugger can be
   // paused for breakpoints, isolate interruption, and (sometimes)
   // exceptions.
-  DebuggerEvent* pause_event_;
+  ServiceEvent* pause_event_;
 
   // An id -> object map.  Valid only while IsPaused().
   RemoteObjectCache* obj_cache_;
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index 4bfcae1..957bd6f 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -110,13 +110,13 @@
 static Dart_IsolateEventHandler* isolate_event_handler = NULL;
 
 
-static void DebuggerEventHandler(DebuggerEvent* event) {
+static void DebuggerEventHandler(ServiceEvent* event) {
   Thread* thread = Thread::Current();
   Isolate* isolate = thread->isolate();
   ASSERT(isolate != NULL);
   Dart_EnterScope();
   Dart_IsolateId isolate_id = isolate->debugger()->GetIsolateId();
-  if (event->type() == DebuggerEvent::kBreakpointReached) {
+  if (event->kind() == ServiceEvent::kPauseBreakpoint) {
     if (paused_event_handler != NULL) {
       Dart_CodeLocation location;
       ActivationFrame* top_frame = event->top_frame();
@@ -131,10 +131,13 @@
       }
       (*paused_event_handler)(isolate_id, bp_id, location);
     }
-  } else if (event->type() == DebuggerEvent::kBreakpointResolved) {
-    if (bp_resolved_handler != NULL) {
-      Breakpoint* bpt = event->breakpoint();
-      ASSERT(bpt != NULL);
+  } else if (event->kind() == ServiceEvent::kBreakpointAdded ||
+             event->kind() == ServiceEvent::kBreakpointResolved) {
+    Breakpoint* bpt = event->breakpoint();
+    ASSERT(bpt != NULL);
+    if (bp_resolved_handler != NULL &&
+        bpt->bpt_location()->IsResolved() &&
+        !bpt->IsSingleShot()) {
       Dart_CodeLocation location;
       Zone* zone = thread->zone();
       Library& library = Library::Handle(zone);
@@ -146,7 +149,9 @@
       location.token_pos = token_pos.Pos();
       (*bp_resolved_handler)(isolate_id, bpt->id(), location);
     }
-  } else if (event->type() == DebuggerEvent::kExceptionThrown) {
+  } else if (event->kind() == ServiceEvent::kBreakpointRemoved) {
+    // Ignore.
+  } else if (event->kind() == ServiceEvent::kPauseException) {
     if (exc_thrown_handler != NULL) {
       Dart_Handle exception =
           Api::NewHandle(thread, event->exception()->raw());
@@ -154,15 +159,15 @@
       reinterpret_cast<Dart_StackTrace>(isolate->debugger()->StackTrace());
       (*exc_thrown_handler)(isolate_id, exception, trace);
     }
-  } else if (event->type() == DebuggerEvent::kIsolateCreated) {
+  } else if (event->kind() == ServiceEvent::kIsolateStart) {
     if (isolate_event_handler != NULL) {
       (*isolate_event_handler)(event->isolate_id(), kCreated);
     }
-  } else if (event->type() == DebuggerEvent::kIsolateInterrupted) {
+  } else if (event->kind() == ServiceEvent::kPauseInterrupted) {
     if (isolate_event_handler != NULL) {
       (*isolate_event_handler)(event->isolate_id(), kInterrupted);
     }
-  } else if (event->type() == DebuggerEvent::kIsolateShutdown) {
+  } else if (event->kind() == ServiceEvent::kIsolateExit) {
     if (isolate_event_handler != NULL) {
       (*isolate_event_handler)(event->isolate_id(), kShutdown);
     }
diff --git a/runtime/vm/debugger_test.cc b/runtime/vm/debugger_test.cc
index ffe3241..8b8b84e 100644
--- a/runtime/vm/debugger_test.cc
+++ b/runtime/vm/debugger_test.cc
@@ -10,6 +10,8 @@
 
 #ifndef PRODUCT
 
+DECLARE_FLAG(bool, remove_script_timestamps_for_test);
+
 // Search for the formatted string in buffer.
 //
 // TODO(turnidge): This function obscures the line number of failing
@@ -38,6 +40,7 @@
       "  x.add('too');\n"
       "  return x.toString();\n"
       "}\n";
+  SetFlagScope<bool> sfs(&FLAG_remove_script_timestamps_for_test, true);
   Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
   EXPECT_VALID(lib);
   Library& vmlib = Library::Handle();
@@ -46,7 +49,6 @@
 
   Isolate* isolate = Isolate::Current();
   Debugger* debugger = isolate->debugger();
-  const String& url = String::Handle(String::New(TestCase::url()));
 
   // Empty case.
   {
@@ -59,8 +61,9 @@
   }
 
   // Test with a couple of breakpoints.
-  debugger->SetBreakpointAtLine(url, 2);
-  debugger->SetBreakpointAtLine(url, 3);
+  Dart_Handle url = NewString(TestCase::url());
+  EXPECT_VALID(Dart_SetBreakpoint(url, 2));
+  EXPECT_VALID(Dart_SetBreakpoint(url, 3));
   {
     JSONStream js;
     {
@@ -73,14 +76,14 @@
         "\"breakpointNumber\":2,\"resolved\":false,"
         "\"location\":{\"type\":\"UnresolvedSourceLocation\","
         "\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
-        "\"id\":\"libraries\\/%" Pd "\\/scripts\\/test-lib\","
+        "\"id\":\"libraries\\/%" Pd "\\/scripts\\/test-lib\\/0\","
         "\"uri\":\"test-lib\","
         "\"_kind\":\"script\"},\"line\":3}},"
         "{\"type\":\"Breakpoint\",\"fixedId\":true,\"id\":\"breakpoints\\/1\","
         "\"breakpointNumber\":1,\"resolved\":false,"
         "\"location\":{\"type\":\"UnresolvedSourceLocation\","
         "\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
-        "\"id\":\"libraries\\/%" Pd "\\/scripts\\/test-lib\","
+        "\"id\":\"libraries\\/%" Pd "\\/scripts\\/test-lib\\/0\","
         "\"uri\":\"test-lib\","
         "\"_kind\":\"script\"},\"line\":2}}]",
         vmlib.index(), vmlib.index());
@@ -98,9 +101,9 @@
 
   // The debugger knows that it is paused, and why.
   EXPECT(debugger->IsPaused());
-  const DebuggerEvent* event = debugger->PauseEvent();
+  const ServiceEvent* event = debugger->PauseEvent();
   EXPECT(event != NULL);
-  EXPECT(event->type() == DebuggerEvent::kBreakpointReached);
+  EXPECT(event->kind() == ServiceEvent::kPauseBreakpoint);
   saw_paused_event = true;
 }
 
@@ -118,7 +121,6 @@
 
   Isolate* isolate = Isolate::Current();
   Debugger* debugger = isolate->debugger();
-  const String& url = String::Handle(String::New(TestCase::url()));
 
   // No pause event.
   EXPECT(!debugger->IsPaused());
@@ -128,7 +130,7 @@
   Dart_SetPausedEventHandler(InspectPausedEvent);
 
   // Set a breakpoint and run.
-  debugger->SetBreakpointAtLine(url, 2);
+  EXPECT_VALID(Dart_SetBreakpoint(NewString(TestCase::url()), 2));
   Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
   EXPECT_VALID(result);
   EXPECT(Dart_IsString(result));
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index 614b976..1d89239 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -141,7 +141,7 @@
   if (FLAG_support_timeline && (deopt_start_micros_ != 0)) {
     TimelineStream* compiler_stream = Timeline::GetCompilerStream();
     ASSERT(compiler_stream != NULL);
-    if (compiler_stream->Enabled()) {
+    if (compiler_stream->enabled()) {
       // Allocate all Dart objects needed before calling StartEvent,
       // which blocks safe points until Complete is called.
       const Code& code = Code::Handle(zone(), code_);
diff --git a/runtime/vm/disassembler_arm.cc b/runtime/vm/disassembler_arm.cc
index 437bee8..2b0c103 100644
--- a/runtime/vm/disassembler_arm.cc
+++ b/runtime/vm/disassembler_arm.cc
@@ -114,12 +114,14 @@
 // formatting, except for register alias pp (r5).
 // See for example the command "objdump -d <binary file>".
 static const char* reg_names[kNumberOfCpuRegisters] = {
-#if defined(TARGET_OS_MACOS)
+#if defined(TARGET_ABI_IOS)
   "r0", "r1", "r2", "r3", "r4", "pp", "r6", "fp",
   "r8", "r9", "r10", "r11", "ip", "sp", "lr", "pc",
-#else
+#elif defined(TARGET_ABI_EABI)
   "r0", "r1", "r2", "r3", "r4", "pp", "r6", "r7",
   "r8", "r9", "r10", "fp", "ip", "sp", "lr", "pc",
+#else
+#error Unknown ABI
 #endif
 };
 
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index a215851..2cb67e1 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -545,7 +545,7 @@
     Isolate* isolate = thread->isolate();
     if (exception.raw() != isolate->object_store()->out_of_memory() &&
         exception.raw() != isolate->object_store()->stack_overflow()) {
-      isolate->debugger()->SignalExceptionThrown(exception);
+      isolate->debugger()->PauseException(exception);
     }
   }
   // Null object is a valid exception object.
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index 13eeead..ee483ad 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -5,31 +5,39 @@
 #ifndef VM_FLAG_LIST_H_
 #define VM_FLAG_LIST_H_
 
+// Don't use USING_DBC outside of this file.
 #if defined(TARGET_ARCH_DBC)
-#define USING_DBC 1
+#define USING_DBC true
 #else
-#define USING_DBC 0
+#define USING_DBC false
+#endif
+
+// Don't use USING_MULTICORE outside of this file.
+#if defined(ARCH_IS_MULTI_CORE)
+#define USING_MULTICORE true
+#else
+#define USING_MULTICORE false
 #endif
 
 // List of all flags in the VM.
 // Flags can be one of three categories:
 // * P roduct flags: Can be set in any of the deployment modes, including in
 //   production.
-// * D ebug flags: Can only be set in debug VMs, which also have assertions
-//   enabled.
 // * R elease flags: Generally available flags except when building product.
+// * D ebug flags: Can only be set in debug VMs, which also have C++ assertions
+//   enabled.
 // * pre C ompile flags: Generally available flags except when building product
 //   or precompiled runtime.
 //
 // Usage:
 //   P(name, type, default_value, comment)
-//   D(name, type, default_value, comment)
 //   R(name, product_value, type, default_value, comment)
+//   D(name, type, default_value, comment)
 //   C(name, precompiled_value, product_value, type, default_value, comment)
 #define FLAG_LIST(P, R, D, C)                                                  \
 P(always_megamorphic_calls, bool, false,                                       \
   "Instance call always as megamorphic.")                                      \
-P(background_compilation, bool, true,                                          \
+P(background_compilation, bool, USING_MULTICORE,                               \
   "Run optimizing compilation in background")                                  \
 R(background_compilation_stop_alot, false, bool, false,                        \
   "Stress test system: stop background compiler often.")                       \
@@ -37,8 +45,10 @@
   "Insert a one-time breakpoint at the entrypoint for all spawned isolates")   \
 C(collect_code, false, true, bool, true,                                       \
   "Attempt to GC infrequently used code.")                                     \
-P(collect_dynamic_function_names, bool, false,                                 \
+P(collect_dynamic_function_names, bool, true,                                  \
   "Collects all dynamic function names to identify unique targets")            \
+R(concurrent_sweep, USING_MULTICORE, bool, USING_MULTICORE,                    \
+  "Concurrent sweep for old generation.")                                      \
 R(dedup_instructions, true, bool, false,                                       \
   "Canonicalize instructions when precompiling.")                              \
 C(deoptimize_alot, false, false, bool, false,                                  \
@@ -86,6 +96,11 @@
   "Link native calls lazily")                                                  \
 C(load_deferred_eagerly, true, true, bool, false,                              \
   "Load deferred libraries eagerly.")                                          \
+R(log_marker_tasks, false, bool, false,                                        \
+  "Log debugging information for old gen GC marking tasks.")                   \
+R(marker_tasks, USING_MULTICORE ? 2 : 0, int, USING_MULTICORE ? 2 : 0,         \
+  "The number of tasks to spawn during old gen GC marking (0 means "           \
+  "perform all marking on main thread).")                                      \
 P(max_polymorphic_checks, int, 4,                                              \
   "Maximum number of polymorphic check, otherwise it is megamorphic.")         \
 P(max_equality_polymorphic_checks, int, 32,                                    \
@@ -182,5 +197,4 @@
 D(verify_on_transition, bool, false,                                           \
   "Verify on dart <==> VM.")                                                   \
 
-
 #endif  // VM_FLAG_LIST_H_
diff --git a/runtime/vm/flow_graph_allocator.cc b/runtime/vm/flow_graph_allocator.cc
index e2ba4bf..747094c 100644
--- a/runtime/vm/flow_graph_allocator.cc
+++ b/runtime/vm/flow_graph_allocator.cc
@@ -374,7 +374,7 @@
     last_use_interval_ = first_use_interval_;
   } else {
     // Shrink the first use interval. It was optimistically expanded to
-    // cover the the block from the start to the last use in the block.
+    // cover the block from the start to the last use in the block.
     ASSERT(first_use_interval_->start_ <= pos);
     first_use_interval_->start_ = pos;
   }
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 71fcec4..93225db 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -62,6 +62,7 @@
 DECLARE_FLAG(int, inlining_caller_size_threshold);
 DECLARE_FLAG(int, inlining_constant_arguments_max_size_threshold);
 DECLARE_FLAG(int, inlining_constant_arguments_min_size_threshold);
+DECLARE_FLAG(int, reload_every);
 
 static void PrecompilationModeHandler(bool value) {
   if (value) {
@@ -85,7 +86,6 @@
 
     FLAG_background_compilation = false;
     FLAG_always_megamorphic_calls = true;
-    FLAG_collect_dynamic_function_names = true;
     FLAG_fields_may_be_reset = true;
     FLAG_ic_range_profiling = false;
     FLAG_interpret_irregexp = true;
@@ -280,11 +280,6 @@
 
 
 void FlowGraphCompiler::InitCompiler() {
-#ifndef PRODUCT
-  TimelineDurationScope tds(thread(),
-                            Timeline::GetCompilerStream(),
-                            "InitCompiler");
-#endif  // !PRODUCT
   pc_descriptors_list_ = new(zone()) DescriptorList(64);
   exception_handlers_list_ = new(zone()) ExceptionHandlerList();
   block_info_.Clear();
@@ -359,7 +354,9 @@
 
 
 bool FlowGraphCompiler::ForceSlowPathForStackOverflow() const {
-  if (FLAG_stacktrace_every > 0 || FLAG_deoptimize_every > 0) {
+  if ((FLAG_stacktrace_every > 0) ||
+      (FLAG_deoptimize_every > 0) ||
+      (FLAG_reload_every > 0)) {
     return true;
   }
   if (FLAG_stacktrace_filter != NULL &&
@@ -1197,7 +1194,7 @@
     return;
   }
   ASSERT(!ic_data.IsNull());
-  if (is_optimizing() && (ic_data.NumberOfUsedChecks() == 0)) {
+  if (is_optimizing() && (ic_data_in.NumberOfUsedChecks() == 0)) {
     // Emit IC call that will count and thus may need reoptimization at
     // function entry.
     ASSERT(may_reoptimize() || flow_graph().IsCompiledForOsr());
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 34172891..269e668 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -445,8 +445,8 @@
   // R1: instance class.
   // Check immediate superclass equality.
   __ ldr(R2, FieldAddress(R1, Class::super_type_offset()));
-  __ ldr(R2, FieldAddress(R2, Type::type_class_offset()));
-  __ CompareObject(R2, type_class);
+  __ ldr(R2, FieldAddress(R2, Type::type_class_id_offset()));
+  __ CompareImmediate(R2, Smi::RawValue(type_class.id()));
   __ b(is_instance_lbl, EQ);
 
   const Register kTypeArgumentsReg = kNoRegister;
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index 07cff9e..d0c066e 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -437,8 +437,8 @@
   // R1: instance class.
   // Check immediate superclass equality.
   __ LoadFieldFromOffset(R2, R1, Class::super_type_offset());
-  __ LoadFieldFromOffset(R2, R2, Type::type_class_offset());
-  __ CompareObject(R2, type_class);
+  __ LoadFieldFromOffset(R2, R2, Type::type_class_id_offset());
+  __ CompareImmediate(R2, Smi::RawValue(type_class.id()));
   __ b(is_instance_lbl, EQ);
 
   const Register kTypeArgumentsReg = kNoRegister;
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 30cff6b2..64d92a9 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -446,8 +446,8 @@
   // ECX: instance class.
   // Check immediate superclass equality.
   __ movl(EDI, FieldAddress(ECX, Class::super_type_offset()));
-  __ movl(EDI, FieldAddress(EDI, Type::type_class_offset()));
-  __ CompareObject(EDI, type_class);
+  __ movl(EDI, FieldAddress(EDI, Type::type_class_id_offset()));
+  __ cmpl(EDI, Immediate(Smi::RawValue(type_class.id())));
   __ j(EQUAL, is_instance_lbl);
 
   const Register kTypeArgumentsReg = kNoRegister;
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index c63f850..2376554 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -434,8 +434,9 @@
   // T0: instance class.
   // Check immediate superclass equality.
   __ lw(T0, FieldAddress(T0, Class::super_type_offset()));
-  __ lw(T0, FieldAddress(T0, Type::type_class_offset()));
-  __ BranchEqual(T0, type_class, is_instance_lbl);
+  __ lw(T0, FieldAddress(T0, Type::type_class_id_offset()));
+  __ BranchEqual(T0, Immediate(Smi::RawValue(type_class.id())),
+                 is_instance_lbl);
 
   const Register kTypeArgumentsReg = kNoRegister;
   const Register kTempReg = kNoRegister;
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index c8ce4f5..b76da0b 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -442,8 +442,8 @@
   // R10: instance class.
   // Check immediate superclass equality.
   __ movq(R13, FieldAddress(R10, Class::super_type_offset()));
-  __ movq(R13, FieldAddress(R13, Type::type_class_offset()));
-  __ CompareObject(R13, type_class);
+  __ movq(R13, FieldAddress(R13, Type::type_class_id_offset()));
+  __ CompareImmediate(R13, Immediate(Smi::RawValue(type_class.id())));
   __ j(EQUAL, is_instance_lbl);
 
   const Register kTypeArgumentsReg = kNoRegister;
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index c360c98..e92bc3f 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -1418,7 +1418,7 @@
         // Convert the old target entry to a new join entry.
         TargetEntryInstr* old_target =
             inlined_entries_[i]->AsGraphEntry()->normal_entry();
-        // Unuse all inputs in the the old graph entry since it is not part of
+        // Unuse all inputs in the old graph entry since it is not part of
         // the graph anymore. A new target be created instead.
         inlined_entries_[i]->AsGraphEntry()->UnuseAllInputs();
 
diff --git a/runtime/vm/flow_graph_range_analysis_test.cc b/runtime/vm/flow_graph_range_analysis_test.cc
index 8f91943..7ebd6b4 100644
--- a/runtime/vm/flow_graph_range_analysis_test.cc
+++ b/runtime/vm/flow_graph_range_analysis_test.cc
@@ -80,7 +80,7 @@
                   RangeBoundary(kSmiMin),
                   RangeBoundary(kSmiMax));
     TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 30, 30,
-                  RangeBoundary(-1 << 30),
+                  RangeBoundary(-(1 << 30)),
                   RangeBoundary(1 << 30));
   } else {
     TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 30, 30,
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index d0391db..af0a03fc 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -947,13 +947,18 @@
     abstract_type = &AbstractType::ZoneHandle(field.type());
   }
   ASSERT(field.is_static());
-  if (field.is_final() && !FLAG_fields_may_be_reset) {
-    const Instance& obj = Instance::Handle(field.StaticValue());
-    if ((obj.raw() != Object::sentinel().raw()) &&
-        (obj.raw() != Object::transition_sentinel().raw()) &&
-        !obj.IsNull()) {
-      is_nullable = CompileType::kNonNullable;
-      cid = obj.GetClassId();
+  if (field.is_final()) {
+    if (!FLAG_fields_may_be_reset) {
+      const Instance& obj = Instance::Handle(field.StaticValue());
+      if ((obj.raw() != Object::sentinel().raw()) &&
+          (obj.raw() != Object::transition_sentinel().raw()) &&
+          !obj.IsNull()) {
+        is_nullable = CompileType::kNonNullable;
+        cid = obj.GetClassId();
+      }
+    } else if (field.guarded_cid() != kIllegalCid) {
+      cid = field.guarded_cid();
+      if (!IsNullableCid(cid)) is_nullable = CompileType::kNonNullable;
     }
   }
   if (Field::IsExternalizableCid(cid)) {
diff --git a/runtime/vm/gc_marker.cc b/runtime/vm/gc_marker.cc
index cc5db20..2c2643e 100644
--- a/runtime/vm/gc_marker.cc
+++ b/runtime/vm/gc_marker.cc
@@ -25,12 +25,6 @@
 
 namespace dart {
 
-DEFINE_FLAG(int, marker_tasks, 2,
-            "The number of tasks to spawn during old gen GC marking (0 means "
-            "perform all marking on main thread).");
-DEFINE_FLAG(bool, log_marker_tasks, false,
-            "Log debugging information for old gen GC marking tasks.");
-
 class DelaySet {
  private:
   typedef std::multimap<RawObject*, RawWeakProperty*> Map;
diff --git a/runtime/vm/heap.h b/runtime/vm/heap.h
index c5a7693..6131bf3 100644
--- a/runtime/vm/heap.h
+++ b/runtime/vm/heap.h
@@ -366,8 +366,11 @@
 
   int pretenure_policy_;
 
+  friend class Become;  // VisitObjectPointers
   friend class ServiceEvent;
   friend class PageSpace;  // VerifyGC
+  friend class IsolateReloadContext;  // VisitObjects
+
   DISALLOW_COPY_AND_ASSIGN(Heap);
 };
 
diff --git a/runtime/vm/heap_test.cc b/runtime/vm/heap_test.cc
index ad01502..1d55a13 100644
--- a/runtime/vm/heap_test.cc
+++ b/runtime/vm/heap_test.cc
@@ -5,6 +5,7 @@
 #include "platform/globals.h"
 
 #include "platform/assert.h"
+#include "vm/become.h"
 #include "vm/dart_api_impl.h"
 #include "vm/globals.h"
 #include "vm/heap.h"
@@ -12,8 +13,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(int, marker_tasks);
-
 TEST_CASE(OldGC) {
   const char* kScriptChars =
   "main() {\n"
@@ -32,7 +31,7 @@
   heap->CollectGarbage(Heap::kOld);
 }
 
-
+#if !defined(PRODUCT)
 TEST_CASE(OldGC_Unsync) {
   FLAG_marker_tasks = 0;
   const char* kScriptChars =
@@ -51,7 +50,7 @@
   Heap* heap = isolate->heap();
   heap->CollectGarbage(Heap::kOld);
 }
-
+#endif
 
 TEST_CASE(LargeSweep) {
   const char* kScriptChars =
@@ -289,4 +288,80 @@
   EXPECT(heap->Contains(RawObject::ToAddr(obj.raw())));
 }
 
-}  // namespace dart.
+
+void TestBecomeForward(Heap::Space before_space, Heap::Space after_space) {
+  Isolate* isolate = Isolate::Current();
+  Heap* heap = isolate->heap();
+
+  const String& before_obj = String::Handle(String::New("old", before_space));
+  const String& after_obj = String::Handle(String::New("new", after_space));
+
+  EXPECT(before_obj.raw() != after_obj.raw());
+
+  // Allocate the arrays in old space to test the remembered set.
+  const Array& before = Array::Handle(Array::New(1, Heap::kOld));
+  before.SetAt(0, before_obj);
+  const Array& after = Array::Handle(Array::New(1, Heap::kOld));
+  after.SetAt(0, after_obj);
+
+  Become::ElementsForwardIdentity(before, after);
+
+  EXPECT(before_obj.raw() == after_obj.raw());
+
+  heap->CollectAllGarbage();
+
+  EXPECT(before_obj.raw() == after_obj.raw());
+}
+
+
+VM_TEST_CASE(BecomeFowardOldToOld) {
+  TestBecomeForward(Heap::kOld, Heap::kOld);
+}
+
+
+VM_TEST_CASE(BecomeFowardNewToNew) {
+  TestBecomeForward(Heap::kNew, Heap::kNew);
+}
+
+
+VM_TEST_CASE(BecomeFowardOldToNew) {
+  TestBecomeForward(Heap::kOld, Heap::kNew);
+}
+
+
+VM_TEST_CASE(BecomeFowardNewToOld) {
+  TestBecomeForward(Heap::kNew, Heap::kOld);
+}
+
+
+VM_TEST_CASE(BecomeForwardRememberedObject) {
+  Isolate* isolate = Isolate::Current();
+  Heap* heap = isolate->heap();
+
+  const String& new_element = String::Handle(String::New("new", Heap::kNew));
+  const String& old_element = String::Handle(String::New("old", Heap::kOld));
+  const Array& before_obj = Array::Handle(Array::New(1, Heap::kOld));
+  const Array& after_obj = Array::Handle(Array::New(1, Heap::kOld));
+  before_obj.SetAt(0, new_element);
+  after_obj.SetAt(0, old_element);
+  EXPECT(before_obj.raw()->IsRemembered());
+  EXPECT(!after_obj.raw()->IsRemembered());
+
+  EXPECT(before_obj.raw() != after_obj.raw());
+
+  const Array& before = Array::Handle(Array::New(1, Heap::kOld));
+  before.SetAt(0, before_obj);
+  const Array& after = Array::Handle(Array::New(1, Heap::kOld));
+  after.SetAt(0, after_obj);
+
+  Become::ElementsForwardIdentity(before, after);
+
+  EXPECT(before_obj.raw() == after_obj.raw());
+  EXPECT(!after_obj.raw()->IsRemembered());
+
+  heap->CollectAllGarbage();
+
+  EXPECT(before_obj.raw() == after_obj.raw());
+}
+
+}  // namespace dart
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 3950f3e..66abf75 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -3083,28 +3083,7 @@
     if (stub_entry != NULL) {
       // We have a dedicated inline cache stub for this operation, add an
       // an initial Smi/Smi check with count 0.
-      ASSERT(call_ic_data->NumArgsTested() == 2);
-      const String& name = String::Handle(zone, call_ic_data->target_name());
-      const Class& smi_class = Class::Handle(zone, Smi::Class());
-      const Function& smi_op_target = Function::Handle(zone,
-          Resolver::ResolveDynamicAnyArgs(zone, smi_class, name));
-      if (call_ic_data->NumberOfChecks() == 0) {
-        GrowableArray<intptr_t> class_ids(2);
-        class_ids.Add(kSmiCid);
-        class_ids.Add(kSmiCid);
-        call_ic_data->AddCheck(class_ids, smi_op_target);
-        // 'AddCheck' sets the initial count to 1.
-        call_ic_data->SetCountAt(0, 0);
-        is_smi_two_args_op = true;
-      } else if (call_ic_data->NumberOfChecks() == 1) {
-        GrowableArray<intptr_t> class_ids(2);
-        Function& target = Function::Handle(zone);
-        call_ic_data->GetCheckAt(0, &class_ids, &target);
-        if ((target.raw() == smi_op_target.raw()) &&
-            (class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) {
-          is_smi_two_args_op = true;
-        }
-      }
+      is_smi_two_args_op = call_ic_data->AddSmiSmiCheckForFastSmiStubs();
     }
     if (is_smi_two_args_op) {
       ASSERT(ArgumentCount() == 2);
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index a7f522d..a7f3d7f 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -2586,7 +2586,7 @@
   virtual void InferRange(RangeAnalysis* analysis, Range* range);
 
   // Constraints for branches have their target block stored in order
-  // to find the the comparsion that generated the constraint:
+  // to find the comparison that generated the constraint:
   // target->predecessor->last_instruction->comparison.
   void set_target(TargetEntryInstr* target) {
     target_ = target;
diff --git a/runtime/vm/intermediate_language_dbc.cc b/runtime/vm/intermediate_language_dbc.cc
index 7c87f8e..c4399e0 100644
--- a/runtime/vm/intermediate_language_dbc.cc
+++ b/runtime/vm/intermediate_language_dbc.cc
@@ -60,7 +60,7 @@
   M(ShiftMintOp)                                                               \
   M(UnaryMintOp)                                                               \
   M(StringToCharCode)                                                          \
-  M(StringFromCharCode)                                                        \
+  M(OneByteStringFromCharCode)                                                 \
   M(InvokeMathCFunction)                                                       \
   M(MergedMath)                                                                \
   M(GuardFieldClass)                                                           \
diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc
index 27631b3..bdd7c5c 100644
--- a/runtime/vm/intrinsifier.cc
+++ b/runtime/vm/intrinsifier.cc
@@ -588,7 +588,9 @@
 
 
 bool Intrinsifier::Build_Float64ArraySetIndexed(FlowGraph* flow_graph) {
-  if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false;
+  if (!FlowGraphCompiler::SupportsUnboxedDoubles()) {
+    return false;
+  }
 
   GraphEntryInstr* graph_entry = flow_graph->graph_entry();
   TargetEntryInstr* normal_entry = graph_entry->normal_entry();
@@ -634,7 +636,9 @@
 
 
 bool Intrinsifier::Build_Float64ArrayGetIndexed(FlowGraph* flow_graph) {
-  if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false;
+  if (!FlowGraphCompiler::SupportsUnboxedDoubles()) {
+    return false;
+  }
 
   GraphEntryInstr* graph_entry = flow_graph->graph_entry();
   TargetEntryInstr* normal_entry = graph_entry->normal_entry();
@@ -783,7 +787,10 @@
 
 static bool BuildFloat32x4Shuffle(FlowGraph* flow_graph,
                                   MethodRecognizer::Kind kind) {
-  if (!FlowGraphCompiler::SupportsUnboxedSimd128()) return false;
+  if (!FlowGraphCompiler::SupportsUnboxedDoubles() ||
+      !FlowGraphCompiler::SupportsUnboxedSimd128()) {
+    return false;
+  }
   GraphEntryInstr* graph_entry = flow_graph->graph_entry();
   TargetEntryInstr* normal_entry = graph_entry->normal_entry();
   BlockBuilder builder(flow_graph, normal_entry);
@@ -1021,6 +1028,9 @@
 
 
 bool Intrinsifier::Build_DoubleFlipSignBit(FlowGraph* flow_graph) {
+  if (!FlowGraphCompiler::SupportsUnboxedDoubles()) {
+    return false;
+  }
   GraphEntryInstr* graph_entry = flow_graph->graph_entry();
   TargetEntryInstr* normal_entry = graph_entry->normal_entry();
   BlockBuilder builder(flow_graph, normal_entry);
@@ -1044,6 +1054,9 @@
 static bool BuildInvokeMathCFunction(BlockBuilder* builder,
                                      MethodRecognizer::Kind kind,
                                      intptr_t num_parameters = 1) {
+  if (!FlowGraphCompiler::SupportsUnboxedDoubles()) {
+    return false;
+  }
   ZoneGrowableArray<Value*>* args =
       new ZoneGrowableArray<Value*>(num_parameters);
 
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index e878d03..119fd7a 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -15,6 +15,7 @@
 #include "vm/object_store.h"
 #include "vm/regexp_assembler.h"
 #include "vm/symbols.h"
+#include "vm/timeline.h"
 
 namespace dart {
 
@@ -1557,7 +1558,7 @@
   __ CompareImmediate(R3, 0);
   __ b(&fall_through, NE);
 
-  __ ldr(R0, FieldAddress(R2, Class::canonical_types_offset()));
+  __ ldr(R0, FieldAddress(R2, Class::canonical_type_offset()));
   __ CompareObject(R0, Object::null_object());
   __ b(&fall_through, EQ);
   __ Ret();
@@ -2104,6 +2105,23 @@
   __ Ret();
 }
 
+
+void Intrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler) {
+  if (!FLAG_support_timeline) {
+    __ LoadObject(R0, Bool::False());
+    __ Ret();
+    return;
+  }
+  // Load TimelineStream*.
+  __ ldr(R0, Address(THR, Thread::dart_stream_offset()));
+  // Load uintptr_t from TimelineStream*.
+  __ ldr(R0, Address(R0, TimelineStream::enabled_offset()));
+  __ cmp(R0, Operand(0));
+  __ LoadObject(R0, Bool::True(), NE);
+  __ LoadObject(R0, Bool::False(), EQ);
+  __ Ret();
+}
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_ARM
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index 88512e8..0ca8c25 100644
--- a/runtime/vm/intrinsifier_arm64.cc
+++ b/runtime/vm/intrinsifier_arm64.cc
@@ -14,6 +14,7 @@
 #include "vm/object_store.h"
 #include "vm/regexp_assembler.h"
 #include "vm/symbols.h"
+#include "vm/timeline.h"
 
 namespace dart {
 
@@ -1634,7 +1635,7 @@
   __ CompareImmediate(R3, 0);
   __ b(&fall_through, NE);
 
-  __ ldr(R0, FieldAddress(R2, Class::canonical_types_offset()));
+  __ ldr(R0, FieldAddress(R2, Class::canonical_type_offset()));
   __ CompareObject(R0, Object::null_object());
   __ b(&fall_through, EQ);
   __ ret();
@@ -2178,6 +2179,24 @@
   __ ret();
 }
 
+
+void Intrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler) {
+  if (!FLAG_support_timeline) {
+    __ LoadObject(R0, Bool::False());
+    __ ret();
+    return;
+  }
+  // Load TimelineStream*.
+  __ ldr(R0, Address(THR, Thread::dart_stream_offset()));
+  // Load uintptr_t from TimelineStream*.
+  __ ldr(R0, Address(R0, TimelineStream::enabled_offset()));
+  __ cmp(R0, Operand(0));
+  __ LoadObject(R0, Bool::False());
+  __ LoadObject(TMP, Bool::True());
+  __ csel(R0, TMP, R0, NE);
+  __ ret();
+}
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_ARM64
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index 8dc9e99..576c6a0 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -21,6 +21,7 @@
 #include "vm/os.h"
 #include "vm/regexp_assembler.h"
 #include "vm/symbols.h"
+#include "vm/timeline.h"
 
 namespace dart {
 
@@ -1697,7 +1698,7 @@
   __ movzxw(EDI, FieldAddress(EBX, Class::num_type_arguments_offset()));
   __ cmpl(EDI, Immediate(0));
   __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
-  __ movl(EAX, FieldAddress(EBX, Class::canonical_types_offset()));
+  __ movl(EAX, FieldAddress(EBX, Class::canonical_type_offset()));
   __ CompareObject(EAX, Object::null_object());
   __ j(EQUAL, &fall_through, Assembler::kNearJump);  // Not yet set.
   __ ret();
@@ -2131,7 +2132,31 @@
   __ ret();
 }
 
+
+void Intrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler) {
+  if (!FLAG_support_timeline) {
+    __ LoadObject(EAX, Bool::False());
+    __ ret();
+    return;
+  }
+  Label true_label;
+  // Load TimelineStream*.
+  __ movl(EAX, Address(THR, Thread::dart_stream_offset()));
+  // Load uintptr_t from TimelineStream*.
+  __ movl(EAX, Address(EAX, TimelineStream::enabled_offset()));
+  __ cmpl(EAX, Immediate(0));
+  __ j(NOT_ZERO, &true_label, Assembler::kNearJump);
+  // Not enabled.
+  __ LoadObject(EAX, Bool::False());
+  __ ret();
+  // Enabled.
+  __ Bind(&true_label);
+  __ LoadObject(EAX, Bool::True());
+  __ ret();
+}
+
 #undef __
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_IA32
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 2398a7b..ea2183c 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -14,6 +14,7 @@
 #include "vm/object_store.h"
 #include "vm/regexp_assembler.h"
 #include "vm/symbols.h"
+#include "vm/timeline.h"
 
 namespace dart {
 
@@ -1664,7 +1665,7 @@
   __ lhu(T1, FieldAddress(T2, Class::num_type_arguments_offset()));
   __ BranchNotEqual(T1, Immediate(0), &fall_through);
 
-  __ lw(V0, FieldAddress(T2, Class::canonical_types_offset()));
+  __ lw(V0, FieldAddress(T2, Class::canonical_type_offset()));
   __ BranchEqual(V0, Object::null_object(), &fall_through);
   __ Ret();
 
@@ -2208,6 +2209,23 @@
   __ delay_slot()->lw(V0, Address(V0, Isolate::current_tag_offset()));
 }
 
+
+void Intrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler) {
+  if (!FLAG_support_timeline) {
+    __ LoadObject(V0, Bool::False());
+    __ Ret();
+    return;
+  }
+  // Load TimelineStream*.
+  __ lw(V0, Address(THR, Thread::dart_stream_offset()));
+  // Load uintptr_t from TimelineStream*.
+  __ lw(T0, Address(V0, TimelineStream::enabled_offset()));
+  __ LoadObject(V0, Bool::True());
+  __ LoadObject(V1, Bool::False());
+  __ Ret();
+  __ delay_slot()->movz(V0, V1, T0);  // V0 = (T0 == 0) ? V1 : V0.
+}
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_MIPS
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index 402613e..58f096d 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -14,6 +14,7 @@
 #include "vm/object_store.h"
 #include "vm/regexp_assembler.h"
 #include "vm/symbols.h"
+#include "vm/timeline.h"
 
 namespace dart {
 
@@ -1552,7 +1553,7 @@
   __ movzxw(RCX, FieldAddress(RDI, Class::num_type_arguments_offset()));
   __ cmpq(RCX, Immediate(0));
   __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
-  __ movq(RAX, FieldAddress(RDI, Class::canonical_types_offset()));
+  __ movq(RAX, FieldAddress(RDI, Class::canonical_type_offset()));
   __ CompareObject(RAX, Object::null_object());
   __ j(EQUAL, &fall_through, Assembler::kNearJump);  // Not yet set.
   __ ret();
@@ -2086,6 +2087,29 @@
   __ ret();
 }
 
+
+void Intrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler) {
+  if (!FLAG_support_timeline) {
+    __ LoadObject(RAX, Bool::False());
+    __ ret();
+    return;
+  }
+  Label true_label;
+  // Load TimelineStream*.
+  __ movq(RAX, Address(THR, Thread::dart_stream_offset()));
+  // Load uintptr_t from TimelineStream*.
+  __ movq(RAX, Address(RAX, TimelineStream::enabled_offset()));
+  __ cmpq(RAX, Immediate(0));
+  __ j(NOT_ZERO, &true_label, Assembler::kNearJump);
+  // Not enabled.
+  __ LoadObject(RAX, Bool::False());
+  __ ret();
+  // Enabled.
+  __ Bind(&true_label);
+  __ LoadObject(RAX, Bool::True());
+  __ ret();
+}
+
 #undef __
 
 }  // namespace dart
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 57fb16a..11f5536 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -19,6 +19,7 @@
 #include "vm/deopt_instructions.h"
 #include "vm/flags.h"
 #include "vm/heap.h"
+#include "vm/isolate_reload.h"
 #include "vm/lockers.h"
 #include "vm/log.h"
 #include "vm/message_handler.h"
@@ -52,6 +53,7 @@
 DECLARE_FLAG(bool, print_metrics);
 DECLARE_FLAG(bool, timing);
 DECLARE_FLAG(bool, trace_service);
+DECLARE_FLAG(bool, trace_reload);
 DECLARE_FLAG(bool, warn_on_pause_with_no_debugger);
 
 NOT_IN_PRODUCT(
@@ -134,7 +136,28 @@
 
 
 
+NoReloadScope::NoReloadScope(Isolate* isolate, Thread* thread)
+    : StackResource(thread),
+      isolate_(isolate) {
+  ASSERT(isolate_ != NULL);
+  isolate_->no_reload_scope_depth_++;
+  ASSERT(isolate_->no_reload_scope_depth_ >= 0);
+}
+
+
+NoReloadScope::~NoReloadScope() {
+  isolate_->no_reload_scope_depth_--;
+  ASSERT(isolate_->no_reload_scope_depth_ >= 0);
+}
+
+
 void Isolate::RegisterClass(const Class& cls) {
+  NOT_IN_PRODUCT(
+    if (IsReloading()) {
+      reload_context()->RegisterClass(cls);
+      return;
+    }
+  )
   class_table()->Register(cls);
 }
 
@@ -338,7 +361,7 @@
 
       // If we are already paused, don't pause again.
       if (FLAG_support_debugger && (I->debugger()->PauseEvent() == NULL)) {
-        return I->debugger()->SignalIsolateInterrupted();
+        return I->debugger()->PauseInterrupted();
       }
       break;
     }
@@ -624,6 +647,12 @@
 
 MessageHandler::MessageStatus IsolateMessageHandler::ProcessUnhandledException(
     const Error& result) {
+  NOT_IN_PRODUCT(
+    if (I->IsReloading()) {
+      I->ReportReloadError(result);
+      return kOK;
+    }
+  )
   // Generate the error and stacktrace strings for the error message.
   String& exc_str = String::Handle(T->zone());
   String& stacktrace_str = String::Handle(T->zone());
@@ -670,7 +699,7 @@
             (exception == I->object_store()->stack_overflow())) {
           // We didn't notify the debugger when the stack was full. Do it now.
           if (FLAG_support_debugger) {
-            I->debugger()->SignalExceptionThrown(Instance::Handle(exception));
+            I->debugger()->PauseException(Instance::Handle(exception));
           }
         }
       }
@@ -785,6 +814,7 @@
       deoptimized_code_array_(GrowableObjectArray::null()),
       sticky_error_(Error::null()),
       background_compiler_(NULL),
+      background_compiler_disabled_depth_(0),
       pending_service_extension_calls_(GrowableObjectArray::null()),
       registered_service_extension_handlers_(GrowableObjectArray::null()),
       metrics_list_head_(NULL),
@@ -799,7 +829,10 @@
       boxed_field_list_(GrowableObjectArray::null()),
       disabling_field_list_(GrowableObjectArray::null()),
       spawn_count_monitor_(new Monitor()),
-      spawn_count_(0) {
+      spawn_count_(0),
+      has_attempted_reload_(false),
+      no_reload_scope_depth_(0),
+      reload_context_(NULL) {
   NOT_IN_PRODUCT(FlagsCopyFrom(api_flags));
   // TODO(asiva): A Thread is not available here, need to figure out
   // how the vm_tag (kEmbedderTagId) can be set, these tags need to
@@ -1016,6 +1049,60 @@
 }
 
 
+bool Isolate::CanReload() const {
+#ifndef PRODUCT
+  return (!ServiceIsolate::IsServiceIsolateDescendant(this) &&
+          is_runnable() && !IsReloading() && no_reload_scope_depth_ == 0);
+#else
+  return false;
+#endif
+}
+
+
+#ifndef PRODUCT
+void Isolate::ReportReloadError(const Error& error) {
+  ASSERT(IsReloading());
+  reload_context_->AbortReload(error);
+  delete reload_context_;
+  reload_context_ = NULL;
+}
+
+
+void Isolate::OnStackReload() {
+  UNREACHABLE();
+}
+
+
+void Isolate::ReloadSources(bool test_mode) {
+  ASSERT(!IsReloading());
+  has_attempted_reload_ = true;
+  reload_context_ = new IsolateReloadContext(this, test_mode);
+  reload_context_->StartReload();
+}
+
+#endif
+
+
+void Isolate::DoneFinalizing() {
+  NOT_IN_PRODUCT(
+    if (IsReloading()) {
+      reload_context_->FinishReload();
+      if (reload_context_->has_error() && reload_context_->test_mode()) {
+        // If the reload has an error and we are in test mode keep the reload
+        // context on the isolate so that it can be used by unit tests.
+        return;
+      }
+      if (!reload_context_->has_error()) {
+        reload_context_->ReportSuccess();
+      }
+      delete reload_context_;
+      reload_context_ = NULL;
+    }
+  )
+}
+
+
+
 bool Isolate::MakeRunnable() {
   ASSERT(Isolate::Current() == NULL);
 
@@ -1690,6 +1777,13 @@
     debugger()->VisitObjectPointers(visitor);
   }
 
+  NOT_IN_PRODUCT(
+    // Visit objects that are being used for isolate reload.
+    if (reload_context() != NULL) {
+      reload_context()->VisitObjectPointers(visitor);
+    }
+  )
+
   // Visit objects that are being used for deoptimization.
   if (deopt_context() != NULL) {
     deopt_context()->VisitObjectPointers(visitor);
@@ -1712,6 +1806,23 @@
 }
 
 
+RawClass* Isolate::GetClassForHeapWalkAt(intptr_t cid) {
+  RawClass* raw_class = NULL;
+#ifndef PRODUCT
+  if (IsReloading()) {
+    raw_class = reload_context()->GetClassForHeapWalkAt(cid);
+  } else {
+    raw_class = class_table()->At(cid);
+  }
+#else
+  raw_class = class_table()->At(cid);
+#endif  // !PRODUCT
+  ASSERT(raw_class != NULL);
+  ASSERT(raw_class->ptr()->id_ == cid);
+  return raw_class;
+}
+
+
 static const char* ExceptionPauseInfoToServiceEnum(Dart_ExceptionPauseInfo pi) {
   switch (pi) {
     case kPauseOnAllExceptions:
@@ -1755,6 +1866,7 @@
   jsobj.AddProperty("runnable", is_runnable());
   jsobj.AddProperty("livePorts", message_handler()->live_ports());
   jsobj.AddProperty("pauseOnExit", message_handler()->should_pause_on_exit());
+  jsobj.AddProperty("_isReloading", IsReloading());
 
   if (debugger() != NULL) {
     if (!is_runnable()) {
@@ -1772,8 +1884,7 @@
       ServiceEvent pause_event(this, ServiceEvent::kPauseExit);
       jsobj.AddProperty("pauseEvent", &pause_event);
     } else if (debugger()->PauseEvent() != NULL && !resume_request_) {
-      ServiceEvent pause_event(debugger()->PauseEvent());
-      jsobj.AddProperty("pauseEvent", &pause_event);
+      jsobj.AddProperty("pauseEvent", debugger()->PauseEvent());
     } else {
       ServiceEvent pause_event(this, ServiceEvent::kResume);
 
@@ -2188,6 +2299,9 @@
       message_notify_callback();
   set_message_notify_callback(Isolate::WakePauseEventHandler);
 
+  const bool had_isolate_reload_context = reload_context() != NULL;
+  const int64_t start_time_micros =
+      !had_isolate_reload_context ? 0 : reload_context()->start_time_micros();
   bool resume = false;
   while (true) {
     // Handle all available vm service messages, up to a resume
@@ -2201,6 +2315,17 @@
       break;
     }
 
+    if (had_isolate_reload_context && (reload_context() == NULL)) {
+      if (FLAG_trace_reload) {
+        const int64_t reload_time_micros =
+            OS::GetCurrentMonotonicMicros() - start_time_micros;
+        double reload_millis =
+            MicrosecondsToMilliseconds(reload_time_micros);
+        OS::Print("Reloading has finished! (%.2f ms)\n", reload_millis);
+      }
+      break;
+    }
+
     // Wait for more service messages.
     Monitor::WaitResult res = ml.Wait();
     ASSERT(res == Monitor::kNotified);
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index c2fc955..b418fd6 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -35,6 +35,7 @@
 class Heap;
 class ICData;
 class IsolateProfilerData;
+class IsolateReloadContext;
 class IsolateSpawnState;
 class Log;
 class MessageHandler;
@@ -47,12 +48,12 @@
 class RawArray;
 class RawContext;
 class RawDouble;
+class RawError;
+class RawField;
 class RawGrowableObjectArray;
 class RawMint;
 class RawObject;
 class RawInteger;
-class RawError;
-class RawField;
 class RawFloat32x4;
 class RawInt32x4;
 class RawUserTag;
@@ -91,6 +92,18 @@
 };
 
 
+// Disallow isolate reload.
+class NoReloadScope : public StackResource {
+ public:
+  NoReloadScope(Isolate* isolate, Thread* thread);
+  ~NoReloadScope();
+
+ private:
+  Isolate* isolate_;
+  DISALLOW_COPY_AND_ASSIGN(NoReloadScope);
+};
+
+
 class Isolate : public BaseIsolate {
  public:
   // Keep both these enums in sync with isolate_patch.dart.
@@ -150,6 +163,9 @@
     return OFFSET_OF(Isolate, class_table_);
   }
 
+  // Prefers old classes when we are in the middle of a reload.
+  RawClass* GetClassForHeapWalkAt(intptr_t cid);
+
   static intptr_t ic_miss_code_offset() {
     return OFFSET_OF(Isolate, ic_miss_code_);
   }
@@ -237,6 +253,10 @@
 
   // Marks all libraries as loaded.
   void DoneLoading();
+  void DoneFinalizing();
+
+  void OnStackReload();
+  void ReloadSources(bool test_mode = false);
 
   bool MakeRunnable();
   void Run();
@@ -388,6 +408,22 @@
     background_compiler_ = value;
   }
 
+  void enable_background_compiler() {
+    background_compiler_disabled_depth_--;
+    if (background_compiler_disabled_depth_ < 0) {
+      FATAL("Mismatched number of calls to disable_background_compiler and "
+            "enable_background_compiler.");
+    }
+  }
+
+  void disable_background_compiler() {
+    background_compiler_disabled_depth_++;
+  }
+
+  bool is_background_compiler_disabled() const {
+    return background_compiler_disabled_depth_ > 0;
+  }
+
   void UpdateLastAllocationProfileAccumulatorResetTimestamp() {
     last_allocationprofile_accumulator_reset_timestamp_ =
         OS::GetCurrentTimeMillis();
@@ -432,6 +468,22 @@
     return &vm_tag_counters_;
   }
 
+  bool IsReloading() const {
+    return reload_context_ != NULL;
+  }
+
+  IsolateReloadContext* reload_context() {
+    return reload_context_;
+  }
+
+  bool HasAttemptedReload() const {
+    return has_attempted_reload_;
+  }
+
+  bool CanReload() const;
+
+  void ReportReloadError(const Error& error);
+
   uword user_tag() const {
     return user_tag_;
   }
@@ -717,6 +769,7 @@
 
   // Background compilation.
   BackgroundCompiler* background_compiler_;
+  intptr_t background_compiler_disabled_depth_;
 
   // We use 6 list entries for each pending service extension calls.
   enum {
@@ -769,6 +822,11 @@
   Monitor* spawn_count_monitor_;
   intptr_t spawn_count_;
 
+  // Has a reload ever been attempted?
+  bool has_attempted_reload_;
+  intptr_t no_reload_scope_depth_;  // we can only reload when this is 0.
+  IsolateReloadContext* reload_context_;
+
 #define ISOLATE_METRIC_VARIABLE(type, variable, name, unit)                    \
   type metric_##variable##_;
   ISOLATE_METRIC_LIST(ISOLATE_METRIC_VARIABLE);
@@ -795,12 +853,15 @@
 REUSABLE_HANDLE_LIST(REUSABLE_FRIEND_DECLARATION)
 #undef REUSABLE_FRIEND_DECLARATION
 
+  friend class Become;  // VisitObjectPointers
   friend class GCMarker;  // VisitObjectPointers
   friend class SafepointHandler;
   friend class Scavenger;  // VisitObjectPointers
   friend class ServiceIsolate;
   friend class Thread;
   friend class Timeline;
+  friend class NoReloadScope;  // reload_block
+
 
   DISALLOW_COPY_AND_ASSIGN(Isolate);
 };
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
new file mode 100644
index 0000000..0291517
--- /dev/null
+++ b/runtime/vm/isolate_reload.cc
@@ -0,0 +1,1195 @@
+// Copyright (c) 2016, 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.
+
+#include "vm/isolate_reload.h"
+
+#include "vm/become.h"
+#include "vm/code_generator.h"
+#include "vm/compiler.h"
+#include "vm/dart_api_impl.h"
+#include "vm/hash_table.h"
+#include "vm/isolate.h"
+#include "vm/log.h"
+#include "vm/object.h"
+#include "vm/object_store.h"
+#include "vm/parser.h"
+#include "vm/safepoint.h"
+#include "vm/service_event.h"
+#include "vm/stack_frame.h"
+#include "vm/thread.h"
+#include "vm/timeline.h"
+#include "vm/visitor.h"
+
+namespace dart {
+
+DEFINE_FLAG(bool, trace_reload, false, "Trace isolate reloading");
+DEFINE_FLAG(bool, identity_reload, false, "Enable checks for identity reload.");
+DEFINE_FLAG(int, reload_every, 0, "Reload every N stack overflow checks.");
+DEFINE_FLAG(bool, reload_every_optimized, true, "Only from optimized code.");
+
+#ifndef PRODUCT
+
+#define I (isolate())
+#define Z (thread->zone())
+
+#define TIMELINE_SCOPE(name)                                                   \
+    TimelineDurationScope tds##name(Thread::Current(),                         \
+                                   Timeline::GetIsolateStream(),               \
+                                   #name)
+
+
+class ScriptUrlSetTraits {
+ public:
+  static bool ReportStats() { return false; }
+  static const char* Name() { return "ScriptUrlSetTraits"; }
+
+  static bool IsMatch(const Object& a, const Object& b) {
+    if (!a.IsString() || !b.IsString()) {
+      return false;
+    }
+
+    return String::Cast(a).Equals(String::Cast(b));
+  }
+
+  static uword Hash(const Object& obj) {
+    return String::Cast(obj).Hash();
+  }
+};
+
+
+class ClassMapTraits {
+ public:
+  static bool ReportStats() { return false; }
+  static const char* Name() { return "ClassMapTraits"; }
+
+  static bool IsMatch(const Object& a, const Object& b) {
+    if (!a.IsClass() || !b.IsClass()) {
+      return false;
+    }
+    return IsolateReloadContext::IsSameClass(Class::Cast(a), Class::Cast(b));
+  }
+
+  static uword Hash(const Object& obj) {
+    return String::HashRawSymbol(Class::Cast(obj).Name());
+  }
+};
+
+
+class LibraryMapTraits {
+ public:
+  static bool ReportStats() { return false; }
+  static const char* Name() { return "LibraryMapTraits"; }
+
+  static bool IsMatch(const Object& a, const Object& b) {
+    if (!a.IsLibrary() || !b.IsLibrary()) {
+      return false;
+    }
+    return IsolateReloadContext::IsSameLibrary(
+        Library::Cast(a), Library::Cast(b));
+  }
+
+  static uword Hash(const Object& obj) {
+    return Library::Cast(obj).UrlHash();
+  }
+};
+
+
+class BecomeMapTraits {
+ public:
+  static bool ReportStats() { return false; }
+  static const char* Name() { return "BecomeMapTraits"; }
+
+  static bool IsMatch(const Object& a, const Object& b) {
+    return a.raw() == b.raw();
+  }
+
+  static uword Hash(const Object& obj) {
+    if (obj.IsLibrary()) {
+      return Library::Cast(obj).UrlHash();
+    } else if (obj.IsClass()) {
+      if (Class::Cast(obj).id() == kFreeListElement) {
+        return 0;
+      }
+      return String::HashRawSymbol(Class::Cast(obj).Name());
+    } else if (obj.IsField()) {
+      return String::HashRawSymbol(Field::Cast(obj).name());
+    }
+    return 0;
+  }
+};
+
+
+bool IsolateReloadContext::IsSameField(const Field& a, const Field& b) {
+  if (a.is_static() != b.is_static()) {
+    return false;
+  }
+  const Class& a_cls = Class::Handle(a.Owner());
+  const Class& b_cls = Class::Handle(b.Owner());
+
+  if (!IsSameClass(a_cls, b_cls)) {
+    return false;
+  }
+
+  const String& a_name = String::Handle(a.name());
+  const String& b_name = String::Handle(b.name());
+
+  return a_name.Equals(b_name);
+}
+
+
+bool IsolateReloadContext::IsSameClass(const Class& a, const Class& b) {
+  if (a.is_patch() != b.is_patch()) {
+    // TODO(johnmccutchan): Should we just check the class kind bits?
+    return false;
+  }
+
+  // TODO(turnidge): We need to look at generic type arguments for
+  // synthetic mixin classes.  Their names are not necessarily unique
+  // currently.
+  const String& a_name = String::Handle(Class::Cast(a).Name());
+  const String& b_name = String::Handle(Class::Cast(b).Name());
+
+  if (!a_name.Equals(b_name)) {
+    return false;
+  }
+
+  const Library& a_lib = Library::Handle(Class::Cast(a).library());
+  const Library& b_lib = Library::Handle(Class::Cast(b).library());
+  return IsSameLibrary(a_lib, b_lib);
+}
+
+
+bool IsolateReloadContext::IsSameLibrary(
+    const Library& a_lib, const Library& b_lib) {
+  const String& a_lib_url =
+      String::Handle(a_lib.IsNull() ? String::null() : a_lib.url());
+  const String& b_lib_url =
+      String::Handle(b_lib.IsNull() ? String::null() : b_lib.url());
+  return a_lib_url.Equals(b_lib_url);
+}
+
+
+IsolateReloadContext::IsolateReloadContext(Isolate* isolate, bool test_mode)
+    : start_time_micros_(OS::GetCurrentMonotonicMicros()),
+      isolate_(isolate),
+      test_mode_(test_mode),
+      has_error_(false),
+      saved_num_cids_(-1),
+      saved_class_table_(NULL),
+      num_saved_libs_(-1),
+      script_uri_(String::null()),
+      error_(Error::null()),
+      clean_scripts_set_storage_(Array::null()),
+      compile_time_constants_(Array::null()),
+      old_classes_set_storage_(Array::null()),
+      class_map_storage_(Array::null()),
+      old_libraries_set_storage_(Array::null()),
+      library_map_storage_(Array::null()),
+      become_map_storage_(Array::null()),
+      saved_root_library_(Library::null()),
+      saved_libraries_(GrowableObjectArray::null()) {
+  // Preallocate storage for maps.
+  clean_scripts_set_storage_ =
+      HashTables::New<UnorderedHashSet<ScriptUrlSetTraits> >(4);
+  old_classes_set_storage_ =
+      HashTables::New<UnorderedHashSet<ClassMapTraits> >(4);
+  class_map_storage_ =
+      HashTables::New<UnorderedHashMap<ClassMapTraits> >(4);
+  old_libraries_set_storage_ =
+      HashTables::New<UnorderedHashSet<LibraryMapTraits> >(4);
+  library_map_storage_ =
+      HashTables::New<UnorderedHashMap<LibraryMapTraits> >(4);
+  become_map_storage_ =
+      HashTables::New<UnorderedHashMap<BecomeMapTraits> >(4);
+}
+
+
+IsolateReloadContext::~IsolateReloadContext() {
+}
+
+
+void IsolateReloadContext::ReportError(const Error& error) {
+  has_error_ = true;
+  error_ = error.raw();
+  if (FLAG_trace_reload) {
+    THR_Print("ISO-RELOAD: Error: %s\n", error.ToErrorCString());
+  }
+  ServiceEvent service_event(Isolate::Current(), ServiceEvent::kIsolateReload);
+  service_event.set_reload_error(&error);
+  Service::HandleEvent(&service_event);
+}
+
+
+void IsolateReloadContext::ReportError(const String& error_msg) {
+  ReportError(LanguageError::Handle(LanguageError::New(error_msg)));
+}
+
+
+void IsolateReloadContext::ReportSuccess() {
+  ServiceEvent service_event(Isolate::Current(), ServiceEvent::kIsolateReload);
+  Service::HandleEvent(&service_event);
+}
+
+
+void IsolateReloadContext::StartReload() {
+  Thread* thread = Thread::Current();
+
+  // Grab root library before calling CheckpointBeforeReload.
+  const Library& root_lib = Library::Handle(object_store()->root_library());
+  ASSERT(!root_lib.IsNull());
+  const String& root_lib_url = String::Handle(root_lib.url());
+
+  // Disable the background compiler while we are performing the reload.
+  BackgroundCompiler::Disable();
+
+  if (FLAG_write_protect_code) {
+    // Disable code page write protection while we are reloading.
+    I->heap()->WriteProtectCode(false);
+  }
+
+  // Ensure all functions on the stack have unoptimized code.
+  EnsuredUnoptimizedCodeForStack();
+  // Deoptimize all code that had optimizing decisions that are dependent on
+  // assumptions from field guards or CHA or deferred library prefixes.
+  // TODO(johnmccutchan): Deoptimizing dependent code here (before the reload)
+  // is paranoid. This likely can be moved to the commit phase.
+  DeoptimizeDependentCode();
+  Checkpoint();
+
+  // Block class finalization attempts when calling into the library
+  // tag handler.
+  I->BlockClassFinalization();
+  Object& result = Object::Handle(thread->zone());
+  {
+    TransitionVMToNative transition(thread);
+    Api::Scope api_scope(thread);
+
+    Dart_Handle retval =
+        (I->library_tag_handler())(Dart_kScriptTag,
+                                Api::NewHandle(thread, Library::null()),
+                                Api::NewHandle(thread, root_lib_url.raw()));
+    result = Api::UnwrapHandle(retval);
+  }
+  I->UnblockClassFinalization();
+  if (result.IsError()) {
+    ReportError(Error::Cast(result));
+  }
+}
+
+
+void IsolateReloadContext::RegisterClass(const Class& new_cls) {
+  const Class& old_cls = Class::Handle(OldClassOrNull(new_cls));
+  if (old_cls.IsNull()) {
+    Isolate::Current()->class_table()->Register(new_cls);
+
+    if (FLAG_identity_reload) {
+      TIR_Print("Could not find replacement class for %s\n",
+                new_cls.ToCString());
+      UNREACHABLE();
+    }
+
+    // New class maps to itself.
+    AddClassMapping(new_cls, new_cls);
+    return;
+  }
+  new_cls.set_id(old_cls.id());
+  isolate()->class_table()->SetAt(old_cls.id(), new_cls.raw());
+  if (!old_cls.is_enum_class()) {
+    new_cls.CopyCanonicalConstants(old_cls);
+  }
+  new_cls.CopyCanonicalType(old_cls);
+  AddBecomeMapping(old_cls, new_cls);
+  AddClassMapping(new_cls, old_cls);
+}
+
+
+void IsolateReloadContext::FinishReload() {
+  BuildLibraryMapping();
+  TIR_Print("---- DONE FINALIZING\n");
+  if (ValidateReload()) {
+    Commit();
+    PostCommit();
+  } else {
+    Rollback();
+  }
+  // ValidateReload mutates the direct subclass information and does
+  // not remove dead subclasses.  Rebuild the direct subclass
+  // information from scratch.
+  RebuildDirectSubclasses();
+
+  if (FLAG_write_protect_code) {
+    // Disable code page write protection while we are reloading.
+    I->heap()->WriteProtectCode(true);
+  }
+
+  BackgroundCompiler::Enable();
+}
+
+
+void IsolateReloadContext::AbortReload(const Error& error) {
+  ReportError(error);
+  Rollback();
+}
+
+
+void IsolateReloadContext::EnsuredUnoptimizedCodeForStack() {
+  TIMELINE_SCOPE(EnsuredUnoptimizedCodeForStack);
+  StackFrameIterator it(StackFrameIterator::kDontValidateFrames);
+
+  Function& func = Function::Handle();
+  while (it.HasNextFrame()) {
+    StackFrame* frame = it.NextFrame();
+    if (frame->IsDartFrame()) {
+      func = frame->LookupDartFunction();
+      ASSERT(!func.IsNull());
+      func.EnsureHasCompiledUnoptimizedCode();
+    }
+  }
+}
+
+
+void IsolateReloadContext::DeoptimizeDependentCode() {
+  ClassTable* class_table = I->class_table();
+
+  const intptr_t bottom = Dart::vm_isolate()->class_table()->NumCids();
+  const intptr_t top = I->class_table()->NumCids();
+  Class& cls = Class::Handle();
+  Array& fields = Array::Handle();
+  Field& field = Field::Handle();
+  for (intptr_t cls_idx = bottom; cls_idx < top; cls_idx++) {
+    if (!class_table->HasValidClassAt(cls_idx)) {
+      // Skip.
+      continue;
+    }
+
+    // Deoptimize CHA code.
+    cls = class_table->At(cls_idx);
+    ASSERT(!cls.IsNull());
+
+    cls.DisableAllCHAOptimizedCode();
+
+    // Deoptimize field guard code.
+    fields = cls.fields();
+    ASSERT(!fields.IsNull());
+    for (intptr_t field_idx = 0; field_idx < fields.Length(); field_idx++) {
+      field = Field::RawCast(fields.At(field_idx));
+      ASSERT(!field.IsNull());
+      field.DeoptimizeDependentCode();
+    }
+  }
+
+  // TODO(johnmccutchan): Also call LibraryPrefix::InvalidateDependentCode.
+}
+
+
+void IsolateReloadContext::CheckpointClasses() {
+  TIMELINE_SCOPE(CheckpointClasses);
+  TIR_Print("---- CHECKPOINTING CLASSES\n");
+  // Checkpoint classes before a reload. We need to copy the following:
+  // 1) The size of the class table.
+  // 2) The class table itself.
+  // For efficiency, we build a set of classes before the reload. This set
+  // is used to pair new classes with old classes.
+
+  ClassTable* class_table = I->class_table();
+
+  // Copy the size of the class table.
+  saved_num_cids_ = I->class_table()->NumCids();
+
+  // Copy of the class table.
+  RawClass** local_saved_class_table =
+      reinterpret_cast<RawClass**>(malloc(sizeof(RawClass*) * saved_num_cids_));
+
+  Class& cls = Class::Handle();
+  UnorderedHashSet<ClassMapTraits> old_classes_set(old_classes_set_storage_);
+  for (intptr_t i = 0; i < saved_num_cids_; i++) {
+    if (class_table->IsValidIndex(i) &&
+        class_table->HasValidClassAt(i)) {
+      // Copy the class into the saved class table and add it to the set.
+      local_saved_class_table[i] = class_table->At(i);
+      if (i != kFreeListElement) {
+        cls = class_table->At(i);
+        bool already_present = old_classes_set.Insert(cls);
+        ASSERT(!already_present);
+      }
+    } else {
+      // No class at this index, mark it as NULL.
+      local_saved_class_table[i] = NULL;
+    }
+  }
+  old_classes_set_storage_ = old_classes_set.Release().raw();
+  // Assigning the field must be done after saving the class table.
+  saved_class_table_ = local_saved_class_table;
+  TIR_Print("---- System had %" Pd " classes\n", saved_num_cids_);
+}
+
+
+bool IsolateReloadContext::IsCleanLibrary(const Library& lib) {
+  return lib.is_dart_scheme();
+}
+
+
+void IsolateReloadContext::CheckpointLibraries() {
+  TIMELINE_SCOPE(CheckpointLibraries);
+
+  // Save the root library in case we abort the reload.
+  const Library& root_lib =
+      Library::Handle(object_store()->root_library());
+  set_saved_root_library(root_lib);
+
+  // Save the old libraries array in case we abort the reload.
+  const GrowableObjectArray& libs =
+      GrowableObjectArray::Handle(object_store()->libraries());
+  set_saved_libraries(libs);
+
+  // Make a filtered copy of the old libraries array. Keep "clean" libraries
+  // that we will use instead of reloading.
+  const GrowableObjectArray& new_libs = GrowableObjectArray::Handle(
+      GrowableObjectArray::New(Heap::kOld));
+  Library& lib = Library::Handle();
+  UnorderedHashSet<LibraryMapTraits>
+      old_libraries_set(old_libraries_set_storage_);
+  num_saved_libs_ = 0;
+  for (intptr_t i = 0; i < libs.Length(); i++) {
+    lib ^= libs.At(i);
+    if (IsCleanLibrary(lib)) {
+      // We are preserving this library across the reload, assign its new index
+      lib.set_index(new_libs.Length());
+      new_libs.Add(lib, Heap::kOld);
+      num_saved_libs_++;
+    } else {
+      // We are going to reload this library. Clear the index.
+      lib.set_index(-1);
+    }
+    // Add old library to old libraries set.
+    bool already_present = old_libraries_set.Insert(lib);
+    ASSERT(!already_present);
+  }
+  old_libraries_set_storage_ = old_libraries_set.Release().raw();
+
+  // Reset the registered libraries to the filtered array.
+  Library::RegisterLibraries(Thread::Current(), new_libs);
+  // Reset the root library to null.
+  object_store()->set_root_library(Library::Handle());
+}
+
+
+void IsolateReloadContext::BuildCleanScriptSet() {
+  const GrowableObjectArray& libs =
+      GrowableObjectArray::Handle(object_store()->libraries());
+
+  UnorderedHashSet<ScriptUrlSetTraits>
+      clean_scripts_set(clean_scripts_set_storage_);
+
+  Library& lib = Library::Handle();
+  Array& scripts = Array::Handle();
+  Script& script = Script::Handle();
+  String& script_url = String::Handle();
+  for (intptr_t lib_idx = 0; lib_idx < libs.Length(); lib_idx++) {
+    lib = Library::RawCast(libs.At(lib_idx));
+    ASSERT(!lib.IsNull());
+    ASSERT(IsCleanLibrary(lib));
+    scripts = lib.LoadedScripts();
+    ASSERT(!scripts.IsNull());
+    for (intptr_t script_idx = 0; script_idx < scripts.Length(); script_idx++) {
+      script = Script::RawCast(scripts.At(script_idx));
+      ASSERT(!script.IsNull());
+      script_url = script.url();
+      ASSERT(!script_url.IsNull());
+      bool already_present = clean_scripts_set.Insert(script_url);
+      ASSERT(!already_present);
+    }
+  }
+
+  clean_scripts_set_storage_ = clean_scripts_set.Release().raw();
+}
+
+
+void IsolateReloadContext::FilterCompileTimeConstants() {
+  // Save the compile time constants array.
+  compile_time_constants_ = I->object_store()->compile_time_constants();
+  // Clear the compile time constants array. This will be repopulated
+  // in the loop below.
+  I->object_store()->set_compile_time_constants(Array::Handle());
+
+  if (compile_time_constants_ == Array::null()) {
+    // Nothing to do.
+    return;
+  }
+
+  // Iterate over the saved compile time constants map.
+  ConstantsMap old_constants(compile_time_constants_);
+  ConstantsMap::Iterator it(&old_constants);
+
+  Array& key = Array::Handle();
+  String& url = String::Handle();
+  Smi& token_pos = Smi::Handle();
+  Instance& value = Instance::Handle();
+
+  // We filter the compile time constants map so that after it only contains
+  // constants from scripts contained in this set.
+  UnorderedHashSet<ScriptUrlSetTraits>
+      clean_scripts_set(clean_scripts_set_storage_);
+
+  while (it.MoveNext()) {
+    const intptr_t entry = it.Current();
+    ASSERT(entry != -1);
+    key = Array::RawCast(old_constants.GetKey(entry));
+    ASSERT(!key.IsNull());
+    url = String::RawCast(key.At(0));
+    ASSERT(!url.IsNull());
+    if (clean_scripts_set.ContainsKey(url)) {
+      // We've found a cached constant from a clean script, add it to the
+      // compile time constants map again.
+      token_pos = Smi::RawCast(key.At(1));
+      TokenPosition tp(token_pos.Value());
+      // Use ^= because this might be null.
+      value ^= old_constants.GetPayload(entry, 0);
+      Parser::InsertCachedConstantValue(url, tp, value);
+    }
+  }
+
+  old_constants.Release();
+  clean_scripts_set.Release();
+}
+
+
+// While reloading everything we do must be reversible so that we can abort
+// safely if the reload fails. This function stashes things to the side and
+// prepares the isolate for the reload attempt.
+void IsolateReloadContext::Checkpoint() {
+  TIMELINE_SCOPE(Checkpoint);
+  CheckpointClasses();
+  CheckpointLibraries();
+  BuildCleanScriptSet();
+  FilterCompileTimeConstants();
+}
+
+
+void IsolateReloadContext::RollbackClasses() {
+  TIR_Print("---- ROLLING BACK CLASS TABLE\n");
+  ASSERT(saved_num_cids_ > 0);
+  ASSERT(saved_class_table_ != NULL);
+  ClassTable* class_table = I->class_table();
+  class_table->SetNumCids(saved_num_cids_);
+  // Overwrite classes in class table with the saved classes.
+  for (intptr_t i = 0; i < saved_num_cids_; i++) {
+    if (class_table->IsValidIndex(i)) {
+      class_table->SetAt(i, saved_class_table_[i]);
+    }
+  }
+  free(saved_class_table_);
+  saved_class_table_ = NULL;
+  saved_num_cids_ = 0;
+}
+
+
+void IsolateReloadContext::RollbackLibraries() {
+  TIR_Print("---- ROLLING BACK LIBRARY CHANGES\n");
+  Thread* thread = Thread::Current();
+  Library& lib = Library::Handle();
+  GrowableObjectArray& saved_libs = GrowableObjectArray::Handle(
+      Z, saved_libraries());
+  if (!saved_libs.IsNull()) {
+    for (intptr_t i = 0; i < saved_libs.Length(); i++) {
+      lib = Library::RawCast(saved_libs.At(i));
+      // Restore indexes that were modified in CheckpointLibraries.
+      lib.set_index(i);
+    }
+
+    // Reset the registered libraries to the filtered array.
+    Library::RegisterLibraries(Thread::Current(), saved_libs);
+  }
+
+  Library& saved_root_lib = Library::Handle(Z, saved_root_library());
+  if (!saved_root_lib.IsNull()) {
+    object_store()->set_root_library(saved_root_lib);
+  }
+
+  set_saved_root_library(Library::Handle());
+  set_saved_libraries(GrowableObjectArray::Handle());
+}
+
+
+void IsolateReloadContext::Rollback() {
+  I->object_store()->set_compile_time_constants(
+      Array::Handle(compile_time_constants_));
+  RollbackClasses();
+  RollbackLibraries();
+}
+
+
+#ifdef DEBUG
+void IsolateReloadContext::VerifyMaps() {
+  Class& cls = Class::Handle();
+  Class& new_cls = Class::Handle();
+  Class& cls2 = Class::Handle();
+  Class& new_cls2 = Class::Handle();
+
+  // Verify that two old classes aren't both mapped to the same new
+  // class.  This could happen is the IsSameClass function is broken.
+  UnorderedHashMap<ClassMapTraits> class_map(class_map_storage_);
+  {
+    UnorderedHashMap<ClassMapTraits>::Iterator it(&class_map);
+    while (it.MoveNext()) {
+      const intptr_t entry = it.Current();
+      new_cls = Class::RawCast(class_map.GetKey(entry));
+      cls = Class::RawCast(class_map.GetPayload(entry, 0));
+      if (new_cls.raw() != cls.raw()) {
+        UnorderedHashMap<ClassMapTraits>::Iterator it2(&class_map);
+        while (it2.MoveNext()) {
+          new_cls2 = Class::RawCast(class_map.GetKey(entry));
+          if (new_cls.raw() == new_cls2.raw()) {
+            cls2 = Class::RawCast(class_map.GetPayload(entry, 0));
+            if (cls.raw() != cls2.raw()) {
+              OS::PrintErr(
+                  "Classes '%s' and '%s' are distinct classes but both map to "
+                  "class '%s'\n",
+                  cls.ToCString(), cls2.ToCString(), new_cls.ToCString());
+              UNREACHABLE();
+            }
+          }
+        }
+      }
+    }
+  }
+  class_map.Release();
+}
+#endif
+
+
+void IsolateReloadContext::Commit() {
+  TIMELINE_SCOPE(Commit);
+  TIR_Print("---- COMMITTING REVERSE MAP\n");
+
+#ifdef DEBUG
+  VerifyMaps();
+#endif
+
+  {
+    TIMELINE_SCOPE(CopyStaticFieldsAndPatchFieldsAndFunctions);
+    // Copy static field values from the old classes to the new classes.
+    // Patch fields and functions in the old classes so that they retain
+    // the old script.
+    Class& cls = Class::Handle();
+    Class& new_cls = Class::Handle();
+
+    UnorderedHashMap<ClassMapTraits> class_map(class_map_storage_);
+
+    {
+      UnorderedHashMap<ClassMapTraits>::Iterator it(&class_map);
+      while (it.MoveNext()) {
+        const intptr_t entry = it.Current();
+        new_cls = Class::RawCast(class_map.GetKey(entry));
+        cls = Class::RawCast(class_map.GetPayload(entry, 0));
+        if (new_cls.raw() != cls.raw()) {
+          ASSERT(new_cls.is_enum_class() == cls.is_enum_class());
+          if (new_cls.is_enum_class() && new_cls.is_finalized()) {
+            new_cls.ReplaceEnum(cls);
+          }
+          new_cls.CopyStaticFieldValues(cls);
+          cls.PatchFieldsAndFunctions();
+        }
+      }
+    }
+
+    class_map.Release();
+  }
+
+  // Copy over certain properties of libraries, e.g. is the library
+  // debuggable?
+  {
+    TIMELINE_SCOPE(CopyLibraryBits);
+    Library& lib = Library::Handle();
+    Library& new_lib = Library::Handle();
+
+    UnorderedHashMap<LibraryMapTraits> lib_map(library_map_storage_);
+
+    {
+      // Reload existing libraries.
+      UnorderedHashMap<LibraryMapTraits>::Iterator it(&lib_map);
+
+      while (it.MoveNext()) {
+        const intptr_t entry = it.Current();
+        ASSERT(entry != -1);
+        new_lib = Library::RawCast(lib_map.GetKey(entry));
+        lib = Library::RawCast(lib_map.GetPayload(entry, 0));
+        new_lib.set_debuggable(lib.IsDebuggable());
+      }
+    }
+
+    // Release the library map.
+    lib_map.Release();
+  }
+
+  {
+    TIMELINE_SCOPE(UpdateLibrariesArray);
+    // Update the libraries array.
+    Library& lib = Library::Handle();
+    const GrowableObjectArray& libs = GrowableObjectArray::Handle(
+        I->object_store()->libraries());
+    for (intptr_t i = 0; i < libs.Length(); i++) {
+      lib = Library::RawCast(libs.At(i));
+      TIR_Print("Lib '%s' at index %" Pd "\n", lib.ToCString(), i);
+      lib.set_index(i);
+    }
+
+    // Initialize library side table.
+    library_infos_.SetLength(libs.Length());
+    for (intptr_t i = 0; i < libs.Length(); i++) {
+      lib = Library::RawCast(libs.At(i));
+      // Mark the library dirty if it comes after the libraries we saved.
+      library_infos_[i].dirty = i >= num_saved_libs_;
+    }
+  }
+
+  {
+    UnorderedHashMap<BecomeMapTraits> become_map(become_map_storage_);
+    intptr_t replacement_count = become_map.NumOccupied();
+    const Array& before =
+        Array::Handle(Array::New(replacement_count, Heap::kOld));
+    const Array& after =
+        Array::Handle(Array::New(replacement_count, Heap::kOld));
+    Object& obj = Object::Handle();
+    intptr_t replacement_index = 0;
+    UnorderedHashMap<BecomeMapTraits>::Iterator it(&become_map);
+    while (it.MoveNext()) {
+      const intptr_t entry = it.Current();
+      obj = become_map.GetKey(entry);
+      before.SetAt(replacement_index, obj);
+      obj = become_map.GetPayload(entry, 0);
+      after.SetAt(replacement_index, obj);
+      replacement_index++;
+    }
+    ASSERT(replacement_index == replacement_count);
+    become_map.Release();
+
+    Become::ElementsForwardIdentity(before, after);
+  }
+
+  if (FLAG_identity_reload) {
+    if (saved_num_cids_ != I->class_table()->NumCids()) {
+      TIR_Print("Identity reload failed! B#C=%" Pd " A#C=%" Pd "\n",
+                saved_num_cids_,
+                I->class_table()->NumCids());
+    }
+    const GrowableObjectArray& saved_libs =
+        GrowableObjectArray::Handle(saved_libraries());
+    const GrowableObjectArray& libs =
+        GrowableObjectArray::Handle(I->object_store()->libraries());
+    if (saved_libs.Length() != libs.Length()) {
+     TIR_Print("Identity reload failed! B#L=%" Pd " A#L=%" Pd "\n",
+               saved_libs.Length(),
+               libs.Length());
+    }
+  }
+}
+
+
+bool IsolateReloadContext::IsDirty(const Library& lib) {
+  const intptr_t index = lib.index();
+  if (index == static_cast<classid_t>(-1)) {
+    // Treat deleted libraries as dirty.
+    return true;
+  }
+  ASSERT((index >= 0) && (index < library_infos_.length()));
+  return library_infos_[index].dirty;
+}
+
+
+void IsolateReloadContext::PostCommit() {
+  TIMELINE_SCOPE(PostCommit);
+  set_saved_root_library(Library::Handle());
+  set_saved_libraries(GrowableObjectArray::Handle());
+  InvalidateWorld();
+}
+
+
+bool IsolateReloadContext::ValidateReload() {
+  TIMELINE_SCOPE(ValidateReload);
+  if (has_error_) {
+    return false;
+  }
+
+  // Already built.
+  ASSERT(class_map_storage_ != Array::null());
+  UnorderedHashMap<ClassMapTraits> map(class_map_storage_);
+  UnorderedHashMap<ClassMapTraits>::Iterator it(&map);
+  Class& cls = Class::Handle();
+  Class& new_cls = Class::Handle();
+  while (it.MoveNext()) {
+    const intptr_t entry = it.Current();
+    new_cls = Class::RawCast(map.GetKey(entry));
+    cls = Class::RawCast(map.GetPayload(entry, 0));
+    if (new_cls.raw() != cls.raw()) {
+      if (!cls.CanReload(new_cls)) {
+        map.Release();
+        return false;
+      }
+    }
+  }
+  map.Release();
+  return true;
+}
+
+
+RawClass* IsolateReloadContext::FindOriginalClass(const Class& cls) {
+  return MappedClass(cls);
+}
+
+
+RawClass* IsolateReloadContext::GetClassForHeapWalkAt(intptr_t cid) {
+  if (saved_class_table_ != NULL) {
+    ASSERT(cid > 0);
+    ASSERT(cid < saved_num_cids_);
+    return saved_class_table_[cid];
+  } else {
+    return isolate_->class_table()->At(cid);
+  }
+}
+
+
+RawLibrary* IsolateReloadContext::saved_root_library() const {
+  return saved_root_library_;
+}
+
+
+void IsolateReloadContext::set_saved_root_library(const Library& value) {
+  saved_root_library_ = value.raw();
+}
+
+
+RawGrowableObjectArray* IsolateReloadContext::saved_libraries() const {
+  return saved_libraries_;
+}
+
+
+void IsolateReloadContext::set_saved_libraries(
+    const GrowableObjectArray& value) {
+  saved_libraries_ = value.raw();
+}
+
+
+void IsolateReloadContext::VisitObjectPointers(ObjectPointerVisitor* visitor) {
+  visitor->VisitPointers(from(), to());
+  if (saved_class_table_ != NULL) {
+    visitor->VisitPointers(
+        reinterpret_cast<RawObject**>(&saved_class_table_[0]), saved_num_cids_);
+  }
+}
+
+
+ObjectStore* IsolateReloadContext::object_store() {
+  return isolate_->object_store();
+}
+
+
+static void ResetICs(const Function& function, const Code& code) {
+  // TODO(johnmccutchan): Relying on the function's ICData Map can miss ICDatas.
+  // Use the code's object pool instead.
+  if (function.ic_data_array() == Array::null()) {
+    // TODO(johnmccutchan): Even in this case, we need to scan the code's object
+    // pool instead.
+    return;  // Already reset in an earlier round.
+  }
+
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+
+  ZoneGrowableArray<const ICData*>* ic_data_array =
+      new(zone) ZoneGrowableArray<const ICData*>();
+  function.RestoreICDataMap(ic_data_array, false /* clone ic-data */);
+  const intptr_t ic_data_array_length = ic_data_array->length();
+  if (ic_data_array_length == 0) {
+    return;
+  }
+  const PcDescriptors& descriptors =
+      PcDescriptors::Handle(code.pc_descriptors());
+  PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kIcCall |
+                                            RawPcDescriptors::kUnoptStaticCall);
+  while (iter.MoveNext()) {
+    const intptr_t index = iter.DeoptId();
+    if (index >= ic_data_array_length) {
+      // TODO(johnmccutchan): Investigate how this can happen.
+      continue;
+    }
+    const ICData* ic_data = (*ic_data_array)[index];
+    if (ic_data == NULL) {
+      // TODO(johnmccutchan): Investigate how this can happen.
+      continue;
+    }
+    bool is_static_call = iter.Kind() == RawPcDescriptors::kUnoptStaticCall;
+    ic_data->Reset(is_static_call);
+  }
+}
+
+
+void IsolateReloadContext::ResetUnoptimizedICsOnStack() {
+  Code& code = Code::Handle();
+  Function& function = Function::Handle();
+  DartFrameIterator iterator;
+  StackFrame* frame = iterator.NextFrame();
+  while (frame != NULL) {
+    code = frame->LookupDartCode();
+    if (code.is_optimized()) {
+      // If this code is optimized, we need to reset the ICs in the
+      // corresponding unoptimized code, which will be executed when the stack
+      // unwinds to the the optimized code.
+      function = code.function();
+      code = function.unoptimized_code();
+      ASSERT(!code.IsNull());
+      ResetICs(function, code);
+    } else {
+      function = code.function();
+      ResetICs(function, code);
+    }
+    frame = iterator.NextFrame();
+  }
+}
+
+
+void IsolateReloadContext::ResetMegamorphicCaches() {
+  object_store()->set_megamorphic_cache_table(GrowableObjectArray::Handle());
+  // Since any current optimized code will not make any more calls, it may be
+  // better to clear the table instead of clearing each of the caches, allow
+  // the current megamorphic caches get GC'd and any new optimized code allocate
+  // new ones.
+}
+
+
+class MarkFunctionsForRecompilation : public ObjectVisitor {
+ public:
+  MarkFunctionsForRecompilation(Isolate* isolate,
+                                IsolateReloadContext* reload_context)
+    : ObjectVisitor(),
+      handle_(Object::Handle()),
+      owning_class_(Class::Handle()),
+      owning_lib_(Library::Handle()),
+      code_(Code::Handle()),
+      reload_context_(reload_context) {
+  }
+
+  virtual void VisitObject(RawObject* obj) {
+    // Free-list elements cannot even be wrapped in handles.
+    if (obj->IsFreeListElement()) {
+      return;
+    }
+    handle_ = obj;
+    if (handle_.IsFunction()) {
+      const Function& func = Function::Cast(handle_);
+
+      // Switch to unoptimized code or the lazy compilation stub.
+      func.SwitchToLazyCompiledUnoptimizedCode();
+
+      // Grab the current code.
+      code_ = func.CurrentCode();
+      ASSERT(!code_.IsNull());
+      const bool clear_code = IsFromDirtyLibrary(func);
+      const bool stub_code = code_.IsStubCode();
+
+      // Zero edge counters.
+      func.ZeroEdgeCounters();
+
+      if (!stub_code) {
+        if (clear_code) {
+          ClearAllCode(func);
+        } else {
+          PreserveUnoptimizedCode(func);
+        }
+      }
+
+      // Clear counters.
+      func.set_usage_counter(0);
+      func.set_deoptimization_counter(0);
+      func.set_optimized_instruction_count(0);
+      func.set_optimized_call_site_count(0);
+    }
+  }
+
+ private:
+  void ClearAllCode(const Function& func) {
+    // Null out the ICData array and code.
+    func.ClearICDataArray();
+    func.ClearCode();
+    func.set_was_compiled(false);
+  }
+
+  void PreserveUnoptimizedCode(const Function& func) {
+    ASSERT(!code_.IsNull());
+    // We are preserving the unoptimized code, fill all ICData arrays with
+    // the sentinel values so that we have no stale type feedback.
+    func.FillICDataWithSentinels(code_);
+  }
+
+  bool IsFromDirtyLibrary(const Function& func) {
+    owning_class_ = func.Owner();
+    owning_lib_ = owning_class_.library();
+    return reload_context_->IsDirty(owning_lib_);
+  }
+
+  Object& handle_;
+  Class& owning_class_;
+  Library& owning_lib_;
+  Code& code_;
+  IsolateReloadContext* reload_context_;
+};
+
+
+void IsolateReloadContext::MarkAllFunctionsForRecompilation() {
+  TIMELINE_SCOPE(MarkAllFunctionsForRecompilation);
+  NoSafepointScope no_safepoint;
+  HeapIterationScope heap_iteration_scope;
+  MarkFunctionsForRecompilation visitor(isolate_, this);
+  isolate_->heap()->VisitObjects(&visitor);
+}
+
+
+void IsolateReloadContext::InvalidateWorld() {
+  ResetMegamorphicCaches();
+  DeoptimizeFunctionsOnStack();
+  ResetUnoptimizedICsOnStack();
+  MarkAllFunctionsForRecompilation();
+}
+
+
+RawClass* IsolateReloadContext::MappedClass(const Class& replacement_or_new) {
+  UnorderedHashMap<ClassMapTraits> map(class_map_storage_);
+  Class& cls = Class::Handle();
+  cls ^= map.GetOrNull(replacement_or_new);
+  // No need to update storage address because no mutation occurred.
+  map.Release();
+  return cls.raw();
+}
+
+
+RawLibrary* IsolateReloadContext::MappedLibrary(
+    const Library& replacement_or_new) {
+  return Library::null();
+}
+
+
+RawClass* IsolateReloadContext::OldClassOrNull(
+    const Class& replacement_or_new) {
+  UnorderedHashSet<ClassMapTraits> old_classes_set(old_classes_set_storage_);
+  Class& cls = Class::Handle();
+  cls ^= old_classes_set.GetOrNull(replacement_or_new);
+  old_classes_set_storage_ = old_classes_set.Release().raw();
+  return cls.raw();
+}
+
+
+RawLibrary* IsolateReloadContext::OldLibraryOrNull(
+    const Library& replacement_or_new) {
+  UnorderedHashSet<LibraryMapTraits>
+      old_libraries_set(old_libraries_set_storage_);
+  Library& lib = Library::Handle();
+  lib ^= old_libraries_set.GetOrNull(replacement_or_new);
+  old_libraries_set_storage_ = old_libraries_set.Release().raw();
+  return lib.raw();
+}
+
+
+void IsolateReloadContext::BuildLibraryMapping() {
+  const GrowableObjectArray& libs =
+      GrowableObjectArray::Handle(object_store()->libraries());
+
+  Library& replacement_or_new = Library::Handle();
+  Library& old = Library::Handle();
+  for (intptr_t i = 0; i < libs.Length(); i++) {
+    replacement_or_new = Library::RawCast(libs.At(i));
+    if (IsCleanLibrary(replacement_or_new)) {
+      continue;
+    }
+    old ^= OldLibraryOrNull(replacement_or_new);
+    if (old.IsNull()) {
+      // New library.
+      AddLibraryMapping(replacement_or_new, replacement_or_new);
+    } else {
+      ASSERT(!replacement_or_new.is_dart_scheme());
+      // Replaced class.
+      AddLibraryMapping(replacement_or_new, old);
+
+      AddBecomeMapping(old, replacement_or_new);
+    }
+  }
+}
+
+
+void IsolateReloadContext::AddClassMapping(const Class& replacement_or_new,
+                                           const Class& original) {
+  UnorderedHashMap<ClassMapTraits> map(class_map_storage_);
+  bool update = map.UpdateOrInsert(replacement_or_new, original);
+  ASSERT(!update);
+  // The storage given to the map may have been reallocated, remember the new
+  // address.
+  class_map_storage_ = map.Release().raw();
+}
+
+
+void IsolateReloadContext::AddLibraryMapping(const Library& replacement_or_new,
+                                             const Library& original) {
+  UnorderedHashMap<LibraryMapTraits> map(library_map_storage_);
+  bool update = map.UpdateOrInsert(replacement_or_new, original);
+  ASSERT(!update);
+  // The storage given to the map may have been reallocated, remember the new
+  // address.
+  library_map_storage_ = map.Release().raw();
+}
+
+
+void IsolateReloadContext::AddStaticFieldMapping(
+    const Field& old_field, const Field& new_field) {
+  ASSERT(old_field.is_static());
+  ASSERT(new_field.is_static());
+
+  AddBecomeMapping(old_field, new_field);
+}
+
+
+void IsolateReloadContext::AddBecomeMapping(const Object& old,
+                                            const Object& neu) {
+  ASSERT(become_map_storage_ != Array::null());
+  UnorderedHashMap<BecomeMapTraits> become_map(become_map_storage_);
+  bool update = become_map.UpdateOrInsert(old, neu);
+  ASSERT(!update);
+  become_map_storage_ = become_map.Release().raw();
+}
+
+
+void IsolateReloadContext::RebuildDirectSubclasses() {
+  ClassTable* class_table = I->class_table();
+  intptr_t num_cids = class_table->NumCids();
+
+  // Clear the direct subclasses for all classes.
+  Class& cls = Class::Handle();
+  GrowableObjectArray& subclasses = GrowableObjectArray::Handle();
+  for (intptr_t i = 1; i < num_cids; i++) {
+    if (class_table->HasValidClassAt(i)) {
+      cls = class_table->At(i);
+      subclasses = cls.direct_subclasses();
+      if (!subclasses.IsNull()) {
+        subclasses.SetLength(0);
+      }
+    }
+  }
+
+  // Recompute the direct subclasses.
+  AbstractType& super_type = AbstractType::Handle();
+  Class& super_cls = Class::Handle();
+  for (intptr_t i = 1; i < num_cids; i++) {
+    if (class_table->HasValidClassAt(i)) {
+      cls = class_table->At(i);
+      super_type = cls.super_type();
+      if (!super_type.IsNull() && !super_type.IsObjectType()) {
+        super_cls = cls.SuperClass();
+        ASSERT(!super_cls.IsNull());
+        super_cls.AddDirectSubclass(cls);
+      }
+    }
+  }
+}
+
+#endif  // !PRODUCT
+
+}  // namespace dart
diff --git a/runtime/vm/isolate_reload.h b/runtime/vm/isolate_reload.h
new file mode 100644
index 0000000..d439414
--- /dev/null
+++ b/runtime/vm/isolate_reload.h
@@ -0,0 +1,174 @@
+// Copyright (c) 2016, 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.
+
+#ifndef VM_ISOLATE_RELOAD_H_
+#define VM_ISOLATE_RELOAD_H_
+
+#include "vm/globals.h"
+#include "vm/growable_array.h"
+#include "vm/log.h"
+
+DECLARE_FLAG(bool, trace_reload);
+
+// 'Trace Isolate Reload' TIR_Print
+#if defined(_MSC_VER)
+#define TIR_Print(format, ...) \
+    if (FLAG_trace_reload) Log::Current()->Print(format, __VA_ARGS__)
+#else
+#define TIR_Print(format, ...) \
+    if (FLAG_trace_reload) Log::Current()->Print(format, ##__VA_ARGS__)
+#endif
+
+namespace dart {
+
+class GrowableObjectArray;
+class Isolate;
+class Library;
+class RawError;
+class RawGrowableObjectArray;
+class RawLibrary;
+class RawObject;
+class RawString;
+class ObjectPointerVisitor;
+class ObjectStore;
+class UpdateClassesVisitor;
+
+class IsolateReloadContext {
+ public:
+  explicit IsolateReloadContext(Isolate* isolate, bool test_mode = false);
+  ~IsolateReloadContext();
+
+  void StartReload();
+  void FinishReload();
+  void AbortReload(const Error& error);
+
+  RawLibrary* saved_root_library() const;
+
+  RawGrowableObjectArray* saved_libraries() const;
+
+  void ReportError(const Error& error);
+  void ReportError(const String& error_msg);
+  void ReportSuccess();
+
+  bool has_error() const { return has_error_; }
+  RawError* error() const { return error_; }
+  bool test_mode() const { return test_mode_; }
+
+  static bool IsSameField(const Field& a, const Field& b);
+  static bool IsSameLibrary(const Library& a_lib, const Library& b_lib);
+  static bool IsSameClass(const Class& a, const Class& b);
+
+  RawClass* FindOriginalClass(const Class& cls);
+
+  bool IsDirty(const Library& lib);
+
+  // Prefers old classes when we are in the middle of a reload.
+  RawClass* GetClassForHeapWalkAt(intptr_t cid);
+
+  void RegisterClass(const Class& new_cls);
+
+  int64_t start_time_micros() const { return start_time_micros_; }
+
+ private:
+  void set_saved_root_library(const Library& value);
+
+  void set_saved_libraries(const GrowableObjectArray& value);
+
+  void VisitObjectPointers(ObjectPointerVisitor* visitor);
+
+  Isolate* isolate() { return isolate_; }
+  ObjectStore* object_store();
+
+  void EnsuredUnoptimizedCodeForStack();
+  void DeoptimizeDependentCode();
+
+  void Checkpoint();
+
+  void CheckpointClasses();
+
+  // Is |lib| a library whose sources have not changed?
+  bool IsCleanLibrary(const Library& lib);
+  void CheckpointLibraries();
+
+  bool ValidateReload();
+
+  void Rollback();
+
+  void RollbackClasses();
+  void RollbackLibraries();
+
+#ifdef DEBUG
+  void VerifyMaps();
+#endif
+
+  void Commit();
+
+  void PostCommit();
+
+  void ClearReplacedObjectBits();
+
+  void BuildCleanScriptSet();
+  void FilterCompileTimeConstants();
+
+  // atomic_install:
+  void MarkAllFunctionsForRecompilation();
+  void ResetUnoptimizedICsOnStack();
+  void ResetMegamorphicCaches();
+  void InvalidateWorld();
+
+  int64_t start_time_micros_;
+  Isolate* isolate_;
+  bool test_mode_;
+  bool has_error_;
+
+  intptr_t saved_num_cids_;
+  RawClass** saved_class_table_;
+
+  intptr_t num_saved_libs_;
+  struct LibraryInfo {
+    bool dirty;
+  };
+  MallocGrowableArray<LibraryInfo> library_infos_;
+
+  RawClass* OldClassOrNull(const Class& replacement_or_new);
+
+  RawLibrary* OldLibraryOrNull(const Library& replacement_or_new);
+  void BuildLibraryMapping();
+
+  void AddClassMapping(const Class& replacement_or_new,
+                       const Class& original);
+
+  void AddLibraryMapping(const Library& replacement_or_new,
+                         const Library& original);
+
+  void AddStaticFieldMapping(const Field& old_field, const Field& new_field);
+
+  void AddBecomeMapping(const Object& old, const Object& nue);
+
+  void RebuildDirectSubclasses();
+
+  RawClass* MappedClass(const Class& replacement_or_new);
+  RawLibrary* MappedLibrary(const Library& replacement_or_new);
+
+  RawObject** from() { return reinterpret_cast<RawObject**>(&script_uri_); }
+  RawString* script_uri_;
+  RawError* error_;
+  RawArray* clean_scripts_set_storage_;
+  RawArray* compile_time_constants_;
+  RawArray* old_classes_set_storage_;
+  RawArray* class_map_storage_;
+  RawArray* old_libraries_set_storage_;
+  RawArray* library_map_storage_;
+  RawArray* become_map_storage_;
+  RawLibrary* saved_root_library_;
+  RawGrowableObjectArray* saved_libraries_;
+  RawObject** to() { return reinterpret_cast<RawObject**>(&saved_libraries_); }
+
+  friend class Isolate;
+  friend class Class;  // AddStaticFieldMapping.
+};
+
+}  // namespace dart
+
+#endif   // VM_ISOLATE_RELOAD_H_
diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc
new file mode 100644
index 0000000..b6d1382
--- /dev/null
+++ b/runtime/vm/isolate_reload_test.cc
@@ -0,0 +1,1832 @@
+// Copyright (c) 2016, 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.
+
+#include "include/dart_api.h"
+#include "include/dart_tools_api.h"
+#include "platform/assert.h"
+#include "vm/globals.h"
+#include "vm/isolate.h"
+#include "vm/lockers.h"
+#include "vm/thread_barrier.h"
+#include "vm/thread_pool.h"
+#include "vm/unit_test.h"
+
+namespace dart {
+
+#ifndef PRODUCT
+
+// TODO(johnmccutchan):
+// - Tests involving generics.
+
+int64_t SimpleInvoke(Dart_Handle lib, const char* method) {
+  Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, NULL);
+  EXPECT_VALID(result);
+  EXPECT(Dart_IsInteger(result));
+  int64_t integer_result = 0;
+  result = Dart_IntegerToInt64(result, &integer_result);
+  EXPECT_VALID(result);
+  return integer_result;
+}
+
+
+const char* SimpleInvokeStr(Dart_Handle lib, const char* method) {
+  Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, NULL);
+  const char* result_str = NULL;
+  EXPECT(Dart_IsString(result));
+  EXPECT_VALID(Dart_StringToCString(result, &result_str));
+  return result_str;
+}
+
+
+Dart_Handle SimpleInvokeError(Dart_Handle lib, const char* method) {
+  Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, NULL);
+  EXPECT(Dart_IsError(result));
+  return result;
+}
+
+
+TEST_CASE(IsolateReload_FunctionReplacement) {
+  const char* kScript =
+      "main() {\n"
+      "  return 4;\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+
+  const char* kReloadScript =
+      "var _unused;"
+      "main() {\n"
+      "  return 10;\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_EQ(10, SimpleInvoke(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_BadClass) {
+  const char* kScript =
+      "class Foo {\n"
+      "  final a;\n"
+      "  Foo(this.a);\n"
+      "}\n"
+      "main() {\n"
+      "  new Foo(5);\n"
+      "  return 4;\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+
+  const char* kReloadScript =
+      "var _unused;"
+      "class Foo {\n"
+      "  final a kjsdf ksjdf ;\n"
+      "  Foo(this.a);\n"
+      "}\n"
+      "main() {\n"
+      "  new Foo(5);\n"
+      "  return 10;\n"
+      "}\n";
+
+  Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_ERROR(result, "unexpected token");
+
+  EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_StaticValuePreserved) {
+  const char* kScript =
+      "init() => 'old value';\n"
+      "var value = init();\n"
+      "main() {\n"
+      "  return 'init()=${init()},value=${value}';\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("init()=old value,value=old value",
+               SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "var _unused;"
+      "init() => 'new value';\n"
+      "var value = init();\n"
+      "main() {\n"
+      "  return 'init()=${init()},value=${value}';\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("init()=new value,value=old value",
+               SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_SavedClosure) {
+  // Create a closure in main which only exists in the original source.
+  const char* kScript =
+      "magic() {\n"
+      "  var x = 'ante';\n"
+      "  return x + 'diluvian';\n"
+      "}\n"
+      "var closure;\n"
+      "main() {\n"
+      "  closure = () { return magic().toString() + '!'; };\n"
+      "  return closure();\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("antediluvian!", SimpleInvokeStr(lib, "main"));
+
+  // Remove the original closure from the source code.  The closure is
+  // able to be recompiled because its source is preserved in a
+  // special patch class.
+  const char* kReloadScript =
+      "magic() {\n"
+      "  return 'postapocalyptic';\n"
+      "}\n"
+      "var closure;\n"
+      "main() {\n"
+      "  return closure();\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("postapocalyptic!", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_TopLevelFieldAdded) {
+  const char* kScript =
+      "var value1 = 10;\n"
+      "main() {\n"
+      "  return 'value1=${value1}';\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("value1=10", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "var value1 = 10;\n"
+      "var value2 = 20;\n"
+      "main() {\n"
+      "  return 'value1=${value1},value2=${value2}';\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("value1=10,value2=20",
+               SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_ClassFieldAdded) {
+  const char* kScript =
+      "class Foo {\n"
+      "  var x;\n"
+      "}\n"
+      "main() {\n"
+      "  new Foo();\n"
+      "  return 44;\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_EQ(44, SimpleInvoke(lib, "main"));
+
+  const char* kReloadScript =
+      "class Foo {\n"
+      "  var x;\n"
+      "  var y;\n"
+      "}\n"
+      "main() {\n"
+      "  new Foo();\n"
+      "  return 44;\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_ERROR(lib, "Number of instance fields changed");
+}
+
+
+TEST_CASE(IsolateReload_ClassFieldRemoved) {
+  const char* kScript =
+      "class Foo {\n"
+      "  var x;\n"
+      "  var y;\n"
+      "}\n"
+      "main() {\n"
+      "  new Foo();\n"
+      "  return 44;\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_EQ(44, SimpleInvoke(lib, "main"));
+
+  const char* kReloadScript =
+      "class Foo {\n"
+      "  var x;\n"
+      "}\n"
+      "main() {\n"
+      "  new Foo();\n"
+      "  return 44;\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_ERROR(lib, "Number of instance fields changed");
+}
+
+
+TEST_CASE(IsolateReload_ClassAdded) {
+  const char* kScript =
+      "main() {\n"
+      "  return 'hello';\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "var _unused;"
+      "class A {\n"
+      "  toString() => 'hello from A';\n"
+      "}\n"
+      "main() {\n"
+      "  return new A().toString();\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("hello from A", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_LibraryImportAdded) {
+  const char* kScript =
+      "main() {\n"
+      "  return max(3, 4);\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_ERROR(SimpleInvokeError(lib, "main"), "max");;
+
+  const char* kReloadScript =
+      "import 'dart:math';\n"
+      "main() {\n"
+      "  return max(3, 4);\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_LibraryImportRemoved) {
+  const char* kScript =
+      "import 'dart:math';\n"
+      "main() {\n"
+      "  return max(3, 4);\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+
+  const char* kReloadScript =
+      "main() {\n"
+      "  return max(3, 4);\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_ERROR(SimpleInvokeError(lib, "main"), "max");;
+}
+
+
+TEST_CASE(IsolateReload_LibraryDebuggable) {
+  const char* kScript =
+      "main() {\n"
+      "  return 1;\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  // The library is by default debuggable.  Make it not debuggable.
+  intptr_t lib_id = -1;
+  bool debuggable = false;
+  EXPECT_VALID(Dart_LibraryId(lib, &lib_id));
+  EXPECT_VALID(Dart_GetLibraryDebuggable(lib_id, &debuggable));
+  EXPECT_EQ(true, debuggable);
+  EXPECT_VALID(Dart_SetLibraryDebuggable(lib_id, false));
+  EXPECT_VALID(Dart_GetLibraryDebuggable(lib_id, &debuggable));
+  EXPECT_EQ(false, debuggable);
+
+  EXPECT_EQ(1, SimpleInvoke(lib, "main"));
+
+  const char* kReloadScript =
+      "main() {\n"
+      "  return 2;\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_EQ(2, SimpleInvoke(lib, "main"));
+
+  // Library debuggability is preserved.
+  intptr_t new_lib_id = -1;
+  EXPECT_VALID(Dart_LibraryId(lib, &new_lib_id));
+  EXPECT_VALID(Dart_GetLibraryDebuggable(new_lib_id, &debuggable));
+  EXPECT_EQ(false, debuggable);
+}
+
+
+TEST_CASE(IsolateReload_ImplicitConstructorChanged) {
+  // Note that we are checking that the value 20 gets cleared from the
+  // compile-time constants cache.  To make this test work, "20" and
+  // "10" need to be at the same token position.
+  const char* kScript =
+      "class A {\n"
+      "  int field = 20;\n"
+      "}\n"
+      "var savedA = new A();\n"
+      "main() {\n"
+      "  var newA = new A();\n"
+      "  return 'saved:${savedA.field} new:${newA.field}';\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("saved:20 new:20", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "class A {\n"
+      "  int field = 10;\n"
+      "}\n"
+      "var savedA = new A();\n"
+      "main() {\n"
+      "  var newA = new A();\n"
+      "  return 'saved:${savedA.field} new:${newA.field}';\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("saved:20 new:10", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_ConstructorChanged) {
+  const char* kScript =
+      "class A {\n"
+      "  int field;\n"
+      "  A() { field = 20; }\n"
+      "}\n"
+      "var savedA = new A();\n"
+      "main() {\n"
+      "  var newA = new A();\n"
+      "  return 'saved:${savedA.field} new:${newA.field}';\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("saved:20 new:20", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "var _unused;"
+      "class A {\n"
+      "  int field;\n"
+      "  A() { field = 10; }\n"
+      "}\n"
+      "var savedA = new A();\n"
+      "main() {\n"
+      "  var newA = new A();\n"
+      "  return 'saved:${savedA.field} new:${newA.field}';\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("saved:20 new:10", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_SuperClassChanged) {
+  const char* kScript =
+      "class A {\n"
+      "}\n"
+      "class B extends A {\n"
+      "}\n"
+      "var list = [ new A(), new B() ];\n"
+      "main() {\n"
+      "  return (list.map((x) => '${x is A}/${x is B}')).toString();\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("(true/false, true/true)", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "var _unused;"
+      "class B{\n"
+      "}\n"
+      "class A extends B {\n"
+      "}\n"
+      "var list = [ new A(), new B() ];\n"
+      "main() {\n"
+      "  return (list.map((x) => '${x is A}/${x is B}')).toString();\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("(true/true, false/true)", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_Generics) {
+  // Reload a program with generics without changing the source.  We
+  // do this to produce duplication TypeArguments and make sure that
+  // the system doesn't die.
+  const char* kScript =
+      "class A {\n"
+      "}\n"
+      "class B<T extends A> {\n"
+      "}\n"
+      "main() {\n"
+      "  return new B<A>().toString();\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("Instance of 'B<A>'", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "class A {\n"
+      "}\n"
+      "class B<T extends A> {\n"
+      "}\n"
+      "main() {\n"
+      "  return new B<A>().toString();\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("Instance of 'B<A>'", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_MixinChanged) {
+  const char* kScript =
+      "class Mixin1 {\n"
+      "  var field = 'mixin1';\n"
+      "  func() => 'mixin1';\n"
+      "}\n"
+      "class B extends Object with Mixin1 {\n"
+      "}\n"
+      "var saved = new B();\n"
+      "main() {\n"
+      "  return 'saved:field=${saved.field},func=${saved.func()}';\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("saved:field=mixin1,func=mixin1",
+               SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "class Mixin2 {\n"
+      "  var field = 'mixin2';\n"
+      "  func() => 'mixin2';\n"
+      "}\n"
+      "class B extends Object with Mixin2 {\n"
+      "}\n"
+      "var saved = new B();\n"
+      "main() {\n"
+      "  var newer = new B();\n"
+      "  return 'saved:field=${saved.field},func=${saved.func()} '\n"
+      "         'newer:field=${newer.field},func=${newer.func()}';\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  // The saved instance of B retains its old field value from mixin1,
+  // but it gets the new implementation of func from mixin2.
+  EXPECT_STREQ("saved:field=mixin1,func=mixin2 "
+               "newer:field=mixin2,func=mixin2",
+               SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_ComplexInheritanceChange) {
+  const char* kScript =
+      "class A {\n"
+      "  String name;\n"
+      "  A(this.name);\n"
+      "}\n"
+      "class B extends A {\n"
+      "  B(name) : super(name);\n"
+      "}\n"
+      "class C extends B {\n"
+      "  C(name) : super(name);\n"
+      "}\n"
+      "var list = [ new A('a'), new B('b'), new C('c') ];\n"
+      "main() {\n"
+      "  return (list.map((x) {\n"
+      "    return '${x.name} is A(${x is A})/ B(${x is B})/ C(${x is C})';\n"
+      "  })).toString();\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("(a is A(true)/ B(false)/ C(false),"
+               " b is A(true)/ B(true)/ C(false),"
+               " c is A(true)/ B(true)/ C(true))",
+               SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "class C {\n"
+      "  String name;\n"
+      "  C(this.name);\n"
+      "}\n"
+      "class X extends C {\n"
+      "  X(name) : super(name);\n"
+      "}\n"
+      "class A extends X {\n"
+      "  A(name) : super(name);\n"
+      "}\n"
+      "var list;\n"
+      "main() {\n"
+      "  list.add(new X('x'));\n"
+      "  return (list.map((x) {\n"
+      "    return '${x.name} is A(${x is A})/ C(${x is C})/ X(${x is X})';\n"
+      "  })).toString();\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("(a is A(true)/ C(true)/ X(true),"
+               " b is A(true)/ C(true)/ X(true),"  // still extends A...
+               " c is A(false)/ C(true)/ X(false),"
+               " x is A(false)/ C(true)/ X(true))",
+               SimpleInvokeStr(lib, "main"));
+
+  // Revive the class B and make sure all allocated instances take
+  // their place in the inheritance hierarchy.
+  const char* kReloadScript2 =
+      "class X {\n"
+      "  String name;\n"
+      "  X(this.name);\n"
+      "}\n"
+      "class A extends X{\n"
+      "  A(name) : super(name);\n"
+      "}\n"
+      "class B extends X {\n"
+      "  B(name) : super(name);\n"
+      "}\n"
+      "class C extends A {\n"
+      "  C(name) : super(name);\n"
+      "}\n"
+      "var list;\n"
+      "main() {\n"
+      "  return (list.map((x) {\n"
+      "    return '${x.name} is '\n"
+      "           'A(${x is A})/ B(${x is B})/ C(${x is C})/ X(${x is X})';\n"
+      "  })).toString();\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript2);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("(a is A(true)/ B(false)/ C(false)/ X(true),"
+               " b is A(false)/ B(true)/ C(false)/ X(true),"
+               " c is A(true)/ B(false)/ C(true)/ X(true),"
+               " x is A(false)/ B(false)/ C(false)/ X(true))",
+               SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_LiveStack) {
+  const char* kScript =
+      "import 'isolate_reload_test_helper';\n"
+      "helper() => 7;\n"
+      "alpha() { var x = helper(); reloadTest(); return x + helper(); }\n"
+      "foo() => alpha();\n"
+      "bar() => foo();\n"
+      "main() {\n"
+      "  return bar();\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  const char* kReloadScript =
+      "import 'isolate_reload_test_helper';\n"
+      "helper() => 100;\n"
+      "alpha() => 5 + helper();\n"
+      "foo() => alpha();\n"
+      "bar() => foo();\n"
+      "main() {\n"
+      "  return bar();\n"
+      "}\n";
+
+  TestCase::SetReloadTestScript(kReloadScript);
+
+  EXPECT_EQ(107, SimpleInvoke(lib, "main"));
+
+  lib = TestCase::GetReloadErrorOrRootLibrary();
+  EXPECT_VALID(lib);
+
+  EXPECT_EQ(105, SimpleInvoke(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_LibraryLookup) {
+  const char* kScript =
+      "main() {\n"
+      "  return importedFunc();\n"
+      "}\n";
+
+  Dart_Handle result;
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
+
+  // Fail to find 'importable_test_lib' in the isolate.
+  result = Dart_LookupLibrary(NewString("importable_test_lib"));
+  EXPECT(Dart_IsError(result));
+
+  const char* kReloadScript =
+      "import 'importable_test_lib';\n"
+      "main() {\n"
+      "  return importedFunc();\n"
+      "}\n";
+
+  // Reload and add 'importable_test_lib' to isolate.
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("a", SimpleInvokeStr(lib, "main"));
+
+  // Find 'importable_test_lib' in the isolate.
+  result = Dart_LookupLibrary(NewString("importable_test_lib"));
+  EXPECT(Dart_IsLibrary(result));
+
+  // Reload and remove 'dart:math' from isolate.
+  lib = TestCase::ReloadTestScript(kScript);
+  EXPECT_VALID(lib);
+
+  // Fail to find 'importable_test_lib' in the isolate.
+  result = Dart_LookupLibrary(NewString("importable_test_lib"));
+  EXPECT(Dart_IsError(result));
+}
+
+
+TEST_CASE(IsolateReload_LibraryHide) {
+  // Import 'importable_test_lib' with importedFunc hidden. Will result in an
+  // error.
+  const char* kScript =
+      "import 'importable_test_lib' hide importedFunc;\n"
+      "main() {\n"
+      "  return importedFunc();\n"
+      "}\n";
+
+  // Dart_Handle result;
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
+
+  // Import 'importable_test_lib'.
+  const char* kReloadScript =
+      "import 'importable_test_lib';\n"
+      "main() {\n"
+      "  return importedFunc();\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("a", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_LibraryShow) {
+  // Import 'importable_test_lib' with importedIntFunc visible. Will result in
+  // an error when 'main' is invoked.
+  const char* kScript =
+      "import 'importable_test_lib' show importedIntFunc;\n"
+      "main() {\n"
+      "  return importedFunc();\n"
+      "}\n"
+      "mainInt() {\n"
+      "  return importedIntFunc();\n"
+      "}\n";
+
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  // Works.
+  EXPECT_EQ(4, SimpleInvoke(lib, "mainInt"));
+  // Results in an error.
+  EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
+
+  // Import 'importable_test_lib' with importedFunc visible. Will result in
+  // an error when 'mainInt' is invoked.
+  const char* kReloadScript =
+      "import 'importable_test_lib' show importedFunc;\n"
+      "main() {\n"
+      "  return importedFunc();\n"
+      "}\n"
+      "mainInt() {\n"
+      "  return importedIntFunc();\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  // Works.
+  EXPECT_STREQ("a", SimpleInvokeStr(lib, "main"));
+  // Results in an error.
+  EXPECT_ERROR(SimpleInvokeError(lib, "mainInt"), "importedIntFunc");
+}
+
+
+// Verifies that we clear the ICs for the functions live on the stack in a way
+// that is compatible with the fast path smi stubs.
+TEST_CASE(IsolateReload_SmiFastPathStubs) {
+  const char* kScript =
+      "import 'isolate_reload_test_helper';\n"
+      "import 'importable_test_lib' show importedIntFunc;\n"
+      "main() {\n"
+      "  var x = importedIntFunc();\n"
+      "  var y = importedIntFunc();\n"
+      "  reloadTest();\n"
+      "  return x + y;\n"
+      "}\n";
+
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  // Identity reload.
+  TestCase::SetReloadTestScript(kScript);
+
+  EXPECT_EQ(8, SimpleInvoke(lib, "main"));
+}
+
+
+// Verifies that we assign the correct patch classes for imported
+// mixins when we reload.
+TEST_CASE(IsolateReload_ImportedMixinFunction) {
+  const char* kScript =
+      "import 'importable_test_lib' show ImportedMixin;\n"
+      "class A extends Object with ImportedMixin {\n"
+      "}"
+      "var func = new A().mixinFunc;\n"
+      "main() {\n"
+      "  return func();\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("mixin", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "import 'importable_test_lib' show ImportedMixin;\n"
+      "class A extends Object with ImportedMixin {\n"
+      "}"
+      "var func;\n"
+      "main() {\n"
+      "  return func();\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("mixin", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_TopLevelParseError) {
+  const char* kScript =
+      "main() {\n"
+      "  return 4;\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+
+  const char* kReloadScript =
+      "kjsadkfjaksldfjklsadf;\n"
+      "main() {\n"
+      "  return 4;\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_ERROR(lib, "unexpected token");
+}
+
+
+TEST_CASE(IsolateReload_PendingUnqualifiedCall_StaticToInstance) {
+  const char* kScript =
+      "import 'isolate_reload_test_helper';\n"
+      "class C {\n"
+      "  static foo() => 'static';\n"
+      "  test() {\n"
+      "    reloadTest();\n"
+      "    return foo();\n"
+      "  }\n"
+      "}\n"
+      "main() {\n"
+      "  return new C().test();\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  const char* kReloadScript =
+      "import 'isolate_reload_test_helper';\n"
+      "class C {\n"
+      "  foo() => 'instance';\n"
+      "  test() {\n"
+      "    reloadTest();\n"
+      "    return foo();\n"
+      "  }\n"
+      "}\n"
+      "main() {\n"
+      "  return new C().test();\n"
+      "}\n";
+
+  TestCase::SetReloadTestScript(kReloadScript);
+
+  EXPECT_EQ("instance", SimpleInvokeStr(lib, "main"));
+
+  lib = TestCase::GetReloadErrorOrRootLibrary();
+  EXPECT_VALID(lib);
+
+  EXPECT_EQ("instance", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_PendingUnqualifiedCall_InstanceToStatic) {
+  const char* kScript =
+      "import 'isolate_reload_test_helper';\n"
+      "class C {\n"
+      "  foo() => 'instance';\n"
+      "  test() {\n"
+      "    reloadTest();\n"
+      "    return foo();\n"
+      "  }\n"
+      "}\n"
+      "main() {\n"
+      "  return new C().test();\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  const char* kReloadScript =
+      "import 'isolate_reload_test_helper';\n"
+      "class C {\n"
+      "  static foo() => 'static';\n"
+      "  test() {\n"
+      "    reloadTest();\n"
+      "    return foo();\n"
+      "  }\n"
+      "}\n"
+      "main() {\n"
+      "  return new C().test();\n"
+      "}\n";
+
+  TestCase::SetReloadTestScript(kReloadScript);
+
+  EXPECT_EQ("static", SimpleInvokeStr(lib, "main"));
+
+  lib = TestCase::GetReloadErrorOrRootLibrary();
+  EXPECT_VALID(lib);
+
+  EXPECT_EQ("static", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_PendingConstructorCall_AbstractToConcrete) {
+  const char* kScript =
+      "import 'isolate_reload_test_helper';\n"
+      "abstract class Foo {}\n"
+      "class C {\n"
+      "  test() {\n"
+      "    reloadTest();\n"
+      "    return new Foo();\n"
+      "  }\n"
+      "}\n"
+      "main() {\n"
+      "  try {\n"
+      "    new C().test();\n"
+      "    return 'okay';\n"
+      "  } catch (e) {\n"
+      "    return 'exception';\n"
+      "  }\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  const char* kReloadScript =
+      "import 'isolate_reload_test_helper';\n"
+      "class Foo {}\n"
+      "class C {\n"
+      "  test() {\n"
+      "    reloadTest();\n"
+      "    return new Foo();\n"
+      "  }\n"
+      "}\n"
+      "main() {\n"
+      "  try {\n"
+      "    new C().test();\n"
+      "    return 'okay';\n"
+      "  } catch (e) {\n"
+      "    return 'exception';\n"
+      "  }\n"
+      "}\n";
+
+  TestCase::SetReloadTestScript(kReloadScript);
+
+  EXPECT_EQ("okay", SimpleInvokeStr(lib, "main"));
+
+  lib = TestCase::GetReloadErrorOrRootLibrary();
+  EXPECT_VALID(lib);
+
+  EXPECT_EQ("okay", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_PendingConstructorCall_ConcreteToAbstract) {
+  const char* kScript =
+      "import 'isolate_reload_test_helper';\n"
+      "class Foo {}\n"
+      "class C {\n"
+      "  test() {\n"
+      "    reloadTest();\n"
+      "    return new Foo();\n"
+      "  }\n"
+      "}\n"
+      "main() {\n"
+      "  try {\n"
+      "    new C().test();\n"
+      "    return 'okay';\n"
+      "  } catch (e) {\n"
+      "    return 'exception';\n"
+      "  }\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  const char* kReloadScript =
+      "import 'isolate_reload_test_helper';\n"
+      "abstract class Foo {}\n"
+      "class C {\n"
+      "  test() {\n"
+      "    reloadTest();\n"
+      "    return new Foo();\n"
+      "  }\n"
+      "}\n"
+      "main() {\n"
+      "  try {\n"
+      "    new C().test();\n"
+      "    return 'okay';\n"
+      "  } catch (e) {\n"
+      "    return 'exception';\n"
+      "  }\n"
+      "}\n";
+
+  TestCase::SetReloadTestScript(kReloadScript);
+
+  EXPECT_EQ("exception", SimpleInvokeStr(lib, "main"));
+
+  lib = TestCase::GetReloadErrorOrRootLibrary();
+  EXPECT_VALID(lib);
+
+  EXPECT_EQ("exception", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_PendingStaticCall_DefinedToNSM) {
+  const char* kScript =
+      "import 'isolate_reload_test_helper';\n"
+      "class C {\n"
+      "  static foo() => 'static'\n"
+      "  test() {\n"
+      "    reloadTest();\n"
+      "    return C.foo();\n"
+      "  }\n"
+      "}\n"
+      "main() {\n"
+      "  try {\n"
+      "    return new C().test();\n"
+      "  } catch (e) {\n"
+      "    return 'exception';\n"
+      "  }\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  const char* kReloadScript =
+      "import 'isolate_reload_test_helper';\n"
+      "class C {\n"
+      "  test() {\n"
+      "    reloadTest();\n"
+      "    return C.foo();\n"
+      "  }\n"
+      "}\n"
+      "main() {\n"
+      "  try {\n"
+      "    return new C().test();\n"
+      "  } catch (e) {\n"
+      "    return 'exception';\n"
+      "  }\n"
+      "}\n";
+
+  TestCase::SetReloadTestScript(kReloadScript);
+
+  EXPECT_EQ("exception", SimpleInvokeStr(lib, "main"));
+
+  lib = TestCase::GetReloadErrorOrRootLibrary();
+  EXPECT_VALID(lib);
+
+  EXPECT_EQ("exception", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_PendingStaticCall_NSMToDefined) {
+  const char* kScript =
+      "import 'isolate_reload_test_helper';\n"
+      "class C {\n"
+      "  test() {\n"
+      "    reloadTest();\n"
+      "    return C.foo();\n"
+      "  }\n"
+      "}\n"
+      "main() {\n"
+      "  try {\n"
+      "    return new C().test();\n"
+      "  } catch (e) {\n"
+      "    return 'exception';\n"
+      "  }\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  const char* kReloadScript =
+      "import 'isolate_reload_test_helper';\n"
+      "class C {\n"
+      "  static foo() => 'static'\n"
+      "  test() {\n"
+      "    reloadTest();\n"
+      "    return C.foo();\n"
+      "  }\n"
+      "}\n"
+      "main() {\n"
+      "  try {\n"
+      "    return new C().test();\n"
+      "  } catch (e) {\n"
+      "    return 'exception';\n"
+      "  }\n"
+      "}\n";
+
+  TestCase::SetReloadTestScript(kReloadScript);
+
+  EXPECT_EQ("static", SimpleInvokeStr(lib, "main"));
+
+  lib = TestCase::GetReloadErrorOrRootLibrary();
+  EXPECT_VALID(lib);
+
+  EXPECT_EQ("static", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_EnumEquality) {
+  const char* kScript =
+      "enum Fruit {\n"
+      "  Apple,\n"
+      "  Banana,\n"
+      "}\n"
+      "var x;\n"
+      "main() {\n"
+      "  x = Fruit.Banana;\n"
+      "  return Fruit.Apple.toString();\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "enum Fruit {\n"
+      "  Apple,\n"
+      "  Banana,\n"
+      "}\n"
+      "var x;\n"
+      "main() {\n"
+      "  if (x == Fruit.Banana) {\n"
+      "    return 'yes';\n"
+      "  } else {\n"
+      "    return 'no';\n"
+      "  }\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_EnumIdentical) {
+  const char* kScript =
+      "enum Fruit {\n"
+      "  Apple,\n"
+      "  Banana,\n"
+      "}\n"
+      "var x;\n"
+      "main() {\n"
+      "  x = Fruit.Banana;\n"
+      "  return Fruit.Apple.toString();\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "enum Fruit {\n"
+      "  Apple,\n"
+      "  Banana,\n"
+      "}\n"
+      "var x;\n"
+      "main() {\n"
+      "  if (identical(x, Fruit.Banana)) {\n"
+      "    return 'yes';\n"
+      "  } else {\n"
+      "    return 'no';\n"
+      "  }\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_EnumReorderIdentical) {
+  const char* kScript =
+      "enum Fruit {\n"
+      "  Apple,\n"
+      "  Banana,\n"
+      "}\n"
+      "var x;\n"
+      "main() {\n"
+      "  x = Fruit.Banana;\n"
+      "  return Fruit.Apple.toString();\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "enum Fruit {\n"
+      "  Banana,\n"
+      "  Apple,\n"
+      "}\n"
+      "var x;\n"
+      "main() {\n"
+      "  if (identical(x, Fruit.Banana)) {\n"
+      "    return 'yes';\n"
+      "  } else {\n"
+      "    return 'no';\n"
+      "  }\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_EnumAddition) {
+  const char* kScript =
+      "enum Fruit {\n"
+      "  Apple,\n"
+      "  Banana,\n"
+      "}\n"
+      "var x;\n"
+      "main() {\n"
+      "  return Fruit.Apple.toString();\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "enum Fruit {\n"
+      "  Apple,\n"
+      "  Cantalope,\n"
+      "  Banana,\n"
+      "}\n"
+      "var x;\n"
+      "main() {\n"
+      "  String r = '${Fruit.Apple.index}/${Fruit.Apple} ';\n"
+      "  r += '${Fruit.Cantalope.index}/${Fruit.Cantalope} ';\n"
+      "  r += '${Fruit.Banana.index}/${Fruit.Banana}';\n"
+      "  return r;\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("0/Fruit.Apple 1/Fruit.Cantalope 2/Fruit.Banana",
+               SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_EnumToNotEnum) {
+  const char* kScript =
+      "enum Fruit {\n"
+      "  Apple\n"
+      "}\n"
+      "main() {\n"
+      "  return Fruit.Apple.toString();\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "class Fruit {\n"
+      "  final int zero = 0;\n"
+      "}\n"
+      "main() {\n"
+      "}\n";
+
+  Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_ERROR(result, "Enum class cannot be redefined to be a non-enum class");
+}
+
+
+TEST_CASE(IsolateReload_NotEnumToEnum) {
+  const char* kScript =
+      "class Fruit {\n"
+      "  final int zero = 0;\n"
+      "}\n"
+      "main() {\n"
+      "  return 'yes';\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "enum Fruit {\n"
+      "  Apple\n"
+      "}\n"
+      "main() {\n"
+      "  return Fruit.Apple.toString();\n"
+      "}\n";
+
+  Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_ERROR(result, "Class cannot be redefined to be a enum class");
+}
+
+
+TEST_CASE(IsolateReload_EnumDelete) {
+  const char* kScript =
+      "enum Fruit {\n"
+      "  Apple,\n"
+      "  Banana,\n"
+      "  Cantalope,\n"
+      "}\n"
+      "var x;\n"
+      "main() {\n"
+      "  return Fruit.Apple.toString();\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
+
+  // Delete 'Cantalope'.
+
+  const char* kReloadScript =
+      "enum Fruit {\n"
+      "  Apple,\n"
+      "  Banana,\n"
+      "}\n"
+      "var x;\n"
+      "main() {\n"
+      "  String r = '${Fruit.Apple.index}/${Fruit.Apple} ';\n"
+      "  r += '${Fruit.Banana.index}/${Fruit.Banana} ';\n"
+      "  r += '${Fruit.Cantalope.index}/${Fruit.Cantalope}';\n"
+      "  return r;\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("0/Fruit.Apple 1/Fruit.Banana 2/Fruit.Cantalope",
+               SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_EnumComplex) {
+  const char* kScript =
+      "enum Fruit {\n"
+      "  Apple,\n"
+      "  Banana,\n"
+      "  Cantalope,\n"
+      "}\n"
+      "var x;\n"
+      "var y;\n"
+      "var z;\n"
+      "main() {\n"
+      "  x = Fruit.Apple;\n"
+      "  y = Fruit.Banana;\n"
+      "  z = Fruit.Cantalope;\n"
+      "  return Fruit.Apple.toString();\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
+
+  // Delete 'Cantalope'. Add 'Dragon'. Move 'Apple' and 'Banana'.
+
+  const char* kReloadScript =
+      "enum Fruit {\n"
+      "  Dragon,\n"
+      "  Apple,\n"
+      "  Banana,\n"
+      "}\n"
+      "var x;\n"
+      "var y;\n"
+      "var z;\n"
+      "main() {\n"
+      "  String r = '';\n"
+      "  r += '${identical(x, Fruit.Apple)}';\n"
+      "  r += ' ${identical(y, Fruit.Banana)}';\n"
+      "  r += ' ${identical(z, Fruit.Cantalope)}';\n"
+      "  r += ' ${Fruit.Dragon}';\n"
+      "  return r;\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("true true true Fruit.Dragon", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_EnumValuesArray) {
+  const char* kScript =
+      "enum Fruit {\n"
+      "  Cantalope,\n"
+      "  Apple,\n"
+      "  Banana,\n"
+      "}\n"
+      "var x;\n"
+      "main() {\n"
+      "  x = Fruit.Cantalope;\n"
+      "  return Fruit.Apple.toString();\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
+
+  // Delete 'Cantalope'.
+
+  const char* kReloadScript =
+      "enum Fruit {\n"
+      "  Banana,\n"
+      "  Apple\n"
+      "}\n"
+      "var x;\n"
+      "bool identityCheck(Fruit f) {\n"
+      "  return identical(Fruit.values[f.index], f);\n"
+      "}\n"
+      "main() {\n"
+      "  if ((x is Fruit) && identical(x, Fruit.Cantalope)) {\n"
+      "    String r = '${identityCheck(Fruit.Apple)}';\n"
+      "    r += ' ${identityCheck(Fruit.Banana)}';\n"
+      "    r += ' ${identityCheck(Fruit.Cantalope)}';\n"
+      "    r += ' ${identityCheck(x)}';\n"
+      "    return r;\n"
+      "  }\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("true true true true",
+               SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_EnumIdentityReload) {
+  const char* kScript =
+      "enum Fruit {\n"
+      "  Apple,\n"
+      "  Banana,\n"
+      "  Cantalope,\n"
+      "}\n"
+      "var x;\n"
+      "var y;\n"
+      "var z;\n"
+      "var w;\n"
+      "main() {\n"
+      "  x = { Fruit.Apple: Fruit.Apple.index,\n"
+      "        Fruit.Banana: Fruit.Banana.index,\n"
+      "        Fruit.Cantalope: Fruit.Cantalope.index};\n"
+      "  y = Fruit.Apple;\n"
+      "  z = Fruit.Banana;\n"
+      "  w = Fruit.Cantalope;\n"
+      "  return Fruit.Apple.toString();\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "enum Fruit {\n"
+      "  Apple,\n"
+      "  Banana,\n"
+      "  Cantalope,\n"
+      "}\n"
+      "var x;\n"
+      "var y;\n"
+      "var z;\n"
+      "var w;\n"
+      "bool identityCheck(Fruit f, int index) {\n"
+      "  return identical(Fruit.values[index], f);\n"
+      "}\n"
+      "main() {\n"
+      "  String r = '';\n"
+      "  x.forEach((key, value) {\n"
+      "    r += '${identityCheck(key, value)} ';\n"
+      "  });\n"
+      "  r += '${x[Fruit.Apple] == Fruit.Apple.index} ';\n"
+      "  r += '${x[Fruit.Banana] == Fruit.Banana.index} ';\n"
+      "  r += '${x[Fruit.Cantalope] == Fruit.Cantalope.index} ';\n"
+      "  r += '${identical(y, Fruit.values[x[Fruit.Apple]])} ';\n"
+      "  r += '${identical(z, Fruit.values[x[Fruit.Banana]])} ';\n"
+      "  r += '${identical(w, Fruit.values[x[Fruit.Cantalope]])} ';\n"
+      "  return r;\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("true true true true true true true true true ",
+               SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_ConstantIdentical) {
+  const char* kScript =
+      "class Fruit {\n"
+      "  final String name;\n"
+      "  const Fruit(this.name);\n"
+      "  String toString() => name;\n"
+      "}\n"
+      "var x;\n"
+      "main() {\n"
+      "  x = const Fruit('Pear');\n"
+      "  return x.toString();\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("Pear", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "class Fruit {\n"
+      "  final String name;\n"
+      "  const Fruit(this.name);\n"
+      "  String toString() => name;\n"
+      "}\n"
+      "var x;\n"
+      "main() {\n"
+      "  if (identical(x, const Fruit('Pear'))) {\n"
+      "    return 'yes';\n"
+      "  } else {\n"
+      "    return 'no';\n"
+      "  }\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_EnumValuesToString) {
+  const char* kScript =
+      "enum Fruit {\n"
+      "  Apple,\n"
+      "  Banana,\n"
+      "}\n"
+      "var x;\n"
+      "main() {\n"
+      "  String r = '';\n"
+      "  r += Fruit.Apple.toString();\n"
+      "  r += ' ';\n"
+      "  r += Fruit.Banana.toString();\n"
+      "  return r;\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("Fruit.Apple Fruit.Banana", SimpleInvokeStr(lib, "main"));
+
+  // Insert 'Cantalope'.
+
+  const char* kReloadScript =
+      "enum Fruit {\n"
+      "  Apple,\n"
+      "  Cantalope,\n"
+      "  Banana\n"
+      "}\n"
+      "var x;\n"
+      "main() {\n"
+      "  String r = '';\n"
+      "  r += Fruit.Apple.toString();\n"
+      "  r += ' ';\n"
+      "  r += Fruit.Cantalope.toString();\n"
+      "  r += ' ';\n"
+      "  r += Fruit.Banana.toString();\n"
+      "  return r;\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+
+  EXPECT_STREQ("Fruit.Apple Fruit.Cantalope Fruit.Banana",
+               SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_DirectSubclasses_Success) {
+  Object& new_subclass = Object::Handle();
+  String& name = String::Handle();
+
+  // Lookup the Iterator class by name from the dart core library.
+  ObjectStore* object_store = Isolate::Current()->object_store();
+  const Library& core_lib = Library::Handle(object_store->core_library());
+  name = String::New("Iterator");
+  const Class& iterator_cls = Class::Handle(core_lib.LookupClass(name));
+
+  // Keep track of how many subclasses an Iterator has.
+  const GrowableObjectArray& subclasses =
+      GrowableObjectArray::Handle(iterator_cls.direct_subclasses());
+  intptr_t saved_subclass_count = subclasses.Length();
+
+  const char* kScript =
+      "class AIterator extends Iterator {\n"
+      "}\n"
+      "main() {\n"
+      "  return 1;\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+  EXPECT_EQ(1, SimpleInvoke(lib, "main"));
+
+  // Iterator has one non-core subclass.
+  EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
+
+  // The new subclass is named AIterator.
+  new_subclass = subclasses.At(subclasses.Length() - 1);
+  name = Class::Cast(new_subclass).Name();
+  EXPECT_STREQ("AIterator", name.ToCString());
+
+  const char* kReloadScript =
+      "class AIterator {\n"
+      "}\n"
+      "class BIterator extends Iterator {\n"
+      "}\n"
+      "main() {\n"
+      "  return 2;\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+  EXPECT_EQ(2, SimpleInvoke(lib, "main"));
+
+  // Iterator still has only one non-core subclass (AIterator is gone).
+  EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
+
+  // The new subclass is named BIterator.
+  new_subclass = subclasses.At(subclasses.Length() - 1);
+  name = Class::Cast(new_subclass).Name();
+  EXPECT_STREQ("BIterator", name.ToCString());
+}
+
+
+TEST_CASE(IsolateReload_DirectSubclasses_GhostSubclass) {
+  Object& new_subclass = Object::Handle();
+  String& name = String::Handle();
+
+  // Lookup the Iterator class by name from the dart core library.
+  ObjectStore* object_store = Isolate::Current()->object_store();
+  const Library& core_lib = Library::Handle(object_store->core_library());
+  name = String::New("Iterator");
+  const Class& iterator_cls = Class::Handle(core_lib.LookupClass(name));
+
+  // Keep track of how many subclasses an Iterator has.
+  const GrowableObjectArray& subclasses =
+      GrowableObjectArray::Handle(iterator_cls.direct_subclasses());
+  intptr_t saved_subclass_count = subclasses.Length();
+
+  const char* kScript =
+      "class AIterator extends Iterator {\n"
+      "}\n"
+      "main() {\n"
+      "  return 1;\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+  EXPECT_EQ(1, SimpleInvoke(lib, "main"));
+
+  // Iterator has one new subclass.
+  EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
+
+  // The new subclass is named AIterator.
+  new_subclass = subclasses.At(subclasses.Length() - 1);
+  name = Class::Cast(new_subclass).Name();
+  EXPECT_STREQ("AIterator", name.ToCString());
+
+  const char* kReloadScript =
+      "class BIterator extends Iterator {\n"
+      "}\n"
+      "main() {\n"
+      "  return 2;\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+  EXPECT_EQ(2, SimpleInvoke(lib, "main"));
+
+  // Iterator has two non-core subclasses.
+  EXPECT_EQ(saved_subclass_count + 2, subclasses.Length());
+
+  // The non-core subclasses are AIterator and BIterator.
+  new_subclass = subclasses.At(subclasses.Length() - 2);
+  name = Class::Cast(new_subclass).Name();
+  EXPECT_STREQ("AIterator", name.ToCString());
+
+  new_subclass = subclasses.At(subclasses.Length() - 1);
+  name = Class::Cast(new_subclass).Name();
+  EXPECT_STREQ("BIterator", name.ToCString());
+}
+
+
+// Make sure that we restore the direct subclass info when we revert.
+TEST_CASE(IsolateReload_DirectSubclasses_Failure) {
+  Object& new_subclass = Object::Handle();
+  String& name = String::Handle();
+
+  // Lookup the Iterator class by name from the dart core library.
+  ObjectStore* object_store = Isolate::Current()->object_store();
+  const Library& core_lib = Library::Handle(object_store->core_library());
+  name = String::New("Iterator");
+  const Class& iterator_cls = Class::Handle(core_lib.LookupClass(name));
+
+  // Keep track of how many subclasses an Iterator has.
+  const GrowableObjectArray& subclasses =
+      GrowableObjectArray::Handle(iterator_cls.direct_subclasses());
+  intptr_t saved_subclass_count = subclasses.Length();
+
+  const char* kScript =
+      "class AIterator extends Iterator {\n"
+      "}\n"
+      "class Foo {\n"
+      "  final a;\n"
+      "  Foo(this.a);\n"
+      "}\n"
+      "main() {\n"
+      "  new Foo(5);\n"  // Force Foo to be finalized.
+      "  return 1;\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+  EXPECT_EQ(1, SimpleInvoke(lib, "main"));
+
+  // Iterator has one non-core subclass...
+  EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
+
+  // ... and the non-core subclass is named AIterator.
+  new_subclass = subclasses.At(subclasses.Length() - 1);
+  name = Class::Cast(new_subclass).Name();
+  EXPECT_STREQ("AIterator", name.ToCString());
+
+  // Attempt to reload with a bogus script.
+  const char* kReloadScript =
+      "class BIterator extends Iterator {\n"
+      "}\n"
+      "class Foo {\n"
+      "  final a kjsdf ksjdf ;\n"  // When we refinalize, we get an error.
+      "  Foo(this.a);\n"
+      "}\n"
+      "main() {\n"
+      "  new Foo(5);\n"
+      "  return 2;\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_ERROR(lib, "unexpected token");
+
+  // If we don't clean up the subclasses, we would find BIterator in
+  // the list of subclasses, which would be bad.  Make sure that
+  // Iterator still has only one non-core subclass...
+  EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
+
+  // ...and the non-core subclass is still named AIterator.
+  new_subclass = subclasses.At(subclasses.Length() - 1);
+  name = Class::Cast(new_subclass).Name();
+  EXPECT_STREQ("AIterator", name.ToCString());
+}
+
+#endif  // !PRODUCT
+
+}  // namespace dart
diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc
index a721c7e..003f1b3 100644
--- a/runtime/vm/json_stream.cc
+++ b/runtime/vm/json_stream.cc
@@ -124,10 +124,12 @@
       return "Internal error";
     case kFeatureDisabled:
       return "Feature is disabled";
-    case kVMMustBePaused:
-      return "VM must be paused";
     case kCannotAddBreakpoint:
       return "Cannot add breakpoint";
+    case kIsolateMustBeRunnable:
+      return "Isolate must be runnable";
+    case kIsolateMustBePaused:
+      return "Isolate must be paused";
     default:
       return "Extension error";
   }
diff --git a/runtime/vm/json_stream.h b/runtime/vm/json_stream.h
index 5b020b0..3c77d4b 100644
--- a/runtime/vm/json_stream.h
+++ b/runtime/vm/json_stream.h
@@ -47,12 +47,13 @@
 
   kExtensionError = -32000,
 
-  kFeatureDisabled         = 100,
-  kVMMustBePaused          = 101,
-  kCannotAddBreakpoint     = 102,
-  kStreamAlreadySubscribed = 103,
-  kStreamNotSubscribed     = 104,
-  kIsolateMustBeRunnable   = 105,
+  kFeatureDisabled           = 100,
+  kCannotAddBreakpoint       = 102,
+  kStreamAlreadySubscribed   = 103,
+  kStreamNotSubscribed       = 104,
+  kIsolateMustBeRunnable     = 105,
+  kIsolateMustBePaused       = 106,
+  kIsolateIsReloading        = 107,
 };
 
 // Expected that user_data is a JSONStream*.
diff --git a/runtime/vm/method_recognizer.h b/runtime/vm/method_recognizer.h
index 9ed5848..6d7e1e8 100644
--- a/runtime/vm/method_recognizer.h
+++ b/runtime/vm/method_recognizer.h
@@ -168,7 +168,7 @@
   V(_Double, /, Double_div, 1220198876)                                        \
   V(_Double, get:isNaN, Double_getIsNaN, 184085483)                            \
   V(_Double, get:isNegative, Double_getIsNegative, 978911030)                  \
-  V(_Double, _mulFromInteger, Double_mulFromInteger, 1893886883)               \
+  V(_Double, _mulFromInteger, Double_mulFromInteger, 856594998)                \
   V(_Double, .fromInteger, DoubleFromInteger, 2129942595)                      \
   V(_List, []=, ObjectArraySetIndexed, 886228780)                              \
   V(_GrowableList, .withData, GrowableArray_Allocate, 631736030)               \
@@ -307,6 +307,7 @@
   V(_UserTag, makeCurrent, UserTag_makeCurrent, 187721469)                     \
   V(::, _getDefaultTag, UserTag_defaultTag, 350077879)                         \
   V(::, _getCurrentTag, Profiler_getCurrentTag, 1215225901)                    \
+  V(::, _isDartStreamEnabled, Timeline_isDartStreamEnabled, 1072246292)        \
 
 #define ALL_INTRINSICS_NO_INTEGER_LIB_LIST(V)                                  \
   CORE_LIB_INTRINSIC_LIST(V)                                                   \
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 46320b4..a8ccce5 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -27,10 +27,12 @@
 #include "vm/hash_table.h"
 #include "vm/heap.h"
 #include "vm/intrinsifier.h"
+#include "vm/isolate_reload.h"
 #include "vm/object_store.h"
 #include "vm/parser.h"
 #include "vm/precompiler.h"
 #include "vm/profiler.h"
+#include "vm/resolver.h"
 #include "vm/reusable_handles.h"
 #include "vm/runtime_entry.h"
 #include "vm/scopes.h"
@@ -40,6 +42,7 @@
 #include "vm/thread_registry.h"
 #include "vm/timeline.h"
 #include "vm/timer.h"
+#include "vm/type_table.h"
 #include "vm/unicode.h"
 #include "vm/verified_memory.h"
 #include "vm/weak_code.h"
@@ -61,9 +64,13 @@
 DEFINE_FLAG(bool, ignore_patch_signature_mismatch, false,
             "Ignore patch file member signature mismatch.");
 
+DEFINE_FLAG(bool, remove_script_timestamps_for_test, false,
+            "Remove script timestamps to allow for deterministic testing.");
+
 DECLARE_FLAG(bool, show_invisible_frames);
 DECLARE_FLAG(bool, trace_deoptimization);
 DECLARE_FLAG(bool, trace_deoptimization_verbose);
+DECLARE_FLAG(bool, trace_reload);
 DECLARE_FLAG(bool, write_protect_code);
 DECLARE_FLAG(bool, support_externalizable_strings);
 
@@ -1140,12 +1147,16 @@
       GrowableObjectArray::type_arguments_offset());
   cls.set_num_type_arguments(1);
 
-  // canonical_type_arguments_ are Smi terminated.
-  // Last element contains the count of used slots.
+  // Initialize hash set for canonical_type_.
+  const intptr_t kInitialCanonicalTypeSize = 16;
+  array = HashTables::New<CanonicalTypeSet>(
+      kInitialCanonicalTypeSize, Heap::kOld);
+  object_store->set_canonical_types(array);
+
+  // Initialize hash set for canonical_type_arguments_.
   const intptr_t kInitialCanonicalTypeArgumentsSize = 4;
-  array = Array::New(kInitialCanonicalTypeArgumentsSize + 1);
-  array.SetAt(kInitialCanonicalTypeArgumentsSize,
-              Smi::Handle(zone, Smi::New(0)));
+  array = HashTables::New<CanonicalTypeArgumentsSet>(
+      kInitialCanonicalTypeArgumentsSize, Heap::kOld);
   object_store->set_canonical_type_arguments(array);
 
   // Setup type class early in the process.
@@ -2773,13 +2784,18 @@
 void Class::DisableCHAOptimizedCode(const Class& subclass) {
   ASSERT(Thread::Current()->IsMutatorThread());
   CHACodeArray a(*this);
-  if (FLAG_trace_deoptimization && a.HasCodes()) {
+  if (FLAG_trace_deoptimization && a.HasCodes() && !subclass.IsNull()) {
     THR_Print("Adding subclass %s\n", subclass.ToCString());
   }
   a.DisableCode();
 }
 
 
+void Class::DisableAllCHAOptimizedCode() {
+  DisableCHAOptimizedCode(Class::Handle());
+}
+
+
 bool Class::TraceAllocation(Isolate* isolate) const {
   ClassTable* class_table = isolate->class_table();
   return class_table->TraceAllocationFor(id());
@@ -3124,7 +3140,7 @@
 
 
 template <class FakeInstance>
-RawClass* Class::New(intptr_t index) {
+RawClass* Class::NewCommon(intptr_t index) {
   ASSERT(Object::class_class() != Class::null());
   Class& result = Class::Handle();
   {
@@ -3147,28 +3163,43 @@
   result.set_num_native_fields(0);
   result.set_token_pos(TokenPosition::kNoSource);
   result.InitEmptyFields();
+  return result.raw();
+}
+
+
+template <class FakeInstance>
+RawClass* Class::New(intptr_t index) {
+  Class& result = Class::Handle(NewCommon<FakeInstance>(index));
   Isolate::Current()->RegisterClass(result);
   return result.raw();
 }
 
 
-RawClass* Class::New(const String& name,
+RawClass* Class::New(const Library& lib,
+                     const String& name,
                      const Script& script,
                      TokenPosition token_pos) {
-  Class& result = Class::Handle(New<Instance>(kIllegalCid));
+  Class& result = Class::Handle(NewCommon<Instance>(kIllegalCid));
+  result.set_library(lib);
   result.set_name(name);
   result.set_script(script);
   result.set_token_pos(token_pos);
+  Isolate::Current()->RegisterClass(result);
   return result.raw();
 }
 
 
+RawClass* Class::NewInstanceClass() {
+  return Class::New<Instance>(kIllegalCid);
+}
+
+
 RawClass* Class::NewNativeWrapper(const Library& library,
                                   const String& name,
                                   int field_count) {
   Class& cls = Class::Handle(library.LookupClass(name));
   if (cls.IsNull()) {
-    cls = New(name, Script::Handle(), TokenPosition::kNoSource);
+    cls = New(library, name, Script::Handle(), TokenPosition::kNoSource);
     cls.SetFields(Object::empty_array());
     cls.SetFunctions(Object::empty_array());
     // Set super class to Object.
@@ -3611,96 +3642,26 @@
 }
 
 
-RawObject* Class::canonical_types() const {
-  return raw_ptr()->canonical_types_;
+RawType* Class::canonical_type() const {
+  return raw_ptr()->canonical_type_;
 }
 
 
-void Class::set_canonical_types(const Object& value) const {
+void Class::set_canonical_type(const Type& value) const {
   ASSERT(!value.IsNull());
-  StorePointer(&raw_ptr()->canonical_types_, value.raw());
+  StorePointer(&raw_ptr()->canonical_type_, value.raw());
 }
 
 
 RawType* Class::CanonicalType() const {
-  if (!IsGeneric() && !IsClosureClass()) {
-    return reinterpret_cast<RawType*>(raw_ptr()->canonical_types_);
-  }
-  Array& types = Array::Handle();
-  types ^= canonical_types();
-  if (!types.IsNull() && (types.Length() > 0)) {
-    return reinterpret_cast<RawType*>(types.At(0));
-  }
-  return reinterpret_cast<RawType*>(Object::null());
+  return raw_ptr()->canonical_type_;
 }
 
 
 void Class::SetCanonicalType(const Type& type) const {
-  ASSERT(type.IsCanonical());
-  if (!IsGeneric() && !IsClosureClass()) {
-    ASSERT((canonical_types() == Object::null()) ||
-           (canonical_types() == type.raw()));  // Set during own finalization.
-    set_canonical_types(type);
-  } else {
-    Array& types = Array::Handle();
-    types ^= canonical_types();
-    ASSERT(!types.IsNull() && (types.Length() > 1));
-    ASSERT((types.At(0) == Object::null()) || (types.At(0) == type.raw()));
-    types.SetAt(0, type);
-    // Makes sure that 'canonical_types' has not changed.
-    ASSERT(types.raw() == canonical_types());
-  }
-}
-
-
-intptr_t Class::FindCanonicalTypeIndex(const AbstractType& needle) const {
-  Thread* thread = Thread::Current();
-  if (EnsureIsFinalized(thread) != Error::null()) {
-    return -1;
-  }
-  if (needle.raw() == CanonicalType()) {
-    // For a generic type or signature type, there exists another index with the
-    // same type. It will never be returned by this function.
-    return 0;
-  }
-  REUSABLE_OBJECT_HANDLESCOPE(thread);
-  Object& types = thread->ObjectHandle();
-  types = canonical_types();
-  if (types.IsNull()) {
-    return -1;
-  }
-  const intptr_t len = Array::Cast(types).Length();
-  REUSABLE_ABSTRACT_TYPE_HANDLESCOPE(thread);
-  AbstractType& type = thread->AbstractTypeHandle();
-  for (intptr_t i = 0; i < len; i++) {
-    type ^= Array::Cast(types).At(i);
-    if (needle.raw() == type.raw()) {
-      return i;
-    }
-  }
-  // No type found.
-  return -1;
-}
-
-
-RawAbstractType* Class::CanonicalTypeFromIndex(intptr_t idx) const {
-  AbstractType& type = AbstractType::Handle();
-  if (idx == 0) {
-    type = CanonicalType();
-    if (!type.IsNull()) {
-      return type.raw();
-    }
-  }
-  Object& types = Object::Handle(canonical_types());
-  if (types.IsNull() || !types.IsArray()) {
-    return Type::null();
-  }
-  if ((idx < 0) || (idx >= Array::Cast(types).Length())) {
-    return Type::null();
-  }
-  type ^= Array::Cast(types).At(idx);
-  ASSERT(!type.IsNull());
-  return type.raw();
+  ASSERT((canonical_type() == Object::null()) ||
+         (canonical_type() == type.raw()));  // Set during own finalization.
+  set_canonical_type(type);
 }
 
 
@@ -4272,84 +4233,6 @@
 }
 
 
-// Returns AbstractType::null() if type not found. Modifies index to the last
-// position looked up.
-RawAbstractType* Class::LookupCanonicalType(
-    Zone* zone, const AbstractType& lookup_type, intptr_t* index) const {
-  Array& canonical_types = Array::Handle(zone);
-  canonical_types ^= this->canonical_types();
-  if (canonical_types.IsNull()) {
-    return AbstractType::null();
-  }
-  AbstractType& type = Type::Handle(zone);
-  const intptr_t length = canonical_types.Length();
-  while (*index < length) {
-    type ^= canonical_types.At(*index);
-    if (type.IsNull()) {
-      break;
-    }
-    ASSERT(type.IsFinalized());
-    if (lookup_type.Equals(type)) {
-      ASSERT(type.IsCanonical());
-      return type.raw();
-    }
-    *index = *index + 1;
-  }
-  return AbstractType::null();
-}
-
-
-// Canonicalizing the type arguments may have changed the index, may have
-// grown the table, or may even have canonicalized this type. Therefore
-// conrtinue search for canonical type at the last index visited.
-RawAbstractType* Class::LookupOrAddCanonicalType(
-    const AbstractType& lookup_type, intptr_t start_index) const {
-  Thread* thread = Thread::Current();
-  Zone* zone = thread->zone();
-  Isolate* isolate = thread->isolate();
-  AbstractType& type = Type::Handle(zone);
-  intptr_t index = start_index;
-  type ^= LookupCanonicalType(zone, lookup_type, &index);
-
-  if (!type.IsNull()) {
-    return type.raw();
-  }
-  {
-    SafepointMutexLocker ml(isolate->type_canonicalization_mutex());
-    // Lookup again, in case the canonicalization array changed.
-    Array& canonical_types = Array::Handle(zone);
-    canonical_types ^= this->canonical_types();
-    if (canonical_types.IsNull()) {
-      canonical_types = empty_array().raw();
-    }
-    const intptr_t length = canonical_types.Length();
-    // Start looking after previously looked up last position ('length').
-    type ^= LookupCanonicalType(zone, lookup_type, &index);
-    if (!type.IsNull()) {
-      return type.raw();
-    }
-
-    // 'lookup_type' is not canonicalized yet.
-    lookup_type.SetCanonical();
-
-    // The type needs to be added to the list. Grow the list if it is full.
-    if (index >= length) {
-      ASSERT((index == length) || ((index == 1) && (length == 0)));
-      const intptr_t new_length = (length > 64) ?
-          (length + 64) :
-          ((length == 0) ? 2 : (length * 2));
-      const Array& new_canonical_types = Array::Handle(
-          zone, Array::Grow(canonical_types, new_length, Heap::kOld));
-      new_canonical_types.SetAt(index, lookup_type);
-      this->set_canonical_types(new_canonical_types);
-    } else {
-      canonical_types.SetAt(index, lookup_type);
-    }
-  }
-  return lookup_type.raw();
-}
-
-
 const char* Class::ToCString() const {
   const Library& lib = Library::Handle(library());
   const char* library_name = lib.IsNull() ? "" : lib.ToCString();
@@ -4627,15 +4510,16 @@
 }
 
 
-static uint32_t FinalizeHash(uint32_t hash) {
+static uint32_t FinalizeHash(uint32_t hash, intptr_t hashbits) {
   hash += hash << 3;
   hash ^= hash >> 11;  // Logical shift, unsigned hash.
   hash += hash << 15;
-  return hash;
+  hash &= ((static_cast<intptr_t>(1) << hashbits) - 1);
+  return (hash == 0) ? 1 : hash;
 }
 
 
-intptr_t TypeArguments::Hash() const {
+intptr_t TypeArguments::ComputeHash() const {
   if (IsNull()) return 0;
   const intptr_t num_types = Length();
   if (IsRaw(0, num_types)) return 0;
@@ -4647,7 +4531,9 @@
     // purposes only) while a type argument is still temporarily null.
     result = CombineHashes(result, type.IsNull() ? 0 : type.Hash());
   }
-  return FinalizeHash(result);
+  result = FinalizeHash(result, kHashBits);
+  SetHash(result);
+  return result;
 }
 
 
@@ -5098,6 +4984,7 @@
     result ^= raw;
     // Length must be set before we start storing into the array.
     result.SetLength(len);
+    result.SetHash(0);
   }
   // The zero array should have been initialized.
   ASSERT(Object::zero_array().raw() != Array::null());
@@ -5123,99 +5010,6 @@
 }
 
 
-static void GrowCanonicalTypeArguments(Thread* thread, const Array& table) {
-  Isolate* isolate = thread->isolate();
-  Zone* zone = thread->zone();
-  // Last element of the array is the number of used elements.
-  const intptr_t table_size = table.Length() - 1;
-  const intptr_t new_table_size = table_size * 2;
-  Array& new_table = Array::Handle(zone, Array::New(new_table_size + 1));
-  // Copy all elements from the original table to the newly allocated
-  // array.
-  TypeArguments& element = TypeArguments::Handle(zone);
-  Object& new_element = Object::Handle(zone);
-  for (intptr_t i = 0; i < table_size; i++) {
-    element ^= table.At(i);
-    if (!element.IsNull()) {
-      const intptr_t hash = element.Hash();
-      ASSERT(Utils::IsPowerOfTwo(new_table_size));
-      intptr_t index = hash & (new_table_size - 1);
-      new_element = new_table.At(index);
-      while (!new_element.IsNull()) {
-        index = (index + 1) & (new_table_size - 1);  // Move to next element.
-        new_element = new_table.At(index);
-      }
-      new_table.SetAt(index, element);
-    }
-  }
-  // Copy used count.
-  new_element = table.At(table_size);
-  new_table.SetAt(new_table_size, new_element);
-  // Remember the new table now.
-  isolate->object_store()->set_canonical_type_arguments(new_table);
-}
-
-
-static void InsertIntoCanonicalTypeArguments(Thread* thread,
-                                             const Array& table,
-                                             const TypeArguments& arguments,
-                                             intptr_t index) {
-  Zone* zone = thread->zone();
-  arguments.SetCanonical();  // Mark object as being canonical.
-  table.SetAt(index, arguments);  // Remember the new element.
-  // Update used count.
-  // Last element of the array is the number of used elements.
-  const intptr_t table_size = table.Length() - 1;
-  const intptr_t used_elements =
-      Smi::Value(Smi::RawCast(table.At(table_size))) + 1;
-  const Smi& used = Smi::Handle(zone, Smi::New(used_elements));
-  table.SetAt(table_size, used);
-
-#ifdef DEBUG
-  // Verify that there are no duplicates.
-  // Duplicates could appear if hash values are not kept constant across
-  // snapshots, e.g. if class ids are not preserved by the snapshots.
-  TypeArguments& other_arguments = TypeArguments::Handle();
-  for (intptr_t i = 0; i < table_size; i++) {
-    if ((i != index) && (table.At(i) != TypeArguments::null())) {
-      other_arguments ^= table.At(i);
-      if (arguments.Equals(other_arguments)) {
-        // Recursive types may be equal, but have different hashes.
-        ASSERT(arguments.IsRecursive());
-        ASSERT(other_arguments.IsRecursive());
-        ASSERT(arguments.Hash() != other_arguments.Hash());
-      }
-    }
-  }
-#endif
-
-  // Rehash if table is 75% full.
-  if (used_elements > ((table_size / 4) * 3)) {
-    GrowCanonicalTypeArguments(thread, table);
-  }
-}
-
-
-static intptr_t FindIndexInCanonicalTypeArguments(
-    Zone* zone,
-    const Array& table,
-    const TypeArguments& arguments,
-    intptr_t hash) {
-  // Last element of the array is the number of used elements.
-  const intptr_t table_size = table.Length() - 1;
-  ASSERT(Utils::IsPowerOfTwo(table_size));
-  intptr_t index = hash & (table_size - 1);
-
-  TypeArguments& current = TypeArguments::Handle(zone);
-  current ^= table.At(index);
-  while (!current.IsNull() && !current.Equals(arguments)) {
-    index = (index + 1) & (table_size - 1);  // Move to next element.
-    current ^= table.At(index);
-  }
-  return index;  // Index of element if found or slot into which to add it.
-}
-
-
 RawTypeArguments* TypeArguments::CloneUnfinalized() const {
   if (IsNull() || IsFinalized()) {
     return raw();
@@ -5270,15 +5064,14 @@
   Zone* zone = thread->zone();
   Isolate* isolate = thread->isolate();
   ObjectStore* object_store = isolate->object_store();
-  Array& table = Array::Handle(zone,
-                               object_store->canonical_type_arguments());
-  // Last element of the array is the number of used elements.
-  const intptr_t num_used =
-      Smi::Value(Smi::RawCast(table.At(table.Length() - 1)));
-  const intptr_t hash = Hash();
-  intptr_t index = FindIndexInCanonicalTypeArguments(zone, table, *this, hash);
   TypeArguments& result = TypeArguments::Handle(zone);
-  result ^= table.At(index);
+  {
+    SafepointMutexLocker ml(isolate->type_canonicalization_mutex());
+    CanonicalTypeArgumentsSet table(zone,
+                                    object_store->canonical_type_arguments());
+    result ^= table.GetOrNull(CanonicalTypeArgumentsKey(*this));
+    object_store->set_canonical_type_arguments(table.Release());
+  }
   if (result.IsNull()) {
     // Canonicalize each type argument.
     AbstractType& type_arg = AbstractType::Handle(zone);
@@ -5292,21 +5085,18 @@
       }
       SetTypeAt(i, type_arg);
     }
-    // Canonicalization of a recursive type may change its hash.
-    intptr_t canonical_hash = hash;
+    // Canonicalization of a type argument of a recursive type argument vector
+    // may change the hash of the vector, so recompute.
     if (IsRecursive()) {
-      canonical_hash = Hash();
+      ComputeHash();
     }
-    // Canonicalization of the type argument's own type arguments may add an
-    // entry to the table, or even grow the table, and thereby change the
-    // previously calculated index.
-    table = object_store->canonical_type_arguments();
-    if ((canonical_hash != hash) ||
-        (Smi::Value(Smi::RawCast(table.At(table.Length() - 1))) != num_used)) {
-      index = FindIndexInCanonicalTypeArguments(
-          zone, table, *this, canonical_hash);
-      result ^= table.At(index);
-    }
+    SafepointMutexLocker ml(isolate->type_canonicalization_mutex());
+    CanonicalTypeArgumentsSet table(
+        zone, object_store->canonical_type_arguments());
+    // Since we canonicalized some type arguments above we need to lookup
+    // in the table again to make sure we don't already have an equivalent
+    // canonical entry.
+    result ^= table.GetOrNull(CanonicalTypeArgumentsKey(*this));
     if (result.IsNull()) {
       // Make sure we have an old space object and add it to the table.
       if (this->IsNew()) {
@@ -5315,8 +5105,12 @@
         result ^= this->raw();
       }
       ASSERT(result.IsOld());
-      InsertIntoCanonicalTypeArguments(thread, table, result, index);
+      result.SetCanonical();  // Mark object as being canonical.
+      // Now add this TypeArgument into the canonical list of type arguments.
+      bool present = table.Insert(result);
+      ASSERT(!present);
     }
+    object_store->set_canonical_type_arguments(table.Release());
   }
   ASSERT(result.Equals(*this));
   ASSERT(!result.IsNull());
@@ -5347,12 +5141,13 @@
   if (IsNull()) {
     return "NULL TypeArguments";
   }
-  const char* prev_cstr = "TypeArguments:";
+  Zone* zone = Thread::Current()->zone();
+  const char* prev_cstr = OS::SCreate(
+      zone, "TypeArguments: (%" Pd ")", Smi::Value(raw_ptr()->hash_));
   for (int i = 0; i < Length(); i++) {
-    const AbstractType& type_at = AbstractType::Handle(TypeAt(i));
+    const AbstractType& type_at = AbstractType::Handle(zone, TypeAt(i));
     const char* type_cstr = type_at.IsNull() ? "null" : type_at.ToCString();
-    char* chars = OS::SCreate(Thread::Current()->zone(),
-        "%s [%s]", prev_cstr, type_cstr);
+    char* chars = OS::SCreate(zone, "%s [%s]", prev_cstr, type_cstr);
     prev_cstr = chars;
   }
   return prev_cstr;
@@ -5471,6 +5266,19 @@
 }
 
 
+void Function::EnsureHasCompiledUnoptimizedCode() const {
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  ASSERT(thread->IsMutatorThread());
+
+  const Error& error = Error::Handle(zone,
+      Compiler::EnsureUnoptimizedCode(thread, *this));
+  if (!error.IsNull()) {
+    Exceptions::PropagateError(error);
+  }
+}
+
+
 void Function::SwitchToUnoptimizedCode() const {
   ASSERT(HasOptimizedCode());
   Thread* thread = Thread::Current();
@@ -5497,6 +5305,34 @@
 }
 
 
+void Function::SwitchToLazyCompiledUnoptimizedCode() const {
+  if (!HasOptimizedCode()) {
+    return;
+  }
+
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  ASSERT(thread->IsMutatorThread());
+
+  const Code& current_code = Code::Handle(zone, CurrentCode());
+  TIR_Print("Disabling optimized code for %s\n", ToCString());
+  current_code.DisableDartCode();
+
+  const Code& unopt_code = Code::Handle(zone, unoptimized_code());
+  if (unopt_code.IsNull()) {
+    // Set the lazy compile code.
+    TIR_Print("Switched to lazy compile stub for %s\n", ToCString());
+    SetInstructions(Code::Handle(StubCode::LazyCompile_entry()->code()));
+    return;
+  }
+
+  TIR_Print("Switched to unoptimized code for %s\n", ToCString());
+
+  AttachCode(unopt_code);
+  unopt_code.Enable();
+}
+
+
 void Function::set_unoptimized_code(const Code& value) const {
   ASSERT(Thread::Current()->IsMutatorThread());
   ASSERT(value.IsNull() || !value.is_optimized());
@@ -7061,6 +6897,8 @@
 
 
 RawScript* Function::script() const {
+  // NOTE(turnidge): If you update this function, you probably want to
+  // update Class::PatchFieldsAndFunctions() at the same time.
   if (token_pos() == TokenPosition::kMinSource) {
     // Testing for position 0 is an optimization that relies on temporary
     // eval functions having token position 0.
@@ -7538,6 +7376,8 @@
 
 
 RawScript* Field::Script() const {
+  // NOTE(turnidge): If you update this function, you probably want to
+  // update Class::PatchFieldsAndFunctions() at the same time.
   const Field& field = Field::Handle(Original());
   ASSERT(field.IsOriginal());
   const Object& obj = Object::Handle(field.raw_ptr()->owner_);
@@ -7569,16 +7409,14 @@
 }
 
 
-RawField* Field::New(const String& name,
-                     bool is_static,
-                     bool is_final,
-                     bool is_const,
-                     bool is_reflectable,
-                     const Class& owner,
-                     const AbstractType& type,
-                     TokenPosition token_pos) {
-  ASSERT(!owner.IsNull());
-  const Field& result = Field::Handle(Field::New());
+void Field::InitializeNew(const Field& result,
+                          const String& name,
+                          bool is_static,
+                          bool is_final,
+                          bool is_const,
+                          bool is_reflectable,
+                          const Object& owner,
+                          TokenPosition token_pos) {
   result.set_name(name);
   result.set_is_static(is_static);
   if (!is_static) {
@@ -7589,19 +7427,47 @@
   result.set_is_reflectable(is_reflectable);
   result.set_is_double_initialized(false);
   result.set_owner(owner);
-  result.SetFieldType(type);
   result.set_token_pos(token_pos);
   result.set_has_initializer(false);
   result.set_is_unboxing_candidate(true);
-  result.set_guarded_cid(FLAG_use_field_guards ? kIllegalCid : kDynamicCid);
-  result.set_is_nullable(FLAG_use_field_guards ? false : true);
+  Isolate* isolate = Isolate::Current();
+
+  // Use field guards if they are enabled and the isolate has never reloaded.
+  // TODO(johnmccutchan): The reload case assumes the worst case (everything is
+  // dynamic and possibly null). Attempt to relax this later.
+  const bool use_field_guards =
+      FLAG_use_field_guards && !isolate->HasAttemptedReload();
+  result.set_guarded_cid(use_field_guards ? kIllegalCid : kDynamicCid);
+  result.set_is_nullable(use_field_guards ? false : true);
   result.set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset);
   // Presently, we only attempt to remember the list length for final fields.
-  if (is_final && FLAG_use_field_guards) {
+  if (is_final && use_field_guards) {
     result.set_guarded_list_length(Field::kUnknownFixedLength);
   } else {
     result.set_guarded_list_length(Field::kNoFixedLength);
   }
+}
+
+
+RawField* Field::New(const String& name,
+                     bool is_static,
+                     bool is_final,
+                     bool is_const,
+                     bool is_reflectable,
+                     const Class& owner,
+                     const AbstractType& type,
+                     TokenPosition token_pos) {
+  ASSERT(!owner.IsNull());
+  const Field& result = Field::Handle(Field::New());
+  InitializeNew(result,
+                name,
+                is_static,
+                is_final,
+                is_const,
+                is_reflectable,
+                owner,
+                token_pos);
+  result.SetFieldType(type);
   return result.raw();
 }
 
@@ -7613,25 +7479,14 @@
                              TokenPosition token_pos) {
   ASSERT(!owner.IsNull());
   const Field& result = Field::Handle(Field::New());
-  result.set_name(name);
-  result.set_is_static(true);
-  result.set_is_final(is_final);
-  result.set_is_const(is_const);
-  result.set_is_reflectable(true);
-  result.set_is_double_initialized(false);
-  result.set_owner(owner);
-  result.set_token_pos(token_pos);
-  result.set_has_initializer(false);
-  result.set_is_unboxing_candidate(true);
-  result.set_guarded_cid(FLAG_use_field_guards ? kIllegalCid : kDynamicCid);
-  result.set_is_nullable(FLAG_use_field_guards ? false : true);
-  result.set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset);
-  // Presently, we only attempt to remember the list length for final fields.
-  if (is_final && FLAG_use_field_guards) {
-    result.set_guarded_list_length(Field::kUnknownFixedLength);
-  } else {
-    result.set_guarded_list_length(Field::kNoFixedLength);
-  }
+  InitializeNew(result,
+                name,
+                true, /* is_static */
+                is_final,
+                is_const,
+                true, /* is_reflectable */
+                owner,
+                token_pos);
   return result.raw();
 }
 
@@ -8100,6 +7955,18 @@
 }
 
 
+void Field::ForceDynamicGuardedCidAndLength() const {
+  // Assume nothing about this field.
+  set_is_unboxing_candidate(false);
+  set_guarded_cid(kDynamicCid);
+  set_is_nullable(true);
+  set_guarded_list_length(Field::kNoFixedLength);
+  set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset);
+  // Drop any code that relied on the above assumptions.
+  DeoptimizeDependentCode();
+}
+
+
 void LiteralToken::set_literal(const String& literal) const {
   StorePointer(&raw_ptr()->literal_, literal.raw());
 }
@@ -8373,19 +8240,18 @@
 }
 
 
-TokenPosition TokenStream::ComputeSourcePosition(
-    TokenPosition tok_pos) const {
+intptr_t TokenStream::ComputeSourcePosition(TokenPosition tok_pos) const {
   Zone* zone = Thread::Current()->zone();
   Iterator iterator(zone,
                     *this,
                     TokenPosition::kMinSource,
                     Iterator::kAllTokens);
-  TokenPosition src_pos = TokenPosition::kMinSource;
+  intptr_t src_pos = 0;
   Token::Kind kind = iterator.CurrentTokenKind();
   while ((iterator.CurrentPosition() < tok_pos) && (kind != Token::kEOS)) {
     iterator.Advance();
     kind = iterator.CurrentTokenKind();
-    src_pos.Next();
+    src_pos++;
   }
   return src_pos;
 }
@@ -8457,7 +8323,7 @@
 
 
 // Helper class for creation of compressed token stream data.
-class CompressedTokenStreamData : public ValueObject {
+class CompressedTokenStreamData : public Scanner::TokenCollector {
  public:
   static const intptr_t kInitialBufferSize = 16 * KB;
   static const bool kPrintTokenObjects = false;
@@ -8469,9 +8335,32 @@
       token_objects_(ta),
       tokens_(map),
       value_(Object::Handle()),
-      fresh_index_smi_(Smi::Handle()) {
+      fresh_index_smi_(Smi::Handle()),
+      num_tokens_collected_(0) {
+  }
+  virtual ~CompressedTokenStreamData() { }
+
+  virtual void AddToken(const Scanner::TokenDescriptor& token) {
+    if (token.kind == Token::kIDENT) {  // Identifier token.
+      AddIdentToken(*token.literal);
+    } else if (Token::NeedsLiteralToken(token.kind)) {  // Literal token.
+      AddLiteralToken(token);
+    } else {  // Keyword, pseudo keyword etc.
+      ASSERT(token.kind < Token::kNumTokens);
+      AddSimpleToken(token.kind);
+    }
+    num_tokens_collected_++;
   }
 
+  // Return the compressed token stream.
+  uint8_t* GetStream() const { return buffer_; }
+
+  // Return the compressed token stream length.
+  intptr_t Length() const { return stream_.bytes_written(); }
+
+  intptr_t NumTokens() const { return num_tokens_collected_; }
+
+ private:
   // Add an IDENT token into the stream and the token hash map.
   void AddIdentToken(const String& ident) {
     ASSERT(ident.IsSymbol());
@@ -8522,13 +8411,6 @@
     stream_.WriteUnsigned(kind);
   }
 
-  // Return the compressed token stream.
-  uint8_t* GetStream() const { return buffer_; }
-
-  // Return the compressed token stream length.
-  intptr_t Length() const { return stream_.bytes_written(); }
-
- private:
   void WriteIndex(intptr_t value) {
     stream_.WriteUnsigned(value + Token::kNumTokens);
   }
@@ -8546,18 +8428,17 @@
   CompressedTokenMap* tokens_;
   Object& value_;
   Smi& fresh_index_smi_;
+  intptr_t num_tokens_collected_;
 
   DISALLOW_COPY_AND_ASSIGN(CompressedTokenStreamData);
 };
 
 
-RawTokenStream* TokenStream::New(const Scanner::GrowableTokenStream& tokens,
+RawTokenStream* TokenStream::New(const String& source,
                                  const String& private_key,
                                  bool use_shared_tokens) {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
-  // Copy the relevant data out of the scanner into a compressed stream of
-  // tokens.
 
   GrowableObjectArray& token_objects = GrowableObjectArray::Handle(zone);
   Array& token_objects_map = Array::Handle(zone);
@@ -8581,20 +8462,9 @@
   }
   CompressedTokenMap map(token_objects_map.raw());
   CompressedTokenStreamData data(token_objects, &map);
-
-  intptr_t len = tokens.length();
-  for (intptr_t i = 0; i < len; i++) {
-    Scanner::TokenDescriptor token = tokens[i];
-    if (token.kind == Token::kIDENT) {  // Identifier token.
-      data.AddIdentToken(*token.literal);
-    } else if (Token::NeedsLiteralToken(token.kind)) {  // Literal token.
-      data.AddLiteralToken(token);
-    } else {  // Keyword, pseudo keyword etc.
-      ASSERT(token.kind < Token::kNumTokens);
-      data.AddSimpleToken(token.kind);
-    }
-  }
-  data.AddSimpleToken(Token::kEOS);  // End of stream.
+  Scanner scanner(source, private_key);
+  scanner.ScanAll(&data);
+  INC_STAT(thread, num_tokens_scanned, data.NumTokens());
 
   // Create and setup the token stream object.
   const ExternalTypedData& stream = ExternalTypedData::Handle(
@@ -8924,6 +8794,11 @@
 }
 
 
+void Script::set_load_timestamp(int64_t value) const {
+  StoreNonPointer(&raw_ptr()->load_timestamp_, value);
+}
+
+
 void Script::set_tokens(const TokenStream& value) const {
   StorePointer(&raw_ptr()->tokens_, value.raw());
 }
@@ -8942,11 +8817,9 @@
   VMTagScope tagScope(thread, VMTag::kCompileScannerTagId);
   CSTAT_TIMER_SCOPE(thread, scanner_timer);
   const String& src = String::Handle(zone, Source());
-  Scanner scanner(src, private_key);
-  const Scanner::GrowableTokenStream& ts = scanner.GetStream();
-  INC_STAT(thread, num_tokens_scanned, ts.length());
-  set_tokens(TokenStream::Handle(zone,
-      TokenStream::New(ts, private_key, use_shared_tokens)));
+  const TokenStream& ts = TokenStream::Handle(zone,
+      TokenStream::New(src, private_key, use_shared_tokens));
+  set_tokens(ts);
   INC_STAT(thread, src_length, src.Length());
 }
 
@@ -8994,7 +8867,7 @@
     *line = cur_line;
   } else {
     const String& src = String::Handle(zone, Source());
-    TokenPosition src_pos = tkns.ComputeSourcePosition(token_pos);
+    intptr_t src_pos = tkns.ComputeSourcePosition(token_pos);
     Scanner scanner(src, Symbols::Empty());
     scanner.ScanTo(src_pos);
     intptr_t relative_line = scanner.CurrentPosition().line;
@@ -9179,13 +9052,16 @@
   result.set_url(String::Handle(zone, Symbols::New(thread, url)));
   result.set_source(source);
   result.set_kind(kind);
+  result.set_load_timestamp(FLAG_remove_script_timestamps_for_test
+                            ? 0 : OS::GetCurrentTimeMillis());
   result.SetLocationOffset(0, 0);
   return result.raw();
 }
 
 
 const char* Script::ToCString() const {
-  return "Script";
+  const String& name = String::Handle(url());
+  return OS::SCreate(Thread::Current()->zone(), "Script(%s)", name.ToCString());
 }
 
 
@@ -9373,8 +9249,6 @@
     return Library::Cast(key).UrlHash();
   }
 };
-
-
 typedef UnorderedHashSet<LibraryUrlTraits> LibraryLoadErrorSet;
 
 
@@ -9654,7 +9528,7 @@
   obj = LookupLocalObject(name);
   if (!obj.IsNull()) {
     // Names that are in this library's dictionary and are unmangled
-    // are not cached. This reduces the size of the the cache.
+    // are not cached. This reduces the size of the cache.
     return obj.raw();
   }
   String& accessor_name = String::Handle(Field::LookupGetterSymbol(name));
@@ -12675,9 +12549,20 @@
 }
 
 
+intptr_t ICData::Length() const {
+  return (Smi::Value(ic_data()->ptr()->length_) / TestEntryLength());
+}
+
+
 intptr_t ICData::NumberOfChecks() const {
-  // Do not count the sentinel;
-  return (Smi::Value(ic_data()->ptr()->length_) / TestEntryLength()) - 1;
+  const intptr_t length = Length();
+  for (intptr_t i = 0; i < length; i++) {
+    if (IsSentinelAt(i)) {
+      return i;
+    }
+  }
+  UNREACHABLE();
+  return -1;
 }
 
 
@@ -12714,6 +12599,7 @@
     GetClassIdsAt(i, &class_ids);
     bool matches = true;
     for (intptr_t k = 0; k < class_ids.length(); k++) {
+      ASSERT(class_ids[k] != kIllegalCid);
       if (class_ids[k] != cids[k]) {
         matches = false;
         break;
@@ -12728,6 +12614,142 @@
 #endif  // DEBUG
 
 
+void ICData::WriteSentinelAt(intptr_t index) const {
+  const intptr_t len = Length();
+  ASSERT(index >= 0);
+  ASSERT(index < len);
+  Array& data = Array::Handle(ic_data());
+  const intptr_t start = index * TestEntryLength();
+  const intptr_t end = start + TestEntryLength();
+  for (intptr_t i = start; i < end; i++) {
+    data.SetAt(i, smi_illegal_cid());
+  }
+}
+
+
+void ICData::ClearCountAt(intptr_t index) const {
+  const intptr_t len = NumberOfChecks();
+  ASSERT(index >= 0);
+  ASSERT(index < len);
+  SetCountAt(index, 0);
+}
+
+
+void ICData::ClearWithSentinel() const {
+  if (IsImmutable()) {
+    return;
+  }
+  // Write the sentinel value into all entries except the first one.
+  const intptr_t len = Length();
+  if (len == 0) {
+    return;
+  }
+  // The final entry is always the sentinel.
+  ASSERT(IsSentinelAt(len - 1));
+  for (intptr_t i = len - 1; i > 0; i--) {
+    WriteSentinelAt(i);
+  }
+  if (NumArgsTested() != 2) {
+    // Not the smi fast path case, write sentinel to first one and exit.
+    WriteSentinelAt(0);
+    return;
+  }
+  if (IsSentinelAt(0)) {
+    return;
+  }
+  Zone* zone = Thread::Current()->zone();
+  const String& name = String::Handle(target_name());
+  const Class& smi_class = Class::Handle(Smi::Class());
+  const Function& smi_op_target =
+      Function::Handle(Resolver::ResolveDynamicAnyArgs(zone, smi_class, name));
+  GrowableArray<intptr_t> class_ids(2);
+  Function& target = Function::Handle();
+  GetCheckAt(0, &class_ids, &target);
+  if ((target.raw() == smi_op_target.raw()) &&
+      (class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) {
+    // The smi fast path case, preserve the initial entry but reset the count.
+    ClearCountAt(0);
+    return;
+  }
+  WriteSentinelAt(0);
+}
+
+
+void ICData::ClearAndSetStaticTarget(const Function& func) const {
+  if (IsImmutable()) {
+    return;
+  }
+  const intptr_t len = Length();
+  if (len == 0) {
+    return;
+  }
+  // The final entry is always the sentinel.
+  ASSERT(IsSentinelAt(len - 1));
+  if (NumArgsTested() == 0) {
+    // No type feedback is being collected.
+    const Array& data = Array::Handle(ic_data());
+    // Static calls with no argument checks hold only one target and the
+    // sentinel value.
+    ASSERT(len == 2);
+    // Static calls with no argument checks only need two words.
+    ASSERT(TestEntryLength() == 2);
+    // Set the target.
+    data.SetAt(0, func);
+    // Set count to 0 as this is called during compilation, before the
+    // call has been executed.
+    const Smi& value = Smi::Handle(Smi::New(0));
+    data.SetAt(1, value);
+  } else {
+    // Type feedback on arguments is being collected.
+    const Array& data = Array::Handle(ic_data());
+
+    // Fill all but the first entry with the sentinel.
+    for (intptr_t i = len - 1; i > 0; i--) {
+      WriteSentinelAt(i);
+    }
+    // Rewrite the dummy entry.
+    const Smi& object_cid = Smi::Handle(Smi::New(kObjectCid));
+    for (intptr_t i = 0; i < NumArgsTested(); i++) {
+      data.SetAt(i, object_cid);
+    }
+    data.SetAt(NumArgsTested(), func);
+    const Smi& value = Smi::Handle(Smi::New(0));
+    data.SetAt(NumArgsTested() + 1, value);
+  }
+}
+
+
+// Add an initial Smi/Smi check with count 0.
+bool ICData::AddSmiSmiCheckForFastSmiStubs() const {
+  bool is_smi_two_args_op = false;
+
+  ASSERT(NumArgsTested() == 2);
+  const String& name = String::Handle(target_name());
+  const Class& smi_class = Class::Handle(Smi::Class());
+  Zone* zone = Thread::Current()->zone();
+  const Function& smi_op_target =
+      Function::Handle(Resolver::ResolveDynamicAnyArgs(zone, smi_class, name));
+  if (NumberOfChecks() == 0) {
+    GrowableArray<intptr_t> class_ids(2);
+    class_ids.Add(kSmiCid);
+    class_ids.Add(kSmiCid);
+    AddCheck(class_ids, smi_op_target);
+    // 'AddCheck' sets the initial count to 1.
+    SetCountAt(0, 0);
+    is_smi_two_args_op = true;
+  } else if (NumberOfChecks() == 1) {
+    GrowableArray<intptr_t> class_ids(2);
+    Function& target = Function::Handle();
+    GetCheckAt(0, &class_ids, &target);
+    if ((target.raw() == smi_op_target.raw()) &&
+        (class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) {
+      is_smi_two_args_op = true;
+    }
+  }
+  return is_smi_two_args_op;
+}
+
+
 // Used for unoptimized static calls when no class-ids are checked.
 void ICData::AddTarget(const Function& target) const {
   ASSERT(!target.IsNull());
@@ -12797,10 +12819,10 @@
       return;
     }
   }
-  const intptr_t new_len = data.Length() + TestEntryLength();
-  data = Array::Grow(data, new_len, Heap::kOld);
-  WriteSentinel(data, TestEntryLength());
-  intptr_t data_pos = old_num * TestEntryLength();
+  intptr_t index = -1;
+  data = FindFreeIndex(&index);
+  ASSERT(!data.IsNull());
+  intptr_t data_pos = index * TestEntryLength();
   Smi& value = Smi::Handle();
   for (intptr_t i = 0; i < class_ids.length(); i++) {
     // kIllegalCid is used as terminating value, do not add it.
@@ -12818,6 +12840,57 @@
 }
 
 
+RawArray* ICData::FindFreeIndex(intptr_t* index) const {
+  // The final entry is always the sentinel value, don't consider it
+  // when searching.
+  const intptr_t len = Length() - 1;
+  Array& data = Array::Handle(ic_data());
+  *index = len;
+  for (intptr_t i = 0; i < len; i++) {
+    if (IsSentinelAt(i)) {
+      *index = i;
+      break;
+    }
+  }
+  if (*index < len) {
+    // We've found a free slot.
+    return data.raw();
+  }
+  // Append case.
+  ASSERT(*index == len);
+  ASSERT(*index >= 0);
+  // Grow array.
+  const intptr_t new_len = data.Length() + TestEntryLength();
+  data = Array::Grow(data, new_len, Heap::kOld);
+  WriteSentinel(data, TestEntryLength());
+  return data.raw();
+}
+
+
+void ICData::DebugDump() const {
+  const Function& owner = Function::Handle(Owner());
+  THR_Print("ICData::DebugDump\n");
+  THR_Print("Owner = %s [deopt=%" Pd "]\n", owner.ToCString(), deopt_id());
+  THR_Print("NumArgsTested = %" Pd "\n", NumArgsTested());
+  THR_Print("Length = %" Pd "\n", Length());
+  THR_Print("NumberOfChecks = %" Pd "\n", NumberOfChecks());
+
+  GrowableArray<intptr_t> class_ids;
+  for (intptr_t i = 0; i < NumberOfChecks(); i++) {
+    THR_Print("Check[%" Pd "]:", i);
+    GetClassIdsAt(i, &class_ids);
+    for (intptr_t c = 0; c < class_ids.length(); c++) {
+      THR_Print(" %" Pd "", class_ids[c]);
+    }
+    THR_Print("--- %" Pd " hits\n", GetCountAt(i));
+  }
+}
+
+
+void ICData::ValidateSentinelLocations() const {
+}
+
+
 void ICData::AddReceiverCheck(intptr_t receiver_class_id,
                               const Function& target,
                               intptr_t count) const {
@@ -12830,12 +12903,9 @@
   ASSERT(NumArgsTested() == 1);  // Otherwise use 'AddCheck'.
   ASSERT(receiver_class_id != kIllegalCid);
 
-  const intptr_t old_num = NumberOfChecks();
-  Array& data = Array::Handle(ic_data());
-  const intptr_t new_len = data.Length() + TestEntryLength();
-  data = Array::Grow(data, new_len, Heap::kOld);
-  WriteSentinel(data, TestEntryLength());
-  intptr_t data_pos = old_num * TestEntryLength();
+  intptr_t index = -1;
+  Array& data = Array::Handle(FindFreeIndex(&index));
+  intptr_t data_pos = index * TestEntryLength();
   if ((receiver_class_id == kSmiCid) && (data_pos > 0)) {
     ASSERT(GetReceiverClassIdAt(0) != kSmiCid);
     // Move class occupying position 0 to the data_pos.
@@ -12880,10 +12950,26 @@
 }
 
 
+bool ICData::IsSentinelAt(intptr_t index) const {
+  ASSERT(index < Length());
+  const Array& data = Array::Handle(ic_data());
+  const intptr_t entry_length = TestEntryLength();
+  intptr_t data_pos = index * TestEntryLength();
+  for (intptr_t i = 0; i < entry_length; i++) {
+    if (data.At(data_pos++) != smi_illegal_cid().raw()) {
+      return false;
+    }
+  }
+  // The entry at |index| was filled with the value kIllegalCid.
+  return true;
+}
+
+
 void ICData::GetClassIdsAt(intptr_t index,
                            GrowableArray<intptr_t>* class_ids) const {
-  ASSERT(index < NumberOfChecks());
+  ASSERT(index < Length());
   ASSERT(class_ids != NULL);
+  ASSERT(!IsSentinelAt(index));
   class_ids->Clear();
   const Array& data = Array::Handle(ic_data());
   intptr_t data_pos = index * TestEntryLength();
@@ -12922,7 +13008,8 @@
 
 
 intptr_t ICData::GetReceiverClassIdAt(intptr_t index) const {
-  ASSERT(index < NumberOfChecks());
+  ASSERT(index < Length());
+  ASSERT(!IsSentinelAt(index));
   const intptr_t data_pos = index * TestEntryLength();
   NoSafepointScope no_safepoint;
   RawArray* raw_data = ic_data();
@@ -13126,10 +13213,9 @@
   // Room for all entries and the sentinel.
   const intptr_t data_len =
       result.TestEntryLength() * (aggregate.length() + 1);
+  // Allocate the array but do not assign it to result until we have populated
+  // it with the aggregate data and the terminating sentinel.
   const Array& data = Array::Handle(Array::New(data_len, Heap::kOld));
-  result.set_ic_data_array(data);
-  ASSERT(result.NumberOfChecks() == aggregate.length());
-
   intptr_t pos = 0;
   for (intptr_t i = 0; i < aggregate.length(); i++) {
     data.SetAt(pos + 0, Smi::Handle(Smi::New(aggregate[i].cid)));
@@ -13141,6 +13227,7 @@
   }
   WriteSentinel(data, result.TestEntryLength());
   result.set_ic_data_array(data);
+  ASSERT(result.NumberOfChecks() == aggregate.length());
   return result.raw();
 }
 
@@ -13287,6 +13374,22 @@
 }
 
 
+bool ICData::IsImmutable() const {
+  const Array& data = Array::Handle(ic_data());
+  return data.IsImmutable();
+}
+
+
+void ICData::ResetData() const {
+  // Number of array elements in one test entry.
+  intptr_t len = TestEntryLength();
+  // IC data array must be null terminated (sentinel entry).
+  const Array& ic_data = Array::Handle(Array::New(len, Heap::kOld));
+  set_ic_data_array(ic_data);
+  WriteSentinel(ic_data, len);
+}
+
+
 RawICData* ICData::New() {
   ICData& result = ICData::Handle();
   {
@@ -15113,7 +15216,7 @@
         *reinterpret_cast<RawObject**>(this_addr + offset));
     hash = CombineHashes(hash, value);
   }
-  return FinalizeHash(hash);
+  return FinalizeHash(hash, (kBitsPerWord - 1));
 }
 
 
@@ -15610,6 +15713,13 @@
 }
 
 
+classid_t AbstractType::type_class_id() const {
+  // AbstractType is an abstract class.
+  UNREACHABLE();
+  return kIllegalCid;
+}
+
+
 RawClass* AbstractType::type_class() const {
   // AbstractType is an abstract class.
   UNREACHABLE();
@@ -16475,19 +16585,18 @@
 
 
 bool Type::HasResolvedTypeClass() const {
-  return (raw_ptr()->type_class_->GetClassId() == kClassCid);
+  return !raw_ptr()->type_class_id_->IsHeapObject();
+}
+
+
+classid_t Type::type_class_id() const {
+  ASSERT(HasResolvedTypeClass());
+  return Smi::Value(reinterpret_cast<RawSmi*>(raw_ptr()->type_class_id_));
 }
 
 
 RawClass* Type::type_class() const {
-#ifdef DEBUG
-  ASSERT(HasResolvedTypeClass());
-  Class& type_class = Class::Handle();
-  type_class ^= raw_ptr()->type_class_;
-  return type_class.raw();
-#else
-  return reinterpret_cast<RawClass*>(raw_ptr()->type_class_);
-#endif
+  return Isolate::Current()->class_table()->At(type_class_id());
 }
 
 
@@ -16495,13 +16604,13 @@
 #ifdef DEBUG
   ASSERT(!HasResolvedTypeClass());
   UnresolvedClass& unresolved_class = UnresolvedClass::Handle();
-  unresolved_class ^= raw_ptr()->type_class_;
+  unresolved_class ^= raw_ptr()->type_class_id_;
   ASSERT(!unresolved_class.IsNull());
   return unresolved_class.raw();
 #else
-  ASSERT(!Object::Handle(raw_ptr()->type_class_).IsNull());
-  ASSERT(Object::Handle(raw_ptr()->type_class_).IsUnresolvedClass());
-  return reinterpret_cast<RawUnresolvedClass*>(raw_ptr()->type_class_);
+  ASSERT(!Object::Handle(raw_ptr()->type_class_id_).IsNull());
+  ASSERT(Object::Handle(raw_ptr()->type_class_id_).IsUnresolvedClass());
+  return reinterpret_cast<RawUnresolvedClass*>(raw_ptr()->type_class_id_);
 #endif
 }
 
@@ -16887,19 +16996,23 @@
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   Isolate* isolate = thread->isolate();
-  AbstractType& type = Type::Handle(zone);
-  const Class& cls = Class::Handle(zone, type_class());
+
   // Since void is a keyword, we never have to canonicalize the void type after
   // it is canonicalized once by the vm isolate. The parser does the mapping.
-  ASSERT((cls.raw() != Object::void_class()) ||
+  ASSERT((type_class() != Object::void_class()) ||
          (isolate == Dart::vm_isolate()));
+
   // Since dynamic is not a keyword, the parser builds a type that requires
   // canonicalization.
-  if ((cls.raw() == Object::dynamic_class()) &&
+  if ((type_class() == Object::dynamic_class()) &&
       (isolate != Dart::vm_isolate())) {
     ASSERT(Object::dynamic_type().IsCanonical());
     return Object::dynamic_type().raw();
   }
+
+  AbstractType& type = Type::Handle(zone);
+  const Class& cls = Class::Handle(zone, type_class());
+
   // Fast canonical lookup/registry for simple types.
   if (!cls.IsGeneric() && !cls.IsClosureClass() && !cls.IsTypedefClass()) {
     ASSERT(!IsFunctionType());
@@ -16917,12 +17030,13 @@
       set_arguments(type_args);
       type = cls.CanonicalType();  // May be set while canonicalizing type args.
       if (type.IsNull()) {
-        MutexLocker ml(isolate->type_canonicalization_mutex());
+        SafepointMutexLocker ml(isolate->type_canonicalization_mutex());
         // Recheck if type exists.
         type = cls.CanonicalType();
         if (type.IsNull()) {
+          ComputeHash();
           SetCanonical();
-          cls.set_canonical_types(*this);
+          cls.set_canonical_type(*this);
           return this->raw();
         }
       }
@@ -16932,73 +17046,76 @@
     return type.raw();
   }
 
-  Array& canonical_types = Array::Handle(zone);
-  canonical_types ^= cls.canonical_types();
-  if (canonical_types.IsNull()) {
-    canonical_types = empty_array().raw();
+  ObjectStore* object_store = isolate->object_store();
+  {
+    SafepointMutexLocker ml(isolate->type_canonicalization_mutex());
+    CanonicalTypeSet table(zone, object_store->canonical_types());
+    type ^= table.GetOrNull(CanonicalTypeKey(*this));
+    object_store->set_canonical_types(table.Release());
   }
-  intptr_t length = canonical_types.Length();
-  // Linear search to see whether this type is already present in the
-  // list of canonicalized types.
-  // TODO(asiva): Try to re-factor this lookup code to make sharing
-  // easy between the 4 versions of this loop.
-  intptr_t index = 1;  // Slot 0 is reserved for CanonicalType().
-  while (index < length) {
-    type ^= canonical_types.At(index);
-    if (type.IsNull()) {
-      break;
-    }
-    ASSERT(type.IsFinalized());
-    if (this->Equals(type)) {
-      ASSERT(type.IsCanonical());
-      return type.raw();
-    }
-    index++;
-  }
-  // The type was not found in the table. It is not canonical yet.
+  if (type.IsNull()) {
+    // The type was not found in the table. It is not canonical yet.
 
-  // Canonicalize the type arguments.
-  TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
-  // In case the type is first canonicalized at runtime, its type argument
-  // vector may be longer than necessary. This is not an issue.
-  ASSERT(type_args.IsNull() || (type_args.Length() >= cls.NumTypeArguments()));
-  type_args = type_args.Canonicalize(trail);
-  if (IsCanonical()) {
-    // Canonicalizing type_args canonicalized this type as a side effect.
-    ASSERT(IsRecursive());
-    // Cycles via typedefs are detected and disallowed, but a function type can
-    // be recursive due to a cycle in its type arguments.
-    return this->raw();
-  }
-  set_arguments(type_args);
-  ASSERT(type_args.IsNull() || type_args.IsOld());
+    // Canonicalize the type arguments.
+    TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
+    // In case the type is first canonicalized at runtime, its type argument
+    // vector may be longer than necessary. This is not an issue.
+    ASSERT(type_args.IsNull() ||
+           (type_args.Length() >= cls.NumTypeArguments()));
+    type_args = type_args.Canonicalize(trail);
+    if (IsCanonical()) {
+      // Canonicalizing type_args canonicalized this type as a side effect.
+      ASSERT(IsRecursive());
+      // Cycles via typedefs are detected and disallowed, but a function type
+      // can be recursive due to a cycle in its type arguments.
+      return this->raw();
+    }
+    set_arguments(type_args);
+    ASSERT(type_args.IsNull() || type_args.IsOld());
 
-  // In case of a function type, replace the actual function by a signature
-  // function.
-  if (IsFunctionType()) {
-    const Function& fun = Function::Handle(zone, signature());
-    if (!fun.IsSignatureFunction()) {
-      Function& sig_fun = Function::Handle(zone,
-          Function::NewSignatureFunction(cls, TokenPosition::kNoSource));
-      type = fun.result_type();
-      type = type.Canonicalize(trail);
-      sig_fun.set_result_type(type);
-      const intptr_t num_params = fun.NumParameters();
-      sig_fun.set_num_fixed_parameters(fun.num_fixed_parameters());
-      sig_fun.SetNumOptionalParameters(fun.NumOptionalParameters(),
-                                       fun.HasOptionalPositionalParameters());
-      sig_fun.set_parameter_types(Array::Handle(Array::New(num_params,
-                                                           Heap::kOld)));
-      for (intptr_t i = 0; i < num_params; i++) {
-        type = fun.ParameterTypeAt(i);
+    // In case of a function type, replace the actual function by a signature
+    // function.
+    if (IsFunctionType()) {
+      const Function& fun = Function::Handle(zone, signature());
+      if (!fun.IsSignatureFunction()) {
+        Function& sig_fun = Function::Handle(
+            zone,
+            Function::NewSignatureFunction(cls, TokenPosition::kNoSource));
+        type = fun.result_type();
         type = type.Canonicalize(trail);
-        sig_fun.SetParameterTypeAt(i, type);
+        sig_fun.set_result_type(type);
+        const intptr_t num_params = fun.NumParameters();
+        sig_fun.set_num_fixed_parameters(fun.num_fixed_parameters());
+        sig_fun.SetNumOptionalParameters(fun.NumOptionalParameters(),
+                                         fun.HasOptionalPositionalParameters());
+        sig_fun.set_parameter_types(Array::Handle(Array::New(num_params,
+                                                             Heap::kOld)));
+        for (intptr_t i = 0; i < num_params; i++) {
+          type = fun.ParameterTypeAt(i);
+          type = type.Canonicalize(trail);
+          sig_fun.SetParameterTypeAt(i, type);
+        }
+        sig_fun.set_parameter_names(Array::Handle(zone, fun.parameter_names()));
+        set_signature(sig_fun);
       }
-      sig_fun.set_parameter_names(Array::Handle(zone, fun.parameter_names()));
-      set_signature(sig_fun);
     }
+
+    // Check to see if the type got added to canonical list as part of the
+    // type arguments canonicalization.
+    SafepointMutexLocker ml(isolate->type_canonicalization_mutex());
+    CanonicalTypeSet table(zone, object_store->canonical_types());
+    type ^= table.GetOrNull(CanonicalTypeKey(*this));
+    if (type.IsNull()) {
+      // Add this Type into the canonical list of types.
+      type ^= raw();
+      ASSERT(type.IsOld());
+      type.SetCanonical();  // Mark object as being canonical.
+      bool present = table.Insert(type);
+      ASSERT(!present);
+    }
+    object_store->set_canonical_types(table.Release());
   }
-  return cls.LookupOrAddCanonicalType(*this, index);
+  return type.raw();
 }
 
 
@@ -17039,7 +17156,7 @@
 }
 
 
-intptr_t Type::Hash() const {
+intptr_t Type::ComputeHash() const {
   ASSERT(IsFinalized());
   uint32_t result = 1;
   if (IsMalformed()) return result;
@@ -17063,13 +17180,22 @@
       }
     }
   }
-  return FinalizeHash(result);
+  result = FinalizeHash(result, kHashBits);
+  SetHash(result);
+  return result;
 }
 
 
-void Type::set_type_class(const Object& value) const {
-  ASSERT(!value.IsNull() && (value.IsClass() || value.IsUnresolvedClass()));
-  StorePointer(&raw_ptr()->type_class_, value.raw());
+void Type::set_type_class(const Class& value) const {
+  ASSERT(!value.IsNull());
+  StorePointer(&raw_ptr()->type_class_id_,
+               reinterpret_cast<RawObject*>(Smi::New(value.id())));
+}
+
+
+void Type::set_unresolved_class(const Object& value) const {
+  ASSERT(!value.IsNull() && value.IsUnresolvedClass());
+  StorePointer(&raw_ptr()->type_class_id_, value.raw());
 }
 
 
@@ -17092,8 +17218,13 @@
                    TokenPosition token_pos,
                    Heap::Space space) {
   const Type& result = Type::Handle(Type::New(space));
-  result.set_type_class(clazz);
+  if (clazz.IsClass()) {
+    result.set_type_class(Class::Cast(clazz));
+  } else {
+    result.set_unresolved_class(clazz);
+  }
   result.set_arguments(arguments);
+  result.SetHash(0);
   result.set_token_pos(token_pos);
   result.StoreNonPointer(&result.raw_ptr()->type_state_, RawType::kAllocated);
   return result.raw();
@@ -17273,7 +17404,7 @@
   // Do not calculate the hash of the referenced type to avoid divergence.
   const uint32_t result =
       Class::Handle(AbstractType::Handle(type()).type_class()).id();
-  return FinalizeHash(result);
+  return FinalizeHash(result, kHashBits);
 }
 
 
@@ -17340,7 +17471,25 @@
 
 void TypeParameter::set_parameterized_class(const Class& value) const {
   // Set value may be null.
-  StorePointer(&raw_ptr()->parameterized_class_, value.raw());
+  classid_t cid = kIllegalCid;
+  if (!value.IsNull()) {
+    cid = value.id();
+  }
+  StoreNonPointer(&raw_ptr()->parameterized_class_id_, cid);
+}
+
+
+classid_t TypeParameter::parameterized_class_id() const {
+  return raw_ptr()->parameterized_class_id_;
+}
+
+
+RawClass* TypeParameter::parameterized_class() const {
+  classid_t cid = parameterized_class_id();
+  if (cid == kIllegalCid) {
+    return Class::null();
+  }
+  return Isolate::Current()->class_table()->At(cid);
 }
 
 
@@ -17503,13 +17652,15 @@
 }
 
 
-intptr_t TypeParameter::Hash() const {
+intptr_t TypeParameter::ComputeHash() const {
   ASSERT(IsFinalized());
   uint32_t result = Class::Handle(parameterized_class()).id();
   // No need to include the hash of the bound, since the type parameter is fully
   // identified by its class and index.
   result = CombineHashes(result, index());
-  return FinalizeHash(result);
+  result = FinalizeHash(result, kHashBits);
+  SetHash(result);
+  return result;
 }
 
 
@@ -17531,6 +17682,7 @@
   result.set_index(index);
   result.set_name(name);
   result.set_bound(bound);
+  result.SetHash(0);
   result.set_token_pos(token_pos);
   result.StoreNonPointer(&result.raw_ptr()->type_state_,
                          RawTypeParameter::kAllocated);
@@ -17767,13 +17919,15 @@
 }
 
 
-intptr_t BoundedType::Hash() const {
+intptr_t BoundedType::ComputeHash() const {
   uint32_t result = AbstractType::Handle(type()).Hash();
   // No need to include the hash of the bound, since the bound is defined by the
   // type parameter (modulo instantiation state).
   result = CombineHashes(result,
                          TypeParameter::Handle(type_parameter()).Hash());
-  return FinalizeHash(result);
+  result = FinalizeHash(result, kHashBits);
+  SetHash(result);
+  return result;
 }
 
 
@@ -17791,6 +17945,7 @@
   const BoundedType& result = BoundedType::Handle(BoundedType::New());
   result.set_type(type);
   result.set_bound(bound);
+  result.SetHash(0);
   result.set_type_parameter(type_parameter);
   return result.raw();
 }
@@ -19328,10 +19483,9 @@
   // Return a non-zero hash of at most 'bits' bits.
   intptr_t Finalize(int bits) {
     ASSERT(1 <= bits && bits <= (kBitsPerWord - 1));
-    hash_ = FinalizeHash(hash_);
-    hash_ = hash_ & ((static_cast<intptr_t>(1) << bits) - 1);
+    hash_ = FinalizeHash(hash_, bits);
     ASSERT(hash_ <= static_cast<uint32_t>(kMaxInt32));
-    return hash_ == 0 ? 1 : hash_;
+    return hash_;
   }
  private:
   uint32_t hash_;
@@ -19364,7 +19518,7 @@
 intptr_t String::Hash(const String& str, intptr_t begin_index, intptr_t len) {
   StringHasher hasher;
   hasher.Add(str, begin_index, len);
-  return hasher.Finalize(String::kHashBits);
+  return hasher.Finalize(kHashBits);
 }
 
 
@@ -19379,7 +19533,7 @@
     StringHasher hasher;
     hasher.Add(str1, 0, len1);
     hasher.Add(str2, 0, str2.Length());
-    return hasher.Finalize(String::kHashBits);
+    return hasher.Finalize(kHashBits);
   }
 }
 
@@ -19411,7 +19565,7 @@
   while (i < len) {
     hasher.Add(Utf16::Next(characters, &i, len));
   }
-  return hasher.Finalize(String::kHashBits);
+  return hasher.Finalize(kHashBits);
 }
 
 
@@ -21108,7 +21262,7 @@
     value = reinterpret_cast<uword>(At(i));
     hash = CombineHashes(hash, value);
   }
-  return FinalizeHash(hash);
+  return FinalizeHash(hash, kHashBits);
 }
 
 
@@ -21765,7 +21919,7 @@
   for (intptr_t i = 0; i < len; i++) {
     hash = CombineHashes(len, GetUint8(i));
   }
-  return FinalizeHash(hash);
+  return FinalizeHash(hash, kHashBits);
 }
 
 
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index a2f8d21..c517514 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1051,8 +1051,8 @@
   // Caches the canonical type of this class.
   void SetCanonicalType(const Type& type) const;
 
-  static intptr_t canonical_types_offset() {
-    return OFFSET_OF(RawClass, canonical_types_);
+  static intptr_t canonical_type_offset() {
+    return OFFSET_OF(RawClass, canonical_type_);
   }
 
   // The super type of this class, Object type if not explicitly specified.
@@ -1221,9 +1221,6 @@
                              intptr_t index,
                              const Number& constant) const;
 
-  intptr_t FindCanonicalTypeIndex(const AbstractType& needle) const;
-  RawAbstractType* CanonicalTypeFromIndex(intptr_t idx) const;
-
   void RehashConstants(Zone* zone) const;
 
   static intptr_t InstanceSize() {
@@ -1360,7 +1357,8 @@
   template <class FakeObject> static RawClass* New();
 
   // Allocate instance classes.
-  static RawClass* New(const String& name,
+  static RawClass* New(const Library& lib,
+                       const String& name,
                        const Script& script,
                        TokenPosition token_pos);
   static RawClass* NewNativeWrapper(const Library& library,
@@ -1386,6 +1384,8 @@
 
   void DisableCHAOptimizedCode(const Class& subclass);
 
+  void DisableAllCHAOptimizedCode();
+
   // Return the list of code objects that were compiled using CHA of this class.
   // These code objects will be invalidated if new subclasses of this class
   // are finalized.
@@ -1396,8 +1396,16 @@
   void SetTraceAllocation(bool trace_allocation) const;
 
   bool ValidatePostFinalizePatch(const Class& orig_class, Error* error) const;
+  void ReplaceEnum(const Class& old_enum) const;
+  void CopyStaticFieldValues(const Class& old_cls) const;
+  void PatchFieldsAndFunctions() const;
+  void CopyCanonicalConstants(const Class& old_cls) const;
+  void CopyCanonicalType(const Class& old_cls) const;
+  bool CanReload(const Class& replacement) const;
 
  private:
+  template <class FakeObject> static RawClass* NewCommon(intptr_t index);
+
   enum MemberKind {
     kAny = 0,
     kStatic,
@@ -1454,8 +1462,8 @@
 
   void set_constants(const Array& value) const;
 
-  void set_canonical_types(const Object& value) const;
-  RawObject* canonical_types() const;
+  void set_canonical_type(const Type& value) const;
+  RawType* canonical_type() const;
 
   RawArray* invocation_dispatcher_cache() const;
   void set_invocation_dispatcher_cache(const Array& cache) const;
@@ -1500,6 +1508,9 @@
   // Allocate an instance class which has a VM implementation.
   template <class FakeInstance> static RawClass* New(intptr_t id);
 
+  // Helper that calls 'Class::New<Instance>(kIllegalCid)'.
+  static RawClass* NewInstanceClass();
+
   // Check the subtype or 'more specific' relationship.
   bool TypeTest(TypeTestKind test_kind,
                 const TypeArguments& type_arguments,
@@ -1519,15 +1530,6 @@
       TrailPtr bound_trail,
       Heap::Space space);
 
-  // Returns AbstractType::null() if type not found.
-  RawAbstractType* LookupCanonicalType(Zone* zone,
-                                       const AbstractType& type,
-                                       intptr_t* index) const;
-
-  // Returns canonical type. Thread safe.
-  RawAbstractType* LookupOrAddCanonicalType(const AbstractType& type,
-                                            intptr_t start_index) const;
-
   FINAL_HEAP_OBJECT_IMPLEMENTATION(Class, Object);
   friend class AbstractType;
   friend class Instance;
@@ -1573,6 +1575,11 @@
 // A TypeArguments is an array of AbstractType.
 class TypeArguments : public Object {
  public:
+  // We use 30 bits for the hash code so hashes in a snapshot taken on a
+  // 64-bit architecture stay in Smi range when loaded on a 32-bit
+  // architecture.
+  static const intptr_t kHashBits = 30;
+
   intptr_t Length() const;
   RawAbstractType* TypeAt(intptr_t index) const;
   static intptr_t type_at_offset(intptr_t index) {
@@ -1717,8 +1724,9 @@
 
   static intptr_t InstanceSize(intptr_t len) {
     // Ensure that the types() is not adding to the object size, which includes
-    // 2 fields: instantiations_ and length_.
-    ASSERT(sizeof(RawTypeArguments) == (sizeof(RawObject) + (2 * kWordSize)));
+    // 3 fields: instantiations_, length_ and hash_.
+    ASSERT(sizeof(RawTypeArguments) ==
+           (sizeof(RawObject) + (kNumFields * kWordSize)));
     ASSERT(0 <= len && len <= kMaxElements);
     return RoundedAllocationSize(
         sizeof(RawTypeArguments) + (len * kBytesPerElement));
@@ -1729,6 +1737,9 @@
   static RawTypeArguments* New(intptr_t len, Heap::Space space = Heap::kOld);
 
  private:
+  intptr_t ComputeHash() const;
+  void SetHash(intptr_t value) const;
+
   // Check if the subvector of length 'len' starting at 'from_index' of this
   // type argument vector consists solely of DynamicType.
   // If raw_instantiated is true, consider each type parameter to be first
@@ -1757,6 +1768,8 @@
   void set_instantiations(const Array& value) const;
   RawAbstractType* const* TypeAddr(intptr_t index) const;
   void SetLength(intptr_t value) const;
+  // Number of fields in the raw object=3 (instantiations_, length_ and hash_).
+  static const int kNumFields = 3;
 
   FINAL_HEAP_OBJECT_IMPLEMENTATION(TypeArguments, Object);
   friend class AbstractType;
@@ -1827,6 +1840,11 @@
     return raw_ptr()->deopt_id_;
   }
 
+  bool IsImmutable() const;
+
+  void Reset(bool is_static_call) const;
+  void ResetData() const;
+
   // Note: only deopts with reasons before Unknown in this list are recorded in
   // the ICData. All other reasons are used purely for informational messages
   // printed during deoptimization itself.
@@ -1872,6 +1890,10 @@
   bool HasDeoptReason(ICData::DeoptReasonId reason) const;
   void AddDeoptReason(ICData::DeoptReasonId reason) const;
 
+  // The length of the array. This includes all sentinel entries including
+  // the final one.
+  intptr_t Length() const;
+
   intptr_t NumberOfChecks() const;
 
   // Discounts any checks with usage of zero.
@@ -1909,6 +1931,30 @@
     return OFFSET_OF(RawICData, owner_);
   }
 
+  // Replaces entry |index| with the sentinel.
+  void WriteSentinelAt(intptr_t index) const;
+
+  // Clears the count for entry |index|.
+  void ClearCountAt(intptr_t index) const;
+
+  // Clear all entries with the sentinel value (but will preserve initial
+  // smi smi checks).
+  void ClearWithSentinel() const;
+
+  // Clear all entries with the sentinel value and reset the first entry
+  // with the dummy target entry.
+  void ClearAndSetStaticTarget(const Function& func) const;
+
+  // Returns the first index that should be used to for a new entry. Will
+  // grow the array if necessary.
+  RawArray* FindFreeIndex(intptr_t* index) const;
+
+  void DebugDump() const;
+  void ValidateSentinelLocations() const;
+
+  // Returns true if this is a two arg smi operation.
+  bool AddSmiSmiCheckForFastSmiStubs() const;
+
   // Used for unoptimized static calls when no class-ids are checked.
   void AddTarget(const Function& target) const;
 
@@ -1924,6 +1970,9 @@
                         const Function& target,
                         intptr_t count = 1) const;
 
+  // Does entry |index| contain the sentinel value?
+  bool IsSentinelAt(intptr_t index) const;
+
   // Retrieving checks.
 
   void GetCheckAt(intptr_t index,
@@ -2223,6 +2272,11 @@
   // visible formal parameters of the function.
   RawString* UserVisibleFormalParameters() const;
 
+  // Reloading support:
+  void Reparent(const Class& new_cls) const;
+  void ZeroEdgeCounters() const;
+  void FillICDataWithSentinels(const Code& code) const;
+
   RawClass* Owner() const;
   RawClass* origin() const;
   RawScript* script() const;
@@ -2261,6 +2315,13 @@
   // Disables optimized code and switches to unoptimized code.
   void SwitchToUnoptimizedCode() const;
 
+  // Disables optimized code and switches to unoptimized code (or the lazy
+  // compilation stub).
+  void SwitchToLazyCompiledUnoptimizedCode() const;
+
+  // Compiles unoptimized code (if necessary) and attaches it to the function.
+  void EnsureHasCompiledUnoptimizedCode() const;
+
   // Return the most recently compiled and installed code for this function.
   // It is not the only Code object that points to this function.
   RawCode* CurrentCode() const {
@@ -3188,6 +3249,14 @@
   static bool IsSetterName(const String& function_name);
 
  private:
+  static void InitializeNew(const Field& result,
+                            const String& name,
+                            bool is_static,
+                            bool is_final,
+                            bool is_const,
+                            bool is_reflectable,
+                            const Object& owner,
+                            TokenPosition token_pos);
   friend class StoreInstanceFieldInstr;  // Generated code access to bit field.
 
   enum {
@@ -3214,6 +3283,9 @@
   // deoptimization of dependent code is required.
   bool UpdateGuardedCidAndLength(const Object& value) const;
 
+  // Force this field's guard to be dynamic and deoptimize dependent code.
+  void ForceDynamicGuardedCidAndLength() const;
+
   void set_name(const String& value) const;
   void set_is_static(bool is_static) const {
     set_kind_bits(StaticBit::update(is_static, raw_ptr()->kind_bits_));
@@ -3279,7 +3351,7 @@
   RawString* GenerateSource() const;
   RawString* GenerateSource(TokenPosition start,
                             TokenPosition end) const;
-  TokenPosition ComputeSourcePosition(TokenPosition tok_pos) const;
+  intptr_t ComputeSourcePosition(TokenPosition tok_pos) const;
 
   RawString* PrivateKey() const;
 
@@ -3291,7 +3363,7 @@
   }
 
   static RawTokenStream* New(intptr_t length);
-  static RawTokenStream* New(const Scanner::GrowableTokenStream& tokens,
+  static RawTokenStream* New(const String& source,
                              const String& private_key,
                              bool use_shared_tokens);
 
@@ -3377,6 +3449,9 @@
   intptr_t line_offset() const { return raw_ptr()->line_offset_; }
   intptr_t col_offset() const { return raw_ptr()->col_offset_; }
 
+  // The load time in milliseconds since epoch.
+  int64_t load_timestamp() const { return raw_ptr()->load_timestamp_; }
+
   RawTokenStream* tokens() const { return raw_ptr()->tokens_; }
 
   void Tokenize(const String& private_key,
@@ -3417,6 +3492,7 @@
   void set_url(const String& value) const;
   void set_source(const String& value) const;
   void set_kind(RawScript::Kind value) const;
+  void set_load_timestamp(int64_t value) const;
   void set_tokens(const TokenStream& value) const;
 
   static RawScript* New();
@@ -3706,6 +3782,8 @@
   // the library-specific key.
   static const char kPrivateKeySeparator = '@';
 
+  bool CanReload(const Library& replacement) const;
+
  private:
   static const int kInitialImportsCapacity = 4;
   static const int kImportsCapacityIncrement = 8;
@@ -5370,6 +5448,11 @@
 // Subclasses of AbstractType are Type and TypeParameter.
 class AbstractType : public Instance {
  public:
+  // We use 30 bits for the hash code so hashes in a snapshot taken on a
+  // 64-bit architecture stay in Smi range when loaded on a 32-bit
+  // architecture.
+  static const intptr_t kHashBits = 30;
+
   virtual bool IsFinalized() const;
   virtual void SetIsFinalized() const;
   virtual bool IsBeingFinalized() const;
@@ -5382,6 +5465,7 @@
   virtual bool IsResolved() const;
   virtual void SetIsResolved() const;
   virtual bool HasResolvedTypeClass() const;
+  virtual classid_t type_class_id() const;
   virtual RawClass* type_class() const;
   virtual RawUnresolvedClass* unresolved_class() const;
   virtual RawTypeArguments* arguments() const;
@@ -5570,8 +5654,8 @@
 // relate to a 'raw type', as opposed to a 'cooked type' or 'rare type'.
 class Type : public AbstractType {
  public:
-  static intptr_t type_class_offset() {
-    return OFFSET_OF(RawType, type_class_);
+  static intptr_t type_class_id_offset() {
+    return OFFSET_OF(RawType, type_class_id_);
   }
   virtual bool IsFinalized() const {
     return
@@ -5594,8 +5678,10 @@
   }
   virtual void SetIsResolved() const;
   virtual bool HasResolvedTypeClass() const;  // Own type class resolved.
+  virtual classid_t type_class_id() const;
   virtual RawClass* type_class() const;
-  void set_type_class(const Object& value) const;
+  void set_type_class(const Class& value) const;
+  void set_unresolved_class(const Object& value) const;
   virtual RawUnresolvedClass* unresolved_class() const;
   virtual RawTypeArguments* arguments() const { return raw_ptr()->arguments_; }
   virtual void set_arguments(const TypeArguments& value) const;
@@ -5685,6 +5771,9 @@
                       Heap::Space space = Heap::kOld);
 
  private:
+  intptr_t ComputeHash() const;
+  void SetHash(intptr_t value) const;
+
   void set_token_pos(TokenPosition token_pos) const;
   void set_type_state(int8_t state) const;
 
@@ -5786,9 +5875,8 @@
   virtual bool IsMalformedOrMalbounded() const { return false; }
   virtual bool IsResolved() const { return true; }
   virtual bool HasResolvedTypeClass() const { return false; }
-  RawClass* parameterized_class() const {
-    return raw_ptr()->parameterized_class_;
-  }
+  classid_t parameterized_class_id() const;
+  RawClass* parameterized_class() const;
   RawString* name() const { return raw_ptr()->name_; }
   intptr_t index() const { return raw_ptr()->index_; }
   void set_index(intptr_t value) const;
@@ -5836,6 +5924,9 @@
                                TokenPosition token_pos);
 
  private:
+  intptr_t ComputeHash() const;
+  void SetHash(intptr_t value) const;
+
   void set_parameterized_class(const Class& value) const;
   void set_name(const String& value) const;
   void set_token_pos(TokenPosition token_pos) const;
@@ -5921,6 +6012,9 @@
                              const TypeParameter& type_parameter);
 
  private:
+  intptr_t ComputeHash() const;
+  void SetHash(intptr_t value) const;
+
   void set_type(const AbstractType& value) const;
   void set_bound(const AbstractType& value) const;
   void set_type_parameter(const TypeParameter& value) const;
@@ -6335,8 +6429,9 @@
 // String may not be '\0' terminated.
 class String : public Instance {
  public:
-  // We use 30 bits for the hash code so that we consistently use a
-  // 32bit Smi representation for the hash code on all architectures.
+  // We use 30 bits for the hash code so hashes in a snapshot taken on a
+  // 64-bit architecture stay in Smi range when loaded on a 32-bit
+  // architecture.
   static const intptr_t kHashBits = 30;
 
   static const intptr_t kOneByteChar = 1;
@@ -7115,6 +7210,11 @@
 
 class Array : public Instance {
  public:
+  // We use 30 bits for the hash code so hashes in a snapshot taken on a
+  // 64-bit architecture stay in Smi range when loaded on a 32-bit
+  // architecture.
+  static const intptr_t kHashBits = 30;
+
   intptr_t Length() const {
     ASSERT(!IsNull());
     return Smi::Value(raw_ptr()->length_);
@@ -7482,6 +7582,11 @@
 
 class TypedData : public Instance {
  public:
+  // We use 30 bits for the hash code so hashes in a snapshot taken on a
+  // 64-bit architecture stay in Smi range when loaded on a 32-bit
+  // architecture.
+  static const intptr_t kHashBits = 30;
+
   intptr_t Length() const {
     ASSERT(!IsNull());
     return Smi::Value(raw_ptr()->length_);
@@ -8528,6 +8633,72 @@
   return array.At((index * kEntryLength) + kTargetFunctionIndex);
 }
 
+
+inline intptr_t Type::Hash() const {
+  intptr_t result = Smi::Value(raw_ptr()->hash_);
+  if (result != 0) {
+    return result;
+  }
+  return ComputeHash();
+}
+
+
+inline void Type::SetHash(intptr_t value) const {
+  // This is only safe because we create a new Smi, which does not cause
+  // heap allocation.
+  StoreSmi(&raw_ptr()->hash_, Smi::New(value));
+}
+
+
+inline intptr_t TypeParameter::Hash() const {
+  ASSERT(IsFinalized());
+  intptr_t result = Smi::Value(raw_ptr()->hash_);
+  if (result != 0) {
+    return result;
+  }
+  return ComputeHash();
+}
+
+
+inline void TypeParameter::SetHash(intptr_t value) const {
+  // This is only safe because we create a new Smi, which does not cause
+  // heap allocation.
+  StoreSmi(&raw_ptr()->hash_, Smi::New(value));
+}
+
+
+inline intptr_t BoundedType::Hash() const {
+  intptr_t result = Smi::Value(raw_ptr()->hash_);
+  if (result != 0) {
+    return result;
+  }
+  return ComputeHash();
+}
+
+
+inline void BoundedType::SetHash(intptr_t value) const {
+  // This is only safe because we create a new Smi, which does not cause
+  // heap allocation.
+  StoreSmi(&raw_ptr()->hash_, Smi::New(value));
+}
+
+
+inline intptr_t TypeArguments::Hash() const {
+  if (IsNull()) return 0;
+  intptr_t result = Smi::Value(raw_ptr()->hash_);
+  if (result != 0) {
+    return result;
+  }
+  return ComputeHash();
+}
+
+
+inline void TypeArguments::SetHash(intptr_t value) const {
+  // This is only safe because we create a new Smi, which does not cause
+  // heap allocation.
+  StoreSmi(&raw_ptr()->hash_, Smi::New(value));
+}
+
 }  // namespace dart
 
 #endif  // VM_OBJECT_H_
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
new file mode 100644
index 0000000..405854d
--- /dev/null
+++ b/runtime/vm/object_reload.cc
@@ -0,0 +1,548 @@
+// Copyright (c) 2016, 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.
+
+#include "vm/object.h"
+
+#include "vm/isolate_reload.h"
+#include "vm/log.h"
+#include "vm/resolver.h"
+#include "vm/symbols.h"
+
+namespace dart {
+
+#ifndef PRODUCT
+
+DECLARE_FLAG(bool, trace_reload);
+DECLARE_FLAG(bool, two_args_smi_icd);
+
+#define IRC (Isolate::Current()->reload_context())
+
+class ObjectReloadUtils : public AllStatic {
+  static void DumpLibraryDictionary(const Library& lib) {
+    DictionaryIterator it(lib);
+    Object& entry = Object::Handle();
+    String& name = String::Handle();
+    TIR_Print("Dumping dictionary for %s\n", lib.ToCString());
+    while (it.HasNext()) {
+      entry = it.GetNext();
+      name = entry.DictionaryName();
+      TIR_Print("%s -> %s\n", name.ToCString(), entry.ToCString());
+    }
+  }
+};
+
+
+void Function::Reparent(const Class& new_cls) const {
+  set_owner(new_cls);
+}
+
+
+void Function::ZeroEdgeCounters() const {
+  const Array& saved_ic_data = Array::Handle(ic_data_array());
+  if (saved_ic_data.IsNull()) {
+    return;
+  }
+  const intptr_t saved_ic_datalength = saved_ic_data.Length();
+  ASSERT(saved_ic_datalength > 0);
+  const Array& edge_counters_array =
+      Array::Handle(Array::RawCast(saved_ic_data.At(0)));
+  ASSERT(!edge_counters_array.IsNull());
+  // Fill edge counters array with zeros.
+  const Smi& zero = Smi::Handle(Smi::New(0));
+  for (intptr_t i = 0; i < edge_counters_array.Length(); i++) {
+    edge_counters_array.SetAt(i, zero);
+  }
+}
+
+
+static void ClearICs(const Function& function, const Code& code) {
+  if (function.ic_data_array() == Array::null()) {
+    return;  // Already reset in an earlier round.
+  }
+
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+
+  ZoneGrowableArray<const ICData*>* ic_data_array =
+      new(zone) ZoneGrowableArray<const ICData*>();
+  function.RestoreICDataMap(ic_data_array, false /* clone ic-data */);
+  if (ic_data_array->length() == 0) {
+    return;
+  }
+  const PcDescriptors& descriptors =
+      PcDescriptors::Handle(code.pc_descriptors());
+  PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kIcCall |
+                                            RawPcDescriptors::kUnoptStaticCall);
+  while (iter.MoveNext()) {
+    const ICData* ic_data = (*ic_data_array)[iter.DeoptId()];
+    if (ic_data == NULL) {
+      continue;
+    }
+    bool is_static_call = iter.Kind() == RawPcDescriptors::kUnoptStaticCall;
+    ic_data->Reset(is_static_call);
+  }
+}
+
+
+void Function::FillICDataWithSentinels(const Code& code) const {
+  ASSERT(code.raw() == CurrentCode());
+  ClearICs(*this, code);
+}
+
+
+void Class::CopyStaticFieldValues(const Class& old_cls) const {
+  // We only update values for non-enum classes.
+  const bool update_values = !is_enum_class();
+
+  IsolateReloadContext* reload_context = Isolate::Current()->reload_context();
+  ASSERT(reload_context != NULL);
+
+  const Array& old_field_list = Array::Handle(old_cls.fields());
+  Field& old_field = Field::Handle();
+  String& old_name = String::Handle();
+
+  const Array& field_list = Array::Handle(fields());
+  Field& field = Field::Handle();
+  String& name = String::Handle();
+
+  Instance& value = Instance::Handle();
+  for (intptr_t i = 0; i < field_list.Length(); i++) {
+    field = Field::RawCast(field_list.At(i));
+    name = field.name();
+    if (field.is_static()) {
+      // Find the corresponding old field, if it exists, and migrate
+      // over the field value.
+      for (intptr_t j = 0; j < old_field_list.Length(); j++) {
+        old_field = Field::RawCast(old_field_list.At(j));
+        old_name = old_field.name();
+        if (name.Equals(old_name)) {
+          if (update_values) {
+            value = old_field.StaticValue();
+            field.SetStaticValue(value);
+          }
+          reload_context->AddStaticFieldMapping(old_field, field);
+        }
+      }
+    }
+  }
+}
+
+
+void Class::CopyCanonicalConstants(const Class& old_cls) const {
+  if (is_enum_class()) {
+    return;
+  }
+#if defined(DEBUG)
+  {
+    // Class has no canonical constants allocated.
+    const Array& my_constants = Array::Handle(constants());
+    ASSERT(my_constants.Length() == 0);
+  }
+#endif  // defined(DEBUG).
+  // Copy old constants into new class.
+  const Array& old_constants = Array::Handle(old_cls.constants());
+  if (old_constants.IsNull() || old_constants.Length() == 0) {
+    return;
+  }
+  TIR_Print("Copied %" Pd " canonical constants for class `%s`\n",
+            old_constants.Length(),
+            ToCString());
+  set_constants(old_constants);
+}
+
+
+void Class::CopyCanonicalType(const Class& old_cls) const {
+  const Type& old_canonical_type = Type::Handle(old_cls.canonical_type());
+  if (old_canonical_type.IsNull()) {
+    return;
+  }
+  set_canonical_type(old_canonical_type);
+}
+
+
+static intptr_t IndexOfEnum(const Array& enum_names, const String& name) {
+  ASSERT(!enum_names.IsNull());
+  ASSERT(!name.IsNull());
+  String& enum_name = String::Handle();
+  for (intptr_t i = 0; i < enum_names.Length(); i++) {
+    enum_name = String::RawCast(enum_names.At(i));
+    ASSERT(!enum_name.IsNull());
+    if (enum_name.Equals(name)) {
+      return i;
+    }
+  }
+
+  return -1;
+}
+
+
+static void UpdateEnumIndex(const Instance& enum_value,
+                            const Field& enum_index_field,
+                            const intptr_t index) {
+  enum_value.SetField(enum_index_field, Smi::Handle(Smi::New(index)));
+}
+
+
+// TODO(johnmccutchan): The code in the class finalizer canonicalizes all
+// instances and the values array. We probably should do the same thing.
+void Class::ReplaceEnum(const Class& old_enum) const {
+  // We only do this for finalized enum classes.
+  ASSERT(is_enum_class());
+  ASSERT(old_enum.is_enum_class());
+  ASSERT(is_finalized());
+  ASSERT(old_enum.is_finalized());
+
+  Thread* thread = Thread::Current();
+  IsolateReloadContext* reload_context = Isolate::Current()->reload_context();
+  ASSERT(reload_context != NULL);
+
+  TIR_Print("ReplaceEnum `%s` (%" Pd " and %" Pd ")\n",
+            ToCString(), id(), old_enum.id());
+
+  // Grab '_enum_names' from |old_enum|.
+  const Field& old_enum_names_field = Field::Handle(
+      old_enum.LookupStaticFieldAllowPrivate(Symbols::_EnumNames()));
+  ASSERT(!old_enum_names_field.IsNull());
+  const Array& old_enum_names =
+      Array::Handle(Array::RawCast(old_enum_names_field.StaticValue()));
+  ASSERT(!old_enum_names.IsNull());
+
+  // Grab 'values' from |old_enum|.
+  const Field& old_enum_values_field = Field::Handle(
+      old_enum.LookupStaticField(Symbols::Values()));
+  ASSERT(!old_enum_values_field.IsNull());
+  const Array& old_enum_values =
+      Array::Handle(Array::RawCast(old_enum_values_field.StaticValue()));
+  ASSERT(!old_enum_values.IsNull());
+
+  // Grab _enum_names from |this|.
+  const Field& enum_names_field = Field::Handle(
+      LookupStaticFieldAllowPrivate(Symbols::_EnumNames()));
+  ASSERT(!enum_names_field.IsNull());
+  Array& enum_names =
+      Array::Handle(Array::RawCast(enum_names_field.StaticValue()));
+  ASSERT(!enum_names.IsNull());
+
+  // Grab values from |this|.
+  const Field& enum_values_field = Field::Handle(
+      LookupStaticField(Symbols::Values()));
+  ASSERT(!enum_values_field.IsNull());
+  Array& enum_values =
+      Array::Handle(Array::RawCast(enum_values_field.StaticValue()));
+  ASSERT(!enum_values.IsNull());
+
+  // Grab the |index| field.
+  const Field& index_field =
+      Field::Handle(old_enum.LookupInstanceField(Symbols::Index()));
+  ASSERT(!index_field.IsNull());
+
+  // Build list of enum from |old_enum| that aren't present in |this|.
+  // This array holds pairs: (name, value).
+  const GrowableObjectArray& to_add =
+      GrowableObjectArray::Handle(GrowableObjectArray::New(Heap::kOld));
+  const String& enum_class_name = String::Handle(UserVisibleName());
+  String& enum_name = String::Handle();
+  String& enum_field_name = String::Handle();
+  Object& enum_value = Object::Handle();
+  Field& enum_field = Field::Handle();
+
+  TIR_Print("New version of enum has %" Pd " elements\n",
+            enum_values.Length());
+  TIR_Print("Old version of enum had %" Pd " elements\n",
+            old_enum_values.Length());
+
+  for (intptr_t i = 0; i < old_enum_names.Length(); i++) {
+    enum_name = String::RawCast(old_enum_names.At(i));
+    const intptr_t index_in_new_cls = IndexOfEnum(enum_names, enum_name);
+    if (index_in_new_cls < 0) {
+      // Doesn't exist in new enum, add.
+      TIR_Print("Adding enum value `%s` to %s\n",
+                enum_name.ToCString(),
+                this->ToCString());
+      enum_value = old_enum_values.At(i);
+      ASSERT(!enum_value.IsNull());
+      to_add.Add(enum_name);
+      to_add.Add(enum_value);
+    } else {
+      // Exists in both the new and the old.
+      TIR_Print("Moving enum value `%s` to %" Pd "\n",
+                enum_name.ToCString(),
+                index_in_new_cls);
+      // Grab old value.
+      enum_value = old_enum_values.At(i);
+      // Update index to the be new index.
+      UpdateEnumIndex(Instance::Cast(enum_value),
+                      index_field,
+                      index_in_new_cls);
+      // Chop off the 'EnumClass.'
+      enum_field_name = String::SubString(enum_name,
+                                          enum_class_name.Length() + 1);
+      ASSERT(!enum_field_name.IsNull());
+      // Grab the static field.
+      enum_field = LookupStaticField(enum_field_name);
+      ASSERT(!enum_field.IsNull());
+      // Use old value with updated index.
+      enum_field.SetStaticValue(Instance::Cast(enum_value), true);
+      enum_values.SetAt(index_in_new_cls, enum_value);
+      enum_names.SetAt(index_in_new_cls, enum_name);
+    }
+  }
+
+  if (to_add.Length() == 0) {
+    // Nothing to do.
+    TIR_Print("Found no missing enums in %s\n", ToCString());
+    return;
+  }
+
+  // Grow the values and enum_names arrays.
+  const intptr_t offset = enum_names.Length();
+  const intptr_t num_to_add = to_add.Length() / 2;
+  ASSERT(offset == enum_values.Length());
+  enum_names = Array::Grow(enum_names,
+                           enum_names.Length() + num_to_add,
+                           Heap::kOld);
+  enum_values = Array::Grow(enum_values,
+                            enum_values.Length() + num_to_add,
+                            Heap::kOld);
+
+  // Install new names and values into the grown arrays. Also, update
+  // the index of the new enum values and add static fields for the new
+  // enum values.
+  Field& enum_value_field = Field::Handle();
+  for (intptr_t i = 0; i < num_to_add; i++) {
+    const intptr_t target_index = offset + i;
+    enum_name = String::RawCast(to_add.At(i * 2));
+    enum_value = to_add.At(i * 2 + 1);
+
+    // Update the enum value's index into the new arrays.
+    TIR_Print("Updating index of %s in %s to %" Pd "\n",
+              enum_name.ToCString(),
+              ToCString(),
+              target_index);
+    UpdateEnumIndex(Instance::Cast(enum_value), index_field, target_index);
+
+    enum_names.SetAt(target_index, enum_name);
+    enum_values.SetAt(target_index, enum_value);
+
+    // Install new static field into class.
+    // Chop off the 'EnumClass.'
+    enum_field_name = String::SubString(enum_name,
+                                        enum_class_name.Length() + 1);
+    ASSERT(!enum_field_name.IsNull());
+    enum_field_name = Symbols::New(thread, enum_field_name);
+    enum_value_field = Field::New(enum_field_name,
+                                  /* is_static = */ true,
+                                  /* is_final = */ true,
+                                  /* is_const = */ true,
+                                  /* is_reflectable = */ true,
+                                  *this,
+                                  Object::dynamic_type(),
+                                  token_pos());
+    enum_value_field.set_has_initializer(false);
+    enum_value_field.SetStaticValue(Instance::Cast(enum_value), true);
+    enum_value_field.RecordStore(Instance::Cast(enum_value));
+    AddField(enum_value_field);
+  }
+
+  // Replace the arrays stored in the static fields.
+  enum_names_field.SetStaticValue(enum_names, true);
+  enum_values_field.SetStaticValue(enum_values, true);
+}
+
+
+void Class::PatchFieldsAndFunctions() const {
+  // Move all old functions and fields to a patch class so that they
+  // still refer to their original script.
+  const PatchClass& patch =
+      PatchClass::Handle(PatchClass::New(*this, Script::Handle(script())));
+  ASSERT(!patch.IsNull());
+
+  const Array& funcs = Array::Handle(functions());
+  Function& func = Function::Handle();
+  Object& owner = Object::Handle();
+  for (intptr_t i = 0; i < funcs.Length(); i++) {
+    func = Function::RawCast(funcs.At(i));
+    if ((func.token_pos() == TokenPosition::kMinSource) ||
+        func.IsClosureFunction()) {
+      // Eval functions do not need to have their script updated.
+      //
+      // Closure functions refer to the parent's script which we can
+      // rely on being updated for us, if necessary.
+      continue;
+    }
+
+    // If the source for this function is already patched, leave it alone.
+    owner = func.RawOwner();
+    ASSERT(!owner.IsNull());
+    if (!owner.IsPatchClass()) {
+      ASSERT(owner.raw() == this->raw());
+      func.set_owner(patch);
+    }
+  }
+
+  const Array& field_list = Array::Handle(fields());
+  Field& field = Field::Handle();
+  for (intptr_t i = 0; i < field_list.Length(); i++) {
+    field = Field::RawCast(field_list.At(i));
+    owner = field.RawOwner();
+    ASSERT(!owner.IsNull());
+    if (!owner.IsPatchClass()) {
+      ASSERT(owner.raw() == this->raw());
+      field.set_owner(patch);
+    }
+    field.ForceDynamicGuardedCidAndLength();
+  }
+}
+
+
+bool Class::CanReload(const Class& replacement) const {
+  ASSERT(IsolateReloadContext::IsSameClass(*this, replacement));
+
+  if (is_enum_class() && !replacement.is_enum_class()) {
+    IRC->ReportError(String::Handle(String::NewFormatted(
+        "Enum class cannot be redefined to be a non-enum class: %s",
+        ToCString())));
+    return false;
+  }
+
+  if (!is_enum_class() && replacement.is_enum_class()) {
+    IRC->ReportError(String::Handle(String::NewFormatted(
+        "Class cannot be redefined to be a enum class: %s",
+        ToCString())));
+    return false;
+  }
+
+  if (is_finalized()) {
+    const Error& error =
+        Error::Handle(replacement.EnsureIsFinalized(Thread::Current()));
+    if (!error.IsNull()) {
+      IRC->ReportError(error);
+      return false;
+    }
+    TIR_Print("Finalized replacement class for %s\n", ToCString());
+  }
+
+  if (is_finalized()) {
+    // Get the field maps for both classes. These field maps walk the class
+    // hierarchy.
+    const Array& fields =
+        Array::Handle(OffsetToFieldMap());
+    const Array& replacement_fields =
+        Array::Handle(replacement.OffsetToFieldMap());
+
+    // Check that we have the same number of fields.
+    if (fields.Length() != replacement_fields.Length()) {
+      IRC->ReportError(String::Handle(String::NewFormatted(
+          "Number of instance fields changed in %s", ToCString())));
+      return false;
+    }
+
+    if (NumTypeArguments() != replacement.NumTypeArguments()) {
+      IRC->ReportError(String::Handle(String::NewFormatted(
+          "Number of type arguments changed in %s", ToCString())));
+      return false;
+    }
+
+    // Verify that field names / offsets match across the entire hierarchy.
+    Field& field = Field::Handle();
+    String& field_name = String::Handle();
+    Field& replacement_field = Field::Handle();
+    String& replacement_field_name = String::Handle();
+    for (intptr_t i = 0; i < fields.Length(); i++) {
+      if (fields.At(i) == Field::null()) {
+        ASSERT(replacement_fields.At(i) == Field::null());
+        continue;
+      }
+      field = Field::RawCast(fields.At(i));
+      replacement_field = Field::RawCast(replacement_fields.At(i));
+      field_name = field.name();
+      replacement_field_name = replacement_field.name();
+      if (!field_name.Equals(replacement_field_name)) {
+        IRC->ReportError(String::Handle(String::NewFormatted(
+            "Name of instance field changed ('%s' vs '%s') in '%s'",
+            field_name.ToCString(),
+            replacement_field_name.ToCString(),
+            ToCString())));
+        return false;
+      }
+    }
+  } else if (is_prefinalized()) {
+    if (!replacement.is_prefinalized()) {
+      IRC->ReportError(String::Handle(String::NewFormatted(
+          "Original class ('%s') is prefinalized and replacement class ('%s')",
+          ToCString(), replacement.ToCString())));
+      return false;
+    }
+    if (instance_size() != replacement.instance_size()) {
+     IRC->ReportError(String::Handle(String::NewFormatted(
+         "Instance size mismatch between '%s' (%" Pd ") and replacement "
+         "'%s' ( %" Pd ")",
+         ToCString(),
+         instance_size(),
+         replacement.ToCString(),
+         replacement.instance_size())));
+     return false;
+    }
+  }
+
+  // native field count check.
+  if (num_native_fields() != replacement.num_native_fields()) {
+    IRC->ReportError(String::Handle(String::NewFormatted(
+        "Number of native fields changed in %s", ToCString())));
+    return false;
+  }
+
+  // TODO(johnmccutchan) type parameter count check.
+
+  TIR_Print("Class `%s` can be reloaded (%" Pd " and %" Pd ")\n",
+            ToCString(),
+            id(),
+            replacement.id());
+  return true;
+}
+
+
+bool Library::CanReload(const Library& replacement) const {
+  return true;
+}
+
+
+static const Function* static_call_target = NULL;
+
+void ICData::Reset(bool is_static_call) const {
+  // TODO(johnmccutchan): ICData should know whether or not it's for a
+  // static call.
+  if (is_static_call) {
+    const Function& old_target = Function::Handle(GetTargetAt(0));
+    if (old_target.IsNull()) {
+      FATAL("old_target is NULL.\n");
+    }
+    static_call_target = &old_target;
+    if (!old_target.is_static()) {
+      // TODO(johnmccutchan): Improve this.
+      TIR_Print("Cannot rebind super-call to %s from %s\n",
+                old_target.ToCString(),
+                Object::Handle(Owner()).ToCString());
+      return;
+    }
+    const String& selector = String::Handle(old_target.name());
+    const Class& cls = Class::Handle(old_target.Owner());
+    const Function& new_target =
+        Function::Handle(cls.LookupStaticFunction(selector));
+    if (new_target.IsNull()) {
+      // TODO(johnmccutchan): Improve this.
+      TIR_Print("Cannot rebind static call to %s from %s\n",
+                old_target.ToCString(),
+                Object::Handle(Owner()).ToCString());
+      return;
+    }
+    ClearAndSetStaticTarget(new_target);
+  } else {
+    ClearWithSentinel();
+  }
+}
+
+#endif  // !PRODUCT
+
+}   // namespace dart.
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index 41290fb..7eab800 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -8,6 +8,7 @@
 #include "vm/object_store.h"
 #include "vm/stub_code.h"
 #include "vm/symbols.h"
+#include "vm/type_table.h"
 
 namespace dart {
 
@@ -187,9 +188,15 @@
   // The index in the canonical_type_arguments table cannot be used as part of
   // the object id (as in typearguments/id), because the indices are not
   // preserved when the table grows and the entries get rehashed. Use the ring.
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  Isolate* isolate = thread->isolate();
   ObjectStore* object_store = isolate->object_store();
-  const Array& table = Array::Handle(object_store->canonical_type_arguments());
+  CanonicalTypeArgumentsSet typeargs_table(
+      zone, object_store->canonical_type_arguments());
+  const Array& table =
+      Array::Handle(HashTables::ToArray(typeargs_table, false));
+  typeargs_table.Release();
   ASSERT(table.Length() > 0);
   AddCommonObjectProperties(&jsobj, "TypeArguments", ref);
   jsobj.AddServiceId(*this);
@@ -430,18 +437,19 @@
   const String& encoded_uri = String::Handle(String::EncodeIRI(uri));
   ASSERT(!encoded_uri.IsNull());
   const Library& lib = Library::Handle(FindLibrary());
-  if (kind() == RawScript::kEvaluateTag) {
+  if (lib.IsNull()) {
     jsobj.AddServiceId(*this);
   } else {
-    ASSERT(!lib.IsNull());
-    jsobj.AddFixedServiceId("libraries/%" Pd "/scripts/%s",
-        lib.index(), encoded_uri.ToCString());
+    jsobj.AddFixedServiceId("libraries/%" Pd "/scripts/%s/%" Px64 "",
+                            lib.index(), encoded_uri.ToCString(),
+                            load_timestamp());
   }
   jsobj.AddPropertyStr("uri", uri);
   jsobj.AddProperty("_kind", GetKindAsCString());
   if (ref) {
     return;
   }
+  jsobj.AddPropertyTimeMillis("_loadTime", load_timestamp());
   if (!lib.IsNull()) {
     jsobj.AddProperty("library", lib);
   }
@@ -1129,11 +1137,13 @@
   jsobj.AddProperty("kind", "Type");
   if (IsCanonical()) {
     const Class& type_cls = Class::Handle(type_class());
-    intptr_t id = type_cls.FindCanonicalTypeIndex(*this);
-    ASSERT(id >= 0);
-    intptr_t cid = type_cls.id();
-    jsobj.AddFixedServiceId("classes/%" Pd "/types/%" Pd "", cid, id);
-    jsobj.AddProperty("typeClass", type_cls);
+    if (type_cls.CanonicalType() == raw()) {
+      intptr_t cid = type_cls.id();
+      jsobj.AddFixedServiceId("classes/%" Pd "/types/%d", cid, 0);
+      jsobj.AddProperty("typeClass", type_cls);
+    } else {
+      jsobj.AddServiceId(*this);
+    }
   } else {
     jsobj.AddServiceId(*this);
   }
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 95810d2..9affdcb 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -56,6 +56,7 @@
     error_class_(Class::null()),
     weak_property_class_(Class::null()),
     symbol_table_(Array::null()),
+    canonical_types_(Array::null()),
     canonical_type_arguments_(Array::null()),
     async_library_(Library::null()),
     builtin_library_(Library::null()),
@@ -184,6 +185,10 @@
 
 
 void ObjectStore::InitKnownObjects() {
+#ifdef DART_PRECOMPILED_RUNTIME
+  // These objects are only needed for code generation.
+  return;
+#else
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   Isolate* isolate = thread->isolate();
@@ -205,6 +210,7 @@
   const Library& internal_lib = Library::Handle(internal_library());
   cls = internal_lib.LookupClass(Symbols::Symbol());
   set_symbol_class(cls);
+#endif
 }
 
 }  // namespace dart
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index eb868fb..56ee2b0 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -247,6 +247,13 @@
   RawArray* symbol_table() const { return symbol_table_; }
   void set_symbol_table(const Array& value) { symbol_table_ = value.raw(); }
 
+  RawArray* canonical_types() const {
+    return canonical_types_;
+  }
+  void set_canonical_types(const Array& value) {
+    canonical_types_ = value.raw();
+  }
+
   RawArray* canonical_type_arguments() const {
     return canonical_type_arguments_;
   }
@@ -536,6 +543,7 @@
   RawClass* error_class_;
   RawClass* weak_property_class_;
   RawArray* symbol_table_;
+  RawArray* canonical_types_;
   RawArray* canonical_type_arguments_;
   RawLibrary* async_library_;
   RawLibrary* builtin_library_;
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 7d9be08..9ad5f70 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -24,8 +24,8 @@
 
 static RawClass* CreateDummyClass(const String& class_name,
                                   const Script& script) {
-  const Class& cls = Class::Handle(
-      Class::New(class_name, script, TokenPosition::kNoSource));
+  const Class& cls = Class::Handle(Class::New(
+      Library::Handle(), class_name, script, TokenPosition::kNoSource));
   cls.set_is_synthesized_class();  // Dummy class for testing.
   return cls.raw();
 }
@@ -165,14 +165,9 @@
   Zone* zone = Thread::Current()->zone();
   String& source = String::Handle(zone, String::New("= ( 9 , ."));
   String& private_key = String::Handle(zone, String::New(""));
-  Scanner scanner(source, private_key);
-  const Scanner::GrowableTokenStream& ts = scanner.GetStream();
-  EXPECT_EQ(6, ts.length());
-  EXPECT_EQ(Token::kLPAREN, ts[1].kind);
   const TokenStream& token_stream = TokenStream::Handle(
-      zone, TokenStream::New(ts, private_key, false));
+      zone, TokenStream::New(source, private_key, false));
   TokenStream::Iterator iterator(zone, token_stream, TokenPosition::kMinSource);
-  // EXPECT_EQ(6, token_stream.Length());
   iterator.Advance();  // Advance to '(' token.
   EXPECT_EQ(Token::kLPAREN, iterator.CurrentTokenKind());
   iterator.Advance();
@@ -4084,10 +4079,8 @@
   EXPECT(func_b.CanBeInlined());
 
   // After setting a breakpoint in a function A.b, it is no longer inlineable.
-  Breakpoint* bpt =
-      Isolate::Current()->debugger()->SetBreakpointAtLine(name,
-                                                          kBreakpointLine);
-  ASSERT(bpt != NULL);
+  result = Dart_SetBreakpoint(NewString(TestCase::url()), kBreakpointLine);
+  EXPECT_VALID(result);
   EXPECT(!func_b.CanBeInlined());
 }
 
diff --git a/runtime/vm/os.h b/runtime/vm/os.h
index 9064322..ff61aaa 100644
--- a/runtime/vm/os.h
+++ b/runtime/vm/os.h
@@ -110,6 +110,7 @@
 
   // Not all platform support strndup.
   static char* StrNDup(const char* s, intptr_t n);
+  static intptr_t StrNLen(const char* s, intptr_t n);
 
   // Print formatted output to stdout/stderr for debugging.
   static void Print(const char* format, ...) PRINTF_ATTRIBUTE(1, 2);
diff --git a/runtime/vm/os_android.cc b/runtime/vm/os_android.cc
index 1c22b7c..89cfbe9 100644
--- a/runtime/vm/os_android.cc
+++ b/runtime/vm/os_android.cc
@@ -220,12 +220,12 @@
 
 
 intptr_t OS::PreferredCodeAlignment() {
-#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) || \
-    defined(TARGET_ARCH_ARM64)
-  const int kMinimumAlignment = 16;
-#elif defined(TARGET_ARCH_ARM)
-  const int kMinimumAlignment = 16;
-#elif defined(TARGET_ARCH_DBC)
+#if defined(TARGET_ARCH_IA32) ||                                               \
+    defined(TARGET_ARCH_X64) ||                                                \
+    defined(TARGET_ARCH_ARM64) ||                                              \
+    defined(TARGET_ARCH_DBC)
+  const int kMinimumAlignment = 32;
+#elif defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
   const int kMinimumAlignment = 16;
 #else
 #error Unsupported architecture.
@@ -288,6 +288,11 @@
 }
 
 
+intptr_t OS::StrNLen(const char* s, intptr_t n) {
+  return strnlen(s, n);
+}
+
+
 uint16_t HostToBigEndian16(uint16_t value) {
   return htobe16(value);
 }
diff --git a/runtime/vm/os_linux.cc b/runtime/vm/os_linux.cc
index 7d7c7e0..df05e17 100644
--- a/runtime/vm/os_linux.cc
+++ b/runtime/vm/os_linux.cc
@@ -300,6 +300,11 @@
 }
 
 
+intptr_t OS::StrNLen(const char* s, intptr_t n) {
+  return strnlen(s, n);
+}
+
+
 void OS::Print(const char* format, ...) {
   va_list args;
   va_start(args, format);
diff --git a/runtime/vm/os_macos.cc b/runtime/vm/os_macos.cc
index 6d2d02a..0ed04ec 100644
--- a/runtime/vm/os_macos.cc
+++ b/runtime/vm/os_macos.cc
@@ -109,6 +109,10 @@
   origin += boottime.tv_usec;
   return now - origin;
 #else
+  if (timebase_info.denom == 0) {
+    kern_return_t kr = mach_timebase_info(&timebase_info);
+    ASSERT(KERN_SUCCESS == kr);
+  }
   ASSERT(timebase_info.denom != 0);
   // timebase_info converts absolute time tick units into nanoseconds.
   int64_t result = mach_absolute_time();
@@ -204,8 +208,24 @@
 
 
 intptr_t OS::PreferredCodeAlignment() {
-  ASSERT(32 <= OS::kMaxPreferredCodeAlignment);
-  return 32;
+#if defined(TARGET_ARCH_IA32) ||                                               \
+    defined(TARGET_ARCH_X64) ||                                                \
+    defined(TARGET_ARCH_ARM64) ||                                              \
+    defined(TARGET_ARCH_DBC)
+  const int kMinimumAlignment = 32;
+#elif defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
+  const int kMinimumAlignment = 16;
+#else
+#error Unsupported architecture.
+#endif
+  intptr_t alignment = kMinimumAlignment;
+  // TODO(5411554): Allow overriding default code alignment for
+  // testing purposes.
+  // Flags::DebugIsInt("codealign", &alignment);
+  ASSERT(Utils::IsPowerOfTwo(alignment));
+  ASSERT(alignment >= kMinimumAlignment);
+  ASSERT(alignment <= OS::kMaxPreferredCodeAlignment);
+  return alignment;
 }
 
 
@@ -279,6 +299,23 @@
 }
 
 
+intptr_t OS::StrNLen(const char* s, intptr_t n) {
+  // strnlen has only been added to Mac OS X in 10.7. We are supplying
+  // our own copy here if needed.
+#if !defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) || \
+    __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ <= 1060
+  intptr_t len = 0;
+  while ((len <= n) && (*s != '\0')) {
+    s++;
+    len++;
+  }
+  return len;
+#else  // !defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) || ...
+  return strnlen(s, n);
+#endif  // !defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) || ...
+}
+
+
 void OS::Print(const char* format, ...) {
 #if TARGET_OS_IOS
   va_list args;
@@ -396,8 +433,6 @@
   static bool init_once_called = false;
   ASSERT(init_once_called == false);
   init_once_called = true;
-  kern_return_t kr = mach_timebase_info(&timebase_info);
-  ASSERT(KERN_SUCCESS == kr);
 }
 
 
diff --git a/runtime/vm/os_thread.cc b/runtime/vm/os_thread.cc
index 947b7f6..75a7a31 100644
--- a/runtime/vm/os_thread.cc
+++ b/runtime/vm/os_thread.cc
@@ -23,7 +23,9 @@
 OSThread::OSThread() :
     BaseThread(true),
     id_(OSThread::GetCurrentThreadId()),
-    join_id_(OSThread::GetCurrentThreadJoinId()),
+#if defined(DEBUG)
+    join_id_(kInvalidThreadJoinId),
+#endif
     trace_id_(OSThread::GetCurrentThreadTraceId()),
     name_(NULL),
     timeline_block_lock_(new Mutex()),
@@ -160,8 +162,8 @@
 }
 
 
-bool OSThread::IsThreadInList(ThreadJoinId join_id) {
-  if (join_id == OSThread::kInvalidThreadJoinId) {
+bool OSThread::IsThreadInList(ThreadId id) {
+  if (id == OSThread::kInvalidThreadId) {
     return false;
   }
   OSThreadIterator it;
@@ -169,8 +171,8 @@
     ASSERT(OSThread::thread_list_lock_->IsOwnedByCurrentThread());
     OSThread* t = it.Next();
     // An address test is not sufficient because the allocator may recycle
-    // the address for another Thread. Test against the thread's join id.
-    if (t->join_id() == join_id) {
+    // the address for another Thread. Test against the thread's id.
+    if (t->id() == id) {
       return true;
     }
   }
diff --git a/runtime/vm/os_thread.h b/runtime/vm/os_thread.h
index 1bd2193..415cff89 100644
--- a/runtime/vm/os_thread.h
+++ b/runtime/vm/os_thread.h
@@ -61,13 +61,8 @@
     return id_;
   }
 
-  ThreadJoinId join_id() const {
-    ASSERT(join_id_ != OSThread::kInvalidThreadJoinId);
-    return join_id_;
-  }
-
   ThreadId trace_id() const {
-    ASSERT(trace_id_ != OSThread::kInvalidThreadJoinId);
+    ASSERT(trace_id_ != OSThread::kInvalidThreadId);
     return trace_id_;
   }
 
@@ -174,10 +169,14 @@
   static ThreadId ThreadIdFromIntPtr(intptr_t id);
   static bool Compare(ThreadId a, ThreadId b);
 
+  // This function can be called only once per OSThread, and should only be
+  // called when the retunred id will eventually be passed to OSThread::Join().
+  static ThreadJoinId GetCurrentThreadJoinId(OSThread* thread);
+
   // Called at VM startup and shutdown.
   static void InitOnce();
 
-  static bool IsThreadInList(ThreadJoinId join_id);
+  static bool IsThreadInList(ThreadId id);
 
   static void DisableOSThreadCreation();
   static void EnableOSThreadCreation();
@@ -205,7 +204,6 @@
 
   static void Cleanup();
   static ThreadId GetCurrentThreadTraceId();
-  static ThreadJoinId GetCurrentThreadJoinId();
   static OSThread* GetOSThreadFromThread(Thread* thread);
   static void AddThreadToListLocked(OSThread* thread);
   static void RemoveThreadFromList(OSThread* thread);
@@ -214,7 +212,11 @@
   static ThreadLocalKey thread_key_;
 
   const ThreadId id_;
-  const ThreadJoinId join_id_;
+#if defined(DEBUG)
+  // In DEBUG mode we use this field to ensure that GetCurrentThreadJoinId is
+  // only called once per OSThread.
+  ThreadJoinId join_id_;
+#endif
   const ThreadId trace_id_;  // Used to interface with tracing tools.
   char* name_;  // A name for this thread.
 
diff --git a/runtime/vm/os_thread_android.cc b/runtime/vm/os_thread_android.cc
index b184f61..5a54c59 100644
--- a/runtime/vm/os_thread_android.cc
+++ b/runtime/vm/os_thread_android.cc
@@ -193,8 +193,17 @@
 }
 
 
-ThreadJoinId OSThread::GetCurrentThreadJoinId() {
-  return pthread_self();
+ThreadJoinId OSThread::GetCurrentThreadJoinId(OSThread* thread) {
+  ASSERT(thread != NULL);
+  // Make sure we're filling in the join id for the current thread.
+  ASSERT(thread->id() == GetCurrentThreadId());
+  // Make sure the join_id_ hasn't been set, yet.
+  DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId);
+  pthread_t id = pthread_self();
+#if defined(DEBUG)
+  thread->join_id_ = id;
+#endif
+  return id;
 }
 
 
diff --git a/runtime/vm/os_thread_linux.cc b/runtime/vm/os_thread_linux.cc
index bd9bfaf..9695042 100644
--- a/runtime/vm/os_thread_linux.cc
+++ b/runtime/vm/os_thread_linux.cc
@@ -194,8 +194,17 @@
 }
 
 
-ThreadJoinId OSThread::GetCurrentThreadJoinId() {
-  return pthread_self();
+ThreadJoinId OSThread::GetCurrentThreadJoinId(OSThread* thread) {
+  ASSERT(thread != NULL);
+  // Make sure we're filling in the join id for the current thread.
+  ASSERT(thread->id() == GetCurrentThreadId());
+  // Make sure the join_id_ hasn't been set, yet.
+  DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId);
+  pthread_t id = pthread_self();
+#if defined(DEBUG)
+  thread->join_id_ = id;
+#endif
+  return id;
 }
 
 
diff --git a/runtime/vm/os_thread_macos.cc b/runtime/vm/os_thread_macos.cc
index 4c7d094..b5fd6f9 100644
--- a/runtime/vm/os_thread_macos.cc
+++ b/runtime/vm/os_thread_macos.cc
@@ -168,8 +168,17 @@
 }
 
 
-ThreadJoinId OSThread::GetCurrentThreadJoinId() {
-  return pthread_self();
+ThreadJoinId OSThread::GetCurrentThreadJoinId(OSThread* thread) {
+  ASSERT(thread != NULL);
+  // Make sure we're filling in the join id for the current thread.
+  ASSERT(thread->id() == GetCurrentThreadId());
+  // Make sure the join_id_ hasn't been set, yet.
+  DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId);
+  pthread_t id = pthread_self();
+#if defined(DEBUG)
+  thread->join_id_ = id;
+#endif
+  return id;
 }
 
 
diff --git a/runtime/vm/os_thread_win.cc b/runtime/vm/os_thread_win.cc
index e4083dc..ed8de4af 100644
--- a/runtime/vm/os_thread_win.cc
+++ b/runtime/vm/os_thread_win.cc
@@ -91,7 +91,7 @@
 
 
 const ThreadId OSThread::kInvalidThreadId = 0;
-const ThreadJoinId OSThread::kInvalidThreadJoinId = 0;
+const ThreadJoinId OSThread::kInvalidThreadJoinId = NULL;
 
 
 ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
@@ -130,27 +130,25 @@
 }
 
 
-ThreadJoinId OSThread::GetCurrentThreadJoinId() {
-  // TODO(zra): Use the thread handle as the join id in order to have a more
-  // reliable join on windows.
-  return ::GetCurrentThreadId();
+ThreadJoinId OSThread::GetCurrentThreadJoinId(OSThread* thread) {
+  ASSERT(thread != NULL);
+  // Make sure we're filling in the join id for the current thread.
+  ThreadId id = GetCurrentThreadId();
+  ASSERT(thread->id() == id);
+  // Make sure the join_id_ hasn't been set, yet.
+  DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId);
+  HANDLE handle = OpenThread(SYNCHRONIZE, false, id);
+  ASSERT(handle != NULL);
+#if defined(DEBUG)
+  thread->join_id_ = handle;
+#endif
+  return handle;
 }
 
 
 void OSThread::Join(ThreadJoinId id) {
-  HANDLE handle = OpenThread(SYNCHRONIZE, false, id);
-
-  // 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) {
-    return;
-  }
-
+  HANDLE handle = static_cast<HANDLE>(id);
+  ASSERT(handle != NULL);
   DWORD res = WaitForSingleObject(handle, INFINITE);
   CloseHandle(handle);
   ASSERT(res == WAIT_OBJECT_0);
diff --git a/runtime/vm/os_thread_win.h b/runtime/vm/os_thread_win.h
index 790306d..913b074 100644
--- a/runtime/vm/os_thread_win.h
+++ b/runtime/vm/os_thread_win.h
@@ -18,7 +18,7 @@
 
 typedef DWORD ThreadLocalKey;
 typedef DWORD ThreadId;
-typedef DWORD ThreadJoinId;
+typedef HANDLE ThreadJoinId;
 
 
 static const ThreadLocalKey kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
diff --git a/runtime/vm/os_win.cc b/runtime/vm/os_win.cc
index bb2d634..2ea8c1d 100644
--- a/runtime/vm/os_win.cc
+++ b/runtime/vm/os_win.cc
@@ -259,6 +259,11 @@
 }
 
 
+intptr_t OS::StrNLen(const char* s, intptr_t n) {
+  return strnlen(s, n);
+}
+
+
 void OS::Print(const char* format, ...) {
   va_list args;
   va_start(args, format);
diff --git a/runtime/vm/pages.cc b/runtime/vm/pages.cc
index 64b1d5e..e5d1e65 100644
--- a/runtime/vm/pages.cc
+++ b/runtime/vm/pages.cc
@@ -35,8 +35,6 @@
             "Emit a log message when pointers to unused code are dropped.");
 DEFINE_FLAG(bool, always_drop_code, false,
             "Always try to drop code if the function's usage counter is >= 0");
-DEFINE_FLAG(bool, concurrent_sweep, true,
-            "Concurrent sweep for old generation.");
 DEFINE_FLAG(bool, log_growth, false, "Log PageSpace growth policy decisions.");
 
 HeapPage* HeapPage::Initialize(VirtualMemory* memory, PageType type) {
@@ -846,7 +844,9 @@
     SpaceUsage usage_before = GetCurrentUsage();
 
     // Mark all reachable old-gen objects.
-    bool collect_code = FLAG_collect_code && ShouldCollectCode();
+    bool collect_code = FLAG_collect_code &&
+                        ShouldCollectCode() &&
+                        !isolate->HasAttemptedReload();
     GCMarker marker(heap_);
     marker.MarkObjects(isolate, this, invoke_api_callbacks, collect_code);
     usage_.used_in_words = marker.marked_words();
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 0ace98b..7819cd7 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -514,8 +514,8 @@
   Thread* thread = Thread::Current();
   ASSERT(thread->long_jump_base()->IsSafeToJump());
   CSTAT_TIMER_SCOPE(thread, parser_timer);
-  VMTagScope tagScope(thread, VMTag::kCompileTopLevelTagId);
 #ifndef PRODUCT
+  VMTagScope tagScope(thread, VMTag::kCompileTopLevelTagId);
   TimelineDurationScope tds(thread,
                             Timeline::GetCompilerStream(),
                             "CompileTopLevel");
@@ -989,9 +989,9 @@
   Zone* zone = thread->zone();
   CSTAT_TIMER_SCOPE(thread, parser_timer);
   INC_STAT(thread, num_functions_parsed, 1);
+#ifndef PRODUCT
   VMTagScope tagScope(thread, VMTag::kCompileParseFunctionTagId,
                       FLAG_profile_vm);
-#ifndef PRODUCT
   TimelineDurationScope tds(thread,
                             Timeline::GetCompilerStream(),
                             "ParseFunction");
@@ -1234,6 +1234,12 @@
   Thread* thread = Thread::Current();
   // TODO(koda): Should there be a StackZone here?
   Zone* zone = thread->zone();
+#ifndef PRODUCT
+  VMTagScope tagScope(thread, VMTag::kCompileParseFunctionTagId,
+                      FLAG_profile_vm);
+  TimelineDurationScope tds(thread, Timeline::GetCompilerStream(),
+                            "ParseStaticFieldInitializer");
+#endif  // !PRODUCT
 
   const String& field_name = String::Handle(zone, field.name());
   String& init_name = String::Handle(zone,
@@ -2416,7 +2422,7 @@
   arguments->Add(implicit_argument);
 
   // If this is a super call in a forwarding constructor, add the user-
-  // defined arguments to the super call and adjust the the super
+  // defined arguments to the super call and adjust the super
   // constructor name to the respective named constructor if necessary.
   if (forwarding_args != NULL) {
     for (int i = 0; i < forwarding_args->length(); i++) {
@@ -4384,8 +4390,7 @@
     ReportError(name_pos, "'%s' is already defined", enum_name->ToCString());
   }
   Class& cls = Class::Handle(Z);
-  cls = Class::New(*enum_name, script_, declaration_pos);
-  cls.set_library(library_);
+  cls = Class::New(library_, *enum_name, script_, declaration_pos);
   library_.AddClass(cls);
   cls.set_is_synthesized_class();
   cls.set_is_enum_class();
@@ -4428,7 +4433,7 @@
       ReportError(classname_pos, "missing class '%s' cannot be patched",
                   class_name.ToCString());
     }
-    cls = Class::New(class_name, script_, declaration_pos);
+    cls = Class::New(library_, class_name, script_, declaration_pos);
     library_.AddClass(cls);
   } else {
     if (!obj.IsClass()) {
@@ -4440,8 +4445,7 @@
       // Preserve and reuse the original type parameters and bounds since the
       // ones defined in the patch class will not be finalized.
       orig_type_parameters = cls.type_parameters();
-      cls = Class::New(class_name, script_, declaration_pos);
-      cls.set_library(library_);
+      cls = Class::New(library_, class_name, script_, declaration_pos);
     } else {
       // Not patching a class, but it has been found. This must be one of the
       // pre-registered classes from object.cc or a duplicate definition.
@@ -4911,7 +4915,8 @@
                 class_name.ToCString());
   }
   const Class& mixin_application =
-      Class::Handle(Z, Class::New(class_name, script_, classname_pos));
+      Class::Handle(Z, Class::New(library_, class_name,
+                                  script_, classname_pos));
   mixin_application.set_is_mixin_app_alias();
   library_.AddClass(mixin_application);
   set_current_class(mixin_application);
@@ -5039,8 +5044,9 @@
   // signature function after it has been parsed. The type parameters, in order
   // to be properly finalized, need to be associated to this scope class as
   // they are parsed.
-  const Class& function_type_alias = Class::Handle(Z,
-      Class::New(*alias_name, script_, declaration_pos));
+  const Class& function_type_alias =
+      Class::Handle(Z, Class::New(
+          library_, *alias_name, script_, declaration_pos));
   function_type_alias.set_is_synthesized_class();
   function_type_alias.set_is_abstract();
   function_type_alias.set_is_prefinalized();
@@ -6090,7 +6096,8 @@
   Object& tl_owner = Object::Handle(Z);
   Class& toplevel_class = Class::Handle(Z, library_.toplevel_class());
   if (toplevel_class.IsNull()) {
-    toplevel_class = Class::New(Symbols::TopLevel(), script_, TokenPos());
+    toplevel_class =
+        Class::New(library_, Symbols::TopLevel(), script_, TokenPos());
     toplevel_class.set_library(library_);
     library_.set_toplevel_class(toplevel_class);
     tl_owner = toplevel_class.raw();
@@ -12005,64 +12012,22 @@
   return current_class().IsGeneric();
 }
 
-// We cache computed compile-time constants in a map so we can look them
-// up when the same code gets compiled again. The map key is a pair
-// (script url, token position) which is encoded in an array with 2
-// elements:
-// - key[0] contains the canonicalized url of the script.
-// - key[1] contains the token position of the constant in the script.
 
-// ConstantPosKey allows us to look up a constant in the map without
-// allocating a key pair (array).
-struct ConstantPosKey : ValueObject {
-  ConstantPosKey(const String& url, TokenPosition pos)
-      : script_url(url), token_pos(pos) { }
-  const String& script_url;
-  TokenPosition token_pos;
-};
-
-
-class ConstMapKeyEqualsTraits {
- public:
-  static const char* Name() { return "ConstMapKeyEqualsTraits"; }
-  static bool ReportStats() { return false; }
-
-  static bool IsMatch(const Object& a, const Object& b) {
-    const Array& key1 = Array::Cast(a);
-    const Array& key2 = Array::Cast(b);
-    // Compare raw strings of script url symbol and raw smi of token positon.
-    return (key1.At(0) == key2.At(0)) && (key1.At(1) == key2.At(1));
+void Parser::InsertCachedConstantValue(const String& url,
+                                       TokenPosition token_pos,
+                                       const Instance& value) {
+  Isolate* isolate = Isolate::Current();
+  ConstantPosKey key(url, token_pos);
+  if (isolate->object_store()->compile_time_constants() == Array::null()) {
+    const intptr_t kInitialConstMapSize = 16;
+    isolate->object_store()->set_compile_time_constants(
+        Array::Handle(HashTables::New<ConstantsMap>(kInitialConstMapSize,
+                                                    Heap::kNew)));
   }
-  static bool IsMatch(const ConstantPosKey& key1, const Object& b) {
-    const Array& key2 = Array::Cast(b);
-    // Compare raw strings of script url symbol and token positon.
-    return (key1.script_url.raw() == key2.At(0))
-        && (key1.token_pos.value() == Smi::Value(Smi::RawCast(key2.At(1))));
-  }
-  static uword Hash(const Object& obj) {
-    const Array& key = Array::Cast(obj);
-    intptr_t url_hash = String::HashRawSymbol(String::RawCast(key.At(0)));
-    intptr_t pos = Smi::Value(Smi::RawCast(key.At(1)));
-    return HashValue(url_hash, pos);
-  }
-  static uword Hash(const ConstantPosKey& key) {
-    return HashValue(String::HashRawSymbol(key.script_url.raw()),
-                     key.token_pos.value());
-  }
-  // Used by CacheConstantValue if a new constant is added to the map.
-  static RawObject* NewKey(const ConstantPosKey& key) {
-    const Array& key_obj = Array::Handle(Array::New(2));
-    key_obj.SetAt(0, key.script_url);
-    key_obj.SetAt(1, Smi::Handle(Smi::New(key.token_pos.value())));
-    return key_obj.raw();;
-  }
-
- private:
-  static uword HashValue(intptr_t url_hash, intptr_t pos) {
-    return url_hash * pos % (Smi::kMaxValue - 13);
-  }
-};
-typedef UnorderedHashMap<ConstMapKeyEqualsTraits> ConstantsMap;
+  ConstantsMap constants(isolate->object_store()->compile_time_constants());
+  constants.InsertNewOrGetValue(key, value);
+  isolate->object_store()->set_compile_time_constants(constants.Release());
+}
 
 
 void Parser::CacheConstantValue(TokenPosition token_pos,
@@ -12072,19 +12037,13 @@
     // evaluated only once.
     return;
   }
-  ConstantPosKey key(String::Handle(Z, script_.url()), token_pos);
-  if (isolate()->object_store()->compile_time_constants() == Array::null()) {
-    const intptr_t kInitialConstMapSize = 16;
-    isolate()->object_store()->set_compile_time_constants(
-        Array::Handle(Z, HashTables::New<ConstantsMap>(kInitialConstMapSize,
-                                                       Heap::kNew)));
-  }
-  ConstantsMap constants(isolate()->object_store()->compile_time_constants());
-  constants.InsertNewOrGetValue(key, value);
+  const String& url = String::Handle(Z, script_.url());
+  InsertCachedConstantValue(url, token_pos, value);
   if (FLAG_compiler_stats) {
+    ConstantsMap constants(isolate()->object_store()->compile_time_constants());
     thread_->compiler_stats()->num_cached_consts = constants.NumOccupied();
+    constants.Release();
   }
-  isolate()->object_store()->set_compile_time_constants(constants.Release());
 }
 
 
@@ -14528,6 +14487,13 @@
 }
 
 
+void Parser::InsertCachedConstantValue(const String& url,
+                                       TokenPosition token_pos,
+                                       const Instance& value) {
+  UNREACHABLE();
+}
+
+
 ArgumentListNode* Parser::BuildNoSuchMethodArguments(
     TokenPosition call_pos,
     const String& function_name,
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index eb9f54a..ba284a5 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -14,6 +14,7 @@
 #include "vm/ast.h"
 #include "vm/class_finalizer.h"
 #include "vm/compiler_stats.h"
+#include "vm/hash_table.h"
 #include "vm/object.h"
 #include "vm/raw_object.h"
 #include "vm/token.h"
@@ -38,6 +39,65 @@
 class TopLevel;
 class RecursionChecker;
 
+// We cache computed compile-time constants in a map so we can look them
+// up when the same code gets compiled again. The map key is a pair
+// (script url, token position) which is encoded in an array with 2
+// elements:
+// - key[0] contains the canonicalized url of the script.
+// - key[1] contains the token position of the constant in the script.
+
+// ConstantPosKey allows us to look up a constant in the map without
+// allocating a key pair (array).
+struct ConstantPosKey : ValueObject {
+  ConstantPosKey(const String& url, TokenPosition pos)
+      : script_url(url), token_pos(pos) { }
+  const String& script_url;
+  TokenPosition token_pos;
+};
+
+
+class ConstMapKeyEqualsTraits {
+ public:
+  static const char* Name() { return "ConstMapKeyEqualsTraits"; }
+  static bool ReportStats() { return false; }
+
+  static bool IsMatch(const Object& a, const Object& b) {
+    const Array& key1 = Array::Cast(a);
+    const Array& key2 = Array::Cast(b);
+    // Compare raw strings of script url symbol and raw smi of token positon.
+    return (key1.At(0) == key2.At(0)) && (key1.At(1) == key2.At(1));
+  }
+  static bool IsMatch(const ConstantPosKey& key1, const Object& b) {
+    const Array& key2 = Array::Cast(b);
+    // Compare raw strings of script url symbol and token positon.
+    return (key1.script_url.raw() == key2.At(0))
+        && (key1.token_pos.value() == Smi::Value(Smi::RawCast(key2.At(1))));
+  }
+  static uword Hash(const Object& obj) {
+    const Array& key = Array::Cast(obj);
+    intptr_t url_hash = String::HashRawSymbol(String::RawCast(key.At(0)));
+    intptr_t pos = Smi::Value(Smi::RawCast(key.At(1)));
+    return HashValue(url_hash, pos);
+  }
+  static uword Hash(const ConstantPosKey& key) {
+    return HashValue(String::HashRawSymbol(key.script_url.raw()),
+                     key.token_pos.value());
+  }
+  // Used by CachConstantValue if a new constant is added to the map.
+  static RawObject* NewKey(const ConstantPosKey& key) {
+    const Array& key_obj = Array::Handle(Array::New(2));
+    key_obj.SetAt(0, key.script_url);
+    key_obj.SetAt(1, Smi::Handle(Smi::New(key.token_pos.value())));
+    return key_obj.raw();;
+  }
+
+ private:
+  static uword HashValue(intptr_t url_hash, intptr_t pos) {
+    return url_hash * pos % (Smi::kMaxValue - 13);
+  }
+};
+typedef UnorderedHashMap<ConstMapKeyEqualsTraits> ConstantsMap;
+
 // The class ParsedFunction holds the result of parsing a function.
 class ParsedFunction : public ZoneAllocated {
  public:
@@ -216,6 +276,10 @@
   // given static field.
   static ParsedFunction* ParseStaticFieldInitializer(const Field& field);
 
+  static void InsertCachedConstantValue(const String& url,
+                                        TokenPosition token_pos,
+                                        const Instance& value);
+
   // Parse a function to retrieve parameter information that is not retained in
   // the dart::Function object. Returns either an error if the parse fails
   // (which could be the case for local functions), or a flat array of entries
diff --git a/runtime/vm/parser_test.cc b/runtime/vm/parser_test.cc
index 120e5ca..319b13d 100644
--- a/runtime/vm/parser_test.cc
+++ b/runtime/vm/parser_test.cc
@@ -248,11 +248,8 @@
   EXPECT(ClassFinalizer::ProcessPendingClasses());
   bool saved_flag = FLAG_show_invisible_frames;
   FLAG_show_invisible_frames = true;
-  Isolate* isolate = Isolate::Current();
-  Debugger* debugger = isolate->debugger();
-  const String& url = String::Handle(String::New(TestCase::url()));
   Dart_SetPausedEventHandler(SaveVars);
-  debugger->SetBreakpointAtLine(url, line);
+  EXPECT_VALID(Dart_SetBreakpoint(NewString(TestCase::url()), line));
   saved_vars = NULL;
   EXPECT_VALID(Dart_Invoke(lib, NewString(entry), 0, NULL));
   const char* tmp = saved_vars;
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index 924d8a1..b366396 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -41,6 +41,7 @@
 #include "vm/tags.h"
 #include "vm/timeline.h"
 #include "vm/timer.h"
+#include "vm/type_table.h"
 
 namespace dart {
 
@@ -75,6 +76,33 @@
 
 #ifdef DART_PRECOMPILER
 
+class DartPrecompilationPipeline : public DartCompilationPipeline {
+ public:
+  DartPrecompilationPipeline() : result_type_(CompileType::None()) { }
+
+  virtual void FinalizeCompilation(FlowGraph* flow_graph) {
+    CompileType result_type = CompileType::None();
+    for (BlockIterator block_it = flow_graph->reverse_postorder_iterator();
+         !block_it.Done();
+         block_it.Advance()) {
+      ForwardInstructionIterator it(block_it.Current());
+      for (; !it.Done(); it.Advance()) {
+        ReturnInstr* return_instr = it.Current()->AsReturn();
+        if (return_instr != NULL) {
+          result_type.Union(return_instr->InputAt(0)->Type());
+        }
+      }
+    }
+    result_type_ = result_type;
+  }
+
+  CompileType result_type() { return result_type_; }
+
+ private:
+  CompileType result_type_;
+};
+
+
 class PrecompileParsedFunctionHelper : public ValueObject {
  public:
   PrecompileParsedFunctionHelper(ParsedFunction* parsed_function,
@@ -169,6 +197,9 @@
     // because their class hasn't been finalized yet.
     FinalizeAllClasses();
 
+    // Precompile static initializers to compute result type information.
+    PrecompileStaticInitializers();
+
     for (intptr_t round = 0; round < FLAG_precompiler_rounds; round++) {
       if (FLAG_trace_precompiler) {
         THR_Print("Precompiler round %" Pd "\n", round);
@@ -255,9 +286,52 @@
 }
 
 
+static void CompileStaticInitializerIgnoreErrors(const Field& field) {
+  LongJumpScope jump;
+  if (setjmp(*jump.Set()) == 0) {
+    Precompiler::CompileStaticInitializer(field, /* compute_type = */ true);
+  } else {
+    // Ignore compile-time errors here. If the field is actually used,
+    // the error will be reported later during Iterate().
+  }
+}
+
+
+void Precompiler::PrecompileStaticInitializers() {
+  class StaticInitializerVisitor : public ClassVisitor {
+   public:
+    explicit StaticInitializerVisitor(Zone* zone)
+      : fields_(Array::Handle(zone)),
+        field_(Field::Handle(zone)),
+        function_(Function::Handle(zone)) { }
+    void Visit(const Class& cls) {
+      fields_ = cls.fields();
+      for (intptr_t j = 0; j < fields_.Length(); j++) {
+        field_ ^= fields_.At(j);
+        if (field_.is_static() &&
+            field_.is_final() &&
+            field_.has_initializer()) {
+          if (FLAG_trace_precompiler) {
+            THR_Print("Precompiling initializer for %s\n", field_.ToCString());
+          }
+          CompileStaticInitializerIgnoreErrors(field_);
+        }
+      }
+    }
+
+   private:
+    Array& fields_;
+    Field& field_;
+    Function& function_;
+  };
+  StaticInitializerVisitor visitor(Z);
+  VisitClasses(&visitor);
+}
+
+
 void Precompiler::ClearAllCode() {
   class ClearCodeFunctionVisitor : public FunctionVisitor {
-    void VisitFunction(const Function& function) {
+    void Visit(const Function& function) {
       function.ClearCode();
       function.ClearICDataArray();
     }
@@ -292,14 +366,6 @@
   }
 
   Dart_QualifiedFunctionName vm_entry_points[] = {
-    // TODO(rmacnak): These types are not allocated from C++ but they are
-    // cached in the object store. Consider clearing them from the object store
-    // before snapshotting and adjusting InitKnownObjects to allow their
-    // absence.
-    { "dart:async", "Future", "Future." },
-    { "dart:async", "Completer", "Completer." },
-    { "dart:async", "StreamIterator", "StreamIterator." },
-
     // Functions
     { "dart:async", "::", "_setScheduleImmediateClosure" },
     { "dart:core", "::", "_completeDeferredLoads" },
@@ -326,6 +392,7 @@
     { "dart:isolate", "::", "_getIsolateScheduleImmediateClosure" },
     { "dart:isolate", "::", "_setupHooks" },
     { "dart:isolate", "::", "_startMainIsolate" },
+    { "dart:isolate", "::", "_startIsolate" },
     { "dart:isolate", "_RawReceivePortImpl", "_handleMessage" },
     { "dart:isolate", "_RawReceivePortImpl", "_lookupHandler" },
     { "dart:isolate", "_SendPortImpl", "send" },
@@ -336,6 +403,7 @@
     { "dart:_vmservice", "::", "_registerIsolate" },
     { "dart:_vmservice", "::", "boot" },
     { "dart:developer", "Metrics", "_printMetrics" },
+    { "dart:developer", "::", "_runExtension" },
 #endif  // !PRODUCT
     // Fields
     { "dart:core", "Error", "_stackTrace" },
@@ -774,8 +842,8 @@
           THR_Print("Precompiling initializer for %s\n", field.ToCString());
         }
         ASSERT(Dart::snapshot_kind() != Snapshot::kAppNoJIT);
-        const Function& initializer =
-            Function::Handle(Z, CompileStaticInitializer(field));
+        const Function& initializer = Function::Handle(Z,
+            CompileStaticInitializer(field, /* compute_type = */ true));
         ASSERT(!initializer.IsNull());
         field.SetPrecompiledInitializer(initializer);
         AddCalleesOf(initializer);
@@ -785,21 +853,32 @@
 }
 
 
-RawFunction* Precompiler::CompileStaticInitializer(const Field& field) {
+RawFunction* Precompiler::CompileStaticInitializer(const Field& field,
+                                                   bool compute_type) {
   ASSERT(field.is_static());
-  ASSERT(!field.HasPrecompiledInitializer());
   Thread* thread = Thread::Current();
   StackZone zone(thread);
 
   ParsedFunction* parsed_function = Parser::ParseStaticFieldInitializer(field);
 
   parsed_function->AllocateVariables();
-  DartCompilationPipeline pipeline;
+  DartPrecompilationPipeline pipeline;
   PrecompileParsedFunctionHelper helper(parsed_function,
                                         /* optimized = */ true);
   bool success = helper.Compile(&pipeline);
   ASSERT(success);
 
+  if (compute_type && field.is_final()) {
+    intptr_t result_cid = pipeline.result_type().ToCid();
+    if (result_cid != kDynamicCid) {
+      if (FLAG_trace_precompiler && FLAG_support_il_printer) {
+        THR_Print("Setting guarded_cid of %s to %s\n", field.ToCString(),
+                  pipeline.result_type().ToCString());
+      }
+      field.set_guarded_cid(result_cid);
+    }
+  }
+
   if ((FLAG_disassemble || FLAG_disassemble_optimized) &&
       FlowGraphPrinter::ShouldPrint(parsed_function->function())) {
     Disassembler::DisassembleCode(parsed_function->function(),
@@ -822,7 +901,7 @@
     // remembering it because it won't be used again.
     Function& initializer = Function::Handle();
     if (!field.HasPrecompiledInitializer()) {
-      initializer = CompileStaticInitializer(field);
+      initializer = CompileStaticInitializer(field, /* compute_type = */ false);
     } else {
       initializer ^= field.PrecompiledInitializer();
     }
@@ -883,7 +962,7 @@
     parsed_function->AllocateVariables();
 
     // Non-optimized code generator.
-    DartCompilationPipeline pipeline;
+    DartPrecompilationPipeline pipeline;
     PrecompileParsedFunctionHelper helper(parsed_function,
                                           /* optimized = */ false);
     helper.Compile(&pipeline);
@@ -1130,6 +1209,9 @@
             AddNameToFunctionsTable(zone(), &table, fname, function);
             fname = Field::NameFromGetter(fname);
             AddNameToFunctionsTable(zone(), &table, fname, function);
+          } else if (function.IsMethodExtractor()) {
+            // Skip. We already add getter names for regular methods below.
+            continue;
           } else {
             // Regular function. Enter both getter and non getter name.
             AddNameToFunctionsTable(zone(), &table, fname, function);
@@ -1177,18 +1259,6 @@
 }
 
 
-void Precompiler::GetUniqueDynamicTarget(Isolate* isolate,
-                                         const String& fname,
-                                         Object* function) {
-  UniqueFunctionsSet functions_set(
-      isolate->object_store()->unique_dynamic_targets());
-  ASSERT(fname.IsSymbol());
-  *function = functions_set.GetOrNull(fname);
-  ASSERT(functions_set.Release().raw() ==
-      isolate->object_store()->unique_dynamic_targets());
-}
-
-
 void Precompiler::TraceConstFunctions() {
   // Compilation of const accessors happens outside of the treeshakers
   // queue, so we haven't previously scanned its literal pool.
@@ -1405,92 +1475,78 @@
 
 
 void Precompiler::DropTypes() {
-  Library& lib = Library::Handle(Z);
-  Class& cls = Class::Handle(Z);
-  Object& obj = Object::Handle(Z);
-  Array& arr = Array::Handle(Z);
-  GrowableObjectArray& retained_types = GrowableObjectArray::Handle(Z);
-  AbstractType& type = AbstractType::Handle(Z);
-
-  for (intptr_t i = 0; i < libraries_.Length(); i++) {
-    lib ^= libraries_.At(i);
-    ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
-    while (it.HasNext()) {
-      cls = it.GetNextClass();
-      if (cls.IsDynamicClass()) {
-        continue;  // class 'dynamic' is in the read-only VM isolate.
-      }
-      obj = cls.canonical_types();
-      if (!obj.IsArray()) {
-        // Class only has one type, keep it.
+  ObjectStore* object_store = I->object_store();
+  GrowableObjectArray& retained_types =
+      GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
+  Array& types_array = Array::Handle(Z);
+  Type& type = Type::Handle(Z);
+  // First drop all the types that are not referenced.
+  {
+    CanonicalTypeSet types_table(Z, object_store->canonical_types());
+    types_array = HashTables::ToArray(types_table, false);
+    for (intptr_t i = 0; i < (types_array.Length() - 1); i++) {
+      type ^= types_array.At(i);
+      bool retain = types_to_retain_.Lookup(&type) != NULL;
+      if (retain) {
+        retained_types.Add(type);
       } else {
-        // Class has many types.
-        arr ^= obj.raw();
-        retained_types = GrowableObjectArray::New();
-
-        // Always keep the first one.
-        ASSERT(arr.Length() >= 1);
-        obj = arr.At(0);
-        retained_types.Add(obj);
-
-        for (intptr_t i = 1; i < arr.Length(); i++) {
-          obj = arr.At(i);
-          if (obj.IsNull()) {
-            continue;
-          }
-          type ^= obj.raw();
-          bool retain = types_to_retain_.Lookup(&type) != NULL;
-          if (retain) {
-            retained_types.Add(type);
-          } else {
-            dropped_type_count_++;
-          }
-        }
-        arr = Array::MakeArray(retained_types);
-        cls.set_canonical_types(arr);
+        dropped_type_count_++;
       }
     }
+    types_table.Release();
   }
+
+  // Now construct a new type table and save in the object store.
+  const intptr_t dict_size =
+      Utils::RoundUpToPowerOfTwo(retained_types.Length() * 4 / 3);
+  types_array = HashTables::New<CanonicalTypeSet>(dict_size, Heap::kOld);
+  CanonicalTypeSet types_table(Z, types_array.raw());
+  bool present;
+  for (intptr_t i = 0; i < retained_types.Length(); i++) {
+    type ^= retained_types.At(i);
+    present = types_table.Insert(type);
+    ASSERT(!present);
+  }
+  object_store->set_canonical_types(types_table.Release());
 }
 
 
 void Precompiler::DropTypeArguments() {
-  const Array& typeargs_table =
-      Array::Handle(Z, I->object_store()->canonical_type_arguments());
+  ObjectStore* object_store = I->object_store();
+  Array& typeargs_array = Array::Handle(Z);
   GrowableObjectArray& retained_typeargs =
       GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
   TypeArguments& typeargs = TypeArguments::Handle(Z);
-  for (intptr_t i = 0; i < (typeargs_table.Length() - 1); i++) {
-    typeargs ^= typeargs_table.At(i);
-    bool retain = typeargs_to_retain_.Lookup(&typeargs) != NULL;
-    if (retain) {
-      retained_typeargs.Add(typeargs);
-    } else {
-      dropped_typearg_count_++;
+  // First drop all the type arguments that are not referenced.
+  {
+    CanonicalTypeArgumentsSet typeargs_table(
+        Z, object_store->canonical_type_arguments());
+    typeargs_array = HashTables::ToArray(typeargs_table, false);
+    for (intptr_t i = 0; i < (typeargs_array.Length() - 1); i++) {
+      typeargs ^= typeargs_array.At(i);
+      bool retain = typeargs_to_retain_.Lookup(&typeargs) != NULL;
+      if (retain) {
+        retained_typeargs.Add(typeargs);
+      } else {
+        dropped_typearg_count_++;
+      }
     }
+    typeargs_table.Release();
   }
 
+  // Now construct a new type arguments table and save in the object store.
   const intptr_t dict_size =
       Utils::RoundUpToPowerOfTwo(retained_typeargs.Length() * 4 / 3);
-  const Array& new_table = Array::Handle(Z, Array::New(dict_size + 1));
-
-  Object& element = Object::Handle(Z);
+  typeargs_array = HashTables::New<CanonicalTypeArgumentsSet>(dict_size,
+                                                              Heap::kOld);
+  CanonicalTypeArgumentsSet typeargs_table(Z, typeargs_array.raw());
+  bool present;
   for (intptr_t i = 0; i < retained_typeargs.Length(); i++) {
     typeargs ^= retained_typeargs.At(i);
-    intptr_t hash = typeargs.Hash();
-    intptr_t index = hash & (dict_size - 1);
-    element = new_table.At(index);
-    while (!element.IsNull()) {
-      index = (index + 1) & (dict_size - 1);
-      element = new_table.At(index);
-    }
-    new_table.SetAt(index, typeargs);
+    present = typeargs_table.Insert(typeargs);
+    ASSERT(!present);
   }
-
-  const Smi& used = Smi::Handle(Z, Smi::New(retained_typeargs.Length()));
-  new_table.SetAt(dict_size, used);
-
-  I->object_store()->set_canonical_type_arguments(new_table);
+  object_store->set_canonical_type_arguments(typeargs_table.Release());
 }
 
 
@@ -1688,7 +1744,7 @@
         target_code_(Code::Handle(zone)) {
     }
 
-    void VisitFunction(const Function& function) {
+    void Visit(const Function& function) {
       if (!function.HasCode()) {
         return;
       }
@@ -1757,7 +1813,7 @@
         entry_point_(Smi::Handle(zone)) {
     }
 
-    void VisitFunction(const Function& function) {
+    void Visit(const Function& function) {
       if (!function.HasCode()) {
         return;
       }
@@ -1826,7 +1882,7 @@
       stackmap_(Stackmap::Handle(zone)) {
     }
 
-    void VisitFunction(const Function& function) {
+    void Visit(const Function& function) {
       if (!function.HasCode()) {
         return;
       }
@@ -1876,7 +1932,7 @@
       stackmap_(Stackmap::Handle(zone)) {
     }
 
-    void VisitFunction(const Function& function) {
+    void Visit(const Function& function) {
       if (!function.HasCode()) {
         return;
       }
@@ -1923,7 +1979,7 @@
       instructions_(Instructions::Handle(zone)) {
     }
 
-    void VisitFunction(const Function& function) {
+    void Visit(const Function& function) {
       if (!function.HasCode()) {
         ASSERT(function.HasImplicitClosureFunction());
         return;
@@ -1959,6 +2015,25 @@
   VisitFunctions(&visitor);
 }
 
+
+void Precompiler::VisitClasses(ClassVisitor* visitor) {
+  Library& lib = Library::Handle(Z);
+  Class& cls = Class::Handle(Z);
+
+  for (intptr_t i = 0; i < libraries_.Length(); i++) {
+    lib ^= libraries_.At(i);
+    ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
+    while (it.HasNext()) {
+      cls = it.GetNextClass();
+      if (cls.IsDynamicClass()) {
+        continue;  // class 'dynamic' is in the read-only VM isolate.
+      }
+      visitor->Visit(cls);
+    }
+  }
+}
+
+
 void Precompiler::VisitFunctions(FunctionVisitor* visitor) {
   Library& lib = Library::Handle(Z);
   Class& cls = Class::Handle(Z);
@@ -1981,10 +2056,10 @@
       functions = cls.functions();
       for (intptr_t j = 0; j < functions.Length(); j++) {
         function ^= functions.At(j);
-        visitor->VisitFunction(function);
+        visitor->Visit(function);
         if (function.HasImplicitClosureFunction()) {
           function = function.ImplicitClosureFunction();
-          visitor->VisitFunction(function);
+          visitor->Visit(function);
         }
       }
 
@@ -1993,7 +2068,7 @@
         object = functions.At(j);
         if (object.IsFunction()) {
           function ^= functions.At(j);
-          visitor->VisitFunction(function);
+          visitor->Visit(function);
         }
       }
       fields = cls.fields();
@@ -2001,7 +2076,7 @@
         field ^= fields.At(j);
         if (field.is_static() && field.HasPrecompiledInitializer()) {
           function ^= field.PrecompiledInitializer();
-          visitor->VisitFunction(function);
+          visitor->Visit(function);
         }
       }
     }
@@ -2009,7 +2084,7 @@
   closures = isolate()->object_store()->closure_functions();
   for (intptr_t j = 0; j < closures.Length(); j++) {
     function ^= closures.At(j);
-    visitor->VisitFunction(function);
+    visitor->Visit(function);
     ASSERT(!function.HasImplicitClosureFunction());
   }
 }
@@ -2595,7 +2670,7 @@
                                   "CompileGraph");
 #endif  // !PRODUCT
         graph_compiler.CompileGraph();
-        pipeline->FinalizeCompilation();
+        pipeline->FinalizeCompilation(flow_graph);
       }
       {
 #ifndef PRODUCT
diff --git a/runtime/vm/precompiler.h b/runtime/vm/precompiler.h
index 5b6c7ac..6ec2ed3 100644
--- a/runtime/vm/precompiler.h
+++ b/runtime/vm/precompiler.h
@@ -265,27 +265,18 @@
       Dart_QualifiedFunctionName embedder_entry_points[],
       bool reset_fields);
 
-  // Returns named function that is a unique dynamic target, i.e.,
-  // - the target is identified by its name alone, since it occurs only once.
-  // - target's class has no subclasses, and neither is subclassed, i.e.,
-  //   the receiver type can be only the function's class.
-  // Returns Function::null() if there is no unique dynamic target for
-  // given 'fname'. 'fname' must be a symbol.
-  static void GetUniqueDynamicTarget(Isolate* isolate,
-                                     const String& fname,
-                                     Object* function);
-
   static RawError* CompileFunction(Thread* thread, const Function& function);
 
   static RawObject* EvaluateStaticInitializer(const Field& field);
   static RawObject* ExecuteOnce(SequenceNode* fragment);
 
+  static RawFunction* CompileStaticInitializer(const Field& field,
+                                               bool compute_type);
+
  private:
   Precompiler(Thread* thread, bool reset_fields);
 
 
-  static RawFunction* CompileStaticInitializer(const Field& field);
-
   void DoCompileAll(Dart_QualifiedFunctionName embedder_entry_points[]);
   void ClearAllCode();
   void AddRoots(Dart_QualifiedFunctionName embedder_entry_points[]);
@@ -327,13 +318,19 @@
 
   void CollectDynamicFunctionNames();
 
-  class FunctionVisitor : public ValueObject {
+  void PrecompileStaticInitializers();
+
+  template<typename T>
+  class Visitor : public ValueObject {
    public:
-    virtual ~FunctionVisitor() {}
-    virtual void VisitFunction(const Function& function) = 0;
+    virtual ~Visitor() {}
+    virtual void Visit(const T& obj) = 0;
   };
+  typedef Visitor<Function> FunctionVisitor;
+  typedef Visitor<Class> ClassVisitor;
 
   void VisitFunctions(FunctionVisitor* visitor);
+  void VisitClasses(ClassVisitor* visitor);
 
   void FinalizeAllClasses();
 
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index 4d5c4a5..195149f 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -19,6 +19,7 @@
 DECLARE_FLAG(int, max_profile_depth);
 DECLARE_FLAG(int, profile_period);
 DECLARE_FLAG(bool, show_invisible_frames);
+DECLARE_FLAG(bool, profile_vm);
 
 #ifndef PRODUCT
 
@@ -1375,6 +1376,8 @@
         ASSERT(code != NULL);
         code->Tick(pc, IsExecutingFrame(sample, frame_index), sample_index);
       }
+
+      TickExitFrame(sample->vm_tag(), sample_index);
     }
     SanitizeMinMaxTimes();
   }
@@ -1490,6 +1493,10 @@
         current = current->GetChild(index);
         current->Tick();
       }
+
+      if (!sample->first_frame_executing()) {
+        current = AppendExitFrame(sample->vm_tag(), current);
+      }
     }
   }
 
@@ -1510,6 +1517,10 @@
 
       ResetKind();
 
+      if (!sample->first_frame_executing()) {
+        current = AppendExitFrame(sample->vm_tag(), current);
+      }
+
       // Walk the sampled PCs.
       Code& code = Code::Handle();
       for (intptr_t frame_index = 0;
@@ -1582,6 +1593,10 @@
         current = ProcessFrame(current, sample_index, sample, frame_index);
       }
 
+      if (!sample->first_frame_executing()) {
+        current = AppendExitFrame(sample->vm_tag(), current);
+      }
+
       sample->set_timeline_trie(current);
     }
   }
@@ -1604,6 +1619,10 @@
 
       ResetKind();
 
+      if (!sample->first_frame_executing()) {
+        current = AppendExitFrame(sample->vm_tag(), current);
+      }
+
       // Walk the sampled PCs.
       for (intptr_t frame_index = 0;
            frame_index < sample->length();
@@ -1612,6 +1631,8 @@
         current = ProcessFrame(current, sample_index, sample, frame_index);
       }
 
+      TickExitFrameFunction(sample->vm_tag(), sample_index);
+
       // Truncated tag.
       if (sample->truncated()) {
         current = AppendTruncatedTag(current);
@@ -1750,7 +1771,8 @@
     }
     // Only tick the first frame's node, if we are executing OR
     // vm tags have been emitted.
-    return IsExecutingFrame(sample, frame_index) || vm_tags_emitted();
+    return IsExecutingFrame(sample, frame_index) ||
+           !FLAG_profile_vm || vm_tags_emitted();
   }
 
   ProfileFunctionTrieNode* ProcessFunction(ProfileFunctionTrieNode* current,
@@ -1912,31 +1934,89 @@
     return current;
   }
 
+  void TickExitFrame(uword vm_tag, intptr_t serial) {
+    if (FLAG_profile_vm) {
+      return;
+    }
+    if (!VMTag::IsExitFrameTag(vm_tag)) {
+      return;
+    }
+    ProfileCodeTable* tag_table = profile_->tag_code_;
+    ProfileCode* code = tag_table->FindCodeForPC(vm_tag);
+    ASSERT(code != NULL);
+    code->Tick(vm_tag, true, serial);
+  }
+
+  void TickExitFrameFunction(uword vm_tag, intptr_t serial) {
+    if (FLAG_profile_vm) {
+      return;
+    }
+    if (!VMTag::IsExitFrameTag(vm_tag)) {
+      return;
+    }
+    ProfileCodeTable* tag_table = profile_->tag_code_;
+    ProfileCode* code = tag_table->FindCodeForPC(vm_tag);
+    ASSERT(code != NULL);
+    ProfileFunction* function = code->function();
+    ASSERT(function != NULL);
+    function->Tick(true, serial, TokenPosition::kNoSource);
+  }
+
+  ProfileCodeTrieNode* AppendExitFrame(uword vm_tag,
+                                       ProfileCodeTrieNode* current) {
+    if (FLAG_profile_vm) {
+      return current;
+    }
+
+    if (!VMTag::IsExitFrameTag(vm_tag)) {
+      return current;
+    }
+
+    if (VMTag::IsNativeEntryTag(vm_tag) ||
+        VMTag::IsRuntimeEntryTag(vm_tag)) {
+      current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current);
+    } else {
+      intptr_t tag_index = GetProfileCodeTagIndex(vm_tag);
+      current = current->GetChild(tag_index);
+      // Give the tag a tick.
+      current->Tick();
+    }
+    return current;
+  }
+
   ProfileCodeTrieNode* AppendTags(uword vm_tag,
                                   uword user_tag,
                                   ProfileCodeTrieNode* current) {
-    // None.
+    if (FLAG_profile_vm) {
+      // None.
+      if (tag_order() == Profile::kNoTags) {
+        return current;
+      }
+      // User first.
+      if ((tag_order() == Profile::kUserVM) ||
+          (tag_order() == Profile::kUser)) {
+        current = AppendUserTag(user_tag, current);
+        // Only user.
+        if (tag_order() == Profile::kUser) {
+          return current;
+        }
+        return AppendVMTags(vm_tag, current);
+      }
+      // VM first.
+      ASSERT((tag_order() == Profile::kVMUser) ||
+             (tag_order() == Profile::kVM));
+      current = AppendVMTags(vm_tag, current);
+      // Only VM.
+      if (tag_order() == Profile::kVM) {
+        return current;
+      }
+      return AppendUserTag(user_tag, current);
+    }
+
     if (tag_order() == Profile::kNoTags) {
       return current;
     }
-    // User first.
-    if ((tag_order() == Profile::kUserVM) ||
-        (tag_order() == Profile::kUser)) {
-      current = AppendUserTag(user_tag, current);
-      // Only user.
-      if (tag_order() == Profile::kUser) {
-        return current;
-      }
-      return AppendVMTags(vm_tag, current);
-    }
-    // VM first.
-    ASSERT((tag_order() == Profile::kVMUser) ||
-           (tag_order() == Profile::kVM));
-    current = AppendVMTags(vm_tag, current);
-    // Only VM.
-    if (tag_order() == Profile::kVM) {
-      return current;
-    }
+
     return AppendUserTag(user_tag, current);
   }
 
@@ -2031,37 +2111,66 @@
   }
 
   ProfileFunctionTrieNode* AppendVMTags(uword vm_tag,
-                                    ProfileFunctionTrieNode* current) {
+                                        ProfileFunctionTrieNode* current) {
     current = AppendVMTag(vm_tag, current);
     current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current);
     return current;
   }
 
+  ProfileFunctionTrieNode* AppendExitFrame(uword vm_tag,
+                                           ProfileFunctionTrieNode* current) {
+    if (FLAG_profile_vm) {
+      return current;
+    }
+
+    if (!VMTag::IsExitFrameTag(vm_tag)) {
+      return current;
+    }
+    if (VMTag::IsNativeEntryTag(vm_tag) ||
+        VMTag::IsRuntimeEntryTag(vm_tag)) {
+      current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current);
+    } else {
+      intptr_t tag_index = GetProfileFunctionTagIndex(vm_tag);
+      current = current->GetChild(tag_index);
+      // Give the tag a tick.
+      current->Tick();
+    }
+    return current;
+  }
+
   ProfileFunctionTrieNode* AppendTags(uword vm_tag,
                                       uword user_tag,
                                       ProfileFunctionTrieNode* current) {
-    // None.
+    if (FLAG_profile_vm) {
+      // None.
+      if (tag_order() == Profile::kNoTags) {
+        return current;
+      }
+      // User first.
+      if ((tag_order() == Profile::kUserVM) ||
+          (tag_order() == Profile::kUser)) {
+        current = AppendUserTag(user_tag, current);
+        // Only user.
+        if (tag_order() == Profile::kUser) {
+          return current;
+        }
+        return AppendVMTags(vm_tag, current);
+      }
+      // VM first.
+      ASSERT((tag_order() == Profile::kVMUser) ||
+             (tag_order() == Profile::kVM));
+      current = AppendVMTags(vm_tag, current);
+      // Only VM.
+      if (tag_order() == Profile::kVM) {
+        return current;
+      }
+      return AppendUserTag(user_tag, current);
+    }
+
     if (tag_order() == Profile::kNoTags) {
       return current;
     }
-    // User first.
-    if ((tag_order() == Profile::kUserVM) ||
-        (tag_order() == Profile::kUser)) {
-      current = AppendUserTag(user_tag, current);
-      // Only user.
-      if (tag_order() == Profile::kUser) {
-        return current;
-      }
-      return AppendVMTags(vm_tag, current);
-    }
-    // VM first.
-    ASSERT((tag_order() == Profile::kVMUser) ||
-           (tag_order() == Profile::kVM));
-    current = AppendVMTags(vm_tag, current);
-    // Only VM.
-    if (tag_order() == Profile::kVM) {
-      return current;
-    }
+
     return AppendUserTag(user_tag, current);
   }
 
@@ -2334,6 +2443,8 @@
                    static_cast<intptr_t>(FLAG_max_profile_depth));
   obj->AddProperty("sampleCount", sample_count());
   obj->AddProperty("timeSpan", MicrosecondsToSeconds(GetTimeSpan()));
+  obj->AddPropertyTimeMicros("timeOriginMicros", min_time());
+  obj->AddPropertyTimeMicros("timeExtentMicros", GetTimeSpan());
 }
 
 
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index 1ecac9f..4ab49bd 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -21,24 +21,6 @@
 DECLARE_FLAG(bool, enable_inlining_annotations);
 DECLARE_FLAG(int, optimization_counter_threshold);
 
-template<typename T>
-class SetFlagScope : public ValueObject {
- public:
-  SetFlagScope(T* flag, T value)
-      : flag_(flag),
-        original_value_(*flag) {
-    *flag_ = value;
-  }
-
-  ~SetFlagScope() {
-    *flag_ = original_value_;
-  }
-
- private:
-  T* flag_;
-  T original_value_;
-};
-
 // Some tests are written assuming native stack trace profiling is disabled.
 class DisableNativeProfileScope : public ValueObject {
  public:
@@ -281,6 +263,8 @@
     walker.Reset(Profile::kExclusiveCode);
     // Move down from the root.
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("main", walker.CurrentName());
@@ -293,12 +277,16 @@
     EXPECT_STREQ("main", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
+    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
     EXPECT(!walker.Down());
 
     // Exclusive function: B.boo -> main.
     walker.Reset(Profile::kExclusiveFunction);
     // Move down from the root.
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("main", walker.CurrentName());
@@ -311,6 +299,8 @@
     EXPECT_STREQ("main", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
+    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
     EXPECT(!walker.Down());
   }
 
@@ -395,6 +385,8 @@
     walker.Reset(Profile::kExclusiveCode);
     // Move down from the root.
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("main", walker.CurrentName());
@@ -407,12 +399,16 @@
     EXPECT_STREQ("main", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
+    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
     EXPECT(!walker.Down());
 
     // Exclusive function: boo -> main.
     walker.Reset(Profile::kExclusiveFunction);
     // Move down from the root.
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("main", walker.CurrentName());
@@ -425,6 +421,8 @@
     EXPECT_STREQ("main", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
+    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
     EXPECT(!walker.Down());
   }
 
@@ -514,6 +512,8 @@
     walker.Reset(Profile::kExclusiveCode);
     // Move down from the root.
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
     EXPECT_EQ(3, walker.CurrentNodeTickCount());
     EXPECT_EQ(3, walker.CurrentInclusiveTicks());
@@ -538,6 +538,8 @@
     EXPECT_EQ(3, walker.CurrentNodeTickCount());
     EXPECT_EQ(3, walker.CurrentInclusiveTicks());
     EXPECT_EQ(3, walker.CurrentExclusiveTicks());
+    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
     EXPECT(!walker.Down());
   }
 }
@@ -609,6 +611,8 @@
     walker.Reset(Profile::kExclusiveFunction);
     // Move down from the root.
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
     EXPECT_EQ(3, walker.CurrentNodeTickCount());
     EXPECT_EQ(3, walker.CurrentInclusiveTicks());
@@ -633,6 +637,8 @@
     EXPECT_EQ(3, walker.CurrentNodeTickCount());
     EXPECT_EQ(3, walker.CurrentInclusiveTicks());
     EXPECT_EQ(3, walker.CurrentExclusiveTicks());
+    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
     EXPECT(!walker.Down());
   }
 }
@@ -682,6 +688,8 @@
 
     walker.Reset(Profile::kExclusiveCode);
     EXPECT(walker.Down());
+    EXPECT_STREQ("Double_add", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("_Double._add", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("_Double.+", walker.CurrentName());
@@ -750,6 +758,8 @@
 
     walker.Reset(Profile::kExclusiveCode);
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateArray", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("_List._List", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("List.List", walker.CurrentName());
@@ -798,6 +808,8 @@
 
     walker.Reset(Profile::kExclusiveCode);
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateArray", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("_List._List", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("_GrowableList._GrowableList", walker.CurrentName());
@@ -857,6 +869,8 @@
 
     walker.Reset(Profile::kExclusiveCode);
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateContext", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("foo", walker.CurrentName());
     EXPECT(!walker.Down());
   }
@@ -921,6 +935,8 @@
 
     walker.Reset(Profile::kExclusiveCode);
     EXPECT(walker.Down());
+    EXPECT_SUBSTRING("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_SUBSTRING("foo", walker.CurrentName());
     EXPECT(!walker.Down());
   }
@@ -992,6 +1008,8 @@
 
     walker.Reset(Profile::kExclusiveCode);
     EXPECT(walker.Down());
+    EXPECT_STREQ("TypedData_Float32Array_new", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("Float32List.Float32List", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("foo", walker.CurrentName());
@@ -1072,6 +1090,8 @@
 
     walker.Reset(Profile::kExclusiveCode);
     EXPECT(walker.Down());
+    EXPECT_STREQ("String_concat", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("_StringBase.+", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("foo", walker.CurrentName());
@@ -1153,6 +1173,8 @@
 
     walker.Reset(Profile::kExclusiveCode);
     EXPECT(walker.Down());
+    EXPECT_STREQ("OneByteString_allocate", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("_OneByteString._allocate", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("_OneByteString._concatAll", walker.CurrentName());
@@ -1272,6 +1294,8 @@
     // We have two code objects: mainA and B.boo.
     walker.Reset(Profile::kExclusiveCode);
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
     EXPECT_EQ(1, walker.SiblingCount());
     EXPECT_EQ(50000, walker.CurrentNodeTickCount());
@@ -1298,12 +1322,16 @@
     EXPECT_EQ(50000, walker.CurrentNodeTickCount());
     EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
     EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
+    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
     EXPECT(!walker.Down());
 
     // Inline expansion should show us the complete call chain:
     // mainA -> B.boo -> B.foo -> B.choo.
     walker.Reset(Profile::kExclusiveFunction);
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("B.choo", walker.CurrentName());
     EXPECT_EQ(1, walker.SiblingCount());
     EXPECT_EQ(50000, walker.CurrentNodeTickCount());
@@ -1356,6 +1384,8 @@
     EXPECT_EQ(50000, walker.CurrentNodeTickCount());
     EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
     EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
+    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
     EXPECT(!walker.Down());
   }
 
@@ -1377,6 +1407,8 @@
     // We have two code objects: mainA and B.boo.
     walker.Reset(Profile::kExclusiveCode);
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
@@ -1395,12 +1427,16 @@
     EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
+    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
     EXPECT(!walker.Down());
 
     // Inline expansion should show us the complete call chain:
     // mainA -> B.boo -> B.foo -> B.choo.
     walker.Reset(Profile::kExclusiveFunction);
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("[Inline End]", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("B.choo", walker.CurrentName());
@@ -1437,6 +1473,8 @@
     EXPECT_STREQ("B.choo", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("[Inline End]", walker.CurrentName());
+    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
     EXPECT(!walker.Down());
   }
 }
@@ -1545,6 +1583,8 @@
     // Inline expansion should show us the complete call chain:
     walker.Reset(Profile::kExclusiveFunction);
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("maybeAlloc", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("right", walker.CurrentName());
@@ -1564,6 +1604,8 @@
     EXPECT_STREQ("right", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("maybeAlloc", walker.CurrentName());
+    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
     EXPECT(!walker.Down());
   }
 }
@@ -1635,6 +1677,8 @@
     walker.Reset(Profile::kExclusiveCode);
     // Move down from the root.
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("orange", walker.CurrentName());
@@ -1734,6 +1778,8 @@
     walker.Reset(Profile::kExclusiveFunction);
     // Move down from the root.
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
     EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
@@ -1824,6 +1870,8 @@
     walker.Reset(Profile::kExclusiveFunction);
     // Move down from the root.
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
     EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
@@ -1907,6 +1955,8 @@
     walker.Reset(Profile::kExclusiveFunction);
     // Move down from the root.
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
     EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
@@ -2028,6 +2078,8 @@
     walker.Reset(Profile::kExclusiveFunction);
     // Move down from the root.
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
     EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
@@ -2132,6 +2184,8 @@
     walker.Reset(Profile::kExclusiveFunction);
     // Move down from the root.
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
     EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
@@ -2262,6 +2316,8 @@
     walker.Reset(Profile::kExclusiveFunction);
     // Move down from the root.
     EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+    EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
     EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 98553cd..cc880e9 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -181,16 +181,15 @@
       // Get the (constant) instance size out of the class object.
       // TODO(koda): Add Size(ClassTable*) interface to allow caching in loops.
       Isolate* isolate = Isolate::Current();
-      ClassTable* class_table = isolate->class_table();
 #if defined(DEBUG)
+      ClassTable* class_table = isolate->class_table();
       if (!class_table->IsValidIndex(class_id) ||
           !class_table->HasValidClassAt(class_id)) {
         FATAL2("Invalid class id: %" Pd " from tags %" Px "\n",
                class_id, ptr()->tags_);
       }
 #endif  // DEBUG
-      RawClass* raw_class = class_table->At(class_id);
-      ASSERT(raw_class->ptr()->id_ == class_id);
+      RawClass* raw_class = isolate->GetClassForHeapWalkAt(class_id);
       instance_size =
           raw_class->ptr()->instance_size_in_words_ << kWordSizeLog2;
     }
@@ -713,7 +712,7 @@
   intptr_t instance_size = SizeTag::decode(tags);
   if (instance_size == 0) {
     RawClass* cls =
-        visitor->isolate()->class_table()->At(raw_obj->GetClassId());
+        visitor->isolate()->GetClassForHeapWalkAt(raw_obj->GetClassId());
     instance_size = cls->ptr()->instance_size_in_words_ << kWordSizeLog2;
   }
 
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 977ba55..ef5924e 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -625,6 +625,7 @@
   friend class Closure;
   friend class Code;
   friend class Double;
+  friend class ForwardPointersVisitor;  // StorePointer
   friend class FreeListElement;
   friend class Function;
   friend class GCMarker;
@@ -697,9 +698,8 @@
   RawAbstractType* super_type_;
   RawType* mixin_;  // Generic mixin type, e.g. M<T>, not M<int>.
   RawFunction* signature_function_;  // Associated function for typedef class.
-  RawArray* constants_;  // Canonicalized values of this class.
-  RawObject* canonical_types_;  // An array of canonicalized types of this class
-                                // or the canonical type.
+  RawArray* constants_;  // Canonicalized const instances of this class.
+  RawType* canonical_type_;  // Canonical type for this class.
   RawArray* invocation_dispatcher_cache_;  // Cache for dispatcher functions.
   RawCode* allocation_stub_;  // Stub code for allocation of instances.
   RawGrowableObjectArray* direct_subclasses_;  // Array of Class.
@@ -735,6 +735,7 @@
   uint16_t state_bits_;
 
   friend class Instance;
+  friend class Isolate;
   friend class Object;
   friend class RawInstance;
   friend class RawInstructions;
@@ -771,6 +772,8 @@
   // Instantiations leading to bound errors do not get cached.
   RawSmi* length_;
 
+  RawSmi* hash_;
+
   // Variable length data follows here.
   RawAbstractType* const* types() const {
     OPEN_ARRAY_START(RawAbstractType*, RawAbstractType*);
@@ -1038,6 +1041,7 @@
   int32_t line_offset_;
   int32_t col_offset_;
   int8_t kind_;  // Of type Kind.
+  int64_t load_timestamp_;
 };
 
 
@@ -1683,10 +1687,12 @@
   RAW_HEAP_OBJECT_IMPLEMENTATION(Type);
 
   RawObject** from() {
-    return reinterpret_cast<RawObject**>(&ptr()->type_class_);
+    return reinterpret_cast<RawObject**>(&ptr()->type_class_id_);
   }
-  RawObject* type_class_;  // Either resolved class or unresolved class.
+  // Either the id of the resolved class as a Smi or an UnresolvedClass.
+  RawObject* type_class_id_;
   RawTypeArguments* arguments_;
+  RawSmi* hash_;
   // This type object represents a function type if its signature field is a
   // non-null function object.
   // If this type is malformed or malbounded, the signature field gets
@@ -1724,12 +1730,13 @@
   RAW_HEAP_OBJECT_IMPLEMENTATION(TypeParameter);
 
   RawObject** from() {
-    return reinterpret_cast<RawObject**>(&ptr()->parameterized_class_);
+    return reinterpret_cast<RawObject**>(&ptr()->name_);
   }
-  RawClass* parameterized_class_;
   RawString* name_;
+  RawSmi* hash_;
   RawAbstractType* bound_;  // ObjectType if no explicit bound specified.
   RawObject** to() { return reinterpret_cast<RawObject**>(&ptr()->bound_); }
+  classid_t parameterized_class_id_;
   TokenPosition token_pos_;
   int16_t index_;
   int8_t type_state_;
@@ -1745,6 +1752,7 @@
   }
   RawAbstractType* type_;
   RawAbstractType* bound_;
+  RawSmi* hash_;
   RawTypeParameter* type_parameter_;  // For more detailed error reporting.
   RawObject** to() {
     return reinterpret_cast<RawObject**>(&ptr()->type_parameter_);
@@ -1760,6 +1768,7 @@
     return reinterpret_cast<RawObject**>(&ptr()->super_type_);
   }
   RawAbstractType* super_type_;
+  RawSmi* hash_;
   RawArray* mixin_types_;  // Array of AbstractType.
   RawObject** to() {
     return reinterpret_cast<RawObject**>(&ptr()->mixin_types_);
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 196e145..5f5a15c 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -12,6 +12,8 @@
 
 namespace dart {
 
+DECLARE_FLAG(bool, remove_script_timestamps_for_test);
+
 #define NEW_OBJECT(type)                                                       \
   ((Snapshot::IsFull(kind)) ? reader->New##type() : type::New())
 
@@ -59,7 +61,7 @@
         ASSERT((class_id >= kInstanceCid) && (class_id <= kMirrorReferenceCid));
         cls = reader->isolate()->class_table()->At(class_id);
       } else {
-        cls = New<Instance>(kIllegalCid);
+        cls = Class::NewInstanceClass();
       }
     }
     reader->AddBackRef(object_id, &cls, kIsDeserialized);
@@ -239,6 +241,11 @@
   // Set all the object fields.
   READ_OBJECT_FIELDS(type, type.raw()->from(), type.raw()->to(), kAsReference);
 
+  // Read in the type class.
+  (*reader->ClassHandle()) =
+      Class::RawCast(reader->ReadObjectImpl(kAsReference));
+  type.set_type_class(*reader->ClassHandle());
+
   // Set the canonical bit.
   if (!defer_canonicalization && is_canonical) {
     type.SetCanonical();
@@ -257,7 +264,7 @@
   // Only resolved and finalized types should be written to a snapshot.
   ASSERT((ptr()->type_state_ == RawType::kFinalizedInstantiated) ||
          (ptr()->type_state_ == RawType::kFinalizedUninstantiated));
-  ASSERT(ptr()->type_class_ != Object::null());
+  ASSERT(ptr()->type_class_id_ != Object::null());
 
   // Write out the serialization header value for this object.
   writer->WriteInlinedObjectHeader(object_id);
@@ -266,12 +273,17 @@
   writer->WriteIndexedObject(kTypeCid);
   writer->WriteTags(writer->GetObjectTags(this));
 
+  // Lookup the type class.
+  RawSmi* raw_type_class_id = Smi::RawCast(ptr()->type_class_id_);
+  RawClass* type_class =
+      writer->isolate()->class_table()->At(Smi::Value(raw_type_class_id));
+
   // Write out typeclass_is_in_fullsnapshot first as this will
   // help the reader decide on how to canonicalize the type object.
-  intptr_t tags = writer->GetObjectTags(ptr()->type_class_);
+  intptr_t tags = writer->GetObjectTags(type_class);
   bool typeclass_is_in_fullsnapshot =
       (ClassIdTag::decode(tags) == kClassCid) &&
-      Class::IsInFullSnapshot(reinterpret_cast<RawClass*>(ptr()->type_class_));
+      Class::IsInFullSnapshot(reinterpret_cast<RawClass*>(type_class));
   writer->Write<bool>(typeclass_is_in_fullsnapshot);
 
   // Write out all the non object pointer fields.
@@ -279,9 +291,12 @@
   writer->Write<int8_t>(ptr()->type_state_);
 
   // Write out all the object pointer fields.
-  ASSERT(ptr()->type_class_ != Object::null());
+  ASSERT(ptr()->type_class_id_ != Object::null());
   SnapshotWriterVisitor visitor(writer, kAsReference);
   visitor.VisitPointers(from(), to());
+
+  // Write out the type class.
+  writer->WriteObjectImpl(type_class, kAsReference);
 }
 
 
@@ -348,6 +363,11 @@
                      type_parameter.raw()->from(), type_parameter.raw()->to(),
                      kAsReference);
 
+  // Read in the parameterized class.
+  (*reader->ClassHandle()) =
+      Class::RawCast(reader->ReadObjectImpl(kAsReference));
+  type_parameter.set_parameterized_class(*reader->ClassHandle());
+
   return type_parameter.raw();
 }
 
@@ -376,6 +396,11 @@
   // Write out all the object pointer fields.
   SnapshotWriterVisitor visitor(writer, kAsReference);
   visitor.VisitPointers(from(), to());
+
+  // Write out the parameterized class.
+  RawClass* param_class =
+      writer->isolate()->class_table()->At(ptr()->parameterized_class_id_);
+  writer->WriteObjectImpl(param_class, kAsReference);
 }
 
 
@@ -1101,6 +1126,9 @@
                         reader->PassiveObjectHandle()->raw());
   }
 
+  script.set_load_timestamp(FLAG_remove_script_timestamps_for_test
+                            ? 0 : OS::GetCurrentTimeMillis());
+
   return script.raw();
 }
 
diff --git a/runtime/vm/regexp_assembler_bytecode.cc b/runtime/vm/regexp_assembler_bytecode.cc
index 9586aea..986c0e3 100644
--- a/runtime/vm/regexp_assembler_bytecode.cc
+++ b/runtime/vm/regexp_assembler_bytecode.cc
@@ -12,6 +12,7 @@
 #include "vm/regexp.h"
 #include "vm/regexp_parser.h"
 #include "vm/regexp_interpreter.h"
+#include "vm/timeline.h"
 
 namespace dart {
 
@@ -460,6 +461,13 @@
 
   if (regexp.bytecode(is_one_byte) == TypedData::null()) {
     const String& pattern = String::Handle(zone, regexp.pattern());
+    NOT_IN_PRODUCT(TimelineDurationScope tds(Thread::Current(),
+                                             Timeline::GetCompilerStream(),
+                                             "CompileIrregexpBytecode");
+    if (tds.enabled()) {
+      tds.SetNumArguments(1);
+      tds.CopyArgument(0, "pattern", pattern.ToCString());
+    });  // !PRODUCT
 
     const bool multiline = regexp.is_multi_line();
     RegExpCompileData* compile_data = new(zone) RegExpCompileData();
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index b8d043b..a082636 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -17,8 +17,9 @@
   Thread* thread = Thread::Current();
   const String& class_name = String::Handle(Symbols::New(thread, "ownerClass"));
   const Script& script = Script::Handle();
+  const Library& lib = Library::Handle(Library::CoreLibrary());
   const Class& owner_class =
-      Class::Handle(Class::New(class_name, script,
+      Class::Handle(Class::New(lib, class_name, script,
                                TokenPosition::kNoSource));
   const String& function_name = String::ZoneHandle(Symbols::New(thread, name));
   const Function& function = Function::ZoneHandle(
@@ -34,7 +35,6 @@
   const Array& functions = Array::Handle(Array::New(1));
   functions.SetAt(0, function);
   owner_class.SetFunctions(functions);
-  Library& lib = Library::Handle(Library::CoreLibrary());
   lib.AddClass(owner_class);
   function.AttachCode(code);
   return function;
diff --git a/runtime/vm/scanner.cc b/runtime/vm/scanner.cc
index 4b1e550..f7ae4ac 100644
--- a/runtime/vm/scanner.cc
+++ b/runtime/vm/scanner.cc
@@ -15,9 +15,6 @@
 
 namespace dart {
 
-DEFINE_FLAG(bool, print_tokens, false, "Print scanned tokens.");
-
-
 // Quick access to the locally defined zone() and thread() methods.
 #define Z (zone())
 #define T (thread())
@@ -181,23 +178,29 @@
 }
 
 
-// This method is used when parsing integers and doubles in Dart code. We
+// This method is used when parsing integers in Dart code. We
 // are reusing the Scanner's handling of number literals in that situation.
-bool Scanner::IsValidLiteral(const Scanner::GrowableTokenStream& tokens,
-                             Token::Kind literal_kind,
+bool Scanner::IsValidInteger(const String& str,
                              bool* is_positive,
                              const String** value) {
-  if ((tokens.length() == 2) &&
-      (tokens[0].kind == literal_kind) &&
+  Scanner s(str, Symbols::Empty());
+  TokenDescriptor tokens[3];
+  s.Scan();
+  tokens[0] = s.current_token();
+  s.Scan();
+  tokens[1] = s.current_token();
+  s.Scan();
+  tokens[2] = s.current_token();
+
+  if ((tokens[0].kind == Token::kINTEGER) &&
       (tokens[1].kind == Token::kEOS)) {
     *is_positive = true;
     *value = tokens[0].literal;
     return true;
   }
-  if ((tokens.length() == 3) &&
-      ((tokens[0].kind == Token::kADD) ||
+  if (((tokens[0].kind == Token::kADD) ||
        (tokens[0].kind == Token::kSUB)) &&
-      (tokens[1].kind == literal_kind) &&
+      (tokens[1].kind == Token::kINTEGER) &&
       (tokens[2].kind == Token::kEOS)) {
     // Check there is no space between "+/-" and number.
     if ((tokens[0].offset + 1) != tokens[1].offset) {
@@ -886,85 +889,58 @@
 }
 
 
-void Scanner::ScanAll(GrowableTokenStream* token_stream) {
+void Scanner::ScanAll(TokenCollector* collector) {
   Reset();
   do {
     Scan();
-
     bool inserted_new_lines = false;
     for (intptr_t diff = current_token_.position.line - prev_token_line_;
          diff > 0;
          diff--) {
       newline_token_.position.line = current_token_.position.line - diff;
-      token_stream->Add(newline_token_);
+      collector->AddToken(newline_token_);
       inserted_new_lines = true;
     }
-
     if (inserted_new_lines &&
         ((current_token_.kind == Token::kINTERPOL_VAR) ||
          (current_token_.kind == Token::kINTERPOL_START))) {
-      // NOTE: If this changes, be sure to update
-      // Script::GenerateLineNumberArray to stay in sync.
-      empty_string_token_.position.line = current_token_.position.line;
-      token_stream->Add(empty_string_token_);
-    }
-    token_stream->Add(current_token_);
+          // NOTE: If this changes, be sure to update
+          // Script::GenerateLineNumberArray to stay in sync.
+          empty_string_token_.position.line = current_token_.position.line;
+          collector->AddToken(empty_string_token_);
+        }
+    collector->AddToken(current_token_);
     prev_token_line_ = current_token_.position.line;
   } while (current_token_.kind != Token::kEOS);
 }
 
 
-void Scanner::ScanTo(TokenPosition token_index) {
-  TokenPosition index = TokenPosition::kMinSource;
+void Scanner::ScanTo(intptr_t token_index) {
+  ASSERT(token_index >= 0);
+  intptr_t index = 0;
   Reset();
   do {
     Scan();
-
     bool inserted_new_lines = false;
     for (intptr_t diff = current_token_.position.line - prev_token_line_;
          diff > 0;
          diff--) {
       // Advance the index to account for tokens added in ScanAll.
-      index.Next();
+      index++;
       inserted_new_lines = true;
     }
-
     if (inserted_new_lines &&
         ((current_token_.kind == Token::kINTERPOL_VAR) ||
          (current_token_.kind == Token::kINTERPOL_START))) {
           // Advance the index to account for tokens added in ScanAll.
-          index.Next();
+          index++;
     }
-    index.Next();
+    index++;
     prev_token_line_ = current_token_.position.line;
   } while ((token_index >= index) && (current_token_.kind != Token::kEOS));
 }
 
 
-const Scanner::GrowableTokenStream& Scanner::GetStream() {
-  GrowableTokenStream* ts = new(Z) GrowableTokenStream(128);
-  ScanAll(ts);
-  if (FLAG_print_tokens) {
-    Scanner::PrintTokens(*ts);
-  }
-  return *ts;
-}
-
-
-void Scanner::PrintTokens(const GrowableTokenStream& ts) {
-  int currentLine = -1;
-  for (int i = 0; i < ts.length(); i++) {
-    const TokenDescriptor& td = ts[i];
-    if (currentLine != td.position.line) {
-      currentLine = td.position.line;
-      OS::Print("\n%d (%d): ", currentLine, i);
-    }
-    OS::Print("%s ", Token::Name(td.kind));
-  }
-  OS::Print("\n");
-}
-
-
 void Scanner::InitOnce() {
   ASSERT(Isolate::Current() == Dart::vm_isolate());
   for (int i = 0; i < kNumLowercaseChars; i++) {
diff --git a/runtime/vm/scanner.h b/runtime/vm/scanner.h
index 8d5c6d5..30bc81e 100644
--- a/runtime/vm/scanner.h
+++ b/runtime/vm/scanner.h
@@ -11,7 +11,6 @@
 
 #include "vm/growable_array.h"
 #include "vm/token.h"
-#include "vm/token_position.h"
 
 namespace dart {
 
@@ -23,7 +22,7 @@
 class String;
 
 // A call to Scan() scans the source one token at at time.
-// The scanned token is returned by cur_token().
+// The scanned token is returned by current_token().
 // GetStream() scans the entire source text and returns a stream of tokens.
 class Scanner : ValueObject {
  public:
@@ -45,7 +44,14 @@
     const String* literal;    // Identifier, number or string literal.
   };
 
-  typedef ZoneGrowableArray<TokenDescriptor> GrowableTokenStream;
+  class TokenCollector : public ValueObject {
+   public:
+    TokenCollector() { }
+    virtual ~TokenCollector() { }
+    virtual void AddToken(const TokenDescriptor& token) { }
+   private:
+    DISALLOW_COPY_AND_ASSIGN(TokenCollector);
+  };
 
   // Initializes scanner to scan string source.
   Scanner(const String& source, const String& private_key);
@@ -54,13 +60,12 @@
   // Scans one token at a time.
   void Scan();
 
-  // Scans to specified token position.
-  // Use CurrentPosition() to extract position.
-  void ScanTo(TokenPosition token_index);
+  // Scans the entire source and collects tokens in the provided collector.
+  void ScanAll(TokenCollector* collector);
 
-  // Scans entire source and returns a stream of tokens.
-  // Should be called only once.
-  const GrowableTokenStream& GetStream();
+  // Scans to specified token position.
+  // Use CurrentPosition() to extract line and column number.
+  void ScanTo(intptr_t token_index);
 
   // Info about most recently recognized token.
   const TokenDescriptor& current_token() const { return current_token_; }
@@ -78,10 +83,8 @@
   // Return true if str is an identifier.
   bool IsIdent(const String& str);
 
-  // Does the token stream contain a valid literal. This is used to implement
-  // the Dart methods int.parse and double.parse.
-  static bool IsValidLiteral(const Scanner::GrowableTokenStream& tokens,
-                             Token::Kind literal_kind,
+  // Does the token stream contain a valid integer literal.
+  static bool IsValidInteger(const String& str,
                              bool* is_positive,
                              const String** value);
 
@@ -116,9 +119,6 @@
 
   void ErrorMsg(const char* msg);
 
-  // Scans entire source into a given stream of tokens.
-  void ScanAll(GrowableTokenStream* token_stream);
-
   // These functions return true if the given character is a letter,
   // a decimal digit, a hexadecimal digit, etc.
   static bool IsLetter(int32_t c);
@@ -183,8 +183,6 @@
   Thread* thread() const { return thread_; }
   Zone* zone() const { return zone_; }
 
-  static void PrintTokens(const GrowableTokenStream& ts);
-
   TokenDescriptor current_token_;  // Current token.
   TokenDescriptor newline_token_;  // Newline token.
   TokenDescriptor empty_string_token_;  // Token for "".
diff --git a/runtime/vm/scanner_test.cc b/runtime/vm/scanner_test.cc
index 49b8cc4..3d8d70c 100644
--- a/runtime/vm/scanner_test.cc
+++ b/runtime/vm/scanner_test.cc
@@ -10,6 +10,10 @@
 
 namespace dart {
 
+
+typedef ZoneGrowableArray<Scanner::TokenDescriptor> GrowableTokenStream;
+
+
 static void LogTokenDesc(Scanner::TokenDescriptor token) {
   OS::Print("pos %2d:%d-%d token %s  ",
             token.position.line, token.position.column,
@@ -22,7 +26,7 @@
 }
 
 
-static void LogTokenStream(const Scanner::GrowableTokenStream& token_stream) {
+static void LogTokenStream(const GrowableTokenStream& token_stream) {
   int token_index = 0;
   EXPECT_GT(token_stream.length(), 0);
   while (token_index < token_stream.length()) {
@@ -35,7 +39,7 @@
 }
 
 
-static void CheckKind(const Scanner::GrowableTokenStream &token_stream,
+static void CheckKind(const GrowableTokenStream &token_stream,
                int index,
                Token::Kind kind) {
   if (token_stream[index].kind != kind) {
@@ -46,7 +50,7 @@
 }
 
 
-static void CheckLiteral(const Scanner::GrowableTokenStream& token_stream,
+static void CheckLiteral(const GrowableTokenStream& token_stream,
                  int index,
                  const char* literal) {
   if (token_stream[index].literal == NULL) {
@@ -59,7 +63,7 @@
 }
 
 
-static void CheckIdent(const Scanner::GrowableTokenStream& token_stream,
+static void CheckIdent(const GrowableTokenStream& token_stream,
                int index,
                const char* literal) {
   CheckKind(token_stream, index, Token::kIDENT);
@@ -67,7 +71,7 @@
 }
 
 
-static void CheckInteger(const Scanner::GrowableTokenStream& token_stream,
+static void CheckInteger(const GrowableTokenStream& token_stream,
                  int index,
                  const char* literal) {
   CheckKind(token_stream, index, Token::kINTEGER);
@@ -75,7 +79,7 @@
 }
 
 
-static void CheckLineNumber(const Scanner::GrowableTokenStream& token_stream,
+static void CheckLineNumber(const GrowableTokenStream& token_stream,
                      int index,
                      int line_number) {
   if (token_stream[index].position.line != line_number) {
@@ -85,7 +89,7 @@
 }
 
 
-static void CheckNumTokens(const Scanner::GrowableTokenStream& token_stream,
+static void CheckNumTokens(const GrowableTokenStream& token_stream,
                     int index) {
   if (token_stream.length() != index) {
     OS::PrintErr("Expected %d tokens but got only %" Pd ".\n",
@@ -94,19 +98,35 @@
 }
 
 
-static const Scanner::GrowableTokenStream& Scan(const char* source) {
+class Collector : public Scanner::TokenCollector {
+ public:
+  explicit Collector(GrowableTokenStream* ts) : ts_(ts) { }
+  virtual ~Collector() { }
+
+  virtual void AddToken(const Scanner::TokenDescriptor& token) {
+    ts_->Add(token);
+  }
+ private:
+  GrowableTokenStream* ts_;
+};
+
+
+static const GrowableTokenStream& Scan(const char* source) {
+  OS::Print("\nScanning: <%s>\n", source);
+
   Scanner scanner(String::Handle(String::New(source)),
                   String::Handle(String::New("")));
+  GrowableTokenStream* tokens = new GrowableTokenStream(128);
+  Collector collector(tokens);
 
-  OS::Print("\nScanning: <%s>\n", source);
-  const Scanner::GrowableTokenStream& tokens = scanner.GetStream();
-  LogTokenStream(tokens);
-  return tokens;
+  scanner.ScanAll(&collector);
+  LogTokenStream(*tokens);
+  return *tokens;
 }
 
 
 static void BoringTest() {
-  const Scanner::GrowableTokenStream& tokens = Scan("x = iffy++;");
+  const GrowableTokenStream& tokens = Scan("x = iffy++;");
 
   CheckNumTokens(tokens, 6);
   CheckIdent(tokens, 0, "x");
@@ -118,7 +138,7 @@
 
 
 static void CommentTest() {
-  const Scanner::GrowableTokenStream& tokens =
+  const GrowableTokenStream& tokens =
       Scan("Foo( /*block \n"
            "comment*/ 0xff) // line comment;");
 
@@ -135,7 +155,7 @@
 
 static void GreedIsGood() {
   // means i++ + j
-  const Scanner::GrowableTokenStream& tokens = Scan("x=i+++j");
+  const GrowableTokenStream& tokens = Scan("x=i+++j");
 
   CheckNumTokens(tokens, 7);
   CheckIdent(tokens, 0, "x");
@@ -149,7 +169,7 @@
 
 static void StringEscapes() {
   // sss = "\" \\ \n\r\t \'"
-  const Scanner::GrowableTokenStream& tokens =
+  const GrowableTokenStream& tokens =
       Scan("sss = \"\\\" \\\\ \\n\\r\\t \\\'\"");
 
   EXPECT_EQ(4, tokens.length());
@@ -172,70 +192,70 @@
 
 
 static void InvalidStringEscapes() {
-  const Scanner::GrowableTokenStream& high_start_4 =
+  const GrowableTokenStream& high_start_4 =
       Scan("\"\\uD800\"");
   EXPECT_EQ(2, high_start_4.length());
   CheckKind(high_start_4, 0, Token::kERROR);
   EXPECT(high_start_4[0].literal->Equals("invalid code point"));
   CheckKind(high_start_4, 1, Token::kEOS);
 
-  const Scanner::GrowableTokenStream& high_start_seq =
+  const GrowableTokenStream& high_start_seq =
       Scan("\"\\u{D800}\"");
   EXPECT_EQ(2, high_start_seq.length());
   CheckKind(high_start_seq, 0, Token::kERROR);
   EXPECT(high_start_seq[0].literal->Equals("invalid code point"));
   CheckKind(high_start_seq, 1, Token::kEOS);
 
-  const Scanner::GrowableTokenStream& high_end_4 =
+  const GrowableTokenStream& high_end_4 =
       Scan("\"\\uDBFF\"");
   EXPECT_EQ(2, high_end_4.length());
   CheckKind(high_end_4, 0, Token::kERROR);
   EXPECT(high_end_4[0].literal->Equals("invalid code point"));
   CheckKind(high_end_4, 1, Token::kEOS);
 
-  const Scanner::GrowableTokenStream& high_end_seq =
+  const GrowableTokenStream& high_end_seq =
       Scan("\"\\u{DBFF}\"");
   EXPECT_EQ(2, high_end_seq.length());
   CheckKind(high_end_seq, 0, Token::kERROR);
   EXPECT(high_end_seq[0].literal->Equals("invalid code point"));
   CheckKind(high_end_seq, 1, Token::kEOS);
 
-  const Scanner::GrowableTokenStream& low_start_4 =
+  const GrowableTokenStream& low_start_4 =
       Scan("\"\\uDC00\"");
   EXPECT_EQ(2, low_start_4.length());
   CheckKind(low_start_4, 0, Token::kERROR);
   EXPECT(low_start_4[0].literal->Equals("invalid code point"));
   CheckKind(low_start_4, 1, Token::kEOS);
 
-  const Scanner::GrowableTokenStream& low_start_seq =
+  const GrowableTokenStream& low_start_seq =
       Scan("\"\\u{DC00}\"");
   EXPECT_EQ(2, low_start_seq.length());
   CheckKind(low_start_seq, 0, Token::kERROR);
   EXPECT(low_start_seq[0].literal->Equals("invalid code point"));
   CheckKind(low_start_seq, 1, Token::kEOS);
 
-  const Scanner::GrowableTokenStream& low_end_4 =
+  const GrowableTokenStream& low_end_4 =
       Scan("\"\\uDFFF\"");
   EXPECT_EQ(2, low_end_4.length());
   CheckKind(low_end_4, 0, Token::kERROR);
   EXPECT(low_end_4[0].literal->Equals("invalid code point"));
   CheckKind(low_end_4, 1, Token::kEOS);
 
-  const Scanner::GrowableTokenStream& low_end_seq =
+  const GrowableTokenStream& low_end_seq =
       Scan("\"\\u{DFFF}\"");
   EXPECT_EQ(2, low_end_seq.length());
   CheckKind(low_end_seq, 0, Token::kERROR);
   EXPECT(low_end_seq[0].literal->Equals("invalid code point"));
   CheckKind(low_end_seq, 1, Token::kEOS);
 
-  const Scanner::GrowableTokenStream& out_of_range_low =
+  const GrowableTokenStream& out_of_range_low =
       Scan("\"\\u{110000}\"");
   EXPECT_EQ(2, out_of_range_low.length());
   CheckKind(out_of_range_low, 0, Token::kERROR);
   EXPECT(out_of_range_low[0].literal->Equals("invalid code point"));
   CheckKind(out_of_range_low, 1, Token::kEOS);
 
-  const Scanner::GrowableTokenStream& out_of_range_high =
+  const GrowableTokenStream& out_of_range_high =
       Scan("\"\\u{FFFFFF}\"");
   EXPECT_EQ(2, out_of_range_high.length());
   CheckKind(out_of_range_high, 0, Token::kERROR);
@@ -246,7 +266,7 @@
 
 static void RawString() {
   // rs = @"\' \\"
-  const Scanner::GrowableTokenStream& tokens = Scan("rs = r\"\\\' \\\\\"");
+  const GrowableTokenStream& tokens = Scan("rs = r\"\\\' \\\\\"");
 
   EXPECT_EQ(4, tokens.length());
   CheckIdent(tokens, 0, "rs");
@@ -269,7 +289,7 @@
   // |mls = '''
   // |1' x
   // |2''';
-  const Scanner::GrowableTokenStream& tokens = Scan("mls = '''\n1' x\n2''';");
+  const GrowableTokenStream& tokens = Scan("mls = '''\n1' x\n2''';");
 
   EXPECT_EQ(7, tokens.length());
   CheckIdent(tokens, 0, "mls");
@@ -295,7 +315,7 @@
 
 static void EmptyString() {
   // es = "";
-  const Scanner::GrowableTokenStream& tokens = Scan("es = \"\";");
+  const GrowableTokenStream& tokens = Scan("es = \"\";");
 
   EXPECT_EQ(5, tokens.length());
   CheckIdent(tokens, 0, "es");
@@ -308,7 +328,7 @@
 
 static void EmptyMultilineString() {
   // es = """""";
-  const Scanner::GrowableTokenStream& tokens = Scan("es = \"\"\"\"\"\";");
+  const GrowableTokenStream& tokens = Scan("es = \"\"\"\"\"\";");
 
   EXPECT_EQ(5, tokens.length());
   CheckIdent(tokens, 0, "es");
@@ -321,7 +341,7 @@
 
 
 static void NumberLiteral() {
-  const Scanner::GrowableTokenStream& tokens =
+  const GrowableTokenStream& tokens =
       Scan("5 0x5d 0.3 0.33 1E+12 .42 +5");
 
   CheckKind(tokens, 0, Token::kINTEGER);
@@ -401,7 +421,7 @@
 
 
 void InvalidText() {
-  const Scanner::GrowableTokenStream& tokens =
+  const GrowableTokenStream& tokens =
       Scan("\\");
 
   EXPECT_EQ(2, tokens.length());
@@ -419,7 +439,7 @@
       "d\n"
       "\"\"\";";
 
-  const Scanner::GrowableTokenStream& tokens = Scan(source);
+  const GrowableTokenStream& tokens = Scan(source);
 
   EXPECT_EQ(11, tokens.length());
   CheckKind(tokens, 0, Token::kVAR);
diff --git a/runtime/vm/scavenger.cc b/runtime/vm/scavenger.cc
index bcbb79f..2ca7b09 100644
--- a/runtime/vm/scavenger.cc
+++ b/runtime/vm/scavenger.cc
@@ -31,7 +31,6 @@
 DEFINE_FLAG(int, new_gen_garbage_threshold, 90,
             "Grow new gen when less than this percentage is garbage.");
 DEFINE_FLAG(int, new_gen_growth_factor, 4, "Grow new gen by this factor.");
-DECLARE_FLAG(bool, concurrent_sweep);
 
 // Scavenger uses RawObject::kMarkBit to distinguish forwaded and non-forwarded
 // objects. The kMarkBit does not intersect with the target address because of
@@ -526,6 +525,13 @@
     total_count += count;
     while (!pending->IsEmpty()) {
       RawObject* raw_object = pending->Pop();
+      if (raw_object->IsFreeListElement()) {
+        // TODO(rmacnak): Forwarding corpse from become. Probably we should also
+        // visit the store buffer blocks during become, and mark any forwardees
+        // as remembered if their forwarders are remembered to satisfy the
+        // following assert.
+        continue;
+      }
       ASSERT(raw_object->IsRemembered());
       raw_object->ClearRememberedBit();
       visitor->VisitingOldObject(raw_object);
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 197c77f..fc78a48 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -35,6 +35,7 @@
 #include "vm/stack_frame.h"
 #include "vm/symbols.h"
 #include "vm/timeline.h"
+#include "vm/type_table.h"
 #include "vm/unicode.h"
 #include "vm/version.h"
 
@@ -45,6 +46,7 @@
 
 DECLARE_FLAG(bool, trace_service);
 DECLARE_FLAG(bool, trace_service_pause_events);
+DECLARE_FLAG(bool, profile_vm);
 DEFINE_FLAG(charp, vm_name, "vm",
             "The default name of this vm as reported by the VM service "
             "protocol");
@@ -1008,16 +1010,17 @@
 
 
 void Service::HandleEvent(ServiceEvent* event) {
-  if (event->isolate() != NULL &&
-      ServiceIsolate::IsServiceIsolateDescendant(event->isolate())) {
+  if (event->stream_info() != NULL &&
+      !event->stream_info()->enabled()) {
+    if (FLAG_warn_on_pause_with_no_debugger &&
+        event->IsPause()) {
+      // If we are about to pause a running program which has no
+      // debugger connected, tell the user about it.
+      ReportPauseOnConsole(event);
+    }
+    // Ignore events when no one is listening to the event stream.
     return;
   }
-  if (FLAG_warn_on_pause_with_no_debugger &&
-      event->IsPause() && !Service::debug_stream.enabled()) {
-    // If we are about to pause a running program which has no
-    // debugger connected, tell the user about it.
-    ReportPauseOnConsole(event);
-  }
   if (!ServiceIsolate::IsRunning()) {
     return;
   }
@@ -1451,14 +1454,21 @@
     return lib.raw();
   }
   if (strcmp(parts[2], "scripts") == 0) {
-    // Script ids look like "libraries/35/scripts/library%2Furl.dart"
-    if (num_parts != 4) {
+    // Script ids look like "libraries/35/scripts/library%2Furl.dart/12345"
+    if (num_parts != 5) {
       return Object::sentinel().raw();
     }
     const String& id = String::Handle(String::New(parts[3]));
     ASSERT(!id.IsNull());
     // The id is the url of the script % encoded, decode it.
     const String& requested_url = String::Handle(String::DecodeIRI(id));
+
+    // Each script id is tagged with a load time.
+    int64_t timestamp;
+    if (!GetInteger64Id(parts[4], &timestamp, 16) || (timestamp < 0)) {
+      return Object::sentinel().raw();
+    }
+
     Script& script = Script::Handle();
     String& script_url = String::Handle();
     const Array& loaded_scripts = Array::Handle(lib.LoadedScripts());
@@ -1468,7 +1478,8 @@
       script ^= loaded_scripts.At(i);
       ASSERT(!script.IsNull());
       script_url ^= script.url();
-      if (script_url.Equals(requested_url)) {
+      if (script_url.Equals(requested_url) &&
+          (timestamp == script.load_timestamp())) {
         return script.raw();
       }
     }
@@ -1587,12 +1598,13 @@
     if (!GetIntegerId(parts[3], &id)) {
       return Object::sentinel().raw();
     }
-    Type& type = Type::Handle(zone);
-    type ^= cls.CanonicalTypeFromIndex(id);
-    if (type.IsNull()) {
+    if (id != 0) {
       return Object::sentinel().raw();
     }
-    return type.raw();
+    const Type& type = Type::Handle(zone, cls.CanonicalType());
+    if (!type.IsNull()) {
+      return type.raw();
+    }
   }
 
   // Not found.
@@ -2374,6 +2386,52 @@
 }
 
 
+static const MethodParameter* reload_sources_params[] = {
+  RUNNABLE_ISOLATE_PARAMETER,
+  NULL,
+};
+
+
+static bool ReloadSources(Thread* thread, JSONStream* js) {
+  Isolate* isolate = thread->isolate();
+  if (!isolate->compilation_allowed()) {
+    js->PrintError(kFeatureDisabled,
+        "Cannot reload source when running a precompiled program.");
+    return true;
+  }
+  if (Dart::snapshot_kind() == Snapshot::kAppWithJIT) {
+    js->PrintError(kFeatureDisabled,
+        "Cannot reload source when running an app snapshot.");
+    return true;
+  }
+  Dart_LibraryTagHandler handler = isolate->library_tag_handler();
+  if (handler == NULL) {
+    js->PrintError(kFeatureDisabled,
+                   "A library tag handler must be installed.");
+    return true;
+  }
+  if (isolate->IsReloading()) {
+    js->PrintError(kIsolateIsReloading,
+                   "This isolate is being reloaded.");
+    return true;
+  }
+  DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
+  ASSERT(isolate->CanReload());
+
+  if (stack->Length() > 0) {
+    // TODO(turnidge): We need to support this case.
+    js->PrintError(kFeatureDisabled,
+                   "Source can only be reloaded when stack is empty.");
+    return true;
+  } else {
+    isolate->ReloadSources();
+  }
+
+  PrintSuccess(js);
+  return true;
+}
+
+
 static bool AddBreakpointCommon(Thread* thread,
                                 JSONStream* js,
                                 const String& script_uri) {
@@ -2927,7 +2985,7 @@
     return true;
   }
 
-  js->PrintError(kVMMustBePaused, NULL);
+  js->PrintError(kIsolateMustBePaused, NULL);
   return true;
 }
 
@@ -3564,25 +3622,30 @@
   if (js->ParamIs("onlyWithInstantiations", "true")) {
     only_with_instantiations = true;
   }
+  Zone* zone = thread->zone();
   ObjectStore* object_store = thread->isolate()->object_store();
-  const Array& table = Array::Handle(object_store->canonical_type_arguments());
-  ASSERT(table.Length() > 0);
-  TypeArguments& type_args = TypeArguments::Handle();
-  const intptr_t table_size = table.Length() - 1;
-  const intptr_t table_used = Smi::Value(Smi::RawCast(table.At(table_size)));
+  CanonicalTypeArgumentsSet typeargs_table(
+      zone, object_store->canonical_type_arguments());
+  const intptr_t table_size = typeargs_table.NumEntries();
+  const intptr_t table_used = typeargs_table.NumOccupied();
+  const Array& typeargs_array = Array::Handle(
+      zone, HashTables::ToArray(typeargs_table, false));
+  ASSERT(typeargs_array.Length() == table_used);
+  TypeArguments& typeargs = TypeArguments::Handle(zone);
   JSONObject jsobj(js);
   jsobj.AddProperty("type", "TypeArgumentsList");
   jsobj.AddProperty("canonicalTypeArgumentsTableSize", table_size);
   jsobj.AddProperty("canonicalTypeArgumentsTableUsed", table_used);
   JSONArray members(&jsobj, "typeArguments");
-  for (intptr_t i = 0; i < table_size; i++) {
-    type_args ^= table.At(i);
-    if (!type_args.IsNull()) {
-      if (!only_with_instantiations || type_args.HasInstantiations()) {
-        members.AddValue(type_args);
+  for (intptr_t i = 0; i < table_used; i++) {
+    typeargs ^= typeargs_array.At(i);
+    if (!typeargs.IsNull()) {
+      if (!only_with_instantiations || typeargs.HasInstantiations()) {
+        members.AddValue(typeargs);
       }
     }
   }
+  typeargs_table.Release();
   return true;
 }
 
@@ -3642,6 +3705,7 @@
   jsobj.AddProperty("targetCPU", CPU::Id());
   jsobj.AddProperty("hostCPU", HostCPUFeatures::hardware());
   jsobj.AddProperty("version", Version::String());
+  jsobj.AddProperty("_profilerMode", FLAG_profile_vm ? "VM" : "Dart");
   jsobj.AddProperty64("pid", OS::ProcessId());
   int64_t start_time_millis = (vm_isolate->start_time() /
                                kMicrosecondsPerMillisecond);
@@ -3947,6 +4011,8 @@
     remove_breakpoint_params },
   { "_restartVM", RestartVM,
     restart_vm_params },
+  { "_reloadSources", ReloadSources,
+    reload_sources_params },
   { "resume", Resume,
     resume_params },
   { "_requestHeapSnapshot", RequestHeapSnapshot,
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index f38f7f83..084b218 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -66,10 +66,10 @@
  public:
   explicit StreamInfo(const char* id) : id_(id), enabled_(false) {}
 
-  const char* id() { return id_; }
+  const char* id() const { return id_; }
 
   void set_enabled(bool value) { enabled_ = value; }
-  bool enabled() { return enabled_; }
+  bool enabled() const { return enabled_; }
 
  private:
   const char* id_;
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index e37643c..6e3c180 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -131,7 +131,7 @@
 are not supported by the Dart VM.
 
 By convention, every response returned by the Service Protocol is a subtype
-of [Response](#response) and provides a _type_ paramters which can be used
+of [Response](#response) and provides a _type_ parameter which can be used
 to distinguish the exact return type. In the example above, the
 [Version](#version) type is returned.
 
@@ -172,8 +172,7 @@
 }
 ```
 
-In addition the the [error codes](http://www.jsonrpc.org/specification#error_object)
-specified in the JSON-RPC spec, we use the following application specific error codes:
+In addition to the [error codes](http://www.jsonrpc.org/specification#error_object) specified in the JSON-RPC spec, we use the following application specific error codes:
 
 code | message | meaning
 ---- | ------- | -------
@@ -183,6 +182,7 @@
 103 | Stream already subscribed | The client is already subscribed to the specified _streamId_
 104 | Stream not subscribed | The client is not subscribed to the specified _streamId_
 105 | Isolate must be runnable | This operation cannot happen until the isolate is runnable
+106 | Isolate must be paused | This operation is only valid when the isolate is paused
 
 
 
@@ -2216,6 +2216,10 @@
 
 > [lineNumber, (tokenPos, columnNumber)*]
 
+The _tokenPos_ is an arbitrary integer value that is used to represent
+a location in the source code.  A _tokenPos_ value is not meaningful
+in itself and code should not rely on the exact values returned.
+
 For example, a _tokenPosTable_ with the value...
 
 > [[1, 100, 5, 101, 8],[2, 102, 7]]
@@ -2523,5 +2527,5 @@
 3.2 | Isolate objects now include the runnable bit and many debugger related RPCs will return an error if executed on an isolate before it is runnable.
 3.3 | Pause event now indicates if the isolate is paused at an await, yield, or yield* suspension point via the 'atAsyncSuspension' field. Resume command now supports the step parameter 'OverAsyncSuspension'. A Breakpoint added synthetically by an 'OverAsyncSuspension' resume command identifies itself as such via the 'isSyntheticAsyncContinuation' field.
 3.4 | Add the superType and mixin fields to Class. Added new pause event 'None'.
-3.5 | Add the error field to SourceReportRange.
+3.5 | Add the error field to SourceReportRange.  Clarify definition of token position.  Add "Isolate must be paused" error code.
 [discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/runtime/vm/service_event.cc b/runtime/vm/service_event.cc
index d34f439..94af480 100644
--- a/runtime/vm/service_event.cc
+++ b/runtime/vm/service_event.cc
@@ -4,37 +4,14 @@
 
 #include "vm/service_event.h"
 
+#include "vm/debugger.h"
 #include "vm/message_handler.h"
+#include "vm/service_isolate.h"
 
 namespace dart {
 
 #ifndef PRODUCT
 
-// Translate from the legacy DebugEvent to a ServiceEvent.
-static ServiceEvent::EventKind TranslateEventKind(
-    DebuggerEvent::EventType kind) {
-    switch (kind) {
-      case DebuggerEvent::kIsolateCreated:
-        return ServiceEvent::kIsolateStart;
-
-      case DebuggerEvent::kIsolateShutdown:
-        return ServiceEvent::kIsolateExit;
-
-      case DebuggerEvent::kBreakpointReached:
-        return ServiceEvent::kPauseBreakpoint;
-
-      case DebuggerEvent::kIsolateInterrupted:
-        return ServiceEvent::kPauseInterrupted;
-
-      case DebuggerEvent::kExceptionThrown:
-        return ServiceEvent::kPauseException;
-      default:
-        UNREACHABLE();
-        return ServiceEvent::kIllegal;
-    }
-}
-
-
 ServiceEvent::ServiceEvent(Isolate* isolate, EventKind event_kind)
     : isolate_(isolate),
       kind_(event_kind),
@@ -45,12 +22,18 @@
       timeline_event_block_(NULL),
       extension_rpc_(NULL),
       exception_(NULL),
+      reload_error_(NULL),
       at_async_jump_(false),
       inspectee_(NULL),
       gc_stats_(NULL),
       bytes_(NULL),
       bytes_length_(0),
       timestamp_(OS::GetCurrentTimeMillis()) {
+  // We should never generate events for the vm or service isolates.
+  ASSERT(isolate_ != Dart::vm_isolate());
+  ASSERT(isolate == NULL ||
+         !ServiceIsolate::IsServiceIsolateDescendant(isolate_));
+
   if ((event_kind == ServiceEvent::kPauseStart) &&
       !isolate->message_handler()->is_paused_on_start()) {
     // We will pause on start but the message handler lacks a valid
@@ -65,36 +48,8 @@
 }
 
 
-ServiceEvent::ServiceEvent(const DebuggerEvent* debugger_event)
-    : isolate_(debugger_event->isolate()),
-      kind_(TranslateEventKind(debugger_event->type())),
-      breakpoint_(NULL),
-      top_frame_(NULL),
-      timeline_event_block_(NULL),
-      extension_rpc_(NULL),
-      exception_(NULL),
-      at_async_jump_(false),
-      inspectee_(NULL),
-      gc_stats_(NULL),
-      bytes_(NULL),
-      bytes_length_(0),
-      timestamp_(OS::GetCurrentTimeMillis()) {
-  DebuggerEvent::EventType type = debugger_event->type();
-  if (type == DebuggerEvent::kBreakpointReached) {
-    set_breakpoint(debugger_event->breakpoint());
-    set_at_async_jump(debugger_event->at_async_jump());
-  }
-  if (type == DebuggerEvent::kExceptionThrown) {
-    set_exception(debugger_event->exception());
-  }
-  if (type == DebuggerEvent::kBreakpointReached ||
-      type == DebuggerEvent::kIsolateInterrupted ||
-      type == DebuggerEvent::kExceptionThrown) {
-    set_top_frame(debugger_event->top_frame());
-  }
-  if (debugger_event->timestamp() != -1) {
-    timestamp_ = debugger_event->timestamp();
-  }
+void ServiceEvent::UpdateTimestamp() {
+  timestamp_ = OS::GetCurrentTimeMillis();
 }
 
 
@@ -112,6 +67,8 @@
       return "IsolateUpdate";
     case kServiceExtensionAdded:
       return "ServiceExtensionAdded";
+    case kIsolateReload:
+      return "IsolateReload";
     case kPauseStart:
       return "PauseStart";
     case kPauseExit:
@@ -155,17 +112,18 @@
 }
 
 
-const char* ServiceEvent::stream_id() const {
+const StreamInfo* ServiceEvent::stream_info() const {
   switch (kind()) {
     case kVMUpdate:
-      return Service::vm_stream.id();
+      return &Service::vm_stream;
 
     case kIsolateStart:
     case kIsolateRunnable:
     case kIsolateExit:
     case kIsolateUpdate:
+    case kIsolateReload:
     case kServiceExtensionAdded:
-      return Service::isolate_stream.id();
+      return &Service::isolate_stream;
 
     case kPauseStart:
     case kPauseExit:
@@ -179,22 +137,22 @@
     case kBreakpointRemoved:
     case kInspect:
     case kDebuggerSettingsUpdate:
-      return Service::debug_stream.id();
+      return &Service::debug_stream;
 
     case kGC:
-      return Service::gc_stream.id();
-
-    case kEmbedder:
-      return embedder_stream_id_;
+      return &Service::gc_stream;
 
     case kLogging:
-      return Service::logging_stream.id();
+      return &Service::logging_stream;
 
     case kExtension:
-      return Service::extension_stream.id();
+      return &Service::extension_stream;
 
     case kTimelineEvents:
-      return Service::timeline_stream.id();
+      return &Service::timeline_stream;
+
+    case kEmbedder:
+      return NULL;
 
     default:
       UNREACHABLE();
@@ -203,9 +161,28 @@
 }
 
 
+const char* ServiceEvent::stream_id() const {
+  const StreamInfo* stream = stream_info();
+  if (stream == NULL) {
+    ASSERT(kind() == kEmbedder);
+    return embedder_stream_id_;
+  } else {
+    return stream->id();
+  }
+}
+
+
 void ServiceEvent::PrintJSON(JSONStream* js) const {
   JSONObject jsobj(js);
   PrintJSONHeader(&jsobj);
+  if (kind() == kIsolateReload) {
+    if (reload_error_ == NULL) {
+      jsobj.AddProperty("status", "success");
+    } else {
+      jsobj.AddProperty("status", "failure");
+      jsobj.AddProperty("reloadError", *(reload_error()));
+    }
+  }
   if (kind() == kServiceExtensionAdded) {
     ASSERT(extension_rpc_ != NULL);
     jsobj.AddProperty("extensionRPC", extension_rpc_->ToCString());
diff --git a/runtime/vm/service_event.h b/runtime/vm/service_event.h
index 3ca26e4..d6bc92e 100644
--- a/runtime/vm/service_event.h
+++ b/runtime/vm/service_event.h
@@ -5,23 +5,30 @@
 #ifndef VM_SERVICE_EVENT_H_
 #define VM_SERVICE_EVENT_H_
 
-#include "vm/debugger.h"
-
-class DebuggerEvent;
-class TimelineEventBlock;
+#include "vm/globals.h"
+#include "vm/heap.h"
 
 namespace dart {
 
+class ActivationFrame;
+class Breakpoint;
+class Instance;
+class Isolate;
+class Object;
+class StreamInfo;
+class String;
+class TimelineEventBlock;
+
 class ServiceEvent {
  public:
   enum EventKind {
     kVMUpdate,           // VM identity information has changed
 
-    kIsolateStart,       // New isolate has started
-    kIsolateRunnable,    // Isolate is ready to run
-    kIsolateExit,        // Isolate has exited
-    kIsolateUpdate,      // Isolate identity information has changed
-
+    kIsolateStart,           // New isolate has started
+    kIsolateRunnable,        // Isolate is ready to run
+    kIsolateExit,            // Isolate has exited
+    kIsolateUpdate,          // Isolate identity information has changed
+    kIsolateReload,          // Result of a reload request
     kServiceExtensionAdded,  // A service extension was registered
 
     kPauseStart,         // --pause-isolates-on-start
@@ -68,10 +75,13 @@
 
   ServiceEvent(Isolate* isolate, EventKind event_kind);
 
-  explicit ServiceEvent(const DebuggerEvent* debugger_event);
-
   Isolate* isolate() const { return isolate_; }
 
+  // Used by the C embedding api.
+  Dart_Port isolate_id() const {
+    return isolate_->main_port();
+  }
+
   EventKind kind() const { return kind_; }
 
   bool IsPause() const {
@@ -95,6 +105,7 @@
     embedder_kind_ = embedder_kind;
   }
 
+  const StreamInfo* stream_info() const;
   const char* stream_id() const;
 
   void set_embedder_stream_id(const char* stream_id) {
@@ -138,6 +149,15 @@
     exception_ = exception;
   }
 
+  const Error* reload_error() const {
+    ASSERT(kind_ == kIsolateReload);
+    return reload_error_;
+  }
+  void set_reload_error(const Error* error) {
+    ASSERT(kind_ == kIsolateReload);
+    reload_error_ = error;
+  }
+
   bool at_async_jump() const {
     return at_async_jump_;
   }
@@ -182,6 +202,8 @@
     extension_event_ = extension_event;
   }
 
+  void UpdateTimestamp();
+
   int64_t timestamp() const {
     return timestamp_;
   }
@@ -209,6 +231,7 @@
   const TimelineEventBlock* timeline_event_block_;
   const String* extension_rpc_;
   const Object* exception_;
+  const Error* reload_error_;
   bool at_async_jump_;
   const Object* inspectee_;
   const Heap::GCStats* gc_stats_;
diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc
index fa8cd95..e65c539 100644
--- a/runtime/vm/service_isolate.cc
+++ b/runtime/vm/service_isolate.cc
@@ -113,13 +113,13 @@
 }
 
 
-bool ServiceIsolate::IsServiceIsolate(Isolate* isolate) {
+bool ServiceIsolate::IsServiceIsolate(const Isolate* isolate) {
   MonitorLocker ml(monitor_);
   return isolate == isolate_;
 }
 
 
-bool ServiceIsolate::IsServiceIsolateDescendant(Isolate* isolate) {
+bool ServiceIsolate::IsServiceIsolateDescendant(const Isolate* isolate) {
   MonitorLocker ml(monitor_);
   return isolate->origin_id() == origin_;
 }
diff --git a/runtime/vm/service_isolate.h b/runtime/vm/service_isolate.h
index 1b1a9f6..dc2e4be 100644
--- a/runtime/vm/service_isolate.h
+++ b/runtime/vm/service_isolate.h
@@ -19,8 +19,8 @@
 
   static bool Exists();
   static bool IsRunning();
-  static bool IsServiceIsolate(Isolate* isolate);
-  static bool IsServiceIsolateDescendant(Isolate* isolate);
+  static bool IsServiceIsolate(const Isolate* isolate);
+  static bool IsServiceIsolateDescendant(const Isolate* isolate);
   static Dart_Port Port();
 
   static Dart_Port WaitForLoadPort();
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index f11bab7..24c934b 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -3759,7 +3759,7 @@
   int32_t r6_val = get_register(R6);
   int32_t r7_val = get_register(R7);
   int32_t r8_val = get_register(R8);
-#if !defined(TARGET_OS_MACOS)
+#if defined(TARGET_ABI_EABI)
   int32_t r9_val = get_register(R9);
 #endif
   int32_t r10_val = get_register(R10);
@@ -3793,7 +3793,7 @@
   set_register(R6, callee_saved_value);
   set_register(R7, callee_saved_value);
   set_register(R8, callee_saved_value);
-#if !defined(TARGET_OS_MACOS)
+#if defined(TARGET_ABI_EABI)
   set_register(R9, callee_saved_value);
 #endif
   set_register(R10, callee_saved_value);
@@ -3821,7 +3821,7 @@
   ASSERT(callee_saved_value == get_register(R6));
   ASSERT(callee_saved_value == get_register(R7));
   ASSERT(callee_saved_value == get_register(R8));
-#if !defined(TARGET_OS_MACOS)
+#if defined(TARGET_ABI_EABI)
   ASSERT(callee_saved_value == get_register(R9));
 #endif
   ASSERT(callee_saved_value == get_register(R10));
@@ -3844,7 +3844,7 @@
   set_register(R6, r6_val);
   set_register(R7, r7_val);
   set_register(R8, r8_val);
-#if !defined(TARGET_OS_MACOS)
+#if defined(TARGET_ABI_EABI)
   set_register(R9, r9_val);
 #endif
   set_register(R10, r10_val);
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 33570ae..b1b2f4a 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -18,6 +18,7 @@
 #include "vm/snapshot_ids.h"
 #include "vm/stub_code.h"
 #include "vm/symbols.h"
+#include "vm/timeline.h"
 #include "vm/verified_memory.h"
 #include "vm/version.h"
 
@@ -599,7 +600,7 @@
   ASSERT(object_store != NULL);
 
   // First read the version string, and check that it matches.
-  RawApiError* error = VerifyVersion();
+  RawApiError* error = VerifyVersionAndFeatures();
   if (error != ApiError::null()) {
     return error;
   }
@@ -670,7 +671,7 @@
   ASSERT(kind_ == Snapshot::kScript);
 
   // First read the version string, and check that it matches.
-  RawApiError* error = VerifyVersion();
+  RawApiError* error = VerifyVersionAndFeatures();
   if (error != ApiError::null()) {
     return error;
   }
@@ -693,7 +694,7 @@
 }
 
 
-RawApiError* SnapshotReader::VerifyVersion() {
+RawApiError* SnapshotReader::VerifyVersionAndFeatures() {
   // If the version string doesn't match, return an error.
   // Note: New things are allocated only if we're going to return an error.
 
@@ -706,7 +707,7 @@
     OS::SNPrint(message_buffer,
                 kMessageBufferSize,
                 "No full snapshot version found, expected '%s'",
-                Version::SnapshotString());
+                expected_version);
     // This can also fail while bringing up the VM isolate, so make sure to
     // allocate the error message in old space.
     const String& msg = String::Handle(String::New(message_buffer, Heap::kOld));
@@ -723,7 +724,7 @@
                 kMessageBufferSize,
                 "Wrong %s snapshot version, expected '%s' found '%s'",
                 (Snapshot::IsFull(kind_)) ? "full" : "script",
-                Version::SnapshotString(),
+                expected_version,
                 actual_version);
     free(actual_version);
     // This can also fail while bringing up the VM isolate, so make sure to
@@ -732,6 +733,34 @@
     return ApiError::New(msg, Heap::kOld);
   }
   Advance(version_len);
+
+  const char* expected_features = Dart::FeaturesString(kind_);
+  ASSERT(expected_features != NULL);
+  const intptr_t expected_len = strlen(expected_features);
+
+  const char* features = reinterpret_cast<const char*>(CurrentBufferAddress());
+  ASSERT(features != NULL);
+  intptr_t buffer_len = OS::StrNLen(features, PendingBytes());
+  if ((buffer_len != expected_len) ||
+      strncmp(features, expected_features, expected_len)) {
+    const intptr_t kMessageBufferSize = 256;
+    char message_buffer[kMessageBufferSize];
+    char* actual_features = OS::StrNDup(features, buffer_len < 128 ? buffer_len
+                                                                   : 128);
+    OS::SNPrint(message_buffer,
+                kMessageBufferSize,
+                "Wrong features in snapshot, expected '%s' found '%s'",
+                expected_features,
+                actual_features);
+    free(const_cast<char*>(expected_features));
+    free(actual_features);
+    // This can also fail while bringing up the VM isolate, so make sure to
+    // allocate the error message in old space.
+    const String& msg = String::Handle(String::New(message_buffer, Heap::kOld));
+    return ApiError::New(msg, Heap::kOld);
+  }
+  free(const_cast<char*>(expected_features));
+  Advance(expected_len + 1);
   return ApiError::null();
 }
 
@@ -1191,7 +1220,10 @@
 
 
 void AssemblyInstructionsWriter::Write() {
-  Zone* zone = Thread::Current()->zone();
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  NOT_IN_PRODUCT(TimelineDurationScope tds(thread,
+      Timeline::GetIsolateStream(), "WriteInstructions"));
 
   // Handlify collected raw pointers as building the names below
   // will allocate on the Dart heap.
@@ -1336,7 +1368,10 @@
 
 
 void BlobInstructionsWriter::Write() {
-  Zone* zone = Thread::Current()->zone();
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  NOT_IN_PRODUCT(TimelineDurationScope tds(thread,
+      Timeline::GetIsolateStream(), "WriteInstructions"));
 
   // Handlify collected raw pointers as building the names below
   // will allocate on the Dart heap.
@@ -1715,7 +1750,7 @@
   ASSERT(object_store != NULL);
 
   // First read the version string, and check that it matches.
-  RawApiError* error = VerifyVersion();
+  RawApiError* error = VerifyVersionAndFeatures();
   if (error != ApiError::null()) {
     return error;
   }
@@ -2044,6 +2079,9 @@
 
   intptr_t first_object_id = -1;
   if (vm_isolate_snapshot_buffer != NULL) {
+    NOT_IN_PRODUCT(TimelineDurationScope tds(thread(),
+        Timeline::GetIsolateStream(), "PrepareNewVMIsolate"));
+
     // Collect all the script objects and their accompanying token stream
     // objects into an array so that we can write it out as part of the VM
     // isolate snapshot. We first count the number of script objects, allocate
@@ -2094,6 +2132,9 @@
 
 
 void FullSnapshotWriter::WriteVmIsolateSnapshot() {
+  NOT_IN_PRODUCT(TimelineDurationScope tds(thread(),
+      Timeline::GetIsolateStream(), "WriteVmIsolateSnapshot"));
+
   ASSERT(vm_isolate_snapshot_buffer_ != NULL);
   SnapshotWriter writer(thread(),
                         kind_,
@@ -2113,7 +2154,7 @@
     writer.ReserveHeader();
 
     // Write out the version string.
-    writer.WriteVersion();
+    writer.WriteVersionAndFeatures();
 
     /*
      * Now Write out the following
@@ -2143,6 +2184,9 @@
 
 
 void FullSnapshotWriter::WriteIsolateFullSnapshot() {
+  NOT_IN_PRODUCT(TimelineDurationScope tds(thread(),
+      Timeline::GetIsolateStream(), "WriteIsolateFullSnapshot"));
+
   SnapshotWriter writer(thread(),
                         kind_,
                         isolate_snapshot_buffer_,
@@ -2164,7 +2208,7 @@
     writer.ReserveHeader();
 
     // Write out the version string.
-    writer.WriteVersion();
+    writer.WriteVersionAndFeatures();
 
     // Write out the full snapshot.
 
@@ -2688,11 +2732,18 @@
 }
 
 
-void SnapshotWriter::WriteVersion() {
+void SnapshotWriter::WriteVersionAndFeatures() {
   const char* expected_version = Version::SnapshotString();
   ASSERT(expected_version != NULL);
   const intptr_t version_len = strlen(expected_version);
   WriteBytes(reinterpret_cast<const uint8_t*>(expected_version), version_len);
+
+  const char* expected_features = Dart::FeaturesString(kind_);
+  ASSERT(expected_features != NULL);
+  const intptr_t features_len = strlen(expected_features);
+  WriteBytes(reinterpret_cast<const uint8_t*>(expected_features),
+             features_len + 1);
+  free(const_cast<char*>(expected_features));
 }
 
 
@@ -2726,7 +2777,7 @@
     ReserveHeader();
 
     // Write out the version string.
-    WriteVersion();
+    WriteVersionAndFeatures();
 
     // Write out the library object.
     {
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 1c0fddb..da26ca1 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -187,11 +187,6 @@
     return (kind == kAppWithJIT) || (kind == kAppNoJIT);
   }
 
-  bool IsMessageSnapshot() const { return kind() == kMessage; }
-  bool IsScriptSnapshot() const { return kind() == kScript; }
-  bool IsCoreSnapshot() const { return kind() == kCore; }
-  bool IsAppSnapshotWithJIT() const { return kind() == kAppWithJIT; }
-  bool IsAppSnapshotNoJIT() const { return kind() == kAppNoJIT; }
   uint8_t* Addr() { return reinterpret_cast<uint8_t*>(this); }
 
   static intptr_t length_offset() {
@@ -410,6 +405,7 @@
   ClassTable* class_table() const { return isolate()->class_table(); }
   PassiveObject* PassiveObjectHandle() { return &pobj_; }
   Array* ArrayHandle() { return &array_; }
+  Class* ClassHandle() { return &cls_; }
   String* StringHandle() { return &str_; }
   AbstractType* TypeHandle() { return &type_; }
   TypeArguments* TypeArgumentsHandle() { return &type_arguments_; }
@@ -441,7 +437,7 @@
   RawObject* ReadScriptSnapshot();
 
   // Read version number of snapshot and verify.
-  RawApiError* VerifyVersion();
+  RawApiError* VerifyVersionAndFeatures();
 
   // Helper functions for creating uninitialized versions
   // of various object types. These are used when reading a
@@ -1019,7 +1015,7 @@
   void ThrowException(Exceptions::ExceptionType type, const char* msg);
 
   // Write a version string for the snapshot.
-  void WriteVersion();
+  void WriteVersionAndFeatures();
 
   int32_t GetInstructionsId(RawInstructions* instructions, RawCode* code) {
     return instructions_writer_->GetOffsetFor(instructions, code);
@@ -1093,7 +1089,6 @@
   friend class RawGrowableObjectArray;
   friend class RawImmutableArray;
   friend class RawInstructions;
-  friend class RawRegExp;
   friend class RawLibrary;
   friend class RawLinkedHashMap;
   friend class RawLiteralToken;
@@ -1101,11 +1096,14 @@
   friend class RawMirrorReference;
   friend class RawObjectPool;
   friend class RawReceivePort;
+  friend class RawRegExp;
   friend class RawScript;
   friend class RawStacktrace;
   friend class RawSubtypeTestCache;
   friend class RawTokenStream;
+  friend class RawType;
   friend class RawTypeArguments;
+  friend class RawTypeParameter;
   friend class RawUserTag;
   friend class SnapshotWriterVisitor;
   friend class WriteInlinedObjectVisitor;
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 52db512..493607a 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -18,8 +18,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, concurrent_sweep);
-
 // Check if serialized and deserialized objects are equal.
 static bool Equals(const Object& expected, const Object& actual) {
   if (expected.IsNull()) {
@@ -869,9 +867,8 @@
   const String& str = String::Handle(zone, expected_tokens.GenerateSource());
   const String& private_key =
       String::Handle(zone, expected_tokens.PrivateKey());
-  Scanner scanner(str, private_key);
   const TokenStream& reconstructed_tokens =
-      TokenStream::Handle(zone, TokenStream::New(scanner.GetStream(),
+      TokenStream::Handle(zone, TokenStream::New(str,
                                                  private_key,
                                                  false));
   expected_iterator.SetCurrentPosition(TokenPosition::kMinSource);
diff --git a/runtime/vm/stack_frame_arm.h b/runtime/vm/stack_frame_arm.h
index ca89fb5..a966a29 100644
--- a/runtime/vm/stack_frame_arm.h
+++ b/runtime/vm/stack_frame_arm.h
@@ -43,14 +43,16 @@
 static const int kCallerSpSlotFromFp = 2;
 
 // Entry and exit frame layout.
-#if defined(TARGET_OS_MAC)
+#if defined(TARGET_ABI_IOS)
 static const int kExitLinkSlotFromEntryFp = -26;
 COMPILE_ASSERT(kAbiPreservedCpuRegCount == 6);
 COMPILE_ASSERT(kAbiPreservedFpuRegCount == 4);
-#else
+#elif defined(TARGET_ABI_EABI)
 static const int kExitLinkSlotFromEntryFp = -27;
 COMPILE_ASSERT(kAbiPreservedCpuRegCount == 7);
 COMPILE_ASSERT(kAbiPreservedFpuRegCount == 4);
+#else
+#error Unknown ABI
 #endif
 
 }  // namespace dart
diff --git a/runtime/vm/store_buffer.h b/runtime/vm/store_buffer.h
index 36f17bc..2fce2d6 100644
--- a/runtime/vm/store_buffer.h
+++ b/runtime/vm/store_buffer.h
@@ -121,7 +121,7 @@
   // Adds and transfers ownership of the block to the buffer.
   void PushBlockImpl(Block* block);
 
-  // If needed, trims the the global cache of empty blocks.
+  // If needed, trims the global cache of empty blocks.
   static void TrimGlobalEmpty();
 
   List full_;
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 8e85852..e4e32ce 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -772,9 +772,9 @@
 
   // kExitLinkSlotFromEntryFp must be kept in sync with the code below.
   __ Push(R4);
-#if defined(TARGET_OS_MAC)
+#if defined(TARGET_ABI_IOS)
   ASSERT(kExitLinkSlotFromEntryFp == -26);
-#else
+#elif defined(TARGET_ABI_EABI)
   ASSERT(kExitLinkSlotFromEntryFp == -27);
 #endif
   __ Push(R9);
diff --git a/runtime/vm/stub_code_arm64_test.cc b/runtime/vm/stub_code_arm64_test.cc
index d3a3a46..f2d8a25 100644
--- a/runtime/vm/stub_code_arm64_test.cc
+++ b/runtime/vm/stub_code_arm64_test.cc
@@ -23,10 +23,9 @@
   const String& class_name = String::Handle(Symbols::New(Thread::Current(),
                                                          "ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class = Class::Handle(
-      Class::New(class_name, script, TokenPosition::kNoSource));
   const Library& lib = Library::Handle(Library::New(class_name));
-  owner_class.set_library(lib);
+  const Class& owner_class = Class::Handle(
+      Class::New(lib, class_name, script, TokenPosition::kNoSource));
   const String& function_name = String::ZoneHandle(
       Symbols::New(Thread::Current(), name));
   Function& function = Function::ZoneHandle(
diff --git a/runtime/vm/stub_code_arm_test.cc b/runtime/vm/stub_code_arm_test.cc
index 3f0fe4c..a0c35cc 100644
--- a/runtime/vm/stub_code_arm_test.cc
+++ b/runtime/vm/stub_code_arm_test.cc
@@ -23,10 +23,9 @@
   const String& class_name = String::Handle(Symbols::New(Thread::Current(),
                                                          "ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class = Class::Handle(
-      Class::New(class_name, script, TokenPosition::kNoSource));
   const Library& lib = Library::Handle(Library::New(class_name));
-  owner_class.set_library(lib);
+  const Class& owner_class = Class::Handle(
+      Class::New(lib, class_name, script, TokenPosition::kNoSource));
   const String& function_name = String::ZoneHandle(
       Symbols::New(Thread::Current(), name));
   Function& function = Function::ZoneHandle(
diff --git a/runtime/vm/stub_code_ia32_test.cc b/runtime/vm/stub_code_ia32_test.cc
index 34e8ef3..6ba14dc 100644
--- a/runtime/vm/stub_code_ia32_test.cc
+++ b/runtime/vm/stub_code_ia32_test.cc
@@ -23,10 +23,9 @@
   const String& class_name = String::Handle(Symbols::New(Thread::Current(),
                                                          "ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class = Class::Handle(
-      Class::New(class_name, script, TokenPosition::kNoSource));
   const Library& lib = Library::Handle(Library::New(class_name));
-  owner_class.set_library(lib);
+  const Class& owner_class = Class::Handle(
+      Class::New(lib, class_name, script, TokenPosition::kNoSource));
   const String& function_name = String::ZoneHandle(
       Symbols::New(Thread::Current(), name));
   Function& function = Function::ZoneHandle(
diff --git a/runtime/vm/stub_code_mips_test.cc b/runtime/vm/stub_code_mips_test.cc
index c058dcd..65ff616 100644
--- a/runtime/vm/stub_code_mips_test.cc
+++ b/runtime/vm/stub_code_mips_test.cc
@@ -23,10 +23,9 @@
   const String& class_name = String::Handle(Symbols::New(Thread::Current(),
                                                          "ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class = Class::Handle(
-      Class::New(class_name, script, TokenPosition::kNoSource));
   const Library& lib = Library::Handle(Library::New(class_name));
-  owner_class.set_library(lib);
+  const Class& owner_class = Class::Handle(
+      Class::New(lib, class_name, script, TokenPosition::kNoSource));
   const String& function_name = String::ZoneHandle(
       Symbols::New(Thread::Current(), name));
   Function& function = Function::ZoneHandle(
diff --git a/runtime/vm/stub_code_x64_test.cc b/runtime/vm/stub_code_x64_test.cc
index 6b9b2af..66feaeb 100644
--- a/runtime/vm/stub_code_x64_test.cc
+++ b/runtime/vm/stub_code_x64_test.cc
@@ -23,10 +23,9 @@
   const String& class_name = String::Handle(Symbols::New(Thread::Current(),
                                                          "ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class = Class::Handle(
-      Class::New(class_name, script, TokenPosition::kNoSource));
   const Library& lib = Library::Handle(Library::New(class_name));
-  owner_class.set_library(lib);
+  const Class& owner_class = Class::Handle(
+      Class::New(lib, class_name, script, TokenPosition::kNoSource));
   const String& function_name = String::ZoneHandle(
       Symbols::New(Thread::Current(), name));
   Function& function = Function::ZoneHandle(
diff --git a/runtime/vm/tags.cc b/runtime/vm/tags.cc
index c90fe06..fa3cc67 100644
--- a/runtime/vm/tags.cc
+++ b/runtime/vm/tags.cc
@@ -37,6 +37,17 @@
 }
 
 
+bool VMTag::IsDartTag(uword id) {
+  return id == kDartTagId;
+}
+
+
+bool VMTag::IsExitFrameTag(uword id) {
+  return (id != 0) && !IsDartTag(id) && (id != kIdleTagId) &&
+         (id != kVMTagId) && (id != kEmbedderTagId);
+}
+
+
 static RuntimeEntry* runtime_entry_list = NULL;
 
 
diff --git a/runtime/vm/tags.h b/runtime/vm/tags.h
index 926aed8..3279c82 100644
--- a/runtime/vm/tags.h
+++ b/runtime/vm/tags.h
@@ -62,7 +62,8 @@
   }
   static const char* TagName(uword id);
   static bool IsNativeEntryTag(uword id);
-
+  static bool IsDartTag(uword id);
+  static bool IsExitFrameTag(uword id);
   static bool IsRuntimeEntryTag(uword id);
   static const char* RuntimeEntryTagName(uword id);
 
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 3c7efee..69e7820 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -20,6 +20,7 @@
 #include "vm/symbols.h"
 #include "vm/thread_interrupter.h"
 #include "vm/thread_registry.h"
+#include "vm/timeline.h"
 
 namespace dart {
 
@@ -68,6 +69,7 @@
       store_buffer_block_(NULL),
       vm_tag_(0),
       task_kind_(kUnknownTask),
+      dart_stream_(NULL),
       os_thread_(NULL),
       thread_lock_(new Monitor()),
       zone_(NULL),
@@ -83,6 +85,7 @@
 #endif
       reusable_handles_(),
       saved_stack_limit_(0),
+      defer_oob_messages_count_(0),
       deferred_interrupts_mask_(0),
       deferred_interrupts_(0),
       stack_overflow_count_(0),
@@ -96,6 +99,10 @@
       safepoint_state_(0),
       execution_state_(kThreadInVM),
       next_(NULL) {
+NOT_IN_PRODUCT(
+  dart_stream_ = Timeline::GetDartStream();
+  ASSERT(dart_stream_ != NULL);
+)
 #define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value)    \
   member_name = default_init_value;
 CACHED_CONSTANTS_LIST(DEFAULT_INIT)
@@ -417,6 +424,11 @@
 
 void Thread::DeferOOBMessageInterrupts() {
   MonitorLocker ml(thread_lock_);
+  defer_oob_messages_count_++;
+  if (defer_oob_messages_count_ > 1) {
+    // OOB message interrupts are already deferred.
+    return;
+  }
   ASSERT(deferred_interrupts_mask_ == 0);
   deferred_interrupts_mask_ = kMessageInterrupt;
 
@@ -441,6 +453,11 @@
 
 void Thread::RestoreOOBMessageInterrupts() {
   MonitorLocker ml(thread_lock_);
+  defer_oob_messages_count_--;
+  if (defer_oob_messages_count_ > 0) {
+    return;
+  }
+  ASSERT(defer_oob_messages_count_ == 0);
   ASSERT(deferred_interrupts_mask_ == kMessageInterrupt);
   deferred_interrupts_mask_ = 0;
   if (deferred_interrupts_ != 0) {
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 2201f36..ea5396a 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -48,6 +48,7 @@
 class Smi;
 class StackResource;
 class String;
+class TimelineStream;
 class TypeArguments;
 class TypeParameter;
 class Zone;
@@ -270,6 +271,11 @@
   bool IsMutatorThread() const;
   bool CanCollectGarbage() const;
 
+  // Offset of Dart TimelineStream object.
+  static intptr_t dart_stream_offset() {
+    return OFFSET_OF(Thread, dart_stream_);
+  }
+
   // Is |this| executing Dart code?
   bool IsExecutingDartCode() const;
 
@@ -653,6 +659,7 @@
 LEAF_RUNTIME_ENTRY_LIST(DECLARE_MEMBERS)
 #undef DECLARE_MEMBERS
 
+  TimelineStream* dart_stream_;
   OSThread* os_thread_;
   Monitor* thread_lock_;
   Zone* zone_;
@@ -668,6 +675,7 @@
 #endif
   VMHandles reusable_handles_;
   uword saved_stack_limit_;
+  intptr_t defer_oob_messages_count_;
   uint16_t deferred_interrupts_mask_;
   uint16_t deferred_interrupts_;
   int32_t stack_overflow_count_;
diff --git a/runtime/vm/thread_interrupter.cc b/runtime/vm/thread_interrupter.cc
index 1e0d8cf..fa14d2e 100644
--- a/runtime/vm/thread_interrupter.cc
+++ b/runtime/vm/thread_interrupter.cc
@@ -157,7 +157,7 @@
     MonitorLocker startup_ml(monitor_);
     OSThread* os_thread = OSThread::Current();
     ASSERT(os_thread != NULL);
-    interrupter_thread_id_ = os_thread->join_id();
+    interrupter_thread_id_ = OSThread::GetCurrentThreadJoinId(os_thread);
     thread_running_ = true;
     startup_ml.Notify();
   }
diff --git a/runtime/vm/thread_pool.cc b/runtime/vm/thread_pool.cc
index fb0f7d7..0c326d3 100644
--- a/runtime/vm/thread_pool.cc
+++ b/runtime/vm/thread_pool.cc
@@ -212,6 +212,16 @@
 }
 
 
+void ThreadPool::SetIdleLocked(Worker* worker) {
+  ASSERT(mutex_.IsOwnedByCurrentThread());
+  ASSERT(worker->owned_ && !IsIdle(worker));
+  worker->idle_next_ = idle_workers_;
+  idle_workers_ = worker;
+  count_idle_++;
+  count_running_--;
+}
+
+
 void ThreadPool::SetIdleAndReapExited(Worker* worker) {
   JoinList* list = NULL;
   {
@@ -219,17 +229,25 @@
     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_.
+    if (join_list_ == NULL) {
+      // Nothing to join, add to the idle list and return.
+      SetIdleLocked(worker);
+      return;
+    }
+    // There is something to join. Grab the join list, drop the lock, do the
+    // join, then grab the lock again and add to the idle list.
     list = join_list_;
     join_list_ = NULL;
   }
   JoinList::Join(&list);
+
+  {
+    MutexLocker ml(&mutex_);
+    if (shutting_down_) {
+      return;
+    }
+    SetIdleLocked(worker);
+  }
 }
 
 
@@ -250,7 +268,8 @@
   // so that we can join on it at the next opportunity.
   OSThread* os_thread = OSThread::Current();
   ASSERT(os_thread != NULL);
-  JoinList::AddLocked(os_thread->join_id(), &join_list_);
+  ThreadJoinId join_id = OSThread::GetCurrentThreadJoinId(os_thread);
+  JoinList::AddLocked(join_id, &join_list_);
   count_stopped_++;
   count_idle_--;
   return true;
@@ -430,7 +449,6 @@
   OSThread* os_thread = OSThread::Current();
   ASSERT(os_thread != NULL);
   ThreadId id = os_thread->id();
-  ThreadJoinId join_id = os_thread->join_id();
   ThreadPool* pool;
 
   // Set the thread's stack_base based on the current stack pointer.
@@ -454,6 +472,7 @@
     // 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.
+    ThreadJoinId join_id = OSThread::GetCurrentThreadJoinId(os_thread);
     {
       MutexLocker ml(&pool->mutex_);
       JoinList::AddLocked(join_id, &pool->join_list_);
diff --git a/runtime/vm/thread_pool.h b/runtime/vm/thread_pool.h
index 1713781..8cd29a2 100644
--- a/runtime/vm/thread_pool.h
+++ b/runtime/vm/thread_pool.h
@@ -125,6 +125,7 @@
   void ReapExitedIdleThreads();
 
   // Worker operations.
+  void SetIdleLocked(Worker* worker);  // Assumes mutex_ is held.
   void SetIdleAndReapExited(Worker* worker);
   bool ReleaseIdleWorker(Worker* worker);
 
diff --git a/runtime/vm/thread_registry.h b/runtime/vm/thread_registry.h
index c765a5d..adf2a34 100644
--- a/runtime/vm/thread_registry.h
+++ b/runtime/vm/thread_registry.h
@@ -48,7 +48,7 @@
   // and always schedule execution of Dart code on the same mutator thread
   // object. The ApiLocalScope has been made thread specific but we still
   // have scenarios where we do a temporary exit of an Isolate with live
-  // zones/handles in the the API scope :
+  // zones/handles in the API scope :
   // - Dart_RunLoop()
   // - IsolateSaver in Dart_NewNativePort
   // - Isolate spawn (function/uri) under FLAG_i_like_slow_isolate_spawn
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index aa006df..d0deba9 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -435,12 +435,13 @@
 
 VM_TEST_CASE(ThreadIterator_FindSelf) {
   OSThread* current = OSThread::Current();
-  EXPECT(OSThread::IsThreadInList(current->join_id()));
+  EXPECT(OSThread::IsThreadInList(current->id()));
 }
 
 
 struct ThreadIteratorTestParams {
-  ThreadId spawned_thread_join_id;
+  ThreadId spawned_thread_id;
+  ThreadJoinId spawned_thread_join_id;
   Monitor* monitor;
 };
 
@@ -452,9 +453,10 @@
   EXPECT(thread != NULL);
 
   MonitorLocker ml(params->monitor);
-  params->spawned_thread_join_id = thread->join_id();
-  EXPECT(params->spawned_thread_join_id != OSThread::kInvalidThreadJoinId);
-  EXPECT(OSThread::IsThreadInList(thread->join_id()));
+  params->spawned_thread_id = thread->id();
+  params->spawned_thread_join_id = OSThread::GetCurrentThreadJoinId(thread);
+  EXPECT(params->spawned_thread_id != OSThread::kInvalidThreadId);
+  EXPECT(OSThread::IsThreadInList(thread->id()));
   ml.Notify();
 }
 
@@ -463,25 +465,25 @@
 // on Windows. See |OnDartThreadExit| in os_thread_win.cc for more details.
 TEST_CASE(ThreadIterator_AddFindRemove) {
   ThreadIteratorTestParams params;
-  params.spawned_thread_join_id = OSThread::kInvalidThreadJoinId;
+  params.spawned_thread_id = OSThread::kInvalidThreadId;
   params.monitor = new Monitor();
 
   {
     MonitorLocker ml(params.monitor);
-    EXPECT(params.spawned_thread_join_id == OSThread::kInvalidThreadJoinId);
-    // Spawn thread and wait to receive the thread join id.
+    EXPECT(params.spawned_thread_id == OSThread::kInvalidThreadId);
+    // Spawn thread and wait to receive the thread id.
     OSThread::Start("ThreadIteratorTest",
                     ThreadIteratorTestMain,
                     reinterpret_cast<uword>(&params));
-    while (params.spawned_thread_join_id == OSThread::kInvalidThreadJoinId) {
+    while (params.spawned_thread_id == OSThread::kInvalidThreadId) {
       ml.Wait();
     }
+    EXPECT(params.spawned_thread_id != OSThread::kInvalidThreadId);
     EXPECT(params.spawned_thread_join_id != OSThread::kInvalidThreadJoinId);
-    // Join thread.
     OSThread::Join(params.spawned_thread_join_id);
   }
 
-  EXPECT(!OSThread::IsThreadInList(params.spawned_thread_join_id))
+  EXPECT(!OSThread::IsThreadInList(params.spawned_thread_id))
 
   delete params.monitor;
 }
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index 8b9eaf0..dbe9ef0 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -173,14 +173,12 @@
   enabled_streams_ = GetEnabledByDefaultTimelineStreams();
   // Global overrides.
 #define TIMELINE_STREAM_FLAG_DEFAULT(name, not_used)                           \
-  stream_##name##_enabled_ = HasStream(enabled_streams_, #name);               \
   stream_##name##_.Init(#name,                                                 \
-                        stream_##name##_enabled_,                              \
-                        &stream_##name##_enabled_);
+                        HasStream(enabled_streams_, #name));
   TIMELINE_STREAM_LIST(TIMELINE_STREAM_FLAG_DEFAULT)
 #undef TIMELINE_STREAM_FLAG_DEFAULT
 
-  if (stream_Embedder_enabled_ &&
+  if (Timeline::stream_Embedder_.enabled() &&
       (Timeline::get_start_recording_cb() != NULL)) {
     Timeline::get_start_recording_cb()();
   }
@@ -206,7 +204,7 @@
 void Timeline::Shutdown() {
   ASSERT(recorder_ != NULL);
 
-  if (stream_Embedder_enabled_ &&
+  if (Timeline::stream_Embedder_.enabled() &&
       (Timeline::get_stop_recording_cb() != NULL)) {
     Timeline::get_stop_recording_cb()();
   }
@@ -217,7 +215,7 @@
 
   // Disable global streams.
 #define TIMELINE_STREAM_DISABLE(name, not_used)                                \
-  stream_##name##_enabled_ = false;
+  Timeline::stream_##name##_.set_enabled(false);
   TIMELINE_STREAM_LIST(TIMELINE_STREAM_DISABLE)
 #undef TIMELINE_STREAM_DISABLE
   delete recorder_;
@@ -275,7 +273,7 @@
   {
     JSONArray recordedStreams(&obj, "recordedStreams");
 #define ADD_RECORDED_STREAM_NAME(name, not_used)                               \
-    if (stream_##name##_enabled_) {                                            \
+    if (stream_##name##_.enabled()) {                                          \
       recordedStreams.AddValue(#name);                                         \
     }
 TIMELINE_STREAM_LIST(ADD_RECORDED_STREAM_NAME);
@@ -300,7 +298,6 @@
 Dart_EmbedderTimelineStopRecording Timeline::stop_recording_cb_ = NULL;
 
 #define TIMELINE_STREAM_DEFINE(name, enabled_by_default)                       \
-  bool Timeline::stream_##name##_enabled_ = enabled_by_default;                \
   TimelineStream Timeline::stream_##name##_;
   TIMELINE_STREAM_LIST(TIMELINE_STREAM_DEFINE)
 #undef TIMELINE_STREAM_DEFINE
@@ -680,6 +677,20 @@
 }
 
 
+int64_t TimelineEvent::LowTime() const {
+  return timestamp0_;
+}
+
+
+int64_t TimelineEvent::HighTime() const {
+  if (event_type() == kDuration) {
+    return timestamp1_;
+  } else {
+    return timestamp0_;
+  }
+}
+
+
 int64_t TimelineEvent::TimeDuration() const {
   if (timestamp1_ == 0) {
     // This duration is still open, use current time as end.
@@ -713,23 +724,20 @@
 
 TimelineStream::TimelineStream()
     : name_(NULL),
-      enabled_(false),
-      globally_enabled_(NULL) {
+      enabled_(false) {
 }
 
 
 void TimelineStream::Init(const char* name,
-                          bool enabled,
-                          const bool* globally_enabled) {
+                          bool enabled) {
   name_ = name;
   enabled_ = enabled;
-  globally_enabled_ = globally_enabled;
 }
 
 
 TimelineEvent* TimelineStream::StartEvent() {
   TimelineEventRecorder* recorder = Timeline::recorder();
-  if (!Enabled() || (recorder == NULL)) {
+  if (!enabled() || (recorder == NULL)) {
     return NULL;
   }
   ASSERT(name_ != NULL);
@@ -775,7 +783,7 @@
   ASSERT(enabled_ == false);
   ASSERT(label_ != NULL);
   ASSERT(stream_ != NULL);
-  if (!stream_->Enabled()) {
+  if (!stream_->enabled()) {
     // Stream is not enabled, do nothing.
     return;
   }
@@ -870,7 +878,7 @@
 TimelineDurationScope::TimelineDurationScope(TimelineStream* stream,
                                              const char* label)
     : TimelineEventScope(stream, label) {
-  if (!FLAG_support_timeline) {
+  if (!FLAG_support_timeline || !enabled()) {
     return;
   }
   timestamp_ = OS::GetCurrentMonotonicMicros();
@@ -882,7 +890,7 @@
                                              TimelineStream* stream,
                                              const char* label)
     : TimelineEventScope(thread, stream, label) {
-  if (!FLAG_support_timeline) {
+  if (!FLAG_support_timeline || !enabled()) {
     return;
   }
   timestamp_ = OS::GetCurrentMonotonicMicros();
@@ -1008,7 +1016,9 @@
 
 
 TimelineEventRecorder::TimelineEventRecorder()
-    : async_id_(0) {
+    : async_id_(0),
+      time_low_micros_(0),
+      time_high_micros_(0) {
 }
 
 
@@ -1088,6 +1098,38 @@
 }
 
 
+void TimelineEventRecorder::ResetTimeTracking() {
+  time_high_micros_ = 0;
+  time_low_micros_ = kMaxInt64;
+}
+
+
+void TimelineEventRecorder::ReportTime(int64_t micros) {
+  if (time_high_micros_ < micros) {
+    time_high_micros_ = micros;
+  }
+  if (time_low_micros_ > micros) {
+    time_low_micros_ = micros;
+  }
+}
+
+
+int64_t TimelineEventRecorder::TimeOriginMicros() const {
+  if (time_high_micros_ == 0) {
+    return 0;
+  }
+  return time_low_micros_;
+}
+
+
+int64_t TimelineEventRecorder::TimeExtentMicros() const {
+  if (time_high_micros_ == 0) {
+    return 0;
+  }
+  return time_high_micros_ - time_low_micros_;
+}
+
+
 void TimelineEventRecorder::ThreadBlockCompleteEvent(TimelineEvent* event) {
   if (event == NULL) {
     return;
@@ -1212,6 +1254,7 @@
     return;
   }
   MutexLocker ml(&lock_);
+  ResetTimeTracking();
   intptr_t block_offset = FindOldestBlockIndex();
   if (block_offset == -1) {
     // All blocks are empty.
@@ -1228,6 +1271,8 @@
       if (filter->IncludeEvent(event) &&
           event->Within(filter->time_origin_micros(),
                         filter->time_extent_micros())) {
+        ReportTime(event->LowTime());
+        ReportTime(event->HighTime());
         events->AddValue(event);
       }
     }
@@ -1247,6 +1292,8 @@
     PrintJSONMeta(&events);
     PrintJSONEvents(&events, filter);
   }
+  topLevel.AddPropertyTimeMicros("timeOriginMicros", TimeOriginMicros());
+  topLevel.AddPropertyTimeMicros("timeExtentMicros", TimeExtentMicros());
 }
 
 
@@ -1393,6 +1440,8 @@
     PrintJSONMeta(&events);
     PrintJSONEvents(&events, filter);
   }
+  topLevel.AddPropertyTimeMicros("timeOriginMicros", TimeOriginMicros());
+  topLevel.AddPropertyTimeMicros("timeExtentMicros", TimeExtentMicros());
 }
 
 
@@ -1450,6 +1499,7 @@
     return;
   }
   MutexLocker ml(&lock_);
+  ResetTimeTracking();
   // Collect all interesting blocks.
   MallocGrowableArray<TimelineEventBlock*> blocks(8);
   TimelineEventBlock* current = head_;
@@ -1475,6 +1525,8 @@
       if (filter->IncludeEvent(event) &&
           event->Within(filter->time_origin_micros(),
                         filter->time_extent_micros())) {
+        ReportTime(event->LowTime());
+        ReportTime(event->HighTime());
         events->AddValue(event);
       }
     }
diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h
index 1646d99..d91e909 100644
--- a/runtime/vm/timeline.h
+++ b/runtime/vm/timeline.h
@@ -38,6 +38,45 @@
   V(Isolate, false)                                                            \
   V(VM, false)
 
+// A stream of timeline events. A stream has a name and can be enabled or
+// disabled (globally and per isolate).
+class TimelineStream {
+ public:
+  TimelineStream();
+
+  void Init(const char* name,
+            bool enabled);
+
+  const char* name() const {
+    return name_;
+  }
+
+  bool enabled() const {
+    return enabled_ != 0;
+  }
+
+  void set_enabled(bool enabled) {
+    enabled_ = enabled ? 1 : 0;
+  }
+
+  // Records an event. Will return |NULL| if not enabled. The returned
+  // |TimelineEvent| is in an undefined state and must be initialized.
+  // NOTE: It is not allowed to call StartEvent again without completing
+  // the first event.
+  TimelineEvent* StartEvent();
+
+  static intptr_t enabled_offset() {
+    return OFFSET_OF(TimelineStream, enabled_);
+  }
+
+ private:
+  const char* name_;
+
+  // This field is accessed by generated code (intrinsic) and expects to see
+  // 0 or 1. If this becomes a BitField, the generated code must be updated.
+  uintptr_t enabled_;
+};
+
 class Timeline : public AllStatic {
  public:
   // Initialize timeline system. Not thread safe.
@@ -57,18 +96,15 @@
   // Print information about streams to JSON.
   static void PrintFlagsToJSON(JSONStream* json);
 
-#define TIMELINE_STREAM_ACCESSOR(name, not_used)                       \
+#define TIMELINE_STREAM_ACCESSOR(name, not_used)                               \
   static TimelineStream* Get##name##Stream() { return &stream_##name##_; }
   TIMELINE_STREAM_LIST(TIMELINE_STREAM_ACCESSOR)
 #undef TIMELINE_STREAM_ACCESSOR
 
 #define TIMELINE_STREAM_FLAGS(name, not_used)                                  \
-  static const bool* Stream##name##EnabledFlag() {                             \
-    return &stream_##name##_enabled_;                                          \
-  }                                                                            \
   static void SetStream##name##Enabled(bool enabled) {                         \
-    StreamStateChange(#name, stream_##name##_enabled_, enabled);               \
-    stream_##name##_enabled_ = enabled;                                        \
+    StreamStateChange(#name, stream_##name##_.enabled(), enabled);             \
+    stream_##name##_.set_enabled(enabled);                                     \
   }
   TIMELINE_STREAM_LIST(TIMELINE_STREAM_FLAGS)
 #undef TIMELINE_STREAM_FLAGS
@@ -223,6 +259,11 @@
     return timestamp1_;
   }
 
+  // The lowest time value stored in this event.
+  int64_t LowTime() const;
+  // The highest time value stored in this event.
+  int64_t HighTime() const;
+
   void PrintJSON(JSONStream* stream) const;
 
   ThreadId thread() const {
@@ -378,45 +419,6 @@
 };
 
 
-// A stream of timeline events. A stream has a name and can be enabled or
-// disabled (globally and per isolate).
-class TimelineStream {
- public:
-  TimelineStream();
-
-  void Init(const char* name,
-            bool enabled,
-            const bool* globally_enabled = NULL);
-
-  const char* name() const {
-    return name_;
-  }
-
-  bool Enabled() const {
-    return ((globally_enabled_ != NULL) && *globally_enabled_) ||
-           enabled();
-  }
-
-  bool enabled() const {
-    return enabled_;
-  }
-
-  void set_enabled(bool enabled) {
-    enabled_ = enabled;
-  }
-
-  // Records an event. Will return |NULL| if not enabled. The returned
-  // |TimelineEvent| is in an undefined state and must be initialized.
-  // NOTE: It is not allowed to call StartEvent again without completing
-  // the first event.
-  TimelineEvent* StartEvent();
-
- private:
-  const char* name_;
-  bool enabled_;
-  const bool* globally_enabled_;
-};
-
 #ifndef PRODUCT
 #define TIMELINE_FUNCTION_COMPILATION_DURATION(thread, name, function)         \
   TimelineDurationScope tds(thread,                                            \
@@ -719,8 +721,15 @@
   TimelineEvent* ThreadBlockStartEvent();
   void ThreadBlockCompleteEvent(TimelineEvent* event);
 
+  void ResetTimeTracking();
+  void ReportTime(int64_t micros);
+  int64_t TimeOriginMicros() const;
+  int64_t TimeExtentMicros() const;
+
   Mutex lock_;
   uintptr_t async_id_;
+  int64_t time_low_micros_;
+  int64_t time_high_micros_;
 
   friend class TimelineEvent;
   friend class TimelineEventBlockIterator;
@@ -769,7 +778,7 @@
   ~TimelineEventRingRecorder() {}
 
   const char* name() const {
-    return "ring";
+    return "Ring";
   }
 
  protected:
@@ -786,7 +795,7 @@
   ~TimelineEventStartupRecorder() {}
 
   const char* name() const {
-    return "startup";
+    return "Startup";
   }
 
  protected:
@@ -809,7 +818,7 @@
   virtual void OnEvent(TimelineEvent* event) = 0;
 
   const char* name() const {
-    return "callback";
+    return "Callback";
   }
 
  protected:
@@ -837,7 +846,7 @@
   void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter);
 
   const char* name() const {
-    return "endless";
+    return "Endless";
   }
 
  protected:
diff --git a/runtime/vm/type_table.h b/runtime/vm/type_table.h
new file mode 100644
index 0000000..c33a124
--- /dev/null
+++ b/runtime/vm/type_table.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2016, 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.
+
+#ifndef VM_TYPE_TABLE_H_
+#define VM_TYPE_TABLE_H_
+
+#include "platform/assert.h"
+#include "vm/hash_table.h"
+#include "vm/object.h"
+
+namespace dart {
+
+class CanonicalTypeKey {
+ public:
+  explicit CanonicalTypeKey(const Type& key) : key_(key) {
+  }
+  bool Matches(const Type& arg) const {
+    return key_.Equals(arg);
+  }
+  uword Hash() const {
+    return key_.Hash();
+  }
+  const Type& key_;
+
+ private:
+  DISALLOW_ALLOCATION();
+};
+
+
+// Traits for looking up Canonical Type based on it's hash.
+class CanonicalTypeTraits {
+ public:
+  static const char* Name() { return "CanonicalTypeTraits"; }
+  static bool ReportStats() { return false; }
+
+  // Called when growing the table.
+  static bool IsMatch(const Object& a, const Object& b) {
+    ASSERT(a.IsType() && b.IsType());
+    const Type& arg1 = Type::Cast(a);
+    const Type& arg2 = Type::Cast(b);
+    return arg1.Equals(arg2) && (arg1.Hash() == arg2.Hash());
+  }
+  static bool IsMatch(const CanonicalTypeKey& a, const Object& b) {
+    ASSERT(b.IsType());
+    return a.Matches(Type::Cast(b));
+  }
+  static uword Hash(const Object& key) {
+    ASSERT(key.IsType());
+    return Type::Cast(key).Hash();
+  }
+  static uword Hash(const CanonicalTypeKey& key) {
+    return key.Hash();
+  }
+  static RawObject* NewKey(const CanonicalTypeKey& obj) {
+    return obj.key_.raw();
+  }
+};
+typedef UnorderedHashSet <CanonicalTypeTraits> CanonicalTypeSet;
+
+
+class CanonicalTypeArgumentsKey {
+ public:
+  explicit CanonicalTypeArgumentsKey(const TypeArguments& key) : key_(key) {
+  }
+  bool Matches(const TypeArguments& arg) const {
+    return key_.Equals(arg) && (key_.Hash() == arg.Hash());
+  }
+  uword Hash() const {
+    return key_.Hash();
+  }
+  const TypeArguments& key_;
+
+ private:
+  DISALLOW_ALLOCATION();
+};
+
+
+// Traits for looking up Canonical TypeArguments based on its hash.
+class CanonicalTypeArgumentsTraits {
+ public:
+  static const char* Name() { return "CanonicalTypeArgumentsTraits"; }
+  static bool ReportStats() { return false; }
+
+  // Called when growing the table.
+  static bool IsMatch(const Object& a, const Object& b) {
+    ASSERT(a.IsTypeArguments() && b.IsTypeArguments());
+    const TypeArguments& arg1 = TypeArguments::Cast(a);
+    const TypeArguments& arg2 = TypeArguments::Cast(b);
+    return arg1.Equals(arg2) && (arg1.Hash() == arg2.Hash());
+  }
+  static bool IsMatch(const CanonicalTypeArgumentsKey& a, const Object& b) {
+    ASSERT(b.IsTypeArguments());
+    return a.Matches(TypeArguments::Cast(b));
+  }
+  static uword Hash(const Object& key) {
+    ASSERT(key.IsTypeArguments());
+    return TypeArguments::Cast(key).Hash();
+  }
+  static uword Hash(const CanonicalTypeArgumentsKey& key) {
+    return key.Hash();
+  }
+  static RawObject* NewKey(const CanonicalTypeArgumentsKey& obj) {
+    return obj.key_.raw();
+  }
+};
+typedef UnorderedHashSet<CanonicalTypeArgumentsTraits>
+    CanonicalTypeArgumentsSet;
+
+}  // namespace dart
+
+#endif  // VM_TYPE_TABLE_H_
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index 54352e5..c6b6bdb 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -17,6 +17,7 @@
 #include "vm/compiler.h"
 #include "vm/dart_api_impl.h"
 #include "vm/disassembler.h"
+#include "vm/isolate_reload.h"
 #include "vm/parser.h"
 #include "vm/symbols.h"
 #include "vm/thread.h"
@@ -66,11 +67,62 @@
 
 static const char* kPackageScheme = "package:";
 
+
 static bool IsPackageSchemeURL(const char* url_name) {
   static const intptr_t kPackageSchemeLen = strlen(kPackageScheme);
   return (strncmp(url_name, kPackageScheme, kPackageSchemeLen) == 0);
 }
 
+
+static bool IsImportableTestLib(const char* url_name) {
+  const char* kImportTestLibUri = "importable_test_lib";
+  static const intptr_t kImportTestLibUriLen = strlen(kImportTestLibUri);
+  return (strncmp(url_name, kImportTestLibUri, kImportTestLibUriLen) == 0);
+}
+
+
+static Dart_Handle ImportableTestLibSource() {
+  const char* kScript =
+      "importedFunc() => 'a';\n"
+      "importedIntFunc() => 4;\n"
+      "class ImportedMixin {\n"
+      "  mixinFunc() => 'mixin';\n"
+      "}\n";
+  return DartUtils::NewString(kScript);
+}
+
+
+static bool IsIsolateReloadTestLib(const char* url_name) {
+  const char* kIsolateReloadTestLibUri = "isolate_reload_test_helper";
+  static const intptr_t kIsolateReloadTestLibUriLen =
+      strlen(kIsolateReloadTestLibUri);
+  return (strncmp(url_name,
+                  kIsolateReloadTestLibUri,
+                  kIsolateReloadTestLibUriLen) == 0);
+}
+
+
+#ifndef PRODUCT
+static Dart_Handle IsolateReloadTestLibSource() {
+  // Special library with one function.
+  return DartUtils::NewString("void reloadTest() native 'Reload_Test';\n");
+}
+
+
+static void ReloadTest(Dart_NativeArguments native_args) {
+  DART_CHECK_VALID(TestCase::TriggerReload());
+}
+
+
+static Dart_NativeFunction IsolateReloadTestNativeResolver(
+    Dart_Handle name,
+    int num_of_arguments,
+    bool* auto_setup_scope) {
+  return ReloadTest;
+}
+#endif  // !PRODUCT
+
+
 static Dart_Handle ResolvePackageUri(const char* uri_chars) {
   const int kNumArgs = 1;
   Dart_Handle dart_args[kNumArgs];
@@ -81,9 +133,25 @@
                      dart_args);
 }
 
+
+static ThreadLocalKey script_reload_key = kUnsetThreadLocalKey;
+
 static Dart_Handle LibraryTagHandler(Dart_LibraryTag tag,
                                      Dart_Handle library,
                                      Dart_Handle url) {
+  if (tag == Dart_kScriptTag) {
+    // Reload request.
+    ASSERT(script_reload_key != kUnsetThreadLocalKey);
+    const char* script_source =
+       reinterpret_cast<const char*>(
+           OSThread::GetThreadLocal(script_reload_key));
+    ASSERT(script_source != NULL);
+    OSThread::SetThreadLocal(script_reload_key, NULL);
+    return Dart_LoadScript(url,
+                           NewString(script_source),
+                           0,
+                           0);
+  }
   if (!Dart_IsLibrary(library)) {
     return Dart_NewApiError("not a library");
   }
@@ -105,6 +173,10 @@
   bool is_dart_scheme_url = DartUtils::IsDartSchemeURL(url_chars);
   bool is_io_library = DartUtils::IsDartIOLibURL(library_url_string);
   if (tag == Dart_kCanonicalizeUrl) {
+    // Already canonicalized.
+    if (IsImportableTestLib(url_chars) || IsIsolateReloadTestLib(url_chars)) {
+      return url;
+    }
     // If this is a Dart Scheme URL then it is not modified as it will be
     // handled by the VM internally.
     if (is_dart_scheme_url || is_io_library) {
@@ -128,6 +200,17 @@
       return DartUtils::NewError("Do not know how to load '%s'", url_chars);
     }
   }
+  if (IsImportableTestLib(url_chars)) {
+    return Dart_LoadLibrary(url, ImportableTestLibSource(), 0, 0);
+  }
+  NOT_IN_PRODUCT(
+  if (IsIsolateReloadTestLib(url_chars)) {
+    Dart_Handle library =
+        Dart_LoadLibrary(url, IsolateReloadTestLibSource(), 0, 0);
+    DART_CHECK_VALID(library);
+    Dart_SetNativeResolver(library, IsolateReloadTestNativeResolver, 0);
+    return library;
+  })
   if (is_io_library) {
     ASSERT(tag == Dart_kSourceTag);
     return Dart_LoadSource(library,
@@ -177,6 +260,61 @@
 }
 
 
+#ifndef PRODUCT
+
+
+void TestCase::SetReloadTestScript(const char* script) {
+  if (script_reload_key == kUnsetThreadLocalKey) {
+    script_reload_key = OSThread::CreateThreadLocal();
+  }
+  ASSERT(script_reload_key != kUnsetThreadLocalKey);
+  ASSERT(OSThread::GetThreadLocal(script_reload_key) == 0);
+  // Store the new script in TLS.
+  OSThread::SetThreadLocal(script_reload_key, reinterpret_cast<uword>(script));
+}
+
+
+Dart_Handle TestCase::TriggerReload() {
+  Isolate* isolate = Isolate::Current();
+
+  {
+    TransitionNativeToVM transition(Thread::Current());
+    isolate->ReloadSources(/* test_mode = */ true);
+  }
+
+  return Dart_FinalizeLoading(false);
+}
+
+
+Dart_Handle TestCase::GetReloadErrorOrRootLibrary() {
+  Isolate* isolate = Isolate::Current();
+
+  if (isolate->reload_context() != NULL) {
+    // We should only have a reload context hanging around if an error occurred.
+    ASSERT(isolate->reload_context()->has_error());
+    // Return a handle to the error.
+    return Api::NewHandle(Thread::Current(),
+                          isolate->reload_context()->error());
+  }
+  return Dart_RootLibrary();
+}
+
+
+Dart_Handle TestCase::ReloadTestScript(const char* script) {
+  SetReloadTestScript(script);
+
+  Dart_Handle result = TriggerReload();
+  if (Dart_IsError(result)) {
+    return result;
+  }
+
+  return GetReloadErrorOrRootLibrary();
+}
+
+
+#endif  // !PRODUCT
+
+
 Dart_Handle TestCase::LoadCoreTestScript(const char* script,
                                          Dart_NativeEntryResolver resolver) {
   return LoadTestScript(script, resolver, CORELIB_TEST_URI);
@@ -219,13 +357,12 @@
       String::Handle(String::New(kDummyScript)),
       RawScript::kSourceTag));
   script.Tokenize(String::Handle());
-
+  const Library& lib = Library::Handle(Library::CoreLibrary());
   const Class& cls = Class::ZoneHandle(
-      Class::New(function_name,
+      Class::New(lib,
+                 function_name,
                  script,
                  TokenPosition::kMinSource));
-  const Library& lib = Library::ZoneHandle(Library::New(function_name));
-  cls.set_library(lib);
   Function& function = Function::ZoneHandle(
       Function::New(function_name, RawFunction::kRegularFunction,
                     true, false, false, false, false, cls,
@@ -254,8 +391,9 @@
       Symbols::New(Thread::Current(), name));
   // Add function to a class and that class to the class dictionary so that
   // frame walking can be used.
+  Library& lib = Library::Handle(Library::CoreLibrary());
   const Class& cls = Class::ZoneHandle(
-       Class::New(function_name, Script::Handle(),
+      Class::New(lib, function_name, Script::Handle(),
                   TokenPosition::kMinSource));
   function_ = Function::New(
       function_name, RawFunction::kRegularFunction,
@@ -264,7 +402,6 @@
   const Array& functions = Array::Handle(Array::New(1));
   functions.SetAt(0, function_);
   cls.SetFunctions(functions);
-  Library& lib = Library::Handle(Library::CoreLibrary());
   lib.AddClass(cls);
 }
 
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index a8224c5..ac7645a 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -286,7 +286,6 @@
                                     Dart_NativeEntryResolver resolver,
                                     const char* lib_uri = USER_TEST_URI,
                                     bool finalize = true);
-
   static Dart_Handle LoadCoreTestScript(const char* script,
                                         Dart_NativeEntryResolver resolver);
   static Dart_Handle lib();
@@ -305,6 +304,16 @@
 
   virtual void Run();
 
+  // Sets |script| to be the source used at next reload.
+  static void SetReloadTestScript(const char* script);
+  // Initiates the reload.
+  static Dart_Handle TriggerReload();
+  // Gets the result of a reload.
+  static Dart_Handle GetReloadErrorOrRootLibrary();
+
+  // Helper function which reloads the current isolate using |script|.
+  static Dart_Handle ReloadTestScript(const char* script);
+
  private:
   static Dart_Isolate CreateIsolate(const uint8_t* buffer, const char* name);
 
@@ -586,6 +595,24 @@
 void ElideJSONSubstring(const char* prefix, const char* in, char* out);
 
 
+template<typename T>
+class SetFlagScope : public ValueObject {
+ public:
+  SetFlagScope(T* flag, T value)
+      : flag_(flag),
+        original_value_(*flag) {
+    *flag_ = value;
+  }
+
+  ~SetFlagScope() {
+    *flag_ = original_value_;
+  }
+
+ private:
+  T* flag_;
+  T original_value_;
+};
+
 }  // namespace dart
 
 #endif  // VM_UNIT_TEST_H_
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index 210cfcd..edb97e4 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -49,6 +49,8 @@
     'atomic_test.cc',
     'atomic_win.h',
     'base_isolate.h',
+    'become.h',
+    'become.cc',
     'benchmark_test.cc',
     'benchmark_test.h',
     'bigint_test.cc',
@@ -256,6 +258,9 @@
     'intrinsifier_x64.cc',
     'isolate.cc',
     'isolate.h',
+    'isolate_reload.cc',
+    'isolate_reload.h',
+    'isolate_reload_test.cc',
     'isolate_test.cc',
     'jit_optimizer.cc',
     'jit_optimizer.h',
@@ -313,6 +318,7 @@
     'object_id_ring.h',
     'object_id_ring_test.cc',
     'object_mips_test.cc',
+    'object_reload.cc',
     'object_service.cc',
     'object_set.h',
     'object_store.cc',
@@ -490,6 +496,7 @@
     'token.h',
     'token_position.cc',
     'token_position.h',
+    'type_table.h',
     'unibrow.cc',
     'unibrow.h',
     'unibrow-inl.h',
diff --git a/sdk/lib/_internal/js_runtime/lib/collection_patch.dart b/sdk/lib/_internal/js_runtime/lib/collection_patch.dart
index 7d15ab8..beb67f2 100644
--- a/sdk/lib/_internal/js_runtime/lib/collection_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/collection_patch.dart
@@ -839,7 +839,7 @@
 
   // When iterating over the hash set, it is very convenient to have a
   // list of all the elements. We cache that on the instance and clear
-  // the the cache whenever the set changes. This is also used to
+  // the cache whenever the set changes. This is also used to
   // guard against concurrent modifications.
   List _elements;
 
diff --git a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
index 7a2c5a6..b1073b2 100644
--- a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
@@ -52,6 +52,11 @@
 
 
 @patch
+bool _isDartStreamEnabled() {
+  return false;
+}
+
+@patch
 int _getTraceClock() {
   // TODO.
   return _clockValue++;
diff --git a/sdk/lib/_internal/js_runtime/lib/interceptors.dart b/sdk/lib/_internal/js_runtime/lib/interceptors.dart
index 25fbb11..23025ad 100644
--- a/sdk/lib/_internal/js_runtime/lib/interceptors.dart
+++ b/sdk/lib/_internal/js_runtime/lib/interceptors.dart
@@ -373,9 +373,9 @@
  * have a type mask that contains the objects that we can use the
  * native JS [] operator and length on.
  */
-abstract class JSIndexable {
+abstract class JSIndexable<E> {
   int get length;
-  operator[](int index);
+  E operator[](int index);
 }
 
 /**
@@ -383,8 +383,8 @@
  * JavaScriptIndexingBehavior. Used by the backend to have a type mask
  * that contains the objects we can use the JS []= operator on.
  */
-abstract class JSMutableIndexable extends JSIndexable {
-  operator[]=(int index, var value);
+abstract class JSMutableIndexable<E> extends JSIndexable<E> {
+  operator[]=(int index, E value);
 }
 
 /**
diff --git a/sdk/lib/_internal/js_runtime/lib/io_patch.dart b/sdk/lib/_internal/js_runtime/lib/io_patch.dart
index 4487e15..d941bb2 100644
--- a/sdk/lib/_internal/js_runtime/lib/io_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/io_patch.dart
@@ -39,8 +39,10 @@
     throw new UnsupportedError("Directory._rename");
   }
   @patch
-  static List _list(String path, bool recursive, bool followLinks) {
-    throw new UnsupportedError("Directory._list");
+  static void _fillWithDirectoryListing(
+      List<FileSystemEntity> list, String path, bool recursive,
+      bool followLinks) {
+    throw new UnsupportedError("Directory._fillWithDirectoryListing");
   }
 }
 
@@ -308,6 +310,11 @@
       String host, {InternetAddressType type: InternetAddressType.ANY}) {
     throw new UnsupportedError("InternetAddress.lookup");
   }
+  @patch
+  static InternetAddress _cloneWithNewHost(
+      InternetAddress address, String host) {
+    throw new UnsupportedError("InternetAddress._cloneWithNewHost");
+  }
 }
 
 @patch
@@ -427,7 +434,7 @@
     throw new UnsupportedError("StdIOUtils._getStdioOutputStream");
   }
   @patch
-  static int _socketType(nativeSocket) {
+  static int _socketType(Socket socket) {
     throw new UnsupportedError("StdIOUtils._socketType");
   }
   @patch
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index 7d2e968..5e4d69a 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -1299,6 +1299,19 @@
           return JS('', '#[#](#[0],#[1],#[2])', function, selectorName,
           arguments, arguments, arguments);
         }
+      } else if (argumentCount == 4) {
+        String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX4);
+        if (JS('bool', '!!#[#]', function, selectorName)) {
+          return JS('', '#[#](#[0],#[1],#[2],#[3])', function, selectorName,
+          arguments, arguments, arguments, arguments);
+        }
+      } else if (argumentCount == 5) {
+        String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX5);
+        if (JS('bool', '!!#[#]', function, selectorName)) {
+          return JS('', '#[#](#[0],#[1],#[2],#[3],#[4])',
+          function, selectorName,
+          arguments, arguments, arguments, arguments, arguments);
+        }
       }
       String selectorName =
           '${JS_GET_NAME(JsGetName.CALL_PREFIX)}\$$argumentCount';
@@ -1465,6 +1478,18 @@
         return JS('', '#[#](#[0],#[1],#[2])', function, selectorName,
             arguments, arguments, arguments);
       }
+    } else if (arguments.length == 4) {
+      String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX4);
+      if (JS('bool', '!!#[#]', function, selectorName)) {
+        return JS('', '#[#](#[0],#[1],#[2],#[3])', function, selectorName,
+            arguments, arguments, arguments, arguments);
+      }
+    } else if (arguments.length == 5) {
+      String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX5);
+      if (JS('bool', '!!#[#]', function, selectorName)) {
+        return JS('', '#[#](#[0],#[1],#[2],#[3],#[4])', function, selectorName,
+            arguments, arguments, arguments, arguments, arguments);
+      }
     }
     return _genericApplyFunctionWithPositionalArguments(function, arguments);
   }
@@ -3328,7 +3353,7 @@
  * objects that support integer indexing. This interface is not
  * visible to anyone, and is only injected into special libraries.
  */
-abstract class JavaScriptIndexingBehavior extends JSMutableIndexable {
+abstract class JavaScriptIndexingBehavior<E> extends JSMutableIndexable<E> {
 }
 
 // TODO(lrn): These exceptions should be implemented in core.
diff --git a/sdk/lib/_internal/js_runtime/lib/js_string.dart b/sdk/lib/_internal/js_runtime/lib/js_string.dart
index ed8189d..e82868c 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_string.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_string.dart
@@ -246,7 +246,7 @@
     return index;
   }
 
-  /// Finds the index after the the last non-whitespace character, or 0.
+  /// Finds the index after the last non-whitespace character, or 0.
   /// Start looking at position [index - 1].
   static int _skipTrailingWhitespace(String string, int index) {
     const int SPACE = 0x20;
diff --git a/sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart b/sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart
index cef7f93..ada768f 100644
--- a/sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart
+++ b/sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart
@@ -26,8 +26,8 @@
 
   // The keys and values are stored in cells that are linked together
   // to form a double linked list.
-  LinkedHashMapCell _first;
-  LinkedHashMapCell _last;
+  LinkedHashMapCell/*<K, V>*/ _first;
+  LinkedHashMapCell/*<K, V>*/ _last;
 
   // We track the number of modifications done to the key set of the
   // hash map to be able to throw when the map is modified while being
@@ -92,16 +92,16 @@
     });
   }
 
-  V operator[](Object key) {
+  V operator [](Object key) {
     if (_isStringKey(key)) {
       var strings = _strings;
       if (strings == null) return null;
-      LinkedHashMapCell cell = _getTableEntry(strings, key);
+      LinkedHashMapCell/*<K, V>*/ cell = _getTableCell(strings, key);
       return (cell == null) ? null : cell.hashMapCellValue;
     } else if (_isNumericKey(key)) {
       var nums = _nums;
       if (nums == null) return null;
-      LinkedHashMapCell cell = _getTableEntry(nums, key);
+      LinkedHashMapCell/*<K, V>*/ cell = _getTableCell(nums, key);
       return (cell == null) ? null : cell.hashMapCellValue;
     } else {
       return internalGet(key);
@@ -114,11 +114,11 @@
     var bucket = _getBucket(rest, key);
     int index = internalFindBucketIndex(bucket, key);
     if (index < 0) return null;
-    LinkedHashMapCell cell = JS('var', '#[#]', bucket, index);
+    LinkedHashMapCell/*<K, V>*/ cell = JS('var', '#[#]', bucket, index);
     return cell.hashMapCellValue;
   }
 
-  void operator[]=(K key, V value) {
+  void operator []=(K key, V value) {
     if (_isStringKey(key)) {
       var strings = _strings;
       if (strings == null) _strings = strings = _newHashTable();
@@ -136,17 +136,17 @@
     var rest = _rest;
     if (rest == null) _rest = rest = _newHashTable();
     var hash = internalComputeHashCode(key);
-    var bucket = _getTableEntry(rest, hash);
+    var bucket = _getTableBucket(rest, hash);
     if (bucket == null) {
-      LinkedHashMapCell cell = _newLinkedCell(key, value);
+      LinkedHashMapCell/*<K, V>*/ cell = _newLinkedCell(key, value);
       _setTableEntry(rest, hash, JS('var', '[#]', cell));
     } else {
       int index = internalFindBucketIndex(bucket, key);
       if (index >= 0) {
-        LinkedHashMapCell cell = JS('var', '#[#]', bucket, index);
+        LinkedHashMapCell/*<K, V>*/ cell = JS('var', '#[#]', bucket, index);
         cell.hashMapCellValue = value;
       } else {
-        LinkedHashMapCell cell = _newLinkedCell(key, value);
+        LinkedHashMapCell/*<K, V>*/ cell = _newLinkedCell(key, value);
         JS('void', '#.push(#)', bucket, cell);
       }
     }
@@ -177,7 +177,8 @@
     if (index < 0) return null;
     // Use splice to remove the [cell] element at the index and
     // unlink the cell before returning its value.
-    LinkedHashMapCell cell = JS('var', '#.splice(#, 1)[0]', bucket, index);
+    LinkedHashMapCell/*<K, V>*/ cell =
+        JS('var', '#.splice(#, 1)[0]', bucket, index);
     _unlinkCell(cell);
     // TODO(kasperl): Consider getting rid of the bucket list when
     // the length reaches zero.
@@ -193,7 +194,7 @@
   }
 
   void forEach(void action(K key, V value)) {
-    LinkedHashMapCell cell = _first;
+    LinkedHashMapCell/*<K, V>*/ cell = _first;
     int modifications = _modifications;
     while (cell != null) {
       action(cell.hashMapCellKey, cell.hashMapCellValue);
@@ -205,7 +206,7 @@
   }
 
   void _addHashTableEntry(var table, K key, V value) {
-    LinkedHashMapCell cell = _getTableEntry(table, key);
+    LinkedHashMapCell/*<K, V>*/ cell = _getTableCell(table, key);
     if (cell == null) {
       _setTableEntry(table, key, _newLinkedCell(key, value));
     } else {
@@ -215,7 +216,7 @@
 
   V _removeHashTableEntry(var table, Object key) {
     if (table == null) return null;
-    LinkedHashMapCell cell = _getTableEntry(table, key);
+    LinkedHashMapCell/*<K, V>*/ cell = _getTableCell(table, key);
     if (cell == null) return null;
     _unlinkCell(cell);
     _deleteTableEntry(table, key);
@@ -231,12 +232,13 @@
   }
 
   // Create a new cell and link it in as the last one in the list.
-  LinkedHashMapCell _newLinkedCell(K key, V value) {
-    LinkedHashMapCell cell = new LinkedHashMapCell(key, value);
+  LinkedHashMapCell/*<K, V>*/ _newLinkedCell(K key, V value) {
+    LinkedHashMapCell/*<K, V>*/ cell =
+        new LinkedHashMapCell/*<K, V>*/(key, value);
     if (_first == null) {
       _first = _last = cell;
     } else {
-      LinkedHashMapCell last = _last;
+      LinkedHashMapCell/*<K, V>*/ last = _last;
       cell._previous = last;
       _last = last._next = cell;
     }
@@ -246,9 +248,9 @@
   }
 
   // Unlink the given cell from the linked list of cells.
-  void _unlinkCell(LinkedHashMapCell cell) {
-    LinkedHashMapCell previous = cell._previous;
-    LinkedHashMapCell next = cell._next;
+  void _unlinkCell(LinkedHashMapCell/*<K, V>*/ cell) {
+    LinkedHashMapCell/*<K, V>*/ previous = cell._previous;
+    LinkedHashMapCell/*<K, V>*/ next = cell._next;
     if (previous == null) {
       assert(cell == _first);
       _first = next;
@@ -283,16 +285,16 @@
     return JS('int', '# & 0x3ffffff', key.hashCode);
   }
 
-  List _getBucket(var table, var key) {
+  List<dynamic/*=LinkedHashMapCell<K, V>*/ > _getBucket(var table, var key) {
     var hash = internalComputeHashCode(key);
-    return _getTableEntry(table, hash);
+    return _getTableBucket(table, hash);
   }
 
   int internalFindBucketIndex(var bucket, var key) {
     if (bucket == null) return -1;
     int length = JS('int', '#.length', bucket);
     for (int i = 0; i < length; i++) {
-      LinkedHashMapCell cell = JS('var', '#[#]', bucket, i);
+      LinkedHashMapCell/*<K, V>*/ cell = JS('var', '#[#]', bucket, i);
       if (cell.hashMapCellKey == key) return i;
     }
     return -1;
@@ -300,7 +302,11 @@
 
   String toString() => Maps.mapToString(this);
 
-  _getTableEntry(var table, var key) {
+  /*=LinkedHashMapCell<K, V>*/ _getTableCell(var table, var key) {
+    return JS('var', '#[#]', table, key);
+  }
+
+  /*=List<LinkedHashMapCell<K, V>>*/ _getTableBucket(var table, var key) {
     return JS('var', '#[#]', table, key);
   }
 
@@ -314,7 +320,7 @@
   }
 
   bool _containsTableEntry(var table, var key) {
-    LinkedHashMapCell cell = _getTableEntry(table, key);
+    LinkedHashMapCell/*<K, V>*/ cell = _getTableCell(table, key);
     return cell != null;
   }
 
@@ -333,9 +339,13 @@
 }
 
 class Es6LinkedHashMap<K, V> extends JsLinkedHashMap<K, V> {
+  @override
+  /*=LinkedHashMapCell<K, V>*/ _getTableCell(var table, var key) {
+    return JS('var', '#.get(#)', table, key);
+  }
 
   @override
-  _getTableEntry(var table, var key) {
+  /*=List<LinkedHashMapCell<K, V>>*/ _getTableBucket(var table, var key) {
     return JS('var', '#.get(#)', table, key);
   }
 
@@ -360,19 +370,19 @@
   }
 }
 
-class LinkedHashMapCell {
-  final hashMapCellKey;
-  var hashMapCellValue;
+class LinkedHashMapCell<K, V> {
+  final dynamic/*=K*/ hashMapCellKey;
+  dynamic/*=V*/ hashMapCellValue;
 
-  LinkedHashMapCell _next;
-  LinkedHashMapCell _previous;
+  LinkedHashMapCell/*<K, V>*/ _next;
+  LinkedHashMapCell/*<K, V>*/ _previous;
 
   LinkedHashMapCell(this.hashMapCellKey, this.hashMapCellValue);
 }
 
 class LinkedHashMapKeyIterable<E> extends Iterable<E>
-                                  implements EfficientLength {
-  final _map;
+    implements EfficientLength {
+  final dynamic/*=JsLinkedHashMap<E, dynamic>*/ _map;
   LinkedHashMapKeyIterable(this._map);
 
   int get length => _map._length;
@@ -387,7 +397,7 @@
   }
 
   void forEach(void f(E element)) {
-    LinkedHashMapCell cell = _map._first;
+    LinkedHashMapCell/*<E, dynamic>*/ cell = _map._first;
     int modifications = _map._modifications;
     while (cell != null) {
       f(cell.hashMapCellKey);
@@ -400,9 +410,9 @@
 }
 
 class LinkedHashMapKeyIterator<E> implements Iterator<E> {
-  final _map;
+  final dynamic/*=JsLinkedHashMap<E, dynamic>*/ _map;
   final int _modifications;
-  LinkedHashMapCell _cell;
+  LinkedHashMapCell/*<E, dynamic>*/ _cell;
   E _current;
 
   LinkedHashMapKeyIterator(this._map, this._modifications) {
diff --git a/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart b/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
index b08e3a3..54e7935 100644
--- a/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
+++ b/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
@@ -304,6 +304,8 @@
   CALL_PREFIX1,
   CALL_PREFIX2,
   CALL_PREFIX3,
+  CALL_PREFIX4,
+  CALL_PREFIX5,
   CALL_CATCH_ALL,
   REFLECTABLE,
   CLASS_DESCRIPTOR_PROPERTY,
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index 23bf531..e0e0617 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -363,18 +363,19 @@
   }
 
   /**
-   * Perform an async operation repeatedly until it returns `false`.
+   * Performs an async operation repeatedly until it returns `false`.
    *
-   * Runs [f] repeatedly, starting the next iteration only when the [Future]
-   * returned by [f] completes to `true`. Returns a [Future] that completes once
-   * [f] returns `false`.
+   * The function [f] is called repeatedly while it returns either the [bool]
+   * value `true` or a [Future] which completes with the value `true`.
    *
-   * The return values of all [Future]s are discarded. Any errors will cause the
-   * iteration to stop and will be piped through the returned [Future].
+   * If a call to [f] returns `false` or a [Future] that completes to `false`,
+   * iteration ends and the future returned by [doWhile] is completed.
    *
-   * The function [f] may return either a [bool] or a [Future] that completes to
-   * a [bool]. If it returns a non-[Future], iteration continues immediately.
-   * Otherwise it waits for the returned [Future] to complete.
+   * If a future returned by [f] completes with an error, iteration ends and
+   * the future returned by [doWhile] completes with the same error.
+   *
+   * The [f] function must return either a `bool` value or a [Future] completing
+   * with a `bool` value.
    */
   static Future doWhile(f()) {
     _Future doneSignal = new _Future();
@@ -459,7 +460,7 @@
    *
    * If `test` is omitted, it defaults to a function that always returns true.
    * The `test` function should not throw, but if it does, it is handled as
-   * if the the `onError` function had thrown.
+   * if the `onError` function had thrown.
    *
    * Example:
    *
diff --git a/sdk/lib/async/future_impl.dart b/sdk/lib/async/future_impl.dart
index eb4d6cf..dd07720 100644
--- a/sdk/lib/async/future_impl.dart
+++ b/sdk/lib/async/future_impl.dart
@@ -277,6 +277,11 @@
     _state = _PENDING_COMPLETE;
   }
 
+  void _clearPendingComplete() {
+    assert(_isPendingComplete);
+    _state = _INCOMPLETE;
+  }
+
   AsyncError get _error {
     assert(_hasError);
     return _resultOrListeners;
@@ -405,7 +410,11 @@
     try {
       source.then((value) {
           assert(target._isPendingComplete);
-          target._completeWithValue(value);
+          // The "value" may be another future if the foreign future
+          // implementation is mis-behaving,
+          // so use _complete instead of _completeWithValue.
+          target._clearPendingComplete();  // Clear this first, it's set again.
+          target._complete(value);
         },
         // TODO(floitsch): eventually we would like to make this non-optional
         // and dependent on the listeners of the target future. If none of
@@ -650,7 +659,7 @@
           }
         }
 
- 
+
         if (listener.handlesComplete) {
           handleWhenCompleteCallback();
         } else if (!hasError) {
@@ -662,7 +671,7 @@
             handleError();
           }
         }
-        
+
         // If we changed zone, oldZone will not be null.
         if (oldZone != null) Zone._leave(oldZone);
 
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 6931373..eca6c34 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -503,7 +503,7 @@
    *
    * The [onError] callback must be of type `void onError(error)` or
    * `void onError(error, StackTrace stackTrace)`. Depending on the function
-   * type the the stream either invokes [onError] with or without a stack
+   * type the stream either invokes [onError] with or without a stack
    * trace. The stack trace argument might be `null` if the stream itself
    * received an error without stack trace.
    *
diff --git a/sdk/lib/async/stream_impl.dart b/sdk/lib/async/stream_impl.dart
index dffaa12..8c9af64 100644
--- a/sdk/lib/async/stream_impl.dart
+++ b/sdk/lib/async/stream_impl.dart
@@ -145,7 +145,9 @@
 
   void onError(Function handleError) {
     if (handleError == null) handleError = _nullErrorHandler;
-    _onError = _registerErrorHandler/*<T>*/(handleError, _zone);
+    // We are not allowed to use 'void' as type argument for the generic type,
+    // so we use 'dynamic' instead.
+    _onError = _registerErrorHandler/*<dynamic>*/(handleError, _zone);
   }
 
   void onDone(void handleDone()) {
diff --git a/sdk/lib/collection/hash_map.dart b/sdk/lib/collection/hash_map.dart
index a5f31b6..c8c31c5 100644
--- a/sdk/lib/collection/hash_map.dart
+++ b/sdk/lib/collection/hash_map.dart
@@ -102,7 +102,7 @@
    */
   factory HashMap.from(Map other) {
     HashMap<K, V> result = new HashMap<K, V>();
-    other.forEach((k, v) { result[k] = v; });
+    other.forEach((k, v) { result[k as Object/*=K*/] = v as Object/*=V*/; });
     return result;
   }
 
diff --git a/sdk/lib/collection/hash_set.dart b/sdk/lib/collection/hash_set.dart
index 3ecb82c..8e2a2a1 100644
--- a/sdk/lib/collection/hash_set.dart
+++ b/sdk/lib/collection/hash_set.dart
@@ -121,7 +121,10 @@
    */
   factory HashSet.from(Iterable elements) {
     HashSet<E> result = new HashSet<E>();
-    for (E e in elements) result.add(e);
+    for (final e in elements) {
+      E element = e as Object/*=E*/;
+      result.add(element);
+    }
     return result;
   }
 
diff --git a/sdk/lib/collection/iterable.dart b/sdk/lib/collection/iterable.dart
index c0d2ee0..26ccb5c 100644
--- a/sdk/lib/collection/iterable.dart
+++ b/sdk/lib/collection/iterable.dart
@@ -121,7 +121,7 @@
   }
 
   E get first {
-    Iterator it = iterator;
+    Iterator<E> it = iterator;
     if (!it.moveNext()) {
       throw IterableElementError.noElement();
     }
@@ -129,7 +129,7 @@
   }
 
   E get last {
-    Iterator it = iterator;
+    Iterator<E> it = iterator;
     if (!it.moveNext()) {
       throw IterableElementError.noElement();
     }
@@ -141,7 +141,7 @@
   }
 
   E get single {
-    Iterator it = iterator;
+    Iterator<E> it = iterator;
     if (!it.moveNext()) throw IterableElementError.noElement();
     E result = it.current;
     if (it.moveNext()) throw IterableElementError.tooMany();
diff --git a/sdk/lib/collection/iterator.dart b/sdk/lib/collection/iterator.dart
index 1fe49cd..f870711 100644
--- a/sdk/lib/collection/iterator.dart
+++ b/sdk/lib/collection/iterator.dart
@@ -15,7 +15,7 @@
   static const int _NO_NEXT = 1;
   static const int _NOT_MOVED_YET = 2;
 
-  Iterator _iterator;
+  Iterator<E> _iterator;
   int _state = _NOT_MOVED_YET;
 
   HasNextIterator(this._iterator);
diff --git a/sdk/lib/collection/linked_hash_map.dart b/sdk/lib/collection/linked_hash_map.dart
index 0f76652..91814ed 100644
--- a/sdk/lib/collection/linked_hash_map.dart
+++ b/sdk/lib/collection/linked_hash_map.dart
@@ -89,7 +89,7 @@
    */
   factory LinkedHashMap.from(Map other) {
     LinkedHashMap<K, V> result = new LinkedHashMap<K, V>();
-    other.forEach((k, v) { result[k] = v; });
+    other.forEach((k, v) { result[k as Object/*=K*/] = v as Object/*=V*/; });
     return result;
   }
 
diff --git a/sdk/lib/collection/linked_hash_set.dart b/sdk/lib/collection/linked_hash_set.dart
index e087b5f..3bc170f 100644
--- a/sdk/lib/collection/linked_hash_set.dart
+++ b/sdk/lib/collection/linked_hash_set.dart
@@ -104,8 +104,9 @@
    */
   factory LinkedHashSet.from(Iterable elements) {
     LinkedHashSet<E> result = new LinkedHashSet<E>();
-    for (final E element in elements) {
-      result.add(element);
+    for (final element in elements) {
+      E e = element as Object/*=E*/;
+      result.add(e);
     }
     return result;
   }
diff --git a/sdk/lib/collection/linked_list.dart b/sdk/lib/collection/linked_list.dart
index e2139c0..481f04d 100644
--- a/sdk/lib/collection/linked_list.dart
+++ b/sdk/lib/collection/linked_list.dart
@@ -29,40 +29,37 @@
  * and a constant time length getter.
  */
 class LinkedList<E extends LinkedListEntry<E>>
-    extends Iterable<E>
-    implements _LinkedListLink {
+    extends Iterable<E> {
 
   int _modificationCount = 0;
   int _length = 0;
-  _LinkedListLink _next;
-  _LinkedListLink _previous;
+  E _first;
 
   /**
    * Construct a new empty linked list.
    */
-  LinkedList() {
-    _next = _previous = this;
-  }
+  LinkedList();
 
   /**
    * Add [entry] to the beginning of the linked list.
    */
   void addFirst(E entry) {
-    _insertAfter(this, entry);
+    _insertBefore(_first, entry, updateFirst: true);
+    _first = entry;
   }
 
   /**
    * Add [entry] to the end of the linked list.
    */
   void add(E entry) {
-    _insertAfter(_previous, entry);
+    _insertBefore(_first, entry, updateFirst: false);
   }
 
   /**
    * Add [entries] to the end of the linked list.
    */
   void addAll(Iterable<E> entries) {
-    entries.forEach((entry) => _insertAfter(_previous, entry));
+    entries.forEach(add);
   }
 
   /**
@@ -88,38 +85,41 @@
    */
   void clear() {
     _modificationCount++;
-    _LinkedListLink next = _next;
-    while (!identical(next, this)) {
+    if (isEmpty) return;
+
+    E next = _first;
+    do {
       E entry = next;
       next = entry._next;
       entry._next = entry._previous = entry._list = null;
-    }
-    _next = _previous = this;
+    } while (!identical(next, _first));
+
+    _first = null;
     _length = 0;
   }
 
   E get first {
-    if (identical(_next, this)) {
+    if (isEmpty) {
       throw new StateError('No such element');
     }
-    return _next;
+    return _first;
   }
 
   E get last {
-    if (identical(_previous, this)) {
+    if (isEmpty) {
       throw new StateError('No such element');
     }
-    return _previous;
+    return _first._previous;
   }
 
   E get single {
-    if (identical(_previous, this)) {
+    if (isEmpty) {
       throw new StateError('No such element');
     }
-    if (!identical(_previous, _next)) {
+    if (_length > 1) {
       throw new StateError('Too many elements');
     }
-    return _next;
+    return _first;
   }
 
   /**
@@ -129,40 +129,62 @@
    */
   void forEach(void action(E entry)) {
     int modificationCount = _modificationCount;
-    _LinkedListLink current = _next;
-    while (!identical(current, this)) {
+    if (isEmpty) return;
+
+    E current = _first;
+    do {
       action(current);
       if (modificationCount != _modificationCount) {
         throw new ConcurrentModificationError(this);
       }
       current = current._next;
-    }
+    } while (!identical(current, _first));
   }
 
   bool get isEmpty => _length == 0;
 
-  void _insertAfter(_LinkedListLink entry, E newEntry) {
+  /// Inserts [newEntry] as last entry of the list.
+  ///
+  /// If [updateFirst] is true and [entry] is the first entry in the list,
+  /// updates the [_first] field to point to the [newEntry] as first entry.
+  void _insertBefore(E entry, E newEntry, {bool updateFirst}) {
     if (newEntry.list != null) {
       throw new StateError(
           'LinkedListEntry is already in a LinkedList');
     }
     _modificationCount++;
+
     newEntry._list = this;
-    var predecessor = entry;
-    var successor = entry._next;
-    successor._previous = newEntry;
+    if (isEmpty) {
+      assert(entry == null);
+      newEntry._previous = newEntry._next = newEntry;
+      _first = newEntry;
+      _length++;
+      return;
+    }
+    E predecessor = entry._previous;
+    E successor = entry;
     newEntry._previous = predecessor;
     newEntry._next = successor;
     predecessor._next = newEntry;
+    successor._previous = newEntry;
+    if (updateFirst && identical(entry, _first)) {
+      _first = newEntry;
+    }
     _length++;
   }
 
-  void _unlink(LinkedListEntry<E> entry) {
+  void _unlink(E entry) {
     _modificationCount++;
     entry._next._previous = entry._previous;
-    entry._previous._next = entry._next;
+    E next = entry._previous._next = entry._next;
     _length--;
     entry._list = entry._next = entry._previous = null;
+    if (isEmpty) {
+      _first = null;
+    } else if (identical(entry, _first)) {
+      _first = next;
+    }
   }
 }
 
@@ -172,23 +194,27 @@
   final LinkedList<E> _list;
   final int _modificationCount;
   E _current;
-  _LinkedListLink _next;
+  LinkedListEntry<E> _next;
+  bool _visitedFirst;
 
   _LinkedListIterator(LinkedList<E> list)
     : _list = list,
       _modificationCount = list._modificationCount,
-      _next = list._next;
+      _next = list._first,
+      _visitedFirst = false;
 
   E get current => _current;
 
   bool moveNext() {
-    if (identical(_next, _list)) {
-      _current = null;
-      return false;
-    }
     if (_modificationCount != _list._modificationCount) {
       throw new ConcurrentModificationError(this);
     }
+    if (_list.isEmpty ||
+        (_visitedFirst && identical(_next, _list.first))) {
+      _current = null;
+      return false;
+    }
+    _visitedFirst = true;
     _current = _next;
     _next = _next._next;
     return true;
@@ -196,12 +222,6 @@
 }
 
 
-class _LinkedListLink {
-  _LinkedListLink _next;
-  _LinkedListLink _previous;
-}
-
-
 /**
  * An object that can be an element in a [LinkedList].
  *
@@ -216,11 +236,10 @@
  *
  * When created, an entry is not in any linked list.
  */
-abstract class LinkedListEntry<E extends LinkedListEntry<E>>
-    implements _LinkedListLink {
+abstract class LinkedListEntry<E extends LinkedListEntry<E>> {
   LinkedList<E> _list;
-  _LinkedListLink _next;
-  _LinkedListLink _previous;
+  E _next;
+  E _previous;
 
   /**
    * Get the linked list containing this element.
@@ -245,9 +264,8 @@
    * entry is not currently in any list.
    */
   E get next {
-    if (identical(_next, _list)) return null;
-    E result = _next;
-    return result;
+    if (identical(this, _next)) return null;
+    return _next;
   }
 
   /**
@@ -257,8 +275,8 @@
    * entry is not currently in any list.
    */
   E get previous {
-    if (identical(_previous, _list)) return null;
-    return _previous as E;
+    if (identical(this, _previous)) return null;
+    return _previous;
   }
 
   /**
@@ -268,7 +286,7 @@
    * The [entry] must not be in a linked list.
    */
   void insertAfter(E entry) {
-    _list._insertAfter(this, entry);
+    _list._insertBefore(_next, entry, updateFirst: false);
   }
 
   /**
@@ -278,6 +296,6 @@
    * The [entry] must not be in a linked list.
    */
   void insertBefore(E entry) {
-    _list._insertAfter(_previous, entry);
+    _list._insertBefore(this as dynamic/*=E*/, entry, updateFirst: true);
   }
 }
diff --git a/sdk/lib/collection/list.dart b/sdk/lib/collection/list.dart
index 64586d3..7e6dbd3a 100644
--- a/sdk/lib/collection/list.dart
+++ b/sdk/lib/collection/list.dart
@@ -309,10 +309,10 @@
 
   void sort([int compare(E a, E b)]) {
     if (compare == null) {
-      var defaultCompare = Comparable.compare;
-      compare = defaultCompare;
+      Sort.sort(this, Comparable.compare);
+    } else {
+      Sort.sort(this, compare);
     }
-    Sort.sort(this, compare);
   }
 
   void shuffle([Random random]) {
@@ -368,10 +368,10 @@
     if (length == 0) return;
     RangeError.checkNotNegative(skipCount, "skipCount");
 
-    List otherList;
+    List<E> otherList;
     int otherStart;
     // TODO(floitsch): Make this accept more.
-    if (iterable is List) {
+    if (iterable is List/*<E>*/) {
       otherList = iterable;
       otherStart = skipCount;
     } else {
diff --git a/sdk/lib/collection/maps.dart b/sdk/lib/collection/maps.dart
index bd2e736..7871b87 100644
--- a/sdk/lib/collection/maps.dart
+++ b/sdk/lib/collection/maps.dart
@@ -78,7 +78,7 @@
   int get length => keys.length;
   bool get isEmpty => keys.isEmpty;
   bool get isNotEmpty => keys.isNotEmpty;
-  Iterable<V> get values => new _MapBaseValueIterable<V>(this);
+  Iterable<V> get values => new _MapBaseValueIterable<K, V>(this);
   String toString() => Maps.mapToString(this);
 }
 
@@ -111,9 +111,9 @@
  * It accesses the values by iterating over the keys of the map, and using the
  * map's `operator[]` to lookup the keys.
  */
-class _MapBaseValueIterable<V> extends Iterable<V>
-                               implements EfficientLength {
-  final Map _map;
+class _MapBaseValueIterable<K, V> extends Iterable<V>
+                                  implements EfficientLength {
+  final Map<K, V> _map;
   _MapBaseValueIterable(this._map);
 
   int get length => _map.length;
@@ -123,7 +123,7 @@
   V get single => _map[_map.keys.single];
   V get last => _map[_map.keys.last];
 
-  Iterator<V> get iterator => new _MapBaseValueIterator<V>(_map);
+  Iterator<V> get iterator => new _MapBaseValueIterator<K, V>(_map);
 }
 
 /**
@@ -132,12 +132,14 @@
  * Iterates over the values of a map by iterating its keys and lookup up the
  * values.
  */
-class _MapBaseValueIterator<V> implements Iterator<V> {
-  final Iterator _keys;
-  final Map _map;
+class _MapBaseValueIterator<K, V> implements Iterator<V> {
+  final Iterator<K> _keys;
+  final Map<K, V> _map;
   V _current = null;
 
-  _MapBaseValueIterator(Map map) : _map = map, _keys = map.keys.iterator;
+  _MapBaseValueIterator(Map<K, V> map)
+      : _map = map,
+        _keys = map.keys.iterator;
 
   bool moveNext() {
     if (_keys.moveNext()) {
diff --git a/sdk/lib/collection/queue.dart b/sdk/lib/collection/queue.dart
index af8e07a..816f62e 100644
--- a/sdk/lib/collection/queue.dart
+++ b/sdk/lib/collection/queue.dart
@@ -96,12 +96,11 @@
 }
 
 
-class _DoubleLink {
-  _DoubleLink _previousLink;
-  _DoubleLink _nextLink;
+class _DoubleLink<Link extends _DoubleLink> {
+  Link _previousLink;
+  Link _nextLink;
 
-  void _link(_DoubleLink previous,
-             _DoubleLink next) {
+  void _link(Link previous, Link next) {
     _nextLink = next;
     _previousLink = previous;
     if (previous != null) previous._nextLink = this;
@@ -120,15 +119,18 @@
  * An entry in a doubly linked list. It contains a pointer to the next
  * entry, the previous entry, and the boxed element.
  */
-class DoubleLinkedQueueEntry<E> extends _DoubleLink {
+class DoubleLinkedQueueEntry<E> extends _DoubleLink<DoubleLinkedQueueEntry<E>> {
+  /// The element in the queue.
   E element;
 
   DoubleLinkedQueueEntry(this.element);
 
+  /// Appends the given [e] as entry just after this entry.
   void append(E e) {
     new DoubleLinkedQueueEntry<E>(e)._link(this, _nextLink);
   }
 
+  /// Prepends the given [e] as entry just before this entry.
   void prepend(E e) {
     new DoubleLinkedQueueEntry<E>(e)._link(_previousLink, this);
   }
@@ -138,28 +140,27 @@
     return element;
   }
 
-  DoubleLinkedQueueEntry<E> previousEntry() {
-    return _previousLink;
-  }
+  /// Returns the previous entry or `null` if there is none.
+  DoubleLinkedQueueEntry<E> previousEntry() => _previousLink;
 
-  DoubleLinkedQueueEntry<E> nextEntry() {
-    return _nextLink;
-  }
+  /// Returns the next entry or `null` if there is none.
+  DoubleLinkedQueueEntry<E> nextEntry() => _nextLink;
 }
 
 /**
  * Interface for the link classes used by [DoubleLinkedQueue].
  *
  * Both the [_DoubleLinkedQueueElement] and [_DoubleLinkedQueueSentinel]
- * implements this interface.
+ * implement this interface.
  * The entry contains a link back to the queue, so calling `append`
  * or `prepend` can correctly update the element count.
  */
-abstract class _DoubleLinkedQueueEntry<E> extends _DoubleLink {
+abstract class _DoubleLinkedQueueEntry<E>
+    extends DoubleLinkedQueueEntry<E> {
   DoubleLinkedQueue<E> _queue;
-  _DoubleLinkedQueueEntry(this._queue);
+  _DoubleLinkedQueueEntry(E element, this._queue) : super(element);
 
-  _DoubleLinkedQueueElement _asNonSentinelEntry();
+  DoubleLinkedQueueEntry<E> _asNonSentinelEntry();
 
   void _append(E e) {
     new _DoubleLinkedQueueElement<E>(e, _queue)._link(this, _nextLink);
@@ -171,16 +172,18 @@
 
   E _remove();
 
-  E get element;
+  E get _element => element;
 
   DoubleLinkedQueueEntry<E> nextEntry() {
-    _DoubleLinkedQueueEntry next = _nextLink;
-    return next._asNonSentinelEntry();
+    _DoubleLinkedQueueEntry<E> entry =
+        _nextLink as dynamic/*=DoubleLinkedQueueEntry<E>*/;
+    return entry._asNonSentinelEntry();
   }
 
   DoubleLinkedQueueEntry<E> previousEntry() {
-    _DoubleLinkedQueueEntry previous = _previousLink;
-    return previous._asNonSentinelEntry();
+    _DoubleLinkedQueueEntry<E> entry =
+        _previousLink as dynamic/*=DoubleLinkedQueueEntry<E>*/;
+    return entry._asNonSentinelEntry();
   }
 }
 
@@ -190,11 +193,9 @@
  * The entry contains a reference to the queue, allowing
  * [append]/[prepend] to update the list length.
  */
-class _DoubleLinkedQueueElement<E> extends _DoubleLinkedQueueEntry<E>
-                                   implements DoubleLinkedQueueEntry<E> {
-  E element;
-  _DoubleLinkedQueueElement(this.element, DoubleLinkedQueue<E> queue)
-      : super(queue);
+class _DoubleLinkedQueueElement<E> extends _DoubleLinkedQueueEntry<E> {
+  _DoubleLinkedQueueElement(E element, DoubleLinkedQueue<E> queue)
+      : super(element, queue);
 
   void append(E e) {
     _append(e);
@@ -217,7 +218,7 @@
     return _remove();
   }
 
-  _DoubleLinkedQueueElement _asNonSentinelEntry() {
+  _DoubleLinkedQueueElement<E> _asNonSentinelEntry() {
     return this;
   }
 }
@@ -231,12 +232,13 @@
  * A sentinel does not box any user element.
  */
 class _DoubleLinkedQueueSentinel<E> extends _DoubleLinkedQueueEntry<E> {
-  _DoubleLinkedQueueSentinel(DoubleLinkedQueue queue) : super(queue) {
+  _DoubleLinkedQueueSentinel(DoubleLinkedQueue<E> queue)
+      : super(null, queue) {
     _previousLink = this;
     _nextLink = this;
   }
 
-  _DoubleLinkedQueueElement _asNonSentinelEntry() {
+  DoubleLinkedQueueEntry<E> _asNonSentinelEntry() {
     return null;
   }
 
@@ -246,7 +248,7 @@
   }
 
   /** Hit by, e.g., [DoubleLinkedQueue.first] if the queue is empty. */
-  E get element {
+  E get _element {
     throw IterableElementError.noElement();
   }
 }
@@ -272,8 +274,9 @@
    */
   factory DoubleLinkedQueue.from(Iterable elements) {
     Queue<E> list = new DoubleLinkedQueue<E>();
-    for (final E e in elements) {
-      list.addLast(e);
+    for (final e in elements) {
+      E element = e as Object/*=E*/;
+      list.addLast(element);
     }
     return list;
   }
@@ -303,14 +306,14 @@
   }
 
   E removeLast() {
-    _DoubleLinkedQueueEntry lastEntry = _sentinel._previousLink;
+    _DoubleLinkedQueueEntry<E> lastEntry = _sentinel._previousLink;
     E result = lastEntry._remove();
     _elementCount--;
     return result;
   }
 
   E removeFirst() {
-    _DoubleLinkedQueueEntry firstEntry = _sentinel._nextLink;
+    _DoubleLinkedQueueEntry<E> firstEntry = _sentinel._nextLink;
     E result = firstEntry._remove();
     _elementCount--;
     return result;
@@ -319,7 +322,7 @@
   bool remove(Object o) {
     _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
     while (!identical(entry, _sentinel)) {
-      if (entry.element == o) {
+      if (entry._element == o) {
         entry._remove();
         _elementCount--;
         return true;
@@ -333,7 +336,7 @@
     _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
     while (!identical(entry, _sentinel)) {
       _DoubleLinkedQueueEntry<E> next = entry._nextLink;
-      if (identical(removeMatching, test(entry.element))) {
+      if (identical(removeMatching, test(entry._element))) {
         entry._remove();
         _elementCount--;
       }
@@ -350,21 +353,21 @@
   }
 
   E get first {
-    _DoubleLinkedQueueEntry firstEntry = _sentinel._nextLink;
-    return firstEntry.element;
+    _DoubleLinkedQueueEntry<E> firstEntry = _sentinel._nextLink;
+    return firstEntry._element;
   }
 
   E get last {
-    _DoubleLinkedQueueEntry lastEntry = _sentinel._previousLink;
-    return lastEntry.element;
+    _DoubleLinkedQueueEntry<E> lastEntry = _sentinel._previousLink;
+    return lastEntry._element;
   }
 
   E get single {
     // Note that this throws correctly if the queue is empty
     // because reading element on the sentinel throws.
     if (identical(_sentinel._nextLink, _sentinel._previousLink)) {
-      _DoubleLinkedQueueEntry entry = _sentinel._nextLink;
-      return entry.element;
+      _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
+      return entry._element;
     }
     throw IterableElementError.tooMany();
   }
@@ -391,7 +394,7 @@
     _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
     while (!identical(entry, _sentinel)) {
       _DoubleLinkedQueueEntry<E> nextEntry = entry._nextLink;
-      _DoubleLinkedQueueElement element = entry;
+      _DoubleLinkedQueueElement<E> element = entry;
       f(element);
       entry = nextEntry;
     }
@@ -410,7 +413,8 @@
   E _current;
 
   _DoubleLinkedQueueIterator(_DoubleLinkedQueueSentinel<E> sentinel)
-      : _sentinel = sentinel, _nextEntry = sentinel._nextLink;
+      : _sentinel = sentinel,
+        _nextEntry = sentinel._nextLink;
 
   bool moveNext() {
     if (identical(_nextEntry, _sentinel)) {
@@ -419,11 +423,11 @@
       _sentinel = null;
       return false;
     }
-    _DoubleLinkedQueueElement elementEntry = _nextEntry;
+    _DoubleLinkedQueueElement<E> elementEntry = _nextEntry;
     if (elementEntry._queue == null) {
       throw new ConcurrentModificationError(_sentinel._queue);
     }
-    _current = elementEntry.element;
+    _current = elementEntry._element;
     _nextEntry = elementEntry._nextLink;
     return true;
   }
@@ -476,8 +480,9 @@
       int length = elements.length;
       ListQueue<E> queue = new ListQueue(length + 1);
       assert(queue._table.length > length);
-      List sourceList = elements;
-      queue._table.setRange(0, length, sourceList, 0);
+      for (int i = 0; i < length; i++) {
+        queue._table[i] = elements[i] as Object/*=E*/;
+      }
       queue._tail = length;
       return queue;
     } else {
@@ -486,8 +491,8 @@
         capacity = elements.length;
       }
       ListQueue<E> result = new ListQueue<E>(capacity);
-      for (final E element in elements) {
-        result.addLast(element);
+      for (final element in elements) {
+        result.addLast(element as Object/*=E*/);
       }
       return result;
     }
@@ -548,8 +553,8 @@
   }
 
   void addAll(Iterable<E> elements) {
-    if (elements is List) {
-      List list = elements;
+    if (elements is List/*<E>*/) {
+      List<E> list = elements;
       int addCount = list.length;
       int length = this.length;
       if (length + addCount >= _table.length) {
@@ -792,13 +797,13 @@
  * Considers any add or remove operation a concurrent modification.
  */
 class _ListQueueIterator<E> implements Iterator<E> {
-  final ListQueue _queue;
+  final ListQueue<E> _queue;
   final int _end;
   final int _modificationCount;
   int _position;
   E _current;
 
-  _ListQueueIterator(ListQueue queue)
+  _ListQueueIterator(ListQueue<E> queue)
       : _queue = queue,
         _end = queue._tail,
         _modificationCount = queue._modificationCount,
diff --git a/sdk/lib/collection/set.dart b/sdk/lib/collection/set.dart
index 4dd32cb..499225d 100644
--- a/sdk/lib/collection/set.dart
+++ b/sdk/lib/collection/set.dart
@@ -33,7 +33,7 @@
 
   bool contains(Object element);
 
-  E lookup(E element);
+  E lookup(Object element);
 
   bool remove(Object element);
 
@@ -125,7 +125,7 @@
 
   E get single {
     if (length > 1) throw IterableElementError.tooMany();
-    Iterator it = iterator;
+    Iterator<E> it = iterator;
     if (!it.moveNext()) throw IterableElementError.noElement();
     E result = it.current;
     return result;
@@ -213,7 +213,7 @@
   }
 
   E get first {
-    Iterator it = iterator;
+    Iterator<E> it = iterator;
     if (!it.moveNext()) {
       throw IterableElementError.noElement();
     }
@@ -221,7 +221,7 @@
   }
 
   E get last {
-    Iterator it = iterator;
+    Iterator<E> it = iterator;
     if (!it.moveNext()) {
       throw IterableElementError.noElement();
     }
diff --git a/sdk/lib/collection/splay_tree.dart b/sdk/lib/collection/splay_tree.dart
index 223e58c..72a2f52 100644
--- a/sdk/lib/collection/splay_tree.dart
+++ b/sdk/lib/collection/splay_tree.dart
@@ -36,14 +36,15 @@
  * It performs basic operations such as insertion, look-up and
  * removal, in O(log(n)) amortized time.
  */
-abstract class _SplayTree<K> {
+abstract class _SplayTree<K, Node extends _SplayTreeNode<K>> {
   // The root node of the splay tree. It will contain either the last
   // element inserted or the last element looked up.
-  _SplayTreeNode<K> _root;
+  Node get _root;
+  set _root(Node newValue);
 
   // The dummy node used when performing a splay on the tree. Reusing it
   // avoids allocating a node each time a splay is performed.
-  _SplayTreeNode<K> _dummy = new _SplayTreeNode<K>(null);
+  Node get _dummy;
 
   // Number of elements in the splay tree.
   int _count = 0;
@@ -63,6 +64,12 @@
    */
   int _splayCount = 0;
 
+  /** The comparator that is used for this splay tree. */
+  Comparator<K> get _comparator;
+
+  /** The predicate to determine that a given object is a valid key. */
+  _Predicate get _validKey;
+
   /** Comparison used to compare keys. */
   int _compare(K key1, K key2);
 
@@ -83,9 +90,9 @@
     // the L tree of the algorithm.  The left child of the dummy node
     // will hold the R tree of the algorithm.  Using a dummy node, left
     // and right will always be nodes and we avoid special cases.
-    _SplayTreeNode<K> left = _dummy;
-    _SplayTreeNode<K> right = _dummy;
-    _SplayTreeNode<K> current = _root;
+    Node left = _dummy;
+    Node right = _dummy;
+    Node current = _root;
     int comp;
     while (true) {
       comp = _compare(current.key, key);
@@ -109,7 +116,7 @@
         comp = _compare(current.right.key, key);
         if (comp < 0) {
           // Rotate left.
-          _SplayTreeNode<K> tmp = current.right;
+          Node tmp = current.right;
           current.right = tmp.left;
           tmp.left = current;
           current = tmp;
@@ -140,10 +147,10 @@
   // anchored at [node].
   // and that node is returned. It should replace the reference to [node]
   // in any parent tree or root pointer.
-  _SplayTreeNode<K> _splayMin(_SplayTreeNode<K> node) {
-    _SplayTreeNode current = node;
+  Node _splayMin(Node node) {
+    Node current = node;
     while (current.left != null) {
-      _SplayTreeNode left = current.left;
+      Node left = current.left;
       current.left = left.right;
       left.right = current;
       current = left;
@@ -156,10 +163,10 @@
   // After this, the largest element in the tree is the root of the subtree,
   // and that node is returned. It should replace the reference to [node]
   // in any parent tree or root pointer.
-  _SplayTreeNode<K> _splayMax(_SplayTreeNode<K> node) {
-    _SplayTreeNode current = node;
+  Node _splayMax(Node node) {
+    Node current = node;
     while (current.right != null) {
-      _SplayTreeNode right = current.right;
+      Node right = current.right;
       current.right = right.left;
       right.left = current;
       current = right;
@@ -167,17 +174,17 @@
     return current;
   }
 
-  _SplayTreeNode _remove(K key) {
+  Node _remove(K key) {
     if (_root == null) return null;
     int comp = _splay(key);
     if (comp != 0) return null;
-    _SplayTreeNode result = _root;
+    Node result = _root;
     _count--;
     // assert(_count >= 0);
     if (_root.left == null) {
       _root = _root.right;
     } else {
-      _SplayTreeNode<K> right = _root.right;
+      Node right = _root.right;
       // Splay to make sure that the new root has an empty right child.
       _root = _splayMax(_root.left);
       // Insert the original right child as the right child of the new
@@ -194,7 +201,7 @@
    * The [comp] value is the result of comparing the existing root's key
    * with key.
    */
-  void _addNewRoot(_SplayTreeNode<K> node, int comp) {
+  void _addNewRoot(Node node, int comp) {
     _count++;
     _modificationCount++;
     if (_root == null) {
@@ -214,13 +221,13 @@
     _root = node;
   }
 
-  _SplayTreeNode get _first {
+  Node get _first {
     if (_root == null) return null;
     _root = _splayMin(_root);
     return _root;
   }
 
-  _SplayTreeNode get _last {
+  Node get _last {
     if (_root == null) return null;
     _root = _splayMax(_root);
     return _root;
@@ -260,13 +267,18 @@
  * value. If omitted, the `isValidKey` function defaults to testing if the
  * value is a [K].
  */
-class SplayTreeMap<K, V> extends _SplayTree<K> implements Map<K, V> {
+class SplayTreeMap<K, V> extends _SplayTree<K, _SplayTreeMapNode<K, V>>
+    implements Map<K, V> {
+  _SplayTreeMapNode<K, V> _root;
+  final _SplayTreeMapNode<K, V> _dummy =
+      new _SplayTreeMapNode<K, V>(null, null);
+
   Comparator<K> _comparator;
   _Predicate _validKey;
 
   SplayTreeMap([int compare(K key1, K key2), bool isValidKey(potentialKey)])
-      : _comparator = (compare == null) ? Comparable.compare : compare,
-        _validKey = (isValidKey != null) ? isValidKey : ((v) => v is K);
+      : _comparator = compare ?? Comparable.compare as Comparator<K>,
+        _validKey = isValidKey ?? ((v) => v is K);
 
   /**
    * Creates a [SplayTreeMap] that contains all key/value pairs of [other].
@@ -275,7 +287,7 @@
                             [int compare(K key1, K key2),
                              bool isValidKey(potentialKey)]) {
     SplayTreeMap<K, V> result = new SplayTreeMap<K, V>(compare, isValidKey);
-    other.forEach((k, v) { result[k] = v; });
+    other.forEach((k, v) { result[k as Object/*=K*/] = v as Object/*=V*/; });
     return result;
   }
 
@@ -327,10 +339,9 @@
   V operator [](Object key) {
     if (!_validKey(key)) return null;
     if (_root != null) {
-      int comp = _splay(key);
+      int comp = _splay(key as dynamic/*=K*/);
       if (comp == 0) {
-        _SplayTreeMapNode mapRoot = _root;
-        return mapRoot.value;
+        return _root.value;
       }
     }
     return null;
@@ -338,7 +349,7 @@
 
   V remove(Object key) {
     if (!_validKey(key)) return null;
-    _SplayTreeMapNode mapRoot = _remove(key);
+    _SplayTreeMapNode<K, V> mapRoot = _remove(key as dynamic/*=K*/);
     if (mapRoot != null) return mapRoot.value;
     return null;
   }
@@ -349,8 +360,7 @@
     // the key to the root of the tree.
     int comp = _splay(key);
     if (comp == 0) {
-      _SplayTreeMapNode mapRoot = _root;
-      mapRoot.value = value;
+      _root.value = value;
       return;
     }
     _addNewRoot(new _SplayTreeMapNode(key, value), comp);
@@ -361,8 +371,7 @@
     if (key == null) throw new ArgumentError(key);
     int comp = _splay(key);
     if (comp == 0) {
-      _SplayTreeMapNode mapRoot = _root;
-      return mapRoot.value;
+      return _root.value;
     }
     int modificationCount = _modificationCount;
     int splayCount = _splayCount;
@@ -407,7 +416,7 @@
   }
 
   bool containsKey(Object key) {
-    return _validKey(key) && _splay(key) == 0;
+    return _validKey(key) && _splay(key as dynamic/*=K*/) == 0;
   }
 
   bool containsValue(Object value) {
@@ -486,8 +495,8 @@
   }
 }
 
-abstract class _SplayTreeIterator<T> implements Iterator<T> {
-  final _SplayTree _tree;
+abstract class _SplayTreeIterator<K, T> implements Iterator<T> {
+  final _SplayTree<K, _SplayTreeNode<K>> _tree;
   /**
    * Worklist of nodes to visit.
    *
@@ -498,7 +507,7 @@
    *
    * Only valid as long as the original tree isn't reordered.
    */
-  final List<_SplayTreeNode> _workList = <_SplayTreeNode>[];
+  final List<_SplayTreeNode<K>> _workList = <_SplayTreeNode<K>>[];
 
   /**
    * Original modification counter of [_tree].
@@ -519,16 +528,16 @@
   int _splayCount;
 
   /** Current node. */
-  _SplayTreeNode _currentNode;
+  _SplayTreeNode<K> _currentNode;
 
-  _SplayTreeIterator(_SplayTree tree)
+  _SplayTreeIterator(_SplayTree<K, _SplayTreeNode<K>> tree)
       : _tree = tree,
         _modificationCount = tree._modificationCount,
         _splayCount = tree._splayCount {
     _findLeftMostDescendent(tree._root);
   }
 
-  _SplayTreeIterator.startAt(_SplayTree tree, var startKey)
+  _SplayTreeIterator.startAt(_SplayTree<K, _SplayTreeNode<K>> tree, K startKey)
       : _tree = tree,
         _modificationCount = tree._modificationCount {
     if (tree._root == null) return;
@@ -547,7 +556,7 @@
     return _getValue(_currentNode);
   }
 
-  void _findLeftMostDescendent(_SplayTreeNode node) {
+  void _findLeftMostDescendent(_SplayTreeNode<K> node) {
     while (node != null) {
       _workList.add(node);
       node = node.left;
@@ -562,7 +571,7 @@
    * here, so we know that the keys are the same as before, it's
    * only the tree that has been reordered.
    */
-  void _rebuildWorkList(_SplayTreeNode currentNode) {
+  void _rebuildWorkList(_SplayTreeNode<K> currentNode) {
     assert(!_workList.isEmpty);
     _workList.clear();
     if (currentNode == null) {
@@ -595,21 +604,20 @@
     return true;
   }
 
-  T _getValue(_SplayTreeNode node);
+  T _getValue(_SplayTreeNode<K> node);
 }
 
 class _SplayTreeKeyIterable<K> extends Iterable<K>
                                implements EfficientLength {
-  _SplayTree<K> _tree;
+  _SplayTree<K, _SplayTreeNode<K>> _tree;
   _SplayTreeKeyIterable(this._tree);
   int get length => _tree._count;
   bool get isEmpty => _tree._count == 0;
   Iterator<K> get iterator => new _SplayTreeKeyIterator<K>(_tree);
 
   Set<K> toSet() {
-    var setOrMap = _tree;  // Both have _comparator and _validKey.
     SplayTreeSet<K> set =
-        new SplayTreeSet<K>(setOrMap._comparator, setOrMap._validKey);
+        new SplayTreeSet<K>(_tree._comparator, _tree._validKey);
     set._count = _tree._count;
     set._root = set._copyNode(_tree._root);
     return set;
@@ -625,22 +633,27 @@
   Iterator<V> get iterator => new _SplayTreeValueIterator<K, V>(_map);
 }
 
-class _SplayTreeKeyIterator<K> extends _SplayTreeIterator<K> {
-  _SplayTreeKeyIterator(_SplayTree<K> map): super(map);
-  K _getValue(_SplayTreeNode node) => node.key;
+class _SplayTreeKeyIterator<K> extends _SplayTreeIterator<K, K> {
+  _SplayTreeKeyIterator(_SplayTree<K, _SplayTreeNode<K>> map): super(map);
+  K _getValue(_SplayTreeNode<K> node) => node.key;
 }
 
-class _SplayTreeValueIterator<K, V> extends _SplayTreeIterator<V> {
+class _SplayTreeValueIterator<K, V> extends _SplayTreeIterator<K, V> {
   _SplayTreeValueIterator(SplayTreeMap<K, V> map): super(map);
-  V _getValue(_SplayTreeMapNode node) => node.value;
+  V _getValue(_SplayTreeNode<K> node) {
+    _SplayTreeMapNode<K, V> mapNode =
+        node as dynamic/*=_SplayTreeMapNode<K, V>*/;
+    return mapNode.value;
+  }
 }
 
 class _SplayTreeNodeIterator<K>
-    extends _SplayTreeIterator<_SplayTreeNode<K>> {
-  _SplayTreeNodeIterator(_SplayTree<K> tree): super(tree);
-  _SplayTreeNodeIterator.startAt(_SplayTree<K> tree, var startKey)
+    extends _SplayTreeIterator<K, _SplayTreeNode<K>> {
+  _SplayTreeNodeIterator(_SplayTree<K, _SplayTreeNode<K>> tree): super(tree);
+  _SplayTreeNodeIterator.startAt(
+      _SplayTree<K, _SplayTreeNode<K>> tree, K startKey)
       : super.startAt(tree, startKey);
-  _SplayTreeNode<K> _getValue(_SplayTreeNode node) => node;
+  _SplayTreeNode<K> _getValue(_SplayTreeNode<K> node) => node;
 }
 
 
@@ -660,8 +673,12 @@
  * Non-comparable objects (including `null`) will not work as an element
  * in that case.
  */
-class SplayTreeSet<E> extends _SplayTree<E> with IterableMixin<E>, SetMixin<E> {
-  Comparator _comparator;
+class SplayTreeSet<E> extends _SplayTree<E, _SplayTreeNode<E>>
+    with IterableMixin<E>, SetMixin<E> {
+  _SplayTreeNode<E> _root;
+  final _SplayTreeNode<E> _dummy = new _SplayTreeNode<E>(null);
+
+  Comparator<E> _comparator;
   _Predicate _validKey;
 
   /**
@@ -689,8 +706,9 @@
    * type parameter: `other is E`.
    */
   SplayTreeSet([int compare(E key1, E key2), bool isValidKey(potentialKey)])
-      : _comparator = (compare == null) ? Comparable.compare : compare,
-        _validKey = (isValidKey != null) ? isValidKey : ((v) => v is E);
+      : _comparator =
+            compare ?? Comparable.compare as dynamic/*=Comparator<E>*/,
+        _validKey = isValidKey ?? ((v) => v is E);
 
   /**
    * Creates a [SplayTreeSet] that contains all [elements].
@@ -703,8 +721,9 @@
                             [int compare(E key1, E key2),
                              bool isValidKey(potentialKey)]) {
     SplayTreeSet<E> result = new SplayTreeSet<E>(compare, isValidKey);
-    for (final E element in elements) {
-      result.add(element);
+    for (final element in elements) {
+      E e = element as Object/*=E*/;
+      result.add(e);
     }
     return result;
   }
@@ -737,7 +756,7 @@
 
   // From Set.
   bool contains(Object object) {
-    return _validKey(object) && _splay(object) == 0;
+    return _validKey(object) && _splay(object as dynamic/*=E*/) == 0;
   }
 
   bool add(E element) {
@@ -749,7 +768,7 @@
 
   bool remove(Object object) {
     if (!_validKey(object)) return false;
-    return _remove(object) != null;
+    return _remove(object as dynamic/*=E*/) != null;
   }
 
   void addAll(Iterable<E> elements) {
@@ -763,7 +782,7 @@
 
   void removeAll(Iterable<Object> elements) {
     for (Object element in elements) {
-      if (_validKey(element)) _remove(element);
+      if (_validKey(element)) _remove(element as dynamic/*=E*/);
     }
   }
 
@@ -777,7 +796,9 @@
         throw new ConcurrentModificationError(this);
       }
       // Equivalent to this.contains(object).
-      if (_validKey(object) && _splay(object) == 0) retainSet.add(_root.key);
+      if (_validKey(object) && _splay(object as dynamic/*=E*/) == 0) {
+        retainSet.add(_root.key);
+      }
     }
     // Take over the elements from the retained set, if it differs.
     if (retainSet._count != _count) {
@@ -789,12 +810,12 @@
 
   E lookup(Object object) {
     if (!_validKey(object)) return null;
-    int comp = _splay(object);
+    int comp = _splay(object as dynamic/*=E*/);
     if (comp != 0) return null;
     return _root.key;
   }
 
-  Set<E> intersection(Set<E> other) {
+  Set<E> intersection(Set<Object> other) {
     Set<E> result = new SplayTreeSet<E>(_comparator, _validKey);
     for (E element in this) {
       if (other.contains(element)) result.add(element);
@@ -802,7 +823,7 @@
     return result;
   }
 
-  Set<E> difference(Set<E> other) {
+  Set<E> difference(Set<Object> other) {
     Set<E> result = new SplayTreeSet<E>(_comparator, _validKey);
     for (E element in this) {
       if (!other.contains(element)) result.add(element);
diff --git a/sdk/lib/convert/ascii.dart b/sdk/lib/convert/ascii.dart
index 6302333..a076210 100644
--- a/sdk/lib/convert/ascii.dart
+++ b/sdk/lib/convert/ascii.dart
@@ -69,8 +69,7 @@
 
 // Superclass for [AsciiEncoder] and [Latin1Encoder].
 // Generalizes common operations that only differ by a mask;
-class _UnicodeSubsetEncoder extends
-    ChunkedConverter<String, List<int>, String, List<int>> {
+class _UnicodeSubsetEncoder extends Converter<String, List<int>> {
   final int _subsetMask;
 
   const _UnicodeSubsetEncoder(this._subsetMask);
@@ -86,7 +85,7 @@
     RangeError.checkValidRange(start, end, stringLength);
     if (end == null) end = stringLength;
     int length = end - start;
-    List result = new Uint8List(length);
+    List<int> result = new Uint8List(length);
     for (int i = 0; i < length; i++) {
       var codeUnit = string.codeUnitAt(start + i);
       if ((codeUnit & ~_subsetMask) != 0) {
@@ -155,8 +154,7 @@
  * This class converts Latin-1 bytes (lists of unsigned 8-bit integers)
  * to a string.
  */
-abstract class _UnicodeSubsetDecoder extends
-    ChunkedConverter<List<int>, String, List<int>, String> {
+abstract class _UnicodeSubsetDecoder extends Converter<List<int>, String> {
   final bool _allowInvalid;
   final int _subsetMask;
 
diff --git a/sdk/lib/convert/base64.dart b/sdk/lib/convert/base64.dart
index f3d7019..3fe1357 100644
--- a/sdk/lib/convert/base64.dart
+++ b/sdk/lib/convert/base64.dart
@@ -70,8 +70,7 @@
  *
  * The results are ASCII strings using a restricted alphabet.
  */
-class Base64Encoder extends
-    ChunkedConverter<List<int>, String, List<int>, String> {
+class Base64Encoder extends Converter<List<int>, String> {
   final bool _urlSafe;
 
   const Base64Encoder() : _urlSafe = false;
@@ -341,8 +340,7 @@
  *
  * The encoding is required to be properly padded.
  */
-class Base64Decoder extends
-    ChunkedConverter<String, List<int>, String, List<int>> {
+class Base64Decoder extends Converter<String, List<int>> {
 
   const Base64Decoder();
 
diff --git a/sdk/lib/convert/chunked_conversion.dart b/sdk/lib/convert/chunked_conversion.dart
index 95e561c..ee71f4f 100644
--- a/sdk/lib/convert/chunked_conversion.dart
+++ b/sdk/lib/convert/chunked_conversion.dart
@@ -6,55 +6,14 @@
 
 typedef void _ChunkedConversionCallback<T>(T accumulated);
 
-/**
- * A converter that supports chunked conversions.
- *
- * In addition to immediate conversions from [S] to [T], a chunked converter
- * also supports longer-running conversions from [S2] to [T2].
- *
- * Frequently, the source and target types are the same, but this is not a
- * requirement. In particular, converters that work with lists in the
- * immediate conversion, could flatten the type for the chunked conversion.
- *
- * For example, the [LineSplitter] class returns a `List<String>` for the
- * immediate conversion, but returns individual `String`s in the chunked
- * conversion.
- */
+/// This class is deprecated. Extend [Converter] directly.
+@deprecated
 abstract class ChunkedConverter<S, T, S2, T2> extends Converter<S, T> {
+  const ChunkedConverter(): super();
 
-  const ChunkedConverter();
-
-  /**
-   * Starts a chunked conversion.
-   *
-   * The returned sink serves as input for the long-running conversion. The
-   * given [sink] serves as output.
-   */
-  ChunkedConversionSink<S2> startChunkedConversion(Sink<T2> sink) {
-    throw new UnsupportedError(
-        "This converter does not support chunked conversions: $this");
-  }
-
-  Stream<T2> bind(Stream<S2> stream) {
-    return new Stream<T2>.eventTransformed(
-        stream,
-        (EventSink<T2> sink) =>
-            new _ConverterStreamEventSink<S2, T2>(this, sink));
-  }
-
-  /**
-   * Fuses this instance with the given [other] converter.
-   *
-   * If [other] is a ChunkedConverter (with matching generic types), returns a
-   * [ChunkedConverter].
-   */
-  Converter<S, dynamic> fuse(Converter<T, dynamic> other) {
-    if (other is ChunkedConverter<T, dynamic, T2, dynamic>) {
-      return new _FusedChunkedConverter<S, T, dynamic, S2, T2, dynamic>(
-          this, other);
-    }
-    return super.fuse(other);
-  }
+  dynamic bind(dynamic other) => super.bind(other);
+  dynamic startChunkedConversion(dynamic sink) =>
+      super.startChunkedConversion(sink);
 }
 
 /**
@@ -65,13 +24,13 @@
  * work with a plain `Sink`, but may work more efficiently with certain
  * specialized types of `ChunkedConversionSink`.
  *
- * It is recommended that implementations of `ChunkedConversionSink` extends
+ * It is recommended that implementations of `ChunkedConversionSink` extend
  * this class, to inherit any further methods that may be added to the class.
  */
 abstract class ChunkedConversionSink<T> implements Sink<T> {
   ChunkedConversionSink();
   factory ChunkedConversionSink.withCallback(
-      void callback(List<T> accumulated)) = _SimpleCallbackSink;
+      void callback(List<T> accumulated)) = _SimpleCallbackSink<T>;
 
   /**
    * Adds chunked data to this sink.
@@ -122,10 +81,10 @@
    * The input sink for new data. All data that is received with
    * [handleData] is added into this sink.
    */
-  final ChunkedConversionSink<S> _chunkedSink;
+  final Sink<S> _chunkedSink;
 
   _ConverterStreamEventSink(
-      Converter/*=ChunkedConverter<dynamic, dynamic, S, T>*/ converter,
+      Converter/*=Converter<S, T>*/ converter,
       EventSink<T> sink)
       : this._eventSink = sink,
         _chunkedSink = converter.startChunkedConversion(sink);
@@ -136,20 +95,3 @@
   }
   void close() { _chunkedSink.close(); }
 }
-
-/**
- * Fuses two chunked converters.
- */
-class _FusedChunkedConverter<S, M, T, S2, M2, T2> extends
-    ChunkedConverter<S, T, S2, T2> {
-  final ChunkedConverter<S, M, S2, M2> _first;
-  final ChunkedConverter<M, T, M2, T2> _second;
-
-  _FusedChunkedConverter(this._first, this._second);
-
-  T convert(S input) => _second.convert(_first.convert(input));
-
-  ChunkedConversionSink<S2> startChunkedConversion(Sink<T2> sink) {
-    return _first.startChunkedConversion(_second.startChunkedConversion(sink));
-  }
-}
diff --git a/sdk/lib/convert/codec.dart b/sdk/lib/convert/codec.dart
index 1afe63a..3fc2d31 100644
--- a/sdk/lib/convert/codec.dart
+++ b/sdk/lib/convert/codec.dart
@@ -84,8 +84,8 @@
   final Codec<S, M> _first;
   final Codec<M, T> _second;
 
-  Converter<S, T> get encoder => _first.encoder.fuse(_second.encoder);
-  Converter<T, S> get decoder => _second.decoder.fuse(_first.decoder);
+  Converter<S, T> get encoder => _first.encoder.fuse/*<T>*/(_second.encoder);
+  Converter<T, S> get decoder => _second.decoder.fuse/*<S>*/(_first.decoder);
 
   _FusedCodec(this._first, this._second);
 }
diff --git a/sdk/lib/convert/converter.dart b/sdk/lib/convert/converter.dart
index d6d9a9b..dfcfcdf 100644
--- a/sdk/lib/convert/converter.dart
+++ b/sdk/lib/convert/converter.dart
@@ -10,7 +10,7 @@
  * It is recommended that implementations of `Converter` extend this class,
  * to inherit any further methods that may be added to the class.
  */
-abstract class Converter<S, T> implements StreamTransformer {
+abstract class Converter<S, T> implements StreamTransformer/*<S, T>*/ {
   const Converter();
 
   /**
@@ -24,29 +24,24 @@
    * Encoding with the resulting converter is equivalent to converting with
    * `this` before converting with `other`.
    */
-  Converter<S, dynamic> fuse(Converter<T, dynamic> other) {
-    return new _FusedConverter<S, T, dynamic>(this, other);
+  Converter<S, dynamic/*=TT*/> fuse/*<TT>*/(
+      Converter<T, dynamic/*=TT*/> other) {
+    return new _FusedConverter<S, T, dynamic/*=TT*/>(this, other);
   }
 
   /**
-   * Deprecated.
+   * Starts a chunked conversion.
    *
-   * Use the [ChunkedConverter] interface instead.
+   * The returned sink serves as input for the long-running conversion. The
+   * given [sink] serves as output.
    */
-  @deprecated
-  ChunkedConversionSink startChunkedConversion(Sink sink) {
+  Sink/*<S>*/ startChunkedConversion(Sink/*<T>*/ sink) {
     throw new UnsupportedError(
         "This converter does not support chunked conversions: $this");
   }
 
-  /**
-   * Deprecated.
-   *
-   * Use the [ChunkedConverter] interface instead.
-   */
-  @deprecated
-  Stream bind(Stream stream) {
-    return new Stream.eventTransformed(
+  Stream/*<T>*/ bind(Stream/*<S>*/ stream) {
+    return new Stream/*<T>*/.eventTransformed(
         stream,
         (EventSink sink) => new _ConverterStreamEventSink(this, sink));
   }
@@ -64,4 +59,8 @@
   _FusedConverter(this._first, this._second);
 
   T convert(S input) => _second.convert(_first.convert(input));
+
+  Sink/*<S>*/ startChunkedConversion(Sink/*<T>*/ sink) {
+    return _first.startChunkedConversion(_second.startChunkedConversion(sink));
+  }
 }
diff --git a/sdk/lib/convert/encoding.dart b/sdk/lib/convert/encoding.dart
index fd6f91f..11ae300 100644
--- a/sdk/lib/convert/encoding.dart
+++ b/sdk/lib/convert/encoding.dart
@@ -10,8 +10,8 @@
 abstract class Encoding extends Codec<String, List<int>> {
   const Encoding();
 
-  ChunkedConverter<String, List<int>, String, List<int>> get encoder;
-  ChunkedConverter<List<int>, String, List<int>, String> get decoder;
+  Converter<String, List<int>> get encoder;
+  Converter<List<int>, String> get decoder;
 
   Future<String> decodeStream(Stream<List<int>> byteStream) {
     return byteStream
diff --git a/sdk/lib/convert/html_escape.dart b/sdk/lib/convert/html_escape.dart
index 7efe317..ff74442 100644
--- a/sdk/lib/convert/html_escape.dart
+++ b/sdk/lib/convert/html_escape.dart
@@ -152,7 +152,7 @@
  * found to be easier to read if greater-than is also escaped whenever
  * less-than is.
  */
-class HtmlEscape extends ChunkedConverter<String, String, String, String> {
+class HtmlEscape extends Converter<String, String> {
 
   /** The [HtmlEscapeMode] used by the converter. */
   final HtmlEscapeMode mode;
diff --git a/sdk/lib/convert/json.dart b/sdk/lib/convert/json.dart
index e80a986..24931df 100644
--- a/sdk/lib/convert/json.dart
+++ b/sdk/lib/convert/json.dart
@@ -139,7 +139,7 @@
    * If [toEncodable] is omitted, it defaults to a function that returns the
    * result of calling `.toJson()` on the unencodable object.
    */
-  String encode(Object value, {toEncodable(var object)}) {
+  String encode(Object value, {toEncodable(object)}) {
     if (toEncodable == null) toEncodable = _toEncodable;
     if (toEncodable == null) return encoder.convert(value);
     return new JsonEncoder(toEncodable).convert(value);
@@ -159,7 +159,7 @@
 /**
  * This class converts JSON objects to strings.
  */
-class JsonEncoder extends ChunkedConverter<Object, String, Object, String> {
+class JsonEncoder extends Converter<Object, String> {
   /**
    * The string used for indention.
    *
@@ -174,7 +174,7 @@
    * Function called on non-encodable objects to return a replacement
    * encodable object that will be encoded in the orignal's place.
    */
-  final Function _toEncodable;
+  final _ToEncodable _toEncodable;
 
   /**
    * Creates a JSON encoder.
@@ -188,7 +188,7 @@
    * If [toEncodable] is omitted, it defaults to calling `.toJson()` on
    * the object.
    */
-  const JsonEncoder([Object toEncodable(Object nonSerializable)])
+  const JsonEncoder([toEncodable(nonSerializable)])
       : this.indent = null,
         this._toEncodable = toEncodable;
 
@@ -210,8 +210,7 @@
    * If [toEncodable] is omitted, it defaults to calling `.toJson()` on
    * the object.
    */
-  const JsonEncoder.withIndent(this.indent,
-      [Object toEncodable(Object nonSerializable)])
+  const JsonEncoder.withIndent(this.indent, [toEncodable(nonSerializable)])
       : this._toEncodable = toEncodable;
 
   /**
@@ -268,11 +267,13 @@
   // Override the base class's bind, to provide a better type.
   Stream<String> bind(Stream<Object> stream) => super.bind(stream);
 
-  Converter<Object, dynamic> fuse(Converter<String, dynamic> other) {
+  Converter<Object, dynamic/*=T*/> fuse/*<T>*/(
+      Converter<String, dynamic/*=T*/> other) {
     if (other is Utf8Encoder) {
-      return new JsonUtf8Encoder(indent, _toEncodable);
+      return new JsonUtf8Encoder(indent, _toEncodable)
+          as dynamic/*=Converter<Object, T>*/;
     }
-    return super.fuse(other);
+    return super.fuse/*<T>*/(other);
   }
 }
 
@@ -283,14 +284,13 @@
  * a JSON string, and then UTF-8 encoding the string, but without
  * creating an intermediate string.
  */
-class JsonUtf8Encoder extends
-    ChunkedConverter<Object, List<int>, Object, List<int>> {
+class JsonUtf8Encoder extends Converter<Object, List<int>> {
   /** Default buffer size used by the JSON-to-UTF-8 encoder. */
   static const int DEFAULT_BUFFER_SIZE = 256;
   /** Indentation used in pretty-print mode, `null` if not pretty. */
   final List<int> _indent;
   /** Function called with each un-encodable object encountered. */
-  final Function _toEncodable;
+  final _ToEncodable _toEncodable;
   /** UTF-8 buffer size. */
   final int _bufferSize;
 
@@ -320,7 +320,7 @@
    * object.
    */
   JsonUtf8Encoder([String indent,
-                   toEncodable(Object object),
+                   toEncodable(object),
                    int bufferSize = DEFAULT_BUFFER_SIZE])
       : _indent = _utf8Encode(indent),
         _toEncodable = toEncodable,
@@ -395,10 +395,6 @@
   Stream<List<int>> bind(Stream<Object> stream) {
     return super.bind(stream);
   }
-
-  Converter<Object, dynamic> fuse(Converter<List<int>, dynamic> other) {
-    return super.fuse(other);
-  }
 }
 
 /**
@@ -408,7 +404,7 @@
  */
 class _JsonEncoderSink extends ChunkedConversionSink<Object> {
   final String _indent;
-  final Function _toEncodable;
+  final _ToEncodable _toEncodable;
   final StringConversionSink _sink;
   bool _isDone = false;
 
@@ -441,7 +437,7 @@
   /** The byte sink receiveing the encoded chunks. */
   final ByteConversionSink _sink;
   final List<int> _indent;
-  final Function _toEncodable;
+  final _ToEncodable _toEncodable;
   final int _bufferSize;
   bool _isDone = false;
   _JsonUtf8EncoderSink(this._sink, this._toEncodable, this._indent,
@@ -474,7 +470,7 @@
 /**
  * This class parses JSON strings and builds the corresponding objects.
  */
-class JsonDecoder extends ChunkedConverter<String, Object, String, Object> {
+class JsonDecoder extends Converter<String, Object> {
   final _Reviver _reviver;
   /**
    * Constructs a new JsonDecoder.
@@ -517,7 +513,7 @@
 
 // Implementation of encoder/stringifier.
 
-Object _defaultToEncodable(object) => object.toJson();
+dynamic _defaultToEncodable(dynamic object) => object.toJson();
 
 /**
  * JSON encoder that traverses an object structure and writes JSON source.
@@ -545,11 +541,10 @@
   /** List of objects currently being traversed. Used to detect cycles. */
   final List _seen = new List();
   /** Function called for each un-encodable object encountered. */
-  final Function _toEncodable;
+  final _ToEncodable _toEncodable;
 
-  _JsonStringifier(Object _toEncodable(Object o))
-      : _toEncodable = (_toEncodable != null) ? _toEncodable
-                                              : _defaultToEncodable;
+  _JsonStringifier(toEncodable(o))
+      : _toEncodable = toEncodable ?? _defaultToEncodable;
 
   /** Append a string to the JSON output. */
   void writeString(String characters);
@@ -719,7 +714,7 @@
   }
 
   /** Serialize a [Map]. */
-  bool writeMap(Map<String, Object> map) {
+  bool writeMap(Map map) {
     if (map.isEmpty) {
       writeString("{}");
       return true;
@@ -761,7 +756,7 @@
   /**
    * Add [indentLevel] indentations to the JSON output.
    */
-  void writeIndentation(indentLevel);
+  void writeIndentation(int indentLevel);
 
   void writeList(List list) {
     if (list.isEmpty) {
@@ -838,7 +833,7 @@
    * for each indentation level. It should only contain valid JSON whitespace
    * characters (space, tab, carriage return or line feed).
    */
-  static String stringify(object, toEncodable(object), String indent) {
+  static String stringify(object, toEncodable(o), String indent) {
     StringBuffer output = new StringBuffer();
     printOn(object, output, toEncodable, indent);
     return output.toString();
@@ -849,8 +844,8 @@
    *
    * The result is written piecemally to the sink.
    */
-  static void printOn(object, StringSink output, toEncodable(object),
-                      String indent) {
+  static void printOn(
+      object, StringSink output, toEncodable(o), String indent) {
     var stringifier;
     if (indent == null) {
       stringifier = new _JsonStringStringifier(output, toEncodable);
@@ -879,8 +874,7 @@
                                    with _JsonPrettyPrintMixin {
   final String _indent;
 
-  _JsonStringStringifierPretty(StringSink sink, Function toEncodable,
-                               this._indent)
+  _JsonStringStringifierPretty(StringSink sink, toEncodable(o), this._indent)
       : super(sink, toEncodable);
 
   void writeIndentation(int count) {
@@ -888,6 +882,8 @@
   }
 }
 
+typedef void _AddChunk(Uint8List list, int start, int end);
+
 /**
  * Specialization of [_JsonStringifier] that writes the JSON as UTF-8.
  *
@@ -896,11 +892,11 @@
  */
 class _JsonUtf8Stringifier extends _JsonStringifier {
   final int bufferSize;
-  final Function addChunk;
+  final _AddChunk addChunk;
   Uint8List buffer;
   int index = 0;
 
-  _JsonUtf8Stringifier(toEncodable, int bufferSize, this.addChunk)
+  _JsonUtf8Stringifier(toEncodable(o), int bufferSize, this.addChunk)
       : this.bufferSize = bufferSize,
         buffer = new Uint8List(bufferSize),
         super(toEncodable);
@@ -918,16 +914,15 @@
    */
   static void stringify(Object object,
                         List<int> indent,
-                        toEncodableFunction(Object o),
+                        toEncodable(o),
                         int bufferSize,
                         void addChunk(Uint8List chunk, int start, int end)) {
     _JsonUtf8Stringifier stringifier;
     if (indent != null) {
-      stringifier = new _JsonUtf8StringifierPretty(toEncodableFunction, indent,
+      stringifier = new _JsonUtf8StringifierPretty(toEncodable, indent,
                                                    bufferSize, addChunk);
     } else {
-      stringifier = new _JsonUtf8Stringifier(toEncodableFunction,
-                                             bufferSize, addChunk);
+      stringifier = new _JsonUtf8Stringifier(toEncodable, bufferSize, addChunk);
     }
     stringifier.writeObject(object);
     stringifier.flush();
@@ -1037,9 +1032,10 @@
 class _JsonUtf8StringifierPretty extends _JsonUtf8Stringifier
                                  with _JsonPrettyPrintMixin {
   final List<int> indent;
-  _JsonUtf8StringifierPretty(toEncodableFunction, this.indent,
-                             bufferSize, addChunk)
-      : super(toEncodableFunction, bufferSize, addChunk);
+  _JsonUtf8StringifierPretty(
+      toEncodable(o), this.indent,
+      bufferSize, void addChunk(Uint8List buffer, int start, int end))
+      : super(toEncodable, bufferSize, addChunk);
 
   void writeIndentation(int count) {
     List<int> indent = this.indent;
diff --git a/sdk/lib/convert/line_splitter.dart b/sdk/lib/convert/line_splitter.dart
index a9c9448..b728d8f 100644
--- a/sdk/lib/convert/line_splitter.dart
+++ b/sdk/lib/convert/line_splitter.dart
@@ -17,8 +17,9 @@
  *
  * The returned lines do not contain the line terminators.
  */
-class LineSplitter extends
-    ChunkedConverter<String, List<String>, String, String> {
+class LineSplitter
+    extends Converter<String, List<String>>/*=Object*/
+    implements Object/*=StreamTransformer<String, String>*/ {
 
   const LineSplitter();
 
@@ -80,6 +81,12 @@
     }
     return new _LineSplitterSink(sink);
   }
+
+  Stream/*<String>*/ bind(Stream/*<String>*/ stream) {
+    return new Stream<String>.eventTransformed(
+          stream,
+          (EventSink<String> sink) => new _LineSplitterEventSink(sink));
+  }
 }
 
 // TODO(floitsch): deal with utf8.
@@ -157,3 +164,16 @@
     }
   }
 }
+
+class _LineSplitterEventSink extends _LineSplitterSink
+    implements EventSink<String> {
+  final EventSink<String> _eventSink;
+
+  _LineSplitterEventSink(EventSink<String> eventSink)
+      : _eventSink = eventSink,
+        super(new StringConversionSink.from(eventSink));
+
+  void addError(Object o, [StackTrace stackTrace]) {
+    _eventSink.addError(o, stackTrace);
+  }
+}
diff --git a/sdk/lib/convert/string_conversion.dart b/sdk/lib/convert/string_conversion.dart
index bdfd39b..6eb27d9 100644
--- a/sdk/lib/convert/string_conversion.dart
+++ b/sdk/lib/convert/string_conversion.dart
@@ -17,8 +17,7 @@
  * [StringConversionSinkMixin], to ensure that their class covers the newly
  * added methods.
  */
-abstract class StringConversionSink
-    extends ChunkedConversionSink<String> {
+abstract class StringConversionSink extends ChunkedConversionSink<String> {
   StringConversionSink();
   factory StringConversionSink.withCallback(void callback(String accumulated))
       = _StringCallbackSink;
diff --git a/sdk/lib/convert/utf.dart b/sdk/lib/convert/utf.dart
index a93c9ae..69bb72c 100644
--- a/sdk/lib/convert/utf.dart
+++ b/sdk/lib/convert/utf.dart
@@ -76,8 +76,7 @@
  * This class converts strings to their UTF-8 code units (a list of
  * unsigned 8-bit integers).
  */
-class Utf8Encoder extends
-    ChunkedConverter<String, List<int>, String, List<int>> {
+class Utf8Encoder extends Converter<String, List<int>> {
 
   const Utf8Encoder();
 
@@ -305,8 +304,7 @@
  * This class converts UTF-8 code units (lists of unsigned 8-bit integers)
  * to a string.
  */
-class Utf8Decoder extends
-    ChunkedConverter<List<int>, String, List<int>, String> {
+class Utf8Decoder extends Converter<List<int>, String> {
   final bool _allowMalformed;
 
   /**
@@ -369,7 +367,8 @@
   // Override the base-classes bind, to provide a better type.
   Stream<String> bind(Stream<List<int>> stream) => super.bind(stream);
 
-  external Converter<List<int>,dynamic> fuse(Converter<String, dynamic> next);
+  external Converter<List<int>, dynamic/*=T*/> fuse/*<T>*/(
+      Converter<String, dynamic/*=T*/> next);
 
   external static String _convertIntercepted(
       bool allowMalformed, List<int> codeUnits, int start, int end);
diff --git a/sdk/lib/core/date_time.dart b/sdk/lib/core/date_time.dart
index b5614af..35e93e0 100644
--- a/sdk/lib/core/date_time.dart
+++ b/sdk/lib/core/date_time.dart
@@ -102,7 +102,7 @@
  * the [intl](http://pub.dartlang.org/packages/intl) package.
  *
  */
-class DateTime implements Comparable {
+class DateTime implements Comparable<DateTime> {
   // Weekday constants that are returned by [weekday] method:
   static const int MONDAY = 1;
   static const int TUESDAY = 2;
diff --git a/sdk/lib/core/int.dart b/sdk/lib/core/int.dart
index fdc7727..0884d8f 100644
--- a/sdk/lib/core/int.dart
+++ b/sdk/lib/core/int.dart
@@ -149,7 +149,7 @@
    * for non-negative (unsigned) values.  Negative values are complemented to
    * return the bit position of the first bit that differs from the sign bit.
    *
-   * To find the the number of bits needed to store the value as a signed value,
+   * To find the number of bits needed to store the value as a signed value,
    * add one, i.e. use `x.bitLength + 1`.
    *
    *      x.bitLength == (-x-1).bitLength
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index a1967b7..300b2ef 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.dart
@@ -14,7 +14,7 @@
  * the iterator has now moved to the next element,
  * which is then available as [Iterator.current].
  * If the call returns `false`, there are no more elements,
- * and `iterator.currrent` returns `null`.
+ * and `iterator.current` returns `null`.
  *
  * You can create more than one iterator from the same `Iterable`.
  * Each time `iterator` is read, it returns a new iterator,
@@ -83,15 +83,16 @@
   const Iterable();
 
   /**
-   * Creates an `Iterable` that generates its elements dynamically.
+   * Creates an `Iterable` which generates its elements dynamically.
    *
-   * An `Iterator` created by [iterator] will count from
-   * zero to [:count - 1:], and call [generator]
-   * with each index in turn to create the next value.
+   * The generated iterable has [count] elements,
+   * and the element at index `n` is computed by calling `generator(n)`.
+   * Values are not cached, so each iteration computes the values again.
    *
    * If [generator] is omitted, it defaults to an identity function
-   * on integers `(int x) => x`, so it should only be omitted if the type
-   * parameter allows integer values.
+   * on integers `(int x) => x`, so it may only be omitted if the type
+   * parameter allows integer values. That is, if [E] is one of
+   * `int`, `num`, `Object` or `dynamic`.
    *
    * As an `Iterable`, `new Iterable.generate(n, generator))` is equivalent to
    * `const [0, ..., n - 1].map(generator)`.
@@ -146,7 +147,7 @@
    * This method returns a view of the mapped elements. As long as the
    * returned [Iterable] is not iterated over, the supplied function [f] will
    * not be invoked. The transformed elements will not be cached. Iterating
-   * multiple times over the the returned [Iterable] will invoke the supplied
+   * multiple times over the returned [Iterable] will invoke the supplied
    * function [f] multiple times on the same element.
    *
    * Methods on the returned iterable are allowed to omit calling `f`
@@ -163,13 +164,14 @@
    * The matching elements have the same order in the returned iterable
    * as they have in [iterator].
    *
-   * This method returns a view of the mapped elements. As long as the
-   * returned [Iterable] is not iterated over, the supplied function [test] will
-   * not be invoked. Iterating will not cache results, and thus iterating
-   * multiple times over the returned [Iterable] will invoke the supplied
+   * This method returns a view of the mapped elements.
+   * As long as the returned [Iterable] is not iterated over,
+   * the supplied function [test] will not be invoked.
+   * Iterating will not cache results, and thus iterating multiple times over
+   * the returned [Iterable] may invoke the supplied
    * function [test] multiple times on the same element.
    */
-  Iterable<E> where(bool f(E element)) => new WhereIterable<E>(this, f);
+  Iterable<E> where(bool test(E element)) => new WhereIterable<E>(this, test);
 
   /**
    * Expands each element of this [Iterable] into zero or more elements.
@@ -409,7 +411,7 @@
   }
 
   /**
-   * Returns an Iterable that provides all but the first [count] elements.
+   * Returns an [Iterable] that provides all but the first [count] elements.
    *
    * When the returned iterable is iterated, it starts iterating over `this`,
    * first skipping past the initial [count] elements.
@@ -418,23 +420,27 @@
    * After that, the remaining elements are iterated in the same order as
    * in this iterable.
    *
-   * The `count` must not be negative.
+   * Some iterables may be able to find later elements without first iterating
+   * through earlier elements, for example when iterating a [List].
+   * Such iterables are allowed to ignore the initial skipped elements.
+   *
+   * The [count] must not be negative.
    */
   Iterable<E> skip(int count) {
     return new SkipIterable<E>(this, count);
   }
 
   /**
-   * Returns an Iterable that skips leading elements while [test] is satisfied.
+   * Returns an `Iterable` that skips leading elements while [test] is satisfied.
    *
-   * The filtering happens lazily. Every new Iterator of the returned
-   * Iterable iterates over all elements of `this`.
+   * The filtering happens lazily. Every new [Iterator] of the returned
+   * iterable iterates over all elements of `this`.
    *
    * The returned iterable provides elements by iterating this iterable,
    * but skipping over all initial elements where `test(element)` returns
    * true. If all elements satisfy `test` the resulting iterable is empty,
    * otherwise it iterates the remaining elements in their original order,
-   * starting with the first element for which `test(element)` returns false,
+   * starting with the first element for which `test(element)` returns `false`.
    */
   Iterable<E> skipWhile(bool test(E value)) {
     return new SkipWhileIterable<E>(this, test);
@@ -493,7 +499,7 @@
   /**
    * Returns the first element that satisfies the given predicate [test].
    *
-   * Iterates through elements and returns the first to satsify [test].
+   * Iterates through elements and returns the first to satisfy [test].
    *
    * If no element satisfies [test], the result of invoking the [orElse]
    * function is returned.
@@ -517,7 +523,7 @@
    * checks `test(element)` for each,
    * and finally returns that last one that matched.
    *
-   * If no element satsfies [test], the result of invoking the [orElse]
+   * If no element satisfies [test], the result of invoking the [orElse]
    * function is returned.
    * If [orElse] is omitted, it defaults to throwing a [StateError].
    */
@@ -602,72 +608,30 @@
 
 typedef E _Generator<E>(int index);
 
-class _GeneratorIterable<E> extends Iterable<E>
-                            implements EfficientLength {
-  final int _start;
-  final int _end;
+class _GeneratorIterable<E> extends ListIterable<E> {
+  /// The length of the generated iterable.
+  final int length;
+
+  /// The function mapping indices to values.
   final _Generator<E> _generator;
 
-  /// Creates an iterable that builds the elements from a generator function.
+  /// Creates the generated iterable.
   ///
-  /// The [generator] may be null, in which case the default generator
-  /// enumerating the integer positions is used. This means that [int] must
-  /// be assignable to [E] when no generator is provided. In practice this means
-  /// that the generator can only be emitted when [E] is equal to `dynamic`,
-  /// `int`, or `num`. The constructor will check that the types match.
-  _GeneratorIterable(this._end, E generator(int n))
-      : _start = 0,
-        // The `as` below is used as check to make sure that `int` is assignable
+  /// If [generator] is `null`, it is checked that `int` is assignable to [E].
+  _GeneratorIterable(this.length, E generator(int index))
+      : // The `as` below is used as check to make sure that `int` is assignable
         // to [E].
         _generator = (generator != null) ? generator : _id as _Generator<E>;
 
-  _GeneratorIterable.slice(this._start, this._end, this._generator);
-
-  Iterator<E> get iterator =>
-      new _GeneratorIterator<E>(_start, _end, _generator);
-  int get length => _end - _start;
-
-  Iterable<E> skip(int count) {
-    RangeError.checkNotNegative(count, "count");
-    if (count == 0) return this;
-    int newStart = _start + count;
-    if (newStart >= _end) return new EmptyIterable<E>();
-    return new _GeneratorIterable<E>.slice(newStart, _end, _generator);
+  E elementAt(int index) {
+    RangeError.checkValidIndex(index, this);
+    return _generator(index);
   }
 
-  Iterable<E> take(int count) {
-    RangeError.checkNotNegative(count, "count");
-    if (count == 0) return new EmptyIterable<E>();
-    int newEnd = _start + count;
-    if (newEnd >= _end) return this;
-    return new _GeneratorIterable<E>.slice(_start, newEnd, _generator);
-  }
-
+  /// Helper function used as default _generator function.
   static int _id(int n) => n;
 }
 
-class _GeneratorIterator<E> implements Iterator<E> {
-  final int _end;
-  final _Generator<E> _generator;
-  int _index;
-  E _current;
-
-  _GeneratorIterator(this._index, this._end, this._generator);
-
-  bool moveNext() {
-    if (_index < _end) {
-      _current = _generator(_index);
-      _index++;
-      return true;
-    } else {
-      _current = null;
-      return false;
-    }
-  }
-
-  E get current => _current;
-}
-
 /**
  * An Iterator that allows moving backwards as well as forwards.
  */
diff --git a/sdk/lib/core/set.dart b/sdk/lib/core/set.dart
index 984c416..7e2508c 100644
--- a/sdk/lib/core/set.dart
+++ b/sdk/lib/core/set.dart
@@ -180,7 +180,7 @@
   Set<E> union(Set<E> other);
 
   /**
-   * Returns a new set with the the elements of this that are not in [other].
+   * Returns a new set with the elements of this that are not in [other].
    *
    * That is, the returned set contains all the elements of this [Set] that
    * are not elements of [other] according to `other.contains`.
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
index 0cfeceb..1d35106 100644
--- a/sdk/lib/core/uri.dart
+++ b/sdk/lib/core/uri.dart
@@ -3198,7 +3198,7 @@
   /**
    * A map representing the parameters of the media type.
    *
-   * A data URI may contain parameters between the the MIME type and the
+   * A data URI may contain parameters between the MIME type and the
    * data. This converts these parameters to a map from parameter name
    * to parameter value.
    * The map only contains parameters that actually occur in the URI.
diff --git a/sdk/lib/developer/timeline.dart b/sdk/lib/developer/timeline.dart
index fbdad8b..b6118af 100644
--- a/sdk/lib/developer/timeline.dart
+++ b/sdk/lib/developer/timeline.dart
@@ -23,6 +23,11 @@
                                     'name',
                                     'Must be a String');
     }
+    if (!_isDartStreamEnabled()) {
+      // Push a null onto the stack and return.
+      _stack.add(null);
+      return;
+    }
     var block = new _SyncBlock._(name, _getTraceClock(), _getThreadCpuClock());
     if (arguments is Map) {
       block._appendArguments(arguments);
@@ -41,6 +46,10 @@
     }
     // Pop top item off of stack.
     var block = _stack.removeLast();
+    if (block == null) {
+      // Dart stream was disabled when startSync was called.
+      return;
+    }
     // Finish it.
     block.finish();
   }
@@ -55,6 +64,10 @@
                                     'name',
                                     'Must be a String');
     }
+    if (!_isDartStreamEnabled()) {
+      // Stream is disabled.
+      return;
+    }
     Map instantArguments;
     if (arguments is Map) {
       instantArguments = new Map.from(arguments);
@@ -278,6 +291,9 @@
   return JSON.encode(arguments);
 }
 
+/// Returns true if the Dart Timeline stream is enabled.
+external bool _isDartStreamEnabled();
+
 /// Returns the next async task id.
 external int _getNextAsyncId();
 
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 7be7e5d..0bc3749 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -105,12 +105,6 @@
   HtmlElement.created() : super.created();
 }
 
-// EntryArray type was removed, so explicitly adding it to allow support for
-// older Chrome versions.
-// Issue #12573.
-@Native("EntryArray")
-abstract class _EntryArray implements List<Entry> {}
-
 /**
  * Spawn a DOM isolate using the given URI in the same window.
  * This isolate is not concurrent.  It runs on the browser thread
@@ -11639,17 +11633,27 @@
 
 @DocsEditable()
 @DomName('DOMStringMap')
-abstract class DomStringMap extends Interceptor {
+@Native("DOMStringMap")
+class DomStringMap extends Interceptor {
   // To suppress missing implicit constructor warnings.
   factory DomStringMap._() { throw new UnsupportedError("Not supported"); }
 
-  void __delete__(index_OR_name);
+  @DomName('DOMStringMap.__delete__')
+  @DocsEditable()
+  void __delete__(index_OR_name) native;
 
-  String __getter__(int index);
+  @DomName('DOMStringMap.__getter__')
+  @DocsEditable()
+  String __getter__(int index) native;
 
-  void __setter__(index_OR_name, String value);
+  @DomName('DOMStringMap.__setter__')
+  @DocsEditable()
+  void __setter__(index_OR_name, String value) native;
 
-  String item(String name);
+  @DomName('DOMStringMap.item')
+  @DocsEditable()
+  @Experimental() // untriaged
+  String item(String name) native;
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -16852,7 +16856,7 @@
 @DocsEditable()
 @DomName('FileList')
 @Native("FileList")
-class FileList extends Interceptor with ListMixin<File>, ImmutableListMixin<File> implements JavaScriptIndexingBehavior, List<File> {
+class FileList extends Interceptor with ListMixin<File>, ImmutableListMixin<File> implements List<File>, JavaScriptIndexingBehavior<File> {
   // To suppress missing implicit constructor warnings.
   factory FileList._() { throw new UnsupportedError("Not supported"); }
 
@@ -18887,7 +18891,7 @@
 @DocsEditable()
 @DomName('HTMLCollection')
 @Native("HTMLCollection")
-class HtmlCollection extends Interceptor with ListMixin<Node>, ImmutableListMixin<Node> implements JavaScriptIndexingBehavior, List<Node> {
+class HtmlCollection extends Interceptor with ListMixin<Node>, ImmutableListMixin<Node> implements JavaScriptIndexingBehavior<Node>, List<Node> {
   // To suppress missing implicit constructor warnings.
   factory HtmlCollection._() { throw new UnsupportedError("Not supported"); }
 
@@ -23801,7 +23805,7 @@
 @DomName('MimeTypeArray')
 @Experimental() // non-standard
 @Native("MimeTypeArray")
-class MimeTypeArray extends Interceptor with ListMixin<MimeType>, ImmutableListMixin<MimeType> implements JavaScriptIndexingBehavior, List<MimeType> {
+class MimeTypeArray extends Interceptor with ListMixin<MimeType>, ImmutableListMixin<MimeType> implements List<MimeType>, JavaScriptIndexingBehavior<MimeType> {
   // To suppress missing implicit constructor warnings.
   factory MimeTypeArray._() { throw new UnsupportedError("Not supported"); }
 
@@ -25434,7 +25438,7 @@
 @DocsEditable()
 @DomName('NodeList')
 @Native("NodeList,RadioNodeList")
-class NodeList extends Interceptor with ListMixin<Node>, ImmutableListMixin<Node> implements JavaScriptIndexingBehavior, List<Node> {
+class NodeList extends Interceptor with ListMixin<Node>, ImmutableListMixin<Node> implements JavaScriptIndexingBehavior<Node>, List<Node> {
   // To suppress missing implicit constructor warnings.
   factory NodeList._() { throw new UnsupportedError("Not supported"); }
 
@@ -26938,7 +26942,7 @@
 @DomName('PluginArray')
 @Experimental() // non-standard
 @Native("PluginArray")
-class PluginArray extends Interceptor with ListMixin<Plugin>, ImmutableListMixin<Plugin> implements JavaScriptIndexingBehavior, List<Plugin> {
+class PluginArray extends Interceptor with ListMixin<Plugin>, ImmutableListMixin<Plugin> implements JavaScriptIndexingBehavior<Plugin>, List<Plugin> {
   // To suppress missing implicit constructor warnings.
   factory PluginArray._() { throw new UnsupportedError("Not supported"); }
 
@@ -28031,24 +28035,6 @@
 
 
 @DocsEditable()
-@DomName('ResourceProgressEvent')
-// https://chromiumcodereview.appspot.com/14773025/
-@deprecated // experimental
-@Native("ResourceProgressEvent")
-class ResourceProgressEvent extends ProgressEvent {
-  // To suppress missing implicit constructor warnings.
-  factory ResourceProgressEvent._() { throw new UnsupportedError("Not supported"); }
-
-  @DomName('ResourceProgressEvent.url')
-  @DocsEditable()
-  final String url;
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-
-@DocsEditable()
 @DomName('RTCDataChannel')
 // http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCDataChannel
 @Experimental()
@@ -28358,7 +28344,7 @@
 @SupportedBrowser(SupportedBrowser.CHROME)
 @Experimental()
 // http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCPeerConnection
-@Native("RTCPeerConnection,mozRTCPeerConnection")
+@Native("RTCPeerConnection,webkitRTCPeerConnection,mozRTCPeerConnection")
 class RtcPeerConnection extends EventTarget {
   factory RtcPeerConnection(Map rtcIceServers, [Map mediaConstraints]) {
     var constructorName = JS('RtcPeerConnection', 'window[#]',
@@ -30176,7 +30162,7 @@
 // https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#sourcebufferlist
 @Experimental()
 @Native("SourceBufferList")
-class SourceBufferList extends EventTarget with ListMixin<SourceBuffer>, ImmutableListMixin<SourceBuffer> implements JavaScriptIndexingBehavior, List<SourceBuffer> {
+class SourceBufferList extends EventTarget with ListMixin<SourceBuffer>, ImmutableListMixin<SourceBuffer> implements JavaScriptIndexingBehavior<SourceBuffer>, List<SourceBuffer> {
   // To suppress missing implicit constructor warnings.
   factory SourceBufferList._() { throw new UnsupportedError("Not supported"); }
 
@@ -30370,7 +30356,7 @@
 // https://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html#dfn-speechgrammarlist
 @Experimental()
 @Native("SpeechGrammarList")
-class SpeechGrammarList extends Interceptor with ListMixin<SpeechGrammar>, ImmutableListMixin<SpeechGrammar> implements JavaScriptIndexingBehavior, List<SpeechGrammar> {
+class SpeechGrammarList extends Interceptor with ListMixin<SpeechGrammar>, ImmutableListMixin<SpeechGrammar> implements JavaScriptIndexingBehavior<SpeechGrammar>, List<SpeechGrammar> {
   // To suppress missing implicit constructor warnings.
   factory SpeechGrammarList._() { throw new UnsupportedError("Not supported"); }
 
@@ -32451,7 +32437,7 @@
 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#texttrackcuelist
 @Experimental()
 @Native("TextTrackCueList")
-class TextTrackCueList extends Interceptor with ListMixin<TextTrackCue>, ImmutableListMixin<TextTrackCue> implements List<TextTrackCue>, JavaScriptIndexingBehavior {
+class TextTrackCueList extends Interceptor with ListMixin<TextTrackCue>, ImmutableListMixin<TextTrackCue> implements List<TextTrackCue>, JavaScriptIndexingBehavior<TextTrackCue> {
   // To suppress missing implicit constructor warnings.
   factory TextTrackCueList._() { throw new UnsupportedError("Not supported"); }
 
@@ -32521,7 +32507,7 @@
 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#texttracklist
 @Experimental()
 @Native("TextTrackList")
-class TextTrackList extends EventTarget with ListMixin<TextTrack>, ImmutableListMixin<TextTrack> implements JavaScriptIndexingBehavior, List<TextTrack> {
+class TextTrackList extends EventTarget with ListMixin<TextTrack>, ImmutableListMixin<TextTrack> implements List<TextTrack>, JavaScriptIndexingBehavior<TextTrack> {
   // To suppress missing implicit constructor warnings.
   factory TextTrackList._() { throw new UnsupportedError("Not supported"); }
 
@@ -32863,7 +32849,7 @@
 // http://www.w3.org/TR/touch-events/, http://www.chromestatus.com/features
 @Experimental()
 @Native("TouchList")
-class TouchList extends Interceptor with ListMixin<Touch>, ImmutableListMixin<Touch> implements JavaScriptIndexingBehavior, List<Touch> {
+class TouchList extends Interceptor with ListMixin<Touch>, ImmutableListMixin<Touch> implements JavaScriptIndexingBehavior<Touch>, List<Touch> {
   /// NB: This constructor likely does not work as you might expect it to! This
   /// constructor will simply fail (returning null) if you are not on a device
   /// with touch enabled. See dartbug.com/8314.
@@ -36553,7 +36539,9 @@
   const _BeforeUnloadEventStreamProvider(this._eventType);
 
   Stream<BeforeUnloadEvent> forTarget(EventTarget e, {bool useCapture: false}) {
-    var stream = new _EventStream(e, _eventType, useCapture);
+    // Specify the generic type for EventStream only in dart2js to avoid
+    // checked mode errors in dartium.
+    var stream = new _EventStream<BeforeUnloadEvent>(e, _eventType, useCapture);
     var controller = new StreamController<BeforeUnloadEvent>(sync: true);
 
     stream.listen((event) {
@@ -36569,12 +36557,16 @@
   }
 
   ElementStream<BeforeUnloadEvent> forElement(Element e, {bool useCapture: false}) {
-    return new _ElementEventStreamImpl(e, _eventType, useCapture);
+    // Specify the generic type for _ElementEventStreamImpl only in dart2js to
+    // avoid checked mode errors in dartium.
+    return new _ElementEventStreamImpl<BeforeUnloadEvent>(e, _eventType, useCapture);
   }
 
   ElementStream<BeforeUnloadEvent> _forElementList(ElementList e,
       {bool useCapture: false}) {
-    return new _ElementListEventStreamImpl(e, _eventType, useCapture);
+    // Specify the generic type for _ElementEventStreamImpl only in dart2js to
+    // avoid checked mode errors in dartium.
+    return new _ElementListEventStreamImpl<BeforeUnloadEvent>(e, _eventType, useCapture);
   }
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -37642,7 +37634,7 @@
 @DocsEditable()
 @DomName('CSSRuleList')
 @Native("CSSRuleList")
-class _CssRuleList extends Interceptor with ListMixin<CssRule>, ImmutableListMixin<CssRule> implements JavaScriptIndexingBehavior, List<CssRule> {
+class _CssRuleList extends Interceptor with ListMixin<CssRule>, ImmutableListMixin<CssRule> implements JavaScriptIndexingBehavior<CssRule>, List<CssRule> {
   // To suppress missing implicit constructor warnings.
   factory _CssRuleList._() { throw new UnsupportedError("Not supported"); }
 
@@ -37896,7 +37888,7 @@
 // https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html
 @Experimental()
 @Native("GamepadList")
-class _GamepadList extends Interceptor with ListMixin<Gamepad>, ImmutableListMixin<Gamepad> implements JavaScriptIndexingBehavior, List<Gamepad> {
+class _GamepadList extends Interceptor with ListMixin<Gamepad>, ImmutableListMixin<Gamepad> implements List<Gamepad>, JavaScriptIndexingBehavior<Gamepad> {
   // To suppress missing implicit constructor warnings.
   factory _GamepadList._() { throw new UnsupportedError("Not supported"); }
 
@@ -38103,7 +38095,7 @@
 // http://dom.spec.whatwg.org/#namednodemap
 @deprecated // deprecated
 @Native("NamedNodeMap,MozNamedAttrMap")
-class _NamedNodeMap extends Interceptor with ListMixin<Node>, ImmutableListMixin<Node> implements JavaScriptIndexingBehavior, List<Node> {
+class _NamedNodeMap extends Interceptor with ListMixin<Node>, ImmutableListMixin<Node> implements JavaScriptIndexingBehavior<Node>, List<Node> {
   // To suppress missing implicit constructor warnings.
   factory _NamedNodeMap._() { throw new UnsupportedError("Not supported"); }
 
@@ -38271,6 +38263,20 @@
 
 
 @DocsEditable()
+@DomName('ResourceProgressEvent')
+// https://chromiumcodereview.appspot.com/14773025/
+@deprecated // experimental
+@Native("ResourceProgressEvent")
+abstract class _ResourceProgressEvent extends ProgressEvent {
+  // To suppress missing implicit constructor warnings.
+  factory _ResourceProgressEvent._() { throw new UnsupportedError("Not supported"); }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@DocsEditable()
 @DomName('Response')
 @Experimental() // untriaged
 @Native("Response")
@@ -38319,7 +38325,7 @@
 // https://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html#speechrecognitionresultlist
 @Experimental()
 @Native("SpeechRecognitionResultList")
-class _SpeechRecognitionResultList extends Interceptor with ListMixin<SpeechRecognitionResult>, ImmutableListMixin<SpeechRecognitionResult> implements JavaScriptIndexingBehavior, List<SpeechRecognitionResult> {
+class _SpeechRecognitionResultList extends Interceptor with ListMixin<SpeechRecognitionResult>, ImmutableListMixin<SpeechRecognitionResult> implements JavaScriptIndexingBehavior<SpeechRecognitionResult>, List<SpeechRecognitionResult> {
   // To suppress missing implicit constructor warnings.
   factory _SpeechRecognitionResultList._() { throw new UnsupportedError("Not supported"); }
 
@@ -38383,7 +38389,7 @@
 @DocsEditable()
 @DomName('StyleSheetList')
 @Native("StyleSheetList")
-class _StyleSheetList extends Interceptor with ListMixin<StyleSheet>, ImmutableListMixin<StyleSheet> implements JavaScriptIndexingBehavior, List<StyleSheet> {
+class _StyleSheetList extends Interceptor with ListMixin<StyleSheet>, ImmutableListMixin<StyleSheet> implements List<StyleSheet>, JavaScriptIndexingBehavior<StyleSheet> {
   // To suppress missing implicit constructor warnings.
   factory _StyleSheetList._() { throw new UnsupportedError("Not supported"); }
 
@@ -39916,7 +39922,7 @@
    * [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventListener)
    */
   ElementStream<T> _forElementList(ElementList e, {bool useCapture: false}) {
-    return new _ElementListEventStreamImpl(e, _eventType, useCapture);
+    return new _ElementListEventStreamImpl<T>(e, _eventType, useCapture);
   }
 
   /**
@@ -40134,9 +40140,9 @@
     }
   }
 
-  Future asFuture([var futureValue]) {
+  Future/*<E>*/ asFuture/*<E>*/([var/*=E*/ futureValue]) {
     // We just need a future that will never succeed or fail.
-    Completer completer = new Completer();
+    var completer = new Completer/*<E>*/();
     return completer.future;
   }
 }
@@ -42512,7 +42518,7 @@
 
   // Iterable APIs
 
-  Iterator<E> get iterator => new _WrappedIterator(_list.iterator);
+  Iterator<E> get iterator => new _WrappedIterator<E>(_list.iterator);
 
   int get length => _list.length;
 
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 6d8873e..bc92d6d 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -474,7 +474,7 @@
   'ReadableStreamReader': () => ReadableStreamReader.instanceRuntimeType,
   'RelatedEvent': () => RelatedEvent.instanceRuntimeType,
   'Request': () => _Request.instanceRuntimeType,
-  'ResourceProgressEvent': () => ResourceProgressEvent.instanceRuntimeType,
+  'ResourceProgressEvent': () => _ResourceProgressEvent.instanceRuntimeType,
   'Response': () => _Response.instanceRuntimeType,
   'Screen': () => Screen.instanceRuntimeType,
   'ScreenOrientation': () => ScreenOrientation.instanceRuntimeType,
@@ -12308,6 +12308,13 @@
   // To suppress missing implicit constructor warnings.
   factory DomStringMap._() { throw new UnsupportedError("Not supported"); }
 
+
+  @Deprecated("Internal Use Only")
+  external static Type get instanceRuntimeType;
+
+  @Deprecated("Internal Use Only")
+  DomStringMap.internal_() { }
+
   void __delete__(index_OR_name) {
     if ((index_OR_name is String || index_OR_name == null)) {
       _blink.BlinkDOMStringMap.instance.$__delete___Callback_1_(this, index_OR_name);
@@ -12322,8 +12329,8 @@
 
   @DomName('DOMStringMap.__getter__')
   @DocsEditable()
-  String __getter__(int index);
-
+  String __getter__(int index) => _blink.BlinkDOMStringMap.instance.$__getter___Callback_1_(this, index);
+  
   void __setter__(index_OR_name, String value) {
     if ((value is String || value == null) && (index_OR_name is String || index_OR_name == null)) {
       _blink.BlinkDOMStringMap.instance.$__setter___Callback_2_(this, index_OR_name, value);
@@ -12339,8 +12346,8 @@
   @DomName('DOMStringMap.item')
   @DocsEditable()
   @Experimental() // untriaged
-  String item(String name);
-
+  String item(String name) => _blink.BlinkDOMStringMap.instance.item_Callback_1_(this, name);
+  
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -31455,34 +31462,6 @@
 
 
 @DocsEditable()
-@DomName('ResourceProgressEvent')
-// https://chromiumcodereview.appspot.com/14773025/
-@deprecated // experimental
-class ResourceProgressEvent extends ProgressEvent {
-  // To suppress missing implicit constructor warnings.
-  factory ResourceProgressEvent._() { throw new UnsupportedError("Not supported"); }
-
-
-  @Deprecated("Internal Use Only")
-  external static Type get instanceRuntimeType;
-
-  @Deprecated("Internal Use Only")
-  ResourceProgressEvent.internal_() : super.internal_();
-
-
-  @DomName('ResourceProgressEvent.url')
-  @DocsEditable()
-  String get url => _blink.BlinkResourceProgressEvent.instance.url_Getter_(this);
-  
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable()
 @DomName('RTCDataChannel')
 // http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCDataChannel
 @Experimental()
@@ -37683,10 +37662,10 @@
     if ((blob_OR_source_OR_stream is Blob || blob_OR_source_OR_stream == null)) {
       return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
     }
-    if ((blob_OR_source_OR_stream is MediaSource)) {
+    if ((blob_OR_source_OR_stream is MediaStream)) {
       return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
     }
-    if ((blob_OR_source_OR_stream is MediaStream)) {
+    if ((blob_OR_source_OR_stream is MediaSource)) {
       return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
     }
     throw new ArgumentError("Incorrect number or type of arguments");
@@ -42851,6 +42830,30 @@
 
 
 @DocsEditable()
+@DomName('ResourceProgressEvent')
+// https://chromiumcodereview.appspot.com/14773025/
+@deprecated // experimental
+class _ResourceProgressEvent extends ProgressEvent {
+  // To suppress missing implicit constructor warnings.
+  factory _ResourceProgressEvent._() { throw new UnsupportedError("Not supported"); }
+
+
+  @Deprecated("Internal Use Only")
+  external static Type get instanceRuntimeType;
+
+  @Deprecated("Internal Use Only")
+  _ResourceProgressEvent.internal_() : super.internal_();
+
+
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable()
 @DomName('Response')
 @Experimental() // untriaged
 class _Response extends Body {
@@ -44447,7 +44450,7 @@
    * [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventListener)
    */
   ElementStream<T> _forElementList(ElementList e, {bool useCapture: false}) {
-    return new _ElementListEventStreamImpl(e, _eventType, useCapture);
+    return new _ElementListEventStreamImpl<T>(e, _eventType, useCapture);
   }
 
   /**
@@ -44665,9 +44668,9 @@
     }
   }
 
-  Future asFuture([var futureValue]) {
+  Future/*<E>*/ asFuture/*<E>*/([var/*=E*/ futureValue]) {
     // We just need a future that will never succeed or fail.
-    Completer completer = new Completer();
+    var completer = new Completer/*<E>*/();
     return completer.future;
   }
 }
@@ -47349,7 +47352,7 @@
 
   // Iterable APIs
 
-  Iterator<E> get iterator => new _WrappedIterator(_list.iterator);
+  Iterator<E> get iterator => new _WrappedIterator<E>(_list.iterator);
 
   int get length => _list.length;
 
diff --git a/sdk/lib/io/bytes_builder.dart b/sdk/lib/io/bytes_builder.dart
index a4b611f..0c97748 100644
--- a/sdk/lib/io/bytes_builder.dart
+++ b/sdk/lib/io/bytes_builder.dart
@@ -45,7 +45,7 @@
   /**
    * Returns the contents of `this` and clears `this`.
    *
-   * The list returned is a view of the the internal buffer, limited to the
+   * The list returned is a view of the internal buffer, limited to the
    * [length].
    */
   List<int> takeBytes();
@@ -153,14 +153,17 @@
 
 class _BytesBuilder implements BytesBuilder {
   int _length = 0;
-  final _chunks = <List<int>>[];
+  final List<Uint8List> _chunks = [];
 
   void add(List<int> bytes) {
-    if (bytes is! Uint8List) {
+    Uint8List typedBytes;
+    if (bytes is Uint8List) {
+      typedBytes = bytes;
+    } else {
       bytes = new Uint8List.fromList(bytes);
     }
-    _chunks.add(bytes);
-    _length += bytes.length;
+    _chunks.add(typedBytes);
+    _length += typedBytes.length;
   }
 
   void addByte(int byte) { add([byte]); }
diff --git a/sdk/lib/io/common.dart b/sdk/lib/io/common.dart
index ea35580..6258bcf 100644
--- a/sdk/lib/io/common.dart
+++ b/sdk/lib/io/common.dart
@@ -90,7 +90,7 @@
 
 // Object for holding a buffer and an offset.
 class _BufferAndStart {
-  List buffer;
+  List<int> buffer;
   int start;
   _BufferAndStart(this.buffer, this.start);
 }
@@ -100,7 +100,7 @@
 // All other lists are first copied into a Uint8List. This has the added
 // benefit that it is faster to access from the C code as well.
 _BufferAndStart _ensureFastAndSerializableByteData(
-    List buffer, int start, int end) {
+    List<int> buffer, int start, int end) {
   if (buffer is Uint8List || buffer is Int8List) {
     return new _BufferAndStart(buffer, start);
   }
diff --git a/sdk/lib/io/crypto.dart b/sdk/lib/io/crypto.dart
index 82cff5e..96e4bd14 100644
--- a/sdk/lib/io/crypto.dart
+++ b/sdk/lib/io/crypto.dart
@@ -234,8 +234,8 @@
 
 
   // Compute the final result as a list of bytes from the hash words.
-  _resultAsBytes() {
-    var result = [];
+  List<int> _resultAsBytes() {
+    var result = <int>[];
     for (var i = 0; i < _h.length; i++) {
       result.addAll(_wordToBytes(_h[i]));
     }
@@ -261,7 +261,7 @@
   }
 
   // Convert a 32-bit word to four bytes.
-  _wordToBytes(int word) {
+  List<int> _wordToBytes(int word) {
     List<int> bytes = new List(_BYTES_PER_WORD);
     bytes[0] = (word >> (_bigEndianWords ? 24 : 0)) & _MASK_8;
     bytes[1] = (word >> (_bigEndianWords ? 16 : 8)) & _MASK_8;
diff --git a/sdk/lib/io/data_transformer.dart b/sdk/lib/io/data_transformer.dart
index 12d623a..6a50af4 100644
--- a/sdk/lib/io/data_transformer.dart
+++ b/sdk/lib/io/data_transformer.dart
@@ -275,8 +275,7 @@
  * The [ZLibEncoder] encoder is used by [ZLibCodec] and [GZipCodec] to compress
  * data.
  */
-class ZLibEncoder extends
-    ChunkedConverter<List<int>, List<int>, List<int>, List<int>> {
+class ZLibEncoder extends Converter<List<int>, List<int>> {
   /**
    * When true, `GZip` frames will be added to the compressed data.
    */
@@ -379,8 +378,7 @@
 /**
  * The [ZLibDecoder] is used by [ZLibCodec] and [GZipCodec] to decompress data.
  */
-class ZLibDecoder extends
-    ChunkedConverter<List<int>, List<int>, List<int>, List<int>> {
+class ZLibDecoder extends  Converter<List<int>, List<int>> {
   /**
    * Base two logarithm of the window size (the size of the history buffer). It
    * should be in the range `8..15`. Larger values result in better compression
@@ -494,7 +492,7 @@
       _filter.process(bufferAndStart.buffer,
                       bufferAndStart.start,
                       end - (start - bufferAndStart.start));
-      var out;
+      List<int> out;
       while ((out = _filter.processed(flush: false)) != null) {
         _sink.add(out);
       }
@@ -512,7 +510,7 @@
     // message would not have a GZip frame (if compressed with GZip).
     if (_empty) _filter.process(const [], 0, 0);
     try {
-      var out;
+      List<int> out;
       while ((out = _filter.processed(end: true)) != null) {
         _sink.add(out);
       }
diff --git a/sdk/lib/io/directory.dart b/sdk/lib/io/directory.dart
index 2ff3928..e890fcf 100644
--- a/sdk/lib/io/directory.dart
+++ b/sdk/lib/io/directory.dart
@@ -160,7 +160,7 @@
    * resolved by the OS.
    *
    * Note that setting the current working directory is a synchronous
-   * operation and that it changes the the working directory of *all*
+   * operation and that it changes the working directory of *all*
    * isolates.
    *
    * Use this with care - especially when working with asynchronous
diff --git a/sdk/lib/io/directory_impl.dart b/sdk/lib/io/directory_impl.dart
index d76b86d..c1fc540 100644
--- a/sdk/lib/io/directory_impl.dart
+++ b/sdk/lib/io/directory_impl.dart
@@ -22,7 +22,9 @@
   external static _create(String path);
   external static _deleteNative(String path, bool recursive);
   external static _rename(String path, String newPath);
-  external static List _list(String path, bool recursive, bool followLinks);
+  external static void _fillWithDirectoryListing(
+      List<FileSystemEntity> list, String path, bool recursive,
+      bool followLinks);
 
   static Directory get current {
     var result = _current();
@@ -70,30 +72,6 @@
 
   FileStat statSync() => FileStat.statSync(path);
 
-  // Compute the index of the first directory in the list that exists. If
-  // none of the directories exist dirsToCreate.length is returned.
-  Future<int> _computeExistingIndex(List dirsToCreate) {
-    var future;
-    var notFound = dirsToCreate.length;
-    for (var i = 0; i < dirsToCreate.length; i++) {
-      if (future == null) {
-        future = dirsToCreate[i].exists().then((e) => e ? i : notFound);
-      } else {
-        future = future.then((index) {
-          if (index != notFound) {
-            return new Future.value(index);
-          }
-          return dirsToCreate[i].exists().then((e) => e ? i : notFound);
-        });
-      }
-    }
-    if (future == null) {
-      return new Future.value(notFound);
-    } else {
-      return future;
-    }
-  }
-
   Future<Directory> create({bool recursive: false}) {
     if (recursive) {
       return exists().then((exists) {
@@ -222,14 +200,18 @@
         followLinks).stream;
   }
 
-  List listSync({bool recursive: false, bool followLinks: true}) {
+  List<FileSystemEntity> listSync(
+      {bool recursive: false, bool followLinks: true}) {
     if (recursive is! bool || followLinks is! bool) {
       throw new ArgumentError();
     }
-    return _list(
+    var result = <FileSystemEntity>[];
+    _fillWithDirectoryListing(
+        result,
         FileSystemEntity._ensureTrailingPathSeparators(path),
         recursive,
         followLinks);
+    return result;
   }
 
   String toString() => "Directory: '$path'";
@@ -274,7 +256,7 @@
   final bool recursive;
   final bool followLinks;
 
-  StreamController controller;
+  StreamController<FileSystemEntity> controller;
   bool canceled = false;
   bool nextRunning = false;
   bool closed = false;
@@ -282,10 +264,10 @@
   Completer closeCompleter = new Completer();
 
   _AsyncDirectoryLister(this.path, this.recursive, this.followLinks) {
-    controller = new StreamController(onListen: onListen,
-                                      onResume: onResume,
-                                      onCancel: onCancel,
-                                      sync: true);
+    controller = new StreamController<FileSystemEntity>(onListen: onListen,
+                                                        onResume: onResume,
+                                                        onCancel: onCancel,
+                                                        sync: true);
   }
 
   // Calling this function will increase the reference count on the native
@@ -296,7 +278,7 @@
     return (_ops == null) ? null : _ops.getPointer();
   }
 
-  Stream get stream => controller.stream;
+  Stream<FileSystemEntity> get stream => controller.stream;
 
   void onListen() {
     _IOService._dispatch(_DIRECTORY_LIST_START, [path, recursive, followLinks])
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index a6fdde8..bb00477 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -213,7 +213,7 @@
   }
 
   Future<File> close() =>
-      _openFuture.then((openedFile) => openedFile.close());
+      _openFuture.then/*<File>*/((openedFile) => openedFile.close());
 }
 
 
@@ -441,9 +441,9 @@
   }
 
   Future<List<int>> readAsBytes() {
-    Future<List<int>> readDataChunked(file) {
+    Future<List<int>> readDataChunked(RandomAccessFile file) {
       var builder = new BytesBuilder(copy: false);
-      var completer = new Completer();
+      var completer = new Completer<List<int>>();
       void read() {
         file.read(_BLOCK_SIZE).then((data) {
           if (data.length > 0) {
@@ -472,7 +472,7 @@
   List<int> readAsBytesSync() {
     var opened = openSync();
     try {
-      var data;
+      List<int> data;
       var length = opened.lengthSync();
       if (length == 0) {
         // May be character device, try to read it in chunks.
@@ -670,7 +670,7 @@
         throw _exceptionFromResponse(response, "read failed", path);
       }
       _resourceInfo.addRead(response[1].length);
-      return response[1];
+      return response[1] as Object/*=List<int>*/;
     });
   }
 
@@ -684,7 +684,7 @@
       throw new FileSystemException("readSync failed", path, result);
     }
     _resourceInfo.addRead(result.length);
-    return result;
+    return result as Object/*=List<int>*/;
   }
 
   Future<int> readInto(List<int> buffer, [int start = 0, int end]) {
@@ -703,7 +703,7 @@
         throw _exceptionFromResponse(response, "readInto failed", path);
       }
       var read = response[1];
-      var data = response[2];
+      var data = response[2] as Object/*=List<int>*/;
       buffer.setRange(start, start + read, data);
       _resourceInfo.addRead(read);
       return read;
diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart
index c63d28b..07257ea 100644
--- a/sdk/lib/io/http.dart
+++ b/sdk/lib/io/http.dart
@@ -1660,7 +1660,7 @@
    *
    * If a bad certificate is received on a connection attempt, the library calls
    * the function that was the value of badCertificateCallback at the time
-   * the the request is made, even if the value of badCertificateCallback
+   * the request is made, even if the value of badCertificateCallback
    * has changed since then.
    */
   set badCertificateCallback(bool callback(X509Certificate cert,
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index 846b724..96005c95 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -6,6 +6,8 @@
 
 const int _OUTGOING_BUFFER_SIZE = 8 * 1024;
 
+typedef void _BytesConsumer(List<int> bytes);
+
 class _HttpIncoming extends Stream<List<int>> {
   final int _transferLength;
   final Completer _dataCompleter = new Completer();
@@ -129,13 +131,14 @@
       var proto = headers['x-forwarded-proto'];
       var scheme = proto != null ? proto.first :
           _httpConnection._socket is SecureSocket ? "https" : "http";
-      var host = headers['x-forwarded-host'];
-      if (host != null) {
-        host = host.first;
+      var hostList = headers['x-forwarded-host'];
+      String host;
+      if (hostList != null) {
+        host = hostList.first;
       } else {
-        host = headers['host'];
-        if (host != null) {
-          host = host.first;
+        hostList = headers['host'];
+        if (hostList != null) {
+          host = hostList.first;
         } else {
           host = "${_httpServer.address.host}:${_httpServer.port}";
         }
@@ -182,8 +185,6 @@
   // The HttpClientRequest of this response.
   final _HttpClientRequest _httpRequest;
 
-  List<Cookie> _cookies;
-
   _HttpClientResponse(_HttpIncoming _incoming, this._httpRequest,
                       this._httpClient) : super(_incoming) {
     // Set uri for potential exceptions.
@@ -194,9 +195,9 @@
   String get reasonPhrase => _incoming.reasonPhrase;
 
   X509Certificate get certificate {
-    // The peerCertificate isn't on a plain socket, so cast to dynamic.
     var socket = _httpRequest._httpClientConnection._socket;
-    return socket.peerCertificate;
+    if (socket is SecureSocket) return socket.peerCertificate;
+    throw new UnsupportedError("Socket is not a SecureSocket");
   }
 
   List<Cookie> get cookies {
@@ -267,7 +268,7 @@
       // Since listening to upgraded data is 'bogus', simply close and
       // return empty stream subscription.
       _httpRequest._httpClientConnection.destroy();
-      return new Stream.fromIterable([]).listen(null, onDone: onDone);
+      return new Stream<List<int>>.empty().listen(null, onDone: onDone);
     }
     var stream = _incoming;
     if (_httpClient.autoUncompress &&
@@ -762,13 +763,16 @@
     if (followRedirects && response.isRedirect) {
       if (response.redirects.length < maxRedirects) {
         // Redirect and drain response.
-        future = response.drain().then((_) => response.redirect());
+        future = response.drain()
+            .then/*<HttpClientResponse>*/((_) => response.redirect());
       } else {
         // End with exception, too many redirects.
         future = response.drain()
-            .then((_) => new Future.error(
-                new RedirectException("Redirect limit exceeded",
-                                      response.redirects)));
+            .then/*<HttpClientResponse>*/((_) {
+          return new Future<HttpClientResponse>.error(
+              new RedirectException("Redirect limit exceeded",
+                  response.redirects));
+        });
       }
     } else if (response._shouldAuthenticateProxy) {
       future = response._authenticate(true);
@@ -862,15 +866,19 @@
 // Used by _HttpOutgoing as a target of a chunked converter for gzip
 // compression.
 class _HttpGZipSink extends ByteConversionSink {
-  final Function _consume;
+  final _BytesConsumer _consume;
   _HttpGZipSink(this._consume);
 
   void add(List<int> chunk) {
     _consume(chunk);
   }
 
-  void addSlice(Uint8List chunk, int start, int end, bool isLast) {
-    _consume(new Uint8List.view(chunk.buffer, start, end - start));
+  void addSlice(List<int> chunk, int start, int end, bool isLast) {
+    if (chunk is Uint8List) {
+      _consume(new Uint8List.view(chunk.buffer, start, end - start));
+    } else {
+      _consume(chunk.sublist(start, end - start));
+    }
   }
 
   void close() {}
@@ -893,7 +901,7 @@
   static const List<int> _chunk0Length =
       const [0x30, _CharCode.CR, _CharCode.LF, _CharCode.CR, _CharCode.LF];
 
-  final Completer _doneCompleter = new Completer();
+  final Completer<Socket> _doneCompleter = new Completer<Socket>();
   final Socket socket;
 
   bool ignoreBody = false;
@@ -914,7 +922,7 @@
   ByteConversionSink _gzipSink;
   // _gzipAdd is set iff the sink is being added to. It's used to specify where
   // gzipped data should be taken (sometimes a controller, sometimes a socket).
-  Function _gzipAdd;
+  _BytesConsumer _gzipAdd;
   Uint8List _gzipBuffer;
   int _gzipBufferLength = 0;
 
@@ -936,14 +944,16 @@
             "Headers size exceeded the of '$_OUTGOING_BUFFER_SIZE'"
             " bytes"));
       }
+      return null;
     }
+
     if (headersWritten) return null;
     headersWritten = true;
     Future drainFuture;
-    bool isServerSide = outbound is _HttpResponse;
     bool gzip = false;
-    if (isServerSide) {
-      var response = outbound;
+    if (outbound is _HttpResponse) {
+      // Server side.
+      _HttpResponse response = outbound;
       if (response._httpRequest._httpServer.autoCompress &&
           outbound.bufferOutput &&
           outbound.headers.chunkedTransferEncoding) {
@@ -997,16 +1007,16 @@
       }
       return close();
     }
-    var sub;
+    StreamSubscription<List<int>> sub;
     // Use new stream so we are able to pause (see below listen). The
     // alternative is to use stream.extand, but that won't give us a way of
     // pausing.
-    var controller = new StreamController(
+    var controller = new StreamController<List<int>>(
         onPause: () => sub.pause(),
         onResume: () => sub.resume(),
         sync: true);
 
-    void onData(data) {
+    void onData(List<int> data) {
       if (_socketError) return;
       if (data.length == 0) return;
       if (chunked) {
@@ -1146,7 +1156,7 @@
     return _closeFuture = finalize();
   }
 
-  Future get done => _doneCompleter.future;
+  Future<Socket> get done => _doneCompleter.future;
 
   void setHeader(List<int> data, int length) {
     assert(_length == 0);
@@ -1176,7 +1186,7 @@
     => (error is SocketException || error is TlsException) &&
        outbound is HttpResponse;
 
-  void _addGZipChunk(chunk, void add(List<int> data)) {
+  void _addGZipChunk(List<int> chunk, void add(List<int> data)) {
     if (!outbound.bufferOutput) {
       add(chunk);
       return;
@@ -1197,7 +1207,7 @@
     }
   }
 
-  void _addChunk(chunk, void add(List<int> data)) {
+  void _addChunk(List<int> chunk, void add(List<int> data)) {
     if (!outbound.bufferOutput) {
       if (_buffer != null) {
         // If _buffer is not null, we have not written the header yet. Write
@@ -1266,7 +1276,7 @@
   Uri _currentUri;
 
   Completer<_HttpIncoming> _nextResponseCompleter;
-  Future _streamFuture;
+  Future<Socket> _streamFuture;
 
   _HttpClientConnection(this.key, this._socket, this._httpClient,
                         [this._proxyTunnel = false, this._context])
@@ -1381,7 +1391,7 @@
     // data).
     _httpParser.isHead = method == "HEAD";
     _streamFuture = outgoing.done
-        .then((s) {
+        .then/*<Socket>*/((Socket s) {
           // Request sent, set up response completer.
           _nextResponseCompleter = new Completer();
 
@@ -1476,7 +1486,8 @@
         .then((_) => _socket.destroy());
   }
 
-  Future<_HttpClientConnection> createProxyTunnel(host, port, proxy, callback) {
+  Future<_HttpClientConnection> createProxyTunnel(String host, int port,
+      _Proxy proxy, bool callback(X509Certificate certificate)) {
     _HttpClientRequest request =
         send(new Uri(host: host, port: port),
              port,
@@ -1495,7 +1506,8 @@
             throw "Proxy failed to establish tunnel "
                   "(${response.statusCode} ${response.reasonPhrase})";
           }
-          var socket = response._httpRequest._httpClientConnection._socket;
+          var socket = (response as _HttpClientResponse)._httpRequest
+              ._httpClientConnection._socket;
           return SecureSocket.secure(
               socket,
               host: host,
@@ -1621,17 +1633,19 @@
     }
     if (client.maxConnectionsPerHost != null &&
         _active.length + _connecting >= client.maxConnectionsPerHost) {
-      var completer = new Completer();
+      var completer = new Completer<_ConnectionInfo>();
       _pending.add(() {
-        connect(uriHost, uriPort, proxy, client)
-            .then(completer.complete, onError: completer.completeError);
+        completer.complete(connect(uriHost, uriPort, proxy, client));
       });
       return completer.future;
     }
     var currentBadCertificateCallback = client._badCertificateCallback;
-    callback(X509Certificate certificate) =>
-        currentBadCertificateCallback == null ? false :
-        currentBadCertificateCallback(certificate, uriHost, uriPort);
+
+    bool callback(X509Certificate certificate) {
+      if (currentBadCertificateCallback == null) return false;
+      return currentBadCertificateCallback(certificate, uriHost, uriPort);
+    }
+
     Future socketFuture = (isSecure && proxy.isDirect
         ? SecureSocket.connect(host,
                                port,
@@ -1664,6 +1678,7 @@
   }
 }
 
+typedef bool BadCertificateCallback(X509Certificate cr, String host, int port);
 
 class _HttpClient implements HttpClient {
   bool _closing = false;
@@ -1677,7 +1692,7 @@
   Function _authenticateProxy;
   Function _findProxy = HttpClient.findProxyFromEnvironment;
   Duration _idleTimeout = const Duration(seconds: 15);
-  Function _badCertificateCallback;
+  BadCertificateCallback _badCertificateCallback;
 
   Duration get idleTimeout => _idleTimeout;
 
@@ -1734,9 +1749,8 @@
     return _openUrl(method, uri);
   }
 
-  Future<HttpClientRequest> openUrl(String method, Uri url) {
-    return _openUrl(method, url);
-  }
+  Future<HttpClientRequest> openUrl(String method, Uri url)
+      => _openUrl(method, url);
 
   Future<HttpClientRequest> get(String host, int port, String path)
       => open("get", host, port, path);
@@ -1799,7 +1813,7 @@
 
   set findProxy(String f(Uri uri)) => _findProxy = f;
 
-  Future<HttpClientRequest> _openUrl(String method, Uri uri) {
+  Future<_HttpClientRequest> _openUrl(String method, Uri uri) {
     // Ignore any fragments on the request URI.
     uri = uri.removeFragment();
 
@@ -1834,13 +1848,15 @@
       }
     }
     return _getConnection(uri.host, port, proxyConf, isSecure)
-        .then((info) {
-          send(info) {
+        .then((_ConnectionInfo info) {
+
+          _HttpClientRequest send(_ConnectionInfo info) {
             return info.connection.send(uri,
                                         port,
                                         method.toUpperCase(),
                                         info.proxy);
           }
+
           // If the connection was closed before the request was sent, create
           // and use another connection.
           if (info.connection.closed) {
@@ -1851,13 +1867,13 @@
         });
   }
 
-  Future<HttpClientRequest> _openUrlFromRequest(String method,
+  Future<_HttpClientRequest> _openUrlFromRequest(String method,
                                                 Uri uri,
                                                 _HttpClientRequest previous) {
     // If the new URI is relative (to either '/' or some sub-path),
     // construct a full URI from the previous one.
     Uri resolved = previous.uri.resolveUri(uri);
-    return openUrl(method, resolved).then((_HttpClientRequest request) {
+    return _openUrl(method, resolved).then((_HttpClientRequest request) {
 
           request
               // Only follow redirects if initial request did.
@@ -1935,16 +1951,20 @@
     // connection from the pool. For long-running synchronous code the
     // server might have closed the connection, so this lowers the
     // probability of getting a connection that was already closed.
-    return new Future(() => connect(new HttpException("No proxies given")));
+    return new Future<_ConnectionInfo>(
+        () => connect(new HttpException("No proxies given")));
   }
 
   _SiteCredentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) {
     // Look for credentials.
     _SiteCredentials cr =
-        _credentials.fold(null, (prev, value) {
-          if (value.applies(url, scheme)) {
+        _credentials.fold(null, (_SiteCredentials prev, value) {
+          var siteCredentials = value as _SiteCredentials;
+          if (siteCredentials.applies(url, scheme)) {
             if (prev == null) return value;
-            return value.uri.path.length > prev.uri.path.length ? value : prev;
+            return siteCredentials.uri.path.length > prev.uri.path.length
+                ? siteCredentials
+                : prev;
           } else {
             return prev;
           }
@@ -1961,6 +1981,7 @@
         return it.current;
       }
     }
+    return null;
   }
 
   void _removeCredentials(_Credentials cr) {
@@ -2059,7 +2080,7 @@
   static Map<int, _HttpConnection> _connections =
       new HashMap<int, _HttpConnection>();
 
-  final _socket;
+  final /*_ServerSocket*/ _socket;
   final _HttpServer _httpServer;
   final _HttpParser _httpParser;
   int _state = _IDLE;
@@ -2071,7 +2092,7 @@
       : _httpParser = new _HttpParser.requestParser() {
     try { _socket._owner = this; } catch (_) { print(_); }
     _connections[_serviceId] = this;
-    _httpParser.listenToStream(_socket);
+    _httpParser.listenToStream(_socket as Object/*=Socket*/);
     _subscription = _httpParser.listen(
         (incoming) {
           _httpServer._markActive(this);
@@ -2166,7 +2187,7 @@
   Map _toJSON(bool ref) {
     var name = "${_socket.address.host}:${_socket.port} <-> "
         "${_socket.remoteAddress.host}:${_socket.remotePort}";
-    var r = {
+    var r = <String, dynamic>{
       'id': _servicePath,
       'type': _serviceType(ref),
       'name': name,
@@ -2412,8 +2433,8 @@
   String get _serviceTypePath => 'io/http/servers';
   String get _serviceTypeName => 'HttpServer';
 
-  Map _toJSON(bool ref) {
-    var r = {
+  Map<String, dynamic> _toJSON(bool ref) {
+    var r = <String, dynamic>{
       'id': _servicePath,
       'type': _serviceType(ref),
       'name': '${address.host}:$port',
@@ -2447,7 +2468,7 @@
 
   // The server listen socket. Untyped as it can be both ServerSocket and
   // SecureServerSocket.
-  final _serverSocket;
+  final dynamic/*ServerSocket|SecureServerSocket*/ _serverSocket;
   final bool _closeServer;
 
   // Set of currently connected clients.
@@ -2562,7 +2583,7 @@
 
 class _DetachedSocket extends Stream<List<int>> implements Socket {
   final Stream<List<int>> _incoming;
-  final _socket;
+  final Socket _socket;
 
   _DetachedSocket(this._socket, this._incoming);
 
@@ -2597,7 +2618,7 @@
   void addError(error, [StackTrace stackTrace]) =>
       _socket.addError(error, stackTrace);
 
-  Future<Socket> addStream(Stream<List<int>> stream) {
+  Future addStream(Stream<List<int>> stream) {
     return _socket.addStream(stream);
   }
 
@@ -2605,7 +2626,7 @@
 
   Future flush() => _socket.flush();
 
-  Future close() => _socket.close();
+  Future<Socket> close() => _socket.close();
 
   Future<Socket> get done => _socket.done;
 
@@ -2621,8 +2642,12 @@
     return _socket.setOption(option, enabled);
   }
 
-  Map _toJSON(bool ref) => _socket._toJSON(ref);
-  void set _owner(owner) { _socket._owner = owner; }
+  Map _toJSON(bool ref) {
+    return (_socket as dynamic)._toJSON(ref);
+  }
+  void set _owner(owner) {
+    (_socket as dynamic)._owner = owner;
+  }
 }
 
 
diff --git a/sdk/lib/io/http_parser.dart b/sdk/lib/io/http_parser.dart
index 97d4fd7..c2b08e4 100644
--- a/sdk/lib/io/http_parser.dart
+++ b/sdk/lib/io/http_parser.dart
@@ -120,7 +120,8 @@
 
   bool get isPaused => _subscription.isPaused;
 
-  Future asFuture([futureValue]) => _subscription.asFuture(futureValue);
+  Future/*<T>*/ asFuture/*<T>*/([/*=T*/ futureValue]) =>
+      _subscription.asFuture/*<T>*/(futureValue);
 
   Future cancel() {
     _isCanceled = true;
@@ -182,7 +183,7 @@
 
 
 class _HttpDetachedIncoming extends Stream<List<int>> {
-  final StreamSubscription subscription;
+  final StreamSubscription<List<int>> subscription;
   final List<int> bufferedData;
 
   _HttpDetachedIncoming(this.subscription, this.bufferedData);
@@ -204,7 +205,8 @@
                                                  onData)
         ..resume();
     } else {
-      return new Stream.fromIterable(bufferedData)
+      // TODO(26379): add test for this branch.
+      return new Stream<List<int>>.fromIterable([bufferedData])
           .listen(onData,
                   onError: onError,
                   onDone: onDone,
@@ -266,7 +268,7 @@
 
   // The current incoming connection.
   _HttpIncoming _incoming;
-  StreamSubscription _socketSubscription;
+  StreamSubscription<List<int>> _socketSubscription;
   bool _paused = true;
   bool _bodyPaused = false;
   StreamController<_HttpIncoming> _controller;
diff --git a/sdk/lib/io/io.dart b/sdk/lib/io/io.dart
index 04cc6f2..c0d63de 100644
--- a/sdk/lib/io/io.dart
+++ b/sdk/lib/io/io.dart
@@ -190,7 +190,7 @@
  * tour](https://www.dartlang.org/docs/dart-up-and-running/ch03.html#dartio---io-for-command-line-apps).
  *
  * To learn more about I/O in Dart, refer to the [tutorial about writing
- * command-line apps](https://www.dartlang.org/docs/tutorials/io/).
+ * command-line apps](https://www.dartlang.org/docs/tutorials/cmdline/).
  */
 library dart.io;
 
diff --git a/sdk/lib/io/io_resource_info.dart b/sdk/lib/io/io_resource_info.dart
index 7cea231..317cf13 100644
--- a/sdk/lib/io/io_resource_info.dart
+++ b/sdk/lib/io/io_resource_info.dart
@@ -19,11 +19,11 @@
 
   /// Get the full set of values for a specific implementation. This is normally
   /// looked up based on an id from a referenceValueMap.
-  Map<String, String> get fullValueMap;
+  Map<String, dynamic> get fullValueMap;
 
   /// The reference map, used to return a list of values, e.g., getting
   /// all open sockets. The structure of this is shared among all subclasses.
-  Map<String, String> get referenceValueMap =>
+  Map<String, dynamic> get referenceValueMap =>
       {
         // The type for a reference object is prefixed with @ in observatory.
         'type': '@$type',
@@ -71,7 +71,7 @@
     lastWrite = 0.0,
     super(type);
 
-  Map<String, String> get fullValueMap =>
+  Map<String, dynamic> get fullValueMap =>
     {
       'type': type,
       'id': id,
@@ -118,9 +118,8 @@
     return new Future.value(new ServiceExtensionResponse.result(json));
   }
 
-  Map<String, String> getFileInfoMap() {
-    var result = fullValueMap;
-    return result;
+  Map<String, dynamic> getFileInfoMap() {
+    return fullValueMap;
   }
 
   static Future<ServiceExtensionResponse> getFileInfoMapByID(function, params) {
@@ -155,7 +154,7 @@
 
   void stopped() { ProcessStopped(this); }
 
-  Map<String, String> get fullValueMap =>
+  Map<String, dynamic> get fullValueMap =>
     {
       'type': type,
       'id': id,
@@ -204,7 +203,7 @@
   static const String UDP_STRING = 'UDP';
   static const String TYPE = '_socket';
 
-  final socket;
+  final /*_NativeSocket|*/ socket;
 
   static Map<int, _SocketResourceInfo> openSockets =
       new Map<int, _SocketResourceInfo>();
@@ -230,7 +229,7 @@
     return new List.from(openSockets.values.map((e) => e.referenceValueMap));
   }
 
-  Map<String, String> getSocketInfoMap() {
+  Map<String, dynamic> getSocketInfoMap() {
     var result = fullValueMap;
     result['socketType'] = socket.isTcp ? TCP_STRING : UDP_STRING;
     result['listening'] = socket.isListening;
@@ -279,5 +278,4 @@
     assert(openSockets.containsKey(info.id));
     openSockets.remove(info.id);
   }
-
 }
diff --git a/sdk/lib/io/link.dart b/sdk/lib/io/link.dart
index 25be38c..7c93725 100644
--- a/sdk/lib/io/link.dart
+++ b/sdk/lib/io/link.dart
@@ -223,7 +223,7 @@
     // Atomically changing a link can be done by creating the new link, with
     // a different name, and using the rename() posix call to move it to
     // the old name atomically.
-    return delete().then((_) => create(target));
+    return delete().then/*<Link>*/((_) => create(target));
   }
 
   Future<Link> _delete({bool recursive: false}) {
diff --git a/sdk/lib/io/platform_impl.dart b/sdk/lib/io/platform_impl.dart
index 8c9d30c..7527844 100644
--- a/sdk/lib/io/platform_impl.dart
+++ b/sdk/lib/io/platform_impl.dart
@@ -39,7 +39,7 @@
 
   // Cache the OS environemnt. This can be an OSError instance if
   // retrieving the environment failed.
-  static var _environmentCache;
+  static var/*OSError|Map<String,String>*/ _environmentCache;
 
   static int get numberOfProcessors => _numberOfProcessors();
   static String get pathSeparator => _pathSeparator();
@@ -62,7 +62,9 @@
       var env = _environment();
       if (env is !OSError) {
         var isWindows = operatingSystem == 'windows';
-        var result = isWindows ? new _CaseInsensitiveStringMap() : new Map();
+        var result = isWindows
+            ? new _CaseInsensitiveStringMap<String>()
+            : new Map<String, String>();
         for (var str in env) {
           // The Strings returned by [_environment()] are expected to be
           // valid environment entries, but exceptions have been seen
@@ -84,7 +86,7 @@
     if (_environmentCache is OSError) {
       throw _environmentCache;
     } else {
-      return _environmentCache;
+      return _environmentCache as Object/*=Map<String, String>*/;
     }
   }
 
@@ -96,19 +98,20 @@
 class _CaseInsensitiveStringMap<V> implements Map<String, V> {
   final Map<String, V> _map = new Map<String, V>();
 
-  bool containsKey(String key) => _map.containsKey(key.toUpperCase());
+  bool containsKey(Object key) =>
+      key is String && _map.containsKey(key.toUpperCase());
   bool containsValue(Object value) => _map.containsValue(value);
-  V operator [](String key) => _map[key.toUpperCase()];
+  V operator [](Object key) => key is String ? _map[key.toUpperCase()] : null;
   void operator []=(String key, V value) {
     _map[key.toUpperCase()] = value;
   }
   V putIfAbsent(String key, V ifAbsent()) {
-    _map.putIfAbsent(key.toUpperCase(), ifAbsent);
+    return _map.putIfAbsent(key.toUpperCase(), ifAbsent);
   }
-  addAll(Map other) {
+  void addAll(Map<String, V> other) {
     other.forEach((key, value) => this[key.toUpperCase()] = value);
   }
-  V remove(String key) => _map.remove(key.toUpperCase());
+  V remove(Object key) => key is String ? _map.remove(key.toUpperCase()) : null;
   void clear() { _map.clear(); }
   void forEach(void f(String key, V value)) { _map.forEach(f); }
   Iterable<String> get keys => _map.keys;
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index 679aa71..a2d6d78 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.dart
@@ -74,21 +74,17 @@
       {host,
        SecurityContext context,
        bool onBadCertificate(X509Certificate certificate)}) {
-    var completer = new Completer();
-    (socket as dynamic)._detachRaw()
-        .then((detachedRaw) {
+    return ((socket as dynamic/*_Socket*/)._detachRaw() as Future)
+        .then/*<RawSecureSocket>*/((detachedRaw) {
           return RawSecureSocket.secure(
-            detachedRaw[0],
-            subscription: detachedRaw[1],
+            detachedRaw[0] as RawSocket,
+            subscription: detachedRaw[1] as StreamSubscription<RawSocketEvent>,
             host: host,
             context: context,
             onBadCertificate: onBadCertificate);
           })
-        .then((raw) {
-          completer.complete(new SecureSocket._(raw));
-        });
-    return completer.future;
-  }
+        .then/*<SecureSocket>*/((raw) => new SecureSocket._(raw));
+ }
 
   /**
    * Takes an already connected [socket] and starts server side TLS
@@ -118,22 +114,18 @@
        bool requestClientCertificate: false,
        bool requireClientCertificate: false,
        List<String> supportedProtocols}) {
-    var completer = new Completer();
-    (socket as dynamic)._detachRaw()
-        .then((detachedRaw) {
+    return ((socket as dynamic/*_Socket*/)._detachRaw() as Future)
+        .then/*<RawSecureSocket>*/((detachedRaw) {
           return RawSecureSocket.secureServer(
-            detachedRaw[0],
+            detachedRaw[0] as RawSocket,
             context,
-            subscription: detachedRaw[1],
+            subscription: detachedRaw[1] as StreamSubscription<RawSocketEvent>,
             bufferedData: bufferedData,
             requestClientCertificate: requestClientCertificate,
             requireClientCertificate: requireClientCertificate,
             supportedProtocols: supportedProtocols);
           })
-        .then((raw) {
-          completer.complete(new SecureSocket._(raw));
-        });
-    return completer.future;
+        .then/*<SecureSocket>*/((raw) => new SecureSocket._(raw));
   }
 
   /**
@@ -244,7 +236,7 @@
    */
   static Future<RawSecureSocket> secure(
       RawSocket socket,
-      {StreamSubscription subscription,
+      {StreamSubscription<RawSocketEvent> subscription,
        host,
        SecurityContext context,
        bool onBadCertificate(X509Certificate certificate),
@@ -288,7 +280,7 @@
   static Future<RawSecureSocket> secureServer(
       RawSocket socket,
       SecurityContext context,
-      {StreamSubscription subscription,
+      {StreamSubscription<RawSocketEvent> subscription,
        List<int> bufferedData,
        bool requestClientCertificate: false,
        bool requireClientCertificate: false,
@@ -405,7 +397,8 @@
   bool _socketClosedWrite = false;  // The network socket is closed for writing.
   bool _closedRead = false;  // The secure socket has fired an onClosed event.
   bool _closedWrite = false;  // The secure socket has been closed for writing.
-  Completer _closeCompleter = new Completer();  // The network socket is gone.
+  // The network socket is gone.
+  Completer<RawSecureSocket> _closeCompleter = new Completer<RawSecureSocket>();
   _FilterStatus _filterStatus = new _FilterStatus();
   bool _connectPending = true;
   bool _filterPending = false;
@@ -415,12 +408,12 @@
   String _selectedProtocol;
 
   static Future<_RawSecureSocket> connect(
-      host,
+      dynamic/*String|InternetAddress*/ host,
       int requestedPort,
       {bool is_server,
        SecurityContext context,
        RawSocket socket,
-       StreamSubscription subscription,
+       StreamSubscription<RawSocketEvent> subscription,
        List<int> bufferedData,
        bool requestClientCertificate: false,
        bool requireClientCertificate: false,
@@ -430,8 +423,10 @@
                  requestClientCertificate, requireClientCertificate,
                  onBadCertificate);
     if (host is InternetAddress) host = host.host;
-    var address = socket.address;
-    if (host != null) address =  address._cloneWithNewHost(host);
+    InternetAddress address = socket.address;
+    if (host != null) {
+      address = InternetAddress._cloneWithNewHost(address, host);
+    }
     return new _RawSecureSocket(address,
                                 requestedPort,
                                 is_server,
@@ -517,10 +512,10 @@
     }
   }
 
-  StreamSubscription listen(void onData(RawSocketEvent data),
-                            {Function onError,
-                             void onDone(),
-                             bool cancelOnError}) {
+  StreamSubscription<RawSocketEvent> listen(void onData(RawSocketEvent data),
+                                            {Function onError,
+                                             void onDone(),
+                                             bool cancelOnError}) {
     _sendWriteEvent();
     return _stream.listen(onData,
                           onError: onError,
@@ -574,7 +569,7 @@
     return _closeCompleter.future;
   }
 
-  void _completeCloseCompleter([dummy]) {
+  void _completeCloseCompleter([RawSocket dummy]) {
     if (!_closeCompleter.isCompleted) _closeCompleter.complete(this);
   }
 
@@ -1060,7 +1055,8 @@
  * and one writing.  All updates to start and end are done by Dart code.
  */
 class _ExternalBuffer {
-  List data;  // This will be a ExternalByteArray, backed by C allocated data.
+  // This will be an ExternalByteArray, backed by C allocated data.
+  List<int> data;
   int start;
   int end;
   final size;
diff --git a/sdk/lib/io/socket.dart b/sdk/lib/io/socket.dart
index 30e4eb2..0a112d5 100644
--- a/sdk/lib/io/socket.dart
+++ b/sdk/lib/io/socket.dart
@@ -141,6 +141,15 @@
    */
   external static Future<List<InternetAddress>> lookup(
       String host, {InternetAddressType type: InternetAddressType.ANY});
+
+  /**
+   * Clones the given [address] with the new [host].
+   *
+   * The [address] must be an [InternetAddress] that was created with one
+   * of the static methods of this class.
+   */
+  external static InternetAddress _cloneWithNewHost(
+      InternetAddress address, String host);
 }
 
 
@@ -559,6 +568,10 @@
    * Returns the remote [InternetAddress] connected to by this socket.
    */
   InternetAddress get remoteAddress;
+
+  Future<Socket> close();
+
+  Future<Socket> get done;
 }
 
 
diff --git a/sdk/lib/io/stdio.dart b/sdk/lib/io/stdio.dart
index feea4ff..67f4370 100644
--- a/sdk/lib/io/stdio.dart
+++ b/sdk/lib/io/stdio.dart
@@ -57,7 +57,7 @@
                        bool retainNewlines: false}) {
     const CR = 13;
     const LF = 10;
-    final List line = [];
+    final List<int> line = <int>[];
     // On Windows, if lineMode is disabled, only CR is received.
     bool crIsNewline = Platform.isWindows &&
         (stdioType(stdin) == StdioType.TERMINAL) &&
@@ -328,13 +328,18 @@
     return StdioType.FILE;
   }
   if (object is Socket) {
-    switch (_StdIOUtils._socketType(object._nativeSocket)) {
-      case _STDIO_HANDLE_TYPE_TERMINAL: return StdioType.TERMINAL;
-      case _STDIO_HANDLE_TYPE_PIPE: return StdioType.PIPE;
-      case _STDIO_HANDLE_TYPE_FILE:  return StdioType.FILE;
+    int socketType = _StdIOUtils._socketType(object);
+    if (socketType == null) return StdioType.OTHER;
+    switch (socketType) {
+      case _STDIO_HANDLE_TYPE_TERMINAL:
+        return StdioType.TERMINAL;
+      case _STDIO_HANDLE_TYPE_PIPE:
+        return StdioType.PIPE;
+      case _STDIO_HANDLE_TYPE_FILE:
+        return StdioType.FILE;
     }
   }
-  if (object is IOSink) {
+  if (object is _IOSinkImpl) {
     try {
       if (object._target is _FileStreamConsumer) {
         return StdioType.FILE;
@@ -350,6 +355,7 @@
 class _StdIOUtils {
   external static _getStdioOutputStream(int fd);
   external static Stdin _getStdioInputStream();
-  external static int _socketType(nativeSocket);
+  /// Returns the socket type or `null` if [socket] is not a builtin socket.
+  external static int _socketType(Socket socket);
   external static _getStdioHandleType(int fd);
 }
diff --git a/sdk/lib/io/string_transformer.dart b/sdk/lib/io/string_transformer.dart
index b6f4524..ab17eaf 100644
--- a/sdk/lib/io/string_transformer.dart
+++ b/sdk/lib/io/string_transformer.dart
@@ -25,7 +25,7 @@
   List<int> encode(String input) => encoder.convert(input);
   String decode(List<int> encoded) => decoder.convert(encoded);
 
-  ChunkedConverter<String, List<int>, String, List<int>> get encoder {
+  Converter<String, List<int>> get encoder {
     if (Platform.operatingSystem == "windows") {
       return const _WindowsCodePageEncoder();
     } else {
@@ -33,7 +33,7 @@
     }
   }
 
-  ChunkedConverter<List<int>, String, List<int>, String> get decoder {
+  Converter<List<int>, String> get decoder {
     if (Platform.operatingSystem == "windows") {
       return const _WindowsCodePageDecoder();
     } else {
@@ -42,8 +42,7 @@
   }
 }
 
-class _WindowsCodePageEncoder
-    extends ChunkedConverter<String, List<int>, String, List<int>> {
+class _WindowsCodePageEncoder extends Converter<String, List<int>> {
 
   const _WindowsCodePageEncoder();
 
@@ -62,9 +61,6 @@
     return new _WindowsCodePageEncoderSink(sink);
   }
 
-  // Override the base-class' bind, to provide a better type.
-  Stream<List<int>> bind(Stream<String> stream) => super.bind(stream);
-
   external static List<int> _encodeString(String string);
 }
 
@@ -98,8 +94,7 @@
 }
 
 
-class _WindowsCodePageDecoder
-    extends ChunkedConverter<List<int>, String, List<int>, String> {
+class _WindowsCodePageDecoder extends Converter<List<int>, String> {
 
   const _WindowsCodePageDecoder();
 
@@ -114,9 +109,6 @@
     return new _WindowsCodePageDecoderSink(sink);
   }
 
-  // Override the base-class' bind, to provide a better type.
-  Stream<String> bind(Stream<List<int>> stream) => super.bind(stream);
-
   external static String _decodeBytes(List<int> bytes);
 }
 
diff --git a/sdk/lib/io/websocket.dart b/sdk/lib/io/websocket.dart
index 183714f..df6c8cf 100644
--- a/sdk/lib/io/websocket.dart
+++ b/sdk/lib/io/websocket.dart
@@ -212,9 +212,10 @@
    * then the [WebSocket] will be created with the default [CompressionOptions].
    */
   factory WebSocketTransformer(
-          {protocolSelector(List<String> protocols),
-          CompressionOptions compression: CompressionOptions.DEFAULT}) =>
-      new _WebSocketTransformerImpl(protocolSelector, compression);
+      {/*String|Future<String>*/ protocolSelector(List<String> protocols),
+      CompressionOptions compression: CompressionOptions.DEFAULT}) {
+    return new _WebSocketTransformerImpl(protocolSelector, compression);
+  }
 
   /**
    * Upgrades a [HttpRequest] to a [WebSocket] connection. If the
@@ -252,9 +253,11 @@
  * A two-way HTTP communication object for client or server applications.
  *
  * The stream exposes the messages received. A text message will be of type
- * [:String:] and a binary message will be of type [:List<int>:].
+ * `String` and a binary message will be of type `List<int>`.
  */
-abstract class WebSocket implements Stream, StreamSink {
+abstract class WebSocket
+    implements Stream<dynamic/*String|List<int>*/>,
+        StreamSink<dynamic/*String|List<int>*/> {
   /**
    * Possible states of the connection.
    */
@@ -389,14 +392,14 @@
 
   /**
    * Sends data on the WebSocket connection. The data in [data] must
-   * be either a [:String:], or a [:List<int>:] holding bytes.
+   * be either a `String`, or a `List<int>` holding bytes.
    */
-  void add(data);
+  void add(/*String|List<int>*/ data);
 
   /**
    * Sends data from a stream on WebSocket connection. Each data event from
    * [stream] will be send as a single WebSocket frame. The data from [stream]
-   * must be either [:String:]s, or [:List<int>:]s holding bytes.
+   * must be either `String`s, or `List<int>`s holding bytes.
    */
   Future addStream(Stream stream);
 }
diff --git a/sdk/lib/io/websocket_impl.dart b/sdk/lib/io/websocket_impl.dart
index ec1320a..d593b58 100644
--- a/sdk/lib/io/websocket_impl.dart
+++ b/sdk/lib/io/websocket_impl.dart
@@ -50,7 +50,7 @@
 
 /**
  * The web socket protocol transformer handles the protocol byte stream
- * which is supplied through the [:handleData:]. As the protocol is processed,
+ * which is supplied through the `handleData`. As the protocol is processed,
  * it'll output frame data as either a List<int> or String.
  *
  * Important information about usage: Be sure you use cancelOnError, so the
@@ -59,7 +59,8 @@
  */
 // TODO(ajohnsen): make this transformer reusable?
 class _WebSocketProtocolTransformer
-    implements StreamTransformer<List<int>, dynamic>, EventSink<List<int>> {
+    implements EventSink<List<int>>, StreamTransformer<
+        List<int>, dynamic/*List<int>|_WebSocketPing|_WebSocketPong>*/> {
   static const int START = 0;
   static const int LEN_FIRST = 1;
   static const int LEN_REST = 2;
@@ -87,7 +88,7 @@
   int closeCode = WebSocketStatus.NO_STATUS_RECEIVED;
   String closeReason = "";
 
-  EventSink _eventSink;
+  EventSink<dynamic/*List<int>|_WebSocketPing|_WebSocketPong>*/> _eventSink;
 
   final bool _serverSide;
   final List _maskingBytes = new List(4);
@@ -96,7 +97,8 @@
   _WebSocketPerMessageDeflate _deflate;
   _WebSocketProtocolTransformer([this._serverSide = false, this._deflate]);
 
-  Stream bind(Stream stream) {
+  Stream<dynamic/*List<int>|_WebSocketPing|_WebSocketPong>*/> bind(
+      Stream<List<int>> stream) {
     return new Stream.eventTransformed(stream, (EventSink eventSink) {
       if (_eventSink != null) {
         throw new StateError("WebSocket transformer already used.");
@@ -394,10 +396,12 @@
   _WebSocketPong([this.payload = null]);
 }
 
+typedef /*String|Future<String>*/ _ProtocolSelector(List<String> protocols);
+
 class _WebSocketTransformerImpl implements WebSocketTransformer {
   final StreamController<WebSocket> _controller =
       new StreamController<WebSocket>(sync: true);
-  final Function _protocolSelector;
+  final _ProtocolSelector _protocolSelector;
   final CompressionOptions _compression;
 
   _WebSocketTransformerImpl(this._protocolSelector, this._compression);
@@ -414,8 +418,8 @@
     return _controller.stream;
   }
 
-  static Future<WebSocket> _upgrade(
-      HttpRequest request, _protocolSelector, CompressionOptions compression) {
+  static Future<WebSocket> _upgrade(HttpRequest request,
+      _ProtocolSelector _protocolSelector, CompressionOptions compression) {
     var response = request.response;
     if (!_isUpgradeRequest(request)) {
       // Send error response.
@@ -426,7 +430,7 @@
           new WebSocketException("Invalid WebSocket upgrade request"));
     }
 
-    Future upgrade(String protocol) {
+    Future<WebSocket> upgrade(String protocol) {
       // Send the upgrade response.
       response
         ..statusCode = HttpStatus.SWITCHING_PROTOCOLS
@@ -444,7 +448,7 @@
       var deflate = _negotiateCompression(request, response, compression);
 
       response.headers.contentLength = 0;
-      return response.detachSocket().then((socket) =>
+      return response.detachSocket().then/*<WebSocket>*/((socket) =>
           new _WebSocketImpl._fromSocket(
               socket, protocol, compression, true, deflate));
     }
@@ -455,7 +459,8 @@
       // consisting of multiple protocols. To unify all of them, first join
       // the lists with ', ' and then tokenize.
       protocols = _HttpParser._tokenizeFieldValue(protocols.join(', '));
-      return new Future(() => _protocolSelector(protocols)).then((protocol) {
+      return new Future<String>(() => _protocolSelector(protocols))
+          .then/*<String>*/((protocol) {
         if (protocols.indexOf(protocol) < 0) {
           throw new WebSocketException(
               "Selected protocol is not in the list of available protocols");
@@ -466,7 +471,7 @@
           ..statusCode = HttpStatus.INTERNAL_SERVER_ERROR
           ..close();
         throw error;
-      }).then(upgrade);
+      }).then/*<WebSocket>*/(upgrade);
     } else {
       return upgrade(null);
     }
@@ -570,13 +575,13 @@
   Uint8List processIncomingMessage(List<int> msg) {
     _ensureDecoder();
 
-    var data = [];
+    var data = <int>[];
     data.addAll(msg);
     data.addAll(const [0x00, 0x00, 0xff, 0xff]);
 
     decoder.process(data, 0, data.length);
-    var result = [];
-    var out;
+    var result = <int>[];
+    List<int> out;
 
     while ((out = decoder.processed()) != null) {
       result.addAll(out);
@@ -592,9 +597,8 @@
 
   List<int> processOutgoingMessage(List<int> msg) {
     _ensureEncoder();
-    var result = [];
+    var result = <int>[];
     Uint8List buffer;
-    var out;
 
     if (msg is! Uint8List) {
       for (var i = 0; i < msg.length; i++) {
@@ -610,6 +614,7 @@
 
     encoder.process(buffer, 0, buffer.length);
 
+    List<int> out;
     while ((out = encoder.processed()) != null) {
       result.addAll(out);
     }
@@ -640,7 +645,8 @@
   }
 
   Stream<List<int>> bind(Stream stream) {
-    return new Stream.eventTransformed(stream, (eventSink) {
+    return new Stream<List<int>>.eventTransformed(
+        stream, (EventSink<List<int>> eventSink) {
       if (_eventSink != null) {
         throw new StateError("WebSocket transformer already used");
       }
@@ -666,8 +672,8 @@
         data = UTF8.encode(message);
       } else {
         if (message is List<int>) {
-          data = message;
           opcode = _WebSocketOpcode.BINARY;
+          data = message;
         } else {
           throw new ArgumentError(message);
         }
@@ -702,15 +708,16 @@
     _eventSink.close();
   }
 
-  void addFrame(int opcode, List<int> data) => createFrame(
-          opcode,
-          data,
-          webSocket._serverSide,
-          _deflateHelper != null &&
-              (opcode == _WebSocketOpcode.TEXT ||
-                  opcode == _WebSocketOpcode.BINARY)).forEach((e) {
-        _eventSink.add(e);
-      });
+  void addFrame(int opcode, List<int> data) {
+    createFrame(
+        opcode,
+        data,
+        webSocket._serverSide,
+        _deflateHelper != null &&
+            (opcode == _WebSocketOpcode.TEXT ||
+                opcode == _WebSocketOpcode.BINARY))
+      .forEach((e) { _eventSink.add(e); });
+  }
 
   static Iterable<List<int>> createFrame(
       int opcode, List<int> data, bool serverSide, bool compressed) {
@@ -1000,6 +1007,7 @@
 
       return request.close();
     }).then((response) {
+
       void error(String message) {
         // Flush data.
         response.detachSocket().then((socket) {
@@ -1007,6 +1015,7 @@
         });
         throw new WebSocketException(message);
       }
+
       if (response.statusCode != HttpStatus.SWITCHING_PROTOCOLS ||
           response.headers[HttpHeaders.CONNECTION] == null ||
           !response.headers[HttpHeaders.CONNECTION]
@@ -1036,7 +1045,7 @@
       _WebSocketPerMessageDeflate deflate =
           negotiateClientCompression(response, compression);
 
-      return response.detachSocket().then((socket) =>
+      return response.detachSocket().then/*<WebSocket>*/((socket) =>
           new _WebSocketImpl._fromSocket(
               socket, protocol, compression, false, deflate));
     });
@@ -1064,8 +1073,7 @@
           return DEFAULT_WINDOW_BITS;
         }
 
-        o = int.parse(o, onError: (s) => DEFAULT_WINDOW_BITS);
-        return o;
+        return int.parse(o, onError: (s) => DEFAULT_WINDOW_BITS);
       }
 
       return new _WebSocketPerMessageDeflate(
@@ -1220,7 +1228,7 @@
   String get _serviceTypePath => 'io/websockets';
   String get _serviceTypeName => 'WebSocket';
 
-  Map _toJSON(bool ref) {
+  Map<String, dynamic> _toJSON(bool ref) {
     var name = '${_socket.address.host}:${_socket.port}';
     var r = <String, dynamic>{
       'id': _servicePath,
diff --git a/sdk/lib/js/dartium/cached_patches.dart b/sdk/lib/js/dartium/cached_patches.dart
index 81edc87..f9a46f2 100644
--- a/sdk/lib/js/dartium/cached_patches.dart
+++ b/sdk/lib/js/dartium/cached_patches.dart
@@ -2644,15 +2644,6 @@
   get runtimeType => RelatedEvent;
   toString() => super.toString();
 }
-patch class ResourceProgressEvent {
-  static Type get instanceRuntimeType => ResourceProgressEventImpl;
-
-}
-class ResourceProgressEventImpl extends ResourceProgressEvent implements js_library.JSObjectInterfacesDom {
-  ResourceProgressEventImpl.internal_() : super.internal_();
-  get runtimeType => ResourceProgressEvent;
-  toString() => super.toString();
-}
 patch class RtcDataChannel {
   static Type get instanceRuntimeType => RtcDataChannelImpl;
 
@@ -3958,6 +3949,15 @@
   get runtimeType => _Request;
   toString() => super.toString();
 }
+patch class _ResourceProgressEvent {
+  static Type get instanceRuntimeType => _ResourceProgressEventImpl;
+
+}
+class _ResourceProgressEventImpl extends _ResourceProgressEvent implements js_library.JSObjectInterfacesDom {
+  _ResourceProgressEventImpl.internal_() : super.internal_();
+  get runtimeType => _ResourceProgressEvent;
+  toString() => super.toString();
+}
 patch class _Response {
   static Type get instanceRuntimeType => _ResponseImpl;
 
diff --git a/sdk/lib/math/point.dart b/sdk/lib/math/point.dart
index 42fcc46..01ce93c 100644
--- a/sdk/lib/math/point.dart
+++ b/sdk/lib/math/point.dart
@@ -55,8 +55,9 @@
    * it, passing in a double [factor] on a `Point<int>` _causes_ _a_
    * _runtime_ _error_ in checked mode.
    */
-  Point<T> operator *(num factor) {
-    return new Point<T>(x * factor, y * factor);
+  Point<T> operator *(num/*T|int*/ factor) {
+    return new Point<T>(
+        (x * factor) as dynamic/*=T*/, (y * factor) as dynamic/*=T*/);
   }
 
   /**
diff --git a/sdk/lib/math/rectangle.dart b/sdk/lib/math/rectangle.dart
index 1ab292a..6fe2075 100644
--- a/sdk/lib/math/rectangle.dart
+++ b/sdk/lib/math/rectangle.dart
@@ -209,8 +209,8 @@
    * point `(left, top)`.
    */
   MutableRectangle(this.left, this.top, T width, T height)
-      : this._width = (width < 0) ? _clampToZero(width) : width,
-        this._height = (height < 0) ? _clampToZero(height) : height;
+      : this._width = (width < 0) ? _clampToZero/*<T>*/(width) : width,
+        this._height = (height < 0) ? _clampToZero/*<T>*/(height) : height;
 
   /**
    * Create a mutable rectangle spanned by the points [a] and [b];
@@ -244,7 +244,7 @@
    * but will not change [left].
    */
   void set width(T width) {
-    if (width < 0) width = _clampToZero(width);
+    if (width < 0) width = _clampToZero/*<T>*/(width);
     _width = width;
   }
 
@@ -260,7 +260,7 @@
    * but will not change [top].
    */
   void set height(T height) {
-    if (height < 0) height = _clampToZero(height);
+    if (height < 0) height = _clampToZero/*<T>*/(height);
     _height = height;
   }
 }
@@ -270,7 +270,7 @@
  *
  * Returns `0` if value is int, `0.0` if value is double.
  */
-num _clampToZero(num value) {
+num/*=T*/ _clampToZero/*<T extends num>*/(num/*=T*/ value) {
   assert(value < 0);
   return -value * 0;
 }
diff --git a/sdk/lib/mirrors/mirrors.dart b/sdk/lib/mirrors/mirrors.dart
index 3ba8dcd..a5f5750 100644
--- a/sdk/lib/mirrors/mirrors.dart
+++ b/sdk/lib/mirrors/mirrors.dart
@@ -225,7 +225,7 @@
   /**
    * The simple name for this Dart language entity.
    *
-   * The simple name is in most cases the the identifier name of the entity,
+   * The simple name is in most cases the identifier name of the entity,
    * such as 'myMethod' for a method, [:void myMethod() {...}:] or 'mylibrary'
    * for a [:library 'mylibrary';:] declaration.
    */
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index d9a0814..69afd94 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -150,20 +150,6 @@
 Language/Mixins/Mixin_Application/error_t02: Pass
 Language/Mixins/declaring_constructor_t01: Pass
 
-[ $runtime == vm && $mode == product ]
-LibTest/typed_data/Float32List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
-LibTest/typed_data/Float32x4List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
-LibTest/typed_data/Float64List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
-LibTest/typed_data/Int16List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
-LibTest/typed_data/Int32List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
-LibTest/typed_data/Int64List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
-LibTest/typed_data/Int8List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
-LibTest/typed_data/Uint16List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
-LibTest/typed_data/Uint32List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
-LibTest/typed_data/Uint64List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
-LibTest/typed_data/Uint8ClampedList/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
-LibTest/typed_data/Uint8List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
-
 [ ($arch == simdbc || $arch == simdbc64) && $mode == debug ]
 # TODO(vegorov) These tests are very slow on unoptimized SIMDBC
 LibTest/collection/ListMixin/ListMixin_class_A01_t02: Timeout
diff --git a/tests/compiler/dart2js/analyze_test_test.dart b/tests/compiler/dart2js/analyze_test_test.dart
index a38c814..af3eb25 100644
--- a/tests/compiler/dart2js/analyze_test_test.dart
+++ b/tests/compiler/dart2js/analyze_test_test.dart
@@ -58,27 +58,34 @@
 
 main(List<String> arguments) {
   List<String> options = <String>[];
-  for (String argument in arguments) {
-    if (argument == '-v') {
-      options.add(Flags.verbose);
-    } else if (argument.startsWith('-')) {
-      options.add(argument);
-    }
-  }
   List<Uri> uriList = <Uri>[];
-  for (String arg in arguments) {
-    if (!arg.startsWith('-')) {
-      for (String line in new File(arg).readAsLinesSync()) {
-        line = line.trim();
-        if (line.startsWith('Analyzing uri: ')) {
-          int filenameOffset = line.indexOf('tests/compiler/dart2js/');
-          if (filenameOffset != -1) {
-            uriList.add(Uri.base.resolve(
-                nativeToUriPath(line.substring(filenameOffset))));
+  String filter;
+  bool first = true;
+  for (String argument in arguments) {
+    if (argument.startsWith('-')) {
+      options.add(argument == '-v' ? Flags.verbose : argument);
+    } else if (first) {
+      File file = new File(argument);
+      if (file.existsSync()) {
+        // Read test files from [file].
+        for (String line in file.readAsLinesSync()) {
+          line = line.trim();
+          if (line.startsWith('Analyzing uri: ')) {
+            int filenameOffset = line.indexOf('tests/compiler/dart2js/');
+            if (filenameOffset != -1) {
+              uriList.add(Uri.base.resolve(
+                  nativeToUriPath(line.substring(filenameOffset))));
+            }
           }
         }
+      } else {
+        // Use argument as filter on test files.
+        filter = argument;
       }
+    } else {
+      throw new ArgumentError("Extra argument $argument in $arguments.");
     }
+    first = false;
   }
 
   asyncTest(() async {
@@ -88,6 +95,9 @@
       for (FileSystemEntity entity in dir.listSync(recursive: true)) {
         if (entity is File && entity.path.endsWith('.dart')) {
           Uri file = Uri.base.resolve(nativeToUriPath(entity.path));
+          if (filter != null && !'$file'.contains(filter)) {
+            continue;
+          }
           if (!SKIP_LIST.any((skip) => file.path.contains(skip))) {
             uriList.add(file);
           }
diff --git a/tests/compiler/dart2js/bad_output_io_test.dart b/tests/compiler/dart2js/bad_output_io_test.dart
index 6f11981..ebda63f 100644
--- a/tests/compiler/dart2js/bad_output_io_test.dart
+++ b/tests/compiler/dart2js/bad_output_io_test.dart
@@ -56,11 +56,9 @@
   int throwOnErrorCount;
 }
 
-testOutputProvider(script, libraryRoot, packageRoot, inputProvider, handler,
-                   [options, outputProvider, environment, packageConfig,
-                    findPackages]) {
+testOutputProvider(options, input, diagnostics, output) {
   diagnosticHandler = new CollectingFormattingDiagnosticHandler();
-  outputProvider("/non/existing/directory/should/fail/file", "js");
+  output.createEventSink("/non/existing/directory/should/fail/file", "js");
 }
 
 void main() {
diff --git a/tests/compiler/dart2js/exit_code_test.dart b/tests/compiler/dart2js/exit_code_test.dart
index 67a04bd..3c7b2d9 100644
--- a/tests/compiler/dart2js/exit_code_test.dart
+++ b/tests/compiler/dart2js/exit_code_test.dart
@@ -11,7 +11,6 @@
 import 'package:async_helper/async_helper.dart';
 import 'package:expect/expect.dart';
 
-import 'package:compiler/compiler.dart' as old_api;
 import 'package:compiler/compiler_new.dart' as api;
 import 'package:compiler/src/common/codegen.dart';
 import 'package:compiler/src/compile_time_constants.dart';
@@ -26,7 +25,6 @@
 import 'package:compiler/src/elements/elements.dart';
 import 'package:compiler/src/library_loader.dart';
 import 'package:compiler/src/null_compiler_output.dart';
-import 'package:compiler/src/old_to_new_api.dart';
 import 'package:compiler/src/options.dart' show CompilerOptions;
 import 'package:compiler/src/resolution/resolution.dart';
 import 'package:compiler/src/scanner/scanner_task.dart';
@@ -42,24 +40,12 @@
   TestCompiler(api.CompilerInput inputProvider,
                api.CompilerOutput outputProvider,
                api.CompilerDiagnostics handler,
-               Uri libraryRoot,
-               Uri packageRoot,
-               List<String> options,
-               Map<String, dynamic> environment,
-               Uri packageConfig,
-               api.PackagesDiscoveryProvider findPackages,
+               CompilerOptions options,
                String this.testMarker,
                String this.testType,
                Function this.onTest)
       : reporter = new TestDiagnosticReporter(),
-        super(inputProvider, outputProvider, handler,
-            new CompilerOptions.parse(
-                libraryRoot: libraryRoot,
-                packageRoot: packageRoot,
-                options: options,
-                environment: environment,
-                packageConfig: packageConfig,
-                packagesDiscoveryProvider: findPackages)) {
+        super(inputProvider, outputProvider, handler, options) {
     reporter.compiler = this;
     reporter.reporter = super.reporter;
     test('Compiler');
@@ -186,36 +172,24 @@
     }
   }
   return new Future(() {
-    Future<old_api.CompilationResult> compile(
-        Uri script,
-        Uri libraryRoot,
-        Uri packageRoot,
-        old_api.CompilerInputProvider inputProvider,
-        old_api.DiagnosticHandler handler,
-        [List<String> options = const [],
-         old_api.CompilerOutputProvider outputProvider,
-         Map<String, dynamic> environment = const {},
-         Uri packageConfig,
-         api.PackagesDiscoveryProvider findPackages]) {
-      libraryRoot = Platform.script.resolve('../../../sdk/');
-      outputProvider = NullSink.outputProvider;
+    Future<api.CompilationResult> compile(
+        CompilerOptions compilerOptions,
+        api.CompilerInput compilerInput,
+        api.CompilerDiagnostics compilerDiagnostics,
+        api.CompilerOutput compilerOutput) {
+      compilerOutput = const NullCompilerOutput();
       // Use this to silence the test when debugging:
       // handler = (uri, begin, end, message, kind) {};
       Compiler compiler = new TestCompiler(
-          new LegacyCompilerInput(inputProvider),
-          new LegacyCompilerOutput(outputProvider),
-          new LegacyCompilerDiagnostics(handler),
-          libraryRoot,
-          packageRoot,
-          options,
-          environment,
-          packageConfig,
-          findPackages,
+          compilerInput,
+          compilerOutput,
+          compilerDiagnostics,
+          compilerOptions,
           marker,
           type,
           onTest);
-      return compiler.run(script).then((bool success) {
-        return new old_api.CompilationResult(compiler, isSuccess: success);
+      return compiler.run(compilerOptions.entryPoint).then((bool success) {
+        return new api.CompilationResult(compiler, isSuccess: success);
       });
     }
 
@@ -242,6 +216,7 @@
     entry.compileFunc = compile;
 
     List<String> args = new List<String>.from(options)
+        ..add("--library-root=${Platform.script.resolve('../../../sdk/')}")
         ..add("tests/compiler/dart2js/data/exit_code_helper.dart");
     Future result = entry.internalMain(args);
     return result.catchError((e, s) {
diff --git a/tests/compiler/dart2js/serialization/analysis_test.dart b/tests/compiler/dart2js/serialization/analysis_test.dart
index b1a96b5..1630660 100644
--- a/tests/compiler/dart2js/serialization/analysis_test.dart
+++ b/tests/compiler/dart2js/serialization/analysis_test.dart
@@ -8,8 +8,6 @@
 import 'package:async_helper/async_helper.dart';
 import 'package:expect/expect.dart';
 import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common/backend_api.dart';
-import 'package:compiler/src/common/names.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/filenames.dart';
 import '../memory_compiler.dart';
@@ -40,7 +38,7 @@
       options: [Flags.analyzeOnly],
       diagnosticHandler: diagnosticCollector,
       beforeRun: (Compiler compiler) {
-        deserialize(compiler, serializedData);
+        compiler.serialization.deserializeFromText(serializedData);
       });
   if (test != null) {
     Expect.equals(test.expectedErrorCount, diagnosticCollector.errors.length,
diff --git a/tests/compiler/dart2js/serialization/compilation_test.dart b/tests/compiler/dart2js/serialization/compilation_test.dart
index e6601e1..7346b86 100644
--- a/tests/compiler/dart2js/serialization/compilation_test.dart
+++ b/tests/compiler/dart2js/serialization/compilation_test.dart
@@ -6,10 +6,6 @@
 
 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/common/backend_api.dart';
-import 'package:compiler/src/common/names.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/filenames.dart';
 import '../memory_compiler.dart';
@@ -20,29 +16,27 @@
 main(List<String> args) {
   asyncTest(() async {
     Arguments arguments = new Arguments.from(args);
-    String serializedData = await serializeDartCore(
-        arguments: arguments,
-        serializeResolvedAst: true);
+    String serializedData = await serializeDartCore(arguments: arguments);
     if (arguments.filename != null) {
       Uri entryPoint = Uri.base.resolve(nativeToUriPath(arguments.filename));
       await compile(serializedData, entryPoint, null);
     } else {
       Uri entryPoint = Uri.parse('memory:main.dart');
-      // TODO(johnniwinther): Handle the remaining tests.
-      for (Test test in TESTS.sublist(0, 5)) {
+      arguments.forEachTest(TESTS, (int index, Test test) async {
         await compile(serializedData, entryPoint, test,
+                      index: index,
                       verbose: arguments.verbose);
-      }
+      });
     }
   });
 }
 
 Future compile(String serializedData, Uri entryPoint, Test test,
-               {bool verbose: false}) async {
+               {int index, bool verbose: false}) async {
   String testDescription =
       test != null ? test.sourceFiles[entryPoint.path] : '${entryPoint}';
   print('------------------------------------------------------------------');
-  print('compile ${testDescription}');
+  print('compile ${index != null ? '$index:' :''}${testDescription}');
   print('------------------------------------------------------------------');
   OutputCollector outputCollector = new OutputCollector();
   await runCompiler(
@@ -51,7 +45,7 @@
       options: [],
       outputProvider: outputCollector,
       beforeRun: (Compiler compiler) {
-        deserialize(compiler, serializedData, deserializeResolvedAst: true);
+        compiler.serialization.deserializeFromText(serializedData);
       });
   if (verbose) {
     print(outputCollector.getOutput('', 'js'));
diff --git a/tests/compiler/dart2js/serialization/equivalence_test.dart b/tests/compiler/dart2js/serialization/equivalence_test.dart
index 32a538a..fb1ace8 100644
--- a/tests/compiler/dart2js/serialization/equivalence_test.dart
+++ b/tests/compiler/dart2js/serialization/equivalence_test.dart
@@ -8,10 +8,7 @@
 import '../memory_compiler.dart';
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common.dart';
 import 'package:compiler/src/constants/constructors.dart';
-import 'package:compiler/src/constants/expressions.dart';
-import 'package:compiler/src/dart_types.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/diagnostics/invariant.dart';
 import 'package:compiler/src/elements/elements.dart';
@@ -245,6 +242,12 @@
     element1.accept(this, element2);
     check(element1, element2, 'isSynthesized',
         element1.isSynthesized, element2.isSynthesized);
+    check(element1, element2, 'isLocal',
+        element1.isLocal, element2.isLocal);
+    check(element1, element2, 'isFinal',
+        element1.isFinal, element2.isFinal);
+    check(element1, element2, 'isConst',
+        element1.isConst, element2.isConst);
   }
 
   @override
@@ -438,10 +441,6 @@
     checkTypes(
         element1, element2, 'type',
         element1.type, element2.type);
-    check(element1, element2, 'isConst',
-          element1.isConst, element2.isConst);
-    check(element1, element2, 'isFinal',
-          element1.isFinal, element2.isFinal);
     checkConstants(
         element1, element2, 'constant',
         element1.constant, element2.constant);
@@ -553,8 +552,6 @@
     checkTypes(
         element1, element2, 'type',
         element1.type, element2.type);
-    check(element1, element2, 'isConst',
-          element1.isConst, element2.isConst);
     check(element1, element2, 'isExternal',
           element1.isExternal, element2.isExternal);
     if (element1.isConst && !element1.isExternal) {
@@ -646,9 +643,6 @@
     check(
         element1, element2, 'isNamed',
         element1.isNamed, element2.isNamed);
-    check(
-        element1, element2, 'isFinal',
-        element1.isFinal, element2.isFinal);
     check(element1, element2, 'name', element1.name, element2.name);
     if (element1.isOptional) {
       checkConstants(
diff --git a/tests/compiler/dart2js/serialization/helper.dart b/tests/compiler/dart2js/serialization/helper.dart
index 095915b..1ce8c2b 100644
--- a/tests/compiler/dart2js/serialization/helper.dart
+++ b/tests/compiler/dart2js/serialization/helper.dart
@@ -8,30 +8,16 @@
 import 'dart:io';
 
 import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common.dart';
-import 'package:compiler/src/common/backend_api.dart';
 import 'package:compiler/src/common/names.dart';
-import 'package:compiler/src/common/resolution.dart';
 import 'package:compiler/src/compiler.dart';
-import 'package:compiler/src/elements/elements.dart';
-import 'package:compiler/src/io/source_file.dart';
-import 'package:compiler/src/scanner/scanner.dart';
-import 'package:compiler/src/script.dart';
-import 'package:compiler/src/serialization/impact_serialization.dart';
-import 'package:compiler/src/serialization/json_serializer.dart';
-import 'package:compiler/src/serialization/modelz.dart';
-import 'package:compiler/src/serialization/resolved_ast_serialization.dart';
-import 'package:compiler/src/serialization/serialization.dart';
-import 'package:compiler/src/serialization/task.dart';
-import 'package:compiler/src/tokens/token.dart';
-import 'package:compiler/src/universe/call_structure.dart';
-import 'package:compiler/src/universe/world_impact.dart';
-import 'package:compiler/src/universe/use.dart';
 
 import '../memory_compiler.dart';
+import 'test_data.dart';
 
 class Arguments {
   final String filename;
+  final int start;
+  final int end;
   final bool loadSerializedData;
   final bool saveSerializedData;
   final String serializedDataFileName;
@@ -39,6 +25,8 @@
 
   const Arguments({
     this.filename,
+    this.start,
+    this.end,
     this.loadSerializedData: false,
     this.saveSerializedData: false,
     this.serializedDataFileName: 'out.data',
@@ -46,9 +34,18 @@
 
   factory Arguments.from(List<String> arguments) {
     String filename;
+    int start;
+    int end;
     for (String arg in arguments) {
       if (!arg.startsWith('-')) {
-        filename = arg;
+        int index = int.parse(arg);
+        if (index == null) {
+          filename = arg;
+        } else if (start == null) {
+          start = index;
+        } else {
+          end = index;
+        }
       }
     }
     bool verbose = arguments.contains('-v');
@@ -56,16 +53,26 @@
     bool saveSerializedData = arguments.contains('-s');
     return new Arguments(
         filename: filename,
+        start: start,
+        end: end,
         verbose: verbose,
         loadSerializedData: loadSerializedData,
         saveSerializedData: saveSerializedData);
   }
+
+  Future forEachTest(List<Test> tests, Future f(int index, Test test)) async {
+    int first = start ?? 0;
+    int last = end ?? tests.length - 1;
+    for (int index = first; index <= last; index++) {
+      Test test = TESTS[index];
+      await f(index, test);
+    }
+  }
 }
 
 
 Future<String> serializeDartCore(
-    {Arguments arguments: const Arguments(),
-     bool serializeResolvedAst: false}) async {
+    {Arguments arguments: const Arguments()}) async {
   print('------------------------------------------------------------------');
   print('serialize dart:core');
   print('------------------------------------------------------------------');
@@ -82,11 +89,10 @@
         options: [Flags.analyzeAll]);
     compiler.serialization.supportSerialization = true;
     await compiler.run(Uris.dart_core);
-    serializedData = serialize(
-        compiler,
-        compiler.libraryLoader.libraries,
-        serializeResolvedAst: serializeResolvedAst)
-          .toText(const JsonSerializationEncoder());
+    BufferedEventSink sink = new BufferedEventSink();
+    compiler.serialization.serializeToSink(
+        sink, compiler.libraryLoader.libraries);
+    serializedData = sink.text;
     if (arguments.saveSerializedData) {
       File file = new File(arguments.serializedDataFileName);
       print('Saving data to $file');
@@ -95,287 +101,3 @@
   }
   return serializedData;
 }
-
-Serializer serialize(
-    Compiler compiler,
-    Iterable<LibraryElement> libraries,
-    {bool serializeResolvedAst: false}) {
-  assert(compiler.serialization.supportSerialization);
-
-  Serializer serializer = new Serializer();
-  SerializerPlugin backendSerializer =
-      compiler.backend.serialization.serializer;
-  serializer.plugins.add(backendSerializer);
-  serializer.plugins.add(new ResolutionImpactSerializer(
-      compiler.resolution, backendSerializer));
-  if (serializeResolvedAst) {
-    serializer.plugins.add(new ResolvedAstSerializerPlugin(
-        compiler.resolution, backendSerializer));
-  }
-
-  for (LibraryElement library in libraries) {
-    serializer.serialize(library);
-  }
-  return serializer;
-}
-
-void deserialize(Compiler compiler,
-                 String serializedData,
-                 {bool deserializeResolvedAst: false}) {
-  Deserializer deserializer = new Deserializer.fromText(
-      new DeserializationContext(),
-      serializedData,
-      const JsonSerializationDecoder());
-  deserializer.plugins.add(compiler.backend.serialization.deserializer);
-  compiler.serialization.deserializer =
-      new _DeserializerSystem(
-          compiler,
-          deserializer,
-          compiler.backend.impactTransformer,
-          deserializeResolvedAst: deserializeResolvedAst);
-}
-
-
-const String WORLD_IMPACT_TAG = 'worldImpact';
-
-class ResolutionImpactSerializer extends SerializerPlugin {
-  final Resolution resolution;
-  final SerializerPlugin nativeDataSerializer;
-
-  ResolutionImpactSerializer(this.resolution, this.nativeDataSerializer);
-
-  @override
-  void onElement(Element element, ObjectEncoder createEncoder(String tag)) {
-    if (resolution.hasBeenResolved(element)) {
-      ResolutionImpact impact = resolution.getResolutionImpact(element);
-      ObjectEncoder encoder = createEncoder(WORLD_IMPACT_TAG);
-      new ImpactSerializer(element, encoder, nativeDataSerializer)
-          .serialize(impact);
-    }
-  }
-}
-
-class ResolutionImpactDeserializer extends DeserializerPlugin {
-  Map<Element, ResolutionImpact> impactMap = <Element, ResolutionImpact>{};
-  final DeserializerPlugin nativeDataDeserializer;
-
-  ResolutionImpactDeserializer(this.nativeDataDeserializer);
-
-  @override
-  void onElement(Element element, ObjectDecoder getDecoder(String tag)) {
-    ObjectDecoder decoder = getDecoder(WORLD_IMPACT_TAG);
-    if (decoder != null) {
-      impactMap[element] =
-          ImpactDeserializer.deserializeImpact(
-              element, decoder, nativeDataDeserializer);
-    }
-  }
-}
-
-class _DeserializerSystem extends DeserializerSystem {
-  final Compiler _compiler;
-  final Deserializer _deserializer;
-  final List<LibraryElement> deserializedLibraries = <LibraryElement>[];
-  final ResolutionImpactDeserializer _resolutionImpactDeserializer;
-  final ResolvedAstDeserializerPlugin _resolvedAstDeserializer;
-  final ImpactTransformer _impactTransformer;
-  final bool deserializeResolvedAst;
-
-  factory _DeserializerSystem(
-      Compiler compiler,
-      Deserializer deserializer,
-      ImpactTransformer impactTransformer,
-      {bool deserializeResolvedAst: false}) {
-    List<DeserializerPlugin> plugins = <DeserializerPlugin>[];
-    DeserializerPlugin backendDeserializer =
-        compiler.backend.serialization.deserializer;
-    deserializer.plugins.add(backendDeserializer);
-    ResolutionImpactDeserializer resolutionImpactDeserializer =
-        new ResolutionImpactDeserializer(backendDeserializer);
-    deserializer.plugins.add(resolutionImpactDeserializer);
-    ResolvedAstDeserializerPlugin resolvedAstDeserializer;
-    if (deserializeResolvedAst) {
-      resolvedAstDeserializer = new ResolvedAstDeserializerPlugin(
-          compiler.parsingContext, backendDeserializer);
-      deserializer.plugins.add(resolvedAstDeserializer);
-    }
-    return new _DeserializerSystem._(
-        compiler,
-        deserializer,
-        impactTransformer,
-        resolutionImpactDeserializer,
-        resolvedAstDeserializer,
-        deserializeResolvedAst: deserializeResolvedAst);
-  }
-
-  _DeserializerSystem._(
-      this._compiler,
-      this._deserializer,
-      this._impactTransformer,
-      this._resolutionImpactDeserializer,
-      this._resolvedAstDeserializer,
-      {this.deserializeResolvedAst: false});
-
-
-  @override
-  Future<LibraryElement> readLibrary(Uri resolvedUri) {
-    LibraryElement library = _deserializer.lookupLibrary(resolvedUri);
-    if (library != null) {
-      deserializedLibraries.add(library);
-      if (deserializeResolvedAst) {
-        return Future.forEach(library.compilationUnits,
-            (CompilationUnitElement compilationUnit) {
-          ScriptZ script = compilationUnit.script;
-          return _compiler.readScript(script.readableUri)
-              .then((Script newScript) {
-            script.file = newScript.file;
-            _resolvedAstDeserializer.sourceFiles[script.resourceUri] =
-                newScript.file;
-          });
-        }).then((_) => library);
-      }
-    }
-    return new Future<LibraryElement>.value(library);
-  }
-
-  @override
-  bool hasResolvedAst(ExecutableElement element) {
-    if (_resolvedAstDeserializer != null) {
-      return _resolvedAstDeserializer.hasResolvedAst(element);
-    }
-    return false;
-  }
-
-  @override
-  ResolvedAst getResolvedAst(ExecutableElement element) {
-    if (_resolvedAstDeserializer != null) {
-      return _resolvedAstDeserializer.getResolvedAst(element);
-    }
-    return null;
-  }
-
-  @override
-  bool hasResolutionImpact(Element element) {
-    if (element.isConstructor &&
-            element.enclosingClass.isUnnamedMixinApplication) {
-      return true;
-    }
-    return _resolutionImpactDeserializer.impactMap.containsKey(element);
-  }
-
-  @override
-  ResolutionImpact getResolutionImpact(Element element) {
-    if (element.isConstructor &&
-        element.enclosingClass.isUnnamedMixinApplication) {
-      ClassElement superclass =  element.enclosingClass.superclass;
-      ConstructorElement superclassConstructor =
-          superclass.lookupConstructor(element.name);
-      assert(invariant(element, superclassConstructor != null,
-          message: "Superclass constructor '${element.name}' called from "
-                   "${element} not found in ${superclass}."));
-      // TODO(johnniwinther): Compute callStructure. Currently not used.
-      CallStructure callStructure;
-      return _resolutionImpactDeserializer.impactMap.putIfAbsent(element, () {
-        return new DeserializedResolutionImpact(
-            staticUses: <StaticUse>[new StaticUse.superConstructorInvoke(
-                superclassConstructor, callStructure)]);
-      });
-    }
-    return _resolutionImpactDeserializer.impactMap[element];
-  }
-
-  @override
-  WorldImpact computeWorldImpact(Element element) {
-    ResolutionImpact resolutionImpact = getResolutionImpact(element);
-    assert(invariant(element, resolutionImpact != null,
-        message: 'No impact found for $element (${element.library})'));
-    return _impactTransformer.transformResolutionImpact(resolutionImpact);
-  }
-
-  @override
-  bool isDeserialized(Element element) {
-    return deserializedLibraries.contains(element.library);
-  }
-}
-
-const String RESOLVED_AST_TAG = 'resolvedAst';
-
-class ResolvedAstSerializerPlugin extends SerializerPlugin {
-  final Resolution resolution;
-  final SerializerPlugin nativeDataSerializer;
-
-  ResolvedAstSerializerPlugin(this.resolution, this.nativeDataSerializer);
-
-  @override
-  void onElement(Element element, ObjectEncoder createEncoder(String tag)) {
-    assert(invariant(element, element.isDeclaration,
-        message: "Element $element must be the declaration"));
-    if (element is MemberElement) {
-      assert(invariant(element, resolution.hasResolvedAst(element),
-          message: "Element $element must have a resolved ast"));
-      ResolvedAst resolvedAst = resolution.getResolvedAst(element);
-      ObjectEncoder objectEncoder = createEncoder(RESOLVED_AST_TAG);
-      new ResolvedAstSerializer(
-          objectEncoder,
-          resolvedAst,
-          nativeDataSerializer).serialize();
-    }
-  }
-}
-
-class ResolvedAstDeserializerPlugin extends DeserializerPlugin {
-  final ParsingContext parsingContext;
-  final DeserializerPlugin nativeDataDeserializer;
-  final Map<Uri, SourceFile> sourceFiles = <Uri, SourceFile>{};
-
-  Map<ExecutableElement, ResolvedAst> _resolvedAstMap =
-      <ExecutableElement, ResolvedAst>{};
-  Map<MemberElement, ObjectDecoder> _decoderMap =
-      <MemberElement, ObjectDecoder>{};
-  Map<Uri, Token> beginTokenMap = <Uri, Token>{};
-
-  ResolvedAstDeserializerPlugin(
-      this.parsingContext, this.nativeDataDeserializer);
-
-  bool hasResolvedAst(ExecutableElement element) {
-    return _resolvedAstMap.containsKey(element) ||
-        _decoderMap.containsKey(element.memberContext);
-  }
-
-  ResolvedAst getResolvedAst(ExecutableElement element) {
-    ResolvedAst resolvedAst = _resolvedAstMap[element];
-    if (resolvedAst == null) {
-      ObjectDecoder decoder = _decoderMap[element.memberContext];
-      if (decoder != null) {
-         ResolvedAstDeserializer.deserialize(
-             element.memberContext, decoder, parsingContext, findToken,
-             nativeDataDeserializer,
-             _resolvedAstMap);
-        _decoderMap.remove(element);
-        resolvedAst = _resolvedAstMap[element];
-      }
-    }
-    return resolvedAst;
-  }
-
-  Token findToken(Uri uri, int offset) {
-    Token beginToken = beginTokenMap.putIfAbsent(uri, () {
-      SourceFile sourceFile = sourceFiles[uri];
-      if (sourceFile == null) {
-        throw 'No source file found for $uri in:\n '
-              '${sourceFiles.keys.join('\n ')}';
-      }
-      return new Scanner(sourceFile).tokenize();
-    });
-    return ResolvedAstDeserializer.findTokenInStream(beginToken, offset);
-  }
-
-  @override
-  void onElement(Element element, ObjectDecoder getDecoder(String tag)) {
-    ObjectDecoder decoder = getDecoder(RESOLVED_AST_TAG);
-    if (decoder != null) {
-      _decoderMap[element] = decoder;
-    }
-  }
-}
-
diff --git a/tests/compiler/dart2js/serialization/impact_test.dart b/tests/compiler/dart2js/serialization/impact_test.dart
index ea1d113..5b062fe 100644
--- a/tests/compiler/dart2js/serialization/impact_test.dart
+++ b/tests/compiler/dart2js/serialization/impact_test.dart
@@ -7,11 +7,8 @@
 import 'dart:async';
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common/resolution.dart';
 import 'package:compiler/src/compiler.dart';
-import 'package:compiler/src/elements/elements.dart';
 import 'package:compiler/src/filenames.dart';
-import 'package:compiler/src/serialization/equivalence.dart';
 import '../memory_compiler.dart';
 import 'helper.dart';
 import 'test_helper.dart';
@@ -48,7 +45,7 @@
       memorySourceFiles: sourceFiles,
       options: [Flags.analyzeAll]);
   compilerDeserialized.resolution.retainCachesForTesting = true;
-  deserialize(compilerDeserialized, serializedData);
+  compilerDeserialized.serialization.deserializeFromText(serializedData);
   await compilerDeserialized.run(entryPoint);
 
   checkAllImpacts(compilerNormal, compilerDeserialized, verbose: verbose);
diff --git a/tests/compiler/dart2js/serialization/library_test.dart b/tests/compiler/dart2js/serialization/library_test.dart
index 81d90cf..c8cfd4c 100644
--- a/tests/compiler/dart2js/serialization/library_test.dart
+++ b/tests/compiler/dart2js/serialization/library_test.dart
@@ -9,15 +9,9 @@
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/common/names.dart';
-import 'package:compiler/src/constants/constructors.dart';
-import 'package:compiler/src/constants/expressions.dart';
-import 'package:compiler/src/dart_types.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/diagnostics/invariant.dart';
 import 'package:compiler/src/elements/elements.dart';
-import 'package:compiler/src/elements/visitor.dart';
-import 'package:compiler/src/ordered_typeset.dart';
-import 'package:compiler/src/serialization/element_serialization.dart';
 import 'package:compiler/src/serialization/json_serializer.dart';
 import 'package:compiler/src/serialization/serialization.dart';
 
diff --git a/tests/compiler/dart2js/serialization/model_test.dart b/tests/compiler/dart2js/serialization/model_test.dart
index 0229b02..a8704ae 100644
--- a/tests/compiler/dart2js/serialization/model_test.dart
+++ b/tests/compiler/dart2js/serialization/model_test.dart
@@ -8,23 +8,14 @@
 import 'dart:io';
 import 'package:async_helper/async_helper.dart';
 import 'package:expect/expect.dart';
+import 'package:compiler/src/closure.dart';
 import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common/backend_api.dart';
-import 'package:compiler/src/common/names.dart';
-import 'package:compiler/src/common/resolution.dart';
 import 'package:compiler/src/compiler.dart';
-import 'package:compiler/src/dart_types.dart';
 import 'package:compiler/src/elements/elements.dart';
 import 'package:compiler/src/filenames.dart';
-import 'package:compiler/src/serialization/element_serialization.dart';
-import 'package:compiler/src/serialization/impact_serialization.dart';
-import 'package:compiler/src/serialization/json_serializer.dart';
-import 'package:compiler/src/serialization/serialization.dart';
 import 'package:compiler/src/serialization/equivalence.dart';
-import 'package:compiler/src/serialization/task.dart';
-import 'package:compiler/src/universe/world_impact.dart';
+import 'package:compiler/src/tree/nodes.dart';
 import 'package:compiler/src/universe/class_set.dart';
-import 'package:compiler/src/universe/use.dart';
 import '../memory_compiler.dart';
 import 'helper.dart';
 import 'test_data.dart';
@@ -36,23 +27,23 @@
     String serializedData = await serializeDartCore(arguments: arguments);
     if (arguments.filename != null) {
       Uri entryPoint = Uri.base.resolve(nativeToUriPath(arguments.filename));
-      await check(serializedData, entryPoint);
+      await checkModels(serializedData, entryPoint);
     } else {
       Uri entryPoint = Uri.parse('memory:main.dart');
-      for (Test test in TESTS) {
+      arguments.forEachTest(TESTS, (int index, Test test) async {
         print('==============================================================');
         print(test.sourceFiles);
-        await check(
+        await checkModels(
           serializedData,
           entryPoint,
           sourceFiles: test.sourceFiles,
           verbose: arguments.verbose);
-      }
+      });
     }
   });
 }
 
-Future check(
+Future checkModels(
   String serializedData,
   Uri entryPoint,
   {Map<String, String> sourceFiles: const <String, String>{},
@@ -66,7 +57,9 @@
       options: [Flags.analyzeOnly]);
   compilerNormal.resolution.retainCachesForTesting = true;
   await compilerNormal.run(entryPoint);
+  compilerNormal.phase = Compiler.PHASE_DONE_RESOLVING;
   compilerNormal.world.populate();
+  compilerNormal.backend.onResolutionComplete();
 
   print('------------------------------------------------------------------');
   print('compile deserialized');
@@ -75,9 +68,11 @@
       memorySourceFiles: sourceFiles,
       options: [Flags.analyzeOnly]);
   compilerDeserialized.resolution.retainCachesForTesting = true;
-  deserialize(compilerDeserialized, serializedData);
+  compilerDeserialized.serialization.deserializeFromText(serializedData);
   await compilerDeserialized.run(entryPoint);
+  compilerDeserialized.phase = Compiler.PHASE_DONE_RESOLVING;
   compilerDeserialized.world.populate();
+  compilerDeserialized.backend.onResolutionComplete();
 
   checkAllImpacts(
       compilerNormal, compilerDeserialized,
@@ -109,64 +104,144 @@
       compilerDeserialized.enqueuer.resolution.processedElements,
       "Processed element mismatch",
       areElementsEquivalent,
+      onSameElement: (a, b) {
+        checkElements(
+            compilerNormal, compilerDeserialized, a, b, verbose: verbose);
+      },
       verbose: verbose);
 
   checkClassHierarchyNodes(
-    compilerNormal.world.getClassHierarchyNode(
-        compilerNormal.coreClasses.objectClass),
-    compilerDeserialized.world.getClassHierarchyNode(
-        compilerDeserialized.coreClasses.objectClass),
-    verbose: verbose);
+      compilerNormal,
+      compilerDeserialized,
+      compilerNormal.world.getClassHierarchyNode(
+          compilerNormal.coreClasses.objectClass),
+      compilerDeserialized.world.getClassHierarchyNode(
+          compilerDeserialized.coreClasses.objectClass),
+      verbose: verbose);
+}
+
+void checkElements(
+    Compiler compiler1, Compiler compiler2,
+    Element element1, Element element2,
+    {bool verbose: false}) {
+  if (element1.isFunction ||
+      element1.isConstructor ||
+      (element1.isField && element1.isInstanceMember)) {
+    AstElement astElement1 = element1;
+    AstElement astElement2 = element2;
+    ClosureClassMap closureData1 =
+    compiler1.closureToClassMapper.computeClosureToClassMapping(
+        astElement1.resolvedAst);
+    ClosureClassMap closureData2 =
+    compiler2.closureToClassMapper.computeClosureToClassMapping(
+        astElement2.resolvedAst);
+
+    checkElementIdentities(closureData1, closureData2,
+        '$element1.closureElement',
+        closureData1.closureElement, closureData2.closureElement);
+    checkElementIdentities(closureData1, closureData2,
+        '$element1.closureClassElement',
+        closureData1.closureClassElement, closureData2.closureClassElement);
+    checkElementIdentities(closureData1, closureData2,
+        '$element1.callElement',
+        closureData1.callElement, closureData2.callElement);
+    check(closureData1, closureData2,
+        '$element1.thisLocal',
+        closureData1.thisLocal, closureData2.thisLocal,
+        areLocalsEquivalent);
+    checkMaps(
+        closureData1.freeVariableMap,
+        closureData2.freeVariableMap,
+        "$element1.freeVariableMap",
+        areLocalsEquivalent,
+        areCapturedVariablesEquivalent,
+        verbose: verbose);
+    checkMaps(
+        closureData1.capturingScopes,
+        closureData2.capturingScopes,
+        "$element1.capturingScopes",
+        areNodesEquivalent,
+        areClosureScopesEquivalent,
+        verbose: verbose,
+        keyToString: nodeToString);
+    checkSets(
+        closureData1.variablesUsedInTryOrGenerator,
+        closureData2.variablesUsedInTryOrGenerator,
+        "$element1.variablesUsedInTryOrGenerator",
+        areLocalsEquivalent,
+        verbose: verbose);
+  }
+}
+
+void checkMixinUses(
+    Compiler compiler1, Compiler compiler2,
+    ClassElement class1, ClassElement class2,
+    {bool verbose: false}) {
+
+  checkSets(
+      compiler1.world.mixinUsesOf(class1),
+      compiler2.world.mixinUsesOf(class2),
+      "Mixin uses of $class1 vs $class2",
+      areElementsEquivalent,
+      verbose: verbose);
+
 }
 
 void checkClassHierarchyNodes(
-    ClassHierarchyNode a, ClassHierarchyNode b,
+    Compiler compiler1,
+    Compiler compiler2,
+    ClassHierarchyNode node1, ClassHierarchyNode node2,
     {bool verbose: false}) {
   if (verbose) {
-    print('Checking $a vs $b');
+    print('Checking $node1 vs $node2');
   }
   Expect.isTrue(
-      areElementsEquivalent(a.cls, b.cls),
-      "Element identity mismatch for ${a.cls} vs ${b.cls}.");
+      areElementsEquivalent(node1.cls, node2.cls),
+      "Element identity mismatch for ${node1.cls} vs ${node2.cls}.");
   Expect.equals(
-      a.isDirectlyInstantiated,
-      b.isDirectlyInstantiated,
-      "Value mismatch for 'isDirectlyInstantiated' for ${a.cls} vs ${b.cls}.");
+      node1.isDirectlyInstantiated,
+      node2.isDirectlyInstantiated,
+      "Value mismatch for 'isDirectlyInstantiated' "
+      "for ${node1.cls} vs ${node2.cls}.");
   Expect.equals(
-      a.isIndirectlyInstantiated,
-      b.isIndirectlyInstantiated,
+      node1.isIndirectlyInstantiated,
+      node2.isIndirectlyInstantiated,
       "Value mismatch for 'isIndirectlyInstantiated' "
-      "for ${a.cls} vs ${b.cls}.");
+      "for ${node1.cls} vs ${node2.cls}.");
   // TODO(johnniwinther): Enforce a canonical and stable order on direct
   // subclasses.
-  for (ClassHierarchyNode child in a.directSubclasses) {
+  for (ClassHierarchyNode child in node1.directSubclasses) {
     bool found = false;
-    for (ClassHierarchyNode other in b.directSubclasses) {
+    for (ClassHierarchyNode other in node2.directSubclasses) {
       if (areElementsEquivalent(child.cls, other.cls)) {
-        checkClassHierarchyNodes(child, other,
-            verbose: verbose);
+        checkClassHierarchyNodes(compiler1, compiler2,
+            child, other, verbose: verbose);
         found = true;
         break;
       }
     }
     if (!found) {
-      Expect.isFalse(
-          child.isInstantiated, 'Missing subclass ${child.cls} of ${a.cls}');
+      Expect.isFalse(child.isInstantiated,
+          'Missing subclass ${child.cls} of ${node1.cls}');
     }
   }
+  checkMixinUses(compiler1, compiler2, node1.cls, node2.cls, verbose: verbose);
 }
 
 void checkSets(
     Iterable set1,
     Iterable set2,
     String messagePrefix,
-    bool areEquivalent(a, b),
+    bool sameElement(a, b),
     {bool failOnUnfound: true,
-     bool verbose: false}) {
+     bool verbose: false,
+     void onSameElement(a, b)}) {
   List common = [];
   List unfound = [];
   Set remaining = computeSetDifference(
-      set1, set2, common, unfound, areEquivalent);
+      set1, set2, common, unfound,
+      sameElement: sameElement,
+      checkElements: onSameElement);
   StringBuffer sb = new StringBuffer();
   sb.write("$messagePrefix:");
   if (verbose) {
@@ -190,3 +265,136 @@
     print(message);
   }
 }
+
+String defaultToString(obj) => '$obj';
+
+void checkMaps(
+    Map map1,
+    Map map2,
+    String messagePrefix,
+    bool sameKey(a, b),
+    bool sameValue(a, b),
+    {bool failOnUnfound: true,
+     bool failOnMismatch: true,
+     bool verbose: false,
+     String keyToString(key): defaultToString,
+     String valueToString(key): defaultToString}) {
+  List common = [];
+  List unfound = [];
+  List<List> mismatch = <List>[];
+  Set remaining = computeSetDifference(
+      map1.keys, map2.keys, common, unfound,
+      sameElement: sameKey,
+      checkElements: (k1, k2) {
+        var v1 = map1[k1];
+        var v2 = map2[k2];
+        if (!sameValue(v1, v2)) {
+          mismatch.add([k1, k2]);
+        }
+      });
+  StringBuffer sb = new StringBuffer();
+  sb.write("$messagePrefix:");
+  if (verbose) {
+    sb.write("\n Common: \n");
+    for (List pair in common) {
+      var k1 = pair[0];
+      var k2 = pair[1];
+      var v1 = map1[k1];
+      var v2 = map2[k2];
+      sb.write(" key1   =${keyToString(k1)}\n");
+      sb.write(" key2   =${keyToString(k2)}\n");
+      sb.write("  value1=${valueToString(v1)}\n");
+      sb.write("  value2=${valueToString(v2)}\n");
+    }
+  }
+  if (unfound.isNotEmpty || verbose) {
+    sb.write("\n Unfound: \n");
+    for (var k1 in unfound) {
+      var v1 = map1[k1];
+      sb.write(" key1   =${keyToString(k1)}\n");
+      sb.write("  value1=${valueToString(v1)}\n");
+    }
+  }
+  if (remaining.isNotEmpty || verbose) {
+    sb.write("\n Extra: \n");
+    for (var k2 in remaining) {
+      var v2 = map2[k2];
+      sb.write(" key2   =${keyToString(k2)}\n");
+      sb.write("  value2=${valueToString(v2)}\n");
+    }
+  }
+  if (mismatch.isNotEmpty || verbose) {
+    sb.write("\n Mismatch: \n");
+    for (List pair in mismatch) {
+      var k1 = pair[0];
+      var k2 = pair[1];
+      var v1 = map1[k1];
+      var v2 = map2[k2];
+      sb.write(" key1   =${keyToString(k1)}\n");
+      sb.write(" key2   =${keyToString(k2)}\n");
+      sb.write("  value1=${valueToString(v1)}\n");
+      sb.write("  value2=${valueToString(v2)}\n");
+    }
+  }
+  String message = sb.toString();
+  if (unfound.isNotEmpty || mismatch.isNotEmpty || remaining.isNotEmpty) {
+    if ((unfound.isNotEmpty && failOnUnfound) ||
+        (mismatch.isNotEmpty && failOnMismatch) ||
+        remaining.isNotEmpty) {
+      Expect.fail(message);
+    } else {
+      print(message);
+    }
+  } else if (verbose) {
+    print(message);
+  }
+}
+
+bool areLocalsEquivalent(Local a, Local b) {
+  if (a == b) return true;
+  if (a == null || b == null) return false;
+
+  if (a is Element) {
+    return b is Element && areElementsEquivalent(a as Element, b as Element);
+  } else {
+    return a.runtimeType == b.runtimeType &&
+        areElementsEquivalent(a.executableContext, b.executableContext);
+  }
+}
+
+bool areCapturedVariablesEquivalent(CapturedVariable a, CapturedVariable b) {
+  if (a == b) return true;
+  if (a == null || b == null) return false;
+  if (a is ClosureFieldElement && b is ClosureFieldElement) {
+    return areElementsEquivalent(a.closureClass, b.closureClass) &&
+      areLocalsEquivalent(a.local, b.local);
+  } else if (a is BoxFieldElement && b is BoxFieldElement) {
+    return areElementsEquivalent(a.variableElement, b.variableElement) &&
+        areLocalsEquivalent(a.box, b.box);
+  }
+  return false;
+}
+
+bool areClosureScopesEquivalent(ClosureScope a, ClosureScope b) {
+  if (a == b) return true;
+  if (a == null || b == null) return false;
+  if (!areLocalsEquivalent(a.boxElement, b.boxElement)) {
+    return false;
+  }
+  checkMaps(a.capturedVariables, b.capturedVariables,
+      'ClosureScope.capturedVariables',
+      areLocalsEquivalent,
+      areElementsEquivalent);
+  checkSets(a.boxedLoopVariables, b.boxedLoopVariables,
+      'ClosureScope.boxedLoopVariables',
+      areElementsEquivalent);
+  return true;
+}
+
+String nodeToString(Node node) {
+  String text = '$node';
+  if (text.length > 40) {
+    return '(${node.runtimeType}) ${text.substring(0, 37)}...';
+  }
+  return '(${node.runtimeType}) $text';
+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/serialization/resolved_ast_test.dart b/tests/compiler/dart2js/serialization/resolved_ast_test.dart
index 0ca8672..b9bae80 100644
--- a/tests/compiler/dart2js/serialization/resolved_ast_test.dart
+++ b/tests/compiler/dart2js/serialization/resolved_ast_test.dart
@@ -6,10 +6,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/common/backend_api.dart';
-import 'package:compiler/src/common/names.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/elements.dart';
 import 'package:compiler/src/filenames.dart';
@@ -23,8 +20,7 @@
 main(List<String> args) {
   Arguments arguments = new Arguments.from(args);
   asyncTest(() async {
-    String serializedData = await serializeDartCore(
-        arguments: arguments, serializeResolvedAst: true);
+    String serializedData = await serializeDartCore(arguments: arguments);
     if (arguments.filename != null) {
       Uri entryPoint = Uri.base.resolve(nativeToUriPath(arguments.filename));
       await check(serializedData, entryPoint);
@@ -53,8 +49,7 @@
       memorySourceFiles: sourceFiles,
       options: [Flags.analyzeAll]);
   compilerDeserialized.resolution.retainCachesForTesting = true;
-  deserialize(
-      compilerDeserialized, serializedData, deserializeResolvedAst: true);
+  compilerDeserialized.serialization.deserializeFromText(serializedData);
   await compilerDeserialized.run(entryPoint);
 
   checkAllResolvedAsts(compilerNormal, compilerDeserialized, verbose: true);
@@ -80,9 +75,11 @@
 void checkResolvedAsts(Compiler compiler1, Element member1,
                        Compiler compiler2, Element member2,
                        {bool verbose: false}) {
+  if (!compiler2.serialization.isDeserialized(member2)) {
+    return;
+  }
   ResolvedAst resolvedAst1 = compiler1.resolution.getResolvedAst(member1);
-  ResolvedAst resolvedAst2 =
-      compiler2.serialization.deserializer.getResolvedAst(member2);
+  ResolvedAst resolvedAst2 = compiler2.serialization.getResolvedAst(member2);
 
   if (resolvedAst1 == null || resolvedAst2 == null) return;
 
diff --git a/tests/compiler/dart2js/serialization/test_data.dart b/tests/compiler/dart2js/serialization/test_data.dart
index 3056735..0606a48 100644
--- a/tests/compiler/dart2js/serialization/test_data.dart
+++ b/tests/compiler/dart2js/serialization/test_data.dart
@@ -201,6 +201,22 @@
 }'''
   }),
 
+  const Test(const {
+    'main.dart': '''
+class A {
+  A();
+}
+main() => new A();
+    ''',
+  }),
+
+  const Test(const {
+    'main.dart': '''
+class C {
+  const C();
+}
+main() => const C();'''
+  }),
 ];
 
 class Test {
diff --git a/tests/compiler/dart2js/serialization/test_helper.dart b/tests/compiler/dart2js/serialization/test_helper.dart
index d753b53..496d0e3 100644
--- a/tests/compiler/dart2js/serialization/test_helper.dart
+++ b/tests/compiler/dart2js/serialization/test_helper.dart
@@ -4,23 +4,12 @@
 
 library dart2js.serialization_test_helper;
 
-import 'dart:io';
-import '../memory_compiler.dart';
-import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/common/resolution.dart';
-import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/constants/constructors.dart';
 import 'package:compiler/src/constants/expressions.dart';
 import 'package:compiler/src/dart_types.dart';
 import 'package:compiler/src/compiler.dart';
-import 'package:compiler/src/diagnostics/invariant.dart';
 import 'package:compiler/src/elements/elements.dart';
-import 'package:compiler/src/elements/visitor.dart';
-import 'package:compiler/src/ordered_typeset.dart';
-import 'package:compiler/src/serialization/element_serialization.dart';
 import 'package:compiler/src/serialization/equivalence.dart';
-import 'package:compiler/src/serialization/json_serializer.dart';
-import 'package:compiler/src/serialization/serialization.dart';
 import 'package:compiler/src/tree/nodes.dart';
 
 /// Strategy for checking equivalence.
@@ -163,7 +152,8 @@
     Iterable set2,
     List common,
     List unfound,
-    [bool sameElement(a, b) = equality]) {
+    {bool sameElement(a, b): equality,
+     void checkElements(a, b)}) {
   // TODO(johnniwinther): Avoid the quadratic cost here. Some ideas:
   // - convert each set to a list and sort it first, then compare by walking
   // both lists in parallel
@@ -175,6 +165,9 @@
     bool found = false;
     for (var element2 in remaining) {
       if (sameElement(element1, element2)) {
+        if (checkElements != null) {
+          checkElements(element1, element2);
+        }
         found = true;
         remaining.remove(element2);
         break;
@@ -199,11 +192,13 @@
     String property,
     Iterable set1,
     Iterable set2,
-    bool sameElement(a, b)) {
+    bool sameElement(a, b),
+    {void onSameElement(a, b)}) {
   List common = [];
   List unfound = [];
   Set remaining =
-      computeSetDifference(set1, set2, common, unfound, sameElement);
+      computeSetDifference(set1, set2, common, unfound,
+          sameElement: sameElement, checkElements: onSameElement);
   if (unfound.isNotEmpty || remaining.isNotEmpty) {
     String message =
         "Set mismatch for `$property` on $object1 vs $object2: \n"
diff --git a/tests/compiler/dart2js/source_map_d2js_validity_test.dart b/tests/compiler/dart2js/source_map_d2js_validity_test.dart
index 062a35a..3829144 100644
--- a/tests/compiler/dart2js/source_map_d2js_validity_test.dart
+++ b/tests/compiler/dart2js/source_map_d2js_validity_test.dart
@@ -8,7 +8,7 @@
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/dart2js.dart' as entry;
 import 'package:compiler/src/apiimpl.dart';
-import 'package:compiler/compiler.dart';
+import 'package:compiler/compiler_new.dart';
 
 import 'source_map_validator_helper.dart';
 
diff --git a/tests/compiler/dart2js/source_map_deferred_d2js_validity_test.dart b/tests/compiler/dart2js/source_map_deferred_d2js_validity_test.dart
index 36a4878..0afe96e 100644
--- a/tests/compiler/dart2js/source_map_deferred_d2js_validity_test.dart
+++ b/tests/compiler/dart2js/source_map_deferred_d2js_validity_test.dart
@@ -8,7 +8,7 @@
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/dart2js.dart' as entry;
 import 'package:compiler/src/apiimpl.dart';
-import 'package:compiler/compiler.dart';
+import 'package:compiler/compiler_new.dart';
 
 import 'source_map_validator_helper.dart';
 
diff --git a/tests/corelib/apply5_test.dart b/tests/corelib/apply5_test.dart
new file mode 100644
index 0000000..5435f10
--- /dev/null
+++ b/tests/corelib/apply5_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, 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";
+
+// Testing that, when compiled to JS, Function.apply works correctly for
+// functions with that will be invoked directly vs using .apply().
+
+class A {
+  foo([a = 10, b = 20, c = 30, d = 40, e = 50]) => "$a $b $c $d $e";
+}
+
+main() {
+  var a = new A();
+  var clos = a.foo;
+  Expect.equals(Function.apply(clos, []), "10 20 30 40 50");
+  Expect.equals(Function.apply(clos, [11]), "11 20 30 40 50");
+  Expect.equals(Function.apply(clos, [11, 21]), "11 21 30 40 50");
+  Expect.equals(Function.apply(clos, [11, 21, 31]), "11 21 31 40 50");
+  Expect.equals(Function.apply(clos, [11, 21, 31, 41]), "11 21 31 41 50");
+  Expect.equals(Function.apply(clos, [11, 21, 31, 41, 51]), "11 21 31 41 51");
+}
diff --git a/tests/corelib/iterable_generate_test.dart b/tests/corelib/iterable_generate_test.dart
index 851f14d..170dba9 100644
--- a/tests/corelib/iterable_generate_test.dart
+++ b/tests/corelib/iterable_generate_test.dart
@@ -42,4 +42,32 @@
   if (checkedMode) {
     Expect.throws(() => new Iterable<String>.generate(5));
   }
+
+  // Omitted generator function means `(int x) => x`, and the type parameters
+  // must then be compatible with `int`.
+  // Check that we catch invalid type parameters.
+
+  // Valid types:
+  Iterable<int> iter1 = new Iterable<int>.generate(5);
+  Expect.equals(2, iter1.elementAt(2));
+  Iterable<num> iter2 = new Iterable<num>.generate(5);
+  Expect.equals(2, iter2.elementAt(2));
+  Iterable<Object> iter3 = new Iterable<Object>.generate(5);
+  Expect.equals(2, iter3.elementAt(2));
+  Iterable<dynamic> iter4 = new Iterable<dynamic>.generate(5);
+  Expect.equals(2, iter4.elementAt(2));
+
+  // Invalid types:
+  Expect.throws(() => new Iterable<String>.generate(5));
+  Expect.throws(() => new Iterable<Null>.generate(5));
+  Expect.throws(() => new Iterable<bool>.generate(5));
+
+  // Regression: https://github.com/dart-lang/sdk/issues/26358
+  var count = 0;
+  var iter = new Iterable.generate(5, (v) { count++; return v; });
+  Expect.equals(0, count);
+  Expect.equals(2, iter.elementAt(2));  // Doesn't compute the earlier values.
+  Expect.equals(1, count);
+  Expect.equals(2, iter.skip(2).first);  // Doesn't compute the skipped values.
+  Expect.equals(2, count);
 }
diff --git a/tests/corelib/set_test.dart b/tests/corelib/set_test.dart
index 20a136a..55e7250 100644
--- a/tests/corelib/set_test.dart
+++ b/tests/corelib/set_test.dart
@@ -523,5 +523,5 @@
   testASetFrom((x) => new Set<A>.from(x));
   testASetFrom((x) => new HashSet<A>.from(x));
   testASetFrom((x) => new LinkedHashSet<A>.from(x));
-  testASetFrom((x) => new SplayTreeSet<A>.from(x));
+  testASetFrom((x) => new SplayTreeSet<A>.from(x, identityCompare));
 }
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 157f638..59748da 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -4,9 +4,9 @@
 
 [ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
 browser/*: SkipByDesign  # Browser specific tests
-isolate_stress_test: Fail # Issue 12588: This should be able to pass when we have wrapper-less tests.
+isolate_stress_test: Skip # Issue 12588: Uses dart:html. This should be able to pass when we have wrapper-less tests.
 
-[ $runtime != vm ]
+[ $runtime != vm || $mode == product ]
 checked_test: Skip # Unsupported.
 
 [ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $arch == mips && $mode == debug ]
@@ -176,10 +176,11 @@
 spawn_uri_vm_test: Skip # Isolate.spawnUri
 issue_21398_parent_isolate_test: Skip # Isolate.spawnUri
 error_at_spawnuri_test: Skip # Isolate.spawnUri
+spawn_uri_missing_from_isolate_test: Skip # Isolate.spawnUri
+spawn_uri_missing_test: Skip # Isolate.spawnUri
 
-[ $runtime == dart_product ]
-spawn_uri_missing_from_isolate_test: Skip # SpawnUri in product mode
-spawn_uri_missing_test: Skip # SpawnUri in product mode
+[ $mode == product ]
+issue_24243_parent_isolate_test: Skip # Requires checked mode
 
 [ $compiler == dart2js && $cps_ir && $checked ]
 *: Skip # `assert` not implemented
diff --git a/tests/language/generic_functions_test.dart b/tests/language/generic_functions_test.dart
index e3f6caf..c9628a6 100644
--- a/tests/language/generic_functions_test.dart
+++ b/tests/language/generic_functions_test.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2016, 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.
+//
+// DartOptions=--generic-method-syntax
 
 /// Dart test verifying that the parser can handle type parameterization of
 /// function declarations and function invocations. Variant of code from
diff --git a/tests/language/generic_local_functions_test.dart b/tests/language/generic_local_functions_test.dart
index 6a350d4..21bd7a7 100644
--- a/tests/language/generic_local_functions_test.dart
+++ b/tests/language/generic_local_functions_test.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2016, 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.
+//
+// DartOptions=--generic-method-syntax
 
 /// Dart test verifying that the parser can handle type parameterization of
 /// local function declarations, and declarations of function parameters.
diff --git a/tests/language/generic_methods_test.dart b/tests/language/generic_methods_test.dart
index 9151fc3..fba394a 100644
--- a/tests/language/generic_methods_test.dart
+++ b/tests/language/generic_methods_test.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2016, 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.
+//
+// DartOptions=--generic-method-syntax
 
 /// Dart test verifying that the parser can handle type parameterization of
 /// method declarations and method invocations. Slightly adjusted version of
diff --git a/tests/language/generic_sends_test.dart b/tests/language/generic_sends_test.dart
index 57befee..332439c7 100644
--- a/tests/language/generic_sends_test.dart
+++ b/tests/language/generic_sends_test.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2016, 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.
+//
+// DartOptions=--generic-method-syntax
 
 /// Dart test verifying that the parser can handle certain cases where
 /// grammar ambiguity is resolved in favor of generic sends, not
diff --git a/tests/language/language.status b/tests/language/language.status
index 5eacbfa..4b75506 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -49,7 +49,6 @@
 generic_functions_test: CompiletimeError # Issue 25869
 generic_local_functions_test: CompiletimeError # Issue 25869
 generic_sends_test: CompiletimeError # Issue 25869
-generic_method_type_usage_test: CompiletimeError # Tests --generic-method-syntax, plus issue 25869
 
 [ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
 
@@ -58,7 +57,7 @@
 vm/debug_break_enabled_vm_test/01: Crash, OK # Expected to hit breakpoint.
 try_catch_optimized1_test: Skip # Srdjan investigating
 
-[ ($compiler == none || $compiler == precompiler) && $checked ]
+[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && $checked ]
 type_variable_bounds4_test/01: Fail # Issue 14006
 
 [ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && (($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) || $runtime == drt || $runtime == dartium) ]
@@ -95,7 +94,6 @@
 generic_functions_test: RuntimeError # Issue 25869
 generic_local_functions_test: RuntimeError # Issue 25869
 generic_sends_test: RuntimeError # Issue 25869
-generic_method_type_usage_test: CompiletimeError # Tests --generic-method-syntax, plus issue 25869
 config_import_test: Skip  # Issue 26250
 
 [ $compiler == none && $runtime == dartium && $system == linux && $arch != x64 ]
@@ -158,17 +156,30 @@
 super_getter_setter_test: SkipByDesign
 vm/reflect_core_vm_test: SkipByDesign
 
-[ ($noopt || $compiler == precompiler || $compiler == dart2app) ]
+[ $noopt || $compiler == precompiler || $compiler == dart2app || $mode == product ]
 # Deferred loading happens eagerly
 regress_23408_test: Skip
 deferred_inheritance_constraints_test: Skip
 deferred_global_test: Skip
 deferred_load_constants_test: Skip
 tearoff_basic_test: Skip
+deferred_static_seperate_test: Skip
+deferred_constraints_type_annotation_test/new_before_load: Skip
+regress_22443_test: Skip
 
+[ $compiler == precompiler || $compiler == dart2app ]
+ct_const2_test: Skip # Incompatible flag: --compile_all
+hello_dart_test: Skip # Incompatible flag: --compile_all
+
+[ $compiler == precompiler ]
+implicit_closure_test: Skip # Incompatible flag: --use_slow_path
+deopt_inlined_function_lazy_test: Skip # Incompatible flag: --deoptimize-alot
+
+[ $noopt || $compiler == precompiler || $compiler == dart2app ]
 vm/type_vm_test: RuntimeError # Expects line and column numbers
-vm/type_cast_vm_test: RuntimeError # Line number mismatch.
+vm/type_cast_vm_test: RuntimeError # Expects line and column numbers
 
+[ $mode == product ]
 issue13474_test: SkipByDesign # Requires checked mode.
 assertion_test: SkipByDesign # Requires checked mode.
 named_parameters_type_test/01: SkipByDesign # Requires checked mode.
@@ -181,21 +192,9 @@
 generic_test: SkipByDesign # Requires checked mode.
 map_literal4_test: SkipByDesign # Requires checked mode.
 
-[ $runtime == dart_precompiled ]
-ct_const2_test: Skip # Incompatible flag: --compile_all
-hello_dart_test: Skip # Incompatible flag: --compile_all
-implicit_closure_test: Skip # Incompatible flag: --use_slow_path
-deopt_inlined_function_lazy_test: Skip # Incompatible flag: --deoptimize-alot
-
-[ $runtime == dart_product ]
-# Deferred loading happens eagerly (not sure why this works on precompiled code).
-deferred_static_seperate_test: Skip
-deferred_constraints_type_annotation_test/new_before_load: Skip
-regress_22443_test: Skip
-
-[ $runtime == vm && $mode == product ]
 vm/type_vm_test: Fail,OK  # Expects exact type name.
 
+
 [ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && $browser ]
 # The following tests are supposed to fail.
 library_env_test/has_io_support: RuntimeError, OK
@@ -206,7 +205,7 @@
 library_env_test/has_html_support: RuntimeError, OK
 library_env_test/has_no_io_support: RuntimeError, OK
 
-[ $compiler == none && $noopt == false && $mode != product ]
+[ ($compiler == none || $compiler == dart2app) && $noopt == false && $mode != product ]
 # The following tests are supposed to fail.
 library_env_test/has_no_mirror_support: RuntimeError, OK
 
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index 9cc27c9..2035434 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -506,4 +506,3 @@
 generic_local_functions_test: CompileTimeError # Issue 25868
 generic_methods_test: CompileTimeError # Issue 25868
 generic_sends_test: CompileTimeError # Issue 25868
-generic_method_type_usage_test: CompiletimeError # Tests --generic-method-syntax, plus issue 25868
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 025d91a..25902c1 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -35,13 +35,6 @@
 accessor_conflict_import_prefixed_test: RuntimeError # Issue 25626
 accessor_conflict_import_test: RuntimeError # Issue 25626
 
-# Experimental feature: Syntactic support for generic methods.
-generic_functions_test: CompileTimeError # Issue 25835
-generic_local_functions_test: CompileTimeError # Issue 25835
-generic_methods_test: CompileTimeError # Issue 25835
-generic_sends_test: CompileTimeError # Issue 25835
-generic_method_type_usage_test: CompiletimeError # Tests --generic-method-syntax, plus issue 25835
-
 [ $compiler == dart2js && $runtime == jsshell ]
 await_for_test: Skip # Jsshell does not provide periodic timers, Issue 7728
 async_star_test: RuntimeError # Jsshell does not provide non-zero timers, Issue 7728
@@ -52,6 +45,12 @@
 [ $compiler == dart2js && $browser ]
 config_import_test: Fail # Test flag is not passed to the compiler.
 
+# Experimental feature: Syntactic support for generic methods.
+generic_functions_test: CompileTimeError # DartOptions not passed to compiler.
+generic_local_functions_test: CompileTimeError # DartOptions not passed to compiler.
+generic_methods_test: CompileTimeError # DartOptions not passed to compiler.
+generic_sends_test: CompileTimeError # DartOptions not passed to compiler.
+
 [ $compiler == dart2js ]
 invocation_mirror_empty_arguments_test: Fail # Issue 24331
 nan_identical_test: Fail # Issue 11551
@@ -133,6 +132,9 @@
 malbounded_type_test_test/04: Fail # Issue 14121
 malbounded_type_test2_test: Fail # Issue 14121
 default_factory2_test/01: Fail # Issue 14121
+generic_functions_test: Crash # Issue 26436
+generic_local_functions_test: Crash # Issue 26436
+generic_methods_test: Crash # Issue 26436
 
 [ $compiler == dart2js && $unchecked ]
 type_checks_in_factory_method_test: RuntimeError # Issue 12746
diff --git a/tests/lib/async/future_test.dart b/tests/lib/async/future_test.dart
index e8387bf..52185f2 100644
--- a/tests/lib/async/future_test.dart
+++ b/tests/lib/async/future_test.dart
@@ -994,6 +994,29 @@
   cs[0].completeError("BAD");
 }
 
+void testFutureResult() {
+  asyncStart();
+  () async {
+    var f = new UglyFuture(5);
+    // Sanity check that our future is as mis-behaved as we think.
+    f.then((v) { Expect.isTrue(v is Future); });
+
+    var v = await f;
+    // The static type of await is Flatten(static-type-of-expression), so it
+    // suggests that it flattens. In practice it currently doesn't.
+    // The specification doesn't say anything special, so v should be the
+    // completion value of the UglyFuture future which is a future.
+    Expect.isTrue(v is Future);
+
+    // This used to hit an assert in checked mode.
+    // The CL adding this test changed the behavior to actually flatten the
+    // the future returned by the then-callback.
+    var w = new Future.value(42).then((_) => f);
+    Expect.equals(42, await w);
+    asyncEnd();
+  }();
+}
+
 main() {
   asyncStart();
 
@@ -1062,10 +1085,12 @@
   testAnyIgnoreIncomplete();
   testAnyIgnoreError();
 
+  testFutureResult();
+
   asyncEnd();
 }
 
-/// A Future that isn't recognizable as a _Future.
+/// A well-behaved Future that isn't recognizable as a _Future.
 class CustomFuture<T> implements Future<T> {
   Future _realFuture;
   CustomFuture(this._realFuture);
@@ -1081,6 +1106,7 @@
   int get hashCode => _realFuture.hashCode;
 }
 
+/// A bad future that throws on every method.
 class BadFuture<T> implements Future<T> {
   Future then(action(T result), {Function onError}) {
     throw "then GOTCHA!";
@@ -1098,3 +1124,25 @@
     throw "timeout GOTCHA!";
   }
 }
+
+// An evil future that completes with another future.
+class UglyFuture implements Future<dynamic> {
+  final _result;
+  UglyFuture(int badness) :
+      _result = (badness == 0) ? 42 : new UglyFuture(badness - 1);
+  Future then(action(value), {onError(error, StackTrace stack)}) {
+    var c = new Completer();
+    c.complete(new Future.microtask(() => action(_result)));
+    return c.future;
+  }
+  Future catchError(onError, {test}) => this;  // Never an error.
+  Future whenComplete(action()) {
+    return new Future.microtask(action).then((_) => this);
+  }
+  Stream asStream() {
+    return (new StreamController()..add(_result)..close()).stream;
+  }
+  Future timeout(Duration duration, {onTimeout()}) {
+    return this;
+  }
+}
diff --git a/tests/lib/convert/chunked_conversion1_test.dart b/tests/lib/convert/chunked_conversion1_test.dart
index 3c84b3e..0bbe44b 100644
--- a/tests/lib/convert/chunked_conversion1_test.dart
+++ b/tests/lib/convert/chunked_conversion1_test.dart
@@ -54,8 +54,7 @@
   specialB(o) => add(o);
 }
 
-class IntBoolConverter1 extends
-    ChunkedConverter<List<int>, List<bool>, int, bool> {
+class IntBoolConverter1 extends Converter<List<int>, List<bool>> {
   List<bool> convert(List<int> input) => input.map((x) => x > 0).toList();
 
   startChunkedConversion(sink) {
@@ -64,8 +63,7 @@
   }
 }
 
-class BoolIntConverter1 extends
-    ChunkedConverter<List<bool>, List<int>, bool, int> {
+class BoolIntConverter1 extends Converter<List<bool>, List<int>> {
   List<int> convert(List<bool> input) => input.map((x) => x ? 1 : 0).toList();
 
   startChunkedConversion(sink) {
@@ -106,7 +104,7 @@
   close() => outSink.close();
 }
 
-class IdentityConverter extends ChunkedConverter {
+class IdentityConverter extends Converter {
   convert(x) => x;
 
   startChunkedConversion(sink) {
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index ec94cf6..d6abe8f 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -314,6 +314,9 @@
 developer/metrics_num_test: Skip # Because of a int / double type test.
 developer/timeline_test: Skip # Not supported
 
+[ $mode == product ]
+developer/timeline_test: Skip # Not supported
+
 [ $arch == simarm64 ]
 convert/utf85_test: Skip # Pass, Slow Issue 20111.
 
diff --git a/tests/standalone/io/https_bad_certificate_test.dart b/tests/standalone/io/https_bad_certificate_test.dart
index 7dc5aa2..cafacfb 100644
--- a/tests/standalone/io/https_bad_certificate_test.dart
+++ b/tests/standalone/io/https_bad_certificate_test.dart
@@ -71,7 +71,8 @@
   } catch (error) {
     Expect.notEquals(result, 'pass');
     if (result == 'fail') {
-      Expect.isTrue(error is HandshakeException);
+      Expect.isTrue(error is HandshakeException ||
+          (callbackReturns is! bool && error is TypeError));
     } else if (result == 'throw') {
       Expect.isTrue(error is CustomException);
     } else {
diff --git a/tests/standalone/io/skipping_dart2js_compilations_test.dart b/tests/standalone/io/skipping_dart2js_compilations_test.dart
index 0c907ba..27d896f 100644
--- a/tests/standalone/io/skipping_dart2js_compilations_test.dart
+++ b/tests/standalone/io/skipping_dart2js_compilations_test.dart
@@ -7,7 +7,7 @@
  * already up to date" feature does work as it should.
  * Therefore this test ensures that compilations are only skipped if the last
  * modified date of the output of a dart2js compilation is newer than
- *   - the the dart application to compile (including it's dependencies)
+ *   - the dart application to compile (including it's dependencies)
  *   - the dart2js snapshot
  * Furtheremore it ensure that a compilations is not skipped if any of the
  * necessary files could not be found (dart2js snapshots, previous dart2js
diff --git a/tests/standalone/io/stdin_sync_test.dart b/tests/standalone/io/stdin_sync_test.dart
index 97c4b58..470f34b 100644
--- a/tests/standalone/io/stdin_sync_test.dart
+++ b/tests/standalone/io/stdin_sync_test.dart
@@ -12,7 +12,7 @@
   void test(String line, List<String> expected) {
     var script = Platform.script.resolve("stdin_sync_script.dart").toFilePath();
     Process.start(Platform.executable,
-                  ["--checked", script]..addAll(
+                  [script]..addAll(
                       expected.map(JSON.encode))).then((process) {
       process.stdin.write(line);
       process.stdin.close();
diff --git a/tests/standalone/io/stdio_nonblocking_test.dart b/tests/standalone/io/stdio_nonblocking_test.dart
index 05f5fde..69220e9 100644
--- a/tests/standalone/io/stdio_nonblocking_test.dart
+++ b/tests/standalone/io/stdio_nonblocking_test.dart
@@ -11,7 +11,7 @@
   var script =
       Platform.script.resolve("stdio_nonblocking_script.dart").toFilePath();
   Process.run(Platform.executable,
-              ['--checked', script],
+              [script],
               stdoutEncoding: ASCII,
               stderrEncoding: ASCII).then((result) {
                   print(result.stdout);
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 30a1101..b163964 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -115,6 +115,7 @@
 [ ($runtime == vm || $runtime == dart_product) && ($arch == arm || $arch == arm64) ]
 io/file_stream_test: Skip # Issue 26109
 io/file_typed_data_test: Skip # Issue 26109
+io/file_input_stream_test: Skip # Issue 26109
 
 [ $compiler == dart2js && $jscl ]
 assert_test: RuntimeError, OK # Assumes unspecified fields on the AssertionError.
@@ -216,14 +217,13 @@
 full_coverage_test: Skip # Platform.executable
 regress_26031_test: Skip # Platform.resolvedExecutable
 
-[ $runtime == dart_precompiled ]
-io/compile_all_test: Crash # Incompatible flag --compile_all
+[ $compiler == precompiler || $compiler == dart2app ]
+io/compile_all_test: Skip # Incompatible flag --compile_all
 
 [ $runtime == dart_product ]
 io/stdout_bad_argument_test: Skip # Test exits and so can't generate snapshot.
 
 [ $runtime == dart_precompiled || $runtime == dart_product ]
-debugger/*: Skip
 full_coverage_test: Skip # Platform.executable
 http_launch_test: Skip # Platform.executable
 io/addlatexhash_test: Skip # Platform.executable
@@ -253,14 +253,17 @@
 io/file_lock_test: Skip # Platform.executable
 io/code_collection_test: Skip # Platform.executable
 io/file_lock_test: Skip # Platform.executable
-io/code_collection_test: Skip # Platform.executable
 io/raw_socket_cross_process_test: Skip # Platform.executable
 io/test_extension_test: Skip # Platform.executable
 io/named_pipe_script_test: Skip # Platform.executable
 io/regress_7679_test: Skip # Platform.executable
 io/process_*: Skip # Most use Platform.executable
+
+[ $runtime == dart_precompiled || $runtime == dart_product || $mode == product ]
+debugger/*: Skip
 assert_test: SkipByDesign # Requires checked mode.
 no_assert_test: SkipByDesign # Requires checked mode.
+io/code_collection_test: Skip # Incompatible flags
 
 # Code coverage is not supported in product mode.
 [ $mode == product ]
diff --git a/tests/try/web/test_case.dart b/tests/try/web/test_case.dart
index 5cb3846..56e1157 100644
--- a/tests/try/web/test_case.dart
+++ b/tests/try/web/test_case.dart
@@ -33,7 +33,7 @@
  *   3. Repeat step 2 until there are no more tests.
  *
  * The purpose of this test is to simulate edits (during setup), and then let
- * the the mutation observer to process the mutations followed by validation.
+ * the mutation observer to process the mutations followed by validation.
  */
 void runTests(List<TestCase> tests) {
   Completer completer = new Completer();
diff --git a/tools/VERSION b/tools/VERSION
index ea11638..16386c7 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 1
 MINOR 17
 PATCH 0
-PRERELEASE 3
+PRERELEASE 4
 PRERELEASE_PATCH 0
diff --git a/tools/dom/dom.json b/tools/dom/dom.json
index 3437c02..6514306 100644
--- a/tools/dom/dom.json
+++ b/tools/dom/dom.json
@@ -433,10 +433,34 @@
       "PLAYING_STATE": {},
       "SCHEDULED_STATE": {},
       "UNSCHEDULED_STATE": {},
+      "addEventListener": {
+        "support_level": "untriaged"
+      },
       "buffer": {},
+      "channelCount": {
+        "support_level": "untriaged"
+      },
+      "channelCountMode": {
+        "support_level": "untriaged"
+      },
+      "channelInterpretation": {
+        "support_level": "untriaged"
+      },
+      "connect": {
+        "support_level": "untriaged"
+      },
+      "context": {
+        "support_level": "untriaged"
+      },
       "detune": {
         "support_level": "untriaged"
       },
+      "disconnect": {
+        "support_level": "untriaged"
+      },
+      "dispatchEvent": {
+        "support_level": "untriaged"
+      },
       "gain": {},
       "loop": {},
       "loopEnd": {},
@@ -444,11 +468,20 @@
       "noteGrainOn": {},
       "noteOff": {},
       "noteOn": {},
+      "numberOfInputs": {
+        "support_level": "untriaged"
+      },
+      "numberOfOutputs": {
+        "support_level": "untriaged"
+      },
       "onended": {
         "support_level": "untriaged"
       },
       "playbackRate": {},
       "playbackState": {},
+      "removeEventListener": {
+        "support_level": "untriaged"
+      },
       "start": {},
       "stop": {}
     },
@@ -1589,6 +1622,9 @@
       "MIN_RADIUS": {
         "support_level": "untriaged"
       },
+      "id": {
+        "support_level": "untriaged"
+      },
       "latitude": {
         "support_level": "untriaged"
       },
@@ -1858,6 +1894,12 @@
       "timeStamp": {
         "support_level": "experimental"
       },
+      "timeline": {
+        "support_level": "untriaged"
+      },
+      "timelineEnd": {
+        "support_level": "untriaged"
+      },
       "trace": {},
       "warn": {}
     },
@@ -2873,10 +2915,43 @@
   "DirectoryEntry": {
     "comment": "http://www.w3.org/TR/file-system-api/#the-directoryentry-interface",
     "members": {
+      "copyTo": {
+        "support_level": "untriaged"
+      },
       "createReader": {},
+      "filesystem": {
+        "support_level": "untriaged"
+      },
+      "fullPath": {
+        "support_level": "untriaged"
+      },
       "getDirectory": {},
       "getFile": {},
-      "removeRecursively": {}
+      "getMetadata": {
+        "support_level": "untriaged"
+      },
+      "getParent": {
+        "support_level": "untriaged"
+      },
+      "isDirectory": {
+        "support_level": "untriaged"
+      },
+      "isFile": {
+        "support_level": "untriaged"
+      },
+      "moveTo": {
+        "support_level": "untriaged"
+      },
+      "name": {
+        "support_level": "untriaged"
+      },
+      "remove": {
+        "support_level": "untriaged"
+      },
+      "removeRecursively": {},
+      "toURL": {
+        "support_level": "untriaged"
+      }
     },
     "support_level": "experimental"
   },
@@ -4312,8 +4387,41 @@
   "FileEntry": {
     "comment": "http://www.w3.org/TR/file-system-api/#the-fileentry-interface",
     "members": {
+      "copyTo": {
+        "support_level": "untriaged"
+      },
       "createWriter": {},
-      "file": {}
+      "file": {},
+      "filesystem": {
+        "support_level": "untriaged"
+      },
+      "fullPath": {
+        "support_level": "untriaged"
+      },
+      "getMetadata": {
+        "support_level": "untriaged"
+      },
+      "getParent": {
+        "support_level": "untriaged"
+      },
+      "isDirectory": {
+        "support_level": "untriaged"
+      },
+      "isFile": {
+        "support_level": "untriaged"
+      },
+      "moveTo": {
+        "support_level": "untriaged"
+      },
+      "name": {
+        "support_level": "untriaged"
+      },
+      "remove": {
+        "support_level": "untriaged"
+      },
+      "toURL": {
+        "support_level": "untriaged"
+      }
     },
     "support_level": "experimental"
   },
@@ -8054,8 +8162,41 @@
   "MediaElementAudioSourceNode": {
     "comment": "https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#MediaElementAudioSourceNode",
     "members": {
+      "addEventListener": {
+        "support_level": "untriaged"
+      },
+      "channelCount": {
+        "support_level": "untriaged"
+      },
+      "channelCountMode": {
+        "support_level": "untriaged"
+      },
+      "channelInterpretation": {
+        "support_level": "untriaged"
+      },
+      "connect": {
+        "support_level": "untriaged"
+      },
+      "context": {
+        "support_level": "untriaged"
+      },
+      "disconnect": {
+        "support_level": "untriaged"
+      },
+      "dispatchEvent": {
+        "support_level": "untriaged"
+      },
       "mediaElement": {
         "support_level": "nonstandard"
+      },
+      "numberOfInputs": {
+        "support_level": "untriaged"
+      },
+      "numberOfOutputs": {
+        "support_level": "untriaged"
+      },
+      "removeEventListener": {
+        "support_level": "untriaged"
       }
     },
     "support_level": "experimental"
@@ -8346,7 +8487,40 @@
   "MediaStreamAudioSourceNode": {
     "comment": "https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#MediaStreamAudioSourceNode",
     "members": {
-      "mediaStream": {}
+      "addEventListener": {
+        "support_level": "untriaged"
+      },
+      "channelCount": {
+        "support_level": "untriaged"
+      },
+      "channelCountMode": {
+        "support_level": "untriaged"
+      },
+      "channelInterpretation": {
+        "support_level": "untriaged"
+      },
+      "connect": {
+        "support_level": "untriaged"
+      },
+      "context": {
+        "support_level": "untriaged"
+      },
+      "disconnect": {
+        "support_level": "untriaged"
+      },
+      "dispatchEvent": {
+        "support_level": "untriaged"
+      },
+      "mediaStream": {},
+      "numberOfInputs": {
+        "support_level": "untriaged"
+      },
+      "numberOfOutputs": {
+        "support_level": "untriaged"
+      },
+      "removeEventListener": {
+        "support_level": "untriaged"
+      }
     },
     "support_level": "experimental"
   },
@@ -9215,8 +9389,101 @@
     "comment": "https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#OfflineAudioContext-section",
     "members": {
       "OfflineAudioContext": {},
+      "addEventListener": {
+        "support_level": "untriaged"
+      },
+      "close": {
+        "support_level": "untriaged"
+      },
+      "createAnalyser": {
+        "support_level": "untriaged"
+      },
+      "createBiquadFilter": {
+        "support_level": "untriaged"
+      },
+      "createBuffer": {
+        "support_level": "untriaged"
+      },
+      "createBufferSource": {
+        "support_level": "untriaged"
+      },
+      "createChannelMerger": {
+        "support_level": "untriaged"
+      },
+      "createChannelSplitter": {
+        "support_level": "untriaged"
+      },
+      "createConvolver": {
+        "support_level": "untriaged"
+      },
+      "createDelay": {
+        "support_level": "untriaged"
+      },
+      "createDynamicsCompressor": {
+        "support_level": "untriaged"
+      },
+      "createGain": {
+        "support_level": "untriaged"
+      },
+      "createMediaElementSource": {
+        "support_level": "untriaged"
+      },
+      "createMediaStreamDestination": {
+        "support_level": "untriaged"
+      },
+      "createMediaStreamSource": {
+        "support_level": "untriaged"
+      },
+      "createOscillator": {
+        "support_level": "untriaged"
+      },
+      "createPanner": {
+        "support_level": "untriaged"
+      },
+      "createPeriodicWave": {
+        "support_level": "untriaged"
+      },
+      "createScriptProcessor": {
+        "support_level": "untriaged"
+      },
+      "createStereoPanner": {
+        "support_level": "untriaged"
+      },
+      "createWaveShaper": {
+        "support_level": "untriaged"
+      },
+      "currentTime": {
+        "support_level": "untriaged"
+      },
+      "decodeAudioData": {
+        "support_level": "untriaged"
+      },
+      "destination": {
+        "support_level": "untriaged"
+      },
+      "dispatchEvent": {
+        "support_level": "untriaged"
+      },
+      "listener": {
+        "support_level": "untriaged"
+      },
+      "removeEventListener": {
+        "support_level": "untriaged"
+      },
+      "resume": {
+        "support_level": "untriaged"
+      },
+      "sampleRate": {
+        "support_level": "untriaged"
+      },
       "startRendering": {
         "support_level": "untriaged"
+      },
+      "state": {
+        "support_level": "untriaged"
+      },
+      "suspend": {
+        "support_level": "untriaged"
       }
     },
     "support_level": "experimental"
@@ -9253,14 +9520,47 @@
         "support_level": "deprecated"
       },
       "UNSCHEDULED_STATE": {},
+      "addEventListener": {
+        "support_level": "untriaged"
+      },
+      "channelCount": {
+        "support_level": "untriaged"
+      },
+      "channelCountMode": {
+        "support_level": "untriaged"
+      },
+      "channelInterpretation": {
+        "support_level": "untriaged"
+      },
+      "connect": {
+        "support_level": "untriaged"
+      },
+      "context": {
+        "support_level": "untriaged"
+      },
       "detune": {},
+      "disconnect": {
+        "support_level": "untriaged"
+      },
+      "dispatchEvent": {
+        "support_level": "untriaged"
+      },
       "frequency": {},
       "noteOff": {},
       "noteOn": {},
+      "numberOfInputs": {
+        "support_level": "untriaged"
+      },
+      "numberOfOutputs": {
+        "support_level": "untriaged"
+      },
       "onended": {
         "support_level": "untriaged"
       },
       "playbackState": {},
+      "removeEventListener": {
+        "support_level": "untriaged"
+      },
       "setPeriodicWave": {
         "support_level": "untriaged"
       },
@@ -10438,6 +10738,15 @@
   "Request": {
     "members": {
       "Request": {},
+      "arrayBuffer": {
+        "support_level": "untriaged"
+      },
+      "blob": {
+        "support_level": "untriaged"
+      },
+      "bodyUsed": {
+        "support_level": "untriaged"
+      },
       "clone": {
         "support_level": "untriaged"
       },
@@ -10450,6 +10759,9 @@
       "headers": {
         "support_level": "untriaged"
       },
+      "json": {
+        "support_level": "untriaged"
+      },
       "mode": {
         "support_level": "untriaged"
       },
@@ -10459,6 +10771,9 @@
       "referrer": {
         "support_level": "untriaged"
       },
+      "text": {
+        "support_level": "untriaged"
+      },
       "url": {
         "support_level": "untriaged"
       }
@@ -20356,7 +20671,77 @@
     "support_level": "stable"
   },
   "WorkerConsole": {
-    "members": {},
+    "members": {
+      "assert": {
+        "support_level": "untriaged"
+      },
+      "clear": {
+        "support_level": "untriaged"
+      },
+      "count": {
+        "support_level": "untriaged"
+      },
+      "debug": {
+        "support_level": "untriaged"
+      },
+      "dir": {
+        "support_level": "untriaged"
+      },
+      "dirxml": {
+        "support_level": "untriaged"
+      },
+      "error": {
+        "support_level": "untriaged"
+      },
+      "group": {
+        "support_level": "untriaged"
+      },
+      "groupCollapsed": {
+        "support_level": "untriaged"
+      },
+      "groupEnd": {
+        "support_level": "untriaged"
+      },
+      "info": {
+        "support_level": "untriaged"
+      },
+      "log": {
+        "support_level": "untriaged"
+      },
+      "markTimeline": {
+        "support_level": "untriaged"
+      },
+      "profile": {
+        "support_level": "untriaged"
+      },
+      "profileEnd": {
+        "support_level": "untriaged"
+      },
+      "table": {
+        "support_level": "untriaged"
+      },
+      "time": {
+        "support_level": "untriaged"
+      },
+      "timeEnd": {
+        "support_level": "untriaged"
+      },
+      "timeStamp": {
+        "support_level": "untriaged"
+      },
+      "timeline": {
+        "support_level": "untriaged"
+      },
+      "timelineEnd": {
+        "support_level": "untriaged"
+      },
+      "trace": {
+        "support_level": "untriaged"
+      },
+      "warn": {
+        "support_level": "untriaged"
+      }
+    },
     "support_level": "untriaged"
   },
   "WorkerContext": {
diff --git a/tools/dom/scripts/database.py b/tools/dom/scripts/database.py
index 7329b22..e5f1e6c 100755
--- a/tools/dom/scripts/database.py
+++ b/tools/dom/scripts/database.py
@@ -333,7 +333,7 @@
     result = []
     if interface.parents:
       parent = interface.parents[0]
-      if (IsPureInterface(parent.type.id) or
+      if (IsPureInterface(parent.type.id, self) or
           (propagate_event_target and parent.type.id == 'EventTarget')):
         result = walk(interface.parents, [])
       else:
diff --git a/tools/dom/scripts/databasebuilder.py b/tools/dom/scripts/databasebuilder.py
index b0977ad..95dcd42 100755
--- a/tools/dom/scripts/databasebuilder.py
+++ b/tools/dom/scripts/databasebuilder.py
@@ -301,7 +301,7 @@
         continue
       if sig in res:
         op = res[sig]
-        # Only report if the the operations that match are either both suppressed
+        # Only report if the operations that match are either both suppressed
         # or both not suppressed.  Optional args aren't part of type signature
         # for this routine. Suppressing a non-optional type and supplementing
         # with an optional type appear the same.
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index 90f8b34..125d64a 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -14,50 +14,152 @@
 from htmlrenamer import custom_html_constructors, html_interface_renames, \
     typed_array_renames
 
-_pure_interfaces = monitored.Set('generator._pure_interfaces', [
-    # TODO(sra): DOMStringMap should be a class implementing Map<String,String>.
-    'DOMStringMap',
-    'AbstractWorker',
-    'CanvasPathMethods',
-    'ChildNode',
-    'DocumentAnimation',
-    'DocumentFontFaceSet',
-    'DocumentFullscreen',
-    'DocumentXPathEvaluator',
-    'ElementAnimation',
-    'ElementFullscreen',
-    'EventListener',
-    'GlobalEventHandlers',
-    'ImageBitmapFactories',
-    'MediaQueryListListener',
-    'MouseEventHitRegion',
-    'MutationCallback',
-    'NavigatorCPU',
-    'NavigatorEvents',
-    'NavigatorID',
-    'NavigatorLanguage',
-    'NavigatorOnLine',
-    'ParentNode',
-    'SVGDocument',
-    'SVGExternalResourcesRequired',
-    'SVGFilterPrimitiveStandardAttributes',
-    'SVGFitToViewBox',
-    'SVGTests',
-    'SVGURIReference',
-    'SVGZoomAndPan',
-    'TimeoutHandler',
-    'URLUtils',
-    'URLUtilsReadOnly',
-    'WebGLRenderingContextBase',
-    'WindowBase64',
-    'WindowEventHandlers',
-    'WindowImageBitmapFactories',
-    'WindowPagePopup',
-    'WindowTimers',
+_safe_interfaces = monitored.Set('generator._safe_interfaces', [
+    'double',
+    'Float32Array',
+    'Float64Array',
+    'Int8Array',
+    'Int16Array',
+    'Int32Array',
+    'Uint8Array',
+    'Uint8ClampedArray',
+    'Uint16Array',
+    'Uint32Array',
+    'ArrayBufferView',
+    'ArrayBuffer',
+    'SourceBuffer', # IDL lies about this class being a pure interface.
+    'Console', # this one is a bit of a hack as our console implementation
+              # in dart:html is non-standard for legacy reasons.
+    'AudioContext',
+    'AudioSourceNode',
+    'WebGLVertexArrayObjectOES', # Added a polyfill for this.
+    # Types where we can get access to the prototype easily enough.
+    # We might consider in the future treating these are regular interface types.
+    'StereoPannerNode',
+    'PannerNode',
+    'AudioNode',
+    'FontFaceSet',
+    'MemoryInfo',
+    'ConsoleBase',
+    'Geolocation',
+    'Animation',
+    'SourceBufferList',
+    'GamepadList',
+
+    # The following classes are enabled just to get the build to go.
+    # SpeechRecognitionResultList isn't really allowed but the codegen creates
+    # invalid output otherwise.
+
+    'SpeechRecognitionResultList',
+    'SQLResultSetRowList',
     ])
 
-def IsPureInterface(interface_name):
-  return interface_name in _pure_interfaces
+# These are interfaces that we have to treat as safe for dart2js and dartium
+# but going in dev compiler we should not treat as safe as these classes
+# really aren't guaranteed to have a stable interface name.
+_safe_interfaces_legacy = monitored.Set('generator._safe_interfaces_legacy', [
+    'ANGLEInstancedArrays',
+    'Bluetooth',
+    'Body',
+    'NonDocumentTypeChildNode',
+    'CHROMIUMSubscribeUniform',
+    'CHROMIUMValuebuffer',
+    'GeofencingRegion',
+    'Coordinates',
+    'DOMFileSystem',
+    'DirectoryEntry',
+    'DOMFileSystemSync',
+    'Entry',
+    'Database',
+    'DeprecatedStorageInfo',
+    'DeprecatedStorageQuota',
+    'DeviceAcceleration',
+    'DeviceRotationRate',
+    'DirectoryReader',
+    'EntrySync',
+    'DirectoryEntrySync',
+    'DirectoryReaderSync',
+    'NonElementParentNode',
+    'EXTBlendMinMax',
+    'EXTFragDepth',
+    'EXTShaderTextureLOD',
+    'EXTTextureFilterAnisotropic',
+    'EXTsRGB',
+    'EffectModel',
+    'FileEntry',
+    'FileEntrySync',
+    'FileWriter',
+    'FileWriterSync',
+    'FontFaceSetLoadEvent',
+    'Geofencing',
+    'Geoposition',
+    'Iterator',
+    'MediaDeviceInfo',
+    'MediaStreamTrackEvent',
+    'Metadata',
+    'NavigatorStorageUtils',
+    'StorageQuota',
+    'NavigatorUserMediaError',
+    'OESElementIndexUint',
+    'OESStandardDerivatives',
+    'OESTextureFloat',
+    'OESTextureFloatLinear',
+    'OESTextureHalfFloat',
+    'OESTextureHalfFloatLinear',
+    'OESVertexArrayObject',
+    'PagePopupController',
+    'PluginPlaceholderElement',
+    'PositionError',
+    'RTCDTMFSender',
+    'RTCDataChannel',
+    'RTCDataChannelEvent',
+    'RTCIceCandidateEvent',
+    'RTCStatsReport',
+    'RTCStatsResponse',
+    'ReadableByteStreamReader',
+    'ReadableStreamReader',
+    'ResourceProgressEvent',
+    'SQLError',
+    'SQLResultSet',
+    'SQLTransaction',
+    'SharedArrayBuffer',
+    'SourceInfo',
+    'SpeechRecognitionAlternative',
+    'SpeechRecognitionResult',
+    'SpeechSynthesis',
+    'SpeechSynthesisVoice',
+    'StorageInfo',
+    'StyleMedia',
+    'WebGL2RenderingContextBase',
+    'WebGLCompressedTextureATC',
+    'WebGLCompressedTextureETC1',
+    'WebGLCompressedTexturePVRTC',
+    'WebGLCompressedTextureS3TC',
+    'WebGLDebugRendererInfo',
+    'WebGLDebugShaders',
+    'WebGLDepthTexture',
+    'WebGLDrawBuffers',
+    'WebGLLoseContext',
+    'WorkerConsole',
+    'WorkerPerformance',
+    'XPathNSResolver',
+])
+
+# Classes we should just suppress?
+# SpeechGrammarList and friends
+
+def IsPureInterface(interface_name, database):
+  if (interface_name in _safe_interfaces or
+      interface_name in _safe_interfaces_legacy or
+      database.HasInterface(interface_name)):
+    return False
+
+  interface = database.GetInterface(interface_name)
+
+  if 'Constructor' in interface.ext_attrs:
+    return False
+
+  return interface.is_no_interface_object
 
 #
 # Classes which have native constructors but which we are suppressing because
@@ -163,7 +265,7 @@
 
     'PannerNode': 'PannerNode,AudioPannerNode,webkitAudioPannerNode',
 
-    'RTCPeerConnection': 'RTCPeerConnection,mozRTCPeerConnection',
+    'RTCPeerConnection': 'RTCPeerConnection,webkitRTCPeerConnection,mozRTCPeerConnection',
 
     'RTCIceCandidate': 'RTCIceCandidate,mozRTCIceCandidate',
 
@@ -929,7 +1031,7 @@
     # dart_type.
     if self._data.dart_type != None:
       return self.dart_type()
-    if IsPureInterface(self.idl_type()):
+    if IsPureInterface(self.idl_type(), self._type_registry._database):
       return self.idl_type()
     return self.interface_name()
 
diff --git a/tools/dom/scripts/htmldartgenerator.py b/tools/dom/scripts/htmldartgenerator.py
index c66ce5b..8397b8f 100644
--- a/tools/dom/scripts/htmldartgenerator.py
+++ b/tools/dom/scripts/htmldartgenerator.py
@@ -177,7 +177,7 @@
 
     # Never remove operations that are added as a result of an implements they
     # are pure interfaces (mixins to this interface).
-    if (IsPureInterface(parent_name)):
+    if (IsPureInterface(parent_name, self._database)):
       return
 
     for operation in parent.operations:
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index 8b9311b..856da50 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -141,6 +141,8 @@
   'WorkerLocation', # Workers
   'WorkerNavigator', # Workers
   'XMLHttpRequestProgressEvent',
+  # Obsolete event for NaCl.
+  'ResourceProgressEvent',
 ]
 
 for interface in _removed_html_interfaces:
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index 75e38fd..2208f22 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -554,7 +554,7 @@
     base_type_info = None
     if self._interface.parents:
       supertype = self._interface.parents[0].type.id
-      if not IsDartCollectionType(supertype) and not IsPureInterface(supertype):
+      if not IsDartCollectionType(supertype) and not IsPureInterface(supertype, self._database):
         base_type_info = self._type_registry.TypeInfo(supertype)
 
     if base_type_info:
@@ -594,7 +594,7 @@
 
     class_modifiers = ''
     if (self._renamer.ShouldSuppressInterface(self._interface) or
-      IsPureInterface(self._interface.id)):
+      IsPureInterface(self._interface.id, self._database)):
       # XMLHttpRequestProgressEvent can't be abstract we need to instantiate
       # for JsInterop.
       if (not(isinstance(self._backend, Dart2JSBackend)) and
@@ -614,7 +614,7 @@
           class_modifiers = 'abstract '
 
     native_spec = ''
-    if not IsPureInterface(self._interface.id):
+    if not IsPureInterface(self._interface.id, self._database):
       native_spec = self._backend.NativeSpec()
 
     class_name = self._interface_type_info.implementation_name()
@@ -689,7 +689,7 @@
     if (implementation_members_emitter and
         self._options.templates._conditions['DARTIUM'] and
         self._options.dart_js_interop and
-        not IsPureInterface(self._interface.id)):
+        not IsPureInterface(self._interface.id, self._database)):
       implementation_members_emitter.Emit(js_interop_wrapper)
 
     if isElement and self._interface.id != 'Element':
@@ -760,7 +760,9 @@
   def AdditionalImplementedInterfaces(self):
     implements = super(Dart2JSBackend, self).AdditionalImplementedInterfaces()
     if self._interface_type_info.list_item_type() and self.HasIndexedGetter():
-      implements.append('JavaScriptIndexingBehavior')
+      item_type = self._type_registry.TypeInfo(
+          self._interface_type_info.list_item_type()).dart_type()
+      implements.append('JavaScriptIndexingBehavior<%s>' % item_type)
     return implements
 
   def NativeSpec(self):
@@ -898,7 +900,7 @@
     if self._HasCustomImplementation(attribute.id):
       return
 
-    if IsPureInterface(self._interface.id):
+    if IsPureInterface(self._interface.id, self._database):
       self._AddInterfaceAttribute(attribute, html_name, read_only)
       return
 
@@ -1068,7 +1070,7 @@
     if self._HasCustomImplementation(info.name):
       return
 
-    if IsPureInterface(self._interface.id):
+    if IsPureInterface(self._interface.id, self._database):
       self._AddInterfaceOperation(info, html_name)
     elif info.callback_args:
       self._AddFutureifiedOperation(info, html_name)
@@ -1202,6 +1204,7 @@
         idl_type, self._interface.id, idl_member_name):
       return_type = self.SecureOutputType(idl_type)
       native_type = self._NarrowToImplementationType(idl_type)
+
       if native_type != return_type:
         anns = anns + [
           "@Returns('%s')" % native_type,
@@ -1227,7 +1230,7 @@
         parent = interface.parents[0]
         if IsDartCollectionType(parent.type.id):
           return (None, None)
-        if IsPureInterface(parent.type.id):
+        if IsPureInterface(parent.type.id, self._database):
           return (None, None)
         if self._database.HasInterface(parent.type.id):
           interfaces_to_search_in = []
diff --git a/tools/dom/scripts/systemnative.py b/tools/dom/scripts/systemnative.py
index 1f5a030..f6284ab 100644
--- a/tools/dom/scripts/systemnative.py
+++ b/tools/dom/scripts/systemnative.py
@@ -193,7 +193,7 @@
 
   def StartInterface(self, members_emitter):
     # Create emitters for c++ implementation.
-    if not IsPureInterface(self._interface.id) and \
+    if not IsPureInterface(self._interface.id, self._database) and \
         not IsCustomType(self._interface.id):
       self._cpp_header_emitter = self._cpp_library_emitter.CreateHeaderEmitter(
         self._interface.id,
@@ -951,7 +951,7 @@
         full_dart_name = \
             self.DeriveQualifiedBlinkName(self._interface.id,
                                           dart_native_name)
-        if IsPureInterface(self._interface.id):
+        if IsPureInterface(self._interface.id, self._database):
             caller_emitter.Emit(
                 '\n'
                 '  $METADATA$DART_DECLARATION;\n',
diff --git a/tools/dom/src/EventStreamProvider.dart b/tools/dom/src/EventStreamProvider.dart
index 76bed57..474a143 100644
--- a/tools/dom/src/EventStreamProvider.dart
+++ b/tools/dom/src/EventStreamProvider.dart
@@ -76,7 +76,7 @@
    * [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventListener)
    */
   ElementStream<T> _forElementList(ElementList e, {bool useCapture: false}) {
-    return new _ElementListEventStreamImpl(e, _eventType, useCapture);
+    return new _ElementListEventStreamImpl<T>(e, _eventType, useCapture);
   }
 
   /**
@@ -294,9 +294,9 @@
     }
   }
 
-  Future asFuture([var futureValue]) {
+  Future/*<E>*/ asFuture/*<E>*/([var/*=E*/ futureValue]) {
     // We just need a future that will never succeed or fail.
-    Completer completer = new Completer();
+    var completer = new Completer/*<E>*/();
     return completer.future;
   }
 }
diff --git a/tools/dom/src/WrappedList.dart b/tools/dom/src/WrappedList.dart
index c06e8dc..2e28c5c 100644
--- a/tools/dom/src/WrappedList.dart
+++ b/tools/dom/src/WrappedList.dart
@@ -16,7 +16,7 @@
 
   // Iterable APIs
 
-  Iterator<E> get iterator => new _WrappedIterator(_list.iterator);
+  Iterator<E> get iterator => new _WrappedIterator<E>(_list.iterator);
 
   int get length => _list.length;
 
diff --git a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
index ead9d63..a2bd1e8 100644
--- a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
@@ -132,12 +132,6 @@
   HtmlElement.created() : super.created();
 }
 
-// EntryArray type was removed, so explicitly adding it to allow support for
-// older Chrome versions.
-// Issue #12573.
-@Native("EntryArray")
-abstract class _EntryArray implements List<Entry> {}
-
 /**
  * Spawn a DOM isolate using the given URI in the same window.
  * This isolate is not concurrent.  It runs on the browser thread
diff --git a/tools/dom/templates/html/impl/impl_Window.darttemplate b/tools/dom/templates/html/impl/impl_Window.darttemplate
index c9f8279..8abac37 100644
--- a/tools/dom/templates/html/impl/impl_Window.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Window.darttemplate
@@ -339,8 +339,10 @@
   const _BeforeUnloadEventStreamProvider(this._eventType);
 
   Stream<BeforeUnloadEvent> forTarget(EventTarget e, {bool useCapture: false}) {
-    var stream = new _EventStream(e, _eventType, useCapture);
 $if DART2JS
+    // Specify the generic type for EventStream only in dart2js to avoid
+    // checked mode errors in dartium.
+    var stream = new _EventStream<BeforeUnloadEvent>(e, _eventType, useCapture);
     var controller = new StreamController<BeforeUnloadEvent>(sync: true);
 
     stream.listen((event) {
@@ -350,6 +352,7 @@
 
     return controller.stream;
 $else
+    var stream = new _EventStream(e, _eventType, useCapture);
     return stream;
 $endif
   }
@@ -359,11 +362,23 @@
   }
 
   ElementStream<BeforeUnloadEvent> forElement(Element e, {bool useCapture: false}) {
+$if DART2JS
+    // Specify the generic type for _ElementEventStreamImpl only in dart2js to
+    // avoid checked mode errors in dartium.
+    return new _ElementEventStreamImpl<BeforeUnloadEvent>(e, _eventType, useCapture);
+$else
     return new _ElementEventStreamImpl(e, _eventType, useCapture);
+$endif
   }
 
   ElementStream<BeforeUnloadEvent> _forElementList(ElementList e,
       {bool useCapture: false}) {
+$if DART2JS
+    // Specify the generic type for _ElementEventStreamImpl only in dart2js to
+    // avoid checked mode errors in dartium.
+    return new _ElementListEventStreamImpl<BeforeUnloadEvent>(e, _eventType, useCapture);
+$else
     return new _ElementListEventStreamImpl(e, _eventType, useCapture);
+$endif
   }
 }
diff --git a/tools/get_archive.py b/tools/get_archive.py
index 409d147..7517f54 100755
--- a/tools/get_archive.py
+++ b/tools/get_archive.py
@@ -132,7 +132,7 @@
         result, out = Gsutil('ls', permanent_prefix % {'osname' : osname,
             'num1': the_revision_num, 'num2': '*', 'bot': bot })
         if result == 0:
-          # First try to find one with the the second number the same as the
+          # First try to find one with the second number the same as the
           # requested number.
           latest = out.split()[0]
           # Now test that the permissions are correct so you can actually
diff --git a/tools/testing/dart/runtime_configuration.dart b/tools/testing/dart/runtime_configuration.dart
index 67a739a..822700f 100644
--- a/tools/testing/dart/runtime_configuration.dart
+++ b/tools/testing/dart/runtime_configuration.dart
@@ -299,6 +299,7 @@
     return <Command>[
       commandBuilder.getAdbPrecompiledCommand(precompiledRunner,
                                               script,
+                                              arguments,
                                               useBlobs)
     ];
   }
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index d862db5..e9fed49 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -348,10 +348,12 @@
 class AdbPrecompilationCommand extends Command {
   final String precompiledRunnerFilename;
   final String precompiledTestDirectory;
+  final List<String> arguments;
   final bool useBlobs;
 
   AdbPrecompilationCommand._(this.precompiledRunnerFilename,
                              this.precompiledTestDirectory,
+                             this.arguments,
                              this.useBlobs)
       : super._("adb_precompilation");
 
@@ -359,6 +361,7 @@
     super._buildHashCode(builder);
     builder.add(precompiledRunnerFilename);
     builder.add(precompiledTestDirectory);
+    builder.add(arguments);
     builder.add(useBlobs);
   }
 
@@ -366,6 +369,7 @@
       super._equal(other) &&
       precompiledRunnerFilename == other.precompiledRunnerFilename &&
       useBlobs == other.useBlobs &&
+      arguments == other.arguments &&
       precompiledTestDirectory == other.precompiledTestDirectory;
 
   String toString() => 'Steps to push precompiled runner and precompiled code '
@@ -640,9 +644,10 @@
 
   AdbPrecompilationCommand getAdbPrecompiledCommand(String precompiledRunner,
                                                     String testDirectory,
+                                                    List<String> arguments,
                                                     bool useBlobs) {
     var command = new AdbPrecompilationCommand._(
-        precompiledRunner, testDirectory, useBlobs);
+        precompiledRunner, testDirectory, arguments, useBlobs);
     return _getUniqueCommand(command);
   }
 
@@ -2415,7 +2420,7 @@
 
 /*
  * [CommandExecutor] is responsible for executing commands. It will make sure
- * that the the following two constraints are satisfied
+ * that the following two constraints are satisfied
  *  - [:numberOfProcessesUsed <= maxProcesses:]
  *  - [:numberOfBrowserProcessesUsed <= maxBrowserProcesses:]
  *
@@ -2518,6 +2523,7 @@
       AdbDevice device, AdbPrecompilationCommand command, int timeout) async {
     var runner = command.precompiledRunnerFilename;
     var testdir = command.precompiledTestDirectory;
+    var arguments = command.arguments;
     var devicedir = '/data/local/tmp/precompilation-testing';
     var deviceTestDir = '/data/local/tmp/precompilation-testing/test';
 
@@ -2556,13 +2562,13 @@
       steps.add(() => device.runAdbShellCommand(
             ['$devicedir/dart_precompiled_runtime',
              '--run-app-snapshot=$deviceTestDir',
-             '--use-blobs', 'ignored.dart'],
+             '--use-blobs']..addAll(arguments),
             timeout: timeoutDuration));
     } else {
       steps.add(() => device.runAdbShellCommand(
             ['$devicedir/dart_precompiled_runtime',
-             '--run-app-snapshot=$deviceTestDir',
-             'ignored.dart'],
+             '--run-app-snapshot=$deviceTestDir'
+             ]..addAll(arguments),
             timeout: timeoutDuration));
     }
 
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index 58b0937..ca8b8c8 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -1610,7 +1610,7 @@
    *     // OtherScripts=file1.dart file2.dart
    *
    *   - You can indicate whether a test is treated as a web-only test by
-   *   using an explicit import to a part of the the dart:html library:
+   *   using an explicit import to a part of the dart:html library:
    *
    *     import 'dart:html';
    *     import 'dart:web_audio';
diff --git a/utils/peg/pegparser.dart b/utils/peg/pegparser.dart
index 8666550..9c58dea 100644
--- a/utils/peg/pegparser.dart
+++ b/utils/peg/pegparser.dart
@@ -371,7 +371,7 @@
         }
       }
     }
-    // Delegate the matching logic to the the specialized function.
+    // Delegate the matching logic to the specialized function.
     return _match(state, pos);
   }