Version 1.14.0-dev.2.0

Merge commit '79a8654e5fb30dfce902636961d6a5ffb69e6f85' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5f6d954..087ba19 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@
   * `Base64Decoder.convert` now takes optional `start` and `end` parameters.
 
 * `dart:core`
+  * Added `current` getter to `StackTrace` class.
   * Added `Uri.data` getter for `data:` URIs, and `UriData` class for the
     return type.
   * Added `growable` parameter to `List.filled` constructor.
@@ -18,6 +19,33 @@
   * `Platform` added an `isiOS` getter and `Platform.operatingSystem` may now
     return `ios`.
 
+### Tool changes
+
+* Pub
+
+  * **Breaking:** Pub now eagerly emits an error when a pubspec's "name" field
+    is not a valid Dart identifier. Since packages with non-identifier names
+    were never allowed to be published, and some of them already caused crashes
+    when being written to a `.packages` file, this is unlikely to break many
+    people in practice.
+
+  * `pub serve` now GZIPs the assets it serves to make load times more similar
+    to real-world use-cases.
+
+  * `pub deps` now supports a `--no-dev` flag, which causes it to emit the
+    dependency tree as it would be if no `dev_dependencies` were in use. This
+    makes it easier to see your package's dependency footprint as your users
+    will experience it.
+
+  * `pub global run` now detects when a global executable's SDK constraint is no
+    longer met and errors out, rather than trying to run the executable anyway.
+
+  * Fixed a crashing bug when using `pub global run` on a global script that
+    didn't exist.
+
+  * Fixed a crashing bug when a pubspec contains a dependency without a source
+    declared.
+
 ## 1.13.0 - 2015-11-18
 
 ### Core library changes
diff --git a/DEPS b/DEPS
index a98a3b5..0ca12c9 100644
--- a/DEPS
+++ b/DEPS
@@ -38,7 +38,6 @@
 
   # Revisions of /third_party/* dependencies.
   "7zip_rev" : "@19997",
-  "analyzer_cli_rev" : "@c93a3d2d1c7715a6c7a067ebdbc9ba716b865226",
   "args_tag": "@0.13.0",
   "async_tag": "@1.2.0",
   "barback_tag" : "@0.15.2+7",
@@ -51,7 +50,7 @@
   "crypto_rev" : "@2df57a1e26dd88e8d0614207d4b062c73209917d",
   "csslib_tag" : "@0.12.0",
   "dart2js_info_rev" : "@0a221eaf16aec3879c45719de656680ccb80d8a1",
-  "dartdoc_rev" : "@18f85ff0b389c417550e541055a84b04273f2b38",
+  "dartdoc_tag" : "@v0.8.3",
   "dart_services_rev" : "@7aea2574e6f3924bf409a80afb8ad52aa2be4f97",
   "dart_style_tag": "@0.2.0",
   "dev_compiler_rev": "@0.1.9",
@@ -68,14 +67,14 @@
   "intl_rev": "@32047558bd220a53c1f4d93a26d54b83533b1475",
   "jinja2_rev": "@2222b31554f03e62600cd7e383376a7c187967a1",
   "json_rpc_2_tag": "@1.1.1",
-  "linter_rev": "@74e5478c3693a9dcf05cc99b0dc5d53f0f776375",
+  "linter_rev": "@e5281475126efdc556c3eba6a8b6683fd814b033",
   "logging_rev": "@85d83e002670545e9039ad3985f0018ab640e597",
   "markdown_rev": "@4aaadf3d940bb172e1f6285af4d2b1710d309982",
   "matcher_tag": "@0.12.0",
   "metatest_rev": "@e5aa8e4e19fc4188ac2f6d38368a47d8f07c3df1",
   "mime_rev": "@75890811d4af5af080351ba8a2853ad4c8df98dd",
   "mustache4dart_rev" : "@5724cfd85151e5b6b53ddcd3380daf188fe47f92",
-  "oauth2_rev": "@1bff41f4d54505c36f2d1a001b83b8b745c452f5",
+  "oauth2_tag": "@1.0.0",
   "observe_rev": "@eee2b8ec34236fa46982575fbccff84f61202ac6",
   "observatory_pub_packages_rev": "@5c199c5954146747f75ed127871207718dc87786",
   "package_config_rev": "@0.1.3",
@@ -84,7 +83,7 @@
   "ply_rev": "@604b32590ffad5cbb82e4afef1d305512d06ae93",
   "plugin_tag": "@0.1.0",
   "pool_rev": "@e454b4b54d2987e8d2f0fbd3ac519641ada9bd0f",
-  "pub_rev": "@1c08b841158e33b8090bb07e5c39df830db58d44",
+  "pub_rev": "@8c091bf6332e8b392fdac63ae297426fb65ed925",
   "pub_cache_tag": "@v0.1.0",
   "pub_semver_tag": "@1.2.1",
   "quiver_tag": "@0.21.4",
@@ -172,8 +171,6 @@
       (Var("github_mirror") % "dart-services") +
       Var("dart_services_rev"),
 
-  Var("dart_root") + "/third_party/pkg/analyzer_cli":
-      (Var("github_mirror") % "analyzer_cli") + Var("analyzer_cli_rev"),
   Var("dart_root") + "/third_party/pkg/args":
       (Var("github_mirror") % "args") + Var("args_tag"),
   Var("dart_root") + "/third_party/pkg/async":
@@ -195,7 +192,7 @@
   Var("dart_root") + "/third_party/pkg/dart2js_info":
       (Var("github_mirror") % "dart2js_info") + Var("dart2js_info_rev"),
   Var("dart_root") + "/third_party/pkg/dartdoc":
-      (Var("github_mirror") % "dartdoc") + Var("dartdoc_rev"),
+      (Var("github_mirror") % "dartdoc") + Var("dartdoc_tag"),
   Var("dart_root") + "/third_party/pkg/dev_compiler":
       (Var("github_mirror") % "dev_compiler") + Var("dev_compiler_rev"),
   Var("dart_root") + "/third_party/pkg/glob":
@@ -233,7 +230,7 @@
       + "/external/github.com/valotas/mustache4dart.git"
       + Var("mustache4dart_rev"),
   Var("dart_root") + "/third_party/pkg/oauth2":
-      (Var("github_mirror") % "oauth2") + Var("oauth2_rev"),
+      (Var("github_mirror") % "oauth2") + Var("oauth2_tag"),
   Var("dart_root") + "/third_party/pkg/observe":
       (Var("github_mirror") % "observe") + Var("observe_rev"),
   Var("dart_root") + "/third_party/observatory_pub_packages":
diff --git a/dart.gyp b/dart.gyp
index 81a8f05..3e73877 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -25,6 +25,7 @@
       'type': 'none',
       'dependencies': [
         'runtime/dart-runtime.gyp:dart',
+        'runtime/dart-runtime.gyp:dart_precompiled',
         'runtime/dart-runtime.gyp:dart_no_snapshot',
         'runtime/dart-runtime.gyp:run_vm_tests',
         'runtime/dart-runtime.gyp:process_test',
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index eb5f9a9..68947be 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -61,7 +61,7 @@
 </style></head>
   <body>
     <h1>Analysis Server API Specification</h1>
-    <h1 style="color:#999999">Version 1.12.0</h1>
+    <h1 style="color:#999999">Version 1.13.0</h1>
     <p>
       This document contains a specification of the API provided by the
       analysis server.  The API in this document is currently under
@@ -405,6 +405,7 @@
       
       
       
+      
      
       
       
@@ -515,6 +516,46 @@
               in multiple contexts in conflicting ways (such as a
               part that is included in multiple libraries).
             </p>
+          </dd></dl></dd><dt class="request"><a name="request_analysis.getReachableSources">analysis.getReachableSources</a> (<a href="#request_analysis.getReachableSources">#</a>)</dt><dd><div class="box"><pre>request: {
+  "id": String
+  "method": "analysis.getReachableSources"
+  "params": {
+    "<b>file</b>": <a href="#type_FilePath">FilePath</a>
+  }
+}</pre><br><pre>response: {
+  "id": String
+  "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+  "result": {
+    "<b>sources</b>": Map&lt;String, List&lt;String&gt;&gt;
+  }
+}</pre></div>
+        <p>
+          Return the transitive closure of reachable sources for a given file.
+        </p>
+        <p>
+          If a request is made for a file which does not exist, or
+          which is not currently subject to analysis (e.g. because it
+          is not associated with any analysis root specified to
+          analysis.setAnalysisRoots), an error of type
+          <tt>GET_REACHABLE_SOURCES_INVALID_FILE</tt> will be generated.
+        </p>
+        
+        
+      <h4>Parameters</h4><dl><dt class="field"><b><i>file ( <a href="#type_FilePath">FilePath</a> )</i></b></dt><dd>
+            
+            <p>
+              The file for which reachable source information is being requested.
+            </p>
+          </dd></dl><h4>Returns</h4><dl><dt class="field"><b><i>sources ( Map&lt;String, List&lt;String&gt;&gt; )</i></b></dt><dd>
+            
+            <p>
+              A mapping from source URIs to directly reachable source URIs. For example,
+              a file "foo.dart" that imports "bar.dart" would have the corresponding mapping
+              { "file:///foo.dart" : ["file:///bar.dart"] }.  If "bar.dart" has further imports
+              (or exports) there will be a mapping from the URI "file:///bar.dart" to them.
+              To check if a specific URI is reachable from a given file, clients can check
+              for its presence in the resulting key set.
+            </p>
           </dd></dl></dd><dt class="request"><a name="request_analysis.getLibraryDependencies">analysis.getLibraryDependencies</a> (<a href="#request_analysis.getLibraryDependencies">#</a>)</dt><dd><div class="box"><pre>request: {
   "id": String
   "method": "analysis.getLibraryDependencies"
@@ -3576,6 +3617,13 @@
               which does not match a file currently subject to
               analysis.
             </p>
+          </dd><dt class="value">GET_REACHABLE_SOURCES_INVALID_FILE</dt><dd>
+            
+            <p>
+              An "analysis.getReachableSources" request specified a FilePath
+              which does not match a file currently subject to
+              analysis.
+            </p>
           </dd><dt class="value">INVALID_ANALYSIS_ROOT</dt><dd>
             
             <p>
@@ -4253,7 +4301,7 @@
       TBD
     </p>
     <h2 class="domain"><a name="index">Index</a></h2>
-    <h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_FileKind">FileKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
+    <h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getReachableSources">getReachableSources</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_FileKind">FileKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
   
 
 </body></html>
\ No newline at end of file
diff --git a/pkg/analysis_server/lib/plugin/edit/assist/assist_core.dart b/pkg/analysis_server/lib/plugin/edit/assist/assist_core.dart
index d4903e6..14bdcb3 100644
--- a/pkg/analysis_server/lib/plugin/edit/assist/assist_core.dart
+++ b/pkg/analysis_server/lib/plugin/edit/assist/assist_core.dart
@@ -4,6 +4,8 @@
 
 library analysis_server.plugin.edit.assist.assist_core;
 
+import 'dart:async';
+
 import 'package:analysis_server/plugin/protocol/protocol.dart'
     show SourceChange;
 import 'package:analyzer/src/generated/engine.dart';
@@ -50,19 +52,42 @@
 }
 
 /**
+ * An object used to provide context information for [AssistContributor]s.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class AssistContext {
+  /**
+   * The [AnalysisContext] to get assists in.
+   */
+  AnalysisContext get analysisContext;
+
+  /**
+   * The length of the selection.
+   */
+  int get selectionLength;
+
+  /**
+   * The start of the selection.
+   */
+  int get selectionOffset;
+
+  /**
+   * The source to get assists in.
+   */
+  Source get source;
+}
+
+/**
  * An object used to produce assists for a specific location.
  *
  * Clients may implement this class when implementing plugins.
  */
 abstract class AssistContributor {
   /**
-   * Return a list of assists for a location in the given [source]. The location
-   * is specified by the [offset] and [length] of the selected region. The
-   * [context] can be used to get additional information that is useful for
-   * computing assists.
+   * Completes with a list of assists for the given [context].
    */
-  List<Assist> computeAssists(
-      AnalysisContext context, Source source, int offset, int length);
+  Future<List<Assist>> computeAssists(AssistContext context);
 }
 
 /**
diff --git a/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart b/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart
index ccdc123..2da3812 100644
--- a/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart
+++ b/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart
@@ -4,42 +4,109 @@
 
 library analysis_server.plugin.edit.assist.assist_dart;
 
+import 'dart:async';
+
 import 'package:analysis_server/plugin/edit/assist/assist_core.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
 
 /**
- * An [AssistContributor] that can be used to contribute assists for Dart
- * files.
+ * An object used to provide context information for [DartAssistContributor]s.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class DartAssistContext {
+  /**
+   * The [AnalysisContext] to get assists in.
+   */
+  AnalysisContext get analysisContext;
+
+  /**
+   * The length of the selection.
+   */
+  int get selectionLength;
+
+  /**
+   * The start of the selection.
+   */
+  int get selectionOffset;
+
+  /**
+   * The source to get assists in.
+   */
+  Source get source;
+
+  /**
+   * The [CompilationUnit] to compute assists in.
+   */
+  CompilationUnit get unit;
+}
+
+/**
+ * An [AssistContributor] that can be used to contribute assists for Dart files.
  *
  * Clients may extend this class when implementing plugins.
  */
 abstract class DartAssistContributor implements AssistContributor {
   @override
-  List<Assist> computeAssists(
-      AnalysisContext context, Source source, int offset, int length) {
+  Future<List<Assist>> computeAssists(AssistContext context) async {
+    AnalysisContext analysisContext = context.analysisContext;
+    Source source = context.source;
     if (!AnalysisEngine.isDartFileName(source.fullName)) {
       return Assist.EMPTY_LIST;
     }
-    List<Source> libraries = context.getLibrariesContaining(source);
+    List<Source> libraries = analysisContext.getLibrariesContaining(source);
     if (libraries.isEmpty) {
       return Assist.EMPTY_LIST;
     }
     CompilationUnit unit =
-        context.resolveCompilationUnit2(source, libraries[0]);
+        analysisContext.resolveCompilationUnit2(source, libraries[0]);
     if (unit == null) {
       return Assist.EMPTY_LIST;
     }
-    return internalComputeAssists(unit, offset, length);
+    DartAssistContext dartContext = new _DartAssistContextImpl(context, unit);
+    return internalComputeAssists(dartContext);
   }
 
   /**
-   * Return a list of assists for a location in the given [source]. The location
-   * is specified by the [offset] and [length] of the selected region. The
-   * [context] can be used to get additional information that is useful for
-   * computing assists.
+   * Completes with a list of assists for the given [context].
    */
-  List<Assist> internalComputeAssists(
-      CompilationUnit unit, int offset, int length);
+  Future<List<Assist>> internalComputeAssists(DartAssistContext context);
+}
+
+/**
+ * The implementation of [DartAssistContext].
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class _DartAssistContextImpl implements DartAssistContext {
+  final AssistContext _context;
+
+  /**
+   * The [CompilationUnit] to compute assists in.
+   */
+  final CompilationUnit unit;
+
+  _DartAssistContextImpl(this._context, this.unit);
+
+  /**
+   * The [AnalysisContext] to get assists in.
+   */
+  AnalysisContext get analysisContext => _context.analysisContext;
+
+  /**
+   * The length of the selection.
+   */
+  int get selectionLength => _context.selectionLength;
+
+  /**
+   * The start of the selection.
+   */
+  int get selectionOffset => _context.selectionOffset;
+
+  /**
+   * The source to get assists in.
+   */
+  Source get source => _context.source;
 }
diff --git a/pkg/analysis_server/lib/plugin/edit/fix/fix_core.dart b/pkg/analysis_server/lib/plugin/edit/fix/fix_core.dart
index 123fa24..0ff626f 100644
--- a/pkg/analysis_server/lib/plugin/edit/fix/fix_core.dart
+++ b/pkg/analysis_server/lib/plugin/edit/fix/fix_core.dart
@@ -4,6 +4,8 @@
 
 library analysis_server.plugin.edit.fix.fix_core;
 
+import 'dart:async';
+
 import 'package:analysis_server/plugin/protocol/protocol.dart'
     show SourceChange;
 import 'package:analyzer/file_system/file_system.dart';
@@ -51,6 +53,28 @@
 }
 
 /**
+ * An object used to provide context information for [FixContributor]s.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FixContext {
+  /**
+   * The [AnalysisContext] to get fixes in.
+   */
+  AnalysisContext get analysisContext;
+
+  /**
+   * The error to fix, should be reported in the given [analysisContext].
+   */
+  AnalysisError get error;
+
+  /**
+   * The [ResourceProvider] to access files and folders.
+   */
+  ResourceProvider get resourceProvider;
+}
+
+/**
  * An object used to produce fixes for a specific error. Fix contributors are
  * long-lived objects and must not retain any state between invocations of
  * [computeFixes].
@@ -59,11 +83,9 @@
  */
 abstract class FixContributor {
   /**
-   * Return a list of fixes for the given [error]. The error was reported
-   * after it's source was analyzed in the given [context].
+   * Return a list of fixes for the given [context].
    */
-  List<Fix> computeFixes(ResourceProvider resourceProvider,
-      AnalysisContext context, AnalysisError error);
+  Future<List<Fix>> computeFixes(FixContext context);
 }
 
 /**
@@ -71,8 +93,8 @@
  * information that is common across a number of fixes and to be shared by those
  * fixes. For example, if an unnecessary cast is found then one of the suggested
  * fixes will be to remove the cast. If there are multiple unnecessary casts in
- * a single file, then there will be multiple fixes, one per occurance, but they
- * will all share the same kind.
+ * a single file, then there will be multiple fixes, one per occurrence, but
+ * they will all share the same kind.
  *
  * Clients may not extend, implement or mix-in this class.
  */
diff --git a/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart b/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
index 54baa7c..e8f7104 100644
--- a/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
+++ b/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
@@ -4,14 +4,28 @@
 
 library analysis_server.plugin.edit.fix.fix_dart;
 
+import 'dart:async';
+
 import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
-import 'package:analyzer/file_system/file_system.dart';
+import 'package:analysis_server/src/services/correction/fix_internal.dart'
+    show DartFixContextImpl;
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/source.dart';
 
 /**
+ * An object used to provide context information for [DartFixContributor]s.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class DartFixContext implements FixContext {
+  /**
+   * The [CompilationUnit] to compute fixes in.
+   */
+  CompilationUnit get unit;
+}
+
+/**
  * A [FixContributor] that can be used to contribute fixes for errors in Dart
  * files.
  *
@@ -19,28 +33,27 @@
  */
 abstract class DartFixContributor implements FixContributor {
   @override
-  List<Fix> computeFixes(ResourceProvider resourceProvider,
-      AnalysisContext context, AnalysisError error) {
-    Source source = error.source;
+  Future<List<Fix>> computeFixes(FixContext context) async {
+    AnalysisContext analysisContext = context.analysisContext;
+    Source source = context.error.source;
     if (!AnalysisEngine.isDartFileName(source.fullName)) {
       return Fix.EMPTY_LIST;
     }
-    List<Source> libraries = context.getLibrariesContaining(source);
+    List<Source> libraries = analysisContext.getLibrariesContaining(source);
     if (libraries.isEmpty) {
       return Fix.EMPTY_LIST;
     }
     CompilationUnit unit =
-        context.resolveCompilationUnit2(source, libraries[0]);
+        analysisContext.resolveCompilationUnit2(source, libraries[0]);
     if (unit == null) {
       return Fix.EMPTY_LIST;
     }
-    return internalComputeFixes(resourceProvider, unit, error);
+    DartFixContext dartContext = new DartFixContextImpl(context, unit);
+    return internalComputeFixes(dartContext);
   }
 
   /**
-   * Return a list of fixes for the given [error]. The error was reported
-   * against the given compilation [unit].
+   * Return a list of fixes for the given [context].
    */
-  List<Fix> internalComputeFixes(ResourceProvider resourceProvider,
-      CompilationUnit unit, AnalysisError error);
+  Future<List<Fix>> internalComputeFixes(DartFixContext context);
 }
diff --git a/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart b/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
index 26a0080..81ad8dc 100644
--- a/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
+++ b/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
@@ -938,6 +938,176 @@
     return JenkinsSmiHash.finish(hash);
   }
 }
+
+/**
+ * analysis.getReachableSources params
+ *
+ * {
+ *   "file": FilePath
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisGetReachableSourcesParams implements HasToJson {
+  String _file;
+
+  /**
+   * The file for which reachable source information is being requested.
+   */
+  String get file => _file;
+
+  /**
+   * The file for which reachable source information is being requested.
+   */
+  void set file(String value) {
+    assert(value != null);
+    this._file = value;
+  }
+
+  AnalysisGetReachableSourcesParams(String file) {
+    this.file = file;
+  }
+
+  factory AnalysisGetReachableSourcesParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      String file;
+      if (json.containsKey("file")) {
+        file = jsonDecoder.decodeString(jsonPath + ".file", json["file"]);
+      } else {
+        throw jsonDecoder.missingKey(jsonPath, "file");
+      }
+      return new AnalysisGetReachableSourcesParams(file);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "analysis.getReachableSources params", json);
+    }
+  }
+
+  factory AnalysisGetReachableSourcesParams.fromRequest(Request request) {
+    return new AnalysisGetReachableSourcesParams.fromJson(
+        new RequestDecoder(request), "params", request._params);
+  }
+
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["file"] = file;
+    return result;
+  }
+
+  Request toRequest(String id) {
+    return new Request(id, "analysis.getReachableSources", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisGetReachableSourcesParams) {
+      return file == other.file;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, file.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * analysis.getReachableSources result
+ *
+ * {
+ *   "sources": Map<String, List<String>>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class AnalysisGetReachableSourcesResult implements HasToJson {
+  Map<String, List<String>> _sources;
+
+  /**
+   * A mapping from source URIs to directly reachable source URIs. For example,
+   * a file "foo.dart" that imports "bar.dart" would have the corresponding
+   * mapping { "file:///foo.dart" : ["file:///bar.dart"] }. If "bar.dart" has
+   * further imports (or exports) there will be a mapping from the URI
+   * "file:///bar.dart" to them. To check if a specific URI is reachable from a
+   * given file, clients can check for its presence in the resulting key set.
+   */
+  Map<String, List<String>> get sources => _sources;
+
+  /**
+   * A mapping from source URIs to directly reachable source URIs. For example,
+   * a file "foo.dart" that imports "bar.dart" would have the corresponding
+   * mapping { "file:///foo.dart" : ["file:///bar.dart"] }. If "bar.dart" has
+   * further imports (or exports) there will be a mapping from the URI
+   * "file:///bar.dart" to them. To check if a specific URI is reachable from a
+   * given file, clients can check for its presence in the resulting key set.
+   */
+  void set sources(Map<String, List<String>> value) {
+    assert(value != null);
+    this._sources = value;
+  }
+
+  AnalysisGetReachableSourcesResult(Map<String, List<String>> sources) {
+    this.sources = sources;
+  }
+
+  factory AnalysisGetReachableSourcesResult.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      Map<String, List<String>> sources;
+      if (json.containsKey("sources")) {
+        sources = jsonDecoder.decodeMap(jsonPath + ".sources", json["sources"], valueDecoder: (String jsonPath, Object json) => jsonDecoder.decodeList(jsonPath, json, jsonDecoder.decodeString));
+      } else {
+        throw jsonDecoder.missingKey(jsonPath, "sources");
+      }
+      return new AnalysisGetReachableSourcesResult(sources);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "analysis.getReachableSources result", json);
+    }
+  }
+
+  factory AnalysisGetReachableSourcesResult.fromResponse(Response response) {
+    return new AnalysisGetReachableSourcesResult.fromJson(
+        new ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id)), "result", response._result);
+  }
+
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["sources"] = sources;
+    return result;
+  }
+
+  Response toResponse(String id) {
+    return new Response(id, result: toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is AnalysisGetReachableSourcesResult) {
+      return mapEqual(sources, other.sources, (List<String> a, List<String> b) => listEqual(a, b, (String a, String b) => a == b));
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, sources.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
 /**
  * analysis.getLibraryDependencies params
  *
@@ -9277,6 +9447,7 @@
  *   "explicitFileCount": int
  *   "implicitFileCount": int
  *   "workItemQueueLength": int
+ *   "workItemQueueLengthAverage": String
  *   "cacheEntryExceptions": List<String>
  * }
  *
@@ -9291,6 +9462,8 @@
 
   int _workItemQueueLength;
 
+  String _workItemQueueLengthAverage;
+
   List<String> _cacheEntryExceptions;
 
   /**
@@ -9346,6 +9519,21 @@
   }
 
   /**
+   * A rolling average of work items in the queue. (A double encoded as a
+   * String.)
+   */
+  String get workItemQueueLengthAverage => _workItemQueueLengthAverage;
+
+  /**
+   * A rolling average of work items in the queue. (A double encoded as a
+   * String.)
+   */
+  void set workItemQueueLengthAverage(String value) {
+    assert(value != null);
+    this._workItemQueueLengthAverage = value;
+  }
+
+  /**
    * Exceptions associated with cache entries.
    */
   List<String> get cacheEntryExceptions => _cacheEntryExceptions;
@@ -9358,11 +9546,12 @@
     this._cacheEntryExceptions = value;
   }
 
-  ContextData(String name, int explicitFileCount, int implicitFileCount, int workItemQueueLength, List<String> cacheEntryExceptions) {
+  ContextData(String name, int explicitFileCount, int implicitFileCount, int workItemQueueLength, String workItemQueueLengthAverage, List<String> cacheEntryExceptions) {
     this.name = name;
     this.explicitFileCount = explicitFileCount;
     this.implicitFileCount = implicitFileCount;
     this.workItemQueueLength = workItemQueueLength;
+    this.workItemQueueLengthAverage = workItemQueueLengthAverage;
     this.cacheEntryExceptions = cacheEntryExceptions;
   }
 
@@ -9395,13 +9584,19 @@
       } else {
         throw jsonDecoder.missingKey(jsonPath, "workItemQueueLength");
       }
+      String workItemQueueLengthAverage;
+      if (json.containsKey("workItemQueueLengthAverage")) {
+        workItemQueueLengthAverage = jsonDecoder.decodeString(jsonPath + ".workItemQueueLengthAverage", json["workItemQueueLengthAverage"]);
+      } else {
+        throw jsonDecoder.missingKey(jsonPath, "workItemQueueLengthAverage");
+      }
       List<String> cacheEntryExceptions;
       if (json.containsKey("cacheEntryExceptions")) {
         cacheEntryExceptions = jsonDecoder.decodeList(jsonPath + ".cacheEntryExceptions", json["cacheEntryExceptions"], jsonDecoder.decodeString);
       } else {
         throw jsonDecoder.missingKey(jsonPath, "cacheEntryExceptions");
       }
-      return new ContextData(name, explicitFileCount, implicitFileCount, workItemQueueLength, cacheEntryExceptions);
+      return new ContextData(name, explicitFileCount, implicitFileCount, workItemQueueLength, workItemQueueLengthAverage, cacheEntryExceptions);
     } else {
       throw jsonDecoder.mismatch(jsonPath, "ContextData", json);
     }
@@ -9413,6 +9608,7 @@
     result["explicitFileCount"] = explicitFileCount;
     result["implicitFileCount"] = implicitFileCount;
     result["workItemQueueLength"] = workItemQueueLength;
+    result["workItemQueueLengthAverage"] = workItemQueueLengthAverage;
     result["cacheEntryExceptions"] = cacheEntryExceptions;
     return result;
   }
@@ -9427,6 +9623,7 @@
           explicitFileCount == other.explicitFileCount &&
           implicitFileCount == other.implicitFileCount &&
           workItemQueueLength == other.workItemQueueLength &&
+          workItemQueueLengthAverage == other.workItemQueueLengthAverage &&
           listEqual(cacheEntryExceptions, other.cacheEntryExceptions, (String a, String b) => a == b);
     }
     return false;
@@ -9439,6 +9636,7 @@
     hash = JenkinsSmiHash.combine(hash, explicitFileCount.hashCode);
     hash = JenkinsSmiHash.combine(hash, implicitFileCount.hashCode);
     hash = JenkinsSmiHash.combine(hash, workItemQueueLength.hashCode);
+    hash = JenkinsSmiHash.combine(hash, workItemQueueLengthAverage.hashCode);
     hash = JenkinsSmiHash.combine(hash, cacheEntryExceptions.hashCode);
     return JenkinsSmiHash.finish(hash);
   }
@@ -13892,6 +14090,7 @@
  *   FORMAT_WITH_ERRORS
  *   GET_ERRORS_INVALID_FILE
  *   GET_NAVIGATION_INVALID_FILE
+ *   GET_REACHABLE_SOURCES_INVALID_FILE
  *   INVALID_ANALYSIS_ROOT
  *   INVALID_EXECUTION_CONTEXT
  *   INVALID_OVERLAY_CHANGE
@@ -13950,6 +14149,12 @@
   static const GET_NAVIGATION_INVALID_FILE = const RequestErrorCode._("GET_NAVIGATION_INVALID_FILE");
 
   /**
+   * An "analysis.getReachableSources" request specified a FilePath which does
+   * not match a file currently subject to analysis.
+   */
+  static const GET_REACHABLE_SOURCES_INVALID_FILE = const RequestErrorCode._("GET_REACHABLE_SOURCES_INVALID_FILE");
+
+  /**
    * A path passed as an argument to a request (such as analysis.reanalyze) is
    * required to be an analysis root, but isn't.
    */
@@ -14055,7 +14260,7 @@
   /**
    * A list containing all of the enum values that are defined.
    */
-  static const List<RequestErrorCode> VALUES = const <RequestErrorCode>[CONTENT_MODIFIED, FILE_NOT_ANALYZED, FORMAT_INVALID_FILE, FORMAT_WITH_ERRORS, GET_ERRORS_INVALID_FILE, GET_NAVIGATION_INVALID_FILE, INVALID_ANALYSIS_ROOT, INVALID_EXECUTION_CONTEXT, INVALID_OVERLAY_CHANGE, INVALID_PARAMETER, INVALID_REQUEST, NO_INDEX_GENERATED, ORGANIZE_DIRECTIVES_ERROR, REFACTORING_REQUEST_CANCELLED, SERVER_ALREADY_STARTED, SERVER_ERROR, SORT_MEMBERS_INVALID_FILE, SORT_MEMBERS_PARSE_ERRORS, UNANALYZED_PRIORITY_FILES, UNKNOWN_REQUEST, UNKNOWN_SOURCE, UNSUPPORTED_FEATURE];
+  static const List<RequestErrorCode> VALUES = const <RequestErrorCode>[CONTENT_MODIFIED, FILE_NOT_ANALYZED, FORMAT_INVALID_FILE, FORMAT_WITH_ERRORS, GET_ERRORS_INVALID_FILE, GET_NAVIGATION_INVALID_FILE, GET_REACHABLE_SOURCES_INVALID_FILE, INVALID_ANALYSIS_ROOT, INVALID_EXECUTION_CONTEXT, INVALID_OVERLAY_CHANGE, INVALID_PARAMETER, INVALID_REQUEST, NO_INDEX_GENERATED, ORGANIZE_DIRECTIVES_ERROR, REFACTORING_REQUEST_CANCELLED, SERVER_ALREADY_STARTED, SERVER_ERROR, SORT_MEMBERS_INVALID_FILE, SORT_MEMBERS_PARSE_ERRORS, UNANALYZED_PRIORITY_FILES, UNKNOWN_REQUEST, UNKNOWN_SOURCE, UNSUPPORTED_FEATURE];
 
   final String name;
 
@@ -14075,6 +14280,8 @@
         return GET_ERRORS_INVALID_FILE;
       case "GET_NAVIGATION_INVALID_FILE":
         return GET_NAVIGATION_INVALID_FILE;
+      case "GET_REACHABLE_SOURCES_INVALID_FILE":
+        return GET_REACHABLE_SOURCES_INVALID_FILE;
       case "INVALID_ANALYSIS_ROOT":
         return INVALID_ANALYSIS_ROOT;
       case "INVALID_EXECUTION_CONTEXT":
diff --git a/pkg/analysis_server/lib/plugin/protocol/protocol.dart b/pkg/analysis_server/lib/plugin/protocol/protocol.dart
index 823ffd6..5617efc 100644
--- a/pkg/analysis_server/lib/plugin/protocol/protocol.dart
+++ b/pkg/analysis_server/lib/plugin/protocol/protocol.dart
@@ -20,7 +20,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-abstract class DomainHandler extends RequestHandler {
+abstract class DomainHandler implements RequestHandler {
   /**
    * Perform any operations associated with the shutdown of the domain. It is
    * not guaranteed that this method will be called. If it is, it will be
@@ -411,6 +411,16 @@
                 'Error during `analysis.getNavigation`: invalid file.'));
 
   /**
+   * Initialize a newly created instance to represent the
+   * GET_REACHABLE_SOURCES_INVALID_FILE error condition.
+   */
+  Response.getReachableSourcesInvalidFile(Request request)
+      : this(request.id,
+            error: new RequestError(
+                RequestErrorCode.GET_REACHABLE_SOURCES_INVALID_FILE,
+                'Error during `analysis.getReachableSources`: invalid file.'));
+
+  /**
    * Initialize a newly created instance to represent an error condition caused
    * by an analysis.reanalyze [request] that specifies an analysis root that is
    * not in the current list of analysis roots.
diff --git a/pkg/analysis_server/lib/src/analysis_logger.dart b/pkg/analysis_server/lib/src/analysis_logger.dart
index 04ad6c6..bc2276e 100644
--- a/pkg/analysis_server/lib/src/analysis_logger.dart
+++ b/pkg/analysis_server/lib/src/analysis_logger.dart
@@ -43,8 +43,7 @@
     } else {
       baseLogger.severe(message, exception.exception, exception.stackTrace);
     }
-    server.sendServerErrorNotification(
-        message, exception, exception?.stackTrace);
+    server.sendServerErrorNotification(message, exception, null);
   }
 
   @override
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 93c929c..6a5ace1 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -892,35 +892,28 @@
   /**
    * Sends a `server.error` notification.
    */
-  void sendServerErrorNotification(String msg, exception, stackTrace,
+  void sendServerErrorNotification(String message, exception, stackTrace,
       {bool fatal: false}) {
-    // prepare exception.toString()
-    String exceptionString;
+    StringBuffer buffer = new StringBuffer();
     if (exception != null) {
-      exceptionString = exception.toString();
+      buffer.write(exception);
     } else {
-      exceptionString = 'null exception';
+      buffer.write('null exception');
     }
-    // prepare message
-    String message = msg != null ? '$msg\n$exceptionString' : exceptionString;
-    // prepare stackTrace.toString()
-    String stackTraceString;
     if (stackTrace != null) {
-      stackTraceString = stackTrace.toString();
-    } else {
+      buffer.writeln();
+      buffer.write(stackTrace);
+    } else if (exception is! CaughtException) {
       try {
         throw 'ignored';
       } catch (ignored, stackTrace) {
-        stackTraceString = stackTrace.toString();
-      }
-      if (stackTraceString == null) {
-        // This code should be unreachable.
-        stackTraceString = 'null stackTrace';
+        buffer.writeln();
+        buffer.write(stackTrace);
       }
     }
     // send the notification
     channel.sendNotification(
-        new ServerErrorParams(fatal, message, stackTraceString)
+        new ServerErrorParams(fatal, message, buffer.toString())
             .toNotification());
   }
 
@@ -977,8 +970,11 @@
       Set<String> todoFiles =
           oldFiles != null ? newFiles.difference(oldFiles) : newFiles;
       for (String file in todoFiles) {
-        ContextSourcePair contextSource = getContextSourcePair(file);
+        if (contextManager.isIgnored(file)) {
+          continue;
+        }
         // prepare context
+        ContextSourcePair contextSource = getContextSourcePair(file);
         AnalysisContext context = contextSource.context;
         if (context == null) {
           continue;
@@ -1066,6 +1062,11 @@
     List<String> unanalyzed = new List<String>();
     Source firstSource = null;
     files.forEach((String file) {
+      if (contextManager.isIgnored(file)) {
+        unanalyzed.add(file);
+        return;
+      }
+      // Prepare the context/source pair.
       ContextSourcePair contextSource = getContextSourcePair(file);
       AnalysisContext preferredContext = contextSource.context;
       Source source = contextSource.source;
diff --git a/pkg/analysis_server/lib/src/constants.dart b/pkg/analysis_server/lib/src/constants.dart
index a32ad98..0d90251 100644
--- a/pkg/analysis_server/lib/src/constants.dart
+++ b/pkg/analysis_server/lib/src/constants.dart
@@ -26,6 +26,7 @@
 const String ANALYSIS_GET_LIBRARY_DEPENDENCIES =
     'analysis.getLibraryDependencies';
 const String ANALYSIS_GET_NAVIGATION = 'analysis.getNavigation';
+const String ANALYSIS_GET_REACHABLE_SOURCES = 'analysis.getReachableSources';
 const String ANALYSIS_REANALYZE = 'analysis.reanalyze';
 const String ANALYSIS_SET_ANALYSIS_ROOTS = 'analysis.setAnalysisRoots';
 const String ANALYSIS_SET_GENERAL_SUBSCRIPTIONS =
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index e45846d..061cc23 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -181,6 +181,31 @@
   void setDependencies(Iterable<String> newDependencies) {
     _dependencies = newDependencies.toSet();
   }
+
+  /**
+   * Return `true` if the given [path] is managed by this context or by
+   * any of its children.
+   */
+  bool _managesOrHasChildThatManages(String path) {
+    if (parent == null) {
+      for (ContextInfo child in children) {
+        if (child._managesOrHasChildThatManages(path)) {
+          return true;
+        }
+      }
+      return false;
+    } else {
+      if (!folder.isOrContains(path)) {
+        return false;
+      }
+      for (ContextInfo child in children) {
+        if (child._managesOrHasChildThatManages(path)) {
+          return true;
+        }
+      }
+      return !pathFilter.ignored(path);
+    }
+  }
 }
 
 /**
@@ -241,6 +266,12 @@
   AnalysisContext getContextFor(String path);
 
   /**
+   * Return `true` if the given [path] is ignored by a [ContextInfo] whose
+   * folder contains it.
+   */
+  bool isIgnored(String path);
+
+  /**
    * Return `true` if the given absolute [path] is in one of the current
    * root folders and is not excluded.
    */
@@ -419,7 +450,7 @@
    * Virtual [ContextInfo] which acts as the ancestor of all other
    * [ContextInfo]s.
    */
-  final ContextInfo _rootInfo = new ContextInfo._root();
+  final ContextInfo rootInfo = new ContextInfo._root();
 
   /**
    * Stream subscription we are using to watch each analysis root directory for
@@ -474,13 +505,27 @@
   }
 
   @override
+  bool isIgnored(String path) {
+    ContextInfo info = rootInfo;
+    do {
+      info = info.findChildInfoFor(path);
+      if (info == null) {
+        return false;
+      }
+      if (info.ignored(path)) {
+        return true;
+      }
+    } while (true);
+  }
+
+  @override
   bool isInAnalysisRoot(String path) {
     // check if excluded
     if (_isExcluded(path)) {
       return false;
     }
     // check if in one of the roots
-    for (ContextInfo info in _rootInfo.children) {
+    for (ContextInfo info in rootInfo.children) {
       if (info.folder.contains(path)) {
         return true;
       }
@@ -555,7 +600,7 @@
   @override
   void refresh(List<Resource> roots) {
     // Destroy old contexts
-    List<ContextInfo> contextInfos = _rootInfo.descendants.toList();
+    List<ContextInfo> contextInfos = rootInfo.descendants.toList();
     if (roots == null) {
       contextInfos.forEach(_destroyContext);
     } else {
@@ -596,22 +641,31 @@
       }
     });
 
-    List<ContextInfo> contextInfos = _rootInfo.descendants.toList();
+    List<ContextInfo> contextInfos = rootInfo.descendants.toList();
     // included
-    Set<Folder> includedFolders = new HashSet<Folder>();
-    for (int i = 0; i < includedPaths.length; i++) {
-      String path = includedPaths[i];
-      Resource resource = resourceProvider.getResource(path);
-      if (resource is Folder) {
-        includedFolders.add(resource);
-      } else if (!resource.exists) {
-        // Non-existent resources are ignored.  TODO(paulberry): we should set
-        // up a watcher to ensure that if the resource appears later, we will
-        // begin analyzing it.
-      } else {
-        // TODO(scheglov) implemented separate files analysis
-        throw new UnimplementedError('$path is not a folder. '
-            'Only support for folder analysis is implemented currently.');
+    List<Folder> includedFolders = <Folder>[];
+    {
+      // Sort paths to ensure that outer roots are handled before inner roots,
+      // so we can correctly ignore inner roots, which are already managed
+      // by outer roots.
+      LinkedHashSet<String> uniqueIncludedPaths =
+          new LinkedHashSet<String>.from(includedPaths);
+      List<String> sortedIncludedPaths = uniqueIncludedPaths.toList();
+      sortedIncludedPaths.sort((a, b) => a.length - b.length);
+      // Convert paths to folders.
+      for (String path in sortedIncludedPaths) {
+        Resource resource = resourceProvider.getResource(path);
+        if (resource is Folder) {
+          includedFolders.add(resource);
+        } else if (!resource.exists) {
+          // Non-existent resources are ignored.  TODO(paulberry): we should set
+          // up a watcher to ensure that if the resource appears later, we will
+          // begin analyzing it.
+        } else {
+          // TODO(scheglov) implemented separate files analysis
+          throw new UnimplementedError('$path is not a folder. '
+              'Only support for folder analysis is implemented currently.');
+        }
       }
     }
     this.includedPaths = includedPaths;
@@ -628,7 +682,7 @@
       }
     }
     // Update package roots for existing contexts
-    for (ContextInfo info in _rootInfo.descendants) {
+    for (ContextInfo info in rootInfo.descendants) {
       String newPackageRoot = normalizedPackageRoots[info.folder.path];
       if (info.packageRoot != newPackageRoot) {
         info.packageRoot = newPackageRoot;
@@ -637,17 +691,17 @@
     }
     // create new contexts
     for (Folder includedFolder in includedFolders) {
-      bool wasIncluded = contextInfos.any((info) {
-        return info.folder.isOrContains(includedFolder.path);
-      });
-      if (!wasIncluded) {
+      String includedPath = includedFolder.path;
+      bool isManaged = rootInfo._managesOrHasChildThatManages(includedPath);
+      if (!isManaged) {
+        ContextInfo parent = _getParentForNewContext(includedPath);
         changeSubscriptions[includedFolder] =
             includedFolder.changes.listen(_handleWatchEvent);
-        _createContexts(_rootInfo, includedFolder, false);
+        _createContexts(parent, includedFolder, false);
       }
     }
     // remove newly excluded sources
-    for (ContextInfo info in _rootInfo.descendants) {
+    for (ContextInfo info in rootInfo.descendants) {
       // prepare excluded sources
       Map<String, Source> excludedSources = new HashMap<String, Source>();
       info.sources.forEach((String path, Source source) {
@@ -665,7 +719,7 @@
       callbacks.applyChangesToContext(info.folder, changeSet);
     }
     // add previously excluded sources
-    for (ContextInfo info in _rootInfo.descendants) {
+    for (ContextInfo info in rootInfo.descendants) {
       ChangeSet changeSet = new ChangeSet();
       _addPreviouslyExcludedSources(
           info, changeSet, info.folder, oldExcludedPaths);
@@ -802,7 +856,7 @@
     for (Source source in context.sources) {
       flushedFiles.add(source.fullName);
     }
-    for (ContextInfo contextInfo in _rootInfo.descendants) {
+    for (ContextInfo contextInfo in rootInfo.descendants) {
       AnalysisContext contextN = contextInfo.context;
       if (context != contextN) {
         for (Source source in contextN.sources) {
@@ -1062,7 +1116,7 @@
    * If no context contains the given path, `null` is returned.
    */
   ContextInfo _getInnermostContextInfoFor(String path) {
-    ContextInfo info = _rootInfo.findChildInfoFor(path);
+    ContextInfo info = rootInfo.findChildInfoFor(path);
     if (info == null) {
       return null;
     }
@@ -1075,6 +1129,17 @@
     }
   }
 
+  /**
+   * Return the parent for a new [ContextInfo] with the given [path] folder.
+   */
+  ContextInfo _getParentForNewContext(String path) {
+    ContextInfo parent = _getInnermostContextInfoFor(path);
+    if (parent != null) {
+      return parent;
+    }
+    return rootInfo;
+  }
+
   void _handleWatchEvent(WatchEvent event) {
     // Figure out which context this event applies to.
     // TODO(brianwilkerson) If a file is explicitly included in one context
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index 494d37c..f1bdf14 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -21,6 +21,7 @@
 import 'package:analysis_server/src/protocol/protocol_internal.dart';
 import 'package:analysis_server/src/protocol_server.dart';
 import 'package:analysis_server/src/services/dependencies/library_dependencies.dart';
+import 'package:analysis_server/src/services/dependencies/reachable_source_collector.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
@@ -164,6 +165,22 @@
     return Response.DELAYED_RESPONSE;
   }
 
+  /**
+   * Implement the `analysis.getReachableSources` request.
+   */
+  Response getReachableSources(Request request) {
+    AnalysisGetReachableSourcesParams params =
+        new AnalysisGetReachableSourcesParams.fromRequest(request);
+    ContextSourcePair pair = server.getContextSourcePair(params.file);
+    if (pair.context == null || pair.source == null) {
+      return new Response.getReachableSourcesInvalidFile(request);
+    }
+    Map<String, List<String>> sources = new ReachableSourceCollector(
+        pair.source, pair.context).collectSources();
+    return new AnalysisGetReachableSourcesResult(sources)
+        .toResponse(request.id);
+  }
+
   @override
   Response handleRequest(Request request) {
     try {
@@ -176,6 +193,8 @@
         return getLibraryDependencies(request);
       } else if (requestName == ANALYSIS_GET_NAVIGATION) {
         return getNavigation(request);
+      } else if (requestName == ANALYSIS_GET_REACHABLE_SOURCES) {
+        return getReachableSources(request);
       } else if (requestName == ANALYSIS_REANALYZE) {
         return reanalyze(request);
       } else if (requestName == ANALYSIS_SET_ANALYSIS_ROOTS) {
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index 6d43e53..370e7bf 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -12,6 +12,7 @@
 import 'package:analysis_server/src/context_manager.dart';
 import 'package:analysis_server/src/provisional/completion/completion_core.dart'
     show CompletionRequest, CompletionResult;
+import 'package:analysis_server/src/services/completion/completion_core.dart';
 import 'package:analysis_server/src/services/completion/completion_manager.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
 import 'package:analyzer/src/generated/engine.dart';
@@ -100,7 +101,7 @@
       }
       _discardManager();
     }
-    _manager = createCompletionManager(context, source, searchEngine);
+    _manager = createCompletionManager(server, context, source);
     if (context != null) {
       _sourcesChangedSubscription =
           context.onSourcesChanged.listen(sourcesChanged);
@@ -122,8 +123,9 @@
   }
 
   CompletionManager createCompletionManager(
-      AnalysisContext context, Source source, SearchEngine searchEngine) {
-    return new CompletionManager.create(context, source, searchEngine);
+      AnalysisServer server, AnalysisContext context, Source source) {
+    return new CompletionManager.create(context, source, server.searchEngine,
+        server.serverPlugin.completionContributors);
   }
 
   @override
@@ -194,8 +196,8 @@
     if (manager == null) {
       manager = completionManagerFor(context, source);
     }
-    CompletionRequest completionRequest =
-        new CompletionRequestImpl(server, context, source, params.offset);
+    CompletionRequest completionRequest = new CompletionRequestImpl(context,
+        server.resourceProvider, server.searchEngine, source, params.offset);
     int notificationCount = 0;
     manager.results(completionRequest).listen((CompletionResult result) {
       ++notificationCount;
diff --git a/pkg/analysis_server/lib/src/domain_diagnostic.dart b/pkg/analysis_server/lib/src/domain_diagnostic.dart
index e6c08c4..5d30d92 100644
--- a/pkg/analysis_server/lib/src/domain_diagnostic.dart
+++ b/pkg/analysis_server/lib/src/domain_diagnostic.dart
@@ -4,11 +4,13 @@
 
 library src.domain_diagnostic;
 
+import 'dart:async';
 import 'dart:collection';
 import 'dart:core' hide Resource;
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
 import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/utilities/average.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/context/cache.dart';
 import 'package:analyzer/src/context/context.dart';
@@ -19,42 +21,10 @@
 import 'package:analyzer/src/task/driver.dart';
 import 'package:analyzer/task/model.dart';
 
-/// Extract context data from the given [context].
-ContextData extractData(AnalysisContext context) {
-  int explicitFiles = 0;
-  int implicitFiles = 0;
-  int workItems = 0;
-  Set<String> exceptions = new HashSet<String>();
-  if (context is AnalysisContextImpl) {
-    // Work Item count.
-    AnalysisDriver driver = context.driver;
-    List<WorkItem> items = driver.currentWorkOrder?.workItems;
-    workItems ??= items?.length;
-    var cache = context.analysisCache;
-    if (cache is AnalysisCache) {
-      Set<AnalysisTarget> countedTargets = new HashSet<AnalysisTarget>();
-      MapIterator<AnalysisTarget, CacheEntry> iterator = cache.iterator();
-      while (iterator.moveNext()) {
-        AnalysisTarget target = iterator.key;
-        if (countedTargets.add(target)) {
-          CacheEntry cacheEntry = iterator.value;
-          if (target is Source) {
-            if (cacheEntry.explicitlyAdded) {
-              explicitFiles++;
-            } else {
-              implicitFiles++;
-            }
-          }
-          // Caught exceptions.
-          if (cacheEntry.exception != null) {
-            exceptions.add(cacheEntry.exception.toString());
-          }
-        }
-      }
-    }
-  }
-  return new ContextData(context.name, explicitFiles, implicitFiles, workItems,
-      exceptions.toList());
+int _workItemCount(AnalysisContextImpl context) {
+  AnalysisDriver driver = context.driver;
+  List<WorkItem> items = driver.currentWorkOrder?.workItems;
+  return items?.length ?? 0;
 }
 
 /// Instances of the class [DiagnosticDomainHandler] implement a
@@ -66,20 +36,65 @@
   /// The analysis server that is using this handler to process requests.
   final AnalysisServer server;
 
+  /// The sampler tracking rolling work queue length averages.
+  Sampler sampler;
+
   /// Initialize a newly created handler to handle requests for the given
   /// [server].
   DiagnosticDomainHandler(this.server);
 
   /// Answer the `diagnostic.diagnostics` request.
   Response computeDiagnostics(Request request) {
+    // Initialize sampler if needed.
+    if (sampler == null) {
+      sampler = new Sampler(server);
+    }
+
     List<ContextData> infos = <ContextData>[];
     server.folderMap.forEach((Folder folder, AnalysisContext context) {
-      infos.add(extractData(context));
+      infos.add(extractData(folder, context));
     });
 
     return new DiagnosticGetDiagnosticsResult(infos).toResponse(request.id);
   }
 
+  /// Extract context data from the given [context].
+  ContextData extractData(Folder folder, AnalysisContext context) {
+    int explicitFiles = 0;
+    int implicitFiles = 0;
+    int workItems = 0;
+    String workItemAverage = '-1';
+    Set<String> exceptions = new HashSet<String>();
+    if (context is AnalysisContextImpl) {
+      workItems = _workItemCount(context);
+      workItemAverage = sampler.getAverage(folder)?.toString() ?? '-1';
+      var cache = context.analysisCache;
+      if (cache is AnalysisCache) {
+        Set<AnalysisTarget> countedTargets = new HashSet<AnalysisTarget>();
+        MapIterator<AnalysisTarget, CacheEntry> iterator = cache.iterator();
+        while (iterator.moveNext()) {
+          AnalysisTarget target = iterator.key;
+          if (countedTargets.add(target)) {
+            CacheEntry cacheEntry = iterator.value;
+            if (target is Source) {
+              if (cacheEntry.explicitlyAdded) {
+                explicitFiles++;
+              } else {
+                implicitFiles++;
+              }
+            }
+            // Caught exceptions.
+            if (cacheEntry.exception != null) {
+              exceptions.add(cacheEntry.exception.toString());
+            }
+          }
+        }
+      }
+    }
+    return new ContextData(context.name, explicitFiles, implicitFiles,
+        workItems, workItemAverage, exceptions.toList());
+  }
+
   @override
   Response handleRequest(Request request) {
     try {
@@ -93,3 +108,83 @@
     return null;
   }
 }
+
+/// Keeps track of a moving average of work item queue lengths mapped to
+/// contexts.
+///
+/// Sampling terminates after [maxSampleCount], if no one expresses interest
+/// by calling [resetTimerCountdown].
+class Sampler {
+  /// Timer interval.
+  static const Duration duration = const Duration(seconds: 1);
+
+  /// Maximum number of samples taken between calls to [reset].
+  static const int maxSampleCount = 30;
+
+  /// Current sample count.
+  int sampleCount = 0;
+
+  /// The shared timer.
+  Timer timer;
+
+  /// Map of contexts (tracked as folders to avoid leaks) to averages.
+  /// TOOD(pq): consider adding GC to remove mappings for deleted folders
+  Map<Folder, Average> averages = new HashMap<Folder, Average>();
+
+  final AnalysisServer server;
+  Sampler(this.server) {
+    start();
+    _sample();
+  }
+
+  /// Get the average for the context associated with the given [folder].
+  num getAverage(Folder folder) {
+    resetTimerCountdown();
+    return averages[folder].value;
+  }
+
+  /// Check if we're currently sampling.
+  bool isSampling() => timer?.isActive ?? false;
+
+  /// Reset counter.
+  void resetTimerCountdown() {
+    sampleCount = 0;
+  }
+
+  /// Start sampling.
+  void start() {
+    // No need to (re)start if already sampling.
+    if (isSampling()) {
+      return;
+    }
+    timer = new Timer.periodic(duration, (Timer timer) {
+      _sample();
+      if (sampleCount++ >= maxSampleCount) {
+        timer.cancel();
+      }
+    });
+  }
+
+  /// Stop sampling.
+  void stop() {
+    timer.cancel();
+  }
+
+  /// Take a sample.
+  void _sample() {
+    try {
+      server.folderMap.forEach((Folder folder, AnalysisContext context) {
+        if (context is AnalysisContextImpl) {
+          Average average = averages[folder];
+          if (average == null) {
+            average = new Average();
+            averages[folder] = average;
+          }
+          average.addSample(_workItemCount(context));
+        }
+      });
+    } on Exception {
+      stop();
+    }
+  }
+}
diff --git a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
index f96f42f..2321ee3 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
@@ -54,23 +54,38 @@
   }
 
   void _addMemberIfImplemented(Element element) {
-    if (!element.isSynthetic) {
-      String name = element.displayName;
-      if (name != null && _hasOverride(name)) {
-        _addImplementedMember(element);
-      }
+    if (element.isSynthetic || _isStatic(element)) {
+      return;
+    }
+    String name = element.displayName;
+    if (name != null && _hasOverride(name)) {
+      _addImplementedMember(element);
     }
   }
 
   bool _hasOverride(String name) {
     for (ClassElement subtype in subtypes) {
-      if (subtype.getMethod(name) != null) {
-        return true;
+      MethodElement method = subtype.getMethod(name);
+      if (method != null) {
+        return !method.isStatic;
       }
-      if (subtype.getField(name) != null) {
-        return true;
+      FieldElement field = subtype.getField(name);
+      if (field != null) {
+        return !field.isStatic;
       }
     }
     return false;
   }
+
+  /**
+   * Return `true` if the given [element] is a static element.
+   */
+  static bool _isStatic(Element element) {
+    if (element is ExecutableElement) {
+      return element.isStatic;
+    } else if (element is PropertyInducingElement) {
+      return element.isStatic;
+    }
+    return false;
+  }
 }
diff --git a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
index dc4616f..20ed6aa 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
@@ -243,6 +243,19 @@
   }
 
   @override
+  visitRedirectingConstructorInvocation(RedirectingConstructorInvocation node) {
+    Element element = node.staticElement;
+    if (element != null && element.isSynthetic) {
+      element = element.enclosingElement;
+    }
+    // add region
+    computer._addRegionForToken(node.thisKeyword, element);
+    computer._addRegionForNode(node.constructorName, element);
+    // process arguments
+    _safelyVisit(node.argumentList);
+  }
+
+  @override
   visitSimpleIdentifier(SimpleIdentifier node) {
     if (node.parent is ConstructorDeclaration) {
       return;
@@ -258,12 +271,8 @@
       element = element.enclosingElement;
     }
     // add region
-    SimpleIdentifier name = node.constructorName;
-    if (name != null) {
-      computer._addRegion_nodeStart_nodeEnd(node, name, element);
-    } else {
-      computer._addRegionForToken(node.superKeyword, element);
-    }
+    computer._addRegionForToken(node.superKeyword, element);
+    computer._addRegionForNode(node.constructorName, element);
     // process arguments
     _safelyVisit(node.argumentList);
   }
@@ -279,7 +288,16 @@
     }
     // add regions
     TypeName typeName = node.type;
-    computer._addRegionForNode(typeName.name, element);
+    // [prefix].ClassName
+    {
+      Identifier name = typeName.name;
+      Identifier className = name;
+      if (name is PrefixedIdentifier) {
+        name.prefix.accept(this);
+        className = name.identifier;
+      }
+      computer._addRegionForNode(className, element);
+    }
     // <TypeA, TypeB>
     TypeArgumentList typeArguments = typeName.typeArguments;
     if (typeArguments != null) {
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index e14f3b3..1865146 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -130,23 +130,25 @@
         .toResponse(request.id);
   }
 
-  Response getAssists(Request request) {
+  Future getAssists(Request request) async {
     EditGetAssistsParams params = new EditGetAssistsParams.fromRequest(request);
     ContextSourcePair pair = server.getContextSourcePair(params.file);
     engine.AnalysisContext context = pair.context;
     Source source = pair.source;
     List<SourceChange> changes = <SourceChange>[];
     if (context != null && source != null) {
-      List<Assist> assists = computeAssists(
+      List<Assist> assists = await computeAssists(
           server.serverPlugin, context, source, params.offset, params.length);
       assists.forEach((Assist assist) {
         changes.add(assist.change);
       });
     }
-    return new EditGetAssistsResult(changes).toResponse(request.id);
+    Response response =
+        new EditGetAssistsResult(changes).toResponse(request.id);
+    server.sendResponse(response);
   }
 
-  Response getFixes(Request request) {
+  getFixes(Request request) async {
     var params = new EditGetFixesParams.fromRequest(request);
     String file = params.file;
     int offset = params.offset;
@@ -161,7 +163,7 @@
         for (engine.AnalysisError error in errorInfo.errors) {
           int errorLine = lineInfo.getLocation(error.offset).lineNumber;
           if (errorLine == requestLine) {
-            List<Fix> fixes = computeFixes(server.serverPlugin,
+            List<Fix> fixes = await computeFixes(server.serverPlugin,
                 server.resourceProvider, unit.element.context, error);
             if (fixes.isNotEmpty) {
               AnalysisError serverError =
@@ -178,7 +180,8 @@
       }
     }
     // respond
-    return new EditGetFixesResult(errorFixesList).toResponse(request.id);
+    return server.sendResponse(
+        new EditGetFixesResult(errorFixesList).toResponse(request.id));
   }
 
   @override
@@ -188,11 +191,13 @@
       if (requestName == EDIT_FORMAT) {
         return format(request);
       } else if (requestName == EDIT_GET_ASSISTS) {
-        return getAssists(request);
+        getAssists(request);
+        return Response.DELAYED_RESPONSE;
       } else if (requestName == EDIT_GET_AVAILABLE_REFACTORINGS) {
         return _getAvailableRefactorings(request);
       } else if (requestName == EDIT_GET_FIXES) {
-        return getFixes(request);
+        getFixes(request);
+        return Response.DELAYED_RESPONSE;
       } else if (requestName == EDIT_GET_REFACTORING) {
         return _getRefactoring(request);
       } else if (requestName == EDIT_ORGANIZE_DIRECTIVES) {
diff --git a/pkg/analysis_server/lib/src/plugin/server_plugin.dart b/pkg/analysis_server/lib/src/plugin/server_plugin.dart
index a7a13dd..b35d5bd 100644
--- a/pkg/analysis_server/lib/src/plugin/server_plugin.dart
+++ b/pkg/analysis_server/lib/src/plugin/server_plugin.dart
@@ -14,8 +14,6 @@
 import 'package:analysis_server/plugin/edit/assist/assist_core.dart';
 import 'package:analysis_server/plugin/edit/fix/fix.dart';
 import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
-import 'package:analysis_server/plugin/index/index.dart';
-import 'package:analysis_server/plugin/index/index_core.dart';
 import 'package:analysis_server/plugin/protocol/protocol.dart';
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/domain_analysis.dart';
@@ -27,6 +25,8 @@
 import 'package:analysis_server/src/domains/analysis/occurrences_dart.dart';
 import 'package:analysis_server/src/edit/edit_domain.dart';
 import 'package:analysis_server/src/provisional/completion/completion_core.dart';
+import 'package:analysis_server/src/provisional/index/index.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
 import 'package:analysis_server/src/search/search_domain.dart';
 import 'package:analysis_server/src/services/correction/assist_internal.dart';
 import 'package:analysis_server/src/services/correction/fix_internal.dart';
@@ -189,8 +189,9 @@
    * Return a list containing all of the completion contributors that were
    * contributed.
    */
-  List<CompletionContributor> get completionContributors =>
-      completionContributorExtensionPoint.extensions;
+  Iterable<CompletionContributor> get completionContributors =>
+      completionContributorExtensionPoint.extensions
+          .map((CompletionContributorFactory factory) => factory());
 
   /**
    * Return a list containing all of the fix contributors that were contributed.
@@ -291,7 +292,7 @@
     // Register completion contributors.
     //
     // TODO(brianwilkerson) Register the completion contributors.
-//    registerExtension(COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID, ???);
+    //registerExtension(COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID, ???);
     //
     // Register analysis contributors.
     //
@@ -370,10 +371,10 @@
    * valid completion contributor.
    */
   void _validateCompletionContributorExtension(Object extension) {
-    if (extension is! CompletionContributor) {
+    if (extension is! CompletionContributorFactory) {
       String id = completionContributorExtensionPoint.uniqueIdentifier;
       throw new ExtensionError(
-          'Extensions to $id must be an CompletionContributor');
+          'Extensions to $id must be an CompletionContributorFactory');
     }
   }
 
diff --git a/pkg/analysis_server/lib/src/provisional/completion/completion.dart b/pkg/analysis_server/lib/src/provisional/completion/completion.dart
index 9a71bc0..68eb362 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/completion.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/completion.dart
@@ -6,12 +6,13 @@
  * Support for client code that extends the analysis server by adding new code
  * completion contributors.
  *
- * Plugins can register completion contributors. The registered contributors
- * will be used to get completions any time a client issues a
- * 'completion.getSuggestions' request.
+ * Plugins can register completion contributor factories.
+ * The registered contributor factories will be used to instantiate new
+ * contributors to get completions any time a client issues
+ * a 'completion.getSuggestions' request.
  *
- * If a plugin wants to add completions, it should implement the class
- * [CompletionContributor] and then register the contributor by including code
+ * If a plugin wants to add completions, it should implement
+ * [CompletionContributorFactory] by including code
  * like the following in the plugin's registerExtensions method:
  *
  *     @override
@@ -19,20 +20,19 @@
  *       ...
  *       registerExtension(
  *           COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
- *           new MyCompletionContributor());
+ *           () => new MyCompletionContributor());
  *       ...
  *     }
  */
-library analysis_server.src.provisional.completion.completion;
+library analysis_server.src.provisional.completion.core;
 
 import 'package:analysis_server/src/plugin/server_plugin.dart';
-import 'package:analysis_server/src/provisional/completion/completion_core.dart';
 import 'package:plugin/plugin.dart';
 
 /**
  * The identifier of the extension point that allows plugins to register code
  * completion contributors. The object used as an extension must be a
- * [CompletionContributor].
+ * [CompletionContributorFactory].
  */
 final String COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID = Plugin.join(
     ServerPlugin.UNIQUE_IDENTIFIER,
diff --git a/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart b/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
index af69cd0..bdebfcc 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
@@ -4,51 +4,39 @@
 
 library analysis_server.src.provisional.completion.completion_core;
 
+import 'dart:async';
+
 import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analysis_server/src/services/search/search_engine.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/task/model.dart';
 
 /**
- * A method or function called when the requested analysis has been performed.
+ * An empty list returned by [CompletionContributor]s
+ * when they have no suggestions to contribute.
  */
-typedef AnalysisRequest AnalysisCallback<V>(
-    CompletionRequest request, V computedValue);
+const EMPTY_LIST = const <CompletionSuggestion>[];
 
 /**
- * A request from a contributor for additional analysis.
+ * An object used to instantiate a [CompletionContributor] instance
+ * for each 'completion.getSuggestions' request.
+ * Contributors should *not* be cached between requests.
  */
-class AnalysisRequest<V> {
-  /**
-   * An object with which an analysis result can be associated.
-   */
-  AnalysisTarget target;
-
-  /**
-   * A description of an analysis result that can be computed by an [AnalysisTask].
-   */
-  ResultDescriptor<V> descriptor;
-
-  /**
-   * A method or function called when the requested analysis has been performed.
-   */
-  AnalysisCallback<V> callback;
-
-  AnalysisRequest(this.target, this.descriptor, this.callback);
-}
+typedef CompletionContributor CompletionContributorFactory();
 
 /**
  * An object used to produce completions at a specific location within a file.
  *
- * Clients may extend this class when implementing plugins.
+ * Clients may implement this class when implementing plugins.
  */
 abstract class CompletionContributor {
   /**
-   * Compute a list of completion suggestions based on the given completion
-   * [request]. Return the suggestions that were computed.
+   * Return a [Future] that completes with a list of suggestions
+   * for the given completion [request].
    */
-  List<CompletionSuggestion> computeSuggestions(CompletionRequest request);
+  Future<List<CompletionSuggestion>> computeSuggestions(
+      CompletionRequest request);
 }
 
 /**
@@ -74,6 +62,11 @@
   ResourceProvider get resourceProvider;
 
   /**
+   * Return the search engine.
+   */
+  SearchEngine get searchEngine;
+
+  /**
    * Return the source in which the completion is being requested.
    */
   Source get source;
diff --git a/pkg/analysis_server/lib/src/provisional/completion/completion_dart.dart b/pkg/analysis_server/lib/src/provisional/completion/completion_dart.dart
deleted file mode 100644
index e52c433..0000000
--- a/pkg/analysis_server/lib/src/provisional/completion/completion_dart.dart
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library analysis_server.src.provisional.completion.completion_dart;
-
-import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/provisional/completion/completion_core.dart';
-import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/source.dart';
-
-/**
- * An object used to produce completions for a specific error within a Dart
- * file. Completion contributors are long-lived objects and must not retain any
- * state between invocations of [computeSuggestions].
- *
- * Clients may extend this class when implementing plugins.
- */
-abstract class DartCompletionContributor implements CompletionContributor {
-  @override
-  List<CompletionSuggestion> computeSuggestions(CompletionRequest request) {
-    if (request is DartCompletionRequest) {
-      return internalComputeSuggestions(request);
-    }
-    AnalysisContext context = request.context;
-    Source source = request.source;
-    List<Source> libraries = context.getLibrariesContaining(source);
-    if (libraries.length < 1) {
-      return null;
-    }
-//    CompilationUnit unit =
-//        context.getResolvedCompilationUnit2(source, libraries[0]);
-//    bool isResolved = true;
-//    if (unit == null) {
-//      // TODO(brianwilkerson) Implement a method for getting a parsed
-//      // compilation unit without parsing the unit if it hasn't been parsed.
-//      unit = context.getParsedCompilationUnit(source);
-//      if (unit == null) {
-//        return null;
-//      }
-//      isResolved = false;
-//    }
-//    DartCompletionRequest dartRequest =
-//        new DartCompletionRequestImpl(request, unit, isResolved);
-//    return internalComputeSuggestions(dartRequest);
-    return null;
-  }
-
-  /**
-   * Compute a list of completion suggestions based on the given completion
-   * [request]. Return the suggestions that were computed.
-   */
-  List<CompletionSuggestion> internalComputeSuggestions(
-      DartCompletionRequest request);
-}
-
-/**
- * The information about a requested list of completions within a Dart file.
- *
- * Clients may not extend, implement or mix-in this class.
- */
-abstract class DartCompletionRequest extends CompletionRequest {
-  /**
-   * Return `true` if the compilation [unit] is resolved.
-   */
-  bool get isResolved;
-
-  /**
-   * Return the completion target.  This determines what part of the parse tree
-   * will receive the newly inserted text.
-   */
-  CompletionTarget get target;
-
-  /**
-   * Cached information from a prior code completion operation.
-   */
-  //DartCompletionCache get cache;
-
-  /**
-   * Return the compilation unit in which the completion was requested.
-   */
-  CompilationUnit get unit;
-
-  /**
-   * Information about the types of suggestions that should be included.
-   */
-  //OpType get _optype;
-}
diff --git a/pkg/analysis_server/lib/src/provisional/completion/dart/completion.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion.dart
new file mode 100644
index 0000000..4d6601d
--- /dev/null
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Support for client code that extends the analysis server by adding new
+ * Dart specific completion contributors.
+ *
+ * Plugins can register Dart specific completion contributor factories.
+ * The registered contributor factories will be used to instantiate new
+ * contributors to get completions any time a client issues
+ * a 'completion.getSuggestions' request.
+ *
+ * If a plugin wants to add completions, it should implement
+ * [DartCompletionContributorFactory] by including code
+ * like the following in the plugin's registerExtensions method:
+ *
+ *     @override
+ *     void registerExtensions(RegisterExtension registerExtension) {
+ *       ...
+ *       registerExtension(
+ *           DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
+ *           () => new MyDartCompletionContributor());
+ *       ...
+ *     }
+ */
+library analysis_server.src.provisional.completion.dart;
+
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_plugin.dart';
+import 'package:plugin/plugin.dart';
+
+/**
+ * The identifier of the extension point that allows plugins to register code
+ * completion contributors. The object used as an extension must be a
+ * [DartCompletionContributorFactory].
+ */
+final String DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID = Plugin.join(
+    DartCompletionPlugin.UNIQUE_IDENTIFIER,
+    DartCompletionPlugin.CONTRIBUTOR_EXTENSION_POINT);
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
new file mode 100644
index 0000000..816894d
--- /dev/null
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
@@ -0,0 +1,86 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analysis_server.src.provisional.completion.completion_dart;
+
+import 'dart:async';
+
+import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
+import 'package:analyzer/src/generated/ast.dart';
+
+export 'package:analysis_server/src/provisional/completion/completion_core.dart'
+    show EMPTY_LIST;
+
+const int DART_RELEVANCE_COMMON_USAGE = 1200;
+const int DART_RELEVANCE_DEFAULT = 1000;
+const int DART_RELEVANCE_HIGH = 2000;
+const int DART_RELEVANCE_INHERITED_ACCESSOR = 1057;
+const int DART_RELEVANCE_INHERITED_FIELD = 1058;
+const int DART_RELEVANCE_INHERITED_METHOD = 1057;
+const int DART_RELEVANCE_KEYWORD = 1055;
+const int DART_RELEVANCE_LOCAL_ACCESSOR = 1057;
+const int DART_RELEVANCE_LOCAL_FIELD = 1058;
+const int DART_RELEVANCE_LOCAL_FUNCTION = 1056;
+const int DART_RELEVANCE_LOCAL_METHOD = 1057;
+const int DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE = 1056;
+const int DART_RELEVANCE_LOCAL_VARIABLE = 1059;
+const int DART_RELEVANCE_LOW = 500;
+const int DART_RELEVANCE_NAMED_PARAMETER = 1060;
+const int DART_RELEVANCE_PARAMETER = 1059;
+
+/**
+ * An object used to instantiate a [DartCompletionContributor] instance
+ * for each 'completion.getSuggestions' request.
+ * Contributors should *not* be cached between requests.
+ */
+typedef DartCompletionContributor DartCompletionContributorFactory();
+
+/**
+ * An object used to produce completions
+ * at a specific location within a Dart file.
+ *
+ * Clients may implement this class when implementing plugins.
+ */
+abstract class DartCompletionContributor {
+  /**
+   * Return a [Future] that completes with a list of suggestions
+   * for the given completion [request].
+   */
+  Future<List<CompletionSuggestion>> computeSuggestions(
+      DartCompletionRequest request);
+}
+
+/**
+ * The information about a requested list of completions within a Dart file.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class DartCompletionRequest extends CompletionRequest {
+  /**
+   * Return the completion target.  This determines what part of the parse tree
+   * will receive the newly inserted text.
+   */
+  CompletionTarget get target;
+
+  /**
+   * Return a [Future] that completes with a compilation unit in which
+   * all declarations in all scopes containing [target] have been resolved.
+   * The [Future] may return `null` if the unit cannot be resolved
+   * (e.g. unlinked part file).
+   * Any information obtained from [target] prior to calling this method
+   * should be discarded as it may have changed.
+   */
+  Future<CompilationUnit> resolveDeclarationsInScope();
+
+  /**
+   * Return a [Future] that completes when the element associated with
+   * the given [identifier] is available or if the identifier cannot be resolved
+   * (e.g. unknown identifier, completion aborted, etc).
+   * Any information obtained from [target] prior to calling this method
+   * should be discarded as it may have changed.
+   */
+  Future resolveIdentifier(SimpleIdentifier identifier);
+}
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
new file mode 100644
index 0000000..2b73a30
--- /dev/null
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_plugin.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analysis_server.src.provisional.completion.dart.plugin;
+
+import 'package:analysis_server/src/provisional/completion/completion.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/arglist_contributor.dart';
+import 'package:analysis_server/src/services/completion/dart/combinator_contributor.dart';
+import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
+import 'package:analysis_server/src/services/completion/dart/keyword_contributor.dart';
+import 'package:analysis_server/src/services/completion/dart/uri_contributor.dart';
+import 'package:plugin/plugin.dart';
+
+/**
+ * The shared dart completion plugin instance.
+ */
+final DartCompletionPlugin dartCompletionPlugin = new DartCompletionPlugin();
+
+class DartCompletionPlugin implements Plugin {
+  /**
+   * The simple identifier of the extension point that allows plugins to
+   * register Dart specific completion contributor factories.
+   * Use [DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID]
+   * when registering contributors.
+   */
+  static const String CONTRIBUTOR_EXTENSION_POINT = 'contributor';
+
+  /**
+   * The unique identifier of this plugin.
+   */
+  static const String UNIQUE_IDENTIFIER = 'dart.completion';
+
+  /**
+   * The extension point that allows plugins to register Dart specific
+   * completion contributor factories.
+   */
+  ExtensionPoint _contributorExtensionPoint;
+
+  @override
+  String get uniqueIdentifier => UNIQUE_IDENTIFIER;
+
+  /**
+   * Return a list containing all of the Dart specific completion contributors.
+   */
+  Iterable<DartCompletionContributorFactory> get contributors =>
+      _contributorExtensionPoint.extensions
+          .map((DartCompletionContributorFactory factory) => factory());
+
+  @override
+  void registerExtensionPoints(RegisterExtensionPoint registerExtensionPoint) {
+    _contributorExtensionPoint = registerExtensionPoint(
+        CONTRIBUTOR_EXTENSION_POINT,
+        _validateDartCompletionContributorExtension);
+  }
+
+  @override
+  void registerExtensions(RegisterExtension registerExtension) {
+    //
+    // Register DartCompletionManager as a CompletionContributor
+    // which delegates to all the DartCompletionContributors
+    //
+    registerExtension(COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
+        () => new DartCompletionManager());
+    //
+    // Register the default DartCompletionContributors
+    //
+    registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
+        () => new ArgListContributor());
+    registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
+        () => new CombinatorContributor());
+    registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
+        () => new KeywordContributor());
+    registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
+        () => new UriContributor());
+  }
+
+  /**
+   * 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/provisional/completion/dart/completion_target.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
index e94016a..0cb0035 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
@@ -86,6 +86,11 @@
  */
 class CompletionTarget {
   /**
+   * The compilation unit in which the completion is occurring.
+   */
+  final CompilationUnit unit;
+
+  /**
    * The context in which the completion is occurring.  This is the AST node
    * which is a direct parent of [entity].
    */
@@ -156,10 +161,12 @@
             // Try to replace with a comment token.
             Token commentToken = _getContainingCommentToken(entity, offset);
             if (commentToken != null) {
-              return new CompletionTarget._(containingNode, commentToken, true);
+              return new CompletionTarget._(
+                  compilationUnit, containingNode, commentToken, true);
             }
             // Target found.
-            return new CompletionTarget._(containingNode, entity, false);
+            return new CompletionTarget._(
+                compilationUnit, containingNode, entity, false);
           } else {
             // Since entity is a token, we don't need to look inside it; just
             // proceed to the next entity.
@@ -189,10 +196,11 @@
                 containingNode = docComment;
               } else {
                 return new CompletionTarget._(
-                    compilationUnit, commentToken, true);
+                    compilationUnit, compilationUnit, commentToken, true);
               }
             }
-            return new CompletionTarget._(containingNode, entity, false);
+            return new CompletionTarget._(
+                compilationUnit, containingNode, entity, false);
           }
 
           // Otherwise, the completion target is somewhere inside the entity,
@@ -216,7 +224,8 @@
 
       // Since no completion target was found, we set the completion target
       // entity to null and use the compilationUnit as the parent.
-      return new CompletionTarget._(compilationUnit, null, false);
+      return new CompletionTarget._(
+          compilationUnit, compilationUnit, null, false);
     }
   }
 
@@ -224,7 +233,8 @@
    * Create a [CompletionTarget] holding the given [containingNode] and
    * [entity].
    */
-  CompletionTarget._(AstNode containingNode, Object entity, this.isCommentText)
+  CompletionTarget._(
+      this.unit, AstNode containingNode, Object entity, this.isCommentText)
       : this.containingNode = containingNode,
         this.entity = entity,
         this.argIndex = _computeArgIndex(containingNode, entity);
diff --git a/pkg/analysis_server/lib/plugin/edit/utilities/change_builder_core.dart b/pkg/analysis_server/lib/src/provisional/edit/utilities/change_builder_core.dart
similarity index 100%
rename from pkg/analysis_server/lib/plugin/edit/utilities/change_builder_core.dart
rename to pkg/analysis_server/lib/src/provisional/edit/utilities/change_builder_core.dart
diff --git a/pkg/analysis_server/lib/plugin/edit/utilities/change_builder_dart.dart b/pkg/analysis_server/lib/src/provisional/edit/utilities/change_builder_dart.dart
similarity index 98%
rename from pkg/analysis_server/lib/plugin/edit/utilities/change_builder_dart.dart
rename to pkg/analysis_server/lib/src/provisional/edit/utilities/change_builder_dart.dart
index 7d0e0c7..1f2c887 100644
--- a/pkg/analysis_server/lib/plugin/edit/utilities/change_builder_dart.dart
+++ b/pkg/analysis_server/lib/src/provisional/edit/utilities/change_builder_dart.dart
@@ -4,7 +4,7 @@
 
 library analysis_server.plugin.edit.utilities.change_builder_dart;
 
-import 'package:analysis_server/plugin/edit/utilities/change_builder_core.dart';
+import 'package:analysis_server/src/provisional/edit/utilities/change_builder_core.dart';
 import 'package:analysis_server/src/utilities/change_builder_dart.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
diff --git a/pkg/analysis_server/lib/plugin/index/index.dart b/pkg/analysis_server/lib/src/provisional/index/index.dart
similarity index 95%
rename from pkg/analysis_server/lib/plugin/index/index.dart
rename to pkg/analysis_server/lib/src/provisional/index/index.dart
index b87fce9..c67feb2 100644
--- a/pkg/analysis_server/lib/plugin/index/index.dart
+++ b/pkg/analysis_server/lib/src/provisional/index/index.dart
@@ -30,8 +30,8 @@
  */
 library analysis_server.plugin.index.index;
 
-import 'package:analysis_server/plugin/index/index_core.dart';
 import 'package:analysis_server/src/plugin/server_plugin.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
 import 'package:plugin/plugin.dart';
 
 /**
diff --git a/pkg/analysis_server/lib/plugin/index/index_core.dart b/pkg/analysis_server/lib/src/provisional/index/index_core.dart
similarity index 100%
rename from pkg/analysis_server/lib/plugin/index/index_core.dart
rename to pkg/analysis_server/lib/src/provisional/index/index_core.dart
diff --git a/pkg/analysis_server/lib/src/search/search_domain.dart b/pkg/analysis_server/lib/src/search/search_domain.dart
index c0650e0..306477d 100644
--- a/pkg/analysis_server/lib/src/search/search_domain.dart
+++ b/pkg/analysis_server/lib/src/search/search_domain.dart
@@ -6,10 +6,10 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/plugin/index/index_core.dart';
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
+import 'package:analysis_server/src/provisional/index/index_core.dart';
 import 'package:analysis_server/src/search/element_references.dart';
 import 'package:analysis_server/src/search/type_hierarchy.dart';
 import 'package:analysis_server/src/services/index/index.dart';
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 1238a1c..27fb203 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -12,6 +12,7 @@
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/plugin/linter_plugin.dart';
 import 'package:analysis_server/src/plugin/server_plugin.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_plugin.dart';
 import 'package:analysis_server/src/server/http_server.dart';
 import 'package:analysis_server/src/server/stdio_server.dart';
 import 'package:analysis_server/src/socket_server.dart';
@@ -409,6 +410,7 @@
     plugins.addAll(_userDefinedPlugins);
     plugins.add(linterPlugin);
     plugins.add(linterServerPlugin);
+    plugins.add(dartCompletionPlugin);
 
     // Defer to the extension manager in AE for plugin registration.
     AnalysisEngine.instance.userDefinedPlugins = plugins;
diff --git a/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart
deleted file mode 100644
index 4f7780d..0000000
--- a/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart
+++ /dev/null
@@ -1,421 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library services.completion.contributor.dart.arglist;
-
-import 'dart:async';
-
-import 'package:analysis_server/src/protocol_server.dart'
-    hide Element, ElementKind;
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analysis_server/src/services/completion/local_declaration_visitor.dart';
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/element.dart';
-import 'package:analyzer/src/generated/scanner.dart';
-import 'package:analyzer/src/generated/utilities_dart.dart';
-
-void _addNamedParameterSuggestion(
-    DartCompletionRequest request, List<String> namedArgs, String name) {
-  if (name != null && name.length > 0 && !namedArgs.contains(name)) {
-    request.addSuggestion(new CompletionSuggestion(
-        CompletionSuggestionKind.NAMED_ARGUMENT,
-        DART_RELEVANCE_NAMED_PARAMETER,
-        '$name: ',
-        name.length + 2,
-        0,
-        false,
-        false));
-  }
-}
-
-/**
- * Determine the number of arguments.
- */
-int _argCount(DartCompletionRequest request) {
-  AstNode node = request.target.containingNode;
-  if (node is ArgumentList) {
-    return node.arguments.length;
-  }
-  return 0;
-}
-
-/**
- * Determine if the completion target is at the end of the list of arguments.
- */
-bool _isAppendingToArgList(DartCompletionRequest request) {
-  AstNode node = request.target.containingNode;
-  if (node is ArgumentList) {
-    var entity = request.target.entity;
-    if (entity == node.rightParenthesis) {
-      return true;
-    }
-    if (node.arguments.length > 0 && node.arguments.last == entity) {
-      return entity is SimpleIdentifier;
-    }
-  }
-  return false;
-}
-
-/**
- * Determine if the completion target is an emtpy argument list.
- */
-bool _isEmptyArgList(DartCompletionRequest request) {
-  AstNode node = request.target.containingNode;
-  return node is ArgumentList &&
-      node.leftParenthesis.next == node.rightParenthesis;
-}
-
-/**
- * Return a collection of currently specified named arguments
- */
-Iterable<String> _namedArgs(DartCompletionRequest request) {
-  AstNode node = request.target.containingNode;
-  List<String> namedArgs = new List<String>();
-  if (node is ArgumentList) {
-    for (Expression arg in node.arguments) {
-      if (arg is NamedExpression) {
-        namedArgs.add(arg.name.label.name);
-      }
-    }
-  }
-  return namedArgs;
-}
-
-/**
- * A contributor for calculating `completion.getSuggestions` request results
- * when the cursor position is inside the arguments to a method call.
- */
-class ArgListContributor extends DartCompletionContributor {
-  _ArgSuggestionBuilder builder;
-
-  @override
-  bool computeFast(DartCompletionRequest request) {
-    builder =
-        request.target.containingNode.accept(new _ArgListAstVisitor(request));
-    return builder == null;
-  }
-
-  @override
-  Future<bool> computeFull(DartCompletionRequest request) {
-    if (builder != null) {
-      return builder.compute(request.target.containingNode);
-    }
-    return new Future.value(false);
-  }
-}
-
-/**
- * A visitor for determining whether an argument list suggestion is needed
- * and instantiating the builder to create the suggestion.
- */
-class _ArgListAstVisitor extends GeneralizingAstVisitor<_ArgSuggestionBuilder> {
-  final DartCompletionRequest request;
-
-  _ArgListAstVisitor(this.request);
-
-  @override
-  _ArgSuggestionBuilder visitArgumentList(ArgumentList node) {
-    Token leftParen = node.leftParenthesis;
-    if (leftParen != null && request.offset > leftParen.offset) {
-      AstNode parent = node.parent;
-      if (parent is MethodInvocation) {
-        SimpleIdentifier selector = parent.methodName;
-        if (selector != null) {
-          String name = selector.name;
-          if (name != null && name.length > 0) {
-            if (parent.operator == null) {
-              /*
-               * If a local declaration is found, then return null
-               * indicating that suggestions were added
-               * and no further action is necessary
-               */
-              if (new _LocalArgSuggestionBuilder(request, request.offset, name)
-                  .visit(node)) {
-                return null;
-              }
-            } else {
-              // determine target
-            }
-            return new _ArgSuggestionBuilder(request, name);
-          }
-        }
-      }
-      String constructorName;
-      if (parent is Annotation && parent.name != null) {
-        constructorName = parent.name.toSource();
-      }
-      if (parent is InstanceCreationExpression &&
-          parent.constructorName != null) {
-        constructorName = parent.constructorName.toSource();
-      }
-      if (constructorName != null && constructorName.length > 0) {
-        if (new _LocalArgSuggestionBuilder(
-            request, request.offset, constructorName).visit(node)) {
-          return null;
-        }
-        return new _ArgSuggestionBuilder(request, constructorName);
-      }
-    }
-    return null;
-  }
-
-  @override
-  _ArgSuggestionBuilder visitNode(AstNode node) {
-    return null;
-  }
-}
-
-/**
- * A [_ArgSuggestionBuilder] determines which method or function is being
- * invoked, then builds the argument list suggestion.
- * This operation is instantiated during `computeFast`
- * and calculates the suggestions during `computeFull`.
- */
-class _ArgSuggestionBuilder {
-  final DartCompletionRequest request;
-  final String methodName;
-
-  _ArgSuggestionBuilder(this.request, this.methodName);
-
-  Future<bool> compute(ArgumentList node) {
-    AstNode parent = node.parent;
-    if (parent is MethodInvocation) {
-      SimpleIdentifier methodName = parent.methodName;
-      if (methodName != null) {
-        Element methodElem = methodName.bestElement;
-        if (methodElem is ExecutableElement) {
-          _addSuggestions(methodElem.parameters);
-        }
-      }
-    }
-    if (parent is InstanceCreationExpression) {
-      ConstructorName constructorName = parent.constructorName;
-      if (constructorName != null) {
-        ConstructorElement element = constructorName.staticElement;
-        if (element is ExecutableElement) {
-          _addSuggestions(element.parameters);
-        }
-      }
-    }
-    return new Future.value(false);
-  }
-
-  void _addArgListSuggestion(Iterable<ParameterElement> requiredParam) {
-    StringBuffer completion = new StringBuffer('(');
-    List<String> paramNames = new List<String>();
-    List<String> paramTypes = new List<String>();
-    for (ParameterElement param in requiredParam) {
-      String name = param.name;
-      if (name != null && name.length > 0) {
-        if (completion.length > 1) {
-          completion.write(', ');
-        }
-        completion.write(name);
-        paramNames.add(name);
-        paramTypes.add(_getParamType(param));
-      }
-    }
-    completion.write(')');
-    CompletionSuggestion suggestion = new CompletionSuggestion(
-        CompletionSuggestionKind.ARGUMENT_LIST,
-        DART_RELEVANCE_HIGH,
-        completion.toString(),
-        completion.length,
-        0,
-        false,
-        false);
-    suggestion.parameterNames = paramNames;
-    suggestion.parameterTypes = paramTypes;
-    request.addSuggestion(suggestion);
-  }
-
-  void _addDefaultParamSuggestions(Iterable<ParameterElement> parameters) {
-    Iterable<String> namedArgs = _namedArgs(request);
-    for (ParameterElement param in parameters) {
-      if (param.parameterKind == ParameterKind.NAMED) {
-        _addNamedParameterSuggestion(request, namedArgs, param.name);
-      }
-    }
-  }
-
-  void _addSuggestions(Iterable<ParameterElement> parameters) {
-    if (parameters == null || parameters.length == 0) {
-      return;
-    }
-    Iterable<ParameterElement> requiredParam = parameters.where(
-        (ParameterElement p) => p.parameterKind == ParameterKind.REQUIRED);
-    int requiredCount = requiredParam.length;
-    if (requiredCount > 0 && _isEmptyArgList(request)) {
-      _addArgListSuggestion(requiredParam);
-      return;
-    }
-    if (_isAppendingToArgList(request)) {
-      if (requiredCount == 0 || requiredCount < _argCount(request)) {
-        _addDefaultParamSuggestions(parameters);
-      }
-    }
-  }
-
-  String _getParamType(ParameterElement param) {
-    DartType type = param.type;
-    if (type != null) {
-      return type.displayName;
-    }
-    return 'dynamic';
-  }
-}
-
-/**
- * [_LocalArgSuggestionBuilder] visits an [AstNode] and its parent recursively
- * looking for a matching declaration. If found, it adds the appropriate
- * suggestions and sets finished to `true`.
- */
-class _LocalArgSuggestionBuilder extends LocalDeclarationVisitor {
-  final DartCompletionRequest request;
-  final String name;
-
-  _LocalArgSuggestionBuilder(this.request, int offset, this.name)
-      : super(offset);
-
-  @override
-  void declaredClass(ClassDeclaration declaration) {
-    String className = null;
-    if (declaration.name != null) {
-      className = declaration.name.name;
-    }
-    if (className != null && className.length > 0) {
-      for (ClassMember member in declaration.members) {
-        if (member is ConstructorDeclaration) {
-          String selector = className;
-          if (member.name != null) {
-            selector = '$selector.${member.name.name}';
-          }
-          if (selector == name) {
-            _addSuggestions(member.parameters);
-            finished();
-          }
-        }
-      }
-    }
-  }
-
-  @override
-  void declaredClassTypeAlias(ClassTypeAlias declaration) {}
-
-  @override
-  void declaredField(FieldDeclaration fieldDecl, VariableDeclaration varDecl) {}
-
-  @override
-  void declaredFunction(FunctionDeclaration declaration) {
-    SimpleIdentifier selector = declaration.name;
-    if (selector != null && name == selector.name) {
-      _addSuggestions(declaration.functionExpression.parameters);
-      finished();
-    }
-  }
-
-  @override
-  void declaredFunctionTypeAlias(FunctionTypeAlias declaration) {}
-
-  @override
-  void declaredLabel(Label label, bool isCaseLabel) {}
-
-  @override
-  void declaredLocalVar(SimpleIdentifier name, TypeName type) {}
-
-  @override
-  void declaredMethod(MethodDeclaration declaration) {
-    SimpleIdentifier selector = declaration.name;
-    if (selector != null && name == selector.name) {
-      _addSuggestions(declaration.parameters);
-      finished();
-    }
-  }
-
-  @override
-  void declaredParam(SimpleIdentifier name, TypeName type) {}
-
-  @override
-  void declaredTopLevelVar(
-      VariableDeclarationList varList, VariableDeclaration varDecl) {}
-
-  void _addArgListSuggestion(Iterable<FormalParameter> requiredParam) {
-    StringBuffer completion = new StringBuffer('(');
-    List<String> paramNames = new List<String>();
-    List<String> paramTypes = new List<String>();
-    for (FormalParameter param in requiredParam) {
-      SimpleIdentifier paramId = param.identifier;
-      if (paramId != null) {
-        String name = paramId.name;
-        if (name != null && name.length > 0) {
-          if (completion.length > 1) {
-            completion.write(', ');
-          }
-          completion.write(name);
-          paramNames.add(name);
-          paramTypes.add(_getParamType(param));
-        }
-      }
-    }
-    completion.write(')');
-    CompletionSuggestion suggestion = new CompletionSuggestion(
-        CompletionSuggestionKind.ARGUMENT_LIST,
-        DART_RELEVANCE_HIGH,
-        completion.toString(),
-        completion.length,
-        0,
-        false,
-        false);
-    suggestion.parameterNames = paramNames;
-    suggestion.parameterTypes = paramTypes;
-    request.addSuggestion(suggestion);
-  }
-
-  void _addDefaultParamSuggestions(FormalParameterList parameters) {
-    Iterable<String> namedArgs = _namedArgs(request);
-    for (FormalParameter param in parameters.parameters) {
-      if (param.kind == ParameterKind.NAMED) {
-        SimpleIdentifier paramId = param.identifier;
-        if (paramId != null) {
-          _addNamedParameterSuggestion(request, namedArgs, paramId.name);
-        }
-      }
-    }
-  }
-
-  void _addSuggestions(FormalParameterList parameters) {
-    if (parameters == null || parameters.parameters.length == 0) {
-      return;
-    }
-    Iterable<FormalParameter> requiredParam = parameters.parameters
-        .where((FormalParameter p) => p.kind == ParameterKind.REQUIRED);
-    int requiredCount = requiredParam.length;
-    if (requiredCount > 0 && _isEmptyArgList(request)) {
-      _addArgListSuggestion(requiredParam);
-      return;
-    }
-    if (_isAppendingToArgList(request)) {
-      if (requiredCount == 0 || requiredCount < _argCount(request)) {
-        _addDefaultParamSuggestions(parameters);
-      }
-    }
-  }
-
-  String _getParamType(FormalParameter param) {
-    TypeName type;
-    if (param is SimpleFormalParameter) {
-      type = param.type;
-    }
-    if (type != null) {
-      Identifier id = type.name;
-      if (id != null) {
-        String name = id.name;
-        if (name != null && name.length > 0) {
-          return name;
-        }
-      }
-    }
-    return 'dynamic';
-  }
-}
diff --git a/pkg/analysis_server/lib/src/services/completion/combinator_contributor.dart b/pkg/analysis_server/lib/src/services/completion/combinator_contributor.dart
deleted file mode 100644
index a8ef022..0000000
--- a/pkg/analysis_server/lib/src/services/completion/combinator_contributor.dart
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library services.completion.contributor.dart.combinator;
-
-import 'dart:async';
-
-import 'package:analysis_server/src/protocol_server.dart'
-    hide Element, ElementKind;
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analysis_server/src/services/completion/suggestion_builder.dart';
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/element.dart';
-
-/**
- * A contributor for calculating `completion.getSuggestions` request results
- * for the import combinators show and hide.
- */
-class CombinatorContributor extends DartCompletionContributor {
-  _CombinatorSuggestionBuilder builder;
-
-  @override
-  bool computeFast(DartCompletionRequest request) {
-    builder = request.target.containingNode
-        .accept(new _CombinatorAstVisitor(request));
-    return builder == null;
-  }
-
-  @override
-  Future<bool> computeFull(DartCompletionRequest request) {
-    if (builder != null) {
-      return builder.execute(request.target.containingNode);
-    }
-    return new Future.value(false);
-  }
-}
-
-/**
- * A visitor for determining which imported classes and top level variables
- * should be suggested and building those suggestions.
- */
-class _CombinatorAstVisitor
-    extends GeneralizingAstVisitor<_CombinatorSuggestionBuilder> {
-  final DartCompletionRequest request;
-
-  _CombinatorAstVisitor(this.request);
-
-  @override
-  _CombinatorSuggestionBuilder visitCombinator(Combinator node) {
-    return new _CombinatorSuggestionBuilder(
-        request, CompletionSuggestionKind.IDENTIFIER);
-  }
-
-  @override
-  _CombinatorSuggestionBuilder visitNode(AstNode node) {
-    return null;
-  }
-}
-
-/**
- * A `_CombinatorSuggestionBuilder` determines which imported classes
- * and top level variables should be suggested and builds those suggestions.
- * This operation is instantiated during `computeFast`
- * and calculates the suggestions during `computeFull`.
- */
-class _CombinatorSuggestionBuilder extends LibraryElementSuggestionBuilder {
-  _CombinatorSuggestionBuilder(
-      DartCompletionRequest request, CompletionSuggestionKind kind)
-      : super(request, kind, false, false);
-
-  Future<bool> execute(AstNode node) {
-    var directive = node.getAncestor((parent) => parent is NamespaceDirective);
-    if (directive is NamespaceDirective) {
-      LibraryElement library = directive.uriElement;
-      if (library != null) {
-        library.visitChildren(this);
-      }
-    }
-    return new Future.value(false);
-  }
-}
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_core.dart b/pkg/analysis_server/lib/src/services/completion/completion_core.dart
index 68fa732..b65f4bf 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_core.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_core.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 analysis_server.src.services.completion.completion_dart;
+library analysis_server.src.services.completion.completion_core;
 
 import 'package:analysis_server/src/provisional/completion/completion_core.dart';
+import 'package:analysis_server/src/services/search/search_engine.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -13,29 +14,24 @@
  * The information about a requested list of completions.
  */
 class CompletionRequestImpl implements CompletionRequest {
-  /**
-   * The analysis context in which the completion is being requested.
-   */
-  AnalysisContext context;
+  @override
+  final AnalysisContext context;
 
-  /**
-   * The resource provider associated with this request.
-   */
-  ResourceProvider resourceProvider;
+  @override
+  final Source source;
 
-  /**
-   * The source in which the completion is being requested.
-   */
-  Source source;
+  @override
+  final int offset;
 
-  /**
-   * The offset within the source at which the completion is being requested.
-   */
-  int offset;
+  @override
+  final ResourceProvider resourceProvider;
+
+  @override
+  final SearchEngine searchEngine;
 
   /**
    * Initialize a newly created completion request based on the given arguments.
    */
-  CompletionRequestImpl(
-      this.context, this.resourceProvider, this.source, this.offset);
+  CompletionRequestImpl(this.context, this.resourceProvider, this.searchEngine,
+      this.source, this.offset);
 }
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_dart.dart b/pkg/analysis_server/lib/src/services/completion/completion_dart.dart
deleted file mode 100644
index 1cfff04..0000000
--- a/pkg/analysis_server/lib/src/services/completion/completion_dart.dart
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library analysis_server.src.services.completion.completion_dart;
-
-import 'package:analysis_server/src/provisional/completion/completion_core.dart';
-import 'package:analysis_server/src/provisional/completion/completion_dart.dart';
-import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
-import 'package:analysis_server/src/services/completion/completion_core.dart';
-import 'package:analyzer/src/generated/ast.dart';
-
-/**
- * The information about a requested list of completions within a Dart file.
- */
-class DartCompletionRequestImpl extends CompletionRequestImpl
-    implements DartCompletionRequest {
-  /**
-   * The compilation unit in which the completion was requested.
-   */
-  final CompilationUnit unit;
-
-  /**
-   * A flag indicating whether the compilation [unit] is resolved.
-   */
-  final bool isResolved;
-
-  /**
-   * The completion target.  This determines what part of the parse tree
-   * will receive the newly inserted text.
-   */
-  final CompletionTarget target;
-
-  /**
-   * Initialize a newly created completion request based on the given arguments.
-   */
-  DartCompletionRequestImpl(
-      CompletionRequest request, this.unit, this.isResolved, this.target)
-      : super(request.context, request.resourceProvider, request.source,
-            request.offset);
-}
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
index 2ba4340..c559a80 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
@@ -7,12 +7,10 @@
 import 'dart:async';
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/provisional/completion/completion_core.dart'
-    show CompletionRequest, CompletionResult;
+    show CompletionContributor, CompletionContributorFactory, CompletionRequest, CompletionResult;
 import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
-import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
 
@@ -59,14 +57,14 @@
    * Create a manager for the given request.
    */
   factory CompletionManager.create(
-      AnalysisContext context, Source source, SearchEngine searchEngine) {
+      AnalysisContext context,
+      Source source,
+      SearchEngine searchEngine,
+      Iterable<CompletionContributor> newContributors) {
     if (context != null) {
       if (AnalysisEngine.isDartFileName(source.shortName)) {
-        return new DartCompletionManager.create(context, searchEngine, source);
-      }
-      if (AnalysisEngine.isHtmlFileName(source.shortName)) {
-        //TODO (danrubel) implement
-//        return new HtmlCompletionManager(context, searchEngine, source, offset);
+        return new DartCompletionManager.create(
+            context, searchEngine, source, newContributors);
       }
     }
     return new NoOpCompletionManager(source);
@@ -217,30 +215,6 @@
 }
 
 /**
- * Encapsulates information specific to a particular completion request.
- */
-class CompletionRequestImpl implements CompletionRequest {
-  /**
-   * The underlying analysis server for this completion request.
-   */
-  final AnalysisServer server;
-
-  @override
-  final AnalysisContext context;
-
-  @override
-  final Source source;
-
-  @override
-  final int offset;
-
-  CompletionRequestImpl(this.server, this.context, this.source, this.offset);
-
-  @override
-  ResourceProvider get resourceProvider => server.resourceProvider;
-}
-
-/**
  * Code completion result generated by an [CompletionManager].
  */
 class CompletionResultImpl implements CompletionResult {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
new file mode 100644
index 0000000..46e20aa
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
@@ -0,0 +1,242 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library services.completion.contributor.dart.arglist;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/protocol_server.dart'
+    hide Element, ElementKind;
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+
+/**
+ * Determine the number of arguments.
+ */
+int _argCount(DartCompletionRequest request) {
+  AstNode node = request.target.containingNode;
+  if (node is ArgumentList) {
+    return node.arguments.length;
+  }
+  return 0;
+}
+
+String _getParamType(ParameterElement param) {
+  DartType type = param.type;
+  if (type != null) {
+    return type.displayName;
+  }
+  return 'dynamic';
+}
+
+/**
+ * If the containing [node] is an argument list
+ * or named expression in an argument list
+ * then return the simple identifier for the method, constructor, or annotation
+ * to which the argument list is associated
+ */
+SimpleIdentifier _getTargetId(AstNode node) {
+  if (node is NamedExpression) {
+    return _getTargetId(node.parent);
+  }
+  if (node is ArgumentList) {
+    AstNode parent = node.parent;
+    if (parent is MethodInvocation) {
+      return parent.methodName;
+    }
+    if (parent is InstanceCreationExpression) {
+      ConstructorName constructorName = parent.constructorName;
+      if (constructorName != null) {
+        if (constructorName.name != null) {
+          return constructorName.name;
+        }
+        Identifier typeName = constructorName.type.name;
+        if (typeName is SimpleIdentifier) {
+          return typeName;
+        }
+        if (typeName is PrefixedIdentifier) {
+          return typeName.identifier;
+        }
+      }
+    }
+    if (parent is Annotation) {
+      return parent.constructorName ?? parent.name;
+    }
+  }
+  return null;
+}
+
+/**
+ * Determine if the completion target is at the end of the list of arguments.
+ */
+bool _isAppendingToArgList(DartCompletionRequest request) {
+  AstNode node = request.target.containingNode;
+  if (node is ArgumentList) {
+    var entity = request.target.entity;
+    if (entity == node.rightParenthesis) {
+      return true;
+    }
+    if (node.arguments.length > 0 && node.arguments.last == entity) {
+      return entity is SimpleIdentifier;
+    }
+  }
+  return false;
+}
+
+/**
+ * Determine if the completion target is an emtpy argument list.
+ */
+bool _isEmptyArgList(DartCompletionRequest request) {
+  AstNode node = request.target.containingNode;
+  return node is ArgumentList &&
+      node.leftParenthesis.next == node.rightParenthesis;
+}
+
+/**
+ * Return a collection of currently specified named arguments
+ */
+Iterable<String> _namedArgs(DartCompletionRequest request) {
+  AstNode node = request.target.containingNode;
+  List<String> namedArgs = new List<String>();
+  if (node is ArgumentList) {
+    for (Expression arg in node.arguments) {
+      if (arg is NamedExpression) {
+        namedArgs.add(arg.name.label.name);
+      }
+    }
+  }
+  return namedArgs;
+}
+
+/**
+ * A contributor for calculating `completion.getSuggestions` request results
+ * when the cursor position is inside the arguments to a method call.
+ */
+class ArgListContributor extends DartCompletionContributor {
+  DartCompletionRequest request;
+  List<CompletionSuggestion> suggestions;
+
+  @override
+  Future<List<CompletionSuggestion>> computeSuggestions(
+      DartCompletionRequest request) async {
+    this.request = request;
+    this.suggestions = <CompletionSuggestion>[];
+
+    // Determine if the target is in an argument list
+    // for a method or a constructor or an annotation
+    // and resolve the identifier
+    SimpleIdentifier targetId = _getTargetId(request.target.containingNode);
+    if (targetId == null) {
+      return EMPTY_LIST;
+    }
+
+    // Resolve the target expression to determine the arguments
+    await request.resolveIdentifier(targetId);
+    // Gracefully degrade if the element could not be resolved
+    // e.g. target changed, completion aborted
+    targetId = _getTargetId(request.target.containingNode);
+    if (targetId == null) {
+      return EMPTY_LIST;
+    }
+    Element elem = targetId.bestElement;
+    if (elem == null) {
+      return EMPTY_LIST;
+    }
+
+    // Generate argument list suggestion based upon the type of element
+    if (elem is ClassElement) {
+      for (ConstructorElement constructor in elem.constructors) {
+        if (!constructor.isFactory) {
+          _addSuggestions(constructor.parameters);
+          return suggestions;
+        }
+      }
+    }
+    if (elem is ConstructorElement) {
+      _addSuggestions(elem.parameters);
+      return suggestions;
+    }
+    if (elem is FunctionElement) {
+      _addSuggestions(elem.parameters);
+      return suggestions;
+    }
+    if (elem is MethodElement) {
+      _addSuggestions(elem.parameters);
+      return suggestions;
+    }
+    return EMPTY_LIST;
+  }
+
+  void _addArgListSuggestion(Iterable<ParameterElement> requiredParam) {
+    StringBuffer completion = new StringBuffer('(');
+    List<String> paramNames = new List<String>();
+    List<String> paramTypes = new List<String>();
+    for (ParameterElement param in requiredParam) {
+      String name = param.name;
+      if (name != null && name.length > 0) {
+        if (completion.length > 1) {
+          completion.write(', ');
+        }
+        completion.write(name);
+        paramNames.add(name);
+        paramTypes.add(_getParamType(param));
+      }
+    }
+    completion.write(')');
+    CompletionSuggestion suggestion = new CompletionSuggestion(
+        CompletionSuggestionKind.ARGUMENT_LIST,
+        DART_RELEVANCE_HIGH,
+        completion.toString(),
+        completion.length,
+        0,
+        false,
+        false);
+    suggestion.parameterNames = paramNames;
+    suggestion.parameterTypes = paramTypes;
+    suggestions.add(suggestion);
+  }
+
+  void _addDefaultParamSuggestions(Iterable<ParameterElement> parameters) {
+    Iterable<String> namedArgs = _namedArgs(request);
+    for (ParameterElement param in parameters) {
+      if (param.parameterKind == ParameterKind.NAMED) {
+        _addNamedParameterSuggestion(request, namedArgs, param.name);
+      }
+    }
+  }
+
+  void _addNamedParameterSuggestion(
+      DartCompletionRequest request, List<String> namedArgs, String name) {
+    if (name != null && name.length > 0 && !namedArgs.contains(name)) {
+      suggestions.add(new CompletionSuggestion(
+          CompletionSuggestionKind.NAMED_ARGUMENT,
+          DART_RELEVANCE_NAMED_PARAMETER,
+          '$name: ',
+          name.length + 2,
+          0,
+          false,
+          false));
+    }
+  }
+
+  void _addSuggestions(Iterable<ParameterElement> parameters) {
+    if (parameters == null || parameters.length == 0) {
+      return;
+    }
+    Iterable<ParameterElement> requiredParam = parameters.where(
+        (ParameterElement p) => p.parameterKind == ParameterKind.REQUIRED);
+    int requiredCount = requiredParam.length;
+    if (requiredCount > 0 && _isEmptyArgList(request)) {
+      _addArgListSuggestion(requiredParam);
+      return;
+    }
+    if (_isAppendingToArgList(request)) {
+      if (requiredCount == 0 || requiredCount < _argCount(request)) {
+        _addDefaultParamSuggestions(parameters);
+      }
+    }
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/combinator_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/combinator_contributor.dart
new file mode 100644
index 0000000..cba3bd4
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/combinator_contributor.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library services.completion.contributor.dart.combinator;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/protocol_server.dart'
+    hide Element, ElementKind;
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+
+/**
+ * A contributor for calculating `completion.getSuggestions` request results
+ * for the import combinators show and hide.
+ */
+class CombinatorContributor extends DartCompletionContributor {
+  @override
+  Future<List<CompletionSuggestion>> computeSuggestions(
+      DartCompletionRequest request) async {
+    AstNode node = request.target.containingNode;
+    if (node is! Combinator) {
+      return EMPTY_LIST;
+    }
+
+    // Partially resolve the compilation unit
+    CompilationUnit unit = await request.resolveDeclarationsInScope();
+    // Gracefully degrade if the compilation unit could not be resolved
+    // e.g. detached part file or source change
+    if (unit == null) {
+      return EMPTY_LIST;
+    }
+
+    // Check the target since resolution may have changed it
+    node = request.target.containingNode;
+    if (node is! Combinator) {
+      return EMPTY_LIST;
+    }
+
+    // Build list of suggestions
+    var directive = node.getAncestor((parent) => parent is NamespaceDirective);
+    if (directive is NamespaceDirective) {
+      LibraryElement library = directive.uriElement;
+      if (library != null) {
+        LibraryElementSuggestionBuilder builder =
+            new LibraryElementSuggestionBuilder(
+                request, CompletionSuggestionKind.IDENTIFIER, false, false);
+        library.visitChildren(builder);
+        return builder.suggestions;
+      }
+    }
+    return EMPTY_LIST;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart b/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.dart
similarity index 90%
rename from pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart
rename to pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.dart
index 7351ad0..fde8bfb 100644
--- a/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.dart
@@ -2,30 +2,31 @@
 // 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 services.completion.computer.dart.relevance;
+library services.completion.dart.sorter.common;
+
+import 'dart:async';
 
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
 import 'package:analysis_server/src/protocol_server.dart'
     show CompletionSuggestion, CompletionSuggestionKind;
-import 'package:analysis_server/src/provisional/completion/completion_dart.dart';
-import 'package:analysis_server/src/services/completion/contribution_sorter.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
+import 'package:analysis_server/src/services/completion/dart/contribution_sorter.dart';
 import 'package:analysis_server/src/services/completion/dart_completion_manager.dart'
     show DART_RELEVANCE_COMMON_USAGE;
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
-import 'package:analysis_server/src/provisional/completion/completion_core.dart';
-import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
-import 'package:analyzer/task/dart.dart';
 import 'package:analyzer/src/task/dart.dart';
+import 'package:analyzer/task/dart.dart';
 
-part 'common_usage_generated.dart';
+part 'common_usage_sorter.g.dart';
 
 /**
  * A computer for adjusting the relevance of completions computed by others
  * based upon common Dart usage patterns. This is a long-lived object
  * that should not maintain state between calls to it's [sort] method.
  */
-class CommonUsageComputer implements ContributionSorter {
+class CommonUsageSorter implements DartContributionSorter {
   /**
    * A map of <library>.<classname> to an ordered list of method names,
    * field names, getter names, and named constructors.
@@ -34,13 +35,13 @@
    */
   Map<String, List<String>> selectorRelevance;
 
-  CommonUsageComputer([this.selectorRelevance = defaultSelectorRelevance]);
+  CommonUsageSorter([this.selectorRelevance = defaultSelectorRelevance]);
 
   @override
-  AnalysisRequest sort(
-      CompletionRequest request, Iterable<CompletionSuggestion> suggestions) {
+  Future sort(CompletionRequest request,
+      Iterable<CompletionSuggestion> suggestions) {
     _update(request, suggestions);
-    return null;
+    return new Future.value();
   }
 
   CompletionTarget _getCompletionTarget(CompletionRequest request) {
diff --git a/pkg/analysis_server/lib/src/services/completion/common_usage_generated.dart b/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.g.dart
similarity index 99%
rename from pkg/analysis_server/lib/src/services/completion/common_usage_generated.dart
rename to pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.g.dart
index f6899ec..f065701 100644
--- a/pkg/analysis_server/lib/src/services/completion/common_usage_generated.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.g.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.
 
-part of services.completion.computer.dart.relevance;
+part of services.completion.dart.sorter.common;
 
 // Auto-generated, please do not edit.
 
@@ -424,4 +424,4 @@
 'dart.dom.html.Css': const ['supports',],
 'dart.io.IOException': const ['toString',],
 'dart.dom.html.ButtonInputElement': const ['value','onClick',],
-};
\ No newline at end of file
+};
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
new file mode 100644
index 0000000..6f182d8
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
@@ -0,0 +1,185 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library services.completion.dart.manager;
+
+import 'dart:async';
+
+import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart'
+    show CompletionContributor, CompletionRequest;
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_plugin.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
+import 'package:analysis_server/src/services/completion/completion_core.dart';
+import 'package:analysis_server/src/services/search/search_engine.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/context/context.dart'
+    show AnalysisFutureHelper, AnalysisContextImpl;
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/engine.dart' hide AnalysisContextImpl;
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/task/dart.dart';
+import 'package:analyzer/task/dart.dart';
+
+/**
+ * [DartCompletionManager] determines if a completion request is Dart specific
+ * and forwards those requests to all [DartCompletionContributor]s.
+ */
+class DartCompletionManager implements CompletionContributor {
+  @override
+  Future<List<CompletionSuggestion>> computeSuggestions(
+      CompletionRequest request) {
+    if (AnalysisEngine.isDartFileName(request.source.shortName)) {
+      return _computeDartSuggestions(
+          new DartCompletionRequestImpl.forRequest(request));
+    }
+    return new Future.value();
+  }
+
+  /**
+   * Return a [Future] that completes with a list of suggestions
+   * for the given completion [request].
+   */
+  Future<List<CompletionSuggestion>> _computeDartSuggestions(
+      DartCompletionRequest request) async {
+    // Request Dart specific completions from each contributor
+    List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
+    for (DartCompletionContributor c in dartCompletionPlugin.contributors) {
+      suggestions.addAll(await c.computeSuggestions(request));
+    }
+    return suggestions;
+  }
+}
+
+/**
+ * The information about a requested list of completions within a Dart file.
+ */
+class DartCompletionRequestImpl extends CompletionRequestImpl
+    implements DartCompletionRequest {
+  /**
+   * The cached completion target or `null` if not computed yet.
+   */
+  CompletionTarget _target;
+
+  /**
+   * `true` if [resolveDeclarationsInScope] has partially resolved the unit
+   * referenced by [target], else `false`.
+   */
+  bool _haveResolveDeclarationsInScope = false;
+
+  /**
+   * Initialize a newly created completion request based on the given request.
+   */
+  factory DartCompletionRequestImpl.forRequest(CompletionRequest request) {
+    return new DartCompletionRequestImpl._(
+        request.context,
+        request.resourceProvider,
+        request.searchEngine,
+        request.source,
+        request.offset);
+  }
+
+  DartCompletionRequestImpl._(
+      AnalysisContext context,
+      ResourceProvider resourceProvider,
+      SearchEngine searchEngine,
+      Source source,
+      int offset)
+      : super(context, resourceProvider, searchEngine, source, offset);
+
+  @override
+  CompletionTarget get target {
+    if (_target == null) {
+      CompilationUnit unit = context.computeResult(source, PARSED_UNIT);
+      _target = new CompletionTarget.forOffset(unit, offset);
+    }
+    return _target;
+  }
+
+  @override
+  Future<CompilationUnit> resolveDeclarationsInScope() async {
+    CompilationUnit unit = target.unit;
+    if (_haveResolveDeclarationsInScope) {
+      return unit;
+    }
+
+    // Determine the library source
+    Source librarySource;
+    if (unit.directives.any((d) => d is PartOfDirective)) {
+      List<Source> libraries = context.getLibrariesContaining(source);
+      if (libraries.isEmpty) {
+        return null;
+      }
+      librarySource = libraries[0];
+    } else {
+      librarySource = source;
+    }
+
+    // Resolve declarations in the target unit
+    CompilationUnit resolvedUnit =
+        await new AnalysisFutureHelper<CompilationUnit>(
+            context,
+            new LibrarySpecificUnit(librarySource, source),
+            RESOLVED_UNIT3).computeAsync();
+
+    // TODO(danrubel) determine if the underlying source has been modified
+    // in a way that invalidates the completion request
+    // and return null
+
+    // Gracefully degrade if unit cannot be resolved
+    if (resolvedUnit == null) {
+      return null;
+    }
+
+    // Recompute the target for the newly resolved unit
+    _target = new CompletionTarget.forOffset(resolvedUnit, offset);
+    _haveResolveDeclarationsInScope = true;
+    return resolvedUnit;
+  }
+
+  @override
+  Future resolveIdentifier(SimpleIdentifier identifier) async {
+    if (identifier.bestElement != null) {
+      return;
+    }
+
+    //TODO(danrubel) resolve the expression or containing method
+    // rather than the entire complilation unit
+
+    CompilationUnit unit = target.unit;
+
+    // Determine the library source
+    Source librarySource;
+    if (unit.directives.any((d) => d is PartOfDirective)) {
+      List<Source> libraries = context.getLibrariesContaining(source);
+      if (libraries.isEmpty) {
+        return;
+      }
+      librarySource = libraries[0];
+    } else {
+      librarySource = source;
+    }
+
+    // Resolve declarations in the target unit
+    CompilationUnit resolvedUnit =
+        await new AnalysisFutureHelper<CompilationUnit>(
+            context,
+            new LibrarySpecificUnit(librarySource, source),
+            RESOLVED_UNIT).computeAsync();
+
+    // TODO(danrubel) determine if the underlying source has been modified
+    // in a way that invalidates the completion request
+    // and return null
+
+    // Gracefully degrade if unit cannot be resolved
+    if (resolvedUnit == null) {
+      return;
+    }
+
+    // Recompute the target for the newly resolved unit
+    _target = new CompletionTarget.forOffset(resolvedUnit, offset);
+    _haveResolveDeclarationsInScope = true;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/contribution_sorter.dart b/pkg/analysis_server/lib/src/services/completion/dart/contribution_sorter.dart
similarity index 64%
rename from pkg/analysis_server/lib/src/services/completion/contribution_sorter.dart
rename to pkg/analysis_server/lib/src/services/completion/dart/contribution_sorter.dart
index cc7b457..8279be3 100644
--- a/pkg/analysis_server/lib/src/services/completion/contribution_sorter.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/contribution_sorter.dart
@@ -2,26 +2,25 @@
 // 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 services.completion.sorter;
+library services.completion.dart.sorter;
+
+import 'dart:async';
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/provisional/completion/completion_dart.dart';
 import 'package:analysis_server/src/provisional/completion/completion_core.dart';
 
 /**
- * The abstract class `ContributionSorter` defines the behavior of objects
+ * The abstract class [DartContributionSorter] defines the behavior of objects
  * that are used to adjust the relevance of an existing list of suggestions.
  * This is a long-lived object that should not maintain state between
  * calls to it's [sort] method.
  */
-abstract class ContributionSorter {
+abstract class DartContributionSorter {
   /**
    * After [CompletionSuggestion]s have been computed,
    * this method is called to adjust the relevance of those suggestions.
-   * Return an [AnalysisRequest] if more analysis is needed,
-   * or `null` if suggestion sorting is complete.
-   * This method should execute quickly and not block.
+   * Return a [Future] that completes when the suggestions have been updated.
    */
-  AnalysisRequest sort(
+  Future sort(
       CompletionRequest request, Iterable<CompletionSuggestion> suggestions);
 }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/inherited_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/inherited_contributor.dart
new file mode 100644
index 0000000..fdfb353
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/inherited_contributor.dart
@@ -0,0 +1,171 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library services.completion.dart.invocation;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/protocol_server.dart'
+    show CompletionSuggestion, CompletionSuggestionKind, SourceChange;
+import 'package:analysis_server/src/protocol_server.dart' as protocol
+    hide CompletionSuggestion, CompletionSuggestionKind;
+import 'package:analysis_server/src/provisional/completion/completion_core.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+/**
+ * A completion contributor used to suggest replacing partial identifiers inside
+ * a class declaration with templates for inherited members.
+ */
+class InheritedContributor implements DartCompletionContributor {
+  @override
+  Future<List<CompletionSuggestion>> computeSuggestions(
+      DartCompletionRequest request) async {
+    // Determine if the target looks like a partial identifier
+    // inside a class declaration
+    SimpleIdentifier targetId = _getTargetId(request.target);
+    if (targetId == null) {
+      return EMPTY_LIST;
+    }
+
+    // Partially resolve the compilation unit
+    CompilationUnit unit = await request.resolveDeclarationsInScope();
+    // Gracefully degrade if the compilation unit could not be resolved
+    // e.g. detached part file or source change
+    if (unit == null) {
+      return EMPTY_LIST;
+    }
+
+    // Recompute the target since resolution may have changed it
+    targetId = _getTargetId(request.target);
+    if (targetId == null) {
+      return EMPTY_LIST;
+    }
+    ClassDeclaration classDecl =
+        targetId.getAncestor((p) => p is ClassDeclaration);
+    if (classDecl == null) {
+      return EMPTY_LIST;
+    }
+
+    // Generate a collection of inherited members
+    ClassElement classElem = classDecl.element;
+    InheritanceManager manager = new InheritanceManager(classElem.library);
+    MemberMap map = manager.getMapOfMembersInheritedFromInterfaces(classElem);
+    List<String> memberNames = _computeMemberNames(map, classElem);
+
+    // Build suggestions
+    List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
+    for (String memberName in memberNames) {
+      ExecutableElement element = map.get(memberName);
+      // Gracefully degrade if the overridden element has not been resolved.
+      if (element.returnType != null) {
+        CompletionSuggestion suggestion =
+            _buildSuggestion(request, targetId, unit, element);
+        if (suggestion != null) {
+          suggestions.add(suggestion);
+        }
+      }
+    }
+    return suggestions;
+  }
+
+  /**
+   * If the target looks like a partial identifier inside a class declaration
+   * then return that identifier, otherwise return `null`.
+   */
+  SimpleIdentifier _getTargetId(CompletionTarget target) {
+    AstNode node = target.containingNode;
+    if (node is ClassDeclaration) {
+      Object entity = target.entity;
+      if (entity is FieldDeclaration) {
+        NodeList<VariableDeclaration> variables = entity.fields.variables;
+        if (variables.length == 1) {
+          SimpleIdentifier targetId = variables[0].name;
+          if (targetId.name.isEmpty) {
+            return targetId;
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Return a template for an override of the given [element] in the given
+   * [source]. If selected, the template will replace [targetId].
+   */
+  String _buildRepacementText(Source source, SimpleIdentifier targetId,
+      CompilationUnit unit, ExecutableElement element) {
+    // AnalysisContext context = element.context;
+    // Inject partially resolved unit for use by change builder
+    // DartChangeBuilder builder = new DartChangeBuilder(context, unit);
+    // builder.addFileEdit(source, context.getModificationStamp(source),
+    //     (DartFileEditBuilder builder) {
+    //   builder.addReplacement(targetId.offset, targetId.length,
+    //       (DartEditBuilder builder) {
+    //     builder.writeOverrideOfInheritedMember(element);
+    //   });
+    // });
+    // return builder.sourceChange.edits[0].edits[0].replacement.trim();
+    return '';
+  }
+
+  /**
+   * Build a suggestion to replace [targetId] in the given [unit]
+   * with an override of the given [element].
+   */
+  CompletionSuggestion _buildSuggestion(
+      DartCompletionRequest request,
+      SimpleIdentifier targetId,
+      CompilationUnit unit,
+      ExecutableElement element) {
+    String completion =
+        _buildRepacementText(request.source, targetId, unit, element);
+    if (completion == null || completion.length == 0) {
+      return null;
+    }
+    CompletionSuggestion suggestion = new CompletionSuggestion(
+        CompletionSuggestionKind.IDENTIFIER,
+        DART_RELEVANCE_HIGH,
+        completion,
+        targetId.offset,
+        0,
+        element.isDeprecated,
+        false);
+    suggestion.element = protocol.convertElement(element);
+    return suggestion;
+  }
+
+  /**
+   * Return a list containing the names of all of the inherited but not
+   * implemented members of the class represented by the given [element].
+   * The [map] is used to find all of the members that are inherited.
+   */
+  List<String> _computeMemberNames(MemberMap map, ClassElement element) {
+    List<String> memberNames = <String>[];
+    int count = map.size;
+    for (int i = 0; i < count; i++) {
+      String memberName = map.getKey(i);
+      if (!_hasMember(element, memberName)) {
+        memberNames.add(memberName);
+      }
+    }
+    return memberNames;
+  }
+
+  /**
+   * Return `true` if the given [classElement] directly declares a member with
+   * the given [memberName].
+   */
+  bool _hasMember(ClassElement classElement, String memberName) {
+    return classElement.getField(memberName) != null ||
+        classElement.getGetter(memberName) != null ||
+        classElement.getMethod(memberName) != null ||
+        classElement.getSetter(memberName) != null;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
similarity index 94%
rename from pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart
rename to pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
index 0da2c8c..57beb27 100644
--- a/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
@@ -3,12 +3,12 @@
 // 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 services.completion.contributor.dart.keyword;
+library services.completion.dart.keyword;
 
 import 'dart:async';
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/scanner.dart';
 
@@ -21,16 +21,15 @@
  */
 class KeywordContributor extends DartCompletionContributor {
   @override
-  bool computeFast(DartCompletionRequest request) {
-    if (!request.target.isCommentText) {
-      request.target.containingNode.accept(new _KeywordVisitor(request));
+  Future<List<CompletionSuggestion>> computeSuggestions(
+      DartCompletionRequest request) async {
+    if (request.target.isCommentText) {
+      return EMPTY_LIST;
     }
-    return true;
-  }
-
-  @override
-  Future<bool> computeFull(DartCompletionRequest request) {
-    return new Future.value(false);
+    List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
+    request.target.containingNode
+        .accept(new _KeywordVisitor(request, suggestions));
+    return suggestions;
   }
 }
 
@@ -40,8 +39,9 @@
 class _KeywordVisitor extends GeneralizingAstVisitor {
   final DartCompletionRequest request;
   final Object entity;
+  final List<CompletionSuggestion> suggestions;
 
-  _KeywordVisitor(DartCompletionRequest request)
+  _KeywordVisitor(DartCompletionRequest request, this.suggestions)
       : this.request = request,
         this.entity = request.target.entity;
 
@@ -468,14 +468,8 @@
     if (offset == null) {
       offset = completion.length;
     }
-    request.addSuggestion(new CompletionSuggestion(
-        CompletionSuggestionKind.KEYWORD,
-        relevance,
-        completion,
-        offset,
-        0,
-        false,
-        false));
+    suggestions.add(new CompletionSuggestion(CompletionSuggestionKind.KEYWORD,
+        relevance, completion, offset, 0, false, false));
   }
 
   void _addSuggestions(List<Keyword> keywords,
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
new file mode 100644
index 0000000..fa0cf95
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
@@ -0,0 +1,262 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library services.completion.dart.suggestion.builder;
+
+import 'package:analysis_server/src/protocol_server.dart' as protocol;
+import 'package:analysis_server/src/protocol_server.dart'
+    hide Element, ElementKind;
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:path/path.dart' as path;
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+
+const String DYNAMIC = 'dynamic';
+
+/**
+ * Return a suggestion based upon the given element
+ * or `null` if a suggestion is not appropriate for the given element.
+ * If the suggestion is not currently in scope, then specify
+ * importForSource as the source to which an import should be added.
+ */
+CompletionSuggestion createSuggestion(Element element,
+    {String completion,
+    CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
+    int relevance: DART_RELEVANCE_DEFAULT,
+    Source importForSource}) {
+  if (element is ExecutableElement && element.isOperator) {
+    // Do not include operators in suggestions
+    return null;
+  }
+  if (completion == null) {
+    completion = element.displayName;
+  }
+  bool isDeprecated = element.isDeprecated;
+  CompletionSuggestion suggestion = new CompletionSuggestion(
+      kind,
+      isDeprecated ? DART_RELEVANCE_LOW : relevance,
+      completion,
+      completion.length,
+      0,
+      isDeprecated,
+      false);
+  suggestion.element = protocol.convertElement(element);
+  Element enclosingElement = element.enclosingElement;
+  if (enclosingElement is ClassElement) {
+    suggestion.declaringType = enclosingElement.displayName;
+  }
+  suggestion.returnType = getReturnTypeString(element);
+  if (element is ExecutableElement && element is! PropertyAccessorElement) {
+    suggestion.parameterNames = element.parameters
+        .map((ParameterElement parameter) => parameter.name)
+        .toList();
+    suggestion.parameterTypes =
+        element.parameters.map((ParameterElement parameter) {
+      DartType paramType = parameter.type;
+      // Gracefully degrade if type not resolved yet
+      return paramType != null ? paramType.displayName : 'var';
+    }).toList();
+    suggestion.requiredParameterCount = element.parameters
+        .where((ParameterElement parameter) =>
+            parameter.parameterKind == ParameterKind.REQUIRED)
+        .length;
+    suggestion.hasNamedParameters = element.parameters.any(
+        (ParameterElement parameter) =>
+            parameter.parameterKind == ParameterKind.NAMED);
+  }
+  if (importForSource != null) {
+    String srcPath = path.dirname(importForSource.fullName);
+    LibraryElement libElem = element.library;
+    if (libElem != null) {
+      Source libSource = libElem.source;
+      if (libSource != null) {
+        UriKind uriKind = libSource.uriKind;
+        if (uriKind == UriKind.DART_URI) {
+          suggestion.importUri = libSource.uri.toString();
+        } else if (uriKind == UriKind.PACKAGE_URI) {
+          suggestion.importUri = libSource.uri.toString();
+        } else if (uriKind == UriKind.FILE_URI &&
+            element.source.uriKind == UriKind.FILE_URI) {
+          try {
+            suggestion.importUri =
+                path.relative(libSource.fullName, from: srcPath);
+          } catch (_) {
+            // ignored
+          }
+        }
+      }
+    }
+    if (suggestion.importUri == null) {
+      // Do not include out of scope suggestions
+      // for which we cannot determine an import
+      return null;
+    }
+  }
+  return suggestion;
+}
+
+/**
+ * Common mixin for sharing behavior
+ */
+abstract class ElementSuggestionBuilder {
+  /**
+   * A collection of completion suggestions.
+   */
+  final List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
+
+  /**
+   * Return the kind of suggestions that should be built.
+   */
+  CompletionSuggestionKind get kind;
+
+  /**
+   * Return the request on which the builder is operating.
+   */
+  DartCompletionRequest get request;
+
+  /**
+   * Add a suggestion based upon the given element.
+   */
+  void addSuggestion(Element element,
+      {String prefix, int relevance: DART_RELEVANCE_DEFAULT}) {
+    if (element.isPrivate) {
+      LibraryElement elementLibrary = element.library;
+      CompilationUnitElement unitElem = request.target.unit.element;
+      if (unitElem == null) {
+        return;
+      }
+      LibraryElement unitLibrary = unitElem.library;
+      if (elementLibrary != unitLibrary) {
+        return;
+      }
+    }
+    if (prefix == null && element.isSynthetic) {
+      if ((element is PropertyAccessorElement) ||
+          element is FieldElement && !_isSpecialEnumField(element)) {
+        return;
+      }
+    }
+    String completion = element.displayName;
+    if (prefix != null && prefix.length > 0) {
+      if (completion == null || completion.length <= 0) {
+        completion = prefix;
+      } else {
+        completion = '$prefix.$completion';
+      }
+    }
+    if (completion == null || completion.length <= 0) {
+      return;
+    }
+    CompletionSuggestion suggestion = createSuggestion(element,
+        completion: completion, kind: kind, relevance: relevance);
+    if (suggestion != null) {
+      suggestions.add(suggestion);
+    }
+  }
+
+  /**
+   * Determine if the given element is one of the synthetic enum accessors
+   * for which we should generate a suggestion.
+   */
+  bool _isSpecialEnumField(FieldElement element) {
+    Element parent = element.enclosingElement;
+    if (parent is ClassElement && parent.isEnum) {
+      if (element.name == 'values') {
+        return true;
+      }
+    }
+    return false;
+  }
+}
+
+/**
+ * This class visits elements in a library and provides suggestions based upon
+ * the visible members in that library. Clients should call
+ * [LibraryElementSuggestionBuilder.suggestionsFor].
+ */
+class LibraryElementSuggestionBuilder extends GeneralizingElementVisitor
+    with ElementSuggestionBuilder {
+  final DartCompletionRequest request;
+  final CompletionSuggestionKind kind;
+  final bool typesOnly;
+  final bool instCreation;
+
+  LibraryElementSuggestionBuilder(
+      this.request, this.kind, this.typesOnly, this.instCreation);
+
+  @override
+  visitClassElement(ClassElement element) {
+    if (instCreation) {
+      element.visitChildren(this);
+    } else {
+      addSuggestion(element);
+    }
+  }
+
+  @override
+  visitCompilationUnitElement(CompilationUnitElement element) {
+    element.visitChildren(this);
+    LibraryElement containingLibrary = element.library;
+    if (containingLibrary != null) {
+      for (var lib in containingLibrary.exportedLibraries) {
+        lib.visitChildren(this);
+      }
+    }
+  }
+
+  @override
+  visitConstructorElement(ConstructorElement element) {
+    if (instCreation) {
+      ClassElement classElem = element.enclosingElement;
+      if (classElem != null) {
+        String prefix = classElem.name;
+        if (prefix != null && prefix.length > 0) {
+          addSuggestion(element, prefix: prefix);
+        }
+      }
+    }
+  }
+
+  @override
+  visitElement(Element element) {
+    // ignored
+  }
+
+  @override
+  visitFunctionElement(FunctionElement element) {
+    if (!typesOnly) {
+      addSuggestion(element);
+    }
+  }
+
+  @override
+  visitFunctionTypeAliasElement(FunctionTypeAliasElement element) {
+    if (!instCreation) {
+      addSuggestion(element);
+    }
+  }
+
+  @override
+  visitTopLevelVariableElement(TopLevelVariableElement element) {
+    if (!typesOnly) {
+      addSuggestion(element);
+    }
+  }
+
+  /**
+   * Add suggestions for the visible members in the given library
+   */
+  static void suggestionsFor(
+      DartCompletionRequest request,
+      CompletionSuggestionKind kind,
+      LibraryElement library,
+      bool typesOnly,
+      bool instCreation) {
+    if (library != null) {
+      library.visitChildren(new LibraryElementSuggestionBuilder(
+          request, kind, typesOnly, instCreation));
+    }
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/uri_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/uri_contributor.dart
similarity index 86%
rename from pkg/analysis_server/lib/src/services/completion/uri_contributor.dart
rename to pkg/analysis_server/lib/src/services/completion/dart/uri_contributor.dart
index c6b20d3..ebf87fe 100644
--- a/pkg/analysis_server/lib/src/services/completion/uri_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/uri_contributor.dart
@@ -7,7 +7,7 @@
 import 'dart:async';
 import 'dart:core' hide Resource;
 
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/sdk.dart';
@@ -15,7 +15,7 @@
 import 'package:path/path.dart' show posix;
 import 'package:path/src/context.dart';
 
-import '../../protocol_server.dart'
+import '../../../protocol_server.dart'
     show CompletionSuggestion, CompletionSuggestionKind;
 
 /**
@@ -26,27 +26,20 @@
   _UriSuggestionBuilder builder;
 
   @override
-  bool computeFast(DartCompletionRequest request) {
+  Future<List<CompletionSuggestion>> computeSuggestions(
+      DartCompletionRequest request) async {
     builder = new _UriSuggestionBuilder(request);
-    return builder.computeFast(request.target.containingNode);
-  }
-
-  @override
-  Future<bool> computeFull(DartCompletionRequest request) {
-    return new Future.value(false);
+    request.target.containingNode.accept(builder);
+    return builder.suggestions;
   }
 }
 
 class _UriSuggestionBuilder extends SimpleAstVisitor {
   final DartCompletionRequest request;
+  final List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
 
   _UriSuggestionBuilder(this.request);
 
-  bool computeFast(AstNode node) {
-    node.accept(this);
-    return true;
-  }
-
   @override
   visitExportDirective(ExportDirective node) {
     visitNamespaceDirective(node);
@@ -179,24 +172,15 @@
 
   void _addSuggestion(String completion,
       {int relevance: DART_RELEVANCE_DEFAULT}) {
-    request.addSuggestion(new CompletionSuggestion(
-        CompletionSuggestionKind.IMPORT,
-        relevance,
-        completion,
-        completion.length,
-        0,
-        false,
-        false));
+    suggestions.add(new CompletionSuggestion(CompletionSuggestionKind.IMPORT,
+        relevance, completion, completion.length, 0, false, false));
   }
 
   String _extractPartialUri(SimpleStringLiteral node) {
     if (request.offset < node.contentsOffset) {
       return null;
     }
-    String partial = node.literal.lexeme.substring(
+    return node.literal.lexeme.substring(
         node.contentsOffset - node.offset, request.offset - node.offset);
-    request.replacementOffset = node.contentsOffset;
-    request.replacementLength = node.contentsEnd - node.contentsOffset;
-    return partial;
   }
 }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
index 2edb62a..06bbe66 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
@@ -7,51 +7,43 @@
 import 'dart:async';
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/provisional/completion/completion_core.dart'
-    show AnalysisRequest, CompletionRequest;
-import 'package:analysis_server/src/provisional/completion/completion_dart.dart'
-    as newApi;
+    show AnalysisRequest, CompletionContributor, CompletionRequest;
 import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
-import 'package:analysis_server/src/services/completion/arglist_contributor.dart';
-import 'package:analysis_server/src/services/completion/combinator_contributor.dart';
-import 'package:analysis_server/src/services/completion/common_usage_computer.dart';
+import 'package:analysis_server/src/services/completion/completion_core.dart';
 import 'package:analysis_server/src/services/completion/completion_manager.dart';
-import 'package:analysis_server/src/services/completion/contribution_sorter.dart';
+import 'package:analysis_server/src/services/completion/dart/common_usage_sorter.dart';
+import 'package:analysis_server/src/services/completion/dart/contribution_sorter.dart';
 import 'package:analysis_server/src/services/completion/dart_completion_cache.dart';
 import 'package:analysis_server/src/services/completion/imported_reference_contributor.dart';
-import 'package:analysis_server/src/services/completion/keyword_contributor.dart';
 import 'package:analysis_server/src/services/completion/local_reference_contributor.dart';
 import 'package:analysis_server/src/services/completion/optype.dart';
 import 'package:analysis_server/src/services/completion/prefixed_element_contributor.dart';
-import 'package:analysis_server/src/services/completion/uri_contributor.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
 import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/cancelable_future.dart';
-import 'package:analyzer/src/context/context.dart'
-    show AnalysisFutureHelper, AnalysisContextImpl;
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart' hide AnalysisContextImpl;
 import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/task/model.dart';
 
-const int DART_RELEVANCE_COMMON_USAGE = 1200;
-const int DART_RELEVANCE_DEFAULT = 1000;
-const int DART_RELEVANCE_HIGH = 2000;
-const int DART_RELEVANCE_INHERITED_ACCESSOR = 1057;
-const int DART_RELEVANCE_INHERITED_FIELD = 1058;
-const int DART_RELEVANCE_INHERITED_METHOD = 1057;
-const int DART_RELEVANCE_KEYWORD = 1055;
-const int DART_RELEVANCE_LOCAL_ACCESSOR = 1057;
-const int DART_RELEVANCE_LOCAL_FIELD = 1058;
-const int DART_RELEVANCE_LOCAL_FUNCTION = 1056;
-const int DART_RELEVANCE_LOCAL_METHOD = 1057;
-const int DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE = 1056;
-const int DART_RELEVANCE_LOCAL_VARIABLE = 1059;
-const int DART_RELEVANCE_LOW = 500;
-const int DART_RELEVANCE_NAMED_PARAMETER = 1060;
-const int DART_RELEVANCE_PARAMETER = 1059;
+export 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart'
+    show
+        DART_RELEVANCE_COMMON_USAGE,
+        DART_RELEVANCE_DEFAULT,
+        DART_RELEVANCE_HIGH,
+        DART_RELEVANCE_INHERITED_ACCESSOR,
+        DART_RELEVANCE_INHERITED_FIELD,
+        DART_RELEVANCE_INHERITED_METHOD,
+        DART_RELEVANCE_KEYWORD,
+        DART_RELEVANCE_LOCAL_ACCESSOR,
+        DART_RELEVANCE_LOCAL_FIELD,
+        DART_RELEVANCE_LOCAL_FUNCTION,
+        DART_RELEVANCE_LOCAL_METHOD,
+        DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE,
+        DART_RELEVANCE_LOCAL_VARIABLE,
+        DART_RELEVANCE_LOW,
+        DART_RELEVANCE_NAMED_PARAMETER,
+        DART_RELEVANCE_PARAMETER;
 
 /**
  * The base class for contributing code completion suggestions.
@@ -84,17 +76,18 @@
    * The [defaultContributionSorter] is a long-lived object that isn't allowed
    * to maintain state between calls to [ContributionSorter#sort(...)].
    */
-  static ContributionSorter defaultContributionSorter =
-      new CommonUsageComputer();
+  static DartContributionSorter defaultContributionSorter =
+      new CommonUsageSorter();
 
   final SearchEngine searchEngine;
   final DartCompletionCache cache;
   List<DartCompletionContributor> contributors;
-  ContributionSorter contributionSorter;
+  Iterable<CompletionContributor> newContributors;
+  DartContributionSorter contributionSorter;
 
   DartCompletionManager(
       AnalysisContext context, this.searchEngine, Source source, this.cache,
-      [this.contributors, this.contributionSorter])
+      [this.contributors, this.newContributors, this.contributionSorter])
       : super(context, source) {
     if (contributors == null) {
       contributors = [
@@ -103,16 +96,19 @@
         // and can hide other suggestions with the same name
         new LocalReferenceContributor(),
         new ImportedReferenceContributor(),
-        new KeywordContributor(),
-        new ArgListContributor(),
-        new CombinatorContributor(),
+        //new KeywordContributor(),
+        //new ArgListContributor(),
+        // new CombinatorContributor(),
         new PrefixedElementContributor(),
-        new UriContributor(),
+        //new UriContributor(),
         // TODO(brianwilkerson) Use the completion contributor extension point
         // to add the contributor below (and eventually, all the contributors).
 //        new NewCompletionWrapper(new InheritedContributor())
       ];
     }
+    if (newContributors == null) {
+      newContributors = <CompletionContributor>[];
+    }
     if (contributionSorter == null) {
       contributionSorter = defaultContributionSorter;
     }
@@ -122,9 +118,12 @@
    * Create a new initialized Dart source completion manager
    */
   factory DartCompletionManager.create(
-      AnalysisContext context, SearchEngine searchEngine, Source source) {
+      AnalysisContext context,
+      SearchEngine searchEngine,
+      Source source,
+      Iterable<CompletionContributor> newContributors) {
     return new DartCompletionManager(context, searchEngine, source,
-        new DartCompletionCache(context, source));
+        new DartCompletionCache(context, source), null, newContributors);
   }
 
   @override
@@ -145,39 +144,21 @@
    */
   List<DartCompletionContributor> computeFast(
       DartCompletionRequest request, CompletionPerformance performance) {
-    bool isKeywordOrIdentifier(Token token) =>
-        token.type == TokenType.KEYWORD || token.type == TokenType.IDENTIFIER;
-
     return performance.logElapseTime('computeFast', () {
       CompilationUnit unit = context.parseCompilationUnit(source);
       request.unit = unit;
       request.target = new CompletionTarget.forOffset(unit, request.offset);
-      request.replacementOffset = request.offset;
-      request.replacementLength = 0;
       if (request.offset < 0 || request.offset > unit.end) {
+        request.replacementOffset = request.offset;
+        request.replacementLength = 0;
         sendResults(request, true);
         return [];
       }
 
-      var entity = request.target.entity;
-      Token token = entity is AstNode ? entity.beginToken : entity;
-      if (token != null && request.offset < token.offset) {
-        token = token.previous;
-      }
-      if (token != null) {
-        if (request.offset == token.offset && !isKeywordOrIdentifier(token)) {
-          // If the insertion point is at the beginning of the current token
-          // and the current token is not an identifier
-          // then check the previous token to see if it should be replaced
-          token = token.previous;
-        }
-        if (token != null && isKeywordOrIdentifier(token)) {
-          if (token.offset <= request.offset && request.offset <= token.end) {
-            request.replacementOffset = token.offset;
-            request.replacementLength = token.length;
-          }
-        }
-      }
+      ReplacementRange range =
+          new ReplacementRange.compute(request.offset, request.target);
+      request.replacementOffset = range.offset;
+      request.replacementLength = range.length;
 
       List<DartCompletionContributor> todo = new List.from(contributors);
       todo.removeWhere((DartCompletionContributor c) {
@@ -185,14 +166,6 @@
           return c.computeFast(request);
         });
       });
-      _processAnalysisRequest(request,
-          contributionSorter.sort(request, request.suggestions));
-      // TODO (danrubel) if request is obsolete
-      // (processAnalysisRequest returns false)
-      // then send empty results
-      if (todo.isEmpty) {
-        sendResults(request, todo.isEmpty);
-      }
       return todo;
     });
   }
@@ -202,9 +175,38 @@
    * resolved and request that each remaining contributor finish their work.
    * Return a [Future] that completes when the last notification has been sent.
    */
-  Future computeFull(DartCompletionRequest request,
-      CompletionPerformance performance, List<DartCompletionContributor> todo) {
+  Future computeFull(
+      DartCompletionRequest request,
+      CompletionPerformance performance,
+      List<DartCompletionContributor> todo) async {
+    // Compute suggestions using the new API
+    performance.logStartTime('computeSuggestions');
+    for (CompletionContributor contributor in newContributors) {
+      String contributorTag = 'computeSuggestions - ${contributor.runtimeType}';
+      performance.logStartTime(contributorTag);
+      List<CompletionSuggestion> newSuggestions =
+          await contributor.computeSuggestions(request);
+      for (CompletionSuggestion suggestion in newSuggestions) {
+        request.addSuggestion(suggestion);
+      }
+      performance.logElapseTime(contributorTag);
+    }
+    performance.logElapseTime('computeSuggestions');
     performance.logStartTime('waitForAnalysis');
+
+    if (todo.isEmpty) {
+      // TODO(danrubel) current sorter requires no additional analysis,
+      // but need to handle the returned future the same way that futures
+      // returned from contributors are handled once this method is refactored
+      // to be async.
+      /* await */ contributionSorter.sort(request, request.suggestions);
+      // TODO (danrubel) if request is obsolete
+      // (processAnalysisRequest returns false)
+      // then send empty results
+      sendResults(request, true);
+    }
+
+    // Compute the other suggestions
     return waitForAnalysis().then((CompilationUnit unit) {
       if (controller.isClosed) {
         return;
@@ -229,8 +231,12 @@
               performance.logElapseTime(completeTag);
               bool last = --count == 0;
               if (changed || last) {
-                _processAnalysisRequest(request,
-                    contributionSorter.sort(request, request.suggestions));
+                // TODO(danrubel) current sorter requires no additional analysis,
+                // but need to handle the returned future the same way that futures
+                // returned from contributors are handled once this method is refactored
+                // to be async.
+                /* await */ contributionSorter.sort(
+                    request, request.suggestions);
                 // TODO (danrubel) if request is obsolete
                 // (processAnalysisRequest returns false)
                 // then send empty results
@@ -250,9 +256,7 @@
     CompletionPerformance performance = new CompletionPerformance();
     performance.logElapseTime('compute', () {
       List<DartCompletionContributor> todo = computeFast(request, performance);
-      if (!todo.isEmpty) {
-        computeFull(request, performance, todo);
-      }
+      computeFull(request, performance, todo);
     });
   }
 
@@ -291,38 +295,6 @@
       return null;
     }, test: (e) => e is AnalysisNotScheduledError);
   }
-
-  /**
-   * Process the analysis [analysis] and any subsequent requests.
-   * Return a [Future] that returns `true`
-   * once all analysis requests have been processed
-   * or `false` if the original completion request is obsolete
-   * and processing requests was terminated before finished.
-   */
-  Future<bool> _processAnalysisRequest(
-      CompletionRequest request, AnalysisRequest analysis) {
-    // Return if no additional analysis is necessary
-    if (analysis == null) {
-      return new Future.value(true);
-    }
-
-    // Check to see if the result is already cached
-    var cachedValue = context.getResult(analysis.target, analysis.descriptor);
-    if (cachedValue != null) {
-      return _processAnalysisRequest(
-          request, analysis.callback(request, cachedValue));
-    }
-
-    // TODO (danrubel) determine when completion request is obsolete
-    // and analysis should be terminated before requesting additional analysis
-
-    // Request additional analysis
-    return new AnalysisFutureHelper((context as AnalysisContextImpl),
-        analysis.target, analysis.descriptor).computeAsync().then((value) {
-      return _processAnalysisRequest(
-          request, analysis.callback(request, cachedValue));
-    });
-  }
 }
 
 /**
@@ -378,14 +350,19 @@
    */
   final Set<String> _completions = new Set<String>();
 
-  DartCompletionRequest(AnalysisServer server, AnalysisContext context,
-      Source source, int offset, this.cache)
-      : super(server, context, source, offset);
+  DartCompletionRequest(
+      AnalysisContext context,
+      ResourceProvider resourceProvider,
+      SearchEngine searchEngine,
+      Source source,
+      int offset,
+      this.cache)
+      : super(context, resourceProvider, searchEngine, source, offset);
 
   factory DartCompletionRequest.from(
           CompletionRequestImpl request, DartCompletionCache cache) =>
-      new DartCompletionRequest(request.server, request.context, request.source,
-          request.offset, cache);
+      new DartCompletionRequest(request.context, request.resourceProvider,
+          request.searchEngine, request.source, request.offset, cache);
 
   /**
    * Return the original text from the [replacementOffset] to the [offset]
@@ -410,11 +387,6 @@
   }
 
   /**
-   * The search engine for use when building suggestions.
-   */
-  SearchEngine get searchEngine => server.searchEngine;
-
-  /**
    * The list of suggestions to be sent to the client.
    */
   Iterable<CompletionSuggestion> get suggestions => _suggestions;
@@ -461,80 +433,58 @@
 }
 
 /**
- * A wrapper around a new dart completion contributor that makes it usable where
- * an old dart completion contributor is expected.
+ * Utility class for computing the code completion replacement range
  */
-class NewCompletionWrapper implements DartCompletionContributor {
-  /**
-   * The new-style contributor that is being wrapped.
-   */
-  final newApi.DartCompletionContributor contributor;
+class ReplacementRange {
+  int offset;
+  int length;
 
-  /**
-   * Initialize a newly created wrapper for the given [contributor].
-   */
-  NewCompletionWrapper(this.contributor);
+  ReplacementRange(this.offset, this.length);
 
-  @override
-  bool computeFast(DartCompletionRequest request) {
-    List<CompletionSuggestion> suggestions =
-        contributor.computeSuggestions(new OldRequestWrapper(request));
-    if (suggestions == null) {
-      return false;
+  factory ReplacementRange.compute(int requestOffset, CompletionTarget target) {
+    bool isKeywordOrIdentifier(Token token) =>
+        token.type == TokenType.KEYWORD || token.type == TokenType.IDENTIFIER;
+
+    //TODO(danrubel) Ideally this needs to be pushed down into the contributors
+    // but that implies that each suggestion can have a different
+    // replacement offsent/length which would mean an API change
+
+    var entity = target.entity;
+    Token token = entity is AstNode ? entity.beginToken : entity;
+    if (token != null && requestOffset < token.offset) {
+      token = token.previous;
     }
-    for (CompletionSuggestion suggestion in suggestions) {
-      request.addSuggestion(suggestion);
-    }
-    return true;
-  }
-
-  @override
-  Future<bool> computeFull(DartCompletionRequest request) async {
-    List<CompletionSuggestion> suggestions =
-        contributor.computeSuggestions(new OldRequestWrapper(request));
-    if (suggestions != null) {
-      for (CompletionSuggestion suggestion in suggestions) {
-        request.addSuggestion(suggestion);
+    if (token != null) {
+      if (requestOffset == token.offset && !isKeywordOrIdentifier(token)) {
+        // If the insertion point is at the beginning of the current token
+        // and the current token is not an identifier
+        // then check the previous token to see if it should be replaced
+        token = token.previous;
       }
-      return true;
+      if (token != null && isKeywordOrIdentifier(token)) {
+        if (token.offset <= requestOffset && requestOffset <= token.end) {
+          // Replacement range for typical identifier completion
+          return new ReplacementRange(token.offset, token.length);
+        }
+      }
+      if (token is StringToken) {
+        SimpleStringLiteral uri = new SimpleStringLiteral(token, token.lexeme);
+        Token previous = token.previous;
+        if (previous is KeywordToken) {
+          Keyword keyword = previous.keyword;
+          if (keyword == Keyword.IMPORT ||
+              keyword == Keyword.EXPORT ||
+              keyword == Keyword.PART) {
+            int start = uri.contentsOffset;
+            var end = uri.contentsEnd;
+            if (start <= requestOffset && requestOffset <= end) {
+              // Replacement range for import URI
+              return new ReplacementRange(start, end - start);
+            }
+          }
+        }
+      }
     }
-    return false;
+    return new ReplacementRange(requestOffset, 0);
   }
-
-  @override
-  String toString() => 'wrapped $contributor';
-}
-
-/**
- * A wrapper around an old dart completion request that makes it usable where a
- * new dart completion request is expected.
- */
-class OldRequestWrapper implements newApi.DartCompletionRequest {
-  final DartCompletionRequest request;
-
-  OldRequestWrapper(this.request);
-
-  @override
-  AnalysisContext get context => request.context;
-
-  @override
-  bool get isResolved => request.unit.element != null;
-
-  @override
-  int get offset => request.offset;
-
-  @override
-  ResourceProvider get resourceProvider => request.resourceProvider;
-
-  @override
-  Source get source => request.source;
-
-  @override
-  CompletionTarget get target => request.target;
-
-  @override
-  CompilationUnit get unit => request.unit;
-
-  @override
-  String toString() => 'wrapped $request';
 }
diff --git a/pkg/analysis_server/lib/src/services/completion/inherited_contributor.dart b/pkg/analysis_server/lib/src/services/completion/inherited_contributor.dart
deleted file mode 100644
index 451da53..0000000
--- a/pkg/analysis_server/lib/src/services/completion/inherited_contributor.dart
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library services.completion.computer.dart.invocation;
-
-import 'package:analysis_server/plugin/edit/utilities/change_builder_dart.dart';
-import 'package:analysis_server/src/protocol_server.dart'
-    show CompletionSuggestion, CompletionSuggestionKind, SourceChange;
-import 'package:analysis_server/src/protocol_server.dart' as protocol
-    hide CompletionSuggestion, CompletionSuggestionKind;
-import 'package:analysis_server/src/provisional/completion/completion_dart.dart';
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart'
-    show DART_RELEVANCE_HIGH;
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/element.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/source.dart';
-
-/**
- * A completion contributor used to suggest replacing partial identifiers inside
- * a class declaration with templates for inherited members.
- */
-class InheritedContributor extends DartCompletionContributor {
-  @override
-  List<CompletionSuggestion> internalComputeSuggestions(
-      DartCompletionRequest request) {
-    if (!request.isResolved) {
-      return null;
-    }
-    AstNode node = new NodeLocator(request.offset).searchWithin(request.unit);
-    if (node == null || !_isMemberLevelIdentifier(node)) {
-      return null;
-    }
-    ClassDeclaration classDeclaration =
-        node.getAncestor((AstNode node) => node is ClassDeclaration);
-    if (classDeclaration != null) {
-      ClassElement element = classDeclaration.element;
-      if (element == null) {
-        return null;
-      }
-      return _suggestInheritedMembers(request, node, element);
-    }
-    return null;
-  }
-
-  /**
-   * Return a template for an override of the given [element] in the given
-   * [source]. If selected, the template will replace the given [identifier].
-   */
-  String _buildRepacementText(
-      Source source, SimpleIdentifier identifier, Element element) {
-    AnalysisContext context = element.context;
-    DartChangeBuilder builder = new DartChangeBuilder(context);
-    builder.addFileEdit(source, context.getModificationStamp(source),
-        (DartFileEditBuilder builder) {
-      builder.addReplacement(identifier.offset, identifier.length,
-          (DartEditBuilder builder) {
-        builder.writeOverrideOfInheritedMember(element);
-      });
-    });
-    return builder.sourceChange.edits[0].edits[0].replacement.trim();
-  }
-
-  /**
-   * Build a suggestion to replace the partial [identifier] in the given
-   * [source] with an override of the given [element].
-   */
-  CompletionSuggestion _buildSuggestion(
-      Source source, SimpleIdentifier identifier, Element element) {
-    String completion = _buildRepacementText(source, identifier, element);
-    CompletionSuggestion suggestion = new CompletionSuggestion(
-        CompletionSuggestionKind.IDENTIFIER,
-        DART_RELEVANCE_HIGH,
-        completion,
-        identifier.offset,
-        0,
-        element.isDeprecated,
-        false);
-    suggestion.element = protocol.convertElement(element);
-    return suggestion;
-  }
-
-  /**
-   * Return a list containing the names of all of the inherited by not
-   * implemented members of the class represented by the given [element] that
-   * start with the given [prefix]. The [map] is used to find all of the members
-   * that are inherited.
-   */
-  List<String> _computeMemberNames(
-      MemberMap map, ClassElement element, String prefix) {
-    List<String> memberNames = <String>[];
-    int count = map.size;
-    for (int i = 0; i < count; i++) {
-      String memberName = map.getKey(i);
-      if (memberName.startsWith(prefix) && !_hasMember(element, memberName)) {
-        memberNames.add(memberName);
-      }
-    }
-    return memberNames;
-  }
-
-  /**
-   * Return `true` if the given [classElement] directly declares a member with
-   * the given [memberName].
-   */
-  bool _hasMember(ClassElement classElement, String memberName) {
-    return classElement.getField(memberName) != null ||
-        classElement.getGetter(memberName) != null ||
-        classElement.getMethod(memberName) != null ||
-        classElement.getSetter(memberName) != null;
-  }
-
-  /**
-   * Return `true` if the given [node] looks like a partial identifier inside a
-   * class declaration.
-   */
-  bool _isMemberLevelIdentifier(AstNode node) {
-    if (node is SimpleIdentifier) {
-      AstNode parent1 = node.parent;
-      if (parent1 is TypeName) {
-        AstNode parent2 = parent1.parent;
-        if (parent2 is VariableDeclarationList) {
-          AstNode parent3 = parent2.parent;
-          if (parent3 is FieldDeclaration) {
-            NodeList<VariableDeclaration> variables = parent2.variables;
-            return variables.length == 1 && variables[0].name.name.isEmpty;
-          }
-        }
-      }
-    }
-    return false;
-  }
-
-  /**
-   * Add any suggestions that are appropriate to the given [request], using the
-   * given [element] to find inherited members whose name has the given
-   * [identifier] as a prefix.
-   */
-  List<CompletionSuggestion> _suggestInheritedMembers(
-      DartCompletionRequest request,
-      SimpleIdentifier identifier,
-      ClassElement element) {
-    String name = identifier.name;
-    InheritanceManager manager = new InheritanceManager(element.library);
-    MemberMap map = manager.getMapOfMembersInheritedFromInterfaces(element);
-    List<String> memberNames = _computeMemberNames(map, element, name);
-    memberNames.sort();
-    List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
-    for (String memberName in memberNames) {
-      CompletionSuggestion suggestion =
-          _buildSuggestion(request.source, identifier, map.get(memberName));
-      if (suggestion != null) {
-        suggestions.add(suggestion);
-      }
-    }
-    return suggestions;
-  }
-}
diff --git a/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
index 5117855..573dc4b 100644
--- a/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
@@ -7,99 +7,21 @@
 import 'dart:async';
 import 'dart:collection';
 
-import 'package:analysis_server/src/protocol_server.dart' as protocol;
 import 'package:analysis_server/src/protocol_server.dart'
     hide Element, ElementKind;
+import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart'
+    show createSuggestion;
 import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
 import 'package:analyzer/src/generated/engine.dart' as engine;
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_dart.dart';
-import 'package:path/path.dart' as path;
+
+export 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart'
+    show createSuggestion;
 
 const String DYNAMIC = 'dynamic';
 
 /**
- * Return a suggestion based upon the given element
- * or `null` if a suggestion is not appropriate for the given element.
- * If the suggestion is not currently in scope, then specify
- * importForSource as the source to which an import should be added.
- */
-CompletionSuggestion createSuggestion(Element element,
-    {String completion,
-    CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
-    int relevance: DART_RELEVANCE_DEFAULT,
-    Source importForSource}) {
-  if (element is ExecutableElement && element.isOperator) {
-    // Do not include operators in suggestions
-    return null;
-  }
-  if (completion == null) {
-    completion = element.displayName;
-  }
-  bool isDeprecated = element.isDeprecated;
-  CompletionSuggestion suggestion = new CompletionSuggestion(
-      kind,
-      isDeprecated ? DART_RELEVANCE_LOW : relevance,
-      completion,
-      completion.length,
-      0,
-      isDeprecated,
-      false);
-  suggestion.element = protocol.convertElement(element);
-  Element enclosingElement = element.enclosingElement;
-  if (enclosingElement is ClassElement) {
-    suggestion.declaringType = enclosingElement.displayName;
-  }
-  suggestion.returnType = getReturnTypeString(element);
-  if (element is ExecutableElement && element is! PropertyAccessorElement) {
-    suggestion.parameterNames = element.parameters
-        .map((ParameterElement parameter) => parameter.name)
-        .toList();
-    suggestion.parameterTypes = element.parameters
-        .map((ParameterElement parameter) => parameter.type.displayName)
-        .toList();
-    suggestion.requiredParameterCount = element.parameters
-        .where((ParameterElement parameter) =>
-            parameter.parameterKind == ParameterKind.REQUIRED)
-        .length;
-    suggestion.hasNamedParameters = element.parameters.any(
-        (ParameterElement parameter) =>
-            parameter.parameterKind == ParameterKind.NAMED);
-  }
-  if (importForSource != null) {
-    String srcPath = path.dirname(importForSource.fullName);
-    LibraryElement libElem = element.library;
-    if (libElem != null) {
-      Source libSource = libElem.source;
-      if (libSource != null) {
-        UriKind uriKind = libSource.uriKind;
-        if (uriKind == UriKind.DART_URI) {
-          suggestion.importUri = libSource.uri.toString();
-        } else if (uriKind == UriKind.PACKAGE_URI) {
-          suggestion.importUri = libSource.uri.toString();
-        } else if (uriKind == UriKind.FILE_URI &&
-            element.source.uriKind == UriKind.FILE_URI) {
-          try {
-            suggestion.importUri =
-                path.relative(libSource.fullName, from: srcPath);
-          } catch (_) {
-            // ignored
-          }
-        }
-      }
-    }
-    if (suggestion.importUri == null) {
-      // Do not include out of scope suggestions
-      // for which we cannot determine an import
-      return null;
-    }
-  }
-  return suggestion;
-}
-
-/**
  * Call the given function with each non-null non-empty inherited type name
  * that is defined in the given class.
  */
diff --git a/pkg/analysis_server/lib/src/services/correction/assist.dart b/pkg/analysis_server/lib/src/services/correction/assist.dart
index 45ad25f..f4c51be 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist.dart
@@ -9,21 +9,28 @@
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'dart:async';
 
 /**
  * Compute and return the assists available at the given selection (described by
  * the [offset] and [length]) in the given [source]. The source was analyzed in
- * the given [context]. The [plugin] is used to get the list of assist
+ * the given [analysisContext]. The [plugin] is used to get the list of assist
  * contributors.
  */
-List<Assist> computeAssists(ServerPlugin plugin, AnalysisContext context,
-    Source source, int offset, int length) {
+Future<List<Assist>> computeAssists(
+    ServerPlugin plugin,
+    AnalysisContext analysisContext,
+    Source source,
+    int offset,
+    int length) async {
   List<Assist> assists = <Assist>[];
   List<AssistContributor> contributors = plugin.assistContributors;
+  AssistContextImpl assistContext =
+      new AssistContextImpl(analysisContext, source, offset, length);
   for (AssistContributor contributor in contributors) {
     try {
       List<Assist> contributedAssists =
-          contributor.computeAssists(context, source, offset, length);
+          await contributor.computeAssists(assistContext);
       if (contributedAssists != null) {
         assists.addAll(contributedAssists);
       }
@@ -38,6 +45,26 @@
 }
 
 /**
+ * The implementation of [AssistContext].
+ */
+class AssistContextImpl implements AssistContext {
+  @override
+  final AnalysisContext analysisContext;
+
+  @override
+  final Source source;
+
+  @override
+  final int selectionOffset;
+
+  @override
+  final int selectionLength;
+
+  AssistContextImpl(this.analysisContext, this.source, this.selectionOffset,
+      this.selectionLength);
+}
+
+/**
  * An enumeration of possible assist kinds.
  */
 class DartAssistKind {
@@ -47,6 +74,14 @@
       const AssistKind('ADD_TYPE_ANNOTATION', 30, "Add type annotation");
   static const ASSIGN_TO_LOCAL_VARIABLE = const AssistKind(
       'ASSIGN_TO_LOCAL_VARIABLE', 30, "Assign value to new local variable");
+  static const CONVERT_DOCUMENTATION_INTO_BLOCK = const AssistKind(
+      'CONVERT_DOCUMENTATION_INTO_BLOCK',
+      30,
+      "Convert into block documentation comment");
+  static const CONVERT_DOCUMENTATION_INTO_LINE = const AssistKind(
+      'CONVERT_DOCUMENTATION_INTO_LINE',
+      30,
+      "Convert into line documentation comment");
   static const CONVERT_INTO_BLOCK_BODY = const AssistKind(
       'CONVERT_INTO_BLOCK_BODY', 30, "Convert into block body");
   static const CONVERT_INTO_EXPRESSION_BODY = const AssistKind(
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index d83ca2f..c6f1c02 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -4,6 +4,7 @@
 
 library services.src.correction.assist;
 
+import 'dart:async';
 import 'dart:collection';
 
 import 'package:analysis_server/plugin/edit/assist/assist_core.dart';
@@ -30,38 +31,49 @@
  * The computer for Dart assists.
  */
 class AssistProcessor {
+  AnalysisContext analysisContext;
+
   Source source;
   String file;
   int fileStamp;
-  final CompilationUnit unit;
-  final int selectionOffset;
-  final int selectionLength;
-  AnalysisContext context;
+
+  CompilationUnit unit;
   CompilationUnitElement unitElement;
+
   LibraryElement unitLibraryElement;
   String unitLibraryFile;
   String unitLibraryFolder;
 
+  int selectionOffset;
+  int selectionLength;
+  int selectionEnd;
+
   final List<Assist> assists = <Assist>[];
   final Map<String, LinkedEditGroup> linkedPositionGroups =
       <String, LinkedEditGroup>{};
   Position exitPosition = null;
 
-  int selectionEnd;
   CorrectionUtils utils;
   AstNode node;
 
   SourceChange change = new SourceChange('<message>');
 
-  AssistProcessor(this.unit, this.selectionOffset, this.selectionLength) {
-    source = unit.element.source;
-    file = source.fullName;
-    unitElement = unit.element;
-    context = unitElement.context;
-    unitLibraryElement = unitElement.library;
+  AssistProcessor(DartAssistContext dartContext) {
+    analysisContext = dartContext.analysisContext;
+    // source
+    source = dartContext.source;
+    file = dartContext.source.fullName;
+    fileStamp = analysisContext.getModificationStamp(source);
+    // unit
+    unit = dartContext.unit;
+    unitElement = dartContext.unit.element;
+    // library
+    unitLibraryElement = dartContext.unit.element.library;
     unitLibraryFile = unitLibraryElement.source.fullName;
     unitLibraryFolder = dirname(unitLibraryFile);
-    fileStamp = unitElement.context.getModificationStamp(source);
+    // selection
+    selectionOffset = dartContext.selectionOffset;
+    selectionLength = dartContext.selectionLength;
     selectionEnd = selectionOffset + selectionLength;
   }
 
@@ -70,7 +82,7 @@
    */
   String get eol => utils.endOfLine;
 
-  List<Assist> compute() {
+  Future<List<Assist>> compute() async {
     utils = new CorrectionUtils(unit);
     node = new NodeLocator(selectionOffset, selectionEnd).searchWithin(unit);
     if (node == null) {
@@ -81,6 +93,8 @@
     _addProposal_addTypeAnnotation_SimpleFormalParameter();
     _addProposal_addTypeAnnotation_VariableDeclaration();
     _addProposal_assignToLocalVariable();
+    _addProposal_convertDocumentationIntoBlock();
+    _addProposal_convertDocumentationIntoLine();
     _addProposal_convertToBlockFunctionBody();
     _addProposal_convertToExpressionFunctionBody();
     _addProposal_convertToForIndexLoop();
@@ -388,6 +402,80 @@
     _addAssist(DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE, []);
   }
 
+  void _addProposal_convertDocumentationIntoBlock() {
+    Comment comment = node.getAncestor((n) => n is Comment);
+    if (comment != null && comment.isDocumentation) {
+      String prefix = utils.getNodePrefix(comment);
+      SourceBuilder sb = new SourceBuilder(file, comment.offset);
+      sb.append('/**');
+      sb.append(eol);
+      for (Token token in comment.tokens) {
+        if (token is DocumentationCommentToken &&
+            token.type == TokenType.SINGLE_LINE_COMMENT) {
+          sb.append(prefix);
+          sb.append(' * ');
+          sb.append(token.lexeme.substring('/// '.length));
+          sb.append(eol);
+        } else {
+          return;
+        }
+      }
+      sb.append(prefix);
+      sb.append(' */');
+      _insertBuilder(sb, comment.length);
+    }
+    // add proposal
+    _addAssist(DartAssistKind.CONVERT_DOCUMENTATION_INTO_BLOCK, []);
+  }
+
+  void _addProposal_convertDocumentationIntoLine() {
+    Comment comment = node.getAncestor((n) => n is Comment);
+    if (comment != null && comment.isDocumentation) {
+      if (comment.tokens.length == 1) {
+        Token token = comment.tokens.first;
+        if (token.type == TokenType.MULTI_LINE_COMMENT) {
+          String text = token.lexeme;
+          List<String> lines = text.split('\n');
+          String prefix = utils.getNodePrefix(comment);
+          SourceBuilder sb = new SourceBuilder(file, comment.offset);
+          bool firstLine = true;
+          String linePrefix = '';
+          for (String line in lines) {
+            if (firstLine) {
+              firstLine = false;
+              String expectedPrefix = '/**';
+              if (!line.startsWith(expectedPrefix)) {
+                return;
+              }
+              line = line.substring(expectedPrefix.length).trim();
+              if (line.isNotEmpty) {
+                sb.append('/// ');
+                sb.append(line);
+                linePrefix = eol + prefix;
+              }
+            } else {
+              if (line.startsWith(prefix + ' */')) {
+                break;
+              }
+              String expectedPrefix = prefix + ' * ';
+              if (!line.startsWith(expectedPrefix)) {
+                return;
+              }
+              line = line.substring(expectedPrefix.length).trim();
+              sb.append(linePrefix);
+              sb.append('/// ');
+              sb.append(line);
+              linePrefix = eol + prefix;
+            }
+          }
+          _insertBuilder(sb, comment.length);
+        }
+      }
+    }
+    // add proposal
+    _addAssist(DartAssistKind.CONVERT_DOCUMENTATION_INTO_LINE, []);
+  }
+
   void _addProposal_convertToBlockFunctionBody() {
     FunctionBody body = getEnclosingFunctionBody();
     // prepare expression body
@@ -579,7 +667,7 @@
     // iterable should be List
     {
       DartType iterableType = iterable.bestType;
-      InterfaceType listType = context.typeProvider.listType;
+      InterfaceType listType = analysisContext.typeProvider.listType;
       if (iterableType is! InterfaceType ||
           iterableType.element != listType.element) {
         _coverageMarker();
@@ -811,19 +899,19 @@
 
   void _addProposal_encapsulateField() {
     // find FieldDeclaration
-    FieldDeclaration fieldDeclaraton =
+    FieldDeclaration fieldDeclaration =
         node.getAncestor((x) => x is FieldDeclaration);
-    if (fieldDeclaraton == null) {
+    if (fieldDeclaration == null) {
       _coverageMarker();
       return;
     }
     // not interesting for static
-    if (fieldDeclaraton.isStatic) {
+    if (fieldDeclaration.isStatic) {
       _coverageMarker();
       return;
     }
     // has a parse error
-    VariableDeclarationList variableList = fieldDeclaraton.fields;
+    VariableDeclarationList variableList = fieldDeclaration.fields;
     if (variableList.keyword == null && variableList.type == null) {
       _coverageMarker();
       return;
@@ -856,7 +944,7 @@
     // rename field
     _addReplaceEdit(rangeNode(nameNode), '_$name');
     // update references in constructors
-    ClassDeclaration classDeclaration = fieldDeclaraton.parent;
+    ClassDeclaration classDeclaration = fieldDeclaration.parent;
     for (ClassMember member in classDeclaration.members) {
       if (member is ConstructorDeclaration) {
         for (FormalParameter parameter in member.parameters.parameters) {
@@ -877,7 +965,7 @@
         '  void set $name(${typeNameCode}$name) {$eol'
         '    _$name = $name;$eol'
         '  }';
-    _addInsertEdit(fieldDeclaraton.end, getterCode + setterCode);
+    _addInsertEdit(fieldDeclaration.end, getterCode + setterCode);
     // add proposal
     _addAssist(DartAssistKind.ENCAPSULATE_FIELD, []);
   }
@@ -1163,6 +1251,10 @@
     // prepare outer "if" statement
     AstNode parent = targetIfStatement.parent;
     if (parent is Block) {
+      if ((parent as Block).statements.length != 1) {
+        _coverageMarker();
+        return;
+      }
       parent = parent.parent;
     }
     if (parent is! IfStatement) {
@@ -2047,9 +2139,8 @@
  */
 class DefaultAssistContributor extends DartAssistContributor {
   @override
-  List<Assist> internalComputeAssists(
-      CompilationUnit unit, int offset, int length) {
-    AssistProcessor processor = new AssistProcessor(unit, offset, length);
+  Future<List<Assist>> internalComputeAssists(DartAssistContext context) {
+    AssistProcessor processor = new AssistProcessor(context);
     return processor.compute();
   }
 }
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 73f9bd5..a9c4918 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -4,6 +4,8 @@
 
 library analysis_server.src.services.correction.fix;
 
+import 'dart:async';
+
 import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
 import 'package:analysis_server/src/plugin/server_plugin.dart';
 import 'package:analyzer/file_system/file_system.dart';
@@ -17,14 +19,17 @@
  * reported after it's source was analyzed in the given [context]. The [plugin]
  * is used to get the list of fix contributors.
  */
-List<Fix> computeFixes(ServerPlugin plugin, ResourceProvider resourceProvider,
-    AnalysisContext context, AnalysisError error) {
+Future<List<Fix>> computeFixes(
+    ServerPlugin plugin,
+    ResourceProvider resourceProvider,
+    AnalysisContext context,
+    AnalysisError error) async {
   List<Fix> fixes = <Fix>[];
   List<FixContributor> contributors = plugin.fixContributors;
+  FixContext fixContext = new FixContextImpl(resourceProvider, context, error);
   for (FixContributor contributor in contributors) {
     try {
-      List<Fix> contributedFixes =
-          contributor.computeFixes(resourceProvider, context, error);
+      List<Fix> contributedFixes = await contributor.computeFixes(fixContext);
       if (contributedFixes != null) {
         fixes.addAll(contributedFixes);
       }
@@ -122,6 +127,8 @@
   static const CHANGE_TO = const FixKind('CHANGE_TO', 49, "Change to '{0}'");
   static const CHANGE_TO_STATIC_ACCESS = const FixKind(
       'CHANGE_TO_STATIC_ACCESS', 50, "Change access to static using '{0}'");
+  static const CHANGE_TYPE_ANNOTATION = const FixKind(
+      'CHANGE_TYPE_ANNOTATION', 50, "Change '{0}' to '{1}' type annotation");
   static const CREATE_CLASS =
       const FixKind('CREATE_CLASS', 50, "Create class '{0}'");
   static const CREATE_CONSTRUCTOR =
@@ -202,3 +209,24 @@
   static const USE_NOT_EQ_NULL =
       const FixKind('USE_NOT_EQ_NULL', 50, "Use != null instead of 'is! Null'");
 }
+
+/**
+ * The implementation of [FixContext].
+ */
+class FixContextImpl implements FixContext {
+  @override
+  final ResourceProvider resourceProvider;
+
+  @override
+  final AnalysisContext analysisContext;
+
+  @override
+  final AnalysisError error;
+
+  FixContextImpl(this.resourceProvider, this.analysisContext, this.error);
+
+  FixContextImpl.from(FixContext other)
+      : resourceProvider = other.resourceProvider,
+        analysisContext = other.analysisContext,
+        error = other.error;
+}
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 d2c1f86..f068b3b 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -4,6 +4,7 @@
 
 library analysis_server.src.services.correction.fix_internal;
 
+import 'dart:async';
 import 'dart:collection';
 import 'dart:core' hide Resource;
 
@@ -42,13 +43,26 @@
 typedef bool ElementPredicate(Element argument);
 
 /**
+ * The implementation of [DartFixContext].
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class DartFixContextImpl extends FixContextImpl implements DartFixContext {
+  /**
+   * The [CompilationUnit] to compute fixes in.
+   */
+  final CompilationUnit unit;
+
+  DartFixContextImpl(FixContext fixContext, this.unit) : super.from(fixContext);
+}
+
+/**
  * A [FixContributor] that provides the default set of fixes.
  */
 class DefaultFixContributor extends DartFixContributor {
   @override
-  List<Fix> internalComputeFixes(ResourceProvider resourceProvider,
-      CompilationUnit unit, AnalysisError error) {
-    FixProcessor processor = new FixProcessor(resourceProvider, unit, error);
+  Future<List<Fix>> internalComputeFixes(DartFixContext context) {
+    FixProcessor processor = new FixProcessor(context);
     return processor.compute();
   }
 }
@@ -59,9 +73,9 @@
 class FixProcessor {
   static const int MAX_LEVENSHTEIN_DISTANCE = 3;
 
-  final ResourceProvider resourceProvider;
-  final CompilationUnit unit;
-  final AnalysisError error;
+  ResourceProvider resourceProvider;
+  CompilationUnit unit;
+  AnalysisError error;
   AnalysisContext context;
   String file;
   int fileStamp;
@@ -87,15 +101,22 @@
   AstNode node;
   AstNode coveredNode;
 
-  FixProcessor(this.resourceProvider, this.unit, this.error) {
+  FixProcessor(DartFixContext dartContext) {
+    resourceProvider = dartContext.resourceProvider;
+    context = dartContext.analysisContext;
+    // unit
+    unit = dartContext.unit;
     unitElement = unit.element;
-    context = unitElement.context;
     unitSource = unitElement.source;
+    // file
     file = unitSource.fullName;
     fileStamp = context.getModificationStamp(unitSource);
+    // library
     unitLibraryElement = unitElement.library;
     unitLibraryFile = unitLibraryElement.source.fullName;
     unitLibraryFolder = dirname(unitLibraryFile);
+    // error
+    error = dartContext.error;
   }
 
   DartType get coreTypeBool => _getCoreType('bool');
@@ -105,15 +126,15 @@
    */
   String get eol => utils.endOfLine;
 
-  List<Fix> compute() {
+  Future<List<Fix>> compute() async {
     utils = new CorrectionUtils(unit);
     errorOffset = error.offset;
     errorLength = error.length;
     errorEnd = errorOffset + errorLength;
     errorRange = new SourceRange(errorOffset, errorLength);
-    node = new NodeLocator(errorOffset).searchWithin(unit);
-    coveredNode = new NodeLocator(errorOffset, errorOffset + errorLength)
-        .searchWithin(unit);
+    node = new NodeLocator2(errorOffset).searchWithin(unit);
+    coveredNode =
+        new NodeLocator2(errorOffset, errorEnd - 1).searchWithin(unit);
     // analyze ErrorCode
     ErrorCode errorCode = error.errorCode;
     if (errorCode == StaticWarningCode.UNDEFINED_CLASS_BOOLEAN) {
@@ -271,6 +292,9 @@
       _addFix_useStaticAccess_method();
       _addFix_useStaticAccess_property();
     }
+    if (errorCode == StaticTypeWarningCode.INVALID_ASSIGNMENT) {
+      _addFix_changeTypeAnnotation();
+    }
     if (errorCode == StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION) {
       _addFix_removeParentheses_inGetterInvocation();
     }
@@ -359,61 +383,66 @@
   }
 
   void _addFix_addMissingParameter() {
-    if (node is SimpleIdentifier && node.parent is MethodInvocation) {
+    if (node is ArgumentList && node.parent is MethodInvocation) {
+      ArgumentList argumentList = node;
       MethodInvocation invocation = node.parent;
       SimpleIdentifier methodName = invocation.methodName;
-      ArgumentList argumentList = invocation.argumentList;
-      if (methodName == node && argumentList != null) {
-        Element targetElement = methodName.bestElement;
-        List<Expression> arguments = argumentList.arguments;
-        if (targetElement is ExecutableElement) {
-          List<ParameterElement> parameters = targetElement.parameters;
-          int numParameters = parameters.length;
-          Expression argument = arguments[numParameters];
-          // prepare target
-          int targetOffset;
-          if (numParameters != 0) {
-            ParameterElement parameterElement = parameters.last;
-            AstNode parameterNode = parameterElement.computeNode();
-            targetOffset = parameterNode.end;
+      Element targetElement = methodName.bestElement;
+      List<Expression> arguments = argumentList.arguments;
+      if (targetElement is ExecutableElement) {
+        List<ParameterElement> parameters = targetElement.parameters;
+        int numParameters = parameters.length;
+        Iterable<ParameterElement> requiredParameters = parameters
+            .takeWhile((p) => p.parameterKind == ParameterKind.REQUIRED);
+        Iterable<ParameterElement> optionalParameters = parameters
+            .skipWhile((p) => p.parameterKind == ParameterKind.REQUIRED);
+        int numRequired = requiredParameters.length;
+        Expression argument = arguments[numRequired];
+        // prepare target
+        int targetOffset;
+        if (numRequired != 0) {
+          AstNode parameterNode = requiredParameters.last.computeNode();
+          targetOffset = parameterNode.end;
+        } else {
+          AstNode targetNode = targetElement.computeNode();
+          if (targetNode is FunctionDeclaration) {
+            FunctionExpression function = targetNode.functionExpression;
+            targetOffset = function.parameters.leftParenthesis.end;
+          } else if (targetNode is MethodDeclaration) {
+            targetOffset = targetNode.parameters.leftParenthesis.end;
           } else {
-            AstNode targetNode = targetElement.computeNode();
-            if (targetNode is FunctionDeclaration) {
-              FunctionExpression function = targetNode.functionExpression;
-              targetOffset = function.parameters.leftParenthesis.end;
-            } else if (targetNode is MethodDeclaration) {
-              targetOffset = targetNode.parameters.leftParenthesis.end;
-            } else {
-              return;
-            }
+            return;
           }
-          String targetFile = targetElement.source.fullName;
-          // required
-          {
-            SourceBuilder sb = new SourceBuilder(targetFile, targetOffset);
-            // append source
-            if (numParameters != 0) {
-              sb.append(', ');
-            }
-            _appendParameterForArgument(sb, numParameters, argument);
-            // add proposal
-            _insertBuilder(sb, targetElement);
-            _addFix(DartFixKind.ADD_MISSING_PARAMETER_REQUIRED, []);
+        }
+        String targetFile = targetElement.source.fullName;
+        // required
+        {
+          SourceBuilder sb = new SourceBuilder(targetFile, targetOffset);
+          // append source
+          if (numRequired != 0) {
+            sb.append(', ');
           }
-          // optional positional
-          {
-            SourceBuilder sb = new SourceBuilder(targetFile, targetOffset);
-            // append source
-            if (numParameters != 0) {
-              sb.append(', ');
-            }
-            sb.append('[');
-            _appendParameterForArgument(sb, numParameters, argument);
-            sb.append(']');
-            // add proposal
-            _insertBuilder(sb, targetElement);
-            _addFix(DartFixKind.ADD_MISSING_PARAMETER_POSITIONAL, []);
+          _appendParameterForArgument(sb, numRequired, argument);
+          if (numRequired != numParameters) {
+            sb.append(', ');
           }
+          // add proposal
+          _insertBuilder(sb, targetElement);
+          _addFix(DartFixKind.ADD_MISSING_PARAMETER_REQUIRED, []);
+        }
+        // optional positional
+        if (optionalParameters.isEmpty) {
+          SourceBuilder sb = new SourceBuilder(targetFile, targetOffset);
+          // append source
+          if (numRequired != 0) {
+            sb.append(', ');
+          }
+          sb.append('[');
+          _appendParameterForArgument(sb, numRequired, argument);
+          sb.append(']');
+          // add proposal
+          _insertBuilder(sb, targetElement);
+          _addFix(DartFixKind.ADD_MISSING_PARAMETER_POSITIONAL, []);
         }
       }
     }
@@ -467,6 +496,29 @@
     }
   }
 
+  void _addFix_changeTypeAnnotation() {
+    AstNode declaration = coveredNode.parent;
+    if (declaration is VariableDeclaration &&
+        declaration.initializer == coveredNode) {
+      AstNode variableList = declaration.parent;
+      if (variableList is VariableDeclarationList &&
+          variableList.variables.length == 1) {
+        TypeName typeNode = variableList.type;
+        if (typeNode != null) {
+          Expression initializer = coveredNode;
+          DartType newType = initializer.bestType;
+          if (newType is InterfaceType || newType is FunctionType) {
+            String newTypeSource =
+                utils.getTypeSource(newType, librariesToImport);
+            _addReplaceEdit(rf.rangeNode(typeNode), newTypeSource);
+            _addFix(DartFixKind.CHANGE_TYPE_ANNOTATION,
+                [typeNode.type.displayName, newTypeSource]);
+          }
+        }
+      }
+    }
+  }
+
   void _addFix_createClass() {
     Element prefixElement = null;
     String name = null;
@@ -598,45 +650,26 @@
   }
 
   void _addFix_createConstructor_insteadOfSyntheticDefault() {
-    TypeName typeName = null;
-    ConstructorName constructorName = null;
-    InstanceCreationExpression instanceCreation = null;
-    if (node is SimpleIdentifier) {
-      if (node.parent is TypeName) {
-        typeName = node.parent as TypeName;
-        if (typeName.name == node && typeName.parent is ConstructorName) {
-          constructorName = typeName.parent as ConstructorName;
-          // should be synthetic default constructor
-          {
-            ConstructorElement constructorElement =
-                constructorName.staticElement;
-            if (constructorElement == null ||
-                !constructorElement.isDefaultConstructor ||
-                !constructorElement.isSynthetic) {
-              return;
-            }
-          }
-          // prepare InstanceCreationExpression
-          if (constructorName.parent is InstanceCreationExpression) {
-            instanceCreation =
-                constructorName.parent as InstanceCreationExpression;
-            if (instanceCreation.constructorName != constructorName) {
-              return;
-            }
-          }
-        }
-      }
+    if (node is! ArgumentList) {
+      return;
     }
-    // do we have enough information?
-    if (instanceCreation == null) {
+    if (node.parent is! InstanceCreationExpression) {
+      return;
+    }
+    InstanceCreationExpression instanceCreation = node.parent;
+    ConstructorName constructorName = instanceCreation.constructorName;
+    // should be synthetic default constructor
+    ConstructorElement constructorElement = constructorName.staticElement;
+    if (constructorElement == null ||
+        !constructorElement.isDefaultConstructor ||
+        !constructorElement.isSynthetic) {
       return;
     }
     // prepare target
-    DartType targetType = typeName.type;
-    if (targetType is! InterfaceType) {
+    if (constructorElement.enclosingElement is! ClassElement) {
       return;
     }
-    ClassElement targetElement = targetType.element as ClassElement;
+    ClassElement targetElement = constructorElement.enclosingElement;
     String targetFile = targetElement.source.fullName;
     ClassDeclaration targetClass = getParsedClassElementNode(targetElement);
     _ConstructorLocation targetLocation =
@@ -724,6 +757,10 @@
   }
 
   void _addFix_createConstructorSuperExplicit() {
+    if (node.parent is! ConstructorDeclaration ||
+        node.parent.parent is! ClassDeclaration) {
+      return;
+    }
     ConstructorDeclaration targetConstructor =
         node.parent as ConstructorDeclaration;
     ClassDeclaration targetClassNode =
@@ -1085,7 +1122,7 @@
       Source source = importDirective.source;
       if (source != null) {
         String file = source.fullName;
-        if (isAbsolute(file)) {
+        if (isAbsolute(file) && AnalysisEngine.isDartFileName(file)) {
           String libName = _computeLibraryName(file);
           SourceEdit edit = new SourceEdit(0, 0, 'library $libName;$eol$eol');
           doSourceChange_addSourceEdit(change, context, source, edit);
@@ -1586,11 +1623,12 @@
   }
 
   void _addFix_removeParameters_inGetterDeclaration() {
-    if (node is SimpleIdentifier && node.parent is MethodDeclaration) {
-      MethodDeclaration method = node.parent as MethodDeclaration;
+    if (node is MethodDeclaration) {
+      MethodDeclaration method = node as MethodDeclaration;
+      SimpleIdentifier name = method.name;
       FunctionBody body = method.body;
-      if (method.name == node && body != null) {
-        _addReplaceEdit(rf.rangeEndStart(node, body), ' ');
+      if (name != null && body != null) {
+        _addReplaceEdit(rf.rangeEndStart(name, body), ' ');
         _addFix(DartFixKind.REMOVE_PARAMETERS_IN_GETTER_DECLARATION, []);
       }
     }
@@ -1951,6 +1989,7 @@
     // append parameters
     sb.append('(');
     List<Expression> arguments = argumentList.arguments;
+    bool hasNamedParameters = false;
     for (int i = 0; i < arguments.length; i++) {
       Expression argument = arguments[i];
       // append separator
@@ -1958,8 +1997,15 @@
         sb.append(', ');
       }
       // append parameter
+      if (argument is NamedExpression && !hasNamedParameters) {
+        hasNamedParameters = true;
+        sb.append('{');
+      }
       _appendParameterForArgument(sb, i, argument);
     }
+    if (hasNamedParameters) {
+      sb.append('}');
+    }
   }
 
   void _addFix_undefinedMethod_useSimilar() {
@@ -2253,7 +2299,9 @@
       sb.append(' ');
     }
     // append parameter name
-    {
+    if (argument is NamedExpression) {
+      sb.append(argument.name.label.name);
+    } else {
       Set<String> excluded = new Set<String>();
       List<String> suggestions =
           _getArgumentNameSuggestions(excluded, type, argument, index);
@@ -2354,7 +2402,7 @@
       if (relPathParts[0].toLowerCase() == 'lib') {
         relPathParts.removeAt(0);
       }
-      {
+      if (relPathParts.isNotEmpty) {
         String nameWithoutExt = pathContext.withoutExtension(relPathParts.last);
         relPathParts[relPathParts.length - 1] = nameWithoutExt;
       }
diff --git a/pkg/analysis_server/lib/src/services/dependencies/reachable_source_collector.dart b/pkg/analysis_server/lib/src/services/dependencies/reachable_source_collector.dart
new file mode 100644
index 0000000..a0273ce
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/dependencies/reachable_source_collector.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library services.dependencies.reachable_source_collector;
+
+import 'dart:collection';
+
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/task/dart.dart';
+
+/// Collects reachable sources.
+class ReachableSourceCollector {
+  final Map<String, List<String>> _sourceMap =
+      new HashMap<String, List<String>>();
+
+  final Source source;
+  final AnalysisContext context;
+  ReachableSourceCollector(this.source, this.context) {
+    if (source == null) {
+      throw new ArgumentError.notNull('source');
+    }
+    if (context == null) {
+      throw new ArgumentError.notNull('context');
+    }
+  }
+
+  /// Collect reachable sources.
+  Map<String, List<String>> collectSources() {
+    _addDependencies(source);
+    return _sourceMap;
+  }
+
+  void _addDependencies(Source source) {
+
+    String sourceUri = source.uri.toString();
+
+    // Careful not to revisit.
+    if (_sourceMap[source.uri.toString()] != null) {
+      return;
+    }
+
+    List<Source> sources = <Source>[];
+    sources.addAll(context.computeResult(source, IMPORTED_LIBRARIES));
+    sources.addAll(context.computeResult(source, EXPORTED_LIBRARIES));
+
+    _sourceMap[sourceUri] =
+        sources.map((source) => source.uri.toString()).toList();
+
+    sources.forEach((s) => _addDependencies(s));
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/index/index.dart b/pkg/analysis_server/lib/src/services/index/index.dart
index 5b2204c..cad43a2 100644
--- a/pkg/analysis_server/lib/src/services/index/index.dart
+++ b/pkg/analysis_server/lib/src/services/index/index.dart
@@ -6,7 +6,7 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
 import 'package:analysis_server/src/services/index/indexable_element.dart';
 import 'package:analyzer/src/generated/element.dart';
 import 'package:analyzer/src/generated/engine.dart';
diff --git a/pkg/analysis_server/lib/src/services/index/index_contributor.dart b/pkg/analysis_server/lib/src/services/index/index_contributor.dart
index 6fcd934..fdcd8fa 100644
--- a/pkg/analysis_server/lib/src/services/index/index_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/index/index_contributor.dart
@@ -6,7 +6,7 @@
 
 import 'dart:collection' show Queue;
 
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
 import 'package:analysis_server/src/services/correction/namespace.dart';
 import 'package:analysis_server/src/services/index/index.dart';
 import 'package:analysis_server/src/services/index/index_store.dart';
diff --git a/pkg/analysis_server/lib/src/services/index/index_store.dart b/pkg/analysis_server/lib/src/services/index/index_store.dart
index 574a727..18f80bc 100644
--- a/pkg/analysis_server/lib/src/services/index/index_store.dart
+++ b/pkg/analysis_server/lib/src/services/index/index_store.dart
@@ -4,7 +4,7 @@
 
 library services.index_store;
 
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
 import 'package:analysis_server/src/services/index/index.dart';
 import 'package:analyzer/src/generated/element.dart';
 import 'package:analyzer/src/generated/engine.dart';
diff --git a/pkg/analysis_server/lib/src/services/index/indexable_element.dart b/pkg/analysis_server/lib/src/services/index/indexable_element.dart
index 57f8659..df10370 100644
--- a/pkg/analysis_server/lib/src/services/index/indexable_element.dart
+++ b/pkg/analysis_server/lib/src/services/index/indexable_element.dart
@@ -6,7 +6,7 @@
 
 import 'dart:collection';
 
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
 import 'package:analyzer/src/generated/element.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
diff --git a/pkg/analysis_server/lib/src/services/index/indexable_file.dart b/pkg/analysis_server/lib/src/services/index/indexable_file.dart
index 7babfef..4e1c873 100644
--- a/pkg/analysis_server/lib/src/services/index/indexable_file.dart
+++ b/pkg/analysis_server/lib/src/services/index/indexable_file.dart
@@ -4,7 +4,7 @@
 
 library services.index.indexable_file;
 
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
 import 'package:analyzer/src/generated/engine.dart';
 
 /**
diff --git a/pkg/analysis_server/lib/src/services/index/local_index.dart b/pkg/analysis_server/lib/src/services/index/local_index.dart
index 624d3ff..115b3e1 100644
--- a/pkg/analysis_server/lib/src/services/index/local_index.dart
+++ b/pkg/analysis_server/lib/src/services/index/local_index.dart
@@ -6,7 +6,7 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
 import 'package:analysis_server/src/services/index/index.dart';
 import 'package:analysis_server/src/services/index/store/split_store.dart';
 import 'package:analyzer/src/generated/element.dart';
diff --git a/pkg/analysis_server/lib/src/services/index/local_memory_index.dart b/pkg/analysis_server/lib/src/services/index/local_memory_index.dart
index 484085f..ec69627 100644
--- a/pkg/analysis_server/lib/src/services/index/local_memory_index.dart
+++ b/pkg/analysis_server/lib/src/services/index/local_memory_index.dart
@@ -4,7 +4,7 @@
 
 library services.index.memory_file_index;
 
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
 import 'package:analysis_server/src/services/index/index.dart';
 import 'package:analysis_server/src/services/index/index_contributor.dart';
 import 'package:analysis_server/src/services/index/local_index.dart';
diff --git a/pkg/analysis_server/lib/src/services/index/store/codec.dart b/pkg/analysis_server/lib/src/services/index/store/codec.dart
index 8fd23ab..9771f56 100644
--- a/pkg/analysis_server/lib/src/services/index/store/codec.dart
+++ b/pkg/analysis_server/lib/src/services/index/store/codec.dart
@@ -6,7 +6,7 @@
 
 import 'dart:collection';
 
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
 import 'package:analysis_server/src/services/index/index.dart';
 import 'package:analyzer/src/generated/engine.dart';
 
diff --git a/pkg/analysis_server/lib/src/services/index/store/split_store.dart b/pkg/analysis_server/lib/src/services/index/store/split_store.dart
index 880cad3..85dedd2 100644
--- a/pkg/analysis_server/lib/src/services/index/store/split_store.dart
+++ b/pkg/analysis_server/lib/src/services/index/store/split_store.dart
@@ -8,8 +8,8 @@
 import 'dart:collection';
 import 'dart:typed_data';
 
-import 'package:analysis_server/plugin/index/index_core.dart';
 import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
 import 'package:analysis_server/src/services/index/index.dart';
 import 'package:analysis_server/src/services/index/index_store.dart';
 import 'package:analysis_server/src/services/index/indexable_element.dart';
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
index c865aec..ad42a6e 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
@@ -197,8 +197,18 @@
     AstNode coveringNode = new NodeLocator(
         selectionRange.offset, selectionRange.end).searchWithin(unit);
     // compute covering expressions
-    for (AstNode node = coveringNode; node is Expression; node = node.parent) {
+    for (AstNode node = coveringNode;
+        node is Expression || node is ArgumentList;
+        node = node.parent) {
       AstNode parent = node.parent;
+      // skip ArgumentList
+      if (node is ArgumentList) {
+        continue;
+      }
+      // skip AssignmentExpression
+      if (node is AssignmentExpression) {
+        continue;
+      }
       // cannot extract the name part of a property access
       if (parent is PrefixedIdentifier && parent.identifier == node ||
           parent is PropertyAccess && parent.propertyName == node) {
@@ -207,17 +217,15 @@
       // fatal selection problems
       if (coveringExpressionOffsets.isEmpty) {
         if (node is SimpleIdentifier) {
-          Element element = node.bestElement;
-          if (element is FunctionElement || element is MethodElement) {
-            return new RefactoringStatus.fatal(
-                'Cannot extract a single method name.',
-                newLocation_fromNode(node));
-          }
           if (node.inDeclarationContext()) {
             return new RefactoringStatus.fatal(
                 'Cannot extract the name part of a declaration.',
                 newLocation_fromNode(node));
           }
+          Element element = node.bestElement;
+          if (element is FunctionElement || element is MethodElement) {
+            continue;
+          }
         }
         if (parent is AssignmentExpression && parent.leftHandSide == node) {
           return new RefactoringStatus.fatal(
diff --git a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
index cfe43eb..1e89981 100644
--- a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
+++ b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
@@ -6,7 +6,7 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
 import 'package:analysis_server/src/services/correction/source_range.dart';
 import 'package:analysis_server/src/services/index/index.dart';
 import 'package:analysis_server/src/services/index/indexable_element.dart';
diff --git a/pkg/analysis_server/lib/src/status/ast_writer.dart b/pkg/analysis_server/lib/src/status/ast_writer.dart
index 6cb30db..5488a59 100644
--- a/pkg/analysis_server/lib/src/status/ast_writer.dart
+++ b/pkg/analysis_server/lib/src/status/ast_writer.dart
@@ -50,6 +50,9 @@
     } else if (node is ExportDirective) {
       properties['element'] = node.element;
       properties['source'] = node.source;
+    } else if (node is FunctionDeclaration) {
+      properties['external keyword'] = node.externalKeyword;
+      properties['property keyword'] = node.propertyKeyword;
     } else if (node is FunctionExpressionInvocation) {
       properties['static element'] = node.staticElement;
       properties['static type'] = node.staticType;
@@ -60,6 +63,11 @@
       properties['source'] = node.source;
     } else if (node is LibraryDirective) {
       properties['element'] = node.element;
+    } else if (node is MethodDeclaration) {
+      properties['external keyword'] = node.externalKeyword;
+      properties['modifier keyword'] = node.modifierKeyword;
+      properties['operator keyword'] = node.operatorKeyword;
+      properties['property keyword'] = node.propertyKeyword;
     } else if (node is PartDirective) {
       properties['element'] = node.element;
       properties['source'] = node.source;
diff --git a/pkg/analysis_server/lib/src/status/get_handler.dart b/pkg/analysis_server/lib/src/status/get_handler.dart
index 8aa840a..05937c0 100644
--- a/pkg/analysis_server/lib/src/status/get_handler.dart
+++ b/pkg/analysis_server/lib/src/status/get_handler.dart
@@ -13,6 +13,7 @@
 import 'package:analysis_server/plugin/protocol/protocol.dart' hide Element;
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/domain_completion.dart';
+import 'package:analysis_server/src/domain_diagnostic.dart';
 import 'package:analysis_server/src/domain_execution.dart';
 import 'package:analysis_server/src/operation/operation.dart';
 import 'package:analysis_server/src/operation/operation_analysis.dart';
@@ -23,6 +24,7 @@
 import 'package:analysis_server/src/socket_server.dart';
 import 'package:analysis_server/src/status/ast_writer.dart';
 import 'package:analysis_server/src/status/element_writer.dart';
+import 'package:analysis_server/src/utilities/average.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/context/cache.dart';
 import 'package:analyzer/src/context/context.dart' show AnalysisContextImpl;
@@ -30,11 +32,13 @@
 import 'package:analyzer/src/generated/element.dart';
 import 'package:analyzer/src/generated/engine.dart'
     hide AnalysisCache, AnalysisContextImpl, AnalysisTask;
+import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_collection.dart';
 import 'package:analyzer/src/generated/utilities_general.dart';
+import 'package:analyzer/src/services/lint.dart';
 import 'package:analyzer/src/task/dart.dart';
 import 'package:analyzer/src/task/driver.dart';
 import 'package:analyzer/src/task/html.dart';
@@ -94,6 +98,11 @@
   static const String CONTEXT_PATH = '/context';
 
   /**
+   * The path used to request diagnostic information.
+   */
+  static const String DIAGNOSTIC_PATH = '/diagnostic';
+
+  /**
    * The path used to request information about a element model.
    */
   static const String ELEMENT_PATH = '/element';
@@ -157,6 +166,11 @@
       new ContentType("text", "html", charset: "utf-8");
 
   /**
+   * Rolling average of calls to get diagnostics.
+   */
+  Average _diagnosticCallAverage = new Average();
+
+  /**
    * The socket server whose status is to be reported on.
    */
   SocketServer _server;
@@ -172,10 +186,22 @@
   final Map<String, String> _overlayContents = <String, String>{};
 
   /**
+   * Handler for diagnostics requests.
+   */
+  DiagnosticDomainHandler _diagnosticHandler;
+
+  /**
    * Initialize a newly created handler for GET requests.
    */
   GetHandler(this._server, this._printBuffer);
 
+  DiagnosticDomainHandler get diagnosticHandler {
+    if (_diagnosticHandler == null) {
+      _diagnosticHandler = new DiagnosticDomainHandler(_server.analysisServer);
+    }
+    return _diagnosticHandler;
+  }
+
   /**
    * Return the active [CompletionDomainHandler]
    * or `null` if either analysis server is not running
@@ -211,6 +237,8 @@
       _returnCommunicationPerformance(request);
     } else if (path == CONTEXT_PATH) {
       _returnContextInfo(request);
+    } else if (path == DIAGNOSTIC_PATH) {
+      _returnDiagnosticInfo(request);
     } else if (path == ELEMENT_PATH) {
       _returnElement(request);
     } else if (path == INDEX_ELEMENT_BY_NAME) {
@@ -282,6 +310,10 @@
     if (unit != null) {
       return unit;
     }
+    unit = entry.getValue(RESOLVED_UNIT11);
+    if (unit != null) {
+      return unit;
+    }
     return entry.getValue(RESOLVED_UNIT);
   }
 
@@ -350,6 +382,7 @@
       results.add(RESOLVED_UNIT8);
       results.add(RESOLVED_UNIT9);
       results.add(RESOLVED_UNIT10);
+      results.add(RESOLVED_UNIT11);
       results.add(RESOLVED_UNIT);
       results.add(STRONG_MODE_ERRORS);
       results.add(USED_IMPORTED_ELEMENTS);
@@ -648,6 +681,7 @@
     List<Folder> allContexts = <Folder>[];
     Map<Folder, List<CacheEntry>> entryMap =
         new HashMap<Folder, List<CacheEntry>>();
+    StringBuffer invalidKeysBuffer = new StringBuffer();
     analysisServer.folderMap
         .forEach((Folder folder, InternalAnalysisContext context) {
       Source source = context.sourceFactory.forUri(sourceUri);
@@ -664,7 +698,15 @@
               entries = <CacheEntry>[];
               entryMap[folder] = entries;
             }
-            entries.add(iterator.value);
+            CacheEntry value = iterator.value;
+            if (value == null) {
+              if (invalidKeysBuffer.isNotEmpty) {
+                invalidKeysBuffer.write(', ');
+              }
+              invalidKeysBuffer.write(iterator.key.toString());
+            } else {
+              entries.add(value);
+            }
           }
         }
       }
@@ -676,6 +718,11 @@
     _writeResponse(request, (StringBuffer buffer) {
       _writePage(buffer, 'Analysis Server - Cache Entry',
           ['Context: $contextFilter', 'File: $sourceUri'], (HttpResponse) {
+        if (invalidKeysBuffer.isNotEmpty) {
+          buffer.write('<h3>Targets with null Entries</h3><p>');
+          buffer.write(invalidKeysBuffer.toString());
+          buffer.write('</p>');
+        }
         List<CacheEntry> entries = entryMap[folder];
         buffer.write('<h3>Analyzing Contexts</h3><p>');
         bool first = true;
@@ -1039,6 +1086,49 @@
               ?.toList());
         }
 
+        buffer.write('<h3>Configuration</h3>');
+
+        AnalysisOptionsImpl options = context.analysisOptions;
+        buffer.write('<p><b>Options</b></p>');
+        buffer.write('<p>');
+        _writeOption(
+            buffer, 'Analyze functon bodies', options.analyzeFunctionBodies);
+        _writeOption(buffer, 'Cache size', options.cacheSize);
+        _writeOption(
+            buffer, 'Enable generic methods', options.enableGenericMethods);
+        _writeOption(buffer, 'Enable strict call checks',
+            options.enableStrictCallChecks);
+        _writeOption(buffer, 'Enable super mixins', options.enableSuperMixins);
+        _writeOption(buffer, 'Generate dart2js hints', options.dart2jsHint);
+        _writeOption(buffer, 'Generate errors in implicit files',
+            options.generateImplicitErrors);
+        _writeOption(
+            buffer, 'Generate errors in SDK files', options.generateSdkErrors);
+        _writeOption(buffer, 'Generate hints', options.hint);
+        _writeOption(buffer, 'Incremental resolution', options.incremental);
+        _writeOption(buffer, 'Incremental resolution with API changes',
+            options.incrementalApi);
+        _writeOption(buffer, 'Preserve comments', options.preserveComments);
+        _writeOption(buffer, 'Strong mode', options.strongMode);
+        _writeOption(buffer, 'Strong mode hints', options.strongModeHints,
+            last: true);
+        buffer.write('</p>');
+
+        List<Linter> lints = context.getConfigurationData(CONFIGURED_LINTS_KEY);
+        buffer.write('<p><b>Lints</b></p>');
+        if (lints.isEmpty) {
+          buffer.write('<p><none></p>');
+        } else {
+          for (Linter lint in lints) {
+            buffer.write('<p> ${lint.runtimeType}</p>');
+          }
+        }
+
+        List<ErrorFilter> errorFilters =
+            context.getConfigurationData(CONFIGURED_ERROR_FILTERS);
+        int filterCount = errorFilters?.length ?? 0;
+        buffer.write('<p><b>Error Filter count</b>: $filterCount</p>');
+
         _writeFiles(buffer, 'Priority Files', priorityNames);
         _writeFiles(buffer, 'Explicitly Analyzed Files', explicitNames);
         _writeFiles(buffer, 'Implicitly Analyzed Files', implicitNames);
@@ -1056,6 +1146,20 @@
   }
 
   /**
+   * Return a response displaying diagnostic information.
+   */
+  void _returnDiagnosticInfo(HttpRequest request) {
+    String value = request.requestedUri.queryParameters['index'];
+    int index = value != null ? int.parse(value, onError: (_) => 0) : 0;
+    _writeResponse(request, (StringBuffer buffer) {
+      _writePage(buffer, 'Analysis Server - Diagnostic info', [],
+          (StringBuffer buffer) {
+        _writeDiagnosticStatus(buffer);
+      });
+    });
+  }
+
+  /**
    * Return a response containing information about an element structure.
    */
   void _returnElement(HttpRequest request) {
@@ -1242,6 +1346,9 @@
         buffer.write('<p>');
         buffer.write(makeLink(OVERLAYS_PATH, {}, 'File overlays'));
         buffer.write('</p>');
+        buffer.write('<p>');
+        buffer.write(makeLink(DIAGNOSTIC_PATH, {}, 'Diagnostic info'));
+        buffer.write('</p>');
       });
     });
   }
@@ -1307,26 +1414,6 @@
       // TODO(brianwilkerson) Add items for the SDK contexts (currently only one).
       buffer.write('</p>');
 
-      buffer.write('<p><b>Options</b></p>');
-      buffer.write('<p>');
-      _writeOption(
-          buffer, 'Analyze functon bodies', options.analyzeFunctionBodies);
-      _writeOption(buffer, 'Cache size', options.cacheSize);
-      _writeOption(
-          buffer, 'Enable strict call checks', options.enableStrictCallChecks);
-      _writeOption(buffer, 'Enable super mixins', options.enableSuperMixins);
-      _writeOption(buffer, 'Generate hints', options.hint);
-      _writeOption(buffer, 'Generate dart2js hints', options.dart2jsHint);
-      _writeOption(buffer, 'Generate errors in implicit files',
-          options.generateImplicitErrors);
-      _writeOption(
-          buffer, 'Generate errors in SDK files', options.generateSdkErrors);
-      _writeOption(buffer, 'Incremental resolution', options.incremental);
-      _writeOption(buffer, 'Incremental resolution with API changes',
-          options.incrementalApi);
-      _writeOption(buffer, 'Preserve comments', options.preserveComments,
-          last: true);
-      buffer.write('</p>');
       int freq = AnalysisServer.performOperationDelayFreqency;
       String delay = freq > 0 ? '1 ms every $freq ms' : 'off';
       buffer.write('<p><b>perform operation delay:</b> $delay</p>');
@@ -1444,6 +1531,47 @@
   }
 
   /**
+   * Write the status of the diagnostic domain to the given [buffer].
+   */
+  void _writeDiagnosticStatus(StringBuffer buffer) {
+    var request = new DiagnosticGetDiagnosticsParams().toRequest('0');
+
+    var stopwatch = new Stopwatch();
+    stopwatch.start();
+    var response = diagnosticHandler.handleRequest(request);
+    stopwatch.stop();
+
+    int elapsedMs = stopwatch.elapsedMilliseconds;
+    _diagnosticCallAverage.addSample(elapsedMs);
+
+    buffer.write('<h3>Timing</h3>');
+
+    buffer.write('<p>');
+    buffer.write('getDiagnostic (last call): $elapsedMs (ms)');
+    buffer.write('<p>');
+    buffer.write('getDiagnostic (rolling average): '
+        '${_diagnosticCallAverage.value} (ms)');
+    buffer.write('<p>&nbsp;');
+
+    var json = response.toJson()[Response.RESULT];
+    List contexts = json['contexts'];
+    for (var context in contexts) {
+      buffer.write('<p>');
+      buffer.write('<h3>${context["name"]}</h3>');
+      buffer.write('<p>');
+      buffer.write('explicitFileCount: ${context["explicitFileCount"]}');
+      buffer.write('<p>');
+      buffer.write('implicitFileCount: ${context["implicitFileCount"]}');
+      buffer.write('<p>');
+      buffer.write('workItemQueueLength: ${context["workItemQueueLength"]}');
+      buffer.write('<p>');
+      buffer.write('workItemQueueLengthAverage: '
+          '${context["workItemQueueLengthAverage"]}');
+      buffer.write('<p>&nbsp;');
+    }
+  }
+
+  /**
    * Write the status of the edit domain (on the main status page) to the given
    * [buffer].
    */
diff --git a/pkg/analysis_server/lib/src/utilities/average.dart b/pkg/analysis_server/lib/src/utilities/average.dart
new file mode 100644
index 0000000..a738d39
--- /dev/null
+++ b/pkg/analysis_server/lib/src/utilities/average.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analysis_server.src.utilities.average;
+
+/// Simple rolling average sample counter.
+class Average {
+  num _val;
+  final int _sampleCount;
+
+  /// Create an average with the given (optional) sample count size.
+  Average([this._sampleCount = 20]);
+
+  /// The current average.
+  num get value => _val ?? 0;
+
+  /// Add the given [sample].
+  void addSample(num sample) {
+    if (_val == null) {
+      _val = sample;
+    } else {
+      _val = _val * ((_sampleCount - 1) / _sampleCount) +
+          sample * (1 / _sampleCount);
+    }
+  }
+
+  @override
+  String toString() => 'average: ${value}';
+}
diff --git a/pkg/analysis_server/lib/src/utilities/change_builder_core.dart b/pkg/analysis_server/lib/src/utilities/change_builder_core.dart
index a5fe204..cb103f8 100644
--- a/pkg/analysis_server/lib/src/utilities/change_builder_core.dart
+++ b/pkg/analysis_server/lib/src/utilities/change_builder_core.dart
@@ -4,8 +4,8 @@
 
 library analysis_server.src.utilities.change_builder_core;
 
-import 'package:analysis_server/plugin/edit/utilities/change_builder_core.dart';
 import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analysis_server/src/provisional/edit/utilities/change_builder_core.dart';
 import 'package:analyzer/src/generated/source.dart';
 
 /**
diff --git a/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart b/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart
index f40dd36..56fc80f 100644
--- a/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart
+++ b/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart
@@ -4,9 +4,9 @@
 
 library analysis_server.src.utilities.change_builder_dart;
 
-import 'package:analysis_server/plugin/edit/utilities/change_builder_core.dart';
-import 'package:analysis_server/plugin/edit/utilities/change_builder_dart.dart';
 import 'package:analysis_server/plugin/protocol/protocol.dart' hide ElementKind;
+import 'package:analysis_server/src/provisional/edit/utilities/change_builder_core.dart';
+import 'package:analysis_server/src/provisional/edit/utilities/change_builder_dart.dart';
 import 'package:analysis_server/src/services/correction/name_suggestion.dart';
 import 'package:analysis_server/src/services/correction/util.dart';
 import 'package:analysis_server/src/utilities/change_builder_core.dart';
diff --git a/pkg/analysis_server/pubspec.yaml b/pkg/analysis_server/pubspec.yaml
index 951b5b4..d800ed4 100644
--- a/pkg/analysis_server/pubspec.yaml
+++ b/pkg/analysis_server/pubspec.yaml
@@ -6,7 +6,7 @@
 environment:
   sdk: '>=1.12.0 <2.0.0'
 dependencies:
-  analyzer: '>=0.26.2+1 <0.27.0'
+  analyzer: '>=0.26.3 <0.27.0'
   args: '>=0.13.0 <0.14.0'
   dart_style: '>=0.2.0 <0.3.0'
   linter: ^0.1.3+2
diff --git a/pkg/analysis_server/test/abstract_context.dart b/pkg/analysis_server/test/abstract_context.dart
index 46f0dbf..8049890 100644
--- a/pkg/analysis_server/test/abstract_context.dart
+++ b/pkg/analysis_server/test/abstract_context.dart
@@ -10,6 +10,7 @@
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
 import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/java_engine.dart' show CaughtException;
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source_io.dart';
 
@@ -91,6 +92,7 @@
     context = AnalysisEngine.instance.createAnalysisContext();
     context.sourceFactory =
         new SourceFactory([SDK_RESOLVER, packageResolver, resourceResolver]);
+    AnalysisEngine.instance.logger = PrintLogger.instance;
   }
 
   void setupResourceProvider() {
@@ -100,6 +102,46 @@
   void tearDown() {
     context = null;
     provider = null;
+    AnalysisEngine.instance.logger = null;
+  }
+}
+
+/**
+ * Instances of the class [PrintLogger] print all of the errors.
+ */
+class PrintLogger implements Logger {
+  static final Logger instance = new PrintLogger();
+
+  @override
+  void logError(String message, [CaughtException exception]) {
+    print(message);
+    if (exception != null) {
+      print(exception);
+    }
+  }
+
+  @override
+  void logError2(String message, Object exception) {
+    print(message);
+    if (exception != null) {
+      print(exception);
+    }
+  }
+
+  @override
+  void logInformation(String message, [CaughtException exception]) {
+    print(message);
+    if (exception != null) {
+      print(exception);
+    }
+  }
+
+  @override
+  void logInformation2(String message, Object exception) {
+    print(message);
+    if (exception != null) {
+      print(exception);
+    }
   }
 }
 
diff --git a/pkg/analysis_server/test/analysis/get_errors_test.dart b/pkg/analysis_server/test/analysis/get_errors_test.dart
index 205cbbe..a665cfa 100644
--- a/pkg/analysis_server/test/analysis/get_errors_test.dart
+++ b/pkg/analysis_server/test/analysis/get_errors_test.dart
@@ -30,17 +30,42 @@
     createProject();
   }
 
-  test_afterAnalysisComplete() {
+  test_afterAnalysisComplete() async {
     addTestFile('''
 main() {
   print(42)
 }
 ''');
-    return waitForTasksFinished().then((_) {
-      return _getErrors(testFile).then((List<AnalysisError> errors) {
-        expect(errors, hasLength(1));
-      });
-    });
+    await waitForTasksFinished();
+    List<AnalysisError> errors = await _getErrors(testFile);
+    expect(errors, hasLength(1));
+  }
+
+  test_errorInPart() async {
+    String libPath = '$testFolder/main.dart';
+    String partPath = '$testFolder/main_part.dart';
+    addFile(
+        libPath,
+        r'''
+library main;
+part 'main_part.dart';
+class A {}
+''');
+    addFile(
+        partPath,
+        r'''
+part of main;
+class A {}
+''');
+    await waitForTasksFinished();
+    {
+      List<AnalysisError> libErrors = await _getErrors(libPath);
+      expect(libErrors, isEmpty);
+    }
+    {
+      List<AnalysisError> partErrors = await _getErrors(partPath);
+      expect(partErrors, hasLength(1));
+    }
   }
 
   test_fileDoesNotExist() {
@@ -60,69 +85,64 @@
     return _checkInvalid(file);
   }
 
-  test_hasErrors() {
+  test_hasErrors() async {
     addTestFile('''
 main() {
   print(42)
 }
 ''');
-    return _getErrors(testFile).then((List<AnalysisError> errors) {
-      expect(errors, hasLength(1));
-      {
-        AnalysisError error = errors[0];
-        expect(error.severity, AnalysisErrorSeverity.ERROR);
-        expect(error.type, AnalysisErrorType.SYNTACTIC_ERROR);
-        expect(error.location.file, testFile);
-        expect(error.location.startLine, 2);
-      }
-    });
+    List<AnalysisError> errors = await _getErrors(testFile);
+    expect(errors, hasLength(1));
+    {
+      AnalysisError error = errors[0];
+      expect(error.severity, AnalysisErrorSeverity.ERROR);
+      expect(error.type, AnalysisErrorType.SYNTACTIC_ERROR);
+      expect(error.location.file, testFile);
+      expect(error.location.startLine, 2);
+    }
   }
 
-  test_noErrors() {
+  test_noErrors() async {
     addTestFile('''
 main() {
   print(42);
 }
 ''');
-    return _getErrors(testFile).then((List<AnalysisError> errors) {
-      expect(errors, isEmpty);
-    });
+    List<AnalysisError> errors = await _getErrors(testFile);
+    expect(errors, isEmpty);
   }
 
-  test_removeContextAfterRequest() {
+  test_removeContextAfterRequest() async {
     addTestFile('''
 main() {
   print(42)
 }
 ''');
     // handle the request synchronously
-    Request request = _createGetErrorsRequest();
+    Request request = _createGetErrorsRequest(testFile);
     server.handleRequest(request);
     // remove context, causes sending an "invalid file" error
     resourceProvider.deleteFolder(projectPath);
     // wait for an error response
-    return serverChannel.waitForResponse(request).then((Response response) {
-      expect(response.error, isNotNull);
-      expect(response.error.code, RequestErrorCode.GET_ERRORS_INVALID_FILE);
-    });
+    Response response = await serverChannel.waitForResponse(request);
+    expect(response.error, isNotNull);
+    expect(response.error.code, RequestErrorCode.GET_ERRORS_INVALID_FILE);
   }
 
-  Future _checkInvalid(String file) {
-    Request request = _createGetErrorsRequest();
-    return serverChannel.sendRequest(request).then((Response response) {
-      expect(response.error, isNotNull);
-      expect(response.error.code, RequestErrorCode.GET_ERRORS_INVALID_FILE);
-    });
+  Future _checkInvalid(String file) async {
+    Request request = _createGetErrorsRequest(file);
+    Response response = await serverChannel.sendRequest(request);
+    expect(response.error, isNotNull);
+    expect(response.error.code, RequestErrorCode.GET_ERRORS_INVALID_FILE);
   }
 
-  Request _createGetErrorsRequest() {
-    return new AnalysisGetErrorsParams(testFile).toRequest(requestId);
+  Request _createGetErrorsRequest(String file) {
+    return new AnalysisGetErrorsParams(file).toRequest(requestId);
   }
 
-  Future<List<AnalysisError>> _getErrors(String file) {
-    Request request = _createGetErrorsRequest();
-    return serverChannel.sendRequest(request).then((Response response) {
-      return new AnalysisGetErrorsResult.fromResponse(response).errors;
-    });
+  Future<List<AnalysisError>> _getErrors(String file) async {
+    Request request = _createGetErrorsRequest(file);
+    Response response = await serverChannel.sendRequest(request);
+    return new AnalysisGetErrorsResult.fromResponse(response).errors;
   }
 }
diff --git a/pkg/analysis_server/test/analysis/get_hover_test.dart b/pkg/analysis_server/test/analysis/get_hover_test.dart
index 34db510..cc5befe 100644
--- a/pkg/analysis_server/test/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/analysis/get_hover_test.dart
@@ -25,15 +25,14 @@
     return prepareHoverAt(offset);
   }
 
-  Future<HoverInformation> prepareHoverAt(int offset) {
-    return waitForTasksFinished().then((_) {
-      Request request =
-          new AnalysisGetHoverParams(testFile, offset).toRequest('0');
-      Response response = handleSuccessfulRequest(request);
-      var result = new AnalysisGetHoverResult.fromResponse(response);
-      List<HoverInformation> hovers = result.hovers;
-      return hovers.isNotEmpty ? hovers.first : null;
-    });
+  Future<HoverInformation> prepareHoverAt(int offset) async {
+    await waitForTasksFinished();
+    Request request =
+        new AnalysisGetHoverParams(testFile, offset).toRequest('0');
+    Response response = handleSuccessfulRequest(request);
+    var result = new AnalysisGetHoverResult.fromResponse(response);
+    List<HoverInformation> hovers = result.hovers;
+    return hovers.isNotEmpty ? hovers.first : null;
   }
 
   @override
@@ -42,7 +41,7 @@
     createProject();
   }
 
-  test_dartdoc_clunky() {
+  test_dartdoc_clunky() async {
     addTestFile('''
 library my.library;
 /**
@@ -52,12 +51,11 @@
 main() {
 }
 ''');
-    return prepareHover('main() {').then((HoverInformation hover) {
-      expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
-    });
+    HoverInformation hover = await prepareHover('main() {');
+    expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
   }
 
-  test_dartdoc_elegant() {
+  test_dartdoc_elegant() async {
     addTestFile('''
 library my.library;
 /// doc aaa
@@ -65,12 +63,11 @@
 main() {
 }
 ''');
-    return prepareHover('main() {').then((HoverInformation hover) {
-      expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
-    });
+    HoverInformation hover = await prepareHover('main() {');
+    expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
   }
 
-  test_expression_function() {
+  test_expression_function() async {
     addTestFile('''
 library my.library;
 /// doc aaa
@@ -78,43 +75,41 @@
 List<String> fff(int a, String b) {
 }
 ''');
-    return prepareHover('fff(int a').then((HoverInformation hover) {
-      // element
-      expect(hover.containingLibraryName, 'my.library');
-      expect(hover.containingLibraryPath, testFile);
-      expect(hover.containingClassDescription, isNull);
-      expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
-      expect(hover.elementDescription, 'fff(int a, String b) → List<String>');
-      expect(hover.elementKind, 'function');
-      // types
-      expect(hover.staticType, '(int, String) → List<String>');
-      expect(hover.propagatedType, isNull);
-      // no parameter
-      expect(hover.parameter, isNull);
-    });
+    HoverInformation hover = await prepareHover('fff(int a');
+    // element
+    expect(hover.containingLibraryName, 'my.library');
+    expect(hover.containingLibraryPath, testFile);
+    expect(hover.containingClassDescription, isNull);
+    expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
+    expect(hover.elementDescription, 'fff(int a, String b) → List<String>');
+    expect(hover.elementKind, 'function');
+    // types
+    expect(hover.staticType, '(int, String) → List<String>');
+    expect(hover.propagatedType, isNull);
+    // no parameter
+    expect(hover.parameter, isNull);
   }
 
-  test_expression_literal_noElement() {
+  test_expression_literal_noElement() async {
     addTestFile('''
 main() {
   foo(123);
 }
 foo(Object myParameter) {}
 ''');
-    return prepareHover('123').then((HoverInformation hover) {
-      // literal, no Element
-      expect(hover.containingClassDescription, isNull);
-      expect(hover.elementDescription, isNull);
-      expect(hover.elementKind, isNull);
-      // types
-      expect(hover.staticType, 'int');
-      expect(hover.propagatedType, isNull);
-      // parameter
-      expect(hover.parameter, 'Object myParameter');
-    });
+    HoverInformation hover = await prepareHover('123');
+    // literal, no Element
+    expect(hover.containingClassDescription, isNull);
+    expect(hover.elementDescription, isNull);
+    expect(hover.elementKind, isNull);
+    // types
+    expect(hover.staticType, 'int');
+    expect(hover.propagatedType, isNull);
+    // parameter
+    expect(hover.parameter, 'Object myParameter');
   }
 
-  test_expression_method() {
+  test_expression_method() async {
     addTestFile('''
 library my.library;
 class A {
@@ -124,23 +119,22 @@
   }
 }
 ''');
-    return prepareHover('mmm(int a').then((HoverInformation hover) {
-      // element
-      expect(hover.containingLibraryName, 'my.library');
-      expect(hover.containingLibraryPath, testFile);
-      expect(hover.containingClassDescription, 'A');
-      expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
-      expect(hover.elementDescription, 'mmm(int a, String b) → List<String>');
-      expect(hover.elementKind, 'method');
-      // types
-      expect(hover.staticType, '(int, String) → List<String>');
-      expect(hover.propagatedType, isNull);
-      // no parameter
-      expect(hover.parameter, isNull);
-    });
+    HoverInformation hover = await prepareHover('mmm(int a');
+    // element
+    expect(hover.containingLibraryName, 'my.library');
+    expect(hover.containingLibraryPath, testFile);
+    expect(hover.containingClassDescription, 'A');
+    expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
+    expect(hover.elementDescription, 'mmm(int a, String b) → List<String>');
+    expect(hover.elementKind, 'method');
+    // types
+    expect(hover.staticType, '(int, String) → List<String>');
+    expect(hover.propagatedType, isNull);
+    // no parameter
+    expect(hover.parameter, isNull);
   }
 
-  test_expression_method_invocation() {
+  test_expression_method_invocation() async {
     addTestFile('''
 library my.library;
 class A {
@@ -151,24 +145,23 @@
   a.mmm(42, 'foo');
 }
 ''');
-    return prepareHover('mm(42, ').then((HoverInformation hover) {
-      // range
-      expect(hover.offset, findOffset('mmm(42, '));
-      expect(hover.length, 'mmm'.length);
-      // element
-      expect(hover.containingLibraryName, 'my.library');
-      expect(hover.containingLibraryPath, testFile);
-      expect(hover.elementDescription, 'mmm(int a, String b) → List<String>');
-      expect(hover.elementKind, 'method');
-      // types
-      expect(hover.staticType, isNull);
-      expect(hover.propagatedType, isNull);
-      // no parameter
-      expect(hover.parameter, isNull);
-    });
+    HoverInformation hover = await prepareHover('mm(42, ');
+    // range
+    expect(hover.offset, findOffset('mmm(42, '));
+    expect(hover.length, 'mmm'.length);
+    // element
+    expect(hover.containingLibraryName, 'my.library');
+    expect(hover.containingLibraryPath, testFile);
+    expect(hover.elementDescription, 'mmm(int a, String b) → List<String>');
+    expect(hover.elementKind, 'method');
+    // types
+    expect(hover.staticType, isNull);
+    expect(hover.propagatedType, isNull);
+    // no parameter
+    expect(hover.parameter, isNull);
   }
 
-  test_expression_parameter() {
+  test_expression_parameter() async {
     addTestFile('''
 library my.library;
 class A {
@@ -177,23 +170,22 @@
   }
 }
 ''');
-    return prepareHover('p) {').then((HoverInformation hover) {
-      // element
-      expect(hover.containingLibraryName, isNull);
-      expect(hover.containingLibraryPath, isNull);
-      expect(hover.containingClassDescription, isNull);
-      expect(hover.dartdoc, 'The method documentation.');
-      expect(hover.elementDescription, 'int p');
-      expect(hover.elementKind, 'parameter');
-      // types
-      expect(hover.staticType, 'int');
-      expect(hover.propagatedType, isNull);
-      // no parameter
-      expect(hover.parameter, isNull);
-    });
+    HoverInformation hover = await prepareHover('p) {');
+    // element
+    expect(hover.containingLibraryName, isNull);
+    expect(hover.containingLibraryPath, isNull);
+    expect(hover.containingClassDescription, isNull);
+    expect(hover.dartdoc, 'The method documentation.');
+    expect(hover.elementDescription, 'int p');
+    expect(hover.elementKind, 'parameter');
+    // types
+    expect(hover.staticType, 'int');
+    expect(hover.propagatedType, isNull);
+    // no parameter
+    expect(hover.parameter, isNull);
   }
 
-  test_expression_syntheticGetter() {
+  test_expression_syntheticGetter() async {
     addTestFile('''
 library my.library;
 class A {
@@ -205,21 +197,20 @@
   print(a.fff);
 }
 ''');
-    return prepareHover('fff);').then((HoverInformation hover) {
-      // element
-      expect(hover.containingLibraryName, 'my.library');
-      expect(hover.containingLibraryPath, testFile);
-      expect(hover.containingClassDescription, 'A');
-      expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
-      expect(hover.elementDescription, 'String fff');
-      expect(hover.elementKind, 'field');
-      // types
-      expect(hover.staticType, 'String');
-      expect(hover.propagatedType, isNull);
-    });
+    HoverInformation hover = await prepareHover('fff);');
+    // element
+    expect(hover.containingLibraryName, 'my.library');
+    expect(hover.containingLibraryPath, testFile);
+    expect(hover.containingClassDescription, 'A');
+    expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
+    expect(hover.elementDescription, 'String fff');
+    expect(hover.elementKind, 'field');
+    // types
+    expect(hover.staticType, 'String');
+    expect(hover.propagatedType, isNull);
   }
 
-  test_expression_variable_hasPropagatedType() {
+  test_expression_variable_hasPropagatedType() async {
     addTestFile('''
 library my.library;
 main() {
@@ -227,21 +218,20 @@
   print(vvv);
 }
 ''');
-    return prepareHover('vvv);').then((HoverInformation hover) {
-      // element
-      expect(hover.containingLibraryName, isNull);
-      expect(hover.containingLibraryPath, isNull);
-      expect(hover.containingClassDescription, isNull);
-      expect(hover.dartdoc, isNull);
-      expect(hover.elementDescription, 'dynamic vvv');
-      expect(hover.elementKind, 'local variable');
-      // types
-      expect(hover.staticType, 'dynamic');
-      expect(hover.propagatedType, 'int');
-    });
+    HoverInformation hover = await prepareHover('vvv);');
+    // element
+    expect(hover.containingLibraryName, isNull);
+    expect(hover.containingLibraryPath, isNull);
+    expect(hover.containingClassDescription, isNull);
+    expect(hover.dartdoc, isNull);
+    expect(hover.elementDescription, 'dynamic vvv');
+    expect(hover.elementKind, 'local variable');
+    // types
+    expect(hover.staticType, 'dynamic');
+    expect(hover.propagatedType, 'int');
   }
 
-  test_expression_variable_inMethod() {
+  test_expression_variable_inMethod() async {
     addTestFile('''
 library my.library;
 class A {
@@ -250,23 +240,22 @@
   }
 }
 ''');
-    return prepareHover('vvv = 42').then((HoverInformation hover) {
-      // element
-      expect(hover.containingLibraryName, isNull);
-      expect(hover.containingLibraryPath, isNull);
-      expect(hover.containingClassDescription, isNull);
-      expect(hover.dartdoc, isNull);
-      expect(hover.elementDescription, 'num vvv');
-      expect(hover.elementKind, 'local variable');
-      // types
-      expect(hover.staticType, 'num');
-      expect(hover.propagatedType, 'int');
-      // no parameter
-      expect(hover.parameter, isNull);
-    });
+    HoverInformation hover = await prepareHover('vvv = 42');
+    // element
+    expect(hover.containingLibraryName, isNull);
+    expect(hover.containingLibraryPath, isNull);
+    expect(hover.containingClassDescription, isNull);
+    expect(hover.dartdoc, isNull);
+    expect(hover.elementDescription, 'num vvv');
+    expect(hover.elementKind, 'local variable');
+    // types
+    expect(hover.staticType, 'num');
+    expect(hover.propagatedType, 'int');
+    // no parameter
+    expect(hover.parameter, isNull);
   }
 
-  test_instanceCreation_implicit() {
+  test_instanceCreation_implicit() async {
     addTestFile('''
 library my.library;
 class A {
@@ -275,25 +264,24 @@
   new A();
 }
 ''');
-    return prepareHover('new A').then((HoverInformation hover) {
-      // range
-      expect(hover.offset, findOffset('new A'));
-      expect(hover.length, 'new A()'.length);
-      // element
-      expect(hover.containingLibraryName, 'my.library');
-      expect(hover.containingLibraryPath, testFile);
-      expect(hover.dartdoc, isNull);
-      expect(hover.elementDescription, 'A() → A');
-      expect(hover.elementKind, 'constructor');
-      // types
-      expect(hover.staticType, 'A');
-      expect(hover.propagatedType, isNull);
-      // no parameter
-      expect(hover.parameter, isNull);
-    });
+    HoverInformation hover = await prepareHover('new A');
+    // range
+    expect(hover.offset, findOffset('new A'));
+    expect(hover.length, 'new A()'.length);
+    // element
+    expect(hover.containingLibraryName, 'my.library');
+    expect(hover.containingLibraryPath, testFile);
+    expect(hover.dartdoc, isNull);
+    expect(hover.elementDescription, 'A() → A');
+    expect(hover.elementKind, 'constructor');
+    // types
+    expect(hover.staticType, 'A');
+    expect(hover.propagatedType, isNull);
+    // no parameter
+    expect(hover.parameter, isNull);
   }
 
-  test_instanceCreation_implicit_withTypeArgument() {
+  test_instanceCreation_implicit_withTypeArgument() async {
     addTestFile('''
 library my.library;
 class A<T> {}
@@ -301,7 +289,7 @@
   new A<String>();
 }
 ''');
-    Function onConstructor = (HoverInformation hover) {
+    void onConstructor(HoverInformation hover) {
       // range
       expect(hover.offset, findOffset('new A<String>'));
       expect(hover.length, 'new A<String>()'.length);
@@ -316,18 +304,24 @@
       expect(hover.propagatedType, isNull);
       // no parameter
       expect(hover.parameter, isNull);
-    };
-    var futureNewA = prepareHover('new A').then(onConstructor);
-    var futureA = prepareHover('A<String>()').then(onConstructor);
-    var futureString = prepareHover('String>').then((HoverInformation hover) {
+    }
+    {
+      HoverInformation hover = await prepareHover('new A');
+      onConstructor(hover);
+    }
+    {
+      HoverInformation hover = await prepareHover('A<String>()');
+      onConstructor(hover);
+    }
+    {
+      HoverInformation hover = await prepareHover('String>');
       expect(hover.offset, findOffset('String>'));
       expect(hover.length, 'String'.length);
       expect(hover.elementKind, 'class');
-    });
-    return Future.wait([futureNewA, futureA, futureString]);
+    }
   }
 
-  test_instanceCreation_named() {
+  test_instanceCreation_named() async {
     addTestFile('''
 library my.library;
 class A {
@@ -338,7 +332,7 @@
   new A.named();
 }
 ''');
-    var onConstructor = (HoverInformation hover) {
+    void onConstructor(HoverInformation hover) {
       // range
       expect(hover.offset, findOffset('new A'));
       expect(hover.length, 'new A.named()'.length);
@@ -346,21 +340,25 @@
       expect(hover.dartdoc, 'my doc');
       expect(hover.elementDescription, 'A.named() → A');
       expect(hover.elementKind, 'constructor');
-    };
-    var futureCreation = prepareHover('new A').then(onConstructor);
-    var futureName = prepareHover('named();').then(onConstructor);
-    return Future.wait([futureCreation, futureName]);
+    }
+    {
+      HoverInformation hover = await prepareHover('new A');
+      onConstructor(hover);
+    }
+    {
+      HoverInformation hover = await prepareHover('named();');
+      onConstructor(hover);
+    }
   }
 
-  test_noHoverInfo() {
+  test_noHoverInfo() async {
     addTestFile('''
 library my.library;
 main() {
   // nothing
 }
 ''');
-    return prepareHover('nothing').then((HoverInformation hover) {
-      expect(hover, isNull);
-    });
+    HoverInformation hover = await prepareHover('nothing');
+    expect(hover, isNull);
   }
 }
diff --git a/pkg/analysis_server/test/analysis/notification_analyzedFiles_test.dart b/pkg/analysis_server/test/analysis/notification_analyzedFiles_test.dart
index 13c5073..0ce9e164 100644
--- a/pkg/analysis_server/test/analysis/notification_analyzedFiles_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_analyzedFiles_test.dart
@@ -49,24 +49,21 @@
     createProject();
   }
 
-  test_afterAnalysis() {
+  test_afterAnalysis() async {
     addTestFile('''
 class A {}
 ''');
-    return waitForTasksFinished().then((_) {
-      return prepareAnalyzedFiles().then((_) {
-        assertHasFile(testFile);
-      });
-    });
+    await waitForTasksFinished();
+    await prepareAnalyzedFiles();
+    assertHasFile(testFile);
   }
 
-  test_beforeAnalysis() {
+  test_beforeAnalysis() async {
     addTestFile('''
 class A {}
 ''');
-    return prepareAnalyzedFiles().then((_) {
-      assertHasFile(testFile);
-    });
+    await prepareAnalyzedFiles();
+    assertHasFile(testFile);
   }
 
   test_insignificant_change() async {
diff --git a/pkg/analysis_server/test/analysis/notification_errors_test.dart b/pkg/analysis_server/test/analysis/notification_errors_test.dart
index 46de68d..dbbe7af 100644
--- a/pkg/analysis_server/test/analysis/notification_errors_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_errors_test.dart
@@ -48,25 +48,24 @@
     super.tearDown();
   }
 
-  test_importError() {
+  test_importError() async {
     createProject();
 
     addTestFile('''
 import 'does_not_exist.dart';
 ''');
-    return waitForTasksFinished().then((_) {
-      List<AnalysisError> errors = filesErrors[testFile];
-      // Verify that we are generating only 1 error for the bad URI.
-      // https://github.com/dart-lang/sdk/issues/23754
-      expect(errors, hasLength(1));
-      AnalysisError error = errors[0];
-      expect(error.severity, AnalysisErrorSeverity.ERROR);
-      expect(error.type, AnalysisErrorType.COMPILE_TIME_ERROR);
-      expect(error.message, startsWith('Target of URI does not exist'));
-    });
+    await waitForTasksFinished();
+    List<AnalysisError> errors = filesErrors[testFile];
+    // Verify that we are generating only 1 error for the bad URI.
+    // https://github.com/dart-lang/sdk/issues/23754
+    expect(errors, hasLength(1));
+    AnalysisError error = errors[0];
+    expect(error.severity, AnalysisErrorSeverity.ERROR);
+    expect(error.type, AnalysisErrorType.COMPILE_TIME_ERROR);
+    expect(error.message, startsWith('Target of URI does not exist'));
   }
 
-  test_lintError() {
+  test_lintError() async {
     // Requires task model.
     AnalysisEngine.instance.useTaskModel = true;
 
@@ -86,69 +85,64 @@
         new AnalysisSetAnalysisRootsParams([projectPath], []).toRequest('0');
     handleSuccessfulRequest(request);
 
-    return waitForTasksFinished().then((_) {
-      AnalysisContext testContext = server.getContainingContext(testFile);
-      List<Linter> lints = getLints(testContext);
-      // Registry should only contain single lint rule.
-      expect(lints, hasLength(1));
-      LintRule lint = lints.first as LintRule;
-      expect(lint.name, camelCaseTypesLintName);
-      // Verify lint error result.
-      List<AnalysisError> errors = filesErrors[testFile];
-      expect(errors, hasLength(1));
-      AnalysisError error = errors[0];
-      expect(error.location.file, '/project/bin/test.dart');
-      expect(error.severity, AnalysisErrorSeverity.INFO);
-      expect(error.type, AnalysisErrorType.LINT);
-      expect(error.message, lint.description);
-    });
+    await waitForTasksFinished();
+    AnalysisContext testContext = server.getContainingContext(testFile);
+    List<Linter> lints = getLints(testContext);
+    // Registry should only contain single lint rule.
+    expect(lints, hasLength(1));
+    LintRule lint = lints.first as LintRule;
+    expect(lint.name, camelCaseTypesLintName);
+    // Verify lint error result.
+    List<AnalysisError> errors = filesErrors[testFile];
+    expect(errors, hasLength(1));
+    AnalysisError error = errors[0];
+    expect(error.location.file, '/project/bin/test.dart');
+    expect(error.severity, AnalysisErrorSeverity.INFO);
+    expect(error.type, AnalysisErrorType.LINT);
+    expect(error.message, lint.description);
   }
 
-  test_notInAnalysisRoot() {
+  test_notInAnalysisRoot() async {
     createProject();
     String otherFile = '/other.dart';
     addFile(otherFile, 'UnknownType V;');
     addTestFile('''
 import '/other.dart';
-
 main() {
   print(V);
 }
 ''');
-    return waitForTasksFinished().then((_) {
-      expect(filesErrors[otherFile], isNull);
-    });
+    await waitForTasksFinished();
+    expect(filesErrors[otherFile], isNull);
   }
 
-  test_ParserError() {
+  test_ParserError() async {
     createProject();
     addTestFile('library lib');
-    return waitForTasksFinished().then((_) {
-      List<AnalysisError> errors = filesErrors[testFile];
-      expect(errors, hasLength(1));
-      AnalysisError error = errors[0];
-      expect(error.location.file, '/project/bin/test.dart');
-      expect(error.location.offset, isPositive);
-      expect(error.location.length, isNonNegative);
-      expect(error.severity, AnalysisErrorSeverity.ERROR);
-      expect(error.type, AnalysisErrorType.SYNTACTIC_ERROR);
-      expect(error.message, isNotNull);
-    });
+    await waitForTasksFinished();
+    List<AnalysisError> errors = filesErrors[testFile];
+    expect(errors, hasLength(1));
+    AnalysisError error = errors[0];
+    expect(error.location.file, '/project/bin/test.dart');
+    expect(error.location.offset, isPositive);
+    expect(error.location.length, isNonNegative);
+    expect(error.severity, AnalysisErrorSeverity.ERROR);
+    expect(error.type, AnalysisErrorType.SYNTACTIC_ERROR);
+    expect(error.message, isNotNull);
   }
 
-  test_StaticWarning() {
+  test_StaticWarning() async {
     createProject();
     addTestFile('''
 main() {
   print(UNKNOWN);
 }
 ''');
-    return waitForTasksFinished().then((_) {
-      List<AnalysisError> errors = filesErrors[testFile];
-      expect(errors, hasLength(1));
-      AnalysisError error = errors[0];
-      expect(error.severity, AnalysisErrorSeverity.WARNING);
-      expect(error.type, AnalysisErrorType.STATIC_WARNING);
-    });
+    await waitForTasksFinished();
+    List<AnalysisError> errors = filesErrors[testFile];
+    expect(errors, hasLength(1));
+    AnalysisError error = errors[0];
+    expect(error.severity, AnalysisErrorSeverity.WARNING);
+    expect(error.type, AnalysisErrorType.STATIC_WARNING);
   }
 }
diff --git a/pkg/analysis_server/test/analysis/notification_highlights_test.dart b/pkg/analysis_server/test/analysis/notification_highlights_test.dart
index a44d798..6c2b57a3 100644
--- a/pkg/analysis_server/test/analysis/notification_highlights_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_highlights_test.dart
@@ -108,58 +108,54 @@
     createProject();
   }
 
-  test_ANNOTATION_hasArguments() {
+  test_ANNOTATION_hasArguments() async {
     addTestFile('''
 class AAA {
   const AAA(a, b, c);
 }
 @AAA(1, 2, 3) main() {}
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.ANNOTATION, '@AAA(', '@AAA('.length);
-      assertHasRegion(HighlightRegionType.ANNOTATION, ') main', ')'.length);
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.ANNOTATION, '@AAA(', '@AAA('.length);
+    assertHasRegion(HighlightRegionType.ANNOTATION, ') main', ')'.length);
   }
 
-  test_ANNOTATION_noArguments() {
+  test_ANNOTATION_noArguments() async {
     addTestFile('''
 const AAA = 42;
 @AAA main() {}
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.ANNOTATION, '@AAA');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.ANNOTATION, '@AAA');
   }
 
-  test_BUILT_IN_abstract() {
+  test_BUILT_IN_abstract() async {
     addTestFile('''
 abstract class A {};
 abstract class B = Object with A;
 main() {
   var abstract = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'abstract class A');
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'abstract class B');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'abstract = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'abstract class A');
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'abstract class B');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'abstract = 42');
   }
 
-  test_BUILT_IN_as() {
+  test_BUILT_IN_as() async {
     addTestFile('''
 import 'dart:math' as math;
 main() {
   p as int;
   var as = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'as math');
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'as int');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'as = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'as math');
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'as int');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'as = 42');
   }
 
-  test_BUILT_IN_async() {
+  test_BUILT_IN_async() async {
     addTestFile('''
 fa() async {}
 fb() async* {}
@@ -167,14 +163,13 @@
   bool async = false;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasStringRegion(HighlightRegionType.BUILT_IN, 'async');
-      assertHasStringRegion(HighlightRegionType.BUILT_IN, 'async*');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'async = false');
-    });
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.BUILT_IN, 'async');
+    assertHasStringRegion(HighlightRegionType.BUILT_IN, 'async*');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'async = false');
   }
 
-  test_BUILT_IN_await() {
+  test_BUILT_IN_await() async {
     addTestFile('''
 main() async {
   await 42;
@@ -183,37 +178,34 @@
   }
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'await 42');
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'await for');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'await 42');
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'await for');
   }
 
-  test_BUILT_IN_deferred() {
+  test_BUILT_IN_deferred() async {
     addTestFile('''
 import 'dart:math' deferred as math;
 main() {
   var deferred = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'deferred as math');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'deferred = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'deferred as math');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'deferred = 42');
   }
 
-  test_BUILT_IN_export() {
+  test_BUILT_IN_export() async {
     addTestFile('''
 export "dart:math";
 main() {
   var export = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'export "dart:');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'export = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'export "dart:');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'export = 42');
   }
 
-  test_BUILT_IN_external() {
+  test_BUILT_IN_external() async {
     addTestFile('''
 class A {
   external A();
@@ -222,15 +214,14 @@
 external main() {
   var external = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'external A()');
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'external aaa()');
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'external main()');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'external = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'external A()');
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'external aaa()');
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'external main()');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'external = 42');
   }
 
-  test_BUILT_IN_factory() {
+  test_BUILT_IN_factory() async {
     addTestFile('''
 class A {
   factory A() => null;
@@ -238,13 +229,12 @@
 main() {
   var factory = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'factory A()');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'factory = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'factory A()');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'factory = 42');
   }
 
-  test_BUILT_IN_get() {
+  test_BUILT_IN_get() async {
     addTestFile('''
 get aaa => 1;
 class A {
@@ -253,63 +243,58 @@
 main() {
   var get = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'get aaa =>');
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'get bbb =>');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'get = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'get aaa =>');
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'get bbb =>');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'get = 42');
   }
 
-  test_BUILT_IN_hide() {
+  test_BUILT_IN_hide() async {
     addTestFile('''
 import 'foo.dart' hide Foo;
 main() {
   var hide = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'hide Foo');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'hide = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'hide Foo');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'hide = 42');
   }
 
-  test_BUILT_IN_implements() {
+  test_BUILT_IN_implements() async {
     addTestFile('''
 class A {}
 class B implements A {}
 main() {
   var implements = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'implements A {}');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'implements = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'implements A {}');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'implements = 42');
   }
 
-  test_BUILT_IN_import() {
+  test_BUILT_IN_import() async {
     addTestFile('''
 import "foo.dart";
 main() {
   var import = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'import "');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'import = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'import "');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'import = 42');
   }
 
-  test_BUILT_IN_library() {
+  test_BUILT_IN_library() async {
     addTestFile('''
 library lib;
 main() {
   var library = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'library lib;');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'library = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'library lib;');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'library = 42');
   }
 
-  test_BUILT_IN_native() {
+  test_BUILT_IN_native() async {
     addTestFile('''
 class A native "A_native" {}
 class B {
@@ -318,14 +303,13 @@
 main() {
   var native = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'native "A_');
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'native "bbb_');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'native = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'native "A_');
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'native "bbb_');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'native = 42');
   }
 
-  test_BUILT_IN_on() {
+  test_BUILT_IN_on() async {
     addTestFile('''
 main() {
   try {
@@ -333,13 +317,12 @@
   }
   var on = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'on int');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'on = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'on int');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'on = 42');
   }
 
-  test_BUILT_IN_operator() {
+  test_BUILT_IN_operator() async {
     addTestFile('''
 class A {
   operator +(x) => null;
@@ -347,26 +330,24 @@
 main() {
   var operator = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'operator +(');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'operator = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'operator +(');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'operator = 42');
   }
 
-  test_BUILT_IN_part() {
+  test_BUILT_IN_part() async {
     addTestFile('''
 part "my_part.dart";
 main() {
   var part = 42;
 }''');
     addFile('/project/bin/my_part.dart', 'part of lib;');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'part "my_');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'part = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'part "my_');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'part = 42');
   }
 
-  test_BUILT_IN_partOf() {
+  test_BUILT_IN_partOf() async {
     addTestFile('''
 part of lib;
 main() {
@@ -374,15 +355,13 @@
   var of = 2;
 }''');
     _addLibraryForTestPart();
-    return prepareHighlights().then((_) {
-      assertHasRegion(
-          HighlightRegionType.BUILT_IN, 'part of', 'part of'.length);
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'part = 1');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'of = 2');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'part of', 'part of'.length);
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'part = 1');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'of = 2');
   }
 
-  test_BUILT_IN_set() {
+  test_BUILT_IN_set() async {
     addTestFile('''
 set aaa(x) {}
 class A
@@ -391,26 +370,24 @@
 main() {
   var set = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'set aaa(');
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'set bbb(');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'set = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'set aaa(');
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'set bbb(');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'set = 42');
   }
 
-  test_BUILT_IN_show() {
+  test_BUILT_IN_show() async {
     addTestFile('''
 import 'foo.dart' show Foo;
 main() {
   var show = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'show Foo');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'show = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'show Foo');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'show = 42');
   }
 
-  test_BUILT_IN_static() {
+  test_BUILT_IN_static() async {
     addTestFile('''
 class A {
   static aaa;
@@ -419,14 +396,13 @@
 main() {
   var static = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'static aaa;');
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'static bbb()');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'static = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'static aaa;');
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'static bbb()');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'static = 42');
   }
 
-  test_BUILT_IN_sync() {
+  test_BUILT_IN_sync() async {
     addTestFile('''
 fa() sync {}
 fb() sync* {}
@@ -434,81 +410,74 @@
   bool sync = false;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasStringRegion(HighlightRegionType.BUILT_IN, 'sync');
-      assertHasStringRegion(HighlightRegionType.BUILT_IN, 'sync*');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'sync = false');
-    });
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.BUILT_IN, 'sync');
+    assertHasStringRegion(HighlightRegionType.BUILT_IN, 'sync*');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'sync = false');
   }
 
-  test_BUILT_IN_typedef() {
+  test_BUILT_IN_typedef() async {
     addTestFile('''
 typedef A();
 main() {
   var typedef = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'typedef A();');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'typedef = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'typedef A();');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'typedef = 42');
   }
 
-  test_BUILT_IN_yield() {
+  test_BUILT_IN_yield() async {
     addTestFile('''
 main() async* {
   yield 42;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'yield 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'yield 42');
   }
 
-  test_BUILT_IN_yieldStar() {
+  test_BUILT_IN_yieldStar() async {
     addTestFile('''
 main() async* {
   yield* [];
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasStringRegion(HighlightRegionType.BUILT_IN, 'yield*');
-    });
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.BUILT_IN, 'yield*');
   }
 
-  test_CLASS() {
+  test_CLASS() async {
     addTestFile('''
 class AAA {}
 AAA aaa;
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.CLASS, 'AAA {}');
-      assertHasRegion(HighlightRegionType.CLASS, 'AAA aaa');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.CLASS, 'AAA {}');
+    assertHasRegion(HighlightRegionType.CLASS, 'AAA aaa');
   }
 
-  test_CLASS_notDynamic() {
+  test_CLASS_notDynamic() async {
     addTestFile('''
 dynamic f() {}
 ''');
-    return prepareHighlights().then((_) {
-      assertNoRegion(HighlightRegionType.CLASS, 'dynamic f()');
-    });
+    await prepareHighlights();
+    assertNoRegion(HighlightRegionType.CLASS, 'dynamic f()');
   }
 
-  test_CLASS_notVoid() {
+  test_CLASS_notVoid() async {
     addTestFile('''
 void f() {}
 ''');
-    return prepareHighlights().then((_) {
-      assertNoRegion(HighlightRegionType.CLASS, 'void f()');
-    });
+    await prepareHighlights();
+    assertNoRegion(HighlightRegionType.CLASS, 'void f()');
   }
 
-  test_COMMENT() {
+  test_COMMENT() async {
     addTestFile('''
 /**
  * documentation comment
- */ 
+ */
 void main() {
   // end-of-line comment
   my_function(1);
@@ -518,14 +487,13 @@
  /* block comment */
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.COMMENT_DOCUMENTATION, '/**', 32);
-      assertHasRegion(HighlightRegionType.COMMENT_END_OF_LINE, '//', 22);
-      assertHasRegion(HighlightRegionType.COMMENT_BLOCK, '/* b', 19);
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.COMMENT_DOCUMENTATION, '/**', 32);
+    assertHasRegion(HighlightRegionType.COMMENT_END_OF_LINE, '//', 22);
+    assertHasRegion(HighlightRegionType.COMMENT_BLOCK, '/* b', 19);
   }
 
-  test_CONSTRUCTOR() {
+  test_CONSTRUCTOR() async {
     addTestFile('''
 class AAA {
   AAA() {}
@@ -536,42 +504,37 @@
   new AAA.name(42);
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'name(p)');
-      assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'name(42)');
-      assertNoRegion(HighlightRegionType.CONSTRUCTOR, 'AAA() {}');
-      assertNoRegion(HighlightRegionType.CONSTRUCTOR, 'AAA();');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'name(p)');
+    assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'name(42)');
+    assertNoRegion(HighlightRegionType.CONSTRUCTOR, 'AAA() {}');
+    assertNoRegion(HighlightRegionType.CONSTRUCTOR, 'AAA();');
   }
 
-  test_DIRECTIVE() {
+  test_DIRECTIVE() async {
     addTestFile('''
 library lib;
 import 'dart:math';
 export 'dart:math';
 part 'part.dart';
 ''');
-    return prepareHighlights().then((_) {
-      assertHasStringRegion(HighlightRegionType.DIRECTIVE, "library lib;");
-      assertHasStringRegion(
-          HighlightRegionType.DIRECTIVE, "import 'dart:math';");
-      assertHasStringRegion(
-          HighlightRegionType.DIRECTIVE, "export 'dart:math';");
-      assertHasStringRegion(HighlightRegionType.DIRECTIVE, "part 'part.dart';");
-    });
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.DIRECTIVE, "library lib;");
+    assertHasStringRegion(HighlightRegionType.DIRECTIVE, "import 'dart:math';");
+    assertHasStringRegion(HighlightRegionType.DIRECTIVE, "export 'dart:math';");
+    assertHasStringRegion(HighlightRegionType.DIRECTIVE, "part 'part.dart';");
   }
 
-  test_DIRECTIVE_partOf() {
+  test_DIRECTIVE_partOf() async {
     addTestFile('''
 part of lib;
 ''');
     _addLibraryForTestPart();
-    return prepareHighlights().then((_) {
-      assertHasStringRegion(HighlightRegionType.DIRECTIVE, "part of lib;");
-    });
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.DIRECTIVE, "part of lib;");
   }
 
-  test_DYNAMIC_TYPE() {
+  test_DYNAMIC_TYPE() async {
     addTestFile('''
 f() {}
 main(p) {
@@ -581,26 +544,24 @@
   var v3 = v2;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.DYNAMIC_TYPE, 'p)');
-      assertHasRegion(HighlightRegionType.DYNAMIC_TYPE, 'v1 =');
-      assertNoRegion(HighlightRegionType.DYNAMIC_TYPE, 'v2;');
-      assertNoRegion(HighlightRegionType.DYNAMIC_TYPE, 'v3 =');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.DYNAMIC_TYPE, 'p)');
+    assertHasRegion(HighlightRegionType.DYNAMIC_TYPE, 'v1 =');
+    assertNoRegion(HighlightRegionType.DYNAMIC_TYPE, 'v2;');
+    assertNoRegion(HighlightRegionType.DYNAMIC_TYPE, 'v3 =');
   }
 
-  test_ENUM() {
+  test_ENUM() async {
     addTestFile('''
 enum MyEnum {A, B, C}
 MyEnum value;
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.ENUM, 'MyEnum {');
-      assertHasRegion(HighlightRegionType.ENUM, 'MyEnum value;');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.ENUM, 'MyEnum {');
+    assertHasRegion(HighlightRegionType.ENUM, 'MyEnum value;');
   }
 
-  test_ENUM_CONSTANT() {
+  test_ENUM_CONSTANT() async {
     addTestFile('''
 enum MyEnum {AAA, BBB}
 main() {
@@ -608,15 +569,14 @@
   print(MyEnum.BBB);
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'AAA, ');
-      assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'BBB}');
-      assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'AAA);');
-      assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'BBB);');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'AAA, ');
+    assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'BBB}');
+    assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'AAA);');
+    assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'BBB);');
   }
 
-  test_FIELD() {
+  test_FIELD() async {
     addTestFile('''
 class A {
   int aaa = 1;
@@ -628,16 +588,15 @@
   a.bbb = 5;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.FIELD, 'aaa = 1');
-      assertHasRegion(HighlightRegionType.FIELD, 'bbb = 2');
-      assertHasRegion(HighlightRegionType.FIELD, 'bbb = 3');
-      assertHasRegion(HighlightRegionType.FIELD, 'aaa = 4');
-      assertHasRegion(HighlightRegionType.FIELD, 'bbb = 5');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.FIELD, 'aaa = 1');
+    assertHasRegion(HighlightRegionType.FIELD, 'bbb = 2');
+    assertHasRegion(HighlightRegionType.FIELD, 'bbb = 3');
+    assertHasRegion(HighlightRegionType.FIELD, 'aaa = 4');
+    assertHasRegion(HighlightRegionType.FIELD, 'bbb = 5');
   }
 
-  test_FIELD_STATIC() {
+  test_FIELD_STATIC() async {
     addTestFile('''
 class A {
   static aaa = 1;
@@ -650,40 +609,37 @@
   A.ccc = 3;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.FIELD_STATIC, 'aaa = 1');
-      assertHasRegion(HighlightRegionType.FIELD_STATIC, 'aaa = 2');
-      assertHasRegion(HighlightRegionType.FIELD_STATIC, 'bbb;');
-      assertHasRegion(HighlightRegionType.FIELD_STATIC, 'ccc = 3');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.FIELD_STATIC, 'aaa = 1');
+    assertHasRegion(HighlightRegionType.FIELD_STATIC, 'aaa = 2');
+    assertHasRegion(HighlightRegionType.FIELD_STATIC, 'bbb;');
+    assertHasRegion(HighlightRegionType.FIELD_STATIC, 'ccc = 3');
   }
 
-  test_FUNCTION() {
+  test_FUNCTION() async {
     addTestFile('''
 fff(p) {}
 main() {
   fff(42);
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.FUNCTION_DECLARATION, 'fff(p) {}');
-      assertHasRegion(HighlightRegionType.FUNCTION, 'fff(42)');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.FUNCTION_DECLARATION, 'fff(p) {}');
+    assertHasRegion(HighlightRegionType.FUNCTION, 'fff(42)');
   }
 
-  test_FUNCTION_TYPE_ALIAS() {
+  test_FUNCTION_TYPE_ALIAS() async {
     addTestFile('''
 typedef FFF(p);
 main(FFF fff) {
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'FFF(p)');
-      assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'FFF fff)');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'FFF(p)');
+    assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'FFF fff)');
   }
 
-  test_GETTER_DECLARATION() {
+  test_GETTER_DECLARATION() async {
     addTestFile('''
 get aaa => null;
 class A {
@@ -694,15 +650,14 @@
   a.bbb;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.GETTER_DECLARATION, 'aaa => null');
-      assertHasRegion(HighlightRegionType.GETTER_DECLARATION, 'bbb => null');
-      assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'aaa;');
-      assertHasRegion(HighlightRegionType.FIELD, 'bbb;');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.GETTER_DECLARATION, 'aaa => null');
+    assertHasRegion(HighlightRegionType.GETTER_DECLARATION, 'bbb => null');
+    assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'aaa;');
+    assertHasRegion(HighlightRegionType.FIELD, 'bbb;');
   }
 
-  test_IDENTIFIER_DEFAULT() {
+  test_IDENTIFIER_DEFAULT() async {
     addTestFile('''
 main() {
   aaa = 42;
@@ -710,27 +665,25 @@
   CCC ccc;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'aaa = 42');
-      assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'bbb(84)');
-      assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'CCC ccc');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'aaa = 42');
+    assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'bbb(84)');
+    assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'CCC ccc');
   }
 
-  test_IMPORT_PREFIX() {
+  test_IMPORT_PREFIX() async {
     addTestFile('''
 import 'dart:math' as ma;
 main() {
   ma.max(1, 2);
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.IMPORT_PREFIX, 'ma;');
-      assertHasRegion(HighlightRegionType.IMPORT_PREFIX, 'ma.max');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.IMPORT_PREFIX, 'ma;');
+    assertHasRegion(HighlightRegionType.IMPORT_PREFIX, 'ma.max');
   }
 
-  test_KEYWORD() {
+  test_KEYWORD() async {
     addTestFile('''
 main() {
   assert(true);
@@ -763,49 +716,47 @@
 }
 class C = Object with A;
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.KEYWORD, 'assert(true)');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'for (;;)');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'for (var v4 in');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'break;');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'case 0:');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'catch (e) {}');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'class A {}');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'const v1');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'continue;');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'default:');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'do {} while');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'if (true)');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'false;');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'final v3 =');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'finally {}');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'in []');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'is int');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'new A();');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'rethrow;');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'return this');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'super();');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'switch (0)');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'this;');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'true;');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'try {');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'while (true) {}');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'while (true);');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'with A;');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'assert(true)');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'for (;;)');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'for (var v4 in');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'break;');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'case 0:');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'catch (e) {}');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'class A {}');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'const v1');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'continue;');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'default:');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'do {} while');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'if (true)');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'false;');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'final v3 =');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'finally {}');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'in []');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'is int');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'new A();');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'rethrow;');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'return this');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'super();');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'switch (0)');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'this;');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'true;');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'try {');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'while (true) {}');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'while (true);');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'with A;');
   }
 
-  test_KEYWORD_void() {
+  test_KEYWORD_void() async {
     addTestFile('''
 void main() {
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.KEYWORD, 'void main()');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'void main()');
   }
 
-  test_LABEL() {
+  test_LABEL() async {
     addTestFile('''
 main() {
 myLabel:
@@ -814,57 +765,50 @@
   }
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.LABEL, 'myLabel:');
-      assertHasRegion(HighlightRegionType.LABEL, 'myLabel;');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.LABEL, 'myLabel:');
+    assertHasRegion(HighlightRegionType.LABEL, 'myLabel;');
   }
 
-  test_LITERAL_BOOLEAN() {
+  test_LITERAL_BOOLEAN() async {
     addTestFile('var V = true;');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.LITERAL_BOOLEAN, 'true;');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.LITERAL_BOOLEAN, 'true;');
   }
 
-  test_LITERAL_DOUBLE() {
+  test_LITERAL_DOUBLE() async {
     addTestFile('var V = 4.2;');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.LITERAL_DOUBLE, '4.2;', '4.2'.length);
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.LITERAL_DOUBLE, '4.2;', '4.2'.length);
   }
 
-  test_LITERAL_INTEGER() {
+  test_LITERAL_INTEGER() async {
     addTestFile('var V = 42;');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.LITERAL_INTEGER, '42;');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.LITERAL_INTEGER, '42;');
   }
 
-  test_LITERAL_LIST() {
+  test_LITERAL_LIST() async {
     addTestFile('var V = <int>[1, 2, 3];');
-    return prepareHighlights().then((_) {
-      assertHasStringRegion(HighlightRegionType.LITERAL_LIST, '<int>[1, 2, 3]');
-    });
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.LITERAL_LIST, '<int>[1, 2, 3]');
   }
 
-  test_LITERAL_MAP() {
+  test_LITERAL_MAP() async {
     addTestFile("var V = const <int, String>{1: 'a', 2: 'b', 3: 'c'};");
-    return prepareHighlights().then((_) {
-      assertHasStringRegion(HighlightRegionType.LITERAL_MAP,
-          "const <int, String>{1: 'a', 2: 'b', 3: 'c'}");
-    });
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.LITERAL_MAP,
+        "const <int, String>{1: 'a', 2: 'b', 3: 'c'}");
   }
 
-  test_LITERAL_STRING() {
+  test_LITERAL_STRING() async {
     addTestFile('var V = "abc";');
-    return prepareHighlights().then((_) {
-      assertHasRegion(
-          HighlightRegionType.LITERAL_STRING, '"abc";', '"abc"'.length);
-    });
+    await prepareHighlights();
+    assertHasRegion(
+        HighlightRegionType.LITERAL_STRING, '"abc";', '"abc"'.length);
   }
 
-  test_LOCAL_VARIABLE() {
+  test_LOCAL_VARIABLE() async {
     addTestFile('''
 main() {
   int vvv = 0;
@@ -872,15 +816,13 @@
   vvv = 1;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(
-          HighlightRegionType.LOCAL_VARIABLE_DECLARATION, 'vvv = 0');
-      assertHasRegion(HighlightRegionType.LOCAL_VARIABLE, 'vvv;');
-      assertHasRegion(HighlightRegionType.LOCAL_VARIABLE, 'vvv = 1;');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.LOCAL_VARIABLE_DECLARATION, 'vvv = 0');
+    assertHasRegion(HighlightRegionType.LOCAL_VARIABLE, 'vvv;');
+    assertHasRegion(HighlightRegionType.LOCAL_VARIABLE, 'vvv = 1;');
   }
 
-  test_METHOD() {
+  test_METHOD() async {
     addTestFile('''
 class A {
   aaa() {}
@@ -893,18 +835,16 @@
   A.bbb;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.METHOD_DECLARATION, 'aaa() {}');
-      assertHasRegion(
-          HighlightRegionType.METHOD_DECLARATION_STATIC, 'bbb() {}');
-      assertHasRegion(HighlightRegionType.METHOD, 'aaa();');
-      assertHasRegion(HighlightRegionType.METHOD, 'aaa;');
-      assertHasRegion(HighlightRegionType.METHOD_STATIC, 'bbb();');
-      assertHasRegion(HighlightRegionType.METHOD_STATIC, 'bbb;');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.METHOD_DECLARATION, 'aaa() {}');
+    assertHasRegion(HighlightRegionType.METHOD_DECLARATION_STATIC, 'bbb() {}');
+    assertHasRegion(HighlightRegionType.METHOD, 'aaa();');
+    assertHasRegion(HighlightRegionType.METHOD, 'aaa;');
+    assertHasRegion(HighlightRegionType.METHOD_STATIC, 'bbb();');
+    assertHasRegion(HighlightRegionType.METHOD_STATIC, 'bbb;');
   }
 
-  test_METHOD_bestType() {
+  test_METHOD_bestType() async {
     addTestFile('''
 main(p) {
   if (p is List) {
@@ -912,26 +852,24 @@
   }
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.METHOD, 'add(null)');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.METHOD, 'add(null)');
   }
 
-  test_PARAMETER() {
+  test_PARAMETER() async {
     addTestFile('''
 main(int p) {
   p;
   p = 42;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.PARAMETER, 'p) {');
-      assertHasRegion(HighlightRegionType.PARAMETER, 'p;');
-      assertHasRegion(HighlightRegionType.PARAMETER, 'p = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.PARAMETER, 'p) {');
+    assertHasRegion(HighlightRegionType.PARAMETER, 'p;');
+    assertHasRegion(HighlightRegionType.PARAMETER, 'p = 42');
   }
 
-  test_SETTER_DECLARATION() {
+  test_SETTER_DECLARATION() async {
     addTestFile('''
 set aaa(x) {}
 class A {
@@ -942,15 +880,14 @@
   a.bbb = 2;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.SETTER_DECLARATION, 'aaa(x)');
-      assertHasRegion(HighlightRegionType.SETTER_DECLARATION, 'bbb(x)');
-      assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'aaa = 1');
-      assertHasRegion(HighlightRegionType.FIELD, 'bbb = 2');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.SETTER_DECLARATION, 'aaa(x)');
+    assertHasRegion(HighlightRegionType.SETTER_DECLARATION, 'bbb(x)');
+    assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'aaa = 1');
+    assertHasRegion(HighlightRegionType.FIELD, 'bbb = 2');
   }
 
-  test_TOP_LEVEL_VARIABLE() {
+  test_TOP_LEVEL_VARIABLE() async {
     addTestFile('''
 const VVV = 0;
 @VVV // annotation
@@ -959,41 +896,38 @@
   VVV = 1;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'VVV = 0');
-      assertHasRegion(
-          HighlightRegionType.TOP_LEVEL_VARIABLE, 'VVV // annotation');
-      assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'VVV);');
-      assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'VVV = 1');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'VVV = 0');
+    assertHasRegion(
+        HighlightRegionType.TOP_LEVEL_VARIABLE, 'VVV // annotation');
+    assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'VVV);');
+    assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'VVV = 1');
   }
 
-  test_TYPE_NAME_DYNAMIC() {
+  test_TYPE_NAME_DYNAMIC() async {
     addTestFile('''
 dynamic main() {
   dynamic = 42;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.TYPE_NAME_DYNAMIC, 'dynamic main()');
-      assertNoRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'dynamic main()');
-      assertNoRegion(HighlightRegionType.TYPE_NAME_DYNAMIC, 'dynamic = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.TYPE_NAME_DYNAMIC, 'dynamic main()');
+    assertNoRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'dynamic main()');
+    assertNoRegion(HighlightRegionType.TYPE_NAME_DYNAMIC, 'dynamic = 42');
   }
 
-  test_TYPE_PARAMETER() {
+  test_TYPE_PARAMETER() async {
     addTestFile('''
 class A<T> {
   T fff;
   T mmm(T p) => null;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T> {');
-      assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T fff;');
-      assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T mmm(');
-      assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T p)');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T> {');
+    assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T fff;');
+    assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T mmm(');
+    assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T p)');
   }
 
   void _addLibraryForTestPart() {
diff --git a/pkg/analysis_server/test/analysis/notification_highlights_test2.dart b/pkg/analysis_server/test/analysis/notification_highlights_test2.dart
index 28eda94..0342c89 100644
--- a/pkg/analysis_server/test/analysis/notification_highlights_test2.dart
+++ b/pkg/analysis_server/test/analysis/notification_highlights_test2.dart
@@ -109,58 +109,54 @@
     createProject();
   }
 
-  test_ANNOTATION_hasArguments() {
+  test_ANNOTATION_hasArguments() async {
     addTestFile('''
 class AAA {
   const AAA(a, b, c);
 }
 @AAA(1, 2, 3) main() {}
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.ANNOTATION, '@AAA(', '@AAA('.length);
-      assertHasRegion(HighlightRegionType.ANNOTATION, ') main', ')'.length);
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.ANNOTATION, '@AAA(', '@AAA('.length);
+    assertHasRegion(HighlightRegionType.ANNOTATION, ') main', ')'.length);
   }
 
-  test_ANNOTATION_noArguments() {
+  test_ANNOTATION_noArguments() async {
     addTestFile('''
 const AAA = 42;
 @AAA main() {}
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.ANNOTATION, '@AAA');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.ANNOTATION, '@AAA');
   }
 
-  test_BUILT_IN_abstract() {
+  test_BUILT_IN_abstract() async {
     addTestFile('''
 abstract class A {};
 abstract class B = Object with A;
 main() {
   var abstract = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'abstract class A');
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'abstract class B');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'abstract = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'abstract class A');
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'abstract class B');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'abstract = 42');
   }
 
-  test_BUILT_IN_as() {
+  test_BUILT_IN_as() async {
     addTestFile('''
 import 'dart:math' as math;
 main() {
   p as int;
   var as = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'as math');
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'as int');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'as = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'as math');
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'as int');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'as = 42');
   }
 
-  test_BUILT_IN_async() {
+  test_BUILT_IN_async() async {
     addTestFile('''
 fa() async {}
 fb() async* {}
@@ -168,14 +164,13 @@
   bool async = false;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasStringRegion(HighlightRegionType.BUILT_IN, 'async');
-      assertHasStringRegion(HighlightRegionType.BUILT_IN, 'async*');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'async = false');
-    });
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.BUILT_IN, 'async');
+    assertHasStringRegion(HighlightRegionType.BUILT_IN, 'async*');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'async = false');
   }
 
-  test_BUILT_IN_await() {
+  test_BUILT_IN_await() async {
     addTestFile('''
 main() async {
   await 42;
@@ -184,37 +179,34 @@
   }
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'await 42');
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'await for');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'await 42');
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'await for');
   }
 
-  test_BUILT_IN_deferred() {
+  test_BUILT_IN_deferred() async {
     addTestFile('''
 import 'dart:math' deferred as math;
 main() {
   var deferred = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'deferred as math');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'deferred = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'deferred as math');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'deferred = 42');
   }
 
-  test_BUILT_IN_export() {
+  test_BUILT_IN_export() async {
     addTestFile('''
 export "dart:math";
 main() {
   var export = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'export "dart:');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'export = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'export "dart:');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'export = 42');
   }
 
-  test_BUILT_IN_external() {
+  test_BUILT_IN_external() async {
     addTestFile('''
 class A {
   external A();
@@ -223,15 +215,14 @@
 external main() {
   var external = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'external A()');
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'external aaa()');
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'external main()');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'external = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'external A()');
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'external aaa()');
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'external main()');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'external = 42');
   }
 
-  test_BUILT_IN_factory() {
+  test_BUILT_IN_factory() async {
     addTestFile('''
 class A {
   factory A() => null;
@@ -239,13 +230,12 @@
 main() {
   var factory = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'factory A()');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'factory = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'factory A()');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'factory = 42');
   }
 
-  test_BUILT_IN_get() {
+  test_BUILT_IN_get() async {
     addTestFile('''
 get aaa => 1;
 class A {
@@ -254,63 +244,58 @@
 main() {
   var get = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'get aaa =>');
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'get bbb =>');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'get = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'get aaa =>');
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'get bbb =>');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'get = 42');
   }
 
-  test_BUILT_IN_hide() {
+  test_BUILT_IN_hide() async {
     addTestFile('''
 import 'foo.dart' hide Foo;
 main() {
   var hide = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'hide Foo');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'hide = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'hide Foo');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'hide = 42');
   }
 
-  test_BUILT_IN_implements() {
+  test_BUILT_IN_implements() async {
     addTestFile('''
 class A {}
 class B implements A {}
 main() {
   var implements = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'implements A {}');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'implements = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'implements A {}');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'implements = 42');
   }
 
-  test_BUILT_IN_import() {
+  test_BUILT_IN_import() async {
     addTestFile('''
 import "foo.dart";
 main() {
   var import = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'import "');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'import = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'import "');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'import = 42');
   }
 
-  test_BUILT_IN_library() {
+  test_BUILT_IN_library() async {
     addTestFile('''
 library lib;
 main() {
   var library = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'library lib;');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'library = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'library lib;');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'library = 42');
   }
 
-  test_BUILT_IN_native() {
+  test_BUILT_IN_native() async {
     addTestFile('''
 class A native "A_native" {}
 class B {
@@ -319,14 +304,13 @@
 main() {
   var native = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'native "A_');
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'native "bbb_');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'native = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'native "A_');
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'native "bbb_');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'native = 42');
   }
 
-  test_BUILT_IN_on() {
+  test_BUILT_IN_on() async {
     addTestFile('''
 main() {
   try {
@@ -334,13 +318,12 @@
   }
   var on = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'on int');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'on = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'on int');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'on = 42');
   }
 
-  test_BUILT_IN_operator() {
+  test_BUILT_IN_operator() async {
     addTestFile('''
 class A {
   operator +(x) => null;
@@ -348,26 +331,24 @@
 main() {
   var operator = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'operator +(');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'operator = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'operator +(');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'operator = 42');
   }
 
-  test_BUILT_IN_part() {
+  test_BUILT_IN_part() async {
     addTestFile('''
 part "my_part.dart";
 main() {
   var part = 42;
 }''');
     addFile('/project/bin/my_part.dart', 'part of lib;');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'part "my_');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'part = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'part "my_');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'part = 42');
   }
 
-  test_BUILT_IN_partOf() {
+  test_BUILT_IN_partOf() async {
     addTestFile('''
 part of lib;
 main() {
@@ -375,15 +356,13 @@
   var of = 2;
 }''');
     _addLibraryForTestPart();
-    return prepareHighlights().then((_) {
-      assertHasRegion(
-          HighlightRegionType.BUILT_IN, 'part of', 'part of'.length);
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'part = 1');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'of = 2');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'part of', 'part of'.length);
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'part = 1');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'of = 2');
   }
 
-  test_BUILT_IN_set() {
+  test_BUILT_IN_set() async {
     addTestFile('''
 set aaa(x) {}
 class A
@@ -392,26 +371,24 @@
 main() {
   var set = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'set aaa(');
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'set bbb(');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'set = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'set aaa(');
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'set bbb(');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'set = 42');
   }
 
-  test_BUILT_IN_show() {
+  test_BUILT_IN_show() async {
     addTestFile('''
 import 'foo.dart' show Foo;
 main() {
   var show = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'show Foo');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'show = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'show Foo');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'show = 42');
   }
 
-  test_BUILT_IN_static() {
+  test_BUILT_IN_static() async {
     addTestFile('''
 class A {
   static aaa;
@@ -420,14 +397,13 @@
 main() {
   var static = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'static aaa;');
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'static bbb()');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'static = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'static aaa;');
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'static bbb()');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'static = 42');
   }
 
-  test_BUILT_IN_sync() {
+  test_BUILT_IN_sync() async {
     addTestFile('''
 fa() sync {}
 fb() sync* {}
@@ -435,81 +411,74 @@
   bool sync = false;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasStringRegion(HighlightRegionType.BUILT_IN, 'sync');
-      assertHasStringRegion(HighlightRegionType.BUILT_IN, 'sync*');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'sync = false');
-    });
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.BUILT_IN, 'sync');
+    assertHasStringRegion(HighlightRegionType.BUILT_IN, 'sync*');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'sync = false');
   }
 
-  test_BUILT_IN_typedef() {
+  test_BUILT_IN_typedef() async {
     addTestFile('''
 typedef A();
 main() {
   var typedef = 42;
 }''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'typedef A();');
-      assertNoRegion(HighlightRegionType.BUILT_IN, 'typedef = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'typedef A();');
+    assertNoRegion(HighlightRegionType.BUILT_IN, 'typedef = 42');
   }
 
-  test_BUILT_IN_yield() {
+  test_BUILT_IN_yield() async {
     addTestFile('''
 main() async* {
   yield 42;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.BUILT_IN, 'yield 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.BUILT_IN, 'yield 42');
   }
 
-  test_BUILT_IN_yieldStar() {
+  test_BUILT_IN_yieldStar() async {
     addTestFile('''
 main() async* {
   yield* [];
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasStringRegion(HighlightRegionType.BUILT_IN, 'yield*');
-    });
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.BUILT_IN, 'yield*');
   }
 
-  test_CLASS() {
+  test_CLASS() async {
     addTestFile('''
 class AAA {}
 AAA aaa;
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.CLASS, 'AAA {}');
-      assertHasRegion(HighlightRegionType.CLASS, 'AAA aaa');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.CLASS, 'AAA {}');
+    assertHasRegion(HighlightRegionType.CLASS, 'AAA aaa');
   }
 
-  test_CLASS_notDynamic() {
+  test_CLASS_notDynamic() async {
     addTestFile('''
 dynamic f() {}
 ''');
-    return prepareHighlights().then((_) {
-      assertNoRegion(HighlightRegionType.CLASS, 'dynamic f()');
-    });
+    await prepareHighlights();
+    assertNoRegion(HighlightRegionType.CLASS, 'dynamic f()');
   }
 
-  test_CLASS_notVoid() {
+  test_CLASS_notVoid() async {
     addTestFile('''
 void f() {}
 ''');
-    return prepareHighlights().then((_) {
-      assertNoRegion(HighlightRegionType.CLASS, 'void f()');
-    });
+    await prepareHighlights();
+    assertNoRegion(HighlightRegionType.CLASS, 'void f()');
   }
 
-  test_COMMENT() {
+  test_COMMENT() async {
     addTestFile('''
 /**
  * documentation comment
- */ 
+ */
 void main() {
   // end-of-line comment
   my_function(1);
@@ -519,14 +488,13 @@
  /* block comment */
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.COMMENT_DOCUMENTATION, '/**', 32);
-      assertHasRegion(HighlightRegionType.COMMENT_END_OF_LINE, '//', 22);
-      assertHasRegion(HighlightRegionType.COMMENT_BLOCK, '/* b', 19);
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.COMMENT_DOCUMENTATION, '/**', 32);
+    assertHasRegion(HighlightRegionType.COMMENT_END_OF_LINE, '//', 22);
+    assertHasRegion(HighlightRegionType.COMMENT_BLOCK, '/* b', 19);
   }
 
-  test_CONSTRUCTOR() {
+  test_CONSTRUCTOR() async {
     addTestFile('''
 class AAA {
   AAA() {}
@@ -537,42 +505,37 @@
   new AAA.name(42);
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'name(p)');
-      assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'name(42)');
-      assertNoRegion(HighlightRegionType.CONSTRUCTOR, 'AAA() {}');
-      assertNoRegion(HighlightRegionType.CONSTRUCTOR, 'AAA();');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'name(p)');
+    assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'name(42)');
+    assertNoRegion(HighlightRegionType.CONSTRUCTOR, 'AAA() {}');
+    assertNoRegion(HighlightRegionType.CONSTRUCTOR, 'AAA();');
   }
 
-  test_DIRECTIVE() {
+  test_DIRECTIVE() async {
     addTestFile('''
 library lib;
 import 'dart:math';
 export 'dart:math';
 part 'part.dart';
 ''');
-    return prepareHighlights().then((_) {
-      assertHasStringRegion(HighlightRegionType.DIRECTIVE, "library lib;");
-      assertHasStringRegion(
-          HighlightRegionType.DIRECTIVE, "import 'dart:math';");
-      assertHasStringRegion(
-          HighlightRegionType.DIRECTIVE, "export 'dart:math';");
-      assertHasStringRegion(HighlightRegionType.DIRECTIVE, "part 'part.dart';");
-    });
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.DIRECTIVE, "library lib;");
+    assertHasStringRegion(HighlightRegionType.DIRECTIVE, "import 'dart:math';");
+    assertHasStringRegion(HighlightRegionType.DIRECTIVE, "export 'dart:math';");
+    assertHasStringRegion(HighlightRegionType.DIRECTIVE, "part 'part.dart';");
   }
 
-  test_DIRECTIVE_partOf() {
+  test_DIRECTIVE_partOf() async {
     addTestFile('''
 part of lib;
 ''');
     _addLibraryForTestPart();
-    return prepareHighlights().then((_) {
-      assertHasStringRegion(HighlightRegionType.DIRECTIVE, "part of lib;");
-    });
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.DIRECTIVE, "part of lib;");
   }
 
-  test_DYNAMIC_LOCAL_VARIABLE() {
+  test_DYNAMIC_LOCAL_VARIABLE() async {
     addTestFile('''
 f() {}
 main(p) {
@@ -580,27 +543,24 @@
   v;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(
-          HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_DECLARATION, 'v = f()');
-      assertHasRegion(
-          HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_REFERENCE, 'v;');
-    });
+    await prepareHighlights();
+    assertHasRegion(
+        HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_DECLARATION, 'v = f()');
+    assertHasRegion(HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_REFERENCE, 'v;');
   }
 
-  test_DYNAMIC_PARAMETER() {
+  test_DYNAMIC_PARAMETER() async {
     addTestFile('''
 main(p) {
   print(p);
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.DYNAMIC_PARAMETER_DECLARATION, 'p)');
-      assertHasRegion(HighlightRegionType.DYNAMIC_PARAMETER_REFERENCE, 'p);');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.DYNAMIC_PARAMETER_DECLARATION, 'p)');
+    assertHasRegion(HighlightRegionType.DYNAMIC_PARAMETER_REFERENCE, 'p);');
   }
 
-  test_DYNAMIC_VARIABLE_field() {
+  test_DYNAMIC_VARIABLE_field() async {
     addTestFile('''
 class A {
   var f;
@@ -609,24 +569,22 @@
   }
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.INSTANCE_FIELD_DECLARATION, 'f;');
-      assertHasRegion(HighlightRegionType.INSTANCE_SETTER_REFERENCE, 'f = 1');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.INSTANCE_FIELD_DECLARATION, 'f;');
+    assertHasRegion(HighlightRegionType.INSTANCE_SETTER_REFERENCE, 'f = 1');
   }
 
-  test_ENUM() {
+  test_ENUM() async {
     addTestFile('''
 enum MyEnum {A, B, C}
 MyEnum value;
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.ENUM, 'MyEnum {');
-      assertHasRegion(HighlightRegionType.ENUM, 'MyEnum value;');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.ENUM, 'MyEnum {');
+    assertHasRegion(HighlightRegionType.ENUM, 'MyEnum value;');
   }
 
-  test_ENUM_CONSTANT() {
+  test_ENUM_CONSTANT() async {
     addTestFile('''
 enum MyEnum {AAA, BBB}
 main() {
@@ -634,27 +592,25 @@
   print(MyEnum.BBB);
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'AAA, ');
-      assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'BBB}');
-      assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'AAA);');
-      assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'BBB);');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'AAA, ');
+    assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'BBB}');
+    assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'AAA);');
+    assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'BBB);');
   }
 
-  test_FUNCTION_TYPE_ALIAS() {
+  test_FUNCTION_TYPE_ALIAS() async {
     addTestFile('''
 typedef FFF(p);
 main(FFF fff) {
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'FFF(p)');
-      assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'FFF fff)');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'FFF(p)');
+    assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'FFF fff)');
   }
 
-  test_GETTER() {
+  test_GETTER() async {
     addTestFile('''
 get aaa => null;
 class A {
@@ -667,20 +623,19 @@
   A.ccc;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(
-          HighlightRegionType.TOP_LEVEL_GETTER_DECLARATION, 'aaa => null');
-      assertHasRegion(
-          HighlightRegionType.INSTANCE_GETTER_DECLARATION, 'bbb => null');
-      assertHasRegion(
-          HighlightRegionType.STATIC_GETTER_DECLARATION, 'ccc => null');
-      assertHasRegion(HighlightRegionType.TOP_LEVEL_GETTER_REFERENCE, 'aaa;');
-      assertHasRegion(HighlightRegionType.INSTANCE_GETTER_REFERENCE, 'bbb;');
-      assertHasRegion(HighlightRegionType.STATIC_GETTER_REFERENCE, 'ccc;');
-    });
+    await prepareHighlights();
+    assertHasRegion(
+        HighlightRegionType.TOP_LEVEL_GETTER_DECLARATION, 'aaa => null');
+    assertHasRegion(
+        HighlightRegionType.INSTANCE_GETTER_DECLARATION, 'bbb => null');
+    assertHasRegion(
+        HighlightRegionType.STATIC_GETTER_DECLARATION, 'ccc => null');
+    assertHasRegion(HighlightRegionType.TOP_LEVEL_GETTER_REFERENCE, 'aaa;');
+    assertHasRegion(HighlightRegionType.INSTANCE_GETTER_REFERENCE, 'bbb;');
+    assertHasRegion(HighlightRegionType.STATIC_GETTER_REFERENCE, 'ccc;');
   }
 
-  test_IDENTIFIER_DEFAULT() {
+  test_IDENTIFIER_DEFAULT() async {
     addTestFile('''
 main() {
   aaa = 42;
@@ -688,27 +643,25 @@
   CCC ccc;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'aaa = 42');
-      assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'bbb(84)');
-      assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'CCC ccc');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'aaa = 42');
+    assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'bbb(84)');
+    assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'CCC ccc');
   }
 
-  test_IMPORT_PREFIX() {
+  test_IMPORT_PREFIX() async {
     addTestFile('''
 import 'dart:math' as ma;
 main() {
   ma.max(1, 2);
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.IMPORT_PREFIX, 'ma;');
-      assertHasRegion(HighlightRegionType.IMPORT_PREFIX, 'ma.max');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.IMPORT_PREFIX, 'ma;');
+    assertHasRegion(HighlightRegionType.IMPORT_PREFIX, 'ma.max');
   }
 
-  test_INSTANCE_FIELD() {
+  test_INSTANCE_FIELD() async {
     addTestFile('''
 class A {
   int aaa = 1;
@@ -720,31 +673,27 @@
   a.bbb = 5;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(
-          HighlightRegionType.INSTANCE_FIELD_DECLARATION, 'aaa = 1');
-      assertHasRegion(
-          HighlightRegionType.INSTANCE_FIELD_DECLARATION, 'bbb = 2');
-      assertHasRegion(HighlightRegionType.INSTANCE_FIELD_REFERENCE, 'bbb = 3');
-      assertHasRegion(HighlightRegionType.INSTANCE_SETTER_REFERENCE, 'aaa = 4');
-      assertHasRegion(HighlightRegionType.INSTANCE_SETTER_REFERENCE, 'bbb = 5');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.INSTANCE_FIELD_DECLARATION, 'aaa = 1');
+    assertHasRegion(HighlightRegionType.INSTANCE_FIELD_DECLARATION, 'bbb = 2');
+    assertHasRegion(HighlightRegionType.INSTANCE_FIELD_REFERENCE, 'bbb = 3');
+    assertHasRegion(HighlightRegionType.INSTANCE_SETTER_REFERENCE, 'aaa = 4');
+    assertHasRegion(HighlightRegionType.INSTANCE_SETTER_REFERENCE, 'bbb = 5');
   }
 
-  test_INSTANCE_FIELD_dynamic() {
+  test_INSTANCE_FIELD_dynamic() async {
     addTestFile('''
 class A {
   var f;
   A(this.f);
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.INSTANCE_FIELD_DECLARATION, 'f;');
-      assertHasRegion(HighlightRegionType.INSTANCE_FIELD_REFERENCE, 'f);');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.INSTANCE_FIELD_DECLARATION, 'f;');
+    assertHasRegion(HighlightRegionType.INSTANCE_FIELD_REFERENCE, 'f);');
   }
 
-  test_KEYWORD() {
+  test_KEYWORD() async {
     addTestFile('''
 main() {
   assert(true);
@@ -777,49 +726,47 @@
 }
 class C = Object with A;
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.KEYWORD, 'assert(true)');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'for (;;)');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'for (var v4 in');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'break;');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'case 0:');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'catch (e) {}');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'class A {}');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'const v1');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'continue;');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'default:');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'do {} while');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'if (true)');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'false;');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'final v3 =');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'finally {}');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'in []');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'is int');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'new A();');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'rethrow;');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'return this');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'super();');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'switch (0)');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'this;');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'true;');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'try {');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'while (true) {}');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'while (true);');
-      assertHasRegion(HighlightRegionType.KEYWORD, 'with A;');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'assert(true)');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'for (;;)');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'for (var v4 in');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'break;');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'case 0:');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'catch (e) {}');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'class A {}');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'const v1');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'continue;');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'default:');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'do {} while');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'if (true)');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'false;');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'final v3 =');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'finally {}');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'in []');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'is int');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'new A();');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'rethrow;');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'return this');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'super();');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'switch (0)');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'this;');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'true;');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'try {');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'while (true) {}');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'while (true);');
+    assertHasRegion(HighlightRegionType.KEYWORD, 'with A;');
   }
 
-  test_KEYWORD_void() {
+  test_KEYWORD_void() async {
     addTestFile('''
 void main() {
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.KEYWORD, 'void main()');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.KEYWORD, 'void main()');
   }
 
-  test_LABEL() {
+  test_LABEL() async {
     addTestFile('''
 main() {
 myLabel:
@@ -828,76 +775,67 @@
   }
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.LABEL, 'myLabel:');
-      assertHasRegion(HighlightRegionType.LABEL, 'myLabel;');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.LABEL, 'myLabel:');
+    assertHasRegion(HighlightRegionType.LABEL, 'myLabel;');
   }
 
-  test_LIBRARY_NAME_libraryDirective() {
+  test_LIBRARY_NAME_libraryDirective() async {
     addTestFile('''
 library my.lib.name;
 ''');
-    return prepareHighlights().then((_) {
-      assertHasStringRegion(HighlightRegionType.LIBRARY_NAME, 'my.lib.name');
-    });
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.LIBRARY_NAME, 'my.lib.name');
   }
 
-  test_LIBRARY_NAME_partOfDirective() {
+  test_LIBRARY_NAME_partOfDirective() async {
     _addLibraryForTestPart();
     addTestFile('''
 part of my.lib.name;
 ''');
-    return prepareHighlights().then((_) {
-      assertHasStringRegion(HighlightRegionType.LIBRARY_NAME, 'my.lib.name');
-    });
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.LIBRARY_NAME, 'my.lib.name');
   }
 
-  test_LITERAL_BOOLEAN() {
+  test_LITERAL_BOOLEAN() async {
     addTestFile('var V = true;');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.LITERAL_BOOLEAN, 'true;');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.LITERAL_BOOLEAN, 'true;');
   }
 
-  test_LITERAL_DOUBLE() {
+  test_LITERAL_DOUBLE() async {
     addTestFile('var V = 4.2;');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.LITERAL_DOUBLE, '4.2;', '4.2'.length);
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.LITERAL_DOUBLE, '4.2;', '4.2'.length);
   }
 
-  test_LITERAL_INTEGER() {
+  test_LITERAL_INTEGER() async {
     addTestFile('var V = 42;');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.LITERAL_INTEGER, '42;');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.LITERAL_INTEGER, '42;');
   }
 
-  test_LITERAL_LIST() {
+  test_LITERAL_LIST() async {
     addTestFile('var V = <int>[1, 2, 3];');
-    return prepareHighlights().then((_) {
-      assertHasStringRegion(HighlightRegionType.LITERAL_LIST, '<int>[1, 2, 3]');
-    });
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.LITERAL_LIST, '<int>[1, 2, 3]');
   }
 
-  test_LITERAL_MAP() {
+  test_LITERAL_MAP() async {
     addTestFile("var V = const <int, String>{1: 'a', 2: 'b', 3: 'c'};");
-    return prepareHighlights().then((_) {
-      assertHasStringRegion(HighlightRegionType.LITERAL_MAP,
-          "const <int, String>{1: 'a', 2: 'b', 3: 'c'}");
-    });
+    await prepareHighlights();
+    assertHasStringRegion(HighlightRegionType.LITERAL_MAP,
+        "const <int, String>{1: 'a', 2: 'b', 3: 'c'}");
   }
 
-  test_LITERAL_STRING() {
+  test_LITERAL_STRING() async {
     addTestFile('var V = "abc";');
-    return prepareHighlights().then((_) {
-      assertHasRegion(
-          HighlightRegionType.LITERAL_STRING, '"abc";', '"abc"'.length);
-    });
+    await prepareHighlights();
+    assertHasRegion(
+        HighlightRegionType.LITERAL_STRING, '"abc";', '"abc"'.length);
   }
 
-  test_LOCAL_FUNCTION() {
+  test_LOCAL_FUNCTION() async {
     addTestFile('''
 main() {
   fff() {}
@@ -905,15 +843,13 @@
   fff;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(
-          HighlightRegionType.LOCAL_FUNCTION_DECLARATION, 'fff() {}');
-      assertHasRegion(HighlightRegionType.LOCAL_FUNCTION_REFERENCE, 'fff();');
-      assertHasRegion(HighlightRegionType.LOCAL_FUNCTION_REFERENCE, 'fff;');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.LOCAL_FUNCTION_DECLARATION, 'fff() {}');
+    assertHasRegion(HighlightRegionType.LOCAL_FUNCTION_REFERENCE, 'fff();');
+    assertHasRegion(HighlightRegionType.LOCAL_FUNCTION_REFERENCE, 'fff;');
   }
 
-  test_LOCAL_VARIABLE() {
+  test_LOCAL_VARIABLE() async {
     addTestFile('''
 main() {
   int vvv = 0;
@@ -921,15 +857,13 @@
   vvv = 1;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(
-          HighlightRegionType.LOCAL_VARIABLE_DECLARATION, 'vvv = 0');
-      assertHasRegion(HighlightRegionType.LOCAL_VARIABLE_REFERENCE, 'vvv;');
-      assertHasRegion(HighlightRegionType.LOCAL_VARIABLE_REFERENCE, 'vvv = 1;');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.LOCAL_VARIABLE_DECLARATION, 'vvv = 0');
+    assertHasRegion(HighlightRegionType.LOCAL_VARIABLE_REFERENCE, 'vvv;');
+    assertHasRegion(HighlightRegionType.LOCAL_VARIABLE_REFERENCE, 'vvv = 1;');
   }
 
-  test_METHOD() {
+  test_METHOD() async {
     addTestFile('''
 class A {
   aaa() {}
@@ -942,19 +876,17 @@
   A.bbb;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(
-          HighlightRegionType.INSTANCE_METHOD_DECLARATION, 'aaa() {}');
-      assertHasRegion(
-          HighlightRegionType.STATIC_METHOD_DECLARATION, 'bbb() {}');
-      assertHasRegion(HighlightRegionType.INSTANCE_METHOD_REFERENCE, 'aaa();');
-      assertHasRegion(HighlightRegionType.INSTANCE_METHOD_REFERENCE, 'aaa;');
-      assertHasRegion(HighlightRegionType.STATIC_METHOD_REFERENCE, 'bbb();');
-      assertHasRegion(HighlightRegionType.STATIC_METHOD_REFERENCE, 'bbb;');
-    });
+    await prepareHighlights();
+    assertHasRegion(
+        HighlightRegionType.INSTANCE_METHOD_DECLARATION, 'aaa() {}');
+    assertHasRegion(HighlightRegionType.STATIC_METHOD_DECLARATION, 'bbb() {}');
+    assertHasRegion(HighlightRegionType.INSTANCE_METHOD_REFERENCE, 'aaa();');
+    assertHasRegion(HighlightRegionType.INSTANCE_METHOD_REFERENCE, 'aaa;');
+    assertHasRegion(HighlightRegionType.STATIC_METHOD_REFERENCE, 'bbb();');
+    assertHasRegion(HighlightRegionType.STATIC_METHOD_REFERENCE, 'bbb;');
   }
 
-  test_METHOD_bestType() {
+  test_METHOD_bestType() async {
     addTestFile('''
 main(p) {
   if (p is List) {
@@ -962,27 +894,24 @@
   }
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(
-          HighlightRegionType.INSTANCE_METHOD_REFERENCE, 'add(null)');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.INSTANCE_METHOD_REFERENCE, 'add(null)');
   }
 
-  test_PARAMETER() {
+  test_PARAMETER() async {
     addTestFile('''
 main(int p) {
   p;
   p = 42;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.PARAMETER_DECLARATION, 'p) {');
-      assertHasRegion(HighlightRegionType.PARAMETER_REFERENCE, 'p;');
-      assertHasRegion(HighlightRegionType.PARAMETER_REFERENCE, 'p = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.PARAMETER_DECLARATION, 'p) {');
+    assertHasRegion(HighlightRegionType.PARAMETER_REFERENCE, 'p;');
+    assertHasRegion(HighlightRegionType.PARAMETER_REFERENCE, 'p = 42');
   }
 
-  test_SETTER_DECLARATION() {
+  test_SETTER_DECLARATION() async {
     addTestFile('''
 set aaa(x) {}
 class A {
@@ -995,20 +924,16 @@
   A.ccc = 3;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(
-          HighlightRegionType.TOP_LEVEL_SETTER_DECLARATION, 'aaa(x)');
-      assertHasRegion(
-          HighlightRegionType.INSTANCE_SETTER_DECLARATION, 'bbb(x)');
-      assertHasRegion(HighlightRegionType.STATIC_SETTER_DECLARATION, 'ccc(x)');
-      assertHasRegion(
-          HighlightRegionType.TOP_LEVEL_SETTER_REFERENCE, 'aaa = 1');
-      assertHasRegion(HighlightRegionType.INSTANCE_SETTER_REFERENCE, 'bbb = 2');
-      assertHasRegion(HighlightRegionType.STATIC_SETTER_REFERENCE, 'ccc = 3');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.TOP_LEVEL_SETTER_DECLARATION, 'aaa(x)');
+    assertHasRegion(HighlightRegionType.INSTANCE_SETTER_DECLARATION, 'bbb(x)');
+    assertHasRegion(HighlightRegionType.STATIC_SETTER_DECLARATION, 'ccc(x)');
+    assertHasRegion(HighlightRegionType.TOP_LEVEL_SETTER_REFERENCE, 'aaa = 1');
+    assertHasRegion(HighlightRegionType.INSTANCE_SETTER_REFERENCE, 'bbb = 2');
+    assertHasRegion(HighlightRegionType.STATIC_SETTER_REFERENCE, 'ccc = 3');
   }
 
-  test_STATIC_FIELD() {
+  test_STATIC_FIELD() async {
     addTestFile('''
 class A {
   static aaa = 1;
@@ -1021,30 +946,28 @@
   A.ccc = 3;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.STATIC_FIELD_DECLARATION, 'aaa = 1');
-      assertHasRegion(HighlightRegionType.STATIC_SETTER_REFERENCE, 'aaa = 2');
-      assertHasRegion(HighlightRegionType.STATIC_GETTER_REFERENCE, 'bbb;');
-      assertHasRegion(HighlightRegionType.STATIC_SETTER_REFERENCE, 'ccc = 3');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.STATIC_FIELD_DECLARATION, 'aaa = 1');
+    assertHasRegion(HighlightRegionType.STATIC_SETTER_REFERENCE, 'aaa = 2');
+    assertHasRegion(HighlightRegionType.STATIC_GETTER_REFERENCE, 'bbb;');
+    assertHasRegion(HighlightRegionType.STATIC_SETTER_REFERENCE, 'ccc = 3');
   }
 
-  test_TOP_LEVEL_FUNCTION() {
+  test_TOP_LEVEL_FUNCTION() async {
     addTestFile('''
 fff(p) {}
 main() {
   fff(42);
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(
-          HighlightRegionType.TOP_LEVEL_FUNCTION_DECLARATION, 'fff(p) {}');
-      assertHasRegion(
-          HighlightRegionType.TOP_LEVEL_FUNCTION_REFERENCE, 'fff(42)');
-    });
+    await prepareHighlights();
+    assertHasRegion(
+        HighlightRegionType.TOP_LEVEL_FUNCTION_DECLARATION, 'fff(p) {}');
+    assertHasRegion(
+        HighlightRegionType.TOP_LEVEL_FUNCTION_REFERENCE, 'fff(42)');
   }
 
-  test_TOP_LEVEL_VARIABLE() {
+  test_TOP_LEVEL_VARIABLE() async {
     addTestFile('''
 const V1 = 1;
 var V2 = 2;
@@ -1054,47 +977,44 @@
   V2 = 3;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(
-          HighlightRegionType.TOP_LEVEL_VARIABLE_DECLARATION, 'V1 = 1');
-      assertHasRegion(
-          HighlightRegionType.TOP_LEVEL_VARIABLE_DECLARATION, 'V2 = 2');
-      assertHasRegion(
-          HighlightRegionType.TOP_LEVEL_GETTER_REFERENCE, 'V1 // annotation');
-      assertHasRegion(HighlightRegionType.TOP_LEVEL_GETTER_REFERENCE, 'V1);');
-      assertHasRegion(HighlightRegionType.TOP_LEVEL_SETTER_REFERENCE, 'V2 = 3');
-    });
+    await prepareHighlights();
+    assertHasRegion(
+        HighlightRegionType.TOP_LEVEL_VARIABLE_DECLARATION, 'V1 = 1');
+    assertHasRegion(
+        HighlightRegionType.TOP_LEVEL_VARIABLE_DECLARATION, 'V2 = 2');
+    assertHasRegion(
+        HighlightRegionType.TOP_LEVEL_GETTER_REFERENCE, 'V1 // annotation');
+    assertHasRegion(HighlightRegionType.TOP_LEVEL_GETTER_REFERENCE, 'V1);');
+    assertHasRegion(HighlightRegionType.TOP_LEVEL_SETTER_REFERENCE, 'V2 = 3');
   }
 
-  test_TYPE_NAME_DYNAMIC() {
+  test_TYPE_NAME_DYNAMIC() async {
     addTestFile('''
 dynamic main() {
   dynamic = 42;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.TYPE_NAME_DYNAMIC, 'dynamic main()');
-      assertNoRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'dynamic main()');
-      assertNoRegion(HighlightRegionType.TYPE_NAME_DYNAMIC, 'dynamic = 42');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.TYPE_NAME_DYNAMIC, 'dynamic main()');
+    assertNoRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'dynamic main()');
+    assertNoRegion(HighlightRegionType.TYPE_NAME_DYNAMIC, 'dynamic = 42');
   }
 
-  test_TYPE_PARAMETER() {
+  test_TYPE_PARAMETER() async {
     addTestFile('''
 class A<T> {
   T fff;
   T mmm(T p) => null;
 }
 ''');
-    return prepareHighlights().then((_) {
-      assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T> {');
-      assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T fff;');
-      assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T mmm(');
-      assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T p)');
-    });
+    await prepareHighlights();
+    assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T> {');
+    assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T fff;');
+    assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T mmm(');
+    assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T p)');
   }
 
-  test_UNRESOLVED_INSTANCE_MEMBER_REFERENCE_dynamicVarTarget() {
+  test_UNRESOLVED_INSTANCE_MEMBER_REFERENCE_dynamicVarTarget() async {
     addTestFile('''
 main(p) {
   p.aaa;
@@ -1106,20 +1026,19 @@
   ''.length.ccc().ddd();
 }
 ''');
-    return prepareHighlights().then((_) {
-      HighlightRegionType type =
-          HighlightRegionType.UNRESOLVED_INSTANCE_MEMBER_REFERENCE;
-      assertHasRegion(type, 'aaa');
-      assertHasRegion(type, 'aaa++');
-      assertHasRegion(type, 'aaa += 0');
-      assertHasRegion(type, 'aaa; // ++');
-      assertHasRegion(type, 'aaa =');
-      assertHasRegion(type, 'bbb(');
-      assertHasRegion(type, 'ddd()');
-    });
+    await prepareHighlights();
+    HighlightRegionType type =
+        HighlightRegionType.UNRESOLVED_INSTANCE_MEMBER_REFERENCE;
+    assertHasRegion(type, 'aaa');
+    assertHasRegion(type, 'aaa++');
+    assertHasRegion(type, 'aaa += 0');
+    assertHasRegion(type, 'aaa; // ++');
+    assertHasRegion(type, 'aaa =');
+    assertHasRegion(type, 'bbb(');
+    assertHasRegion(type, 'ddd()');
   }
 
-  test_UNRESOLVED_INSTANCE_MEMBER_REFERENCE_nonDynamicTarget() {
+  test_UNRESOLVED_INSTANCE_MEMBER_REFERENCE_nonDynamicTarget() async {
     addTestFile('''
 import 'dart:math' as math;
 main(String str) {
@@ -1135,15 +1054,14 @@
   }
 }
 ''');
-    return prepareHighlights().then((_) {
-      HighlightRegionType type = HighlightRegionType.IDENTIFIER_DEFAULT;
-      assertHasRegion(type, 'aaa()');
-      assertHasRegion(type, 'bbb()');
-      assertHasRegion(type, 'ccc()');
-      assertHasRegion(type, 'unresolved(1)');
-      assertHasRegion(type, 'unresolved(2)');
-      assertHasRegion(type, 'unresolved(3)');
-    });
+    await prepareHighlights();
+    HighlightRegionType type = HighlightRegionType.IDENTIFIER_DEFAULT;
+    assertHasRegion(type, 'aaa()');
+    assertHasRegion(type, 'bbb()');
+    assertHasRegion(type, 'ccc()');
+    assertHasRegion(type, 'unresolved(1)');
+    assertHasRegion(type, 'unresolved(2)');
+    assertHasRegion(type, 'unresolved(3)');
   }
 
   void _addLibraryForTestPart() {
diff --git a/pkg/analysis_server/test/analysis/notification_implemented_test.dart b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
index 5c1c6ed..d5cde86 100644
--- a/pkg/analysis_server/test/analysis/notification_implemented_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
@@ -315,6 +315,84 @@
     assertHasImplementedMember('f(_) {} // A');
   }
 
+  test_static_field_instanceStatic() async {
+    addTestFile('''
+class A {
+  int F = 0;
+}
+class B extends A {
+  static int F = 1;
+}
+''');
+    await prepareImplementedElements();
+    assertNoImplementedMember('F = 0');
+  }
+
+  test_static_field_staticInstance() async {
+    addTestFile('''
+class A {
+  static int F = 0;
+}
+class B extends A {
+  int F = 1;
+}
+''');
+    await prepareImplementedElements();
+    assertNoImplementedMember('F = 0');
+  }
+
+  test_static_field_staticStatic() async {
+    addTestFile('''
+class A {
+  static int F = 0;
+}
+class B extends A {
+  static int F = 1;
+}
+''');
+    await prepareImplementedElements();
+    assertNoImplementedMember('F = 0');
+  }
+
+  test_static_method_instanceStatic() async {
+    addTestFile('''
+class A {
+  int m() => 0;
+}
+class B extends A {
+  static int m() => 1;
+}
+''');
+    await prepareImplementedElements();
+    assertNoImplementedMember('m() => 0');
+  }
+
+  test_static_method_staticInstance() async {
+    addTestFile('''
+class A {
+  static int m() => 0;
+}
+class B extends A {
+  int m() => 1;
+}
+''');
+    await prepareImplementedElements();
+    assertNoImplementedMember('m() => 0');
+  }
+
+  test_static_method_staticStatic() async {
+    addTestFile('''
+class A {
+  static int m() => 0;
+}
+class B extends A {
+  static int m() => 1;
+}
+''');
+    await prepareImplementedElements();
+    assertNoImplementedMember('m() => 0');
+  }
+
   Future waitForImplementedElements() {
     Future waitForNotification(int times) {
       if (times == 0 || implementedClasses != null) {
diff --git a/pkg/analysis_server/test/analysis/notification_navigation_test.dart b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
index 68b347c..2e56daa 100644
--- a/pkg/analysis_server/test/analysis/notification_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
@@ -179,11 +179,10 @@
 
 @reflectiveTest
 class AnalysisNotificationNavigationTest extends AbstractNavigationTest {
-  Future prepareNavigation() {
+  Future prepareNavigation() async {
     addAnalysisSubscription(AnalysisService.NAVIGATION, testFile);
-    return waitForTasksFinished().then((_) {
-      assertRegionsSorted();
-    });
+    await waitForTasksFinished();
+    assertRegionsSorted();
   }
 
   void processNotification(Notification notification) {
@@ -203,16 +202,14 @@
     createProject();
   }
 
-  test_afterAnalysis() {
+  test_afterAnalysis() async {
     addTestFile('''
 class AAA {}
 AAA aaa;
 ''');
-    return waitForTasksFinished().then((_) {
-      return prepareNavigation().then((_) {
-        assertHasRegionTarget('AAA aaa;', 'AAA {}');
-      });
-    });
+    await waitForTasksFinished();
+    await prepareNavigation();
+    assertHasRegionTarget('AAA aaa;', 'AAA {}');
   }
 
   test_annotationConstructor_implicit() async {
@@ -322,55 +319,52 @@
     assertHasRegion('myan // ref');
   }
 
-  test_class_fromSDK() {
+  test_class_fromSDK() async {
     addTestFile('''
 int V = 42;
 ''');
-    return prepareNavigation().then((_) {
-      assertHasRegion('int V');
-      int targetIndex = testTargetIndexes[0];
-      NavigationTarget target = targets[targetIndex];
-      expect(target.startLine, greaterThan(0));
-      expect(target.startColumn, greaterThan(0));
-    });
+    await prepareNavigation();
+    assertHasRegion('int V');
+    int targetIndex = testTargetIndexes[0];
+    NavigationTarget target = targets[targetIndex];
+    expect(target.startLine, greaterThan(0));
+    expect(target.startColumn, greaterThan(0));
   }
 
-  test_constructor_named() {
+  test_constructor_named() async {
     addTestFile('''
 class A {
   A.named(BBB p) {}
 }
 class BBB {}
 ''');
-    return prepareNavigation().then((_) {
-      // has region for complete "A.named"
-      assertHasRegionString('A.named');
-      assertHasTarget('named(BBB');
-      // no separate regions for "A" and "named"
-      assertNoRegion('A.named(', 'A'.length);
-      assertNoRegion('named(', 'named'.length);
-      // validate that we don't forget to resolve parameters
-      assertHasRegionTarget('BBB p', 'BBB {}');
-    });
+    await prepareNavigation();
+    // has region for complete "A.named"
+    assertHasRegionString('A.named');
+    assertHasTarget('named(BBB');
+    // no separate regions for "A" and "named"
+    assertNoRegion('A.named(', 'A'.length);
+    assertNoRegion('named(', 'named'.length);
+    // validate that we don't forget to resolve parameters
+    assertHasRegionTarget('BBB p', 'BBB {}');
   }
 
-  test_constructor_unnamed() {
+  test_constructor_unnamed() async {
     addTestFile('''
 class A {
   A(BBB p) {}
 }
 class BBB {}
 ''');
-    return prepareNavigation().then((_) {
-      // has region for complete "A.named"
-      assertHasRegion("A(BBB");
-      assertHasTarget("A(BBB", 0);
-      // validate that we don't forget to resolve parameters
-      assertHasRegionTarget('BBB p', 'BBB {}');
-    });
+    await prepareNavigation();
+    // has region for complete "A.named"
+    assertHasRegion("A(BBB");
+    assertHasTarget("A(BBB", 0);
+    // validate that we don't forget to resolve parameters
+    assertHasRegionTarget('BBB p', 'BBB {}');
   }
 
-  test_factoryRedirectingConstructor_implicit() {
+  test_factoryRedirectingConstructor_implicit() async {
     addTestFile('''
 class A {
   factory A() = B;
@@ -378,13 +372,12 @@
 class B {
 }
 ''');
-    return prepareNavigation().then((_) {
-      assertHasRegion('B;');
-      assertHasTarget('B {');
-    });
+    await prepareNavigation();
+    assertHasRegion('B;');
+    assertHasTarget('B {');
   }
 
-  test_factoryRedirectingConstructor_implicit_withTypeArgument() {
+  test_factoryRedirectingConstructor_implicit_withTypeArgument() async {
     addTestFile('''
 class A {}
 class B {
@@ -392,19 +385,18 @@
 }
 class C<T> {}
 ''');
-    return prepareNavigation().then((_) {
-      {
-        assertHasRegion('C<A>');
-        assertHasTarget('C<T> {');
-      }
-      {
-        assertHasRegion('A>;');
-        assertHasTarget('A {');
-      }
-    });
+    await prepareNavigation();
+    {
+      assertHasRegion('C<A>');
+      assertHasTarget('C<T> {');
+    }
+    {
+      assertHasRegion('A>;');
+      assertHasTarget('A {');
+    }
   }
 
-  test_factoryRedirectingConstructor_named() {
+  test_factoryRedirectingConstructor_named() async {
     addTestFile('''
 class A {
   factory A() = B.named;
@@ -413,19 +405,18 @@
   B.named();
 }
 ''');
-    return prepareNavigation().then((_) {
-      {
-        assertHasRegionString('B.named;', 'B'.length);
-        assertHasTarget('named();');
-      }
-      {
-        assertHasRegionString('named;', 'named'.length);
-        assertHasTarget('named();');
-      }
-    });
+    await prepareNavigation();
+    {
+      assertHasRegionString('B.named;', 'B'.length);
+      assertHasTarget('named();');
+    }
+    {
+      assertHasRegionString('named;', 'named'.length);
+      assertHasTarget('named();');
+    }
   }
 
-  test_factoryRedirectingConstructor_named_withTypeArgument() {
+  test_factoryRedirectingConstructor_named_withTypeArgument() async {
     addTestFile('''
 class A {}
 class B {
@@ -435,23 +426,22 @@
   C.named() {}
 }
 ''');
-    return prepareNavigation().then((_) {
-      {
-        assertHasRegion('C<A>');
-        assertHasTarget('named() {}');
-      }
-      {
-        assertHasRegion('A>.named');
-        assertHasTarget('A {');
-      }
-      {
-        assertHasRegion('named;', 'named'.length);
-        assertHasTarget('named() {}');
-      }
-    });
+    await prepareNavigation();
+    {
+      assertHasRegion('C<A>');
+      assertHasTarget('named() {}');
+    }
+    {
+      assertHasRegion('A>.named');
+      assertHasTarget('A {');
+    }
+    {
+      assertHasRegion('named;', 'named'.length);
+      assertHasTarget('named() {}');
+    }
   }
 
-  test_factoryRedirectingConstructor_unnamed() {
+  test_factoryRedirectingConstructor_unnamed() async {
     addTestFile('''
 class A {
   factory A() = B;
@@ -460,13 +450,12 @@
   B() {}
 }
 ''');
-    return prepareNavigation().then((_) {
-      assertHasRegion('B;');
-      assertHasTarget('B() {}', 0);
-    });
+    await prepareNavigation();
+    assertHasRegion('B;');
+    assertHasTarget('B() {}', 0);
   }
 
-  test_factoryRedirectingConstructor_unnamed_withTypeArgument() {
+  test_factoryRedirectingConstructor_unnamed_withTypeArgument() async {
     addTestFile('''
 class A {}
 class B {
@@ -476,53 +465,49 @@
   C() {}
 }
 ''');
-    return prepareNavigation().then((_) {
-      {
-        assertHasRegion('C<A>');
-        assertHasTarget('C() {}', 0);
-      }
-      {
-        assertHasRegion('A>;');
-        assertHasTarget('A {');
-      }
-    });
+    await prepareNavigation();
+    {
+      assertHasRegion('C<A>');
+      assertHasTarget('C() {}', 0);
+    }
+    {
+      assertHasRegion('A>;');
+      assertHasTarget('A {');
+    }
   }
 
-  test_factoryRedirectingConstructor_unresolved() {
+  test_factoryRedirectingConstructor_unresolved() async {
     addTestFile('''
 class A {
   factory A() = B;
 }
 ''');
-    return prepareNavigation().then((_) {
-      // don't check regions, but there should be no exceptions
-    });
+    await prepareNavigation();
+    // don't check regions, but there should be no exceptions
   }
 
-  test_fieldFormalParameter() {
+  test_fieldFormalParameter() async {
     addTestFile('''
 class AAA {
   int fff = 123;
   AAA(this.fff);
 }
 ''');
-    return prepareNavigation().then((_) {
-      assertHasRegionTarget('fff);', 'fff = 123');
-    });
+    await prepareNavigation();
+    assertHasRegionTarget('fff);', 'fff = 123');
   }
 
-  test_fieldFormalParameter_unresolved() {
+  test_fieldFormalParameter_unresolved() async {
     addTestFile('''
 class AAA {
   AAA(this.fff);
 }
 ''');
-    return prepareNavigation().then((_) {
-      assertNoRegion('fff);', 3);
-    });
+    await prepareNavigation();
+    assertNoRegion('fff);', 3);
   }
 
-  test_identifier_resolved() {
+  test_identifier_resolved() async {
     addTestFile('''
 class AAA {}
 main() {
@@ -530,25 +515,23 @@
   print(aaa);
 }
 ''');
-    return prepareNavigation().then((_) {
-      assertHasRegionTarget('AAA aaa', 'AAA {}');
-      assertHasRegionTarget('aaa);', 'aaa = null');
-      assertHasRegionTarget('main() {', 'main() {');
-    });
+    await prepareNavigation();
+    assertHasRegionTarget('AAA aaa', 'AAA {}');
+    assertHasRegionTarget('aaa);', 'aaa = null');
+    assertHasRegionTarget('main() {', 'main() {');
   }
 
-  test_identifier_unresolved() {
+  test_identifier_unresolved() async {
     addTestFile('''
 main() {
   print(vvv);
 }
 ''');
-    return prepareNavigation().then((_) {
-      assertNoRegionString('vvv');
-    });
+    await prepareNavigation();
+    assertNoRegionString('vvv');
   }
 
-  test_identifier_whenStrayImportDirective() {
+  test_identifier_whenStrayImportDirective() async {
     addTestFile('''
 main() {
   int aaa = 42;
@@ -556,9 +539,8 @@
 }
 import 'dart:math';
 ''');
-    return prepareNavigation().then((_) {
-      assertHasRegionTarget('aaa);', 'aaa = 42');
-    });
+    await prepareNavigation();
+    assertHasRegionTarget('aaa);', 'aaa = 42');
   }
 
   test_inComment() async {
@@ -578,7 +560,7 @@
     assertHasRegionTarget('FirstClass(', 'FirstClass {');
   }
 
-  test_instanceCreation_implicit() {
+  test_instanceCreation_implicit() async {
     addTestFile('''
 class A {
 }
@@ -586,13 +568,12 @@
   new A();
 }
 ''');
-    return prepareNavigation().then((_) {
-      assertHasRegionString('A()', 'A'.length);
-      assertHasTarget('A {');
-    });
+    await prepareNavigation();
+    assertHasRegionString('A()', 'A'.length);
+    assertHasTarget('A {');
   }
 
-  test_instanceCreation_implicit_withTypeArgument() {
+  test_instanceCreation_implicit_withTypeArgument() async {
     addTestFile('''
 class A {}
 class B<T> {}
@@ -600,19 +581,18 @@
   new B<A>();
 }
 ''');
-    return prepareNavigation().then((_) {
-      {
-        assertHasRegion('B<A>', 'B'.length);
-        assertHasTarget('B<T> {');
-      }
-      {
-        assertHasRegion('A>();', 'A'.length);
-        assertHasTarget('A {');
-      }
-    });
+    await prepareNavigation();
+    {
+      assertHasRegion('B<A>', 'B'.length);
+      assertHasTarget('B<T> {');
+    }
+    {
+      assertHasRegion('A>();', 'A'.length);
+      assertHasTarget('A {');
+    }
   }
 
-  test_instanceCreation_named() {
+  test_instanceCreation_named() async {
     addTestFile('''
 class A {
   A.named() {}
@@ -621,19 +601,18 @@
   new A.named();
 }
 ''');
-    return prepareNavigation().then((_) {
-      {
-        assertHasRegionString('A.named();', 'A'.length);
-        assertHasTarget('named() {}');
-      }
-      {
-        assertHasRegionString('named();', 'named'.length);
-        assertHasTarget('named() {}');
-      }
-    });
+    await prepareNavigation();
+    {
+      assertHasRegionString('A.named();', 'A'.length);
+      assertHasTarget('named() {}');
+    }
+    {
+      assertHasRegionString('named();', 'named'.length);
+      assertHasTarget('named() {}');
+    }
   }
 
-  test_instanceCreation_named_withTypeArgument() {
+  test_instanceCreation_named_withTypeArgument() async {
     addTestFile('''
 class A {}
 class B<T> {
@@ -643,23 +622,22 @@
   new B<A>.named();
 }
 ''');
-    return prepareNavigation().then((_) {
-      {
-        assertHasRegionString('B<A>', 'B'.length);
-        assertHasTarget('named() {}');
-      }
-      {
-        assertHasRegion('A>.named');
-        assertHasTarget('A {');
-      }
-      {
-        assertHasRegion('named();', 'named'.length);
-        assertHasTarget('named() {}');
-      }
-    });
+    await prepareNavigation();
+    {
+      assertHasRegionString('B<A>', 'B'.length);
+      assertHasTarget('named() {}');
+    }
+    {
+      assertHasRegion('A>.named');
+      assertHasTarget('A {');
+    }
+    {
+      assertHasRegion('named();', 'named'.length);
+      assertHasTarget('named() {}');
+    }
   }
 
-  test_instanceCreation_unnamed() {
+  test_instanceCreation_unnamed() async {
     addTestFile('''
 class A {
   A() {}
@@ -668,13 +646,12 @@
   new A();
 }
 ''');
-    return prepareNavigation().then((_) {
-      assertHasRegionString('A();', 'A'.length);
-      assertHasTarget('A() {}', 0);
-    });
+    await prepareNavigation();
+    assertHasRegionString('A();', 'A'.length);
+    assertHasTarget('A() {}', 0);
   }
 
-  test_instanceCreation_unnamed_withTypeArgument() {
+  test_instanceCreation_unnamed_withTypeArgument() async {
     addTestFile('''
 class A {}
 class B<T> {
@@ -684,29 +661,43 @@
   new B<A>();
 }
 ''');
-    return prepareNavigation().then((_) {
-      {
-        assertHasRegionString('B<A>();', 'B'.length);
-        assertHasTarget('B() {}', 0);
-      }
-      {
-        assertHasRegion('A>();');
-        assertHasTarget('A {');
-      }
-    });
+    await prepareNavigation();
+    {
+      assertHasRegionString('B<A>();', 'B'.length);
+      assertHasTarget('B() {}', 0);
+    }
+    {
+      assertHasRegion('A>();');
+      assertHasTarget('A {');
+    }
   }
 
-  test_library() {
+  test_instanceCreation_withImportPrefix_named() async {
+    addTestFile('''
+import 'dart:async' as ppp;
+main() {
+  new ppp.Future.value(42);
+}
+''');
+    await prepareNavigation();
+    {
+      assertHasRegion('ppp.');
+      assertHasTarget('ppp;');
+    }
+    assertHasRegion('Future.value');
+    assertHasRegion('value(42)');
+  }
+
+  test_library() async {
     addTestFile('''
 library my.lib;
 ''');
-    return prepareNavigation().then((_) {
-      assertHasRegionString('my.lib');
-      assertHasTargetString('my.lib');
-    });
+    await prepareNavigation();
+    assertHasRegionString('my.lib');
+    assertHasTargetString('my.lib');
   }
 
-  test_multiplyDefinedElement() {
+  test_multiplyDefinedElement() async {
     addFile('$projectPath/bin/libA.dart', 'library A; int TEST = 1;');
     addFile('$projectPath/bin/libB.dart', 'library B; int TEST = 2;');
     addTestFile('''
@@ -716,12 +707,11 @@
   TEST;
 }
 ''');
-    return prepareNavigation().then((_) {
-      assertNoRegionAt('TEST');
-    });
+    await prepareNavigation();
+    assertNoRegionAt('TEST');
   }
 
-  test_operator_arithmetic() {
+  test_operator_arithmetic() async {
     addTestFile('''
 class A {
   A operator +(other) => null;
@@ -745,22 +735,21 @@
   a /= 6;
 }
 ''');
-    return prepareNavigation().then((_) {
-      assertHasOperatorRegion('- 1', 1, '-(other) => null', 1);
-      assertHasOperatorRegion('+ 2', 1, '+(other) => null', 1);
-      assertHasOperatorRegion('-a; // unary', 1, '-() => null', 1);
-      assertHasOperatorRegion('--a;', 2, '-(other) => null', 1);
-      assertHasOperatorRegion('++a;', 2, '+(other) => null', 1);
-      assertHasOperatorRegion('--; // mm', 2, '-(other) => null', 1);
-      assertHasOperatorRegion('++; // pp', 2, '+(other) => null', 1);
-      assertHasOperatorRegion('-= 3', 2, '-(other) => null', 1);
-      assertHasOperatorRegion('+= 4', 2, '+(other) => null', 1);
-      assertHasOperatorRegion('*= 5', 2, '*(other) => null', 1);
-      assertHasOperatorRegion('/= 6', 2, '/(other) => null', 1);
-    });
+    await prepareNavigation();
+    assertHasOperatorRegion('- 1', 1, '-(other) => null', 1);
+    assertHasOperatorRegion('+ 2', 1, '+(other) => null', 1);
+    assertHasOperatorRegion('-a; // unary', 1, '-() => null', 1);
+    assertHasOperatorRegion('--a;', 2, '-(other) => null', 1);
+    assertHasOperatorRegion('++a;', 2, '+(other) => null', 1);
+    assertHasOperatorRegion('--; // mm', 2, '-(other) => null', 1);
+    assertHasOperatorRegion('++; // pp', 2, '+(other) => null', 1);
+    assertHasOperatorRegion('-= 3', 2, '-(other) => null', 1);
+    assertHasOperatorRegion('+= 4', 2, '+(other) => null', 1);
+    assertHasOperatorRegion('*= 5', 2, '*(other) => null', 1);
+    assertHasOperatorRegion('/= 6', 2, '/(other) => null', 1);
   }
 
-  test_operator_index() {
+  test_operator_index() async {
     addTestFile('''
 class A {
   A operator +(other) => null;
@@ -776,92 +765,106 @@
   b[2] += 2;
 }
 ''');
-    return prepareNavigation().then((_) {
-      assertHasOperatorRegion('[0', 1, '[](index)', 2);
-      assertHasOperatorRegion('] // []', 1, '[](index)', 2);
-      assertHasOperatorRegion('[1', 1, '[]=(index,', 3);
-      assertHasOperatorRegion('] = 1;', 1, '[]=(index,', 3);
-      assertHasOperatorRegion('[2', 1, '[]=(index,', 3);
-      assertHasOperatorRegion('] += 2;', 1, '[]=(index,', 3);
-      assertHasOperatorRegion('+= 2;', 2, '+(other)', 1);
-    });
+    await prepareNavigation();
+    assertHasOperatorRegion('[0', 1, '[](index)', 2);
+    assertHasOperatorRegion('] // []', 1, '[](index)', 2);
+    assertHasOperatorRegion('[1', 1, '[]=(index,', 3);
+    assertHasOperatorRegion('] = 1;', 1, '[]=(index,', 3);
+    assertHasOperatorRegion('[2', 1, '[]=(index,', 3);
+    assertHasOperatorRegion('] += 2;', 1, '[]=(index,', 3);
+    assertHasOperatorRegion('+= 2;', 2, '+(other)', 1);
   }
 
-  test_partOf() {
+  test_partOf() async {
     var libCode = 'library lib; part "test.dart";';
     var libFile = addFile('$projectPath/bin/lib.dart', libCode);
     addTestFile('part of lib;');
-    return prepareNavigation().then((_) {
-      assertHasRegionString('lib');
-      assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
-    });
+    await prepareNavigation();
+    assertHasRegionString('lib');
+    assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
   }
 
-  test_string_export() {
+  test_redirectingConstructorInvocation() async {
+    addTestFile('''
+class A {
+  A() {}
+  A.foo() : this();
+  A.bar() : this.foo();
+}
+''');
+    await prepareNavigation();
+    {
+      assertHasRegion('this();');
+      assertHasTarget('A() {}', 0);
+    }
+    {
+      assertHasRegion('this.foo');
+      assertHasTarget('foo() :');
+    }
+    {
+      assertHasRegion('foo();');
+      assertHasTarget('foo() :');
+    }
+  }
+
+  test_string_export() async {
     var libCode = 'library lib;';
     var libFile = addFile('$projectPath/bin/lib.dart', libCode);
     addTestFile('export "lib.dart";');
-    return prepareNavigation().then((_) {
-      assertHasRegionString('"lib.dart"');
-      assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
-    });
+    await prepareNavigation();
+    assertHasRegionString('"lib.dart"');
+    assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
   }
 
-  test_string_export_unresolvedUri() {
+  test_string_export_unresolvedUri() async {
     addTestFile('export "no.dart";');
-    return prepareNavigation().then((_) {
-      assertNoRegionString('"no.dart"');
-    });
+    await prepareNavigation();
+    assertNoRegionString('"no.dart"');
   }
 
-  test_string_import() {
+  test_string_import() async {
     var libCode = 'library lib;';
     var libFile = addFile('$projectPath/bin/lib.dart', libCode);
     addTestFile('import "lib.dart";');
-    return prepareNavigation().then((_) {
-      assertHasRegionString('"lib.dart"');
-      assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
-    });
+    await prepareNavigation();
+    assertHasRegionString('"lib.dart"');
+    assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
   }
 
-  test_string_import_noUri() {
+  test_string_import_noUri() async {
     addTestFile('import ;');
-    return prepareNavigation().then((_) {
-      assertNoRegionAt('import ;');
-    });
+    await prepareNavigation();
+    assertNoRegionAt('import ;');
   }
 
-  test_string_import_unresolvedUri() {
+  test_string_import_unresolvedUri() async {
     addTestFile('import "no.dart";');
-    return prepareNavigation().then((_) {
-      assertNoRegionString('"no.dart"');
-    });
+    await prepareNavigation();
+    assertNoRegionString('"no.dart"');
   }
 
-  test_string_part() {
+  test_string_part() async {
     var unitCode = 'part of lib;  f() {}';
     var unitFile = addFile('$projectPath/bin/test_unit.dart', unitCode);
     addTestFile('''
 library lib;
 part "test_unit.dart";
 ''');
-    return prepareNavigation().then((_) {
-      assertHasRegionString('"test_unit.dart"');
-      assertHasFileTarget(unitFile, 0, 0);
-    });
+    await prepareNavigation();
+    assertHasRegionString('"test_unit.dart"');
+    assertHasFileTarget(unitFile, 0, 0);
   }
 
-  test_string_part_unresolvedUri() {
+  test_string_part_unresolvedUri() async {
     addTestFile('''
 library lib;
 part "test_unit.dart";
 ''');
-    return prepareNavigation().then((_) {
-      assertNoRegionString('"test_unit.dart"');
-    });
+    await prepareNavigation();
+    assertNoRegionString('"test_unit.dart"');
   }
 
-  test_superConstructorInvocation() {
+  test_superConstructorInvocation() async {
     addTestFile('''
 class A {
   A() {}
@@ -872,19 +875,22 @@
   B.named() : super.named();
 }
 ''');
-    return prepareNavigation().then((_) {
-      {
-        assertHasRegionString('super');
-        assertHasTarget('A() {}', 0);
-      }
-      {
-        assertHasRegionString('super.named');
-        assertHasTarget('named() {}');
-      }
-    });
+    await prepareNavigation();
+    {
+      assertHasRegionString('super');
+      assertHasTarget('A() {}', 0);
+    }
+    {
+      assertHasRegion('super.named');
+      assertHasTarget('named() {}');
+    }
+    {
+      assertHasRegion('named();');
+      assertHasTarget('named() {}');
+    }
   }
 
-  test_superConstructorInvocation_synthetic() {
+  test_superConstructorInvocation_synthetic() async {
     addTestFile('''
 class A {
 }
@@ -892,45 +898,39 @@
   B() : super();
 }
 ''');
-    return prepareNavigation().then((_) {
-      {
-        assertHasRegionString('super');
-        assertHasTarget('A {');
-      }
-    });
+    await prepareNavigation();
+    assertHasRegionString('super');
+    assertHasTarget('A {');
   }
 
-  test_targetElement() {
+  test_targetElement() async {
     addTestFile('''
 class AAA {}
 main() {
   AAA aaa = null;
 }
 ''');
-    return prepareNavigation().then((_) {
-      assertHasRegionTarget('AAA aaa', 'AAA {}');
-      expect(testTarget.kind, ElementKind.CLASS);
-    });
+    await prepareNavigation();
+    assertHasRegionTarget('AAA aaa', 'AAA {}');
+    expect(testTarget.kind, ElementKind.CLASS);
   }
 
-  test_type_dynamic() {
+  test_type_dynamic() async {
     addTestFile('''
 main() {
   dynamic v = null;
 }
 ''');
-    return prepareNavigation().then((_) {
-      assertNoRegionAt('dynamic');
-    });
+    await prepareNavigation();
+    assertNoRegionAt('dynamic');
   }
 
-  test_type_void() {
+  test_type_void() async {
     addTestFile('''
 void main() {
 }
 ''');
-    return prepareNavigation().then((_) {
-      assertNoRegionAt('void');
-    });
+    await prepareNavigation();
+    assertNoRegionAt('void');
   }
 }
diff --git a/pkg/analysis_server/test/analysis/notification_occurrences_test.dart b/pkg/analysis_server/test/analysis/notification_occurrences_test.dart
index cc7ebab..c27fa10 100644
--- a/pkg/analysis_server/test/analysis/notification_occurrences_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_occurrences_test.dart
@@ -22,14 +22,14 @@
 @reflectiveTest
 class AnalysisNotificationOccurrencesTest extends AbstractAnalysisTest {
   List<Occurrences> occurrencesList;
-  Occurrences testOccurences;
+  Occurrences testOccurrences;
 
   /**
-   * Asserts that there is an offset of [search] in [testOccurences].
+   * Asserts that there is an offset of [search] in [testOccurrences].
    */
   void assertHasOffset(String search) {
     int offset = findOffset(search);
-    expect(testOccurences.offsets, contains(offset));
+    expect(testOccurrences.offsets, contains(offset));
   }
 
   /**
@@ -49,7 +49,7 @@
    * Finds an [Occurrences] with the given [offset] and [length].
    *
    * If [exists] is `true`, then fails if such [Occurrences] does not exist.
-   * Otherwise remembers this it into [testOccurences].
+   * Otherwise remembers this it into [testOccurrences].
    *
    * If [exists] is `false`, then fails if such [Occurrences] exists.
    */
@@ -64,7 +64,7 @@
             fail('Not expected to find (offset=$offset; length=$length) in\n'
                 '${occurrencesList.join('\n')}');
           }
-          testOccurences = occurrences;
+          testOccurrences = occurrences;
           return;
         }
       }
@@ -95,25 +95,23 @@
     createProject();
   }
 
-  test_afterAnalysis() {
+  test_afterAnalysis() async {
     addTestFile('''
 main() {
   var vvv = 42;
   print(vvv);
 }
 ''');
-    return waitForTasksFinished().then((_) {
-      return prepareOccurrences().then((_) {
-        assertHasRegion('vvv =');
-        expect(testOccurences.element.kind, ElementKind.LOCAL_VARIABLE);
-        expect(testOccurences.element.name, 'vvv');
-        assertHasOffset('vvv = 42');
-        assertHasOffset('vvv);');
-      });
-    });
+    await waitForTasksFinished();
+    await prepareOccurrences();
+    assertHasRegion('vvv =');
+    expect(testOccurrences.element.kind, ElementKind.LOCAL_VARIABLE);
+    expect(testOccurrences.element.name, 'vvv');
+    assertHasOffset('vvv = 42');
+    assertHasOffset('vvv);');
   }
 
-  test_field() {
+  test_field() async {
     addTestFile('''
 class A {
   int fff;
@@ -124,26 +122,25 @@
   }
 }
 ''');
-    return prepareOccurrences().then((_) {
-      assertHasRegion('fff;');
-      expect(testOccurences.element.kind, ElementKind.FIELD);
-      assertHasOffset('fff); // constructor');
-      assertHasOffset('fff = 42;');
-      assertHasOffset('fff); // print');
-    });
+    await prepareOccurrences();
+    assertHasRegion('fff;');
+    expect(testOccurrences.element.kind, ElementKind.FIELD);
+    assertHasOffset('fff); // constructor');
+    assertHasOffset('fff = 42;');
+    assertHasOffset('fff); // print');
   }
 
-  test_field_unresolved() {
+  test_field_unresolved() async {
     addTestFile('''
 class A {
   A(this.noSuchField);
 }
 ''');
     // no checks for occurrences, just ensure that there is no NPE
-    return prepareOccurrences();
+    await prepareOccurrences();
   }
 
-  test_localVariable() {
+  test_localVariable() async {
     addTestFile('''
 main() {
   var vvv = 42;
@@ -151,17 +148,16 @@
   print(vvv);
 }
 ''');
-    return prepareOccurrences().then((_) {
-      assertHasRegion('vvv =');
-      expect(testOccurences.element.kind, ElementKind.LOCAL_VARIABLE);
-      expect(testOccurences.element.name, 'vvv');
-      assertHasOffset('vvv = 42');
-      assertHasOffset('vvv += 5');
-      assertHasOffset('vvv);');
-    });
+    await prepareOccurrences();
+    assertHasRegion('vvv =');
+    expect(testOccurrences.element.kind, ElementKind.LOCAL_VARIABLE);
+    expect(testOccurrences.element.name, 'vvv');
+    assertHasOffset('vvv = 42');
+    assertHasOffset('vvv += 5');
+    assertHasOffset('vvv);');
   }
 
-  test_memberField() {
+  test_memberField() async {
     addTestFile('''
 class A<T> {
   T fff;
@@ -173,15 +169,14 @@
   b.fff = 2;
 }
 ''');
-    return prepareOccurrences().then((_) {
-      assertHasRegion('fff;');
-      expect(testOccurences.element.kind, ElementKind.FIELD);
-      assertHasOffset('fff = 1;');
-      assertHasOffset('fff = 2;');
-    });
+    await prepareOccurrences();
+    assertHasRegion('fff;');
+    expect(testOccurrences.element.kind, ElementKind.FIELD);
+    assertHasOffset('fff = 1;');
+    assertHasOffset('fff = 2;');
   }
 
-  test_memberMethod() {
+  test_memberMethod() async {
     addTestFile('''
 class A<T> {
   T mmm() {}
@@ -193,15 +188,14 @@
   b.mmm(); // b
 }
 ''');
-    return prepareOccurrences().then((_) {
-      assertHasRegion('mmm() {}');
-      expect(testOccurences.element.kind, ElementKind.METHOD);
-      assertHasOffset('mmm(); // a');
-      assertHasOffset('mmm(); // b');
-    });
+    await prepareOccurrences();
+    assertHasRegion('mmm() {}');
+    expect(testOccurrences.element.kind, ElementKind.METHOD);
+    assertHasOffset('mmm(); // a');
+    assertHasOffset('mmm(); // b');
   }
 
-  test_topLevelVariable() {
+  test_topLevelVariable() async {
     addTestFile('''
 var VVV = 1;
 main() {
@@ -209,15 +203,14 @@
   print(VVV);
 }
 ''');
-    return prepareOccurrences().then((_) {
-      assertHasRegion('VVV = 1;');
-      expect(testOccurences.element.kind, ElementKind.TOP_LEVEL_VARIABLE);
-      assertHasOffset('VVV = 2;');
-      assertHasOffset('VVV);');
-    });
+    await prepareOccurrences();
+    assertHasRegion('VVV = 1;');
+    expect(testOccurrences.element.kind, ElementKind.TOP_LEVEL_VARIABLE);
+    assertHasOffset('VVV = 2;');
+    assertHasOffset('VVV);');
   }
 
-  test_type_class() {
+  test_type_class() async {
     addTestFile('''
 main() {
   int a = 1;
@@ -226,18 +219,17 @@
 }
 int VVV = 4;
 ''');
-    return prepareOccurrences().then((_) {
-      assertHasRegion('int a');
-      expect(testOccurences.element.kind, ElementKind.CLASS);
-      expect(testOccurences.element.name, 'int');
-      assertHasOffset('int a');
-      assertHasOffset('int b');
-      assertHasOffset('int c');
-      assertHasOffset('int VVV');
-    });
+    await prepareOccurrences();
+    assertHasRegion('int a');
+    expect(testOccurrences.element.kind, ElementKind.CLASS);
+    expect(testOccurrences.element.name, 'int');
+    assertHasOffset('int a');
+    assertHasOffset('int b');
+    assertHasOffset('int c');
+    assertHasOffset('int VVV');
   }
 
-  test_type_dynamic() {
+  test_type_dynamic() async {
     addTestFile('''
 main() {
   dynamic a = 1;
@@ -245,20 +237,18 @@
 }
 dynamic V = 3;
 ''');
-    return prepareOccurrences().then((_) {
-      int offset = findOffset('dynamic a');
-      findRegion(offset, 'dynamic'.length, false);
-    });
+    await prepareOccurrences();
+    int offset = findOffset('dynamic a');
+    findRegion(offset, 'dynamic'.length, false);
   }
 
-  test_type_void() {
+  test_type_void() async {
     addTestFile('''
 void main() {
 }
 ''');
-    return prepareOccurrences().then((_) {
-      int offset = findOffset('void main()');
-      findRegion(offset, 'void'.length, false);
-    });
+    await prepareOccurrences();
+    int offset = findOffset('void main()');
+    findRegion(offset, 'void'.length, false);
   }
 }
diff --git a/pkg/analysis_server/test/analysis/notification_outline_test.dart b/pkg/analysis_server/test/analysis/notification_outline_test.dart
index 679baae..1230dbc 100644
--- a/pkg/analysis_server/test/analysis/notification_outline_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_outline_test.dart
@@ -47,24 +47,22 @@
     createProject();
   }
 
-  test_afterAnalysis() {
+  test_afterAnalysis() async {
     addTestFile('''
 class AAA {
 }
 class BBB {
 }
 ''');
-    return waitForTasksFinished().then((_) {
-      expect(outline, isNull);
-      return prepareOutline().then((_) {
-        Outline unitOutline = outline;
-        List<Outline> outlines = unitOutline.children;
-        expect(outlines, hasLength(2));
-      });
-    });
+    await waitForTasksFinished();
+    expect(outline, isNull);
+    await prepareOutline();
+    Outline unitOutline = outline;
+    List<Outline> outlines = unitOutline.children;
+    expect(outlines, hasLength(2));
   }
 
-  test_class() {
+  test_class() async {
     addTestFile('''
 class A<K, V> {
   int fa, fb;
@@ -81,218 +79,216 @@
   B(int p);
 }");
 ''');
-    return prepareOutline().then((_) {
-      Outline unitOutline = outline;
-      List<Outline> topOutlines = unitOutline.children;
-      expect(topOutlines, hasLength(2));
-      // A
+    await prepareOutline();
+    Outline unitOutline = outline;
+    List<Outline> topOutlines = unitOutline.children;
+    expect(topOutlines, hasLength(2));
+    // A
+    {
+      Outline outline_A = topOutlines[0];
+      Element element_A = outline_A.element;
+      expect(element_A.kind, ElementKind.CLASS);
+      expect(element_A.name, "A");
+      expect(element_A.typeParameters, "<K, V>");
       {
-        Outline outline_A = topOutlines[0];
-        Element element_A = outline_A.element;
-        expect(element_A.kind, ElementKind.CLASS);
-        expect(element_A.name, "A");
-        expect(element_A.typeParameters, "<K, V>");
-        {
-          Location location = element_A.location;
-          expect(location.offset, testCode.indexOf("A<K, V> {"));
-          expect(location.length, 1);
-        }
-        expect(element_A.parameters, null);
-        expect(element_A.returnType, null);
-        // A children
-        List<Outline> outlines_A = outline_A.children;
-        expect(outlines_A, hasLength(10));
-        {
-          Outline outline = outlines_A[0];
-          Element element = outline.element;
-          expect(element.kind, ElementKind.FIELD);
-          expect(element.name, "fa");
-          expect(element.parameters, isNull);
-          expect(element.returnType, "int");
-        }
-        {
-          Outline outline = outlines_A[1];
-          Element element = outline.element;
-          expect(element.kind, ElementKind.FIELD);
-          expect(element.name, "fb");
-          expect(element.parameters, isNull);
-          expect(element.returnType, "int");
-        }
-        {
-          Outline outline = outlines_A[2];
-          Element element = outline.element;
-          expect(element.kind, ElementKind.FIELD);
-          expect(element.name, "fc");
-          expect(element.parameters, isNull);
-          expect(element.returnType, "String");
-        }
-        {
-          Outline outline = outlines_A[3];
-          Element element = outline.element;
-          expect(element.kind, ElementKind.CONSTRUCTOR);
-          expect(element.name, "A");
-          {
-            Location location = element.location;
-            expect(location.offset, testCode.indexOf("A(int i, String s);"));
-            expect(location.length, "A".length);
-          }
-          expect(element.parameters, "(int i, String s)");
-          expect(element.returnType, isNull);
-          expect(element.isAbstract, isFalse);
-          expect(element.isStatic, isFalse);
-        }
-        {
-          Outline outline = outlines_A[4];
-          Element element = outline.element;
-          expect(element.kind, ElementKind.CONSTRUCTOR);
-          expect(element.name, "A.name");
-          {
-            Location location = element.location;
-            expect(location.offset, testCode.indexOf("name(num p);"));
-            expect(location.length, "name".length);
-          }
-          expect(element.parameters, "(num p)");
-          expect(element.returnType, isNull);
-          expect(element.isAbstract, isFalse);
-          expect(element.isStatic, isFalse);
-        }
-        {
-          Outline outline = outlines_A[5];
-          Element element = outline.element;
-          expect(element.kind, ElementKind.CONSTRUCTOR);
-          expect(element.name, "A._privateName");
-          {
-            Location location = element.location;
-            expect(location.offset, testCode.indexOf("_privateName(num p);"));
-            expect(location.length, "_privateName".length);
-          }
-          expect(element.parameters, "(num p)");
-          expect(element.returnType, isNull);
-          expect(element.isAbstract, isFalse);
-          expect(element.isStatic, isFalse);
-        }
-        {
-          Outline outline = outlines_A[6];
-          Element element = outline.element;
-          expect(element.kind, ElementKind.METHOD);
-          expect(element.name, "ma");
-          {
-            Location location = element.location;
-            expect(location.offset, testCode.indexOf("ma(int pa) => null;"));
-            expect(location.length, "ma".length);
-          }
-          expect(element.parameters, "(int pa)");
-          expect(element.returnType, "String");
-          expect(element.isAbstract, isFalse);
-          expect(element.isStatic, isTrue);
-        }
-        {
-          Outline outline = outlines_A[7];
-          Element element = outline.element;
-          expect(element.kind, ElementKind.METHOD);
-          expect(element.name, "_mb");
-          {
-            Location location = element.location;
-            expect(location.offset, testCode.indexOf("_mb(int pb);"));
-            expect(location.length, "_mb".length);
-          }
-          expect(element.parameters, "(int pb)");
-          expect(element.returnType, "");
-          expect(element.isAbstract, isTrue);
-          expect(element.isStatic, isFalse);
-        }
-        {
-          Outline outline = outlines_A[8];
-          Element element = outline.element;
-          expect(element.kind, ElementKind.GETTER);
-          expect(element.name, "propA");
-          {
-            Location location = element.location;
-            expect(location.offset, testCode.indexOf("propA => null;"));
-            expect(location.length, "propA".length);
-          }
-          expect(element.parameters, isNull);
-          expect(element.returnType, "String");
-        }
-        {
-          Outline outline = outlines_A[9];
-          Element element = outline.element;
-          expect(element.kind, ElementKind.SETTER);
-          expect(element.name, "propB");
-          {
-            Location location = element.location;
-            expect(location.offset, testCode.indexOf("propB(int v) {}"));
-            expect(location.length, "propB".length);
-          }
-          expect(element.parameters, "(int v)");
-          expect(element.returnType, "");
-        }
+        Location location = element_A.location;
+        expect(location.offset, testCode.indexOf("A<K, V> {"));
+        expect(location.length, 1);
       }
-      // B
+      expect(element_A.parameters, null);
+      expect(element_A.returnType, null);
+      // A children
+      List<Outline> outlines_A = outline_A.children;
+      expect(outlines_A, hasLength(10));
       {
-        Outline outline_B = topOutlines[1];
-        Element element_B = outline_B.element;
-        expect(element_B.kind, ElementKind.CLASS);
-        expect(element_B.name, "B");
-        expect(element_B.typeParameters, isNull);
-        {
-          Location location = element_B.location;
-          expect(location.offset, testCode.indexOf("B {"));
-          expect(location.length, 1);
-        }
-        expect(element_B.parameters, null);
-        expect(element_B.returnType, null);
-        // B children
-        List<Outline> outlines_B = outline_B.children;
-        expect(outlines_B, hasLength(1));
-        {
-          Outline outline = outlines_B[0];
-          Element element = outline.element;
-          expect(element.kind, ElementKind.CONSTRUCTOR);
-          expect(element.name, "B");
-          {
-            Location location = element.location;
-            expect(location.offset, testCode.indexOf("B(int p);"));
-            expect(location.length, "B".length);
-          }
-          expect(element.parameters, "(int p)");
-          expect(element.returnType, isNull);
-        }
+        Outline outline = outlines_A[0];
+        Element element = outline.element;
+        expect(element.kind, ElementKind.FIELD);
+        expect(element.name, "fa");
+        expect(element.parameters, isNull);
+        expect(element.returnType, "int");
       }
-    });
+      {
+        Outline outline = outlines_A[1];
+        Element element = outline.element;
+        expect(element.kind, ElementKind.FIELD);
+        expect(element.name, "fb");
+        expect(element.parameters, isNull);
+        expect(element.returnType, "int");
+      }
+      {
+        Outline outline = outlines_A[2];
+        Element element = outline.element;
+        expect(element.kind, ElementKind.FIELD);
+        expect(element.name, "fc");
+        expect(element.parameters, isNull);
+        expect(element.returnType, "String");
+      }
+      {
+        Outline outline = outlines_A[3];
+        Element element = outline.element;
+        expect(element.kind, ElementKind.CONSTRUCTOR);
+        expect(element.name, "A");
+        {
+          Location location = element.location;
+          expect(location.offset, testCode.indexOf("A(int i, String s);"));
+          expect(location.length, "A".length);
+        }
+        expect(element.parameters, "(int i, String s)");
+        expect(element.returnType, isNull);
+        expect(element.isAbstract, isFalse);
+        expect(element.isStatic, isFalse);
+      }
+      {
+        Outline outline = outlines_A[4];
+        Element element = outline.element;
+        expect(element.kind, ElementKind.CONSTRUCTOR);
+        expect(element.name, "A.name");
+        {
+          Location location = element.location;
+          expect(location.offset, testCode.indexOf("name(num p);"));
+          expect(location.length, "name".length);
+        }
+        expect(element.parameters, "(num p)");
+        expect(element.returnType, isNull);
+        expect(element.isAbstract, isFalse);
+        expect(element.isStatic, isFalse);
+      }
+      {
+        Outline outline = outlines_A[5];
+        Element element = outline.element;
+        expect(element.kind, ElementKind.CONSTRUCTOR);
+        expect(element.name, "A._privateName");
+        {
+          Location location = element.location;
+          expect(location.offset, testCode.indexOf("_privateName(num p);"));
+          expect(location.length, "_privateName".length);
+        }
+        expect(element.parameters, "(num p)");
+        expect(element.returnType, isNull);
+        expect(element.isAbstract, isFalse);
+        expect(element.isStatic, isFalse);
+      }
+      {
+        Outline outline = outlines_A[6];
+        Element element = outline.element;
+        expect(element.kind, ElementKind.METHOD);
+        expect(element.name, "ma");
+        {
+          Location location = element.location;
+          expect(location.offset, testCode.indexOf("ma(int pa) => null;"));
+          expect(location.length, "ma".length);
+        }
+        expect(element.parameters, "(int pa)");
+        expect(element.returnType, "String");
+        expect(element.isAbstract, isFalse);
+        expect(element.isStatic, isTrue);
+      }
+      {
+        Outline outline = outlines_A[7];
+        Element element = outline.element;
+        expect(element.kind, ElementKind.METHOD);
+        expect(element.name, "_mb");
+        {
+          Location location = element.location;
+          expect(location.offset, testCode.indexOf("_mb(int pb);"));
+          expect(location.length, "_mb".length);
+        }
+        expect(element.parameters, "(int pb)");
+        expect(element.returnType, "");
+        expect(element.isAbstract, isTrue);
+        expect(element.isStatic, isFalse);
+      }
+      {
+        Outline outline = outlines_A[8];
+        Element element = outline.element;
+        expect(element.kind, ElementKind.GETTER);
+        expect(element.name, "propA");
+        {
+          Location location = element.location;
+          expect(location.offset, testCode.indexOf("propA => null;"));
+          expect(location.length, "propA".length);
+        }
+        expect(element.parameters, isNull);
+        expect(element.returnType, "String");
+      }
+      {
+        Outline outline = outlines_A[9];
+        Element element = outline.element;
+        expect(element.kind, ElementKind.SETTER);
+        expect(element.name, "propB");
+        {
+          Location location = element.location;
+          expect(location.offset, testCode.indexOf("propB(int v) {}"));
+          expect(location.length, "propB".length);
+        }
+        expect(element.parameters, "(int v)");
+        expect(element.returnType, "");
+      }
+    }
+    // B
+    {
+      Outline outline_B = topOutlines[1];
+      Element element_B = outline_B.element;
+      expect(element_B.kind, ElementKind.CLASS);
+      expect(element_B.name, "B");
+      expect(element_B.typeParameters, isNull);
+      {
+        Location location = element_B.location;
+        expect(location.offset, testCode.indexOf("B {"));
+        expect(location.length, 1);
+      }
+      expect(element_B.parameters, null);
+      expect(element_B.returnType, null);
+      // B children
+      List<Outline> outlines_B = outline_B.children;
+      expect(outlines_B, hasLength(1));
+      {
+        Outline outline = outlines_B[0];
+        Element element = outline.element;
+        expect(element.kind, ElementKind.CONSTRUCTOR);
+        expect(element.name, "B");
+        {
+          Location location = element.location;
+          expect(location.offset, testCode.indexOf("B(int p);"));
+          expect(location.length, "B".length);
+        }
+        expect(element.parameters, "(int p)");
+        expect(element.returnType, isNull);
+      }
+    }
   }
 
-  test_enum() {
+  test_enum() async {
     addTestFile('''
 enum MyEnum {
   A, B, C
 }
 ''');
-    return prepareOutline().then((_) {
-      Outline unitOutline = outline;
-      List<Outline> topOutlines = unitOutline.children;
-      expect(topOutlines, hasLength(1));
-      // MyEnum
+    await prepareOutline();
+    Outline unitOutline = outline;
+    List<Outline> topOutlines = unitOutline.children;
+    expect(topOutlines, hasLength(1));
+    // MyEnum
+    {
+      Outline outline_MyEnum = topOutlines[0];
+      Element element_MyEnum = outline_MyEnum.element;
+      expect(element_MyEnum.kind, ElementKind.ENUM);
+      expect(element_MyEnum.name, "MyEnum");
       {
-        Outline outline_MyEnum = topOutlines[0];
-        Element element_MyEnum = outline_MyEnum.element;
-        expect(element_MyEnum.kind, ElementKind.ENUM);
-        expect(element_MyEnum.name, "MyEnum");
-        {
-          Location location = element_MyEnum.location;
-          expect(location.offset, testCode.indexOf("MyEnum {"));
-          expect(location.length, 'MyEnum'.length);
-        }
-        expect(element_MyEnum.parameters, null);
-        expect(element_MyEnum.returnType, null);
-        // MyEnum children
-        List<Outline> outlines_MyEnum = outline_MyEnum.children;
-        expect(outlines_MyEnum, hasLength(3));
-        _isEnumConstant(outlines_MyEnum[0], 'A');
-        _isEnumConstant(outlines_MyEnum[1], 'B');
-        _isEnumConstant(outlines_MyEnum[2], 'C');
+        Location location = element_MyEnum.location;
+        expect(location.offset, testCode.indexOf("MyEnum {"));
+        expect(location.length, 'MyEnum'.length);
       }
-    });
+      expect(element_MyEnum.parameters, null);
+      expect(element_MyEnum.returnType, null);
+      // MyEnum children
+      List<Outline> outlines_MyEnum = outline_MyEnum.children;
+      expect(outlines_MyEnum, hasLength(3));
+      _isEnumConstant(outlines_MyEnum[0], 'A');
+      _isEnumConstant(outlines_MyEnum[1], 'B');
+      _isEnumConstant(outlines_MyEnum[2], 'C');
+    }
   }
 
   /**
@@ -300,7 +296,7 @@
    *
    * https://code.google.com/p/dart/issues/detail?id=21373
    */
-  test_invalidGetterInConstructor() {
+  test_invalidGetterInConstructor() async {
     addTestFile('''
 class A {
   A() {
@@ -310,9 +306,8 @@
   }
 }
 ''');
-    return prepareOutline().then((_) {
-      expect(outline, isNotNull);
-    });
+    await prepareOutline();
+    expect(outline, isNotNull);
   }
 
   test_libraryName_hasLibraryDirective() async {
@@ -352,7 +347,7 @@
     expect(libraryName, isNull);
   }
 
-  test_localFunctions() {
+  test_localFunctions() async {
     addTestFile('''
 class A {
   A() {
@@ -369,254 +364,251 @@
   }
 }
 ''');
-    return prepareOutline().then((_) {
-      Outline unitOutline = outline;
-      List<Outline> topOutlines = unitOutline.children;
-      expect(topOutlines, hasLength(2));
-      // A
+    await prepareOutline();
+    Outline unitOutline = outline;
+    List<Outline> topOutlines = unitOutline.children;
+    expect(topOutlines, hasLength(2));
+    // A
+    {
+      Outline outline_A = topOutlines[0];
+      Element element_A = outline_A.element;
+      expect(element_A.kind, ElementKind.CLASS);
+      expect(element_A.name, "A");
       {
-        Outline outline_A = topOutlines[0];
-        Element element_A = outline_A.element;
-        expect(element_A.kind, ElementKind.CLASS);
-        expect(element_A.name, "A");
+        Location location = element_A.location;
+        expect(location.offset, testCode.indexOf("A {"));
+        expect(location.length, "A".length);
+      }
+      expect(element_A.parameters, null);
+      expect(element_A.returnType, null);
+      // A children
+      List<Outline> outlines_A = outline_A.children;
+      expect(outlines_A, hasLength(2));
+      {
+        Outline constructorOutline = outlines_A[0];
+        Element constructorElement = constructorOutline.element;
+        expect(constructorElement.kind, ElementKind.CONSTRUCTOR);
+        expect(constructorElement.name, "A");
         {
-          Location location = element_A.location;
-          expect(location.offset, testCode.indexOf("A {"));
+          Location location = constructorElement.location;
+          expect(location.offset, testCode.indexOf("A() {"));
           expect(location.length, "A".length);
         }
-        expect(element_A.parameters, null);
-        expect(element_A.returnType, null);
-        // A children
-        List<Outline> outlines_A = outline_A.children;
-        expect(outlines_A, hasLength(2));
+        expect(constructorElement.parameters, "()");
+        expect(constructorElement.returnType, isNull);
+        // local function
+        List<Outline> outlines_constructor = constructorOutline.children;
+        expect(outlines_constructor, hasLength(1));
         {
-          Outline constructorOutline = outlines_A[0];
-          Element constructorElement = constructorOutline.element;
-          expect(constructorElement.kind, ElementKind.CONSTRUCTOR);
-          expect(constructorElement.name, "A");
+          Outline outline = outlines_constructor[0];
+          Element element = outline.element;
+          expect(element.kind, ElementKind.FUNCTION);
+          expect(element.name, "local_A");
           {
-            Location location = constructorElement.location;
-            expect(location.offset, testCode.indexOf("A() {"));
-            expect(location.length, "A".length);
+            Location location = element.location;
+            expect(location.offset, testCode.indexOf("local_A() {}"));
+            expect(location.length, "local_A".length);
           }
-          expect(constructorElement.parameters, "()");
-          expect(constructorElement.returnType, isNull);
-          // local function
-          List<Outline> outlines_constructor = constructorOutline.children;
-          expect(outlines_constructor, hasLength(1));
-          {
-            Outline outline = outlines_constructor[0];
-            Element element = outline.element;
-            expect(element.kind, ElementKind.FUNCTION);
-            expect(element.name, "local_A");
-            {
-              Location location = element.location;
-              expect(location.offset, testCode.indexOf("local_A() {}"));
-              expect(location.length, "local_A".length);
-            }
-            expect(element.parameters, "()");
-            expect(element.returnType, "int");
-          }
-        }
-        {
-          Outline outline_m = outlines_A[1];
-          Element element_m = outline_m.element;
-          expect(element_m.kind, ElementKind.METHOD);
-          expect(element_m.name, "m");
-          {
-            Location location = element_m.location;
-            expect(location.offset, testCode.indexOf("m() {"));
-            expect(location.length, "m".length);
-          }
-          expect(element_m.parameters, "()");
-          expect(element_m.returnType, "");
-          // local function
-          List<Outline> methodChildren = outline_m.children;
-          expect(methodChildren, hasLength(1));
-          {
-            Outline outline = methodChildren[0];
-            Element element = outline.element;
-            expect(element.kind, ElementKind.FUNCTION);
-            expect(element.name, "local_m");
-            {
-              Location location = element.location;
-              expect(location.offset, testCode.indexOf("local_m() {}"));
-              expect(location.length, "local_m".length);
-            }
-            expect(element.parameters, "()");
-            expect(element.returnType, "");
-          }
+          expect(element.parameters, "()");
+          expect(element.returnType, "int");
         }
       }
-      // f()
       {
-        Outline outline_f = topOutlines[1];
-        Element element_f = outline_f.element;
-        expect(element_f.kind, ElementKind.FUNCTION);
-        expect(element_f.name, "f");
+        Outline outline_m = outlines_A[1];
+        Element element_m = outline_m.element;
+        expect(element_m.kind, ElementKind.METHOD);
+        expect(element_m.name, "m");
         {
-          Location location = element_f.location;
-          expect(location.offset, testCode.indexOf("f() {"));
-          expect(location.length, "f".length);
+          Location location = element_m.location;
+          expect(location.offset, testCode.indexOf("m() {"));
+          expect(location.length, "m".length);
         }
-        expect(element_f.parameters, "()");
-        expect(element_f.returnType, "");
-        // f() children
-        List<Outline> outlines_f = outline_f.children;
-        expect(outlines_f, hasLength(2));
+        expect(element_m.parameters, "()");
+        expect(element_m.returnType, "");
+        // local function
+        List<Outline> methodChildren = outline_m.children;
+        expect(methodChildren, hasLength(1));
         {
-          Outline outline_f1 = outlines_f[0];
-          Element element_f1 = outline_f1.element;
-          expect(element_f1.kind, ElementKind.FUNCTION);
-          expect(element_f1.name, "local_f1");
+          Outline outline = methodChildren[0];
+          Element element = outline.element;
+          expect(element.kind, ElementKind.FUNCTION);
+          expect(element.name, "local_m");
           {
-            Location location = element_f1.location;
-            expect(location.offset, testCode.indexOf("local_f1(int i) {}"));
-            expect(location.length, "local_f1".length);
+            Location location = element.location;
+            expect(location.offset, testCode.indexOf("local_m() {}"));
+            expect(location.length, "local_m".length);
           }
-          expect(element_f1.parameters, "(int i)");
-          expect(element_f1.returnType, "");
-        }
-        {
-          Outline outline_f2 = outlines_f[1];
-          Element element_f2 = outline_f2.element;
-          expect(element_f2.kind, ElementKind.FUNCTION);
-          expect(element_f2.name, "local_f2");
-          {
-            Location location = element_f2.location;
-            expect(location.offset, testCode.indexOf("local_f2(String s) {"));
-            expect(location.length, "local_f2".length);
-          }
-          expect(element_f2.parameters, "(String s)");
-          expect(element_f2.returnType, "");
-          // local_f2() local function
-          List<Outline> outlines_f2 = outline_f2.children;
-          expect(outlines_f2, hasLength(1));
-          {
-            Outline outline_f21 = outlines_f2[0];
-            Element element_f21 = outline_f21.element;
-            expect(element_f21.kind, ElementKind.FUNCTION);
-            expect(element_f21.name, "local_f21");
-            {
-              Location location = element_f21.location;
-              expect(location.offset, testCode.indexOf("local_f21(int p) {"));
-              expect(location.length, "local_f21".length);
-            }
-            expect(element_f21.parameters, "(int p)");
-            expect(element_f21.returnType, "");
-          }
+          expect(element.parameters, "()");
+          expect(element.returnType, "");
         }
       }
-    });
+    }
+    // f()
+    {
+      Outline outline_f = topOutlines[1];
+      Element element_f = outline_f.element;
+      expect(element_f.kind, ElementKind.FUNCTION);
+      expect(element_f.name, "f");
+      {
+        Location location = element_f.location;
+        expect(location.offset, testCode.indexOf("f() {"));
+        expect(location.length, "f".length);
+      }
+      expect(element_f.parameters, "()");
+      expect(element_f.returnType, "");
+      // f() children
+      List<Outline> outlines_f = outline_f.children;
+      expect(outlines_f, hasLength(2));
+      {
+        Outline outline_f1 = outlines_f[0];
+        Element element_f1 = outline_f1.element;
+        expect(element_f1.kind, ElementKind.FUNCTION);
+        expect(element_f1.name, "local_f1");
+        {
+          Location location = element_f1.location;
+          expect(location.offset, testCode.indexOf("local_f1(int i) {}"));
+          expect(location.length, "local_f1".length);
+        }
+        expect(element_f1.parameters, "(int i)");
+        expect(element_f1.returnType, "");
+      }
+      {
+        Outline outline_f2 = outlines_f[1];
+        Element element_f2 = outline_f2.element;
+        expect(element_f2.kind, ElementKind.FUNCTION);
+        expect(element_f2.name, "local_f2");
+        {
+          Location location = element_f2.location;
+          expect(location.offset, testCode.indexOf("local_f2(String s) {"));
+          expect(location.length, "local_f2".length);
+        }
+        expect(element_f2.parameters, "(String s)");
+        expect(element_f2.returnType, "");
+        // local_f2() local function
+        List<Outline> outlines_f2 = outline_f2.children;
+        expect(outlines_f2, hasLength(1));
+        {
+          Outline outline_f21 = outlines_f2[0];
+          Element element_f21 = outline_f21.element;
+          expect(element_f21.kind, ElementKind.FUNCTION);
+          expect(element_f21.name, "local_f21");
+          {
+            Location location = element_f21.location;
+            expect(location.offset, testCode.indexOf("local_f21(int p) {"));
+            expect(location.length, "local_f21".length);
+          }
+          expect(element_f21.parameters, "(int p)");
+          expect(element_f21.returnType, "");
+        }
+      }
+    }
   }
 
-  test_sourceRange_inClass() {
+  test_sourceRange_inClass() async {
     addTestFile('''
 class A { // leftA
   int methodA() {} // endA
   int methodB() {} // endB
 }
 ''');
-    return prepareOutline().then((_) {
-      Outline unitOutline = outline;
-      List<Outline> outlines = unitOutline.children[0].children;
-      expect(outlines, hasLength(2));
-      // methodA
+    await prepareOutline();
+    Outline unitOutline = outline;
+    List<Outline> outlines = unitOutline.children[0].children;
+    expect(outlines, hasLength(2));
+    // methodA
+    {
+      Outline outline = outlines[0];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.METHOD);
+      expect(element.name, "methodA");
       {
-        Outline outline = outlines[0];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.METHOD);
-        expect(element.name, "methodA");
-        {
-          int offset = testCode.indexOf(" // leftA");
-          int end = testCode.indexOf(" // endA");
-          expect(outline.offset, offset);
-          expect(outline.length, end - offset);
-        }
+        int offset = testCode.indexOf(" // leftA");
+        int end = testCode.indexOf(" // endA");
+        expect(outline.offset, offset);
+        expect(outline.length, end - offset);
       }
-      // methodB
+    }
+    // methodB
+    {
+      Outline outline = outlines[1];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.METHOD);
+      expect(element.name, "methodB");
       {
-        Outline outline = outlines[1];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.METHOD);
-        expect(element.name, "methodB");
-        {
-          int offset = testCode.indexOf(" // endA");
-          int end = testCode.indexOf(" // endB");
-          expect(outline.offset, offset);
-          expect(outline.length, end - offset);
-        }
+        int offset = testCode.indexOf(" // endA");
+        int end = testCode.indexOf(" // endB");
+        expect(outline.offset, offset);
+        expect(outline.length, end - offset);
       }
-    });
+    }
   }
 
-  test_sourceRange_inClass_inVariableList() {
+  test_sourceRange_inClass_inVariableList() async {
     addTestFile('''
 class A { // leftA
   int fieldA, fieldB, fieldC; // marker
   int fieldD; // marker2
 }
 ''');
-    return prepareOutline().then((_) {
-      Outline unitOutline = outline;
-      List<Outline> outlines = unitOutline.children[0].children;
-      expect(outlines, hasLength(4));
-      // fieldA
+    await prepareOutline();
+    Outline unitOutline = outline;
+    List<Outline> outlines = unitOutline.children[0].children;
+    expect(outlines, hasLength(4));
+    // fieldA
+    {
+      Outline outline = outlines[0];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.FIELD);
+      expect(element.name, "fieldA");
       {
-        Outline outline = outlines[0];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.FIELD);
-        expect(element.name, "fieldA");
-        {
-          int offset = testCode.indexOf(" // leftA");
-          int end = testCode.indexOf(", fieldB");
-          expect(outline.offset, offset);
-          expect(outline.length, end - offset);
-        }
+        int offset = testCode.indexOf(" // leftA");
+        int end = testCode.indexOf(", fieldB");
+        expect(outline.offset, offset);
+        expect(outline.length, end - offset);
       }
-      // fieldB
+    }
+    // fieldB
+    {
+      Outline outline = outlines[1];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.FIELD);
+      expect(element.name, "fieldB");
       {
-        Outline outline = outlines[1];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.FIELD);
-        expect(element.name, "fieldB");
-        {
-          int offset = testCode.indexOf(", fieldB");
-          int end = testCode.indexOf(", fieldC");
-          expect(outline.offset, offset);
-          expect(outline.length, end - offset);
-        }
+        int offset = testCode.indexOf(", fieldB");
+        int end = testCode.indexOf(", fieldC");
+        expect(outline.offset, offset);
+        expect(outline.length, end - offset);
       }
-      // fieldC
+    }
+    // fieldC
+    {
+      Outline outline = outlines[2];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.FIELD);
+      expect(element.name, "fieldC");
       {
-        Outline outline = outlines[2];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.FIELD);
-        expect(element.name, "fieldC");
-        {
-          int offset = testCode.indexOf(", fieldC");
-          int end = testCode.indexOf(" // marker");
-          expect(outline.offset, offset);
-          expect(outline.length, end - offset);
-        }
+        int offset = testCode.indexOf(", fieldC");
+        int end = testCode.indexOf(" // marker");
+        expect(outline.offset, offset);
+        expect(outline.length, end - offset);
       }
-      // fieldD
+    }
+    // fieldD
+    {
+      Outline outline = outlines[3];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.FIELD);
+      expect(element.name, "fieldD");
       {
-        Outline outline = outlines[3];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.FIELD);
-        expect(element.name, "fieldD");
-        {
-          int offset = testCode.indexOf(" // marker");
-          int end = testCode.indexOf(" // marker2");
-          expect(outline.offset, offset);
-          expect(outline.length, end - offset);
-        }
+        int offset = testCode.indexOf(" // marker");
+        int end = testCode.indexOf(" // marker2");
+        expect(outline.offset, offset);
+        expect(outline.length, end - offset);
       }
-    });
+    }
   }
 
-  test_sourceRange_inUnit() {
+  test_sourceRange_inUnit() async {
     addTestFile('''
 library lib;
 /// My first class.
@@ -625,104 +617,102 @@
 class B {
 } // endB
 ''');
-    return prepareOutline().then((_) {
-      Outline unitOutline = outline;
-      List<Outline> topOutlines = unitOutline.children;
-      expect(topOutlines, hasLength(2));
-      // A
+    await prepareOutline();
+    Outline unitOutline = outline;
+    List<Outline> topOutlines = unitOutline.children;
+    expect(topOutlines, hasLength(2));
+    // A
+    {
+      Outline outline = topOutlines[0];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.CLASS);
+      expect(element.name, "A");
       {
-        Outline outline = topOutlines[0];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.CLASS);
-        expect(element.name, "A");
-        {
-          int offset = testCode.indexOf("/// My first class.");
-          int end = testCode.indexOf(" // endA");
-          expect(outline.offset, offset);
-          expect(outline.length, end - offset);
-        }
+        int offset = testCode.indexOf("/// My first class.");
+        int end = testCode.indexOf(" // endA");
+        expect(outline.offset, offset);
+        expect(outline.length, end - offset);
       }
-      // B
+    }
+    // B
+    {
+      Outline outline = topOutlines[1];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.CLASS);
+      expect(element.name, "B");
       {
-        Outline outline = topOutlines[1];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.CLASS);
-        expect(element.name, "B");
-        {
-          int offset = testCode.indexOf(" // endA");
-          int end = testCode.indexOf(" // endB");
-          expect(outline.offset, offset);
-          expect(outline.length, end - offset);
-        }
+        int offset = testCode.indexOf(" // endA");
+        int end = testCode.indexOf(" // endB");
+        expect(outline.offset, offset);
+        expect(outline.length, end - offset);
       }
-    });
+    }
   }
 
-  test_sourceRange_inUnit_inVariableList() {
+  test_sourceRange_inUnit_inVariableList() async {
     addTestFile('''
 int fieldA, fieldB, fieldC; // marker
 int fieldD; // marker2
 ''');
-    return prepareOutline().then((_) {
-      Outline unitOutline = outline;
-      List<Outline> outlines = unitOutline.children;
-      expect(outlines, hasLength(4));
-      // fieldA
+    await prepareOutline();
+    Outline unitOutline = outline;
+    List<Outline> outlines = unitOutline.children;
+    expect(outlines, hasLength(4));
+    // fieldA
+    {
+      Outline outline = outlines[0];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.TOP_LEVEL_VARIABLE);
+      expect(element.name, "fieldA");
       {
-        Outline outline = outlines[0];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.TOP_LEVEL_VARIABLE);
-        expect(element.name, "fieldA");
-        {
-          int offset = 0;
-          int end = testCode.indexOf(", fieldB");
-          expect(outline.offset, offset);
-          expect(outline.length, end - offset);
-        }
+        int offset = 0;
+        int end = testCode.indexOf(", fieldB");
+        expect(outline.offset, offset);
+        expect(outline.length, end - offset);
       }
-      // fieldB
+    }
+    // fieldB
+    {
+      Outline outline = outlines[1];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.TOP_LEVEL_VARIABLE);
+      expect(element.name, "fieldB");
       {
-        Outline outline = outlines[1];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.TOP_LEVEL_VARIABLE);
-        expect(element.name, "fieldB");
-        {
-          int offset = testCode.indexOf(", fieldB");
-          int end = testCode.indexOf(", fieldC");
-          expect(outline.offset, offset);
-          expect(outline.length, end - offset);
-        }
+        int offset = testCode.indexOf(", fieldB");
+        int end = testCode.indexOf(", fieldC");
+        expect(outline.offset, offset);
+        expect(outline.length, end - offset);
       }
-      // fieldC
+    }
+    // fieldC
+    {
+      Outline outline = outlines[2];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.TOP_LEVEL_VARIABLE);
+      expect(element.name, "fieldC");
       {
-        Outline outline = outlines[2];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.TOP_LEVEL_VARIABLE);
-        expect(element.name, "fieldC");
-        {
-          int offset = testCode.indexOf(", fieldC");
-          int end = testCode.indexOf(" // marker");
-          expect(outline.offset, offset);
-          expect(outline.length, end - offset);
-        }
+        int offset = testCode.indexOf(", fieldC");
+        int end = testCode.indexOf(" // marker");
+        expect(outline.offset, offset);
+        expect(outline.length, end - offset);
       }
-      // fieldD
+    }
+    // fieldD
+    {
+      Outline outline = outlines[3];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.TOP_LEVEL_VARIABLE);
+      expect(element.name, "fieldD");
       {
-        Outline outline = outlines[3];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.TOP_LEVEL_VARIABLE);
-        expect(element.name, "fieldD");
-        {
-          int offset = testCode.indexOf(" // marker");
-          int end = testCode.indexOf(" // marker2");
-          expect(outline.offset, offset);
-          expect(outline.length, end - offset);
-        }
+        int offset = testCode.indexOf(" // marker");
+        int end = testCode.indexOf(" // marker2");
+        expect(outline.offset, offset);
+        expect(outline.length, end - offset);
       }
-    });
+    }
   }
 
-  test_topLevel() {
+  test_topLevel() async {
     addTestFile('''
 typedef String FTA<K, V>(int i, String s);
 typedef FTB(int p);
@@ -735,121 +725,120 @@
 String get propA => null;
 set propB(int v) {}
 ''');
-    return prepareOutline().then((_) {
-      Outline unitOutline = outline;
-      List<Outline> topOutlines = unitOutline.children;
-      expect(topOutlines, hasLength(10));
-      // FTA
+    await prepareOutline();
+    Outline unitOutline = outline;
+    List<Outline> topOutlines = unitOutline.children;
+    expect(topOutlines, hasLength(10));
+    // FTA
+    {
+      Outline outline = topOutlines[0];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.FUNCTION_TYPE_ALIAS);
+      expect(element.name, "FTA");
+      expect(element.typeParameters, "<K, V>");
       {
-        Outline outline = topOutlines[0];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.FUNCTION_TYPE_ALIAS);
-        expect(element.name, "FTA");
-        expect(element.typeParameters, "<K, V>");
-        {
-          Location location = element.location;
-          expect(location.offset, testCode.indexOf("FTA<K, V>("));
-          expect(location.length, "FTA".length);
-        }
-        expect(element.parameters, "(int i, String s)");
-        expect(element.returnType, "String");
+        Location location = element.location;
+        expect(location.offset, testCode.indexOf("FTA<K, V>("));
+        expect(location.length, "FTA".length);
       }
-      // FTB
+      expect(element.parameters, "(int i, String s)");
+      expect(element.returnType, "String");
+    }
+    // FTB
+    {
+      Outline outline = topOutlines[1];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.FUNCTION_TYPE_ALIAS);
+      expect(element.name, "FTB");
+      expect(element.typeParameters, isNull);
       {
-        Outline outline = topOutlines[1];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.FUNCTION_TYPE_ALIAS);
-        expect(element.name, "FTB");
-        expect(element.typeParameters, isNull);
-        {
-          Location location = element.location;
-          expect(location.offset, testCode.indexOf("FTB("));
-          expect(location.length, "FTB".length);
-        }
-        expect(element.parameters, "(int p)");
-        expect(element.returnType, "");
+        Location location = element.location;
+        expect(location.offset, testCode.indexOf("FTB("));
+        expect(location.length, "FTB".length);
       }
-      // CTA
+      expect(element.parameters, "(int p)");
+      expect(element.returnType, "");
+    }
+    // CTA
+    {
+      Outline outline = topOutlines[4];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.CLASS_TYPE_ALIAS);
+      expect(element.name, "CTA");
+      expect(element.typeParameters, '<T>');
       {
-        Outline outline = topOutlines[4];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.CLASS_TYPE_ALIAS);
-        expect(element.name, "CTA");
-        expect(element.typeParameters, '<T>');
-        {
-          Location location = element.location;
-          expect(location.offset, testCode.indexOf("CTA<T> ="));
-          expect(location.length, "CTA".length);
-        }
-        expect(element.parameters, isNull);
-        expect(element.returnType, isNull);
+        Location location = element.location;
+        expect(location.offset, testCode.indexOf("CTA<T> ="));
+        expect(location.length, "CTA".length);
       }
-      // CTB
+      expect(element.parameters, isNull);
+      expect(element.returnType, isNull);
+    }
+    // CTB
+    {
+      Outline outline = topOutlines[5];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.CLASS_TYPE_ALIAS);
+      expect(element.name, 'CTB');
+      expect(element.typeParameters, isNull);
+      expect(element.returnType, isNull);
+    }
+    // fA
+    {
+      Outline outline = topOutlines[6];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.FUNCTION);
+      expect(element.name, "fA");
       {
-        Outline outline = topOutlines[5];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.CLASS_TYPE_ALIAS);
-        expect(element.name, 'CTB');
-        expect(element.typeParameters, isNull);
-        expect(element.returnType, isNull);
+        Location location = element.location;
+        expect(location.offset, testCode.indexOf("fA("));
+        expect(location.length, "fA".length);
       }
-      // fA
+      expect(element.parameters, "(int i, String s)");
+      expect(element.returnType, "String");
+    }
+    // fB
+    {
+      Outline outline = topOutlines[7];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.FUNCTION);
+      expect(element.name, "fB");
       {
-        Outline outline = topOutlines[6];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.FUNCTION);
-        expect(element.name, "fA");
-        {
-          Location location = element.location;
-          expect(location.offset, testCode.indexOf("fA("));
-          expect(location.length, "fA".length);
-        }
-        expect(element.parameters, "(int i, String s)");
-        expect(element.returnType, "String");
+        Location location = element.location;
+        expect(location.offset, testCode.indexOf("fB("));
+        expect(location.length, "fB".length);
       }
-      // fB
+      expect(element.parameters, "(int p)");
+      expect(element.returnType, "");
+    }
+    // propA
+    {
+      Outline outline = topOutlines[8];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.GETTER);
+      expect(element.name, "propA");
       {
-        Outline outline = topOutlines[7];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.FUNCTION);
-        expect(element.name, "fB");
-        {
-          Location location = element.location;
-          expect(location.offset, testCode.indexOf("fB("));
-          expect(location.length, "fB".length);
-        }
-        expect(element.parameters, "(int p)");
-        expect(element.returnType, "");
+        Location location = element.location;
+        expect(location.offset, testCode.indexOf("propA => null;"));
+        expect(location.length, "propA".length);
       }
-      // propA
+      expect(element.parameters, "");
+      expect(element.returnType, "String");
+    }
+    // propB
+    {
+      Outline outline = topOutlines[9];
+      Element element = outline.element;
+      expect(element.kind, ElementKind.SETTER);
+      expect(element.name, "propB");
       {
-        Outline outline = topOutlines[8];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.GETTER);
-        expect(element.name, "propA");
-        {
-          Location location = element.location;
-          expect(location.offset, testCode.indexOf("propA => null;"));
-          expect(location.length, "propA".length);
-        }
-        expect(element.parameters, "");
-        expect(element.returnType, "String");
+        Location location = element.location;
+        expect(location.offset, testCode.indexOf("propB(int v) {}"));
+        expect(location.length, "propB".length);
       }
-      // propB
-      {
-        Outline outline = topOutlines[9];
-        Element element = outline.element;
-        expect(element.kind, ElementKind.SETTER);
-        expect(element.name, "propB");
-        {
-          Location location = element.location;
-          expect(location.offset, testCode.indexOf("propB(int v) {}"));
-          expect(location.length, "propB".length);
-        }
-        expect(element.parameters, "(int v)");
-        expect(element.returnType, "");
-      }
-    });
+      expect(element.parameters, "(int v)");
+      expect(element.returnType, "");
+    }
   }
 
   void _isEnumConstant(Outline outline, String name) {
diff --git a/pkg/analysis_server/test/analysis/notification_overrides_test.dart b/pkg/analysis_server/test/analysis/notification_overrides_test.dart
index fa1a0b5..2465be3 100644
--- a/pkg/analysis_server/test/analysis/notification_overrides_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_overrides_test.dart
@@ -121,7 +121,7 @@
     createProject();
   }
 
-  test_afterAnalysis() {
+  test_afterAnalysis() async {
     addTestFile('''
 class A {
   m() {} // in A
@@ -130,16 +130,14 @@
   m() {} // in B
 }
 ''');
-    return waitForTasksFinished().then((_) {
-      return prepareOverrides().then((_) {
-        assertHasOverride('m() {} // in B');
-        assertNoSuperMember();
-        assertHasInterfaceMember('m() {} // in A');
-      });
-    });
+    await waitForTasksFinished();
+    await prepareOverrides();
+    assertHasOverride('m() {} // in B');
+    assertNoSuperMember();
+    assertHasInterfaceMember('m() {} // in A');
   }
 
-  test_definedInInterface_ofInterface() {
+  test_definedInInterface_ofInterface() async {
     addTestFile('''
 class A {
   m() {} // in A
@@ -149,14 +147,13 @@
   m() {} // in C
 }
 ''');
-    return prepareOverrides().then((_) {
-      assertHasOverride('m() {} // in C');
-      assertNoSuperMember();
-      assertHasInterfaceMember('m() {} // in A');
-    });
+    await prepareOverrides();
+    assertHasOverride('m() {} // in C');
+    assertNoSuperMember();
+    assertHasInterfaceMember('m() {} // in A');
   }
 
-  test_definedInInterface_ofSuper() {
+  test_definedInInterface_ofSuper() async {
     addTestFile('''
 class A {
   m() {} // in A
@@ -166,14 +163,13 @@
   m() {} // in C
 }
 ''');
-    return prepareOverrides().then((_) {
-      assertHasOverride('m() {} // in C');
-      assertNoSuperMember();
-      assertHasInterfaceMember('m() {} // in A');
-    });
+    await prepareOverrides();
+    assertHasOverride('m() {} // in C');
+    assertNoSuperMember();
+    assertHasInterfaceMember('m() {} // in A');
   }
 
-  test_interface_method_direct_multiple() {
+  test_interface_method_direct_multiple() async {
     addTestFile('''
 class IA {
   m() {} // in IA
@@ -185,15 +181,14 @@
   m() {} // in A
 }
 ''');
-    return prepareOverrides().then((_) {
-      assertHasOverride('m() {} // in A');
-      assertNoSuperMember();
-      assertHasInterfaceMember('m() {} // in IA');
-      assertHasInterfaceMember('m() {} // in IB');
-    });
+    await prepareOverrides();
+    assertHasOverride('m() {} // in A');
+    assertNoSuperMember();
+    assertHasInterfaceMember('m() {} // in IA');
+    assertHasInterfaceMember('m() {} // in IB');
   }
 
-  test_interface_method_direct_single() {
+  test_interface_method_direct_single() async {
     addTestFile('''
 class A {
   m() {} // in A
@@ -202,14 +197,13 @@
   m() {} // in B
 }
 ''');
-    return prepareOverrides().then((_) {
-      assertHasOverride('m() {} // in B');
-      assertNoSuperMember();
-      assertHasInterfaceMember('m() {} // in A');
-    });
+    await prepareOverrides();
+    assertHasOverride('m() {} // in B');
+    assertNoSuperMember();
+    assertHasInterfaceMember('m() {} // in A');
   }
 
-  test_interface_method_indirect_single() {
+  test_interface_method_indirect_single() async {
     addTestFile('''
 class A {
   m() {} // in A
@@ -220,14 +214,13 @@
   m() {} // in C
 }
 ''');
-    return prepareOverrides().then((_) {
-      assertHasOverride('m() {} // in C');
-      assertNoSuperMember();
-      assertHasInterfaceMember('m() {} // in A');
-    });
+    await prepareOverrides();
+    assertHasOverride('m() {} // in C');
+    assertNoSuperMember();
+    assertHasInterfaceMember('m() {} // in A');
   }
 
-  test_interface_stopWhenFound() {
+  test_interface_stopWhenFound() async {
     addTestFile('''
 class A {
   m() {} // in A
@@ -239,14 +232,13 @@
   m() {} // in C
 }
 ''');
-    return prepareOverrides().then((_) {
-      assertHasOverride('m() {} // in C');
-      expect(override.interfaceMembers, hasLength(1));
-      assertHasInterfaceMember('m() {} // in B');
-    });
+    await prepareOverrides();
+    assertHasOverride('m() {} // in C');
+    expect(override.interfaceMembers, hasLength(1));
+    assertHasInterfaceMember('m() {} // in B');
   }
 
-  test_mix_sameMethod() {
+  test_mix_sameMethod() async {
     addTestFile('''
 class A {
   m() {} // in A
@@ -257,14 +249,13 @@
   m() {} // in C
 }
 ''');
-    return prepareOverrides().then((_) {
-      assertHasOverride('m() {} // in C');
-      assertHasSuperElement('m() {} // in A');
-      assertNoInterfaceMembers();
-    });
+    await prepareOverrides();
+    assertHasOverride('m() {} // in C');
+    assertHasSuperElement('m() {} // in A');
+    assertNoInterfaceMembers();
   }
 
-  test_mix_sameMethod_Object_hashCode() {
+  test_mix_sameMethod_Object_hashCode() async {
     addTestFile('''
 class A {}
 abstract class B {}
@@ -272,14 +263,13 @@
   int get hashCode => 42;
 }
 ''');
-    return prepareOverrides().then((_) {
-      assertHasOverride('hashCode => 42;');
-      expect(override.superclassMember, isNotNull);
-      expect(override.interfaceMembers, isNull);
-    });
+    await prepareOverrides();
+    assertHasOverride('hashCode => 42;');
+    expect(override.superclassMember, isNotNull);
+    expect(override.interfaceMembers, isNull);
   }
 
-  test_staticMembers() {
+  test_staticMembers() async {
     addTestFile('''
 class A {
   static int F = 0;
@@ -294,12 +284,11 @@
   static void set S(int v) {}
 }
 ''');
-    return prepareOverrides().then((_) {
-      expect(overridesList, isEmpty);
-    });
+    await prepareOverrides();
+    expect(overridesList, isEmpty);
   }
 
-  test_super_fieldByField() {
+  test_super_fieldByField() async {
     addTestFile('''
 class A {
   int fff; // in A
@@ -308,14 +297,13 @@
   int fff; // in B
 }
 ''');
-    return prepareOverrides().then((_) {
-      assertHasOverride('fff; // in B');
-      assertHasSuperElement('fff; // in A');
-      assertNoInterfaceMembers();
-    });
+    await prepareOverrides();
+    assertHasOverride('fff; // in B');
+    assertHasSuperElement('fff; // in A');
+    assertNoInterfaceMembers();
   }
 
-  test_super_fieldByGetter() {
+  test_super_fieldByGetter() async {
     addTestFile('''
 class A {
   int fff; // in A
@@ -324,14 +312,13 @@
   get fff => 0; // in B
 }
 ''');
-    return prepareOverrides().then((_) {
-      assertHasOverride('fff => 0; // in B');
-      assertHasSuperElement('fff; // in A');
-      assertNoInterfaceMembers();
-    });
+    await prepareOverrides();
+    assertHasOverride('fff => 0; // in B');
+    assertHasSuperElement('fff; // in A');
+    assertNoInterfaceMembers();
   }
 
-  test_super_fieldByMethod() {
+  test_super_fieldByMethod() async {
     addTestFile('''
 class A {
   int fff; // in A
@@ -340,14 +327,13 @@
   fff() {} // in B
 }
 ''');
-    return prepareOverrides().then((_) {
-      assertHasOverride('fff() {} // in B');
-      assertHasSuperElement('fff; // in A');
-      assertNoInterfaceMembers();
-    });
+    await prepareOverrides();
+    assertHasOverride('fff() {} // in B');
+    assertHasSuperElement('fff; // in A');
+    assertNoInterfaceMembers();
   }
 
-  test_super_fieldBySetter() {
+  test_super_fieldBySetter() async {
     addTestFile('''
 class A {
   int fff; // in A
@@ -356,14 +342,13 @@
   set fff(x) {} // in B
 }
 ''');
-    return prepareOverrides().then((_) {
-      assertHasOverride('fff(x) {} // in B');
-      assertHasSuperElement('fff; // in A');
-      assertNoInterfaceMembers();
-    });
+    await prepareOverrides();
+    assertHasOverride('fff(x) {} // in B');
+    assertHasSuperElement('fff; // in A');
+    assertNoInterfaceMembers();
   }
 
-  test_super_getterByField() {
+  test_super_getterByField() async {
     addTestFile('''
 class A {
   get fff => 0; // in A
@@ -373,14 +358,13 @@
   int fff; // in B
 }
 ''');
-    return prepareOverrides().then((_) {
-      assertHasOverride('fff; // in B');
-      assertHasSuperElement('fff => 0; // in A');
-      assertNoInterfaceMembers();
-    });
+    await prepareOverrides();
+    assertHasOverride('fff; // in B');
+    assertHasSuperElement('fff => 0; // in A');
+    assertNoInterfaceMembers();
   }
 
-  test_super_getterByGetter() {
+  test_super_getterByGetter() async {
     addTestFile('''
 class A {
   get fff => 0; // in A
@@ -389,14 +373,13 @@
   get fff => 0; // in B
 }
 ''');
-    return prepareOverrides().then((_) {
-      assertHasOverride('fff => 0; // in B');
-      assertHasSuperElement('fff => 0; // in A');
-      assertNoInterfaceMembers();
-    });
+    await prepareOverrides();
+    assertHasOverride('fff => 0; // in B');
+    assertHasSuperElement('fff => 0; // in A');
+    assertNoInterfaceMembers();
   }
 
-  test_super_method_direct() {
+  test_super_method_direct() async {
     addTestFile('''
 class A {
   m() {} // in A
@@ -405,14 +388,13 @@
   m() {} // in B
 }
 ''');
-    return prepareOverrides().then((_) {
-      assertHasOverride('m() {} // in B');
-      assertHasSuperElement('m() {} // in A');
-      assertNoInterfaceMembers();
-    });
+    await prepareOverrides();
+    assertHasOverride('m() {} // in B');
+    assertHasSuperElement('m() {} // in A');
+    assertNoInterfaceMembers();
   }
 
-  test_super_method_indirect() {
+  test_super_method_indirect() async {
     addTestFile('''
 class A {
   m() {} // in A
@@ -423,14 +405,13 @@
   m() {} // in C
 }
 ''');
-    return prepareOverrides().then((_) {
-      assertHasOverride('m() {} // in C');
-      assertHasSuperElement('m() {} // in A');
-      assertNoInterfaceMembers();
-    });
+    await prepareOverrides();
+    assertHasOverride('m() {} // in C');
+    assertHasSuperElement('m() {} // in A');
+    assertNoInterfaceMembers();
   }
 
-  test_super_method_superTypeCycle() {
+  test_super_method_superTypeCycle() async {
     addTestFile('''
 class A extends B {
   m() {} // in A
@@ -439,12 +420,11 @@
   m() {} // in B
 }
 ''');
-    return prepareOverrides().then((_) {
-      // must finish
-    });
+    await prepareOverrides();
+    // must finish
   }
 
-  test_super_setterBySetter() {
+  test_super_setterBySetter() async {
     addTestFile('''
 class A {
   set fff(x) {} // in A
@@ -453,10 +433,9 @@
   set fff(x) {} // in B
 }
 ''');
-    return prepareOverrides().then((_) {
-      assertHasOverride('fff(x) {} // in B');
-      assertHasSuperElement('fff(x) {} // in A');
-      assertNoInterfaceMembers();
-    });
+    await prepareOverrides();
+    assertHasOverride('fff(x) {} // in B');
+    assertHasSuperElement('fff(x) {} // in A');
+    assertNoInterfaceMembers();
   }
 }
diff --git a/pkg/analysis_server/test/analysis/reanalyze_test.dart b/pkg/analysis_server/test/analysis/reanalyze_test.dart
index 310e6d7..0b39e88 100644
--- a/pkg/analysis_server/test/analysis/reanalyze_test.dart
+++ b/pkg/analysis_server/test/analysis/reanalyze_test.dart
@@ -44,31 +44,32 @@
     expect(newContext, isNot(same(oldContext)));
   }
 
-  test_reanalyze_with_overlay() {
+  test_reanalyze_with_overlay() async {
     createProject();
     resourceProvider.newFolder(testFolder);
     resourceProvider.newFile(testFile, 'main() {}');
-    return waitForTasksFinished().then((_) {
-      // Update the content with an overlay that contains a syntax error.
-      server.updateContent('1', {testFile: new AddContentOverlay('main() {')});
-      return waitForTasksFinished();
-    }).then((_) {
-      // Verify that the syntax error was detected.
+    await waitForTasksFinished();
+    // Update the content with an overlay that contains a syntax error.
+    server.updateContent('1', {testFile: new AddContentOverlay('main() {')});
+    await waitForTasksFinished();
+    // Verify that the syntax error was detected.
+    {
       List<AnalysisError> errors = filesErrors[testFile];
       expect(errors, hasLength(1));
-      // Remove testFile from filesErrors so that we'll notice when the file is
-      // re-analyzed.
-      filesErrors.remove(testFile);
-      // Reanalyze.
-      server.reanalyze(null);
-      return waitForTasksFinished();
-    }).then((_) {
-      // The file should have been reanalyzed.
-      expect(filesErrors, contains(testFile));
-      // Verify that the syntax error is present (this indicates that the
-      // content introduced by the call to updateContent is still in effect).
+    }
+    // Remove testFile from filesErrors so that we'll notice when the file is
+    // re-analyzed.
+    filesErrors.remove(testFile);
+    // Reanalyze.
+    server.reanalyze(null);
+    await waitForTasksFinished();
+    // The file should have been reanalyzed.
+    expect(filesErrors, contains(testFile));
+    // Verify that the syntax error is present (this indicates that the
+    // content introduced by the call to updateContent is still in effect).
+    {
       List<AnalysisError> errors = filesErrors[testFile];
       expect(errors, hasLength(1));
-    });
+    }
   }
 }
diff --git a/pkg/analysis_server/test/analysis/set_priority_files_test.dart b/pkg/analysis_server/test/analysis/set_priority_files_test.dart
index 770a036..f89ba30 100644
--- a/pkg/analysis_server/test/analysis/set_priority_files_test.dart
+++ b/pkg/analysis_server/test/analysis/set_priority_files_test.dart
@@ -72,6 +72,58 @@
     expect(response.error.code, RequestErrorCode.UNANALYZED_PRIORITY_FILES);
   }
 
+  test_ignoredInAnalysisOptions() async {
+    String sampleFile = '$projectPath/samples/sample.dart';
+    addFile(
+        '$projectPath/.analysis_options',
+        r'''
+analyzer:
+  exclude:
+    - 'samples/**'
+''');
+    addFile(sampleFile, '');
+    // attempt to set priority file
+    Response response = await _setPriorityFile(sampleFile);
+    expect(response.error, isNotNull);
+    expect(response.error.code, RequestErrorCode.UNANALYZED_PRIORITY_FILES);
+  }
+
+  test_ignoredInAnalysisOptions_inChildContext() async {
+    addFile('$projectPath/.packages', '');
+    addFile('$projectPath/child/.packages', '');
+    String sampleFile = '$projectPath/child/samples/sample.dart';
+    addFile(
+        '$projectPath/child/.analysis_options',
+        r'''
+analyzer:
+  exclude:
+    - 'samples/**'
+''');
+    addFile(sampleFile, '');
+    // attempt to set priority file
+    Response response = await _setPriorityFile(sampleFile);
+    expect(response.error, isNotNull);
+    expect(response.error.code, RequestErrorCode.UNANALYZED_PRIORITY_FILES);
+  }
+
+  test_ignoredInAnalysisOptions_inRootContext() async {
+    addFile('$projectPath/.packages', '');
+    addFile('$projectPath/child/.packages', '');
+    String sampleFile = '$projectPath/child/samples/sample.dart';
+    addFile(
+        '$projectPath/.analysis_options',
+        r'''
+analyzer:
+  exclude:
+    - 'child/samples/**'
+''');
+    addFile(sampleFile, '');
+    // attempt to set priority file
+    Response response = await _setPriorityFile(sampleFile);
+    expect(response.error, isNotNull);
+    expect(response.error.code, RequestErrorCode.UNANALYZED_PRIORITY_FILES);
+  }
+
   _setPriorityFile(String file) async {
     Request request =
         new AnalysisSetPriorityFilesParams(<String>[file]).toRequest('0');
diff --git a/pkg/analysis_server/test/analysis_abstract.dart b/pkg/analysis_server/test/analysis_abstract.dart
index c367665..de27610 100644
--- a/pkg/analysis_server/test/analysis_abstract.dart
+++ b/pkg/analysis_server/test/analysis_abstract.dart
@@ -12,6 +12,7 @@
 import 'package:analysis_server/src/domain_analysis.dart';
 import 'package:analysis_server/src/plugin/linter_plugin.dart';
 import 'package:analysis_server/src/plugin/server_plugin.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_plugin.dart';
 import 'package:analysis_server/src/services/index/index.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
@@ -101,7 +102,8 @@
     List<Plugin> plugins = <Plugin>[
       serverPlugin,
       linterPlugin,
-      linterServerPlugin
+      linterServerPlugin,
+      dartCompletionPlugin,
     ];
     // Accessing `taskManager` ensures that AE plugins are registered.
     AnalysisEngine.instance.taskManager;
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index 5275d3a..58179eb 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -323,7 +323,7 @@
       subscriptions[service] = <String>[bar.path].toSet();
     }
     server.setAnalysisSubscriptions(subscriptions);
-    await pumpEventQueue(500);
+    await pumpEventQueue(1000);
     expect(server.statusAnalyzing, isFalse);
     channel.notificationsReceived.clear();
     server.updateContent(
@@ -456,6 +456,27 @@
     });
   }
 
+  test_setAnalysisSubscriptions_fileInIgnoredFolder() async {
+    String path = '/project/samples/sample.dart';
+    resourceProvider.newFile(path, '');
+    resourceProvider.newFile(
+        '/project/.analysis_options',
+        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);
+  }
+
   Future test_shutdown() {
     server.handlers = [new ServerDomainHandler(server)];
     var request = new Request('my28', SERVER_SHUTDOWN);
diff --git a/pkg/analysis_server/test/completion_test.dart b/pkg/analysis_server/test/completion_test.dart
index 7fc8d23..0d5ea53 100644
--- a/pkg/analysis_server/test/completion_test.dart
+++ b/pkg/analysis_server/test/completion_test.dart
@@ -1121,9 +1121,8 @@
     buildTests(
         'testCompletion_combinator_afterComma',
         '''
-"import 'dart:math' show cos, !1;''',
-        <String>["1+PI", "1+sin", "1+Random", "1-String"],
-        failingTests: '1');
+import 'dart:math' show cos, !1;''',
+        <String>["1+PI", "1+sin", "1+Random", "1-String"]);
 
     buildTests(
         'testCompletion_combinator_ended',
@@ -2119,7 +2118,7 @@
     sources.clear();
     sources["/lib.dart"] = '''
 library lib
-class _A 
+class _A
   foo() {}
 
 class A extends _A {
@@ -2851,7 +2850,7 @@
 
     // test analysis of untyped fields and top-level vars
     buildTests('test035', '''class Y {final x='hi';mth() {x.!1length;}}''',
-        <String>["1+length"], failingTests: '1');
+        <String>["1+length"]);
 
     // TODO(scheglov) decide what to do with Type for untyped field (not
     // supported by the new store)
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index dd3961c..9f51368 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -93,6 +93,51 @@
     resourceProvider.newFolder(projPath);
   }
 
+  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.
+  }
+
+  void test_contextsInAnalysisRoot_nestedContext() {
+    String subProjPath = posix.join(projPath, 'subproj');
+    Folder subProjFolder = resourceProvider.newFolder(subProjPath);
+    resourceProvider.newFile(
+        posix.join(subProjPath, 'pubspec.yaml'), 'contents');
+    String subProjFilePath = posix.join(subProjPath, 'file.dart');
+    resourceProvider.newFile(subProjFilePath, 'contents');
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+    // Make sure that there really are contexts for both the main project and
+    // the subproject.
+    Folder projFolder = resourceProvider.getFolder(projPath);
+    ContextInfo projContextInfo = manager.getContextInfoFor(projFolder);
+    expect(projContextInfo, isNotNull);
+    expect(projContextInfo.folder, projFolder);
+    ContextInfo subProjContextInfo = manager.getContextInfoFor(subProjFolder);
+    expect(subProjContextInfo, isNotNull);
+    expect(subProjContextInfo.folder, subProjFolder);
+    expect(projContextInfo.context != subProjContextInfo.context, isTrue);
+    // Check that contextsInAnalysisRoot() works.
+    List<AnalysisContext> contexts = manager.contextsInAnalysisRoot(projFolder);
+    expect(contexts, hasLength(2));
+    expect(contexts, contains(projContextInfo.context));
+    expect(contexts, contains(subProjContextInfo.context));
+  }
+
   test_embedder_options() async {
     // Create files.
     String libPath = newFolder([projPath, LIB_NAME]);
@@ -167,51 +212,6 @@
     expect(source.fullName, '/my/proj/sdk_ext/entry.dart');
   }
 
-  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.
-  }
-
-  void test_contextsInAnalysisRoot_nestedContext() {
-    String subProjPath = posix.join(projPath, 'subproj');
-    Folder subProjFolder = resourceProvider.newFolder(subProjPath);
-    resourceProvider.newFile(
-        posix.join(subProjPath, 'pubspec.yaml'), 'contents');
-    String subProjFilePath = posix.join(subProjPath, 'file.dart');
-    resourceProvider.newFile(subProjFilePath, 'contents');
-    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-    // Make sure that there really are contexts for both the main project and
-    // the subproject.
-    Folder projFolder = resourceProvider.getFolder(projPath);
-    ContextInfo projContextInfo = manager.getContextInfoFor(projFolder);
-    expect(projContextInfo, isNotNull);
-    expect(projContextInfo.folder, projFolder);
-    ContextInfo subProjContextInfo = manager.getContextInfoFor(subProjFolder);
-    expect(subProjContextInfo, isNotNull);
-    expect(subProjContextInfo.folder, subProjFolder);
-    expect(projContextInfo.context != subProjContextInfo.context, isTrue);
-    // Check that contextsInAnalysisRoot() works.
-    List<AnalysisContext> contexts = manager.contextsInAnalysisRoot(projFolder);
-    expect(contexts, hasLength(2));
-    expect(contexts, contains(projContextInfo.context));
-    expect(contexts, contains(subProjContextInfo.context));
-  }
-
   test_embedder_packagespec() async {
     // Create files.
     String libPath = newFolder([projPath, LIB_NAME]);
@@ -1143,6 +1143,158 @@
     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';
+    String example = '$project/example';
+    String examplePubspec = '$example/pubspec.yaml';
+    // create files
+    resourceProvider.newFile(projectPubspec, 'name: project');
+    resourceProvider.newFile(examplePubspec, 'name: example');
+    manager.setRoots(
+        <String>[example, project], <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_includedByOuter_outerPubspec() {
+    String project = '/project';
+    String projectPubspec = '$project/pubspec.yaml';
+    String example = '$project/example';
+    // create files
+    resourceProvider.newFile(projectPubspec, 'name: project');
+    resourceProvider.newFolder(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, isEmpty);
+      }
+    }
+    expect(callbacks.currentContextPaths, hasLength(1));
+    expect(callbacks.currentContextPaths, unorderedEquals([project]));
+  }
+
+  void test_setRoots_nested_includedByOuter_twoPubspecs() {
+    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');
+    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_newFolderWithPackageRoot() {
     String packageRootPath = '/package';
     manager.setRoots(<String>[projPath], <String>[],
diff --git a/pkg/analysis_server/test/domain_analysis_test.dart b/pkg/analysis_server/test/domain_analysis_test.dart
index 640d2fd..2c6fc7b 100644
--- a/pkg/analysis_server/test/domain_analysis_test.dart
+++ b/pkg/analysis_server/test/domain_analysis_test.dart
@@ -55,6 +55,46 @@
   group('updateContent', testUpdateContent);
 
   group('AnalysisDomainHandler', () {
+    group('getReachableSources', () {
+      test('valid sources', () async {
+        String fileA = '/project/a.dart';
+        String fileB = '/project/b.dart';
+        resourceProvider.newFile(fileA, 'import "b.dart";');
+        resourceProvider.newFile(fileB, '');
+
+        server.setAnalysisRoots('0', ['/project/'], [], {});
+
+        await server.onAnalysisComplete;
+
+        var request =
+            new AnalysisGetReachableSourcesParams(fileA).toRequest('0');
+        var response = handler.handleRequest(request);
+
+        var json = response.toJson()[Response.RESULT];
+
+        // Sanity checks.
+        expect(json['sources'], hasLength(6));
+        expect(json['sources']['file:///project/a.dart'],
+            unorderedEquals(['dart:core', 'file:///project/b.dart']));
+        expect(json['sources']['file:///project/b.dart'], ['dart:core']);
+      });
+
+      test('invalid source', () async {
+        resourceProvider.newFile('/project/a.dart', 'import "b.dart";');
+        server.setAnalysisRoots('0', ['/project/'], [], {});
+
+        await server.onAnalysisComplete;
+
+        var request =
+            new AnalysisGetReachableSourcesParams('/does/not/exist.dart')
+                .toRequest('0');
+        var response = handler.handleRequest(request);
+        expect(response.error, isNotNull);
+        expect(response.error.code,
+            RequestErrorCode.GET_REACHABLE_SOURCES_INVALID_FILE);
+      });
+    });
+
     group('setAnalysisRoots', () {
       Response testSetAnalysisRoots(
           List<String> included, List<String> excluded) {
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 6c4b295..888b7cc 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -16,10 +16,8 @@
 import 'package:analysis_server/src/plugin/server_plugin.dart';
 import 'package:analysis_server/src/provisional/completion/completion_core.dart'
     show AnalysisRequest, CompletionRequest, CompletionResult;
-import 'package:analysis_server/src/provisional/completion/completion_dart.dart'
-    as newApi;
 import 'package:analysis_server/src/services/completion/completion_manager.dart';
-import 'package:analysis_server/src/services/completion/contribution_sorter.dart';
+import 'package:analysis_server/src/services/completion/dart/contribution_sorter.dart';
 import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
 import 'package:analysis_server/src/services/index/index.dart' show Index;
 import 'package:analysis_server/src/services/index/local_memory_index.dart';
@@ -30,9 +28,6 @@
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/task/dart.dart';
-import 'package:analyzer/task/dart.dart';
-import 'package:analyzer/task/model.dart';
 import 'package:plugin/manager.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 import 'package:unittest/unittest.dart';
@@ -363,6 +358,8 @@
         expect(suggestionsDone, isNotNull);
         suggestions = params.results;
       }
+    } else if (notification.event == SERVER_ERROR) {
+      fail('server error: ${notification.toJson()}');
     }
   }
 
@@ -620,28 +617,6 @@
     });
   }
 
-  test_relevancy_sorter_analysis() {
-    var originalSorter = DartCompletionManager.defaultContributionSorter;
-
-    // Setup the mock sorter to request additional analysis
-    var mockSorter = new MockRelevancySorter();
-    mockSorter.addTask(PARSED_UNIT);
-    mockSorter.addTask(LIBRARY_ELEMENT1);
-    mockSorter.addTask(RESOLVED_UNIT3);
-    mockSorter.addTask(RESOLVED_UNIT3);
-
-    DartCompletionManager.defaultContributionSorter = mockSorter;
-    addTestFile('main() {Map m; m.^}');
-
-    return getSuggestions().then((_) {
-      DartCompletionManager.defaultContributionSorter = originalSorter;
-      mockSorter.enabled = false;
-
-      // Assert that the analysis requests were processed
-      mockSorter.assertAnalysisRequestsProcessed();
-    });
-  }
-
   test_simple() {
     addTestFile('''
       void main() {
@@ -747,38 +722,16 @@
   noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 }
 
-class MockRelevancySorter implements ContributionSorter {
+class MockRelevancySorter implements DartContributionSorter {
   bool enabled = true;
-  List<ResultDescriptor> descriptors = <ResultDescriptor>[];
-
-  void addTask(ResultDescriptor descriptor) {
-    descriptors.add(descriptor);
-  }
-
-  void assertAnalysisRequestsProcessed() {
-    expect(descriptors, hasLength(0));
-  }
 
   @override
-  AnalysisRequest sort(
+  Future sort(
       CompletionRequest request, Iterable<CompletionSuggestion> suggestions) {
     if (!enabled) {
       throw 'unexpected sort';
     }
-    return _nextAnalysisRequest(request);
-  }
-
-  AnalysisRequest _callback(CompletionRequest request, var value) {
-    expect(value, isNotNull);
-    return _nextAnalysisRequest(request);
-  }
-
-  AnalysisRequest _nextAnalysisRequest(CompletionRequest request) {
-    if (descriptors.length == 0) {
-      return null;
-    }
-    return new AnalysisRequest(
-        request.source, descriptors.removeAt(0), _callback);
+    return new Future.value();
   }
 }
 
@@ -872,7 +825,7 @@
   }
 
   CompletionManager createCompletionManager(
-      AnalysisContext context, Source source, SearchEngine searchEngine) {
+      AnalysisServer server, AnalysisContext context, Source source) {
     return new MockCompletionManager(mockContext, source, searchEngine);
   }
 }
diff --git a/pkg/analysis_server/test/domain_diagnostic_test.dart b/pkg/analysis_server/test/domain_diagnostic_test.dart
index fdb336e..444e6cf 100644
--- a/pkg/analysis_server/test/domain_diagnostic_test.dart
+++ b/pkg/analysis_server/test/domain_diagnostic_test.dart
@@ -42,6 +42,10 @@
     handler = new DiagnosticDomainHandler(server);
   });
 
+  tearDown(() {
+    handler.sampler?.stop();
+  });
+
   group('DiagnosticDomainHandler', () {
     test('getDiagnostics', () async {
       String file = '/project/bin/test.dart';
@@ -64,6 +68,7 @@
       expect(context['explicitFileCount'], fileCount);
       expect(context['implicitFileCount'], 0);
       expect(context['workItemQueueLength'], isNotNull);
+      expect(context['workItemQueueLengthAverage'], isNotNull);
     });
 
     test('getDiagnostics - (no root)', () async {
diff --git a/pkg/analysis_server/test/edit/assists_test.dart b/pkg/analysis_server/test/edit/assists_test.dart
index b6572c4..538a04e 100644
--- a/pkg/analysis_server/test/edit/assists_test.dart
+++ b/pkg/analysis_server/test/edit/assists_test.dart
@@ -4,8 +4,6 @@
 
 library test.edit.assists;
 
-import 'dart:async';
-
 import 'package:analysis_server/plugin/protocol/protocol.dart';
 import 'package:analysis_server/src/edit/edit_domain.dart';
 import 'package:plugin/manager.dart';
@@ -24,15 +22,15 @@
 class AssistsTest extends AbstractAnalysisTest {
   List<SourceChange> changes;
 
-  void prepareAssists(String search, [int length = 0]) {
+  prepareAssists(String search, [int length = 0]) async {
     int offset = findOffset(search);
-    prepareAssistsAt(offset, length);
+    await prepareAssistsAt(offset, length);
   }
 
-  void prepareAssistsAt(int offset, int length) {
+  prepareAssistsAt(int offset, int length) async {
     Request request =
         new EditGetAssistsParams(testFile, offset, length).toRequest('0');
-    Response response = handleSuccessfulRequest(request);
+    Response response = await waitResponse(request);
     var result = new EditGetAssistsResult.fromResponse(response);
     changes = result.assists;
   }
@@ -46,14 +44,14 @@
     handler = new EditDomainHandler(server);
   }
 
-  Future test_removeTypeAnnotation() async {
+  test_removeTypeAnnotation() async {
     addTestFile('''
 main() {
   int v = 1;
 }
 ''');
     await waitForTasksFinished();
-    prepareAssists('v =');
+    await prepareAssists('v =');
     _assertHasChange(
         'Remove type annotation',
         '''
@@ -63,14 +61,14 @@
 ''');
   }
 
-  Future test_splitVariableDeclaration() async {
+  test_splitVariableDeclaration() async {
     addTestFile('''
 main() {
   int v = 1;
 }
 ''');
     await waitForTasksFinished();
-    prepareAssists('v =');
+    await prepareAssists('v =');
     _assertHasChange(
         'Split variable declaration',
         '''
@@ -81,7 +79,7 @@
 ''');
   }
 
-  Future test_surroundWithIf() async {
+  test_surroundWithIf() async {
     addTestFile('''
 main() {
   print(1);
@@ -91,7 +89,7 @@
     await waitForTasksFinished();
     int offset = findOffset('  print(1)');
     int length = findOffset('}') - offset;
-    prepareAssistsAt(offset, length);
+    await prepareAssistsAt(offset, length);
     _assertHasChange(
         "Surround with 'if'",
         '''
diff --git a/pkg/analysis_server/test/edit/fixes_test.dart b/pkg/analysis_server/test/edit/fixes_test.dart
index 531bf43..fb2ee76 100644
--- a/pkg/analysis_server/test/edit/fixes_test.dart
+++ b/pkg/analysis_server/test/edit/fixes_test.dart
@@ -33,14 +33,14 @@
     handler = new EditDomainHandler(server);
   }
 
-  Future test_fixUndefinedClass() async {
+  test_fixUndefinedClass() async {
     addTestFile('''
 main() {
   Future<String> x = null;
 }
 ''');
     await waitForTasksFinished();
-    List<AnalysisErrorFixes> errorFixes = _getFixesAt('Future<String>');
+    List<AnalysisErrorFixes> errorFixes = await _getFixesAt('Future<String>');
     expect(errorFixes, hasLength(1));
     AnalysisError error = errorFixes[0].error;
     expect(error.severity, AnalysisErrorSeverity.WARNING);
@@ -51,7 +51,7 @@
     expect(fixes[1].message, matches('Create class'));
   }
 
-  Future test_hasFixes() async {
+  test_hasFixes() async {
     addTestFile('''
 foo() {
   print(1)
@@ -63,20 +63,20 @@
     await waitForTasksFinished();
     // print(1)
     {
-      List<AnalysisErrorFixes> errorFixes = _getFixesAt('print(1)');
+      List<AnalysisErrorFixes> errorFixes = await _getFixesAt('print(1)');
       expect(errorFixes, hasLength(1));
       _isSyntacticErrorWithSingleFix(errorFixes[0]);
     }
     // print(10)
     {
-      List<AnalysisErrorFixes> errorFixes = _getFixesAt('print(10)');
+      List<AnalysisErrorFixes> errorFixes = await _getFixesAt('print(10)');
       expect(errorFixes, hasLength(2));
       _isSyntacticErrorWithSingleFix(errorFixes[0]);
       _isSyntacticErrorWithSingleFix(errorFixes[1]);
     }
   }
 
-  Future test_overlayOnlyFile() async {
+  test_overlayOnlyFile() async {
     // add an overlay-only file
     {
       testCode = '''
@@ -92,21 +92,21 @@
     }
     // ask for fixes
     await waitForTasksFinished();
-    List<AnalysisErrorFixes> errorFixes = _getFixesAt('print(1)');
+    List<AnalysisErrorFixes> errorFixes = await _getFixesAt('print(1)');
     expect(errorFixes, hasLength(1));
     _isSyntacticErrorWithSingleFix(errorFixes[0]);
   }
 
-  List<AnalysisErrorFixes> _getFixes(int offset) {
+  Future<List<AnalysisErrorFixes>> _getFixes(int offset) async {
     Request request = new EditGetFixesParams(testFile, offset).toRequest('0');
-    Response response = handleSuccessfulRequest(request);
+    Response response = await waitResponse(request);
     var result = new EditGetFixesResult.fromResponse(response);
     return result.fixes;
   }
 
-  List<AnalysisErrorFixes> _getFixesAt(String search) {
+  Future<List<AnalysisErrorFixes>> _getFixesAt(String search) async {
     int offset = findOffset(search);
-    return _getFixes(offset);
+    return await _getFixes(offset);
   }
 
   void _isSyntacticErrorWithSingleFix(AnalysisErrorFixes fixes) {
diff --git a/pkg/analysis_server/test/integration/integration_test_methods.dart b/pkg/analysis_server/test/integration/integration_test_methods.dart
index 24933ef..af165f2 100644
--- a/pkg/analysis_server/test/integration/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/integration_test_methods.dart
@@ -238,6 +238,41 @@
   }
 
   /**
+   * Return the transitive closure of reachable sources for a given file.
+   *
+   * If a request is made for a file which does not exist, or which is not
+   * currently subject to analysis (e.g. because it is not associated with any
+   * analysis root specified to analysis.setAnalysisRoots), an error of type
+   * GET_REACHABLE_SOURCES_INVALID_FILE will be generated.
+   *
+   * Parameters
+   *
+   * file ( FilePath )
+   *
+   *   The file for which reachable source information is being requested.
+   *
+   * Returns
+   *
+   * sources ( Map<String, List<String>> )
+   *
+   *   A mapping from source URIs to directly reachable source URIs. For
+   *   example, a file "foo.dart" that imports "bar.dart" would have the
+   *   corresponding mapping { "file:///foo.dart" : ["file:///bar.dart"] }. If
+   *   "bar.dart" has further imports (or exports) there will be a mapping from
+   *   the URI "file:///bar.dart" to them. To check if a specific URI is
+   *   reachable from a given file, clients can check for its presence in the
+   *   resulting key set.
+   */
+  Future<AnalysisGetReachableSourcesResult> sendAnalysisGetReachableSources(String file) {
+    var params = new AnalysisGetReachableSourcesParams(file).toJson();
+    return server.send("analysis.getReachableSources", params)
+        .then((result) {
+      ResponseDecoder decoder = new ResponseDecoder(null);
+      return new AnalysisGetReachableSourcesResult.fromJson(decoder, 'result', result);
+    });
+  }
+
+  /**
    * Return library dependency information for use in client-side indexing and
    * package URI resolution.
    *
diff --git a/pkg/analysis_server/test/integration/protocol_matchers.dart b/pkg/analysis_server/test/integration/protocol_matchers.dart
index 6663f98..2a0cd06 100644
--- a/pkg/analysis_server/test/integration/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/protocol_matchers.dart
@@ -153,6 +153,30 @@
   }));
 
 /**
+ * analysis.getReachableSources params
+ *
+ * {
+ *   "file": FilePath
+ * }
+ */
+final Matcher isAnalysisGetReachableSourcesParams = new LazyMatcher(() => new MatchesJsonObject(
+  "analysis.getReachableSources params", {
+    "file": isFilePath
+  }));
+
+/**
+ * analysis.getReachableSources result
+ *
+ * {
+ *   "sources": Map<String, List<String>>
+ * }
+ */
+final Matcher isAnalysisGetReachableSourcesResult = new LazyMatcher(() => new MatchesJsonObject(
+  "analysis.getReachableSources result", {
+    "sources": isMapOf(isString, isListOf(isString))
+  }));
+
+/**
  * analysis.getLibraryDependencies params
  */
 final Matcher isAnalysisGetLibraryDependenciesParams = isNull;
@@ -1283,6 +1307,7 @@
  *   "explicitFileCount": int
  *   "implicitFileCount": int
  *   "workItemQueueLength": int
+ *   "workItemQueueLengthAverage": String
  *   "cacheEntryExceptions": List<String>
  * }
  */
@@ -1292,6 +1317,7 @@
     "explicitFileCount": isInt,
     "implicitFileCount": isInt,
     "workItemQueueLength": isInt,
+    "workItemQueueLengthAverage": isString,
     "cacheEntryExceptions": isListOf(isString)
   }));
 
@@ -2075,6 +2101,7 @@
  *   FORMAT_WITH_ERRORS
  *   GET_ERRORS_INVALID_FILE
  *   GET_NAVIGATION_INVALID_FILE
+ *   GET_REACHABLE_SOURCES_INVALID_FILE
  *   INVALID_ANALYSIS_ROOT
  *   INVALID_EXECUTION_CONTEXT
  *   INVALID_OVERLAY_CHANGE
@@ -2100,6 +2127,7 @@
   "FORMAT_WITH_ERRORS",
   "GET_ERRORS_INVALID_FILE",
   "GET_NAVIGATION_INVALID_FILE",
+  "GET_REACHABLE_SOURCES_INVALID_FILE",
   "INVALID_ANALYSIS_ROOT",
   "INVALID_EXECUTION_CONTEXT",
   "INVALID_OVERLAY_CHANGE",
diff --git a/pkg/analysis_server/test/services/completion/combinator_contributor_test.dart b/pkg/analysis_server/test/services/completion/combinator_contributor_test.dart
deleted file mode 100644
index f0698a0..0000000
--- a/pkg/analysis_server/test/services/completion/combinator_contributor_test.dart
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library test.services.completion.dart.combinator;
-
-import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/services/completion/combinator_contributor.dart';
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-import '../../utils.dart';
-import 'completion_test_util.dart';
-
-main() {
-  initializeTestEnvironment();
-  defineReflectiveTests(CombinatorContributorTest);
-}
-
-@reflectiveTest
-class CombinatorContributorTest extends AbstractCompletionTest {
-  @override
-  void setUpContributor() {
-    contributor = new CombinatorContributor();
-  }
-
-  test_Block_inherited_local() {
-    // Block  BlockFunctionBody  MethodDeclaration  ClassDeclaration
-    addTestSource('''
-      class F { var f1; f2() { } }
-      class E extends F { var e1; e2() { } }
-      class I { int i1; i2() { } }
-      class M { var m1; int m2() { } }
-      class A extends E implements I with M {a() {^}}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertNoSuggestions();
-    });
-  }
-
-  test_Combinator_hide() {
-    // SimpleIdentifier  HideCombinator  ImportDirective
-    addSource(
-        '/testAB.dart',
-        '''
-      library libAB;
-      part '/partAB.dart';
-      class A { }
-      class B { }''');
-    addSource(
-        '/partAB.dart',
-        '''
-      part of libAB;
-      var T1;
-      PB F1() => new PB();
-      class PB { }''');
-    addSource(
-        '/testCD.dart',
-        '''
-      class C { }
-      class D { }''');
-    addTestSource('''
-      import "/testAB.dart" hide ^;
-      import "/testCD.dart";
-      class X {}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestClass('A',
-          relevance: DART_RELEVANCE_DEFAULT,
-          kind: CompletionSuggestionKind.IDENTIFIER);
-      assertSuggestClass('B',
-          relevance: DART_RELEVANCE_DEFAULT,
-          kind: CompletionSuggestionKind.IDENTIFIER);
-      assertSuggestClass('PB',
-          relevance: DART_RELEVANCE_DEFAULT,
-          kind: CompletionSuggestionKind.IDENTIFIER);
-      assertSuggestTopLevelVar('T1', null, DART_RELEVANCE_DEFAULT,
-          CompletionSuggestionKind.IDENTIFIER);
-      assertSuggestFunction('F1', 'PB',
-          kind: CompletionSuggestionKind.IDENTIFIER);
-      assertNotSuggested('C');
-      assertNotSuggested('D');
-      assertNotSuggested('X');
-      assertNotSuggested('Object');
-    });
-  }
-
-  test_Combinator_show() {
-    // SimpleIdentifier  HideCombinator  ImportDirective
-    addSource(
-        '/testAB.dart',
-        '''
-      library libAB;
-      part '/partAB.dart';
-      class A { }
-      class B { }''');
-    addSource(
-        '/partAB.dart',
-        '''
-      part of libAB;
-      var T1;
-      PB F1() => new PB();
-      typedef PB2 F2(int blat);
-      class Clz = Object with Object;
-      class PB { }''');
-    addSource(
-        '/testCD.dart',
-        '''
-      class C { }
-      class D { }''');
-    addTestSource('''
-      import "/testAB.dart" show ^;
-      import "/testCD.dart";
-      class X {}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestClass('A',
-          relevance: DART_RELEVANCE_DEFAULT,
-          kind: CompletionSuggestionKind.IDENTIFIER);
-      assertSuggestClass('B',
-          relevance: DART_RELEVANCE_DEFAULT,
-          kind: CompletionSuggestionKind.IDENTIFIER);
-      assertSuggestClass('PB',
-          relevance: DART_RELEVANCE_DEFAULT,
-          kind: CompletionSuggestionKind.IDENTIFIER);
-      assertSuggestTopLevelVar('T1', null, DART_RELEVANCE_DEFAULT,
-          CompletionSuggestionKind.IDENTIFIER);
-      assertSuggestFunction('F1', 'PB',
-          kind: CompletionSuggestionKind.IDENTIFIER);
-      assertSuggestClass('Clz',
-          relevance: DART_RELEVANCE_DEFAULT,
-          kind: CompletionSuggestionKind.IDENTIFIER);
-      assertSuggestFunctionTypeAlias('F2', null, false, DART_RELEVANCE_DEFAULT,
-          CompletionSuggestionKind.IDENTIFIER);
-      assertNotSuggested('C');
-      assertNotSuggested('D');
-      assertNotSuggested('X');
-      assertNotSuggested('Object');
-    });
-  }
-}
diff --git a/pkg/analysis_server/test/services/completion/completion_computer_test.dart b/pkg/analysis_server/test/services/completion/completion_computer_test.dart
index 21b3393..3614852 100644
--- a/pkg/analysis_server/test/services/completion/completion_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_computer_test.dart
@@ -7,9 +7,9 @@
 import 'dart:async';
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/provisional/completion/completion_core.dart'
     show CompletionRequest, CompletionResult;
+import 'package:analysis_server/src/services/completion/completion_core.dart';
 import 'package:analysis_server/src/services/completion/completion_manager.dart';
 import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
 import 'package:analysis_server/src/services/index/index.dart';
@@ -22,7 +22,6 @@
 import 'package:unittest/unittest.dart';
 
 import '../../abstract_single_unit.dart';
-import '../../operation/operation_queue_test.dart';
 import '../../utils.dart';
 
 main() {
@@ -67,7 +66,8 @@
     index = createLocalMemoryIndex();
     searchEngine = new SearchEngineImpl(index);
     source = addSource('/does/not/exist.dart', '');
-    manager = new DartCompletionManager.create(context, searchEngine, source);
+    manager =
+        new DartCompletionManager.create(context, searchEngine, source, []);
     suggestion1 = new CompletionSuggestion(CompletionSuggestionKind.INVOCATION,
         DART_RELEVANCE_DEFAULT, "suggestion1", 1, 1, false, false);
     suggestion2 = new CompletionSuggestion(CompletionSuggestionKind.IDENTIFIER,
@@ -86,9 +86,8 @@
     manager.contributors = [contributor1, contributor2];
     int count = 0;
     bool done = false;
-    AnalysisServer server = new AnalysisServerMock(searchEngine: searchEngine);
     CompletionRequest completionRequest =
-        new CompletionRequestImpl(server, context, source, 0);
+        new CompletionRequestImpl(context, provider, searchEngine, source, 0);
     manager.results(completionRequest).listen((CompletionResult r) {
       bool isLast = r is CompletionResultImpl ? r.isLast : true;
       switch (++count) {
@@ -113,7 +112,7 @@
       // There is only one notification
       expect(count, equals(1));
     });
-    return pumpEventQueue(150).then((_) {
+    return pumpEventQueue(250).then((_) {
       expect(done, isTrue);
     });
   }
@@ -124,9 +123,8 @@
     manager.contributors = [contributor1, contributor2];
     int count = 0;
     bool done = false;
-    AnalysisServer server = new AnalysisServerMock(searchEngine: searchEngine);
     CompletionRequest completionRequest =
-        new CompletionRequestImpl(server, context, source, 0);
+        new CompletionRequestImpl(context, provider, searchEngine, source, 0);
     manager.results(completionRequest).listen((CompletionResult r) {
       bool isLast = r is CompletionResultImpl ? r.isLast : true;
       switch (++count) {
diff --git a/pkg/analysis_server/test/services/completion/completion_manager_test.dart b/pkg/analysis_server/test/services/completion/completion_manager_test.dart
index eab5223..4ee538d 100644
--- a/pkg/analysis_server/test/services/completion/completion_manager_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_manager_test.dart
@@ -24,25 +24,25 @@
 
   test_dart() {
     Source source = addSource('/does/not/exist.dart', '');
-    var manager = new CompletionManager.create(context, source, null);
+    var manager = new CompletionManager.create(context, source, null, []);
     expect(manager.runtimeType, DartCompletionManager);
   }
 
   test_html() {
     Source source = addSource('/does/not/exist.html', '');
-    var manager = new CompletionManager.create(context, source, null);
+    var manager = new CompletionManager.create(context, source, null, []);
     expect(manager.runtimeType, NoOpCompletionManager);
   }
 
   test_null_context() {
     Source source = addSource('/does/not/exist.dart', '');
-    var manager = new CompletionManager.create(null, source, null);
+    var manager = new CompletionManager.create(null, source, null, []);
     expect(manager.runtimeType, NoOpCompletionManager);
   }
 
   test_other() {
     Source source = addSource('/does/not/exist.foo', '');
-    var manager = new CompletionManager.create(context, source, null);
+    var manager = new CompletionManager.create(context, source, null, []);
     expect(manager.runtimeType, NoOpCompletionManager);
   }
 }
diff --git a/pkg/analysis_server/test/services/completion/completion_test_util.dart b/pkg/analysis_server/test/services/completion/completion_test_util.dart
index a533731..29108ca 100644
--- a/pkg/analysis_server/test/services/completion/completion_test_util.dart
+++ b/pkg/analysis_server/test/services/completion/completion_test_util.dart
@@ -10,10 +10,9 @@
     show Element, ElementKind;
 import 'package:analysis_server/plugin/protocol/protocol.dart'
     hide Element, ElementKind;
-import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
-import 'package:analysis_server/src/services/completion/common_usage_computer.dart';
 import 'package:analysis_server/src/services/completion/completion_manager.dart';
+import 'package:analysis_server/src/services/completion/dart/common_usage_sorter.dart';
 import 'package:analysis_server/src/services/completion/dart_completion_cache.dart';
 import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
 import 'package:analysis_server/src/services/completion/imported_reference_contributor.dart';
@@ -28,7 +27,6 @@
 import 'package:unittest/unittest.dart';
 
 import '../../abstract_context.dart';
-import '../../operation/operation_queue_test.dart';
 
 int suggestionComparator(CompletionSuggestion s1, CompletionSuggestion s2) {
   String c1 = s1.completion.toLowerCase();
@@ -66,10 +64,8 @@
         content.substring(completionOffset + 1);
     testSource = addSource(testFile, content);
     cache = new DartCompletionCache(context, testSource);
-    AnalysisServer server = new AnalysisServerMock(
-        searchEngine: searchEngine, resourceProvider: provider);
     request = new DartCompletionRequest(
-        server, context, testSource, completionOffset, cache);
+        context, provider, searchEngine, testSource, completionOffset, cache);
   }
 
   void assertHasNoParameterInfo(CompletionSuggestion suggestion) {
@@ -441,7 +437,7 @@
   bool computeFast() {
     expect(computeFastResult, isNull);
     _completionManager = new DartCompletionManager(context, searchEngine,
-        testSource, cache, [contributor], new CommonUsageComputer({}));
+        testSource, cache, [contributor], [], new CommonUsageSorter({}));
     var result =
         _completionManager.computeFast(request, new CompletionPerformance());
     expect(request.replacementOffset, isNotNull);
diff --git a/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
similarity index 63%
rename from pkg/analysis_server/test/services/completion/arglist_contributor_test.dart
rename to pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
index 9bb8aa7..273509c 100644
--- a/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
@@ -5,13 +5,13 @@
 library test.services.completion.dart.arglist;
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/services/completion/arglist_contributor.dart';
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/arglist_contributor.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 import 'package:unittest/unittest.dart';
 
-import '../../utils.dart';
-import 'completion_test_util.dart';
+import '../../../utils.dart';
+import 'completion_contributor_util.dart';
 
 main() {
   initializeTestEnvironment();
@@ -19,9 +19,9 @@
 }
 
 @reflectiveTest
-class ArgListContributorTest extends AbstractCompletionTest {
+class ArgListContributorTest extends DartCompletionContributorTest {
   void assertNoOtherSuggestions(Iterable<CompletionSuggestion> expected) {
-    for (CompletionSuggestion suggestion in request.suggestions) {
+    for (CompletionSuggestion suggestion in suggestions) {
       if (!expected.contains(suggestion)) {
         failedCompletion('did not expect completion: '
             '${suggestion.completion}\n  $suggestion');
@@ -34,7 +34,7 @@
     CompletionSuggestionKind csKind = CompletionSuggestionKind.ARGUMENT_LIST;
     CompletionSuggestion cs = getSuggest(csKind: csKind);
     if (cs == null) {
-      failedCompletion('expected completion $csKind', request.suggestions);
+      failedCompletion('expected completion $csKind', suggestions);
     }
     assertSuggestArgumentList_params(
         paramNames, paramTypes, cs.parameterNames, cs.parameterTypes);
@@ -86,50 +86,51 @@
   }
 
   @override
-  void setUpContributor() {
-    contributor = new ArgListContributor();
+  DartCompletionContributor createContributor() {
+    return new ArgListContributor();
   }
 
-  test_Annotation_local_constructor_named_param() {
-    //
+  test_Annotation_local_constructor_named_param() async {
     addTestSource('''
 class A { A({int one, String two: 'defaultValue'}) { } }
 @A(^) main() { }''');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestArguments(namedArguments: ['one', 'two']);
-    });
+    await computeSuggestions();
+    assertSuggestArguments(namedArguments: ['one', 'two']);
   }
 
-  test_ArgumentList_getter() {
+  test_Annotation_imported_constructor_named_param() async {
+    addSource(
+        '/libA.dart',
+        '''
+library libA; class A { A({int one, String two: 'defaultValue'}) { } }''');
+    addTestSource('import "/libA.dart"; @A(^) main() { }');
+    await computeSuggestions();
+    assertSuggestArguments(namedArguments: ['one', 'two']);
+  }
+
+  test_ArgumentList_getter() async {
     addTestSource('class A {int get foo => 7; main() {foo(^)}');
-    computeFast();
-    return computeFull((bool result) {
-      assertNoSuggestions();
-    });
+    await computeSuggestions();
+    assertNoSuggestions();
   }
 
-  test_ArgumentList_imported_constructor_named_param() {
+  test_ArgumentList_imported_constructor_named_param() async {
     //
     addSource('/libA.dart', 'library libA; class A{A({int one}){}}');
     addTestSource('import "/libA.dart"; main() { new A(^);}');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestArguments(namedArguments: ['one']);
-    });
+    await computeSuggestions();
+    assertSuggestArguments(namedArguments: ['one']);
   }
 
-  test_ArgumentList_imported_constructor_named_param2() {
+  test_ArgumentList_imported_constructor_named_param2() async {
     //
     addSource('/libA.dart', 'library libA; class A{A.foo({int one}){}}');
     addTestSource('import "/libA.dart"; main() { new A.foo(^);}');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestArguments(namedArguments: ['one']);
-    });
+    await computeSuggestions();
+    assertSuggestArguments(namedArguments: ['one']);
   }
 
-  test_ArgumentList_imported_function_0() {
+  test_ArgumentList_imported_function_0() async {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addSource(
         '/libA.dart',
@@ -143,13 +144,11 @@
       class B { }
       String bar() => true;
       void main() {expect(a^)}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertNoSuggestions();
-    });
+    await computeSuggestions();
+    assertNoSuggestions();
   }
 
-  test_ArgumentList_imported_function_1() {
+  test_ArgumentList_imported_function_1() async {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addSource(
         '/libA.dart',
@@ -163,13 +162,11 @@
       class B { }
       String bar() => true;
       void main() {expect(^)}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestArgumentList(['arg'], ['String']);
-    });
+    await computeSuggestions();
+    assertSuggestArgumentList(['arg'], ['String']);
   }
 
-  test_ArgumentList_imported_function_2() {
+  test_ArgumentList_imported_function_2() async {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addSource(
         '/libA.dart',
@@ -183,13 +180,11 @@
       class B { }
       String bar() => true;
       void main() {expect(^)}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestArgumentList(['arg1', 'arg2'], ['String', 'int']);
-    });
+    await computeSuggestions();
+    assertSuggestArgumentList(['arg1', 'arg2'], ['String', 'int']);
   }
 
-  test_ArgumentList_imported_function_3() {
+  test_ArgumentList_imported_function_3() async {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addSource(
         '/libA.dart',
@@ -203,13 +198,11 @@
       class B { }
       String bar() => true;
       void main() {expect(^)}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestArgumentList(['arg1', 'arg2'], ['String', 'int']);
-    });
+    await computeSuggestions();
+    assertSuggestArgumentList(['arg1', 'arg2'], ['String', 'int']);
   }
 
-  test_ArgumentList_imported_function_3a() {
+  test_ArgumentList_imported_function_3a() async {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addSource(
         '/libA.dart',
@@ -223,13 +216,11 @@
       class B { }
       String bar() => true;
       void main() {expect('hello', ^)}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertNoSuggestions();
-    });
+    await computeSuggestions();
+    assertNoSuggestions();
   }
 
-  test_ArgumentList_imported_function_3b() {
+  test_ArgumentList_imported_function_3b() async {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addSource(
         '/libA.dart',
@@ -243,13 +234,11 @@
       class B { }
       String bar() => true;
       void main() {expect('hello', ^x)}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertNoSuggestions();
-    });
+    await computeSuggestions();
+    assertNoSuggestions();
   }
 
-  test_ArgumentList_imported_function_3c() {
+  test_ArgumentList_imported_function_3c() async {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addSource(
         '/libA.dart',
@@ -263,13 +252,11 @@
       class B { }
       String bar() => true;
       void main() {expect('hello', x^)}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertNoSuggestions();
-    });
+    await computeSuggestions();
+    assertNoSuggestions();
   }
 
-  test_ArgumentList_imported_function_3d() {
+  test_ArgumentList_imported_function_3d() async {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addSource(
         '/libA.dart',
@@ -283,71 +270,57 @@
       class B { }
       String bar() => true;
       void main() {expect('hello', x ^)}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertNoSuggestions();
-    });
+    await computeSuggestions();
+    assertNoSuggestions();
   }
 
-  test_ArgumentList_imported_function_named_param() {
+  test_ArgumentList_imported_function_named_param() async {
     //
     addTestSource('main() { int.parse("16", ^);}');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestArguments(namedArguments: ['radix', 'onError']);
-    });
+    await computeSuggestions();
+    assertSuggestArguments(namedArguments: ['radix', 'onError']);
   }
 
-  test_ArgumentList_imported_function_named_param1() {
+  test_ArgumentList_imported_function_named_param1() async {
     //
     addTestSource('main() { int.parse("16", r^);}');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestArguments(namedArguments: ['radix', 'onError']);
-    });
+    await computeSuggestions();
+    assertSuggestArguments(namedArguments: ['radix', 'onError']);
   }
 
-  test_ArgumentList_imported_function_named_param2() {
+  test_ArgumentList_imported_function_named_param2() async {
     //
     addTestSource('main() { int.parse("16", radix: 7, ^);}');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestArguments(namedArguments: ['onError']);
-    });
+    await computeSuggestions();
+    assertSuggestArguments(namedArguments: ['onError']);
   }
 
-  test_ArgumentList_imported_function_named_param2a() {
+  test_ArgumentList_imported_function_named_param2a() async {
     //
     addTestSource('main() { int.parse("16", radix: ^);}');
-    computeFast();
-    return computeFull((bool result) {
-      assertNoSuggestions();
-    });
+    await computeSuggestions();
+    assertNoSuggestions();
   }
 
-  test_ArgumentList_local_constructor_named_param() {
+  test_ArgumentList_local_constructor_named_param() async {
     //
     addTestSource('''
 class A { A({int one, String two: 'defaultValue'}) { } }
 main() { new A(^);}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestArguments(namedArguments: ['one', 'two']);
-    });
+    await computeSuggestions();
+    assertSuggestArguments(namedArguments: ['one', 'two']);
   }
 
-  test_ArgumentList_local_constructor_named_param2() {
+  test_ArgumentList_local_constructor_named_param2() async {
     //
     addTestSource('''
 class A { A.foo({int one, String two: 'defaultValue'}) { } }
 main() { new A.foo(^);}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestArguments(namedArguments: ['one', 'two']);
-    });
+    await computeSuggestions();
+    assertSuggestArguments(namedArguments: ['one', 'two']);
   }
 
-  test_ArgumentList_local_function_1() {
+  test_ArgumentList_local_function_1() async {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addTestSource('''
       import '/libA.dart'
@@ -355,13 +328,11 @@
       class B { }
       String bar() => true;
       void main() {expect(^)}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestArgumentList(['arg'], ['dynamic']);
-    });
+    await computeSuggestions();
+    assertSuggestArgumentList(['arg'], ['dynamic']);
   }
 
-  test_ArgumentList_local_function_2() {
+  test_ArgumentList_local_function_2() async {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addTestSource('''
       import '/libA.dart'
@@ -369,13 +340,11 @@
       class B { }
       String bar() => true;
       void main() {expect(^)}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestArgumentList(['arg1', 'arg2'], ['dynamic', 'int']);
-    });
+    await computeSuggestions();
+    assertSuggestArgumentList(['arg1', 'arg2'], ['dynamic', 'int']);
   }
 
-  test_ArgumentList_local_function_3() {
+  test_ArgumentList_local_function_3() async {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addTestSource('''
       import '/libA.dart'
@@ -383,13 +352,11 @@
       class B { }
       String bar() => true;
       void main() {expect(^)}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestArgumentList(['arg1', 'arg2'], ['dynamic', 'int']);
-    });
+    await computeSuggestions();
+    assertSuggestArgumentList(['arg1', 'arg2'], ['dynamic', 'int']);
   }
 
-  test_ArgumentList_local_function_3a() {
+  test_ArgumentList_local_function_3a() async {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addTestSource('''
       import '/libA.dart'
@@ -397,13 +364,11 @@
       class B { }
       String bar() => true;
       void main() {expect('hello', ^)}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertNoSuggestions();
-    });
+    await computeSuggestions();
+    assertNoSuggestions();
   }
 
-  test_ArgumentList_local_function_3b() {
+  test_ArgumentList_local_function_3b() async {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addTestSource('''
       import '/libA.dart'
@@ -411,13 +376,11 @@
       class B { }
       String bar() => true;
       void main() {expect('hello', ^x)}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertNoSuggestions();
-    });
+    await computeSuggestions();
+    assertNoSuggestions();
   }
 
-  test_ArgumentList_local_function_3c() {
+  test_ArgumentList_local_function_3c() async {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addTestSource('''
       import '/libA.dart'
@@ -425,13 +388,11 @@
       class B { }
       String bar() => true;
       void main() {expect('hello', x^)}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertNoSuggestions();
-    });
+    await computeSuggestions();
+    assertNoSuggestions();
   }
 
-  test_ArgumentList_local_function_3d() {
+  test_ArgumentList_local_function_3d() async {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addTestSource('''
       import '/libA.dart'
@@ -439,57 +400,47 @@
       class B { }
       String bar() => true;
       void main() {expect('hello', x ^)}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertNoSuggestions();
-    });
+    await computeSuggestions();
+    assertNoSuggestions();
   }
 
-  test_ArgumentList_local_function_named_param() {
+  test_ArgumentList_local_function_named_param() async {
     //
     addTestSource('''
 f(v,{int radix, int onError(String s)}){}
 main() { f("16", ^);}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestArguments(namedArguments: ['radix', 'onError']);
-    });
+    await computeSuggestions();
+    assertSuggestArguments(namedArguments: ['radix', 'onError']);
   }
 
-  test_ArgumentList_local_function_named_param1() {
+  test_ArgumentList_local_function_named_param1() async {
     //
     addTestSource('''
 f(v,{int radix, int onError(String s)}){}
 main() { f("16", r^);}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestArguments(namedArguments: ['radix', 'onError']);
-    });
+    await computeSuggestions();
+    assertSuggestArguments(namedArguments: ['radix', 'onError']);
   }
 
-  test_ArgumentList_local_function_named_param2() {
+  test_ArgumentList_local_function_named_param2() async {
     //
     addTestSource('''
 f(v,{int radix, int onError(String s)}){}
 main() { f("16", radix: 7, ^);}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestArguments(namedArguments: ['onError']);
-    });
+    await computeSuggestions();
+    assertSuggestArguments(namedArguments: ['onError']);
   }
 
-  test_ArgumentList_local_function_named_param2a() {
+  test_ArgumentList_local_function_named_param2a() async {
     //
     addTestSource('''
 f(v,{int radix, int onError(String s)}){}
 main() { f("16", radix: ^);}''');
-    computeFast();
-    return computeFull((bool result) {
-      assertNoSuggestions();
-    });
+    await computeSuggestions();
+    assertNoSuggestions();
   }
 
-  test_ArgumentList_local_method_0() {
+  test_ArgumentList_local_method_0() async {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addSource(
         '/libA.dart',
@@ -503,13 +454,11 @@
         expect() { }
         void foo() {expect(^)}}
       String bar() => true;''');
-    computeFast();
-    return computeFull((bool result) {
-      assertNoSuggestions();
-    });
+    await computeSuggestions();
+    assertNoSuggestions();
   }
 
-  test_ArgumentList_local_method_2() {
+  test_ArgumentList_local_method_2() async {
     // ArgumentList  MethodInvocation  ExpressionStatement  Block
     addSource(
         '/libA.dart',
@@ -523,9 +472,7 @@
         expect(arg, int blat) { }
         void foo() {expect(^)}}
       String bar() => true;''');
-    computeFast();
-    return computeFull((bool result) {
-      assertSuggestArgumentList(['arg', 'blat'], ['dynamic', 'int']);
-    });
+    await computeSuggestions();
+    assertSuggestArgumentList(['arg', 'blat'], ['dynamic', 'int']);
   }
 }
diff --git a/pkg/analysis_server/test/services/completion/dart/combinator_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/combinator_contributor_test.dart
new file mode 100644
index 0000000..be250e7
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/combinator_contributor_test.dart
@@ -0,0 +1,151 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.services.completion.dart.combinator;
+
+import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/combinator_contributor.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../../utils.dart';
+import 'completion_contributor_util.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+main() {
+  initializeTestEnvironment();
+  defineReflectiveTests(CombinatorContributorTest);
+}
+
+@reflectiveTest
+class CombinatorContributorTest extends DartCompletionContributorTest {
+  @override
+  DartCompletionContributor createContributor() {
+    return new CombinatorContributor();
+  }
+
+  test_Block_inherited_local() async {
+    // Block  BlockFunctionBody  MethodDeclaration  ClassDeclaration
+    addTestSource('''
+      class F { var f1; f2() { } }
+      class E extends F { var e1; e2() { } }
+      class I { int i1; i2() { } }
+      class M { var m1; int m2() { } }
+      class A extends E implements I with M {a() {^}}''');
+    await computeSuggestions();
+    assertNoSuggestions();
+  }
+
+  test_Combinator_hide() async {
+    // SimpleIdentifier  HideCombinator  ImportDirective
+    Source importedLibSource = addSource(
+        '/testAB.dart',
+        '''
+      library libAB;
+      part '/partAB.dart';
+      class A { }
+      class B { }''');
+    addSource(
+        '/partAB.dart',
+        '''
+      part of libAB;
+      var T1;
+      PB F1() => new PB();
+      class PB { }''');
+    addSource(
+        '/testCD.dart',
+        '''
+      class C { }
+      class D { }''');
+    addTestSource('''
+      import "/testAB.dart" hide ^;
+      import "/testCD.dart";
+      class X {}''');
+
+    // Assume that imported libraries have been resolved
+    context.resolveCompilationUnit2(importedLibSource, importedLibSource);
+
+    await computeSuggestions();
+    assertSuggestClass('A',
+        relevance: DART_RELEVANCE_DEFAULT,
+        kind: CompletionSuggestionKind.IDENTIFIER);
+    assertSuggestClass('B',
+        relevance: DART_RELEVANCE_DEFAULT,
+        kind: CompletionSuggestionKind.IDENTIFIER);
+    assertSuggestClass('PB',
+        relevance: DART_RELEVANCE_DEFAULT,
+        kind: CompletionSuggestionKind.IDENTIFIER);
+    assertSuggestTopLevelVar('T1', null,
+        kind: CompletionSuggestionKind.IDENTIFIER);
+    assertSuggestFunction('F1', 'PB',
+        kind: CompletionSuggestionKind.IDENTIFIER);
+    assertNotSuggested('C');
+    assertNotSuggested('D');
+    assertNotSuggested('X');
+    assertNotSuggested('Object');
+  }
+
+  test_Combinator_show() async {
+    // SimpleIdentifier  HideCombinator  ImportDirective
+    Source importedLibSource = addSource(
+        '/testAB.dart',
+        '''
+      library libAB;
+      part '/partAB.dart';
+      class A { }
+      class B { }''');
+    addSource(
+        '/partAB.dart',
+        '''
+      part of libAB;
+      var T1;
+      PB F1() => new PB();
+      typedef PB2 F2(int blat);
+      class Clz = Object with Object;
+      class PB { }''');
+    addSource(
+        '/testCD.dart',
+        '''
+      class C { }
+      class D { }''');
+    addTestSource('''
+      import "/testAB.dart" show ^;
+      import "/testCD.dart";
+      class X {}''');
+
+    // Assume that imported libraries have been resolved
+    context.resolveCompilationUnit2(importedLibSource, importedLibSource);
+
+    await computeSuggestions();
+    assertSuggestClass('A',
+        relevance: DART_RELEVANCE_DEFAULT,
+        kind: CompletionSuggestionKind.IDENTIFIER);
+    assertSuggestClass('B',
+        relevance: DART_RELEVANCE_DEFAULT,
+        kind: CompletionSuggestionKind.IDENTIFIER);
+    assertSuggestClass('PB',
+        relevance: DART_RELEVANCE_DEFAULT,
+        kind: CompletionSuggestionKind.IDENTIFIER);
+    assertSuggestTopLevelVar('T1', null,
+        kind: CompletionSuggestionKind.IDENTIFIER);
+    assertSuggestFunction('F1', 'PB',
+        kind: CompletionSuggestionKind.IDENTIFIER);
+    assertSuggestClass('Clz',
+        relevance: DART_RELEVANCE_DEFAULT,
+        kind: CompletionSuggestionKind.IDENTIFIER);
+    assertSuggestFunctionTypeAlias('F2', null, false, DART_RELEVANCE_DEFAULT,
+        CompletionSuggestionKind.IDENTIFIER);
+    assertNotSuggested('C');
+    assertNotSuggested('D');
+    assertNotSuggested('X');
+    assertNotSuggested('Object');
+  }
+
+  test_Combinator_show_PI() async {
+    addTestSource('import "dart:math" show ^;');
+    await computeSuggestions();
+    assertSuggestTopLevelVar('PI', 'double',
+        kind: CompletionSuggestionKind.IDENTIFIER);
+  }
+}
diff --git a/pkg/analysis_server/test/services/completion/common_usage_computer_test.dart b/pkg/analysis_server/test/services/completion/dart/common_usage_sorter_test.dart
similarity index 94%
rename from pkg/analysis_server/test/services/completion/common_usage_computer_test.dart
rename to pkg/analysis_server/test/services/completion/dart/common_usage_sorter_test.dart
index 8ed33f1..66b236d 100644
--- a/pkg/analysis_server/test/services/completion/common_usage_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/common_usage_sorter_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.services.completion.computer.dart.relevance;
+library test.services.completion.dart.sorter.common;
 
 import 'dart:async';
 
@@ -11,7 +11,7 @@
     show ContextSourcePair;
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/domain_completion.dart';
-import 'package:analysis_server/src/services/completion/common_usage_computer.dart';
+import 'package:analysis_server/src/services/completion/dart/common_usage_sorter.dart';
 import 'package:analysis_server/src/services/completion/dart_completion_cache.dart';
 import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
 import 'package:analysis_server/src/services/index/index.dart';
@@ -21,17 +21,17 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 import 'package:unittest/unittest.dart';
 
-import '../../analysis_abstract.dart';
-import '../../mocks.dart';
-import '../../utils.dart';
+import '../../../analysis_abstract.dart';
+import '../../../mocks.dart';
+import '../../../utils.dart';
 
 main() {
   initializeTestEnvironment();
-  defineReflectiveTests(CommonUsageComputerTest);
+  defineReflectiveTests(CommonUsageSorterTest);
 }
 
 @reflectiveTest
-class CommonUsageComputerTest extends AbstractAnalysisTest {
+class CommonUsageSorterTest extends AbstractAnalysisTest {
   String completionId;
   int completionOffset;
   int replacementOffset;
@@ -107,7 +107,8 @@
         source,
         new DartCompletionCache(context, source),
         null,
-        new CommonUsageComputer(selectorRelevance));
+        server.serverPlugin.completionContributors,
+        new CommonUsageSorter(selectorRelevance));
 
     Response response =
         domainHandler.processRequest(request, completionManager);
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
new file mode 100644
index 0000000..c08a073
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
@@ -0,0 +1,340 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.services.completion.dart.util;
+
+import 'dart:async';
+
+import 'package:analysis_server/plugin/protocol/protocol.dart' as protocol
+    show Element, ElementKind;
+import 'package:analysis_server/plugin/protocol/protocol.dart'
+    hide Element, ElementKind;
+import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/completion_core.dart';
+import 'package:analysis_server/src/services/completion/dart/completion_manager.dart'
+    show DartCompletionRequestImpl;
+import 'package:analysis_server/src/services/completion/dart_completion_manager.dart'
+    show DART_RELEVANCE_DEFAULT, DART_RELEVANCE_LOW, ReplacementRange;
+import 'package:analysis_server/src/services/index/index.dart';
+import 'package:analysis_server/src/services/index/local_memory_index.dart';
+import 'package:analysis_server/src/services/search/search_engine_internal.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../../abstract_context.dart';
+
+int suggestionComparator(CompletionSuggestion s1, CompletionSuggestion s2) {
+  String c1 = s1.completion.toLowerCase();
+  String c2 = s2.completion.toLowerCase();
+  return c1.compareTo(c2);
+}
+
+abstract class DartCompletionContributorTest extends AbstractContextTest {
+  Index index;
+  SearchEngineImpl searchEngine;
+  String testFile = '/completionTest.dart';
+  Source testSource;
+  int completionOffset;
+  int replacementOffset;
+  int replacementLength;
+  DartCompletionContributor contributor;
+  DartCompletionRequest request;
+  List<CompletionSuggestion> suggestions;
+
+  void addTestSource(String content) {
+    expect(completionOffset, isNull, reason: 'Call addTestUnit exactly once');
+    completionOffset = content.indexOf('^');
+    expect(completionOffset, isNot(equals(-1)), reason: 'missing ^');
+    int nextOffset = content.indexOf('^', completionOffset + 1);
+    expect(nextOffset, equals(-1), reason: 'too many ^');
+    content = content.substring(0, completionOffset) +
+        content.substring(completionOffset + 1);
+    testSource = addSource(testFile, content);
+  }
+
+  void assertHasNoParameterInfo(CompletionSuggestion suggestion) {
+    expect(suggestion.parameterNames, isNull);
+    expect(suggestion.parameterTypes, isNull);
+    expect(suggestion.requiredParameterCount, isNull);
+    expect(suggestion.hasNamedParameters, isNull);
+  }
+
+  void assertHasParameterInfo(CompletionSuggestion suggestion) {
+    expect(suggestion.parameterNames, isNotNull);
+    expect(suggestion.parameterTypes, isNotNull);
+    expect(suggestion.parameterNames.length, suggestion.parameterTypes.length);
+    expect(suggestion.requiredParameterCount,
+        lessThanOrEqualTo(suggestion.parameterNames.length));
+    expect(suggestion.hasNamedParameters, isNotNull);
+  }
+
+  void assertNoSuggestions({CompletionSuggestionKind kind: null}) {
+    if (kind == null) {
+      if (suggestions.length > 0) {
+        failedCompletion('Expected no suggestions', suggestions);
+      }
+      return;
+    }
+    CompletionSuggestion suggestion = suggestions.firstWhere(
+        (CompletionSuggestion cs) => cs.kind == kind,
+        orElse: () => null);
+    if (suggestion != null) {
+      failedCompletion('did not expect completion: $completion\n  $suggestion');
+    }
+  }
+
+  void assertNotSuggested(String completion) {
+    CompletionSuggestion suggestion = suggestions.firstWhere(
+        (CompletionSuggestion cs) => cs.completion == completion,
+        orElse: () => null);
+    if (suggestion != null) {
+      failedCompletion('did not expect completion: $completion\n  $suggestion');
+    }
+  }
+
+  CompletionSuggestion assertSuggest(String completion,
+      {CompletionSuggestionKind csKind: CompletionSuggestionKind.INVOCATION,
+      int relevance: DART_RELEVANCE_DEFAULT,
+      String importUri,
+      protocol.ElementKind elemKind: null,
+      bool isDeprecated: false,
+      bool isPotential: false,
+      String elemFile,
+      int elemOffset}) {
+    CompletionSuggestion cs =
+        getSuggest(completion: completion, csKind: csKind, elemKind: elemKind);
+    if (cs == null) {
+      failedCompletion('expected $completion $csKind $elemKind', suggestions);
+    }
+    expect(cs.kind, equals(csKind));
+    if (isDeprecated) {
+      expect(cs.relevance, equals(DART_RELEVANCE_LOW));
+    } else {
+      expect(cs.relevance, equals(relevance));
+    }
+    expect(cs.importUri, importUri);
+    expect(cs.selectionOffset, equals(completion.length));
+    expect(cs.selectionLength, equals(0));
+    expect(cs.isDeprecated, equals(isDeprecated));
+    expect(cs.isPotential, equals(isPotential));
+    if (cs.element != null) {
+      expect(cs.element.location, isNotNull);
+      expect(cs.element.location.file, isNotNull);
+      expect(cs.element.location.offset, isNotNull);
+      expect(cs.element.location.length, isNotNull);
+      expect(cs.element.location.startColumn, isNotNull);
+      expect(cs.element.location.startLine, isNotNull);
+    }
+    if (elemFile != null) {
+      expect(cs.element.location.file, elemFile);
+    }
+    if (elemOffset != null) {
+      expect(cs.element.location.offset, elemOffset);
+    }
+    return cs;
+  }
+
+  CompletionSuggestion assertSuggestClass(String name,
+      {int relevance: DART_RELEVANCE_DEFAULT,
+      String importUri,
+      CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
+      bool isDeprecated: false,
+      String elemFile,
+      int elemOffset}) {
+    CompletionSuggestion cs = assertSuggest(name,
+        csKind: kind,
+        relevance: relevance,
+        importUri: importUri,
+        isDeprecated: isDeprecated,
+        elemFile: elemFile,
+        elemOffset: elemOffset);
+    protocol.Element element = cs.element;
+    expect(element, isNotNull);
+    expect(element.kind, equals(protocol.ElementKind.CLASS));
+    expect(element.name, equals(name));
+    expect(element.parameters, isNull);
+    expect(element.returnType, isNull);
+    assertHasNoParameterInfo(cs);
+    return cs;
+  }
+
+  CompletionSuggestion assertSuggestFunction(String name, String returnType,
+      {CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
+      bool deprecated: false,
+      int relevance: DART_RELEVANCE_DEFAULT,
+      String importUri}) {
+    CompletionSuggestion cs = assertSuggest(name,
+        csKind: kind,
+        relevance: relevance,
+        importUri: importUri,
+        isDeprecated: deprecated);
+    expect(cs.returnType, returnType != null ? returnType : 'dynamic');
+    protocol.Element element = cs.element;
+    expect(element, isNotNull);
+    expect(element.kind, equals(protocol.ElementKind.FUNCTION));
+    expect(element.name, equals(name));
+    expect(element.isDeprecated, equals(deprecated));
+    String param = element.parameters;
+    expect(param, isNotNull);
+    expect(param[0], equals('('));
+    expect(param[param.length - 1], equals(')'));
+    expect(element.returnType,
+        equals(returnType != null ? returnType : 'dynamic'));
+    assertHasParameterInfo(cs);
+    return cs;
+  }
+
+  CompletionSuggestion assertSuggestFunctionTypeAlias(
+      String name, String returnType, bool isDeprecated,
+      [int relevance = DART_RELEVANCE_DEFAULT,
+      CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION,
+      String importUri]) {
+    CompletionSuggestion cs = assertSuggest(name,
+        csKind: kind,
+        relevance: relevance,
+        importUri: importUri,
+        isDeprecated: isDeprecated);
+    expect(cs.returnType, returnType != null ? returnType : 'dynamic');
+    protocol.Element element = cs.element;
+    expect(element, isNotNull);
+    expect(element.kind, equals(protocol.ElementKind.FUNCTION_TYPE_ALIAS));
+    expect(element.name, equals(name));
+    expect(element.isDeprecated, equals(isDeprecated));
+    // TODO (danrubel) Determine why params are null
+    //    String param = element.parameters;
+    //    expect(param, isNotNull);
+    //    expect(param[0], equals('('));
+    //    expect(param[param.length - 1], equals(')'));
+    expect(element.returnType,
+        equals(returnType != null ? returnType : 'dynamic'));
+    // TODO (danrubel) Determine why param info is missing
+    //    assertHasParameterInfo(cs);
+    return cs;
+  }
+
+  CompletionSuggestion assertSuggestTopLevelVar(String name, String returnType,
+      {int relevance: DART_RELEVANCE_DEFAULT,
+      CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
+      String importUri}) {
+    CompletionSuggestion cs = assertSuggest(name,
+        csKind: kind, relevance: relevance, importUri: importUri);
+    expect(cs.returnType, returnType != null ? returnType : 'dynamic');
+    protocol.Element element = cs.element;
+    expect(element, isNotNull);
+    expect(element.kind, equals(protocol.ElementKind.TOP_LEVEL_VARIABLE));
+    expect(element.name, equals(name));
+    expect(element.parameters, isNull);
+    expect(element.returnType, returnType != null ? returnType : 'dynamic');
+    assertHasNoParameterInfo(cs);
+    return cs;
+  }
+
+  /**
+   * Return a [Future] that completes with the containing library information
+   * after it is accessible via [context.getLibrariesContaining].
+   */
+  Future computeLibrariesContaining([int times = 200]) {
+    List<Source> libraries = context.getLibrariesContaining(testSource);
+    if (libraries.isNotEmpty) {
+      return new Future.value(libraries);
+    }
+    context.performAnalysisTask();
+    // We use a delayed future to allow microtask events to finish. The
+    // Future.value or Future() constructors use scheduleMicrotask themselves and
+    // would therefore not wait for microtask callbacks that are scheduled after
+    // invoking this method.
+    return new Future.delayed(
+        Duration.ZERO, () => computeLibrariesContaining(times - 1));
+  }
+
+  Future computeSuggestions([int times = 200]) async {
+    CompletionRequestImpl baseRequest = new CompletionRequestImpl(
+        context, provider, searchEngine, testSource, completionOffset);
+    request = new DartCompletionRequestImpl.forRequest(baseRequest);
+    var range = new ReplacementRange.compute(request.offset, request.target);
+    replacementOffset = range.offset;
+    replacementLength = range.length;
+    Completer<List<CompletionSuggestion>> completer =
+        new Completer<List<CompletionSuggestion>>();
+
+    // Request completions
+    contributor
+        .computeSuggestions(request)
+        .then((List<CompletionSuggestion> computedSuggestions) {
+      completer.complete(computedSuggestions);
+    });
+
+    // Perform analysis until the suggestions have been computed
+    // or the max analysis cycles ([times]) has been reached
+    suggestions = await performAnalysis(times, completer);
+    expect(suggestions, isNotNull, reason: 'expected suggestions');
+  }
+
+  DartCompletionContributor createContributor();
+
+  void failedCompletion(String message,
+      [Iterable<CompletionSuggestion> completions]) {
+    StringBuffer sb = new StringBuffer(message);
+    if (completions != null) {
+      sb.write('\n  found');
+      completions.toList()
+        ..sort(suggestionComparator)
+        ..forEach((CompletionSuggestion suggestion) {
+          sb.write('\n    ${suggestion.completion} -> $suggestion');
+        });
+    }
+    fail(sb.toString());
+  }
+
+  CompletionSuggestion getSuggest(
+      {String completion: null,
+      CompletionSuggestionKind csKind: null,
+      protocol.ElementKind elemKind: null}) {
+    CompletionSuggestion cs;
+    if (suggestions != null) {
+      suggestions.forEach((CompletionSuggestion s) {
+        if (completion != null && completion != s.completion) {
+          return;
+        }
+        if (csKind != null && csKind != s.kind) {
+          return;
+        }
+        if (elemKind != null) {
+          protocol.Element element = s.element;
+          if (element == null || elemKind != element.kind) {
+            return;
+          }
+        }
+        if (cs == null) {
+          cs = s;
+        } else {
+          failedCompletion('expected exactly one $cs',
+              suggestions.where((s) => s.completion == completion));
+        }
+      });
+    }
+    return cs;
+  }
+
+  Future performAnalysis(int times, Completer completer) {
+    if (completer.isCompleted) return completer.future;
+    if (times == 0 || context == null) return new Future.value();
+    context.performAnalysisTask();
+    // We use a delayed future to allow microtask events to finish. The
+    // Future.value or Future() constructors use scheduleMicrotask themselves and
+    // would therefore not wait for microtask callbacks that are scheduled after
+    // invoking this method.
+    return new Future.delayed(
+        Duration.ZERO, () => performAnalysis(times - 1, completer));
+  }
+
+  @override
+  void setUp() {
+    super.setUp();
+    index = createLocalMemoryIndex();
+    searchEngine = new SearchEngineImpl(index);
+    contributor = createContributor();
+  }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/inherited_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/inherited_contributor_test.dart
new file mode 100644
index 0000000..4ef42d3
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/inherited_contributor_test.dart
@@ -0,0 +1,121 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.services.completion.dart.inherited_computer_test;
+
+import 'package:analysis_server/plugin/protocol/protocol.dart'
+    hide Element, ElementKind;
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/inherited_contributor.dart';
+import 'package:analysis_server/src/services/completion/dart_completion_manager.dart'
+    hide DartCompletionContributor;
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart';
+
+import 'completion_contributor_util.dart';
+
+main() {
+  // Revisit this contributor and these tests
+  // once DartChangeBuilder API has solidified.
+  // initializeTestEnvironment();
+  // defineReflectiveTests(InheritedContributorTest);
+}
+
+@reflectiveTest
+class InheritedContributorTest extends DartCompletionContributorTest {
+  @override
+  DartCompletionContributor createContributor() {
+    return new InheritedContributor();
+  }
+
+  test_fromMultipleSuperclasses() async {
+    addTestSource(r'''
+class A {
+  A suggested1(int x) => null;
+  B suggested2(String y) => null;
+}
+class B extends A {
+  B suggested2(String y) => null;
+  C suggested3([String z]) => null;
+}
+class C extends B {
+  sugg^
+}
+''');
+    await computeSuggestions();
+    _assertOverride('''@override
+  A suggested1(int x) {
+    // TODO: implement suggested1
+    return null;
+  }''');
+    _assertOverride(
+        '''@override\n  A suggested1(int x) {\n    // TODO: implement suggested1\n    return null;\n  }''');
+    _assertOverride(
+        '''@override\n  B suggested2(String y) {\n    // TODO: implement suggested2\n    return null;\n  }''');
+    _assertOverride(
+        '''@override\n  C suggested3([String z]) {\n    // TODO: implement suggested3\n    return null;\n  }''');
+  }
+
+  test_fromPart() async {
+    addSource(
+        '/myLib.dart',
+        '''
+library myLib;
+part '$testFile'
+part '/otherPart.dart'
+class A {
+  A suggested1(int x) => null;
+  B suggested2(String y) => null;
+}
+''');
+    addSource(
+        '/otherPart.dart',
+        '''
+part of myLib;
+class B extends A {
+  B suggested2(String y) => null;
+  C suggested3([String z]) => null;
+}
+''');
+    addTestSource(r'''
+part of myLib;
+class C extends B {
+  sugg^
+}
+''');
+    // assume information for context.getLibrariesContaining has been cached
+    await computeLibrariesContaining();
+    await computeSuggestions();
+    _assertOverride('''@override
+  A suggested1(int x) {
+    // TODO: implement suggested1
+    return null;
+  }''');
+    _assertOverride(
+        '''@override\n  A suggested1(int x) {\n    // TODO: implement suggested1\n    return null;\n  }''');
+    _assertOverride(
+        '''@override\n  B suggested2(String y) {\n    // TODO: implement suggested2\n    return null;\n  }''');
+    _assertOverride(
+        '''@override\n  C suggested3([String z]) {\n    // TODO: implement suggested3\n    return null;\n  }''');
+  }
+
+  CompletionSuggestion _assertOverride(String completion) {
+    CompletionSuggestion cs = getSuggest(
+        completion: completion,
+        csKind: CompletionSuggestionKind.IDENTIFIER,
+        elemKind: null);
+    if (cs == null) {
+      failedCompletion('expected $completion', suggestions);
+    }
+    expect(cs.kind, equals(CompletionSuggestionKind.IDENTIFIER));
+    expect(cs.relevance, equals(DART_RELEVANCE_HIGH));
+    expect(cs.importUri, null);
+//    expect(cs.selectionOffset, equals(completion.length));
+//    expect(cs.selectionLength, equals(0));
+    expect(cs.isDeprecated, isFalse);
+    expect(cs.isPotential, isFalse);
+    expect(cs.element, isNotNull);
+    return cs;
+  }
+}
diff --git a/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
similarity index 69%
rename from pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
rename to pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
index 4a2085f..8933b0a 100644
--- a/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
@@ -5,14 +5,14 @@
 library test.services.completion.dart.keyword;
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analysis_server/src/services/completion/keyword_contributor.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/keyword_contributor.dart';
 import 'package:analyzer/src/generated/scanner.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 import 'package:unittest/unittest.dart';
 
-import '../../utils.dart';
-import 'completion_test_util.dart';
+import '../../../utils.dart';
+import 'completion_contributor_util.dart';
 
 main() {
   initializeTestEnvironment();
@@ -20,7 +20,7 @@
 }
 
 @reflectiveTest
-class KeywordContributorTest extends AbstractCompletionTest {
+class KeywordContributorTest extends DartCompletionContributorTest {
   static const List<Keyword> CLASS_BODY_KEYWORDS = const [
     Keyword.CONST,
     Keyword.DYNAMIC,
@@ -221,7 +221,7 @@
     Set<String> actualCompletions = new Set<String>();
     expectedCompletions.addAll(expectedKeywords.map((k) => k.syntax));
     expectedCompletions.addAll(pseudoKeywords);
-    for (CompletionSuggestion s in request.suggestions) {
+    for (CompletionSuggestion s in suggestions) {
       if (s.kind == CompletionSuggestionKind.KEYWORD) {
         Keyword k = Keyword.keywords[s.completion];
         if (k == null && !expectedCompletions.contains(s.completion)) {
@@ -241,7 +241,7 @@
       _appendCompletions(msg, actualCompletions, expectedCompletions);
       fail(msg.toString());
     }
-    for (CompletionSuggestion s in request.suggestions) {
+    for (CompletionSuggestion s in suggestions) {
       if (s.kind == CompletionSuggestionKind.KEYWORD) {
         if (s.completion.startsWith(Keyword.IMPORT.syntax)) {
           int importRelevance = relevance;
@@ -269,420 +269,420 @@
     }
   }
 
-  fail_import_partial() {
+  fail_import_partial() async {
     addTestSource('imp^ import "package:foo/foo.dart"; import "bar.dart";');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     // TODO(danrubel) should not suggest declaration keywords
     assertNotSuggested('class');
   }
 
-  fail_import_partial4() {
+  fail_import_partial4() async {
     addTestSource('^ imp import "package:foo/foo.dart";');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     // TODO(danrubel) should not suggest declaration keywords
     assertNotSuggested('class');
   }
 
-  fail_import_partial5() {
+  fail_import_partial5() async {
     addTestSource('library libA; imp^ import "package:foo/foo.dart";');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     // TODO(danrubel) should not suggest declaration keywords
     assertNotSuggested('class');
   }
 
-  fail_import_partial6() {
+  fail_import_partial6() async {
     addTestSource(
         'library bar; import "zoo.dart"; imp^ import "package:foo/foo.dart";');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     // TODO(danrubel) should not suggest declaration keywords
     assertNotSuggested('class');
   }
 
   @override
-  void setUpContributor() {
-    contributor = new KeywordContributor();
+  DartCompletionContributor createContributor() {
+    return new KeywordContributor();
   }
 
-  test_after_class() {
+  test_after_class() async {
     addTestSource('class A {} ^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(DECLARATION_KEYWORDS, relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_after_class2() {
+  test_after_class2() async {
     addTestSource('class A {} c^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(DECLARATION_KEYWORDS, relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_after_import() {
+  test_after_import() async {
     addTestSource('import "foo"; ^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(DIRECTIVE_AND_DECLARATION_KEYWORDS,
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_after_import2() {
+  test_after_import2() async {
     addTestSource('import "foo"; c^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(DIRECTIVE_AND_DECLARATION_KEYWORDS,
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_anonymous_function_async() {
+  test_anonymous_function_async() async {
     addTestSource('main() {foo(() ^ {}}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([],
         pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_anonymous_function_async2() {
+  test_anonymous_function_async2() async {
     addTestSource('main() {foo(() a^ {}}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_OUTSIDE_CLASS, pseudoKeywords: ['async']);
   }
 
-  test_anonymous_function_async3() {
+  test_anonymous_function_async3() async {
     addTestSource('main() {foo(() async ^ {}}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_argument() {
+  test_argument() async {
     addTestSource('main() {foo(^);}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
   }
 
-  test_argument2() {
+  test_argument2() async {
     addTestSource('main() {foo(n^);}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
   }
 
-  test_argument_literal() {
+  test_argument_literal() async {
     addTestSource('main() {foo("^");}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_argument_named() {
+  test_argument_named() async {
     addTestSource('main() {foo(bar: ^);}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
   }
 
-  test_argument_named2() {
+  test_argument_named2() async {
     addTestSource('main() {foo(bar: n^);}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
   }
 
-  test_argument_named_literal() {
+  test_argument_named_literal() async {
     addTestSource('main() {foo(bar: "^");}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_assignment_field() {
+  test_assignment_field() async {
     addTestSource('class A {var foo = ^}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
   }
 
-  test_assignment_field2() {
+  test_assignment_field2() async {
     addTestSource('class A {var foo = n^}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
   }
 
-  test_assignment_local() {
+  test_assignment_local() async {
     addTestSource('main() {var foo = ^}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
   }
 
-  test_assignment_local2() {
+  test_assignment_local2() async {
     addTestSource('main() {var foo = n^}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
   }
 
-  test_assignment_local2_async() {
+  test_assignment_local2_async() async {
     addTestSource('main() async {var foo = n^}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE,
         pseudoKeywords: ['await']);
   }
 
-  test_assignment_local_async() {
+  test_assignment_local_async() async {
     addTestSource('main() async {var foo = ^}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE,
         pseudoKeywords: ['await']);
   }
 
-  test_before_import() {
+  test_before_import() async {
     addTestSource('^ import foo;');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(
         [Keyword.EXPORT, Keyword.IMPORT, Keyword.LIBRARY, Keyword.PART],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_catch() {
+  test_catch() async {
     addTestSource('main() {try {} catch (e) {^}}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     var keywords = <Keyword>[];
     keywords.addAll(STMT_START_OUTSIDE_CLASS);
     keywords.add(Keyword.RETHROW);
     assertSuggestKeywords(keywords, relevance: DART_RELEVANCE_KEYWORD);
   }
 
-  test_class() {
+  test_class() async {
     addTestSource('class A e^ { }');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.EXTENDS, Keyword.IMPLEMENTS],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_class_body() {
+  test_class_body() async {
     addTestSource('class A {^}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(CLASS_BODY_KEYWORDS);
   }
 
-  test_class_body_beginning() {
+  test_class_body_beginning() async {
     addTestSource('class A {^ var foo;}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(CLASS_BODY_KEYWORDS);
   }
 
-  test_class_body_between() {
+  test_class_body_between() async {
     addTestSource('class A {var bar; ^ var foo;}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(CLASS_BODY_KEYWORDS);
   }
 
-  test_class_body_end() {
+  test_class_body_end() async {
     addTestSource('class A {var foo; ^}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(CLASS_BODY_KEYWORDS);
   }
 
-  test_class_extends() {
+  test_class_extends() async {
     addTestSource('class A extends foo ^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.IMPLEMENTS, Keyword.WITH],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_class_extends2() {
+  test_class_extends2() async {
     addTestSource('class A extends foo i^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.IMPLEMENTS, Keyword.WITH],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_class_extends3() {
+  test_class_extends3() async {
     addTestSource('class A extends foo i^ { }');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.IMPLEMENTS, Keyword.WITH],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_class_extends_name() {
+  test_class_extends_name() async {
     addTestSource('class A extends ^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_class_implements() {
+  test_class_implements() async {
     addTestSource('class A ^ implements foo');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.EXTENDS], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_class_implements2() {
+  test_class_implements2() async {
     addTestSource('class A e^ implements foo');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     // TODO (danrubel) refinement: don't suggest implements
     assertSuggestKeywords([Keyword.EXTENDS, Keyword.IMPLEMENTS],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_class_implements3() {
+  test_class_implements3() async {
     addTestSource('class A e^ implements foo { }');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     // TODO (danrubel) refinement: don't suggest implements
     assertSuggestKeywords([Keyword.EXTENDS, Keyword.IMPLEMENTS],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_class_implements_name() {
+  test_class_implements_name() async {
     addTestSource('class A implements ^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_class_name() {
+  test_class_name() async {
     addTestSource('class ^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_class_noBody() {
+  test_class_noBody() async {
     addTestSource('class A ^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.EXTENDS, Keyword.IMPLEMENTS],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_class_noBody2() {
+  test_class_noBody2() async {
     addTestSource('class A e^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.EXTENDS, Keyword.IMPLEMENTS],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_class_noBody3() {
+  test_class_noBody3() async {
     addTestSource('class A e^ String foo;');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.EXTENDS, Keyword.IMPLEMENTS],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_class_with() {
+  test_class_with() async {
     addTestSource('class A extends foo with bar ^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.IMPLEMENTS], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_class_with2() {
+  test_class_with2() async {
     addTestSource('class A extends foo with bar i^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.IMPLEMENTS], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_class_with3() {
+  test_class_with3() async {
     addTestSource('class A extends foo with bar i^ { }');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.IMPLEMENTS], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_class_with_name() {
+  test_class_with_name() async {
     addTestSource('class A extends foo with ^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_constructor_param() {
+  test_constructor_param() async {
     addTestSource('class A { A(^) {});}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.THIS]);
   }
 
-  test_constructor_param2() {
+  test_constructor_param2() async {
     addTestSource('class A { A(t^) {});}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.THIS]);
   }
 
-  test_do_break_continue() {
+  test_do_break_continue() async {
     addTestSource('main() {do {^} while (true);}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_IN_LOOP_OUTSIDE_CLASS,
         relevance: DART_RELEVANCE_KEYWORD);
   }
 
-  test_do_break_continue2() {
+  test_do_break_continue2() async {
     addTestSource('class A {foo() {do {^} while (true);}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_IN_LOOP_IN_CLASS,
         relevance: DART_RELEVANCE_KEYWORD);
   }
 
-  test_empty() {
+  test_empty() async {
     addTestSource('^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(DIRECTIVE_DECLARATION_AND_LIBRARY_KEYWORDS,
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_for_break_continue() {
+  test_for_break_continue() async {
     addTestSource('main() {for (int x in myList) {^}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_IN_LOOP_OUTSIDE_CLASS,
         relevance: DART_RELEVANCE_KEYWORD);
   }
 
-  test_for_break_continue2() {
+  test_for_break_continue2() async {
     addTestSource('class A {foo() {for (int x in myList) {^}}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_IN_LOOP_IN_CLASS,
         relevance: DART_RELEVANCE_KEYWORD);
   }
 
-  test_for_expression_in() {
+  test_for_expression_in() async {
     addTestSource('main() {for (int x i^)}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.IN], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_for_expression_in2() {
+  test_for_expression_in2() async {
     addTestSource('main() {for (int x in^)}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.IN], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_for_expression_init() {
+  test_for_expression_init() async {
     addTestSource('main() {for (int x = i^)}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
   }
 
-  test_for_expression_init2() {
+  test_for_expression_init2() async {
     addTestSource('main() {for (int x = in^)}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
   }
 
-  test_function_async() {
+  test_function_async() async {
     addTestSource('main()^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(DECLARATION_KEYWORDS,
         pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_function_async2() {
+  test_function_async2() async {
     addTestSource('main()^{}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([],
         pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_function_async3() {
+  test_function_async3() async {
     addTestSource('main()a^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(DECLARATION_KEYWORDS,
         pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_function_async4() {
+  test_function_async4() async {
     addTestSource('main()a^{}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(DECLARATION_KEYWORDS,
         pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_function_async5() {
+  test_function_async5() async {
     addTestSource('main()a^ Foo foo;');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(DECLARATION_KEYWORDS,
         pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_function_body_inClass_constructorInitializer() {
+  test_function_body_inClass_constructorInitializer() async {
     addTestSource(r'''
 foo(p) {}
 class A {
@@ -690,11 +690,11 @@
   A() : f = foo(() {^});
 }
 ''');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_OUTSIDE_CLASS);
   }
 
-  test_function_body_inClass_constructorInitializer_async() {
+  test_function_body_inClass_constructorInitializer_async() async {
     addTestSource(r'''
 foo(p) {}
 class A {
@@ -702,21 +702,21 @@
   A() : f = foo(() async {^});
 }
 ''');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_OUTSIDE_CLASS, pseudoKeywords: ['await']);
   }
 
-  test_function_body_inClass_field() {
+  test_function_body_inClass_field() async {
     addTestSource(r'''
 class A {
   var f = () {^};
 }
 ''');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_OUTSIDE_CLASS);
   }
 
-  test_function_body_inClass_methodBody() {
+  test_function_body_inClass_methodBody() async {
     addTestSource(r'''
 class A {
   m() {
@@ -724,11 +724,11 @@
   }
 }
 ''');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_IN_CLASS);
   }
 
-  test_function_body_inClass_methodBody_inFunction() {
+  test_function_body_inClass_methodBody_inFunction() async {
     addTestSource(r'''
 class A {
   m() {
@@ -738,11 +738,11 @@
   }
 }
 ''');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_IN_CLASS);
   }
 
-  test_function_body_inClass_methodBody_inFunction_async() {
+  test_function_body_inClass_methodBody_inFunction_async() async {
     addTestSource(r'''
 class A {
   m() {
@@ -752,657 +752,659 @@
   }
 }
 ''');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_IN_CLASS, pseudoKeywords: ['await']);
   }
 
-  test_function_body_inUnit() {
+  test_function_body_inUnit() async {
     addTestSource('main() {^}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_OUTSIDE_CLASS);
   }
 
-  test_function_body_inUnit_afterBlock() {
+  test_function_body_inUnit_afterBlock() async {
     addTestSource('main() {{}^}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_OUTSIDE_CLASS);
   }
 
-  test_function_body_inUnit_async() {
+  test_function_body_inUnit_async() async {
     addTestSource('main() async {^}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_OUTSIDE_CLASS, pseudoKeywords: ['await']);
   }
 
-  test_if_expression_in_class() {
+  test_if_expression_in_class() async {
     addTestSource('class A {foo() {if (^) }}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_INSTANCE);
   }
 
-  test_if_expression_in_class2() {
+  test_if_expression_in_class2() async {
     addTestSource('class A {foo() {if (n^) }}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_INSTANCE);
   }
 
-  test_if_expression_in_function() {
+  test_if_expression_in_function() async {
     addTestSource('foo() {if (^) }');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
   }
 
-  test_if_expression_in_function2() {
+  test_if_expression_in_function2() async {
     addTestSource('foo() {if (n^) }');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
   }
 
-  test_if_in_class() {
+  test_if_in_class() async {
     addTestSource('class A {foo() {if (true) ^}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_IN_CLASS);
   }
 
-  test_if_in_class2() {
+  test_if_in_class2() async {
     addTestSource('class A {foo() {if (true) ^;}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_IN_CLASS);
   }
 
-  test_if_in_class3() {
+  test_if_in_class3() async {
     addTestSource('class A {foo() {if (true) r^;}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_IN_CLASS);
   }
 
-  test_if_in_class4() {
+  test_if_in_class4() async {
     addTestSource('class A {foo() {if (true) ^ go();}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_IN_CLASS);
   }
 
-  test_if_outside_class() {
+  test_if_outside_class() async {
     addTestSource('foo() {if (true) ^}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_OUTSIDE_CLASS);
   }
 
-  test_if_outside_class2() {
+  test_if_outside_class2() async {
     addTestSource('foo() {if (true) ^;}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_OUTSIDE_CLASS);
   }
 
-  test_if_outside_class3() {
+  test_if_outside_class3() async {
     addTestSource('foo() {if (true) r^;}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_OUTSIDE_CLASS);
   }
 
-  test_if_outside_class4() {
+  test_if_outside_class4() async {
     addTestSource('foo() {if (true) ^ go();}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_OUTSIDE_CLASS);
   }
 
-  test_import() {
+  test_import() async {
     addTestSource('import "foo" deferred as foo ^;');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([],
         pseudoKeywords: ['show', 'hide'], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_import_as() {
+  test_import_as() async {
     addTestSource('import "foo" deferred ^;');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.AS], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_import_as2() {
+  test_import_as2() async {
     addTestSource('import "foo" deferred a^;');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.AS], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_import_as3() {
+  test_import_as3() async {
     addTestSource('import "foo" deferred a^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.AS], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_import_deferred() {
+  test_import_deferred() async {
     addTestSource('import "foo" ^ as foo;');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.DEFERRED], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_import_deferred2() {
+  test_import_deferred2() async {
     addTestSource('import "foo" d^ as foo;');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.DEFERRED], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_import_deferred3() {
+  test_import_deferred3() async {
     addTestSource('import "foo" d^ show foo;');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.AS],
         pseudoKeywords: ['deferred as'], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_import_deferred4() {
+  test_import_deferred4() async {
     addTestSource('import "foo" d^ hide foo;');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.AS],
         pseudoKeywords: ['deferred as'], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_import_deferred5() {
+  test_import_deferred5() async {
     addTestSource('import "foo" d^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.AS],
         pseudoKeywords: ['deferred as', 'show', 'hide'],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_import_deferred6() {
+  test_import_deferred6() async {
     addTestSource('import "foo" d^ import');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.AS],
         pseudoKeywords: ['deferred as', 'show', 'hide'],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_import_deferred_as() {
+  test_import_deferred_as() async {
     addTestSource('import "foo" ^;');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.AS],
         pseudoKeywords: ['deferred as', 'show', 'hide'],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_import_deferred_as2() {
+  test_import_deferred_as2() async {
     addTestSource('import "foo" d^;');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.AS],
         pseudoKeywords: ['deferred as', 'show', 'hide'],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_import_deferred_as3() {
+  test_import_deferred_as3() async {
     addTestSource('import "foo" ^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.AS],
         pseudoKeywords: ['deferred as', 'show', 'hide'],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_import_deferred_as4() {
+  test_import_deferred_as4() async {
     addTestSource('import "foo" d^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.AS],
         pseudoKeywords: ['deferred as', 'show', 'hide'],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_import_deferred_as5() {
+  test_import_deferred_as5() async {
     addTestSource('import "foo" sh^ import "bar"; import "baz";');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.AS],
         pseudoKeywords: ['deferred as', 'show', 'hide'],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_import_deferred_not() {
+  test_import_deferred_not() async {
     addTestSource('import "foo" as foo ^;');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([],
         pseudoKeywords: ['show', 'hide'], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_import_deferred_partial() {
+  test_import_deferred_partial() async {
     addTestSource('import "package:foo/foo.dart" def^ as foo;');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
+    expect(replacementOffset, 30);
+    expect(replacementLength, 3);
     assertSuggestKeywords([Keyword.DEFERRED], relevance: DART_RELEVANCE_HIGH);
-    expect(request.replacementOffset, 30);
-    expect(request.replacementLength, 3);
+    expect(suggestions[0].selectionOffset, 8);
+    expect(suggestions[0].selectionLength, 0);
   }
 
-  test_import_incomplete() {
+  test_import_incomplete() async {
     addTestSource('import "^"');
-    expect(computeFast(), isTrue);
-    assertNoSuggestions();
+    await computeSuggestions();
+    expect(suggestions, isEmpty);
   }
 
-  test_import_partial() {
+  test_import_partial() async {
     addTestSource('imp^ import "package:foo/foo.dart"; import "bar.dart";');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
+    expect(replacementOffset, 0);
+    expect(replacementLength, 3);
     // TODO(danrubel) should not suggest declaration keywords
     assertSuggestKeywords(DIRECTIVE_DECLARATION_AND_LIBRARY_KEYWORDS,
         relevance: DART_RELEVANCE_HIGH);
-    expect(request.replacementOffset, 0);
-    expect(request.replacementLength, 3);
   }
 
-  test_import_partial2() {
+  test_import_partial2() async {
     addTestSource('^imp import "package:foo/foo.dart";');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
+    expect(replacementOffset, 0);
+    expect(replacementLength, 3);
     // TODO(danrubel) should not suggest declaration keywords
     assertSuggestKeywords(DIRECTIVE_DECLARATION_AND_LIBRARY_KEYWORDS,
         relevance: DART_RELEVANCE_HIGH);
-    expect(request.replacementOffset, 0);
-    expect(request.replacementLength, 3);
   }
 
-  test_import_partial3() {
+  test_import_partial3() async {
     addTestSource(' ^imp import "package:foo/foo.dart"; import "bar.dart";');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
+    expect(replacementOffset, 1);
+    expect(replacementLength, 3);
     // TODO(danrubel) should not suggest declaration keywords
     assertSuggestKeywords(DIRECTIVE_DECLARATION_AND_LIBRARY_KEYWORDS,
         relevance: DART_RELEVANCE_HIGH);
-    expect(request.replacementOffset, 1);
-    expect(request.replacementLength, 3);
   }
 
-  test_import_partial4() {
+  test_import_partial4() async {
     addTestSource('^ imp import "package:foo/foo.dart";');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
+    expect(replacementOffset, 0);
+    expect(replacementLength, 0);
     // TODO(danrubel) should not suggest declaration keywords
     assertSuggestKeywords(DIRECTIVE_DECLARATION_AND_LIBRARY_KEYWORDS,
         relevance: DART_RELEVANCE_HIGH);
-    expect(request.replacementOffset, 0);
-    expect(request.replacementLength, 0);
   }
 
-  test_import_partial5() {
+  test_import_partial5() async {
     addTestSource('library libA; imp^ import "package:foo/foo.dart";');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
+    expect(replacementOffset, 14);
+    expect(replacementLength, 3);
     // TODO(danrubel) should not suggest declaration keywords
     assertSuggestKeywords(DIRECTIVE_AND_DECLARATION_KEYWORDS,
         relevance: DART_RELEVANCE_HIGH);
-    expect(request.replacementOffset, 14);
-    expect(request.replacementLength, 3);
   }
 
-  test_import_partial6() {
+  test_import_partial6() async {
     addTestSource(
         'library bar; import "zoo.dart"; imp^ import "package:foo/foo.dart";');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
+    expect(replacementOffset, 32);
+    expect(replacementLength, 3);
     // TODO(danrubel) should not suggest declaration keywords
     assertSuggestKeywords(DIRECTIVE_AND_DECLARATION_KEYWORDS,
         relevance: DART_RELEVANCE_HIGH);
-    expect(request.replacementOffset, 32);
-    expect(request.replacementLength, 3);
   }
 
-  test_inComment_block() {
+  test_inComment_block() async {
     addTestSource('''
 main() {
   /* text ^ */
   print(42);
 }
 ''');
-    expect(computeFast(), isTrue);
-    assertNoSuggestions();
+    await computeSuggestions();
+    expect(suggestions, isEmpty);
   }
 
-  test_inComment_endOfLine() {
+  test_inComment_endOfLine() async {
     addTestSource('''
 main() {
   // text ^
 }
 ''');
-    expect(computeFast(), isTrue);
-    assertNoSuggestions();
+    await computeSuggestions();
+    expect(suggestions, isEmpty);
   }
 
-  test_is_expression() {
+  test_is_expression() async {
     addTestSource('main() {if (x is^)}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.IS], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_library() {
+  test_library() async {
     addTestSource('library foo;^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(DIRECTIVE_AND_DECLARATION_KEYWORDS,
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_library_declaration() {
+  test_library_declaration() async {
     addTestSource('library ^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_library_declaration2() {
+  test_library_declaration2() async {
     addTestSource('library a^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_library_declaration3() {
+  test_library_declaration3() async {
     addTestSource('library a.^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_library_name() {
+  test_library_name() async {
     addTestSource('library ^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_method_async() {
+  test_method_async() async {
     addTestSource('class A { foo() ^}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(CLASS_BODY_KEYWORDS, pseudoKeywords: ['async']);
   }
 
-  test_method_async2() {
+  test_method_async2() async {
     addTestSource('class A { foo() ^{}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([],
         pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_method_async3() {
+  test_method_async3() async {
     addTestSource('class A { foo() a^}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(CLASS_BODY_KEYWORDS, pseudoKeywords: ['async']);
   }
 
-  test_method_async4() {
+  test_method_async4() async {
     addTestSource('class A { foo() a^{}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(CLASS_BODY_KEYWORDS, pseudoKeywords: ['async']);
   }
 
-  test_method_async5() {
+  test_method_async5() async {
     addTestSource('class A { foo() ^ Foo foo;}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(CLASS_BODY_KEYWORDS, pseudoKeywords: ['async']);
   }
 
-  test_method_async6() {
+  test_method_async6() async {
     addTestSource('class A { foo() a^ Foo foo;}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(CLASS_BODY_KEYWORDS, pseudoKeywords: ['async']);
   }
 
-  test_method_async7() {
+  test_method_async7() async {
     addTestSource('class A { foo() ^ => Foo foo;}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([],
         pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_method_async8() {
+  test_method_async8() async {
     addTestSource('class A { foo() a^ Foo foo;}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(CLASS_BODY_KEYWORDS, pseudoKeywords: ['async']);
   }
 
-  test_method_body() {
+  test_method_body() async {
     addTestSource('class A { foo() {^}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_IN_CLASS);
   }
 
-  test_method_body2() {
+  test_method_body2() async {
     addTestSource('class A { foo() => ^}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_INSTANCE);
   }
 
-  test_method_body3() {
+  test_method_body3() async {
     addTestSource('class A { foo() => ^ Foo foo;}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_INSTANCE);
   }
 
-  test_method_body4() {
+  test_method_body4() async {
     addTestSource('class A { foo() => ^;}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_INSTANCE);
   }
 
-  test_method_body_async() {
+  test_method_body_async() async {
     addTestSource('class A { foo() async {^}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_IN_CLASS, pseudoKeywords: ['await']);
   }
 
-  test_method_body_async2() {
+  test_method_body_async2() async {
     addTestSource('class A { foo() async => ^}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_INSTANCE, pseudoKeywords: ['await']);
   }
 
-  test_method_body_async3() {
+  test_method_body_async3() async {
     addTestSource('class A { foo() async => ^ Foo foo;}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_INSTANCE, pseudoKeywords: ['await']);
   }
 
-  test_method_body_async4() {
+  test_method_body_async4() async {
     addTestSource('class A { foo() async => ^;}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_INSTANCE, pseudoKeywords: ['await']);
   }
 
-  test_method_body_expression1() {
+  test_method_body_expression1() async {
     addTestSource('class A { foo() {return b == true ? ^}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_INSTANCE);
   }
 
-  test_method_body_expression2() {
+  test_method_body_expression2() async {
     addTestSource('class A { foo() {return b == true ? 1 : ^}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_INSTANCE);
   }
 
-  test_method_body_return() {
+  test_method_body_return() async {
     addTestSource('class A { foo() {return ^}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_INSTANCE);
   }
 
-  test_method_param() {
+  test_method_param() async {
     addTestSource('class A { foo(^) {});}');
-    expect(computeFast(), isTrue);
-    assertNoSuggestions();
+    await computeSuggestions();
+    expect(suggestions, isEmpty);
   }
 
-  test_method_param2() {
+  test_method_param2() async {
     addTestSource('class A { foo(t^) {});}');
-    expect(computeFast(), isTrue);
-    assertNoSuggestions();
+    await computeSuggestions();
+    expect(suggestions, isEmpty);
   }
 
-  test_named_constructor_invocation() {
+  test_named_constructor_invocation() async {
     addTestSource('void main() {new Future.^}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_newInstance() {
+  test_newInstance() async {
     addTestSource('class A { foo() {new ^}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_newInstance2() {
+  test_newInstance2() async {
     addTestSource('class A { foo() {new ^ print("foo");}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_newInstance_prefixed() {
+  test_newInstance_prefixed() async {
     addTestSource('class A { foo() {new A.^}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_newInstance_prefixed2() {
+  test_newInstance_prefixed2() async {
     addTestSource('class A { foo() {new A.^ print("foo");}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_part_of() {
+  test_part_of() async {
     addTestSource('part of foo;^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(DIRECTIVE_AND_DECLARATION_KEYWORDS,
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_partial_class() {
+  test_partial_class() async {
     addTestSource('cl^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(DIRECTIVE_DECLARATION_AND_LIBRARY_KEYWORDS,
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_partial_class2() {
+  test_partial_class2() async {
     addTestSource('library a; cl^');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(DIRECTIVE_AND_DECLARATION_KEYWORDS,
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_prefixed_field() {
+  test_prefixed_field() async {
     addTestSource('class A { int x; foo() {x.^}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_prefixed_field2() {
+  test_prefixed_field2() async {
     addTestSource('class A { int x; foo() {x.^ print("foo");}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_prefixed_library() {
+  test_prefixed_library() async {
     addTestSource('import "b" as b; class A { foo() {b.^}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_prefixed_local() {
+  test_prefixed_local() async {
     addTestSource('class A { foo() {int x; x.^}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_prefixed_local2() {
+  test_prefixed_local2() async {
     addTestSource('class A { foo() {int x; x.^ print("foo");}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_property_access() {
+  test_property_access() async {
     addTestSource('class A { get x => 7; foo() {new A().^}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([]);
   }
 
-  test_switch_expression() {
+  test_switch_expression() async {
     addTestSource('main() {switch(^) {}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
   }
 
-  test_switch_expression2() {
+  test_switch_expression2() async {
     addTestSource('main() {switch(n^) {}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
   }
 
-  test_switch_expression3() {
+  test_switch_expression3() async {
     addTestSource('main() {switch(n^)}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
   }
 
-  test_switch_start() {
+  test_switch_start() async {
     addTestSource('main() {switch(1) {^}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.CASE, Keyword.DEFAULT],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_switch_start2() {
+  test_switch_start2() async {
     addTestSource('main() {switch(1) {^ case 1:}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.CASE, Keyword.DEFAULT],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_switch_start3() {
+  test_switch_start3() async {
     addTestSource('main() {switch(1) {^default:}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.CASE, Keyword.DEFAULT],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_switch_start4() {
+  test_switch_start4() async {
     addTestSource('main() {switch(1) {^ default:}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords([Keyword.CASE, Keyword.DEFAULT],
         relevance: DART_RELEVANCE_HIGH);
   }
 
-  test_switch_start5() {
+  test_switch_start5() async {
     addTestSource('main() {switch(1) {c^ default:}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
+    expect(replacementOffset, 19);
+    expect(replacementLength, 1);
     assertSuggestKeywords([Keyword.CASE, Keyword.DEFAULT],
         relevance: DART_RELEVANCE_HIGH);
-    expect(request.replacementOffset, 19);
-    expect(request.replacementLength, 1);
   }
 
-  test_switch_start6() {
+  test_switch_start6() async {
     addTestSource('main() {switch(1) {c^}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
+    expect(replacementOffset, 19);
+    expect(replacementLength, 1);
     assertSuggestKeywords([Keyword.CASE, Keyword.DEFAULT],
         relevance: DART_RELEVANCE_HIGH);
-    expect(request.replacementOffset, 19);
-    expect(request.replacementLength, 1);
   }
 
-  test_switch_start7() {
+  test_switch_start7() async {
     addTestSource('main() {switch(1) { c^ }}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
+    expect(replacementOffset, 20);
+    expect(replacementLength, 1);
     assertSuggestKeywords([Keyword.CASE, Keyword.DEFAULT],
         relevance: DART_RELEVANCE_HIGH);
-    expect(request.replacementOffset, 20);
-    expect(request.replacementLength, 1);
   }
 
-  test_switch_statement() {
+  test_switch_statement() async {
     addTestSource('main() {switch(1) {case 1:^}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_IN_SWITCH_OUTSIDE_CLASS);
   }
 
-  test_switch_statement2() {
+  test_switch_statement2() async {
     addTestSource('class A{foo() {switch(1) {case 1:^}}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_IN_SWITCH_IN_CLASS);
   }
 
-  test_while_break_continue() {
+  test_while_break_continue() async {
     addTestSource('main() {while (true) {^}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_IN_LOOP_OUTSIDE_CLASS,
         relevance: DART_RELEVANCE_KEYWORD);
   }
 
-  test_while_break_continue2() {
+  test_while_break_continue2() async {
     addTestSource('class A {foo() {while (true) {^}}}');
-    expect(computeFast(), isTrue);
+    await computeSuggestions();
     assertSuggestKeywords(STMT_START_IN_LOOP_IN_CLASS,
         relevance: DART_RELEVANCE_KEYWORD);
   }
diff --git a/pkg/analysis_server/test/services/completion/dart/test_all.dart b/pkg/analysis_server/test/services/completion/dart/test_all.dart
new file mode 100644
index 0000000..9d8d061
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/test_all.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.services.completion.dart;
+
+import 'package:unittest/unittest.dart';
+
+import '../../../utils.dart';
+import 'combinator_contributor_test.dart' as combinator_test;
+import 'arglist_contributor_test.dart' as arglist_test;
+import 'common_usage_sorter_test.dart' as common_usage_test;
+import 'inherited_contributor_test.dart' as inherited_contributor_test;
+import 'keyword_contributor_test.dart' as keyword_test;
+import 'uri_contributor_test.dart' as uri_contributor_test;
+
+/// Utility for manually running all tests.
+main() {
+  initializeTestEnvironment();
+  group('dart/completion', () {
+    arglist_test.main();
+    combinator_test.main();
+    common_usage_test.main();
+    inherited_contributor_test.main();
+    keyword_test.main();
+    uri_contributor_test.main();
+  });
+}
diff --git a/pkg/analysis_server/test/services/completion/uri_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/uri_contributor_test.dart
similarity index 73%
rename from pkg/analysis_server/test/services/completion/uri_contributor_test.dart
rename to pkg/analysis_server/test/services/completion/dart/uri_contributor_test.dart
index 22ebe15..e6c2384 100644
--- a/pkg/analysis_server/test/services/completion/uri_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/uri_contributor_test.dart
@@ -5,15 +5,15 @@
 library test.services.completion.contributor.dart.importuri;
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analysis_server/src/services/completion/uri_contributor.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/uri_contributor.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:path/path.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 import 'package:unittest/unittest.dart';
 
-import '../../utils.dart';
-import 'completion_test_util.dart';
+import '../../../utils.dart';
+import 'completion_contributor_util.dart';
 
 main() {
   initializeTestEnvironment();
@@ -22,85 +22,85 @@
 }
 
 @reflectiveTest
-class UriContributorTest extends AbstractCompletionTest {
+class UriContributorTest extends DartCompletionContributorTest {
   @override
-  void setUpContributor() {
-    contributor = new UriContributor();
+  DartCompletionContributor createContributor() {
+    return new UriContributor();
   }
 
-  test_after_import() {
+  test_after_import() async {
     addTestSource('import "p"^');
-    computeFast();
-    expect(request.replacementOffset, completionOffset);
-    expect(request.replacementLength, 0);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset);
+    expect(replacementLength, 0);
     assertNoSuggestions();
   }
 
-  test_after_import_raw() {
+  test_after_import_raw() async {
     addTestSource('import r"p"^');
-    computeFast();
-    expect(request.replacementOffset, completionOffset);
-    expect(request.replacementLength, 0);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset);
+    expect(replacementLength, 0);
     assertNoSuggestions();
   }
 
-  test_before_import() {
+  test_before_import() async {
     addTestSource('import ^"p"');
-    computeFast();
-    expect(request.replacementOffset, completionOffset);
-    expect(request.replacementLength, 0);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset);
+    expect(replacementLength, 0);
     assertNoSuggestions();
   }
 
-  test_before_import_raw() {
+  test_before_import_raw() async {
     addTestSource('import ^r"p"');
-    computeFast();
-    expect(request.replacementOffset, completionOffset);
-    expect(request.replacementLength, 0);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset);
+    expect(replacementLength, 0);
     assertNoSuggestions();
   }
 
-  test_before_import_raw2() {
+  test_before_import_raw2() async {
     addTestSource('import r^"p"');
-    computeFast();
-    expect(request.replacementOffset, completionOffset);
-    expect(request.replacementLength, 0);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset);
+    expect(replacementLength, 0);
     assertNoSuggestions();
   }
 
-  test_export_package2() {
+  test_export_package2() async {
     addPackageSource('foo', 'foo.dart', 'library foo;');
     addPackageSource('foo', 'baz/too.dart', 'library too;');
     addPackageSource('bar', 'bar.dart', 'library bar;');
     addTestSource('export "package:foo/baz/^" import');
-    computeFast();
+    await computeSuggestions();
     assertSuggest('package:foo/baz/too.dart',
         csKind: CompletionSuggestionKind.IMPORT);
   }
 
-  test_import() {
+  test_import() async {
     addTestSource('import "^"');
-    computeFast();
-    expect(request.replacementOffset, completionOffset);
-    expect(request.replacementLength, 0);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset);
+    expect(replacementLength, 0);
     assertSuggest('dart:', csKind: CompletionSuggestionKind.IMPORT);
     assertSuggest('package:', csKind: CompletionSuggestionKind.IMPORT);
   }
 
-  test_import2() {
+  test_import2() async {
     addTestSource('import "^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset);
-    expect(request.replacementLength, 0);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset);
+    expect(replacementLength, 0);
     assertSuggest('dart:', csKind: CompletionSuggestionKind.IMPORT);
     assertSuggest('package:', csKind: CompletionSuggestionKind.IMPORT);
   }
 
-  test_import_dart() {
+  test_import_dart() async {
     addTestSource('import "d^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 1);
-    expect(request.replacementLength, 1);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 1);
+    expect(replacementLength, 1);
     assertSuggest('dart:', csKind: CompletionSuggestionKind.IMPORT);
     assertSuggest('dart:core',
         csKind: CompletionSuggestionKind.IMPORT, relevance: DART_RELEVANCE_LOW);
@@ -109,11 +109,11 @@
     assertSuggest('dart:math', csKind: CompletionSuggestionKind.IMPORT);
   }
 
-  test_import_dart2() {
+  test_import_dart2() async {
     addTestSource('import "dart:async"; import "d^"');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 1);
-    expect(request.replacementLength, 1);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 1);
+    expect(replacementLength, 1);
     assertSuggest('dart:', csKind: CompletionSuggestionKind.IMPORT);
     assertSuggest('dart:core',
         csKind: CompletionSuggestionKind.IMPORT, relevance: DART_RELEVANCE_LOW);
@@ -122,15 +122,15 @@
     assertSuggest('dart:math', csKind: CompletionSuggestionKind.IMPORT);
   }
 
-  test_import_file() {
+  test_import_file() async {
     testFile = '/proj/completion.dart';
     addSource('/proj/other.dart', 'library other;');
     addSource('/proj/foo/bar.dart', 'library bar;');
     addSource('/blat.dart', 'library blat;');
     addTestSource('import "^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset);
-    expect(request.replacementLength, 0);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset);
+    expect(replacementLength, 0);
     assertNotSuggested('completion.dart');
     assertSuggest('other.dart', csKind: CompletionSuggestionKind.IMPORT);
     assertNotSuggested('foo');
@@ -139,15 +139,15 @@
     assertNotSuggested('../blat.dart');
   }
 
-  test_import_file2() {
+  test_import_file2() async {
     testFile = '/proj/completion.dart';
     addSource('/proj/other.dart', 'library other;');
     addSource('/proj/foo/bar.dart', 'library bar;');
     addSource('/blat.dart', 'library blat;');
     addTestSource('import "..^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 2);
-    expect(request.replacementLength, 2);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 2);
+    expect(replacementLength, 2);
     assertNotSuggested('completion.dart');
     assertSuggest('other.dart', csKind: CompletionSuggestionKind.IMPORT);
     assertNotSuggested('foo');
@@ -156,15 +156,15 @@
     assertNotSuggested('../blat.dart');
   }
 
-  test_import_file_child() {
+  test_import_file_child() async {
     testFile = '/proj/completion.dart';
     addSource('/proj/other.dart', 'library other;');
     addSource('/proj/foo/bar.dart', 'library bar;');
     addSource('/blat.dart', 'library blat;');
     addTestSource('import "foo/^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 4);
-    expect(request.replacementLength, 4);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 4);
+    expect(replacementLength, 4);
     assertNotSuggested('completion.dart');
     assertNotSuggested('other.dart');
     assertNotSuggested('foo');
@@ -173,15 +173,15 @@
     assertNotSuggested('../blat.dart');
   }
 
-  test_import_file_parent() {
+  test_import_file_parent() async {
     testFile = '/proj/completion.dart';
     addSource('/proj/other.dart', 'library other;');
     addSource('/proj/foo/bar.dart', 'library bar;');
     addSource('/blat.dart', 'library blat;');
     addTestSource('import "../^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 3);
-    expect(request.replacementLength, 3);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 3);
+    expect(replacementLength, 3);
     assertNotSuggested('completion.dart');
     assertNotSuggested('other.dart');
     assertNotSuggested('foo');
@@ -190,15 +190,15 @@
     assertSuggest('../blat.dart', csKind: CompletionSuggestionKind.IMPORT);
   }
 
-  test_import_file_parent2() {
+  test_import_file_parent2() async {
     testFile = '/proj/completion.dart';
     addSource('/proj/other.dart', 'library other;');
     addSource('/proj/foo/bar.dart', 'library bar;');
     addSource('/blat.dart', 'library blat;');
     addTestSource('import "../b^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 4);
-    expect(request.replacementLength, 4);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 4);
+    expect(replacementLength, 4);
     assertNotSuggested('completion.dart');
     assertNotSuggested('other.dart');
     assertNotSuggested('foo');
@@ -207,14 +207,14 @@
     assertSuggest('../blat.dart', csKind: CompletionSuggestionKind.IMPORT);
   }
 
-  test_import_package() {
+  test_import_package() async {
     addPackageSource('foo', 'foo.dart', 'library foo;');
     addPackageSource('foo', 'baz/too.dart', 'library too;');
     addPackageSource('bar', 'bar.dart', 'library bar;');
     addTestSource('import "p^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 1);
-    expect(request.replacementLength, 1);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 1);
+    expect(replacementLength, 1);
     assertSuggest('package:', csKind: CompletionSuggestionKind.IMPORT);
     assertSuggest('package:foo/', csKind: CompletionSuggestionKind.IMPORT);
     assertSuggest('package:foo/foo.dart',
@@ -226,46 +226,46 @@
         csKind: CompletionSuggestionKind.IMPORT);
   }
 
-  test_import_package2() {
+  test_import_package2() async {
     addPackageSource('foo', 'foo.dart', 'library foo;');
     addPackageSource('foo', 'baz/too.dart', 'library too;');
     addPackageSource('bar', 'bar.dart', 'library bar;');
     addTestSource('import "package:foo/baz/^" import');
-    computeFast();
+    await computeSuggestions();
     assertSuggest('package:foo/baz/too.dart',
         csKind: CompletionSuggestionKind.IMPORT);
   }
 
-  test_import_package2_raw() {
+  test_import_package2_raw() async {
     addPackageSource('foo', 'foo.dart', 'library foo;');
     addPackageSource('foo', 'baz/too.dart', 'library too;');
     addPackageSource('bar', 'bar.dart', 'library bar;');
     addTestSource('import r"package:foo/baz/^" import');
-    computeFast();
+    await computeSuggestions();
     assertSuggest('package:foo/baz/too.dart',
         csKind: CompletionSuggestionKind.IMPORT);
   }
 
-  test_import_package_missing_lib() {
+  test_import_package_missing_lib() async {
     var pkgSrc = addPackageSource('bar', 'bar.dart', 'library bar;');
     provider.deleteFolder(dirname(pkgSrc.fullName));
     addTestSource('import "p^" class');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 1);
-    expect(request.replacementLength, 1);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 1);
+    expect(replacementLength, 1);
     assertSuggest('package:', csKind: CompletionSuggestionKind.IMPORT);
     assertSuggest('package:bar/', csKind: CompletionSuggestionKind.IMPORT);
     assertNotSuggested('package:bar/bar.dart');
   }
 
-  test_import_package_raw() {
+  test_import_package_raw() async {
     addPackageSource('foo', 'foo.dart', 'library foo;');
     addPackageSource('foo', 'baz/too.dart', 'library too;');
     addPackageSource('bar', 'bar.dart', 'library bar;');
     addTestSource('import r"p^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 1);
-    expect(request.replacementLength, 1);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 1);
+    expect(replacementLength, 1);
     assertSuggest('package:', csKind: CompletionSuggestionKind.IMPORT);
     assertSuggest('package:foo/', csKind: CompletionSuggestionKind.IMPORT);
     assertSuggest('package:foo/foo.dart',
@@ -277,40 +277,36 @@
         csKind: CompletionSuggestionKind.IMPORT);
   }
 
-  test_import_raw() {
+  test_import_raw() async {
     addTestSource('import r"^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset);
-    expect(request.replacementLength, 0);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset);
+    expect(replacementLength, 0);
     assertSuggest('dart:', csKind: CompletionSuggestionKind.IMPORT);
     assertSuggest('package:', csKind: CompletionSuggestionKind.IMPORT);
   }
 
-  test_outside_import() {
+  test_outside_import() async {
     addTestSource('import ^"d" import');
-    computeFast();
-    computeFull((_) {
-      assertNoSuggestions();
-    });
+    await computeSuggestions();
+    assertNoSuggestions();
   }
 
-  test_outside_import2() {
+  test_outside_import2() async {
     addTestSource('import "d"^ import');
-    computeFast();
-    computeFull((_) {
-      assertNoSuggestions();
-    });
+    await computeSuggestions();
+    assertNoSuggestions();
   }
 
-  test_part_file() {
+  test_part_file() async {
     testFile = '/proj/completion.dart';
     addSource('/proj/other.dart', 'library other;');
     addSource('/proj/foo/bar.dart', 'library bar;');
     addSource('/blat.dart', 'library blat;');
     addTestSource('library x; part "^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset);
-    expect(request.replacementLength, 0);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset);
+    expect(replacementLength, 0);
     assertNotSuggested('completion.dart');
     assertSuggest('other.dart', csKind: CompletionSuggestionKind.IMPORT);
     assertNotSuggested('foo');
@@ -319,15 +315,15 @@
     assertNotSuggested('../blat.dart');
   }
 
-  test_part_file2() {
+  test_part_file2() async {
     testFile = '/proj/completion.dart';
     addSource('/proj/other.dart', 'library other;');
     addSource('/proj/foo/bar.dart', 'library bar;');
     addSource('/blat.dart', 'library blat;');
     addTestSource('library x; part "..^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 2);
-    expect(request.replacementLength, 2);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 2);
+    expect(replacementLength, 2);
     assertNotSuggested('completion.dart');
     assertSuggest('other.dart', csKind: CompletionSuggestionKind.IMPORT);
     assertNotSuggested('foo');
@@ -336,15 +332,15 @@
     assertNotSuggested('../blat.dart');
   }
 
-  test_part_file_child() {
+  test_part_file_child() async {
     testFile = '/proj/completion.dart';
     addSource('/proj/other.dart', 'library other;');
     addSource('/proj/foo/bar.dart', 'library bar;');
     addSource('/blat.dart', 'library blat;');
     addTestSource('library x; part "foo/^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 4);
-    expect(request.replacementLength, 4);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 4);
+    expect(replacementLength, 4);
     assertNotSuggested('completion.dart');
     assertNotSuggested('other.dart');
     assertNotSuggested('foo');
@@ -353,15 +349,15 @@
     assertNotSuggested('../blat.dart');
   }
 
-  test_part_file_parent() {
+  test_part_file_parent() async {
     testFile = '/proj/completion.dart';
     addSource('/proj/other.dart', 'library other;');
     addSource('/proj/foo/bar.dart', 'library bar;');
     addSource('/blat.dart', 'library blat;');
     addTestSource('library x; part "../^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 3);
-    expect(request.replacementLength, 3);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 3);
+    expect(replacementLength, 3);
     assertNotSuggested('completion.dart');
     assertNotSuggested('other.dart');
     assertNotSuggested('foo');
@@ -372,10 +368,10 @@
 }
 
 @reflectiveTest
-class UriContributorWindowsTest extends AbstractCompletionTest {
+class UriContributorWindowsTest extends DartCompletionContributorTest {
   @override
-  void setUpContributor() {
-    contributor = new UriContributor();
+  DartCompletionContributor createContributor() {
+    return new UriContributor();
   }
 
   @override
@@ -383,15 +379,15 @@
     provider = new _TestWinResourceProvider();
   }
 
-  test_import_file() {
+  test_import_file() async {
     testFile = '\\proj\\completion.dart';
     addSource('\\proj\\other.dart', 'library other;');
     addSource('\\proj\\foo\\bar.dart', 'library bar;');
     addSource('\\blat.dart', 'library blat;');
     addTestSource('import "^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset);
-    expect(request.replacementLength, 0);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset);
+    expect(replacementLength, 0);
     assertNotSuggested('completion.dart');
     assertSuggest('other.dart', csKind: CompletionSuggestionKind.IMPORT);
     assertNotSuggested('foo');
@@ -400,15 +396,15 @@
     assertNotSuggested('../blat.dart');
   }
 
-  test_import_file2() {
+  test_import_file2() async {
     testFile = '\\proj\\completion.dart';
     addSource('\\proj\\other.dart', 'library other;');
     addSource('\\proj\\foo\\bar.dart', 'library bar;');
     addSource('\\blat.dart', 'library blat;');
     addTestSource('import "..^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 2);
-    expect(request.replacementLength, 2);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 2);
+    expect(replacementLength, 2);
     assertNotSuggested('completion.dart');
     assertSuggest('other.dart', csKind: CompletionSuggestionKind.IMPORT);
     assertNotSuggested('foo');
@@ -417,15 +413,15 @@
     assertNotSuggested('../blat.dart');
   }
 
-  test_import_file_child() {
+  test_import_file_child() async {
     testFile = '\\proj\\completion.dart';
     addSource('\\proj\\other.dart', 'library other;');
     addSource('\\proj\\foo\\bar.dart', 'library bar;');
     addSource('\\blat.dart', 'library blat;');
     addTestSource('import "foo/^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 4);
-    expect(request.replacementLength, 4);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 4);
+    expect(replacementLength, 4);
     assertNotSuggested('completion.dart');
     assertNotSuggested('other.dart');
     assertNotSuggested('foo');
@@ -434,15 +430,15 @@
     assertNotSuggested('../blat.dart');
   }
 
-  test_import_file_parent() {
+  test_import_file_parent() async {
     testFile = '\\proj\\completion.dart';
     addSource('\\proj\\other.dart', 'library other;');
     addSource('\\proj\\foo\\bar.dart', 'library bar;');
     addSource('\\blat.dart', 'library blat;');
     addTestSource('import "../^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 3);
-    expect(request.replacementLength, 3);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 3);
+    expect(replacementLength, 3);
     assertNotSuggested('completion.dart');
     assertNotSuggested('other.dart');
     assertNotSuggested('foo');
@@ -451,15 +447,15 @@
     assertSuggest('../blat.dart', csKind: CompletionSuggestionKind.IMPORT);
   }
 
-  test_import_file_parent2() {
+  test_import_file_parent2() async {
     testFile = '\\proj\\completion.dart';
     addSource('\\proj\\other.dart', 'library other;');
     addSource('\\proj\\foo\\bar.dart', 'library bar;');
     addSource('\\blat.dart', 'library blat;');
     addTestSource('import "../b^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 4);
-    expect(request.replacementLength, 4);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 4);
+    expect(replacementLength, 4);
     assertNotSuggested('completion.dart');
     assertNotSuggested('other.dart');
     assertNotSuggested('foo');
@@ -468,15 +464,15 @@
     assertSuggest('../blat.dart', csKind: CompletionSuggestionKind.IMPORT);
   }
 
-  test_part_file() {
+  test_part_file() async {
     testFile = '\\proj\\completion.dart';
     addSource('\\proj\\other.dart', 'library other;');
     addSource('\\proj\\foo\\bar.dart', 'library bar;');
     addSource('\\blat.dart', 'library blat;');
     addTestSource('library x; part "^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset);
-    expect(request.replacementLength, 0);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset);
+    expect(replacementLength, 0);
     assertNotSuggested('completion.dart');
     assertSuggest('other.dart', csKind: CompletionSuggestionKind.IMPORT);
     assertNotSuggested('foo');
@@ -485,15 +481,15 @@
     assertNotSuggested('../blat.dart');
   }
 
-  test_part_file2() {
+  test_part_file2() async {
     testFile = '\\proj\\completion.dart';
     addSource('\\proj\\other.dart', 'library other;');
     addSource('\\proj\\foo\\bar.dart', 'library bar;');
     addSource('\\blat.dart', 'library blat;');
     addTestSource('library x; part "..^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 2);
-    expect(request.replacementLength, 2);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 2);
+    expect(replacementLength, 2);
     assertNotSuggested('completion.dart');
     assertSuggest('other.dart', csKind: CompletionSuggestionKind.IMPORT);
     assertNotSuggested('foo');
@@ -502,15 +498,15 @@
     assertNotSuggested('../blat.dart');
   }
 
-  test_part_file_child() {
+  test_part_file_child() async {
     testFile = '\\proj\\completion.dart';
     addSource('\\proj\\other.dart', 'library other;');
     addSource('\\proj\\foo\\bar.dart', 'library bar;');
     addSource('\\blat.dart', 'library blat;');
     addTestSource('library x; part "foo/^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 4);
-    expect(request.replacementLength, 4);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 4);
+    expect(replacementLength, 4);
     assertNotSuggested('completion.dart');
     assertNotSuggested('other.dart');
     assertNotSuggested('foo');
@@ -519,15 +515,15 @@
     assertNotSuggested('../blat.dart');
   }
 
-  test_part_file_parent() {
+  test_part_file_parent() async {
     testFile = '\\proj\\completion.dart';
     addSource('\\proj\\other.dart', 'library other;');
     addSource('\\proj\\foo\\bar.dart', 'library bar;');
     addSource('\\blat.dart', 'library blat;');
     addTestSource('library x; part "../^" import');
-    computeFast();
-    expect(request.replacementOffset, completionOffset - 3);
-    expect(request.replacementLength, 3);
+    await computeSuggestions();
+    expect(replacementOffset, completionOffset - 3);
+    expect(replacementLength, 3);
     assertNotSuggested('completion.dart');
     assertNotSuggested('other.dart');
     assertNotSuggested('foo');
diff --git a/pkg/analysis_server/test/services/completion/imported_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/imported_reference_contributor_test.dart
index 95cbb70..54ad5e1 100644
--- a/pkg/analysis_server/test/services/completion/imported_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/imported_reference_contributor_test.dart
@@ -8,7 +8,6 @@
     show Element, ElementKind;
 import 'package:analysis_server/plugin/protocol/protocol.dart'
     hide Element, ElementKind;
-import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/services/completion/dart_completion_cache.dart';
 import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
 import 'package:analysis_server/src/services/completion/imported_reference_contributor.dart';
@@ -20,7 +19,6 @@
 import 'package:unittest/unittest.dart';
 
 import '../../abstract_context.dart';
-import '../../operation/operation_queue_test.dart';
 import '../../utils.dart';
 import 'completion_test_util.dart';
 
@@ -64,13 +62,12 @@
     setUpContributor();
     int replacementOffset = request.replacementOffset;
     int replacementLength = request.replacementLength;
-    AnalysisServer server = new AnalysisServerMock();
     /*
      * Pass null for searchEngine to ensure that it is not used
      * when the cache has been populated.
      */
     request = new DartCompletionRequest(
-        server, context, testSource, completionOffset, cache);
+        context, provider, searchEngine, testSource, completionOffset, cache);
     request.replacementOffset = replacementOffset;
     request.replacementLength = replacementLength;
 
diff --git a/pkg/analysis_server/test/services/completion/inherited_computer_test.dart b/pkg/analysis_server/test/services/completion/inherited_computer_test.dart
deleted file mode 100644
index a50fa2f..0000000
--- a/pkg/analysis_server/test/services/completion/inherited_computer_test.dart
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library test.services.completion.inherited_computer_test;
-
-import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analysis_server/src/services/completion/inherited_contributor.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-import 'package:unittest/src/matcher/core_matchers.dart';
-import 'package:unittest/unittest.dart';
-
-import '../../utils.dart';
-import 'completion_test_util.dart';
-
-main() {
-  initializeTestEnvironment();
-//  defineReflectiveTests(InheritedContributorTest);
-}
-
-@reflectiveTest
-class InheritedContributorTest extends AbstractCompletionTest {
-  @override
-  void setUpContributor() {
-    contributor = new NewCompletionWrapper(new InheritedContributor());
-  }
-
-  test_fromMultipleSuperclasses() {
-    addTestSource(r'''
-class A {
-  notSuggested() => null;
-  A suggested1(int x) => null;
-  B suggested2(String y) => null;
-}
-class B extends A {
-  B suggested2(String y) => null;
-  C suggested3([String z]) => null;
-}
-class C extends B {
-  sugg^
-}
-''');
-    computeFast();
-    return computeFull((bool result) {
-      _assertOverride(
-          '@override\n  A suggested1(int x) {\n    // TODO: implement suggested1\n    return null;\n  }');
-      _assertOverride(
-          '''@override\n  B suggested2(String y) {\n    // TODO: implement suggested2\n    return null;\n  }''');
-      _assertOverride(
-          '''@override\n  C suggested3([String z]) {\n    // TODO: implement suggested3\n    return null;\n  }''');
-      assertNotSuggested(
-          '''@override\n  notSuggested() {\n    // TODO: implement notSuggested\n    return null;\n  }''');
-    });
-  }
-
-  CompletionSuggestion _assertOverride(String completion) {
-    CompletionSuggestion cs = getSuggest(
-        completion: completion,
-        csKind: CompletionSuggestionKind.IDENTIFIER,
-        elemKind: null);
-    if (cs == null) {
-      failedCompletion('expected $completion', request.suggestions);
-    }
-    expect(cs.kind, equals(CompletionSuggestionKind.IDENTIFIER));
-    expect(cs.relevance, equals(DART_RELEVANCE_HIGH));
-    expect(cs.importUri, null);
-//    expect(cs.selectionOffset, equals(completion.length));
-    expect(cs.selectionLength, equals(0));
-    expect(cs.isDeprecated, isFalse);
-    expect(cs.isPotential, isFalse);
-    expect(cs.element, isNotNull);
-    return cs;
-  }
-}
diff --git a/pkg/analysis_server/test/services/completion/test_all.dart b/pkg/analysis_server/test/services/completion/test_all.dart
index 69735da..c4adeb2 100644
--- a/pkg/analysis_server/test/services/completion/test_all.dart
+++ b/pkg/analysis_server/test/services/completion/test_all.dart
@@ -7,39 +7,29 @@
 import 'package:unittest/unittest.dart';
 
 import '../../utils.dart';
-import 'arglist_contributor_test.dart' as arglist_test;
-import 'combinator_contributor_test.dart' as combinator_test;
-import 'common_usage_computer_test.dart' as common_usage_computer_test;
 import 'completion_computer_test.dart' as completion_computer_test;
 import 'completion_manager_test.dart' as completion_manager_test;
 import 'completion_target_test.dart' as completion_target_test;
+import 'dart/test_all.dart' as dart_contributor_tests;
 import 'imported_reference_contributor_test.dart' as imported_test;
-import 'inherited_computer_test.dart' as inherited_computer_test;
-import 'keyword_contributor_test.dart' as keyword_test;
 import 'local_declaration_visitor_test.dart' as local_declaration_visitor_test;
 import 'local_reference_contributor_test.dart'
     as local_reference_contributor_test;
 import 'optype_test.dart' as optype_test;
 import 'prefixed_element_contributor_test.dart' as invocation_test;
-import 'uri_contributor_test.dart' as uri_contributor_test;
 
 /// Utility for manually running all tests.
 main() {
   initializeTestEnvironment();
   group('completion', () {
-    arglist_test.main();
-    combinator_test.main();
-    common_usage_computer_test.main();
     completion_computer_test.main();
     completion_manager_test.main();
     completion_target_test.main();
+    dart_contributor_tests.main();
     imported_test.main();
-    inherited_computer_test.main();
     invocation_test.main();
-    keyword_test.main();
     local_declaration_visitor_test.main();
     local_reference_contributor_test.main();
     optype_test.main();
-    uri_contributor_test.main();
   });
 }
diff --git a/pkg/analysis_server/test/services/correction/assist_test.dart b/pkg/analysis_server/test/services/correction/assist_test.dart
index 2885f27..48e8068 100644
--- a/pkg/analysis_server/test/services/correction/assist_test.dart
+++ b/pkg/analysis_server/test/services/correction/assist_test.dart
@@ -4,6 +4,8 @@
 
 library test.services.correction.assist;
 
+import 'dart:async';
+
 import 'package:analysis_server/plugin/edit/assist/assist_core.dart';
 import 'package:analysis_server/plugin/protocol/protocol.dart';
 import 'package:analysis_server/src/plugin/server_plugin.dart';
@@ -36,8 +38,8 @@
    * Asserts that there is an [Assist] of the given [kind] at [offset] which
    * produces the [expected] code when applied to [testCode].
    */
-  void assertHasAssist(AssistKind kind, String expected) {
-    assist = _assertHasAssist(kind);
+  assertHasAssist(AssistKind kind, String expected) async {
+    assist = await _assertHasAssist(kind);
     change = assist.change;
     // apply to "file"
     List<SourceFileEdit> fileEdits = change.edits;
@@ -50,17 +52,17 @@
   /**
    * Calls [assertHasAssist] at the offset of [offsetSearch] in [testCode].
    */
-  void assertHasAssistAt(
-      String offsetSearch, AssistKind kind, String expected) {
+  assertHasAssistAt(
+      String offsetSearch, AssistKind kind, String expected) async {
     offset = findOffset(offsetSearch);
-    assertHasAssist(kind, expected);
+    await assertHasAssist(kind, expected);
   }
 
   /**
    * Asserts that there is no [Assist] of the given [kind] at [offset].
    */
-  void assertNoAssist(AssistKind kind) {
-    List<Assist> assists = computeAssists(
+  assertNoAssist(AssistKind kind) async {
+    List<Assist> assists = await computeAssists(
         plugin, context, testUnit.element.source, offset, length);
     for (Assist assist in assists) {
       if (assist.kind == kind) {
@@ -72,9 +74,9 @@
   /**
    * Calls [assertNoAssist] at the offset of [offsetSearch] in [testCode].
    */
-  void assertNoAssistAt(String offsetSearch, AssistKind kind) {
+  assertNoAssistAt(String offsetSearch, AssistKind kind) async {
     offset = findOffset(offsetSearch);
-    assertNoAssist(kind);
+    await assertNoAssist(kind);
   }
 
   Position expectedPosition(String search) {
@@ -106,7 +108,7 @@
     manager.processPlugins([plugin]);
   }
 
-  void test_addTypeAnnotation_BAD_privateType_closureParameter() {
+  test_addTypeAnnotation_BAD_privateType_closureParameter() async {
     addSource(
         '/my_lib.dart',
         '''
@@ -121,10 +123,10 @@
   foo((test) {});
 }
  ''');
-    assertNoAssistAt('test)', DartAssistKind.ADD_TYPE_ANNOTATION);
+    await assertNoAssistAt('test)', DartAssistKind.ADD_TYPE_ANNOTATION);
   }
 
-  void test_addTypeAnnotation_BAD_privateType_declaredIdentifier() {
+  test_addTypeAnnotation_BAD_privateType_declaredIdentifier() async {
     addSource(
         '/my_lib.dart',
         '''
@@ -142,10 +144,10 @@
   }
 }
 ''');
-    assertNoAssistAt('var item', DartAssistKind.ADD_TYPE_ANNOTATION);
+    await assertNoAssistAt('var item', DartAssistKind.ADD_TYPE_ANNOTATION);
   }
 
-  void test_addTypeAnnotation_BAD_privateType_list() {
+  test_addTypeAnnotation_BAD_privateType_list() async {
     addSource(
         '/my_lib.dart',
         '''
@@ -160,10 +162,10 @@
   var v = getValues();
 }
 ''');
-    assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
+    await assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
   }
 
-  void test_addTypeAnnotation_BAD_privateType_variable() {
+  test_addTypeAnnotation_BAD_privateType_variable() async {
     addSource(
         '/my_lib.dart',
         '''
@@ -178,16 +180,16 @@
   var v = getValue();
 }
 ''');
-    assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
+    await assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
   }
 
-  void test_addTypeAnnotation_classField_OK_final() {
+  test_addTypeAnnotation_classField_OK_final() async {
     resolveTestUnit('''
 class A {
   final f = 0;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'final ',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -197,13 +199,13 @@
 ''');
   }
 
-  void test_addTypeAnnotation_classField_OK_int() {
+  test_addTypeAnnotation_classField_OK_int() async {
     resolveTestUnit('''
 class A {
   var f = 0;
 }
 ''');
-    assertHasAssistAt(
+    await await assertHasAssistAt(
         'var ',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -213,17 +215,17 @@
 ''');
   }
 
-  void test_addTypeAnnotation_declaredIdentifier_BAD_hasTypeAnnotation() {
+  test_addTypeAnnotation_declaredIdentifier_BAD_hasTypeAnnotation() async {
     resolveTestUnit('''
 main(List<String> items) {
   for (String item in items) {
   }
 }
 ''');
-    assertNoAssistAt('item in', DartAssistKind.ADD_TYPE_ANNOTATION);
+    await assertNoAssistAt('item in', DartAssistKind.ADD_TYPE_ANNOTATION);
   }
 
-  void test_addTypeAnnotation_declaredIdentifier_BAD_inForEachBody() {
+  test_addTypeAnnotation_declaredIdentifier_BAD_inForEachBody() async {
     resolveTestUnit('''
 main(List<String> items) {
   for (var item in items) {
@@ -231,10 +233,10 @@
   }
 }
 ''');
-    assertNoAssistAt('42;', DartAssistKind.ADD_TYPE_ANNOTATION);
+    await assertNoAssistAt('42;', DartAssistKind.ADD_TYPE_ANNOTATION);
   }
 
-  void test_addTypeAnnotation_declaredIdentifier_BAD_unknownType() {
+  test_addTypeAnnotation_declaredIdentifier_BAD_unknownType() async {
     verifyNoTestUnitErrors = false;
     resolveTestUnit('''
 main() {
@@ -242,10 +244,10 @@
   }
 }
 ''');
-    assertNoAssistAt('item in', DartAssistKind.ADD_TYPE_ANNOTATION);
+    await assertNoAssistAt('item in', DartAssistKind.ADD_TYPE_ANNOTATION);
   }
 
-  void test_addTypeAnnotation_declaredIdentifier_generic_OK() {
+  test_addTypeAnnotation_declaredIdentifier_generic_OK() async {
     resolveTestUnit('''
 class A<T> {
   main(List<List<T>> items) {
@@ -254,7 +256,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'item in',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -267,7 +269,7 @@
 ''');
   }
 
-  void test_addTypeAnnotation_declaredIdentifier_OK() {
+  test_addTypeAnnotation_declaredIdentifier_OK() async {
     resolveTestUnit('''
 main(List<String> items) {
   for (var item in items) {
@@ -275,7 +277,7 @@
 }
 ''');
     // on identifier
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'item in',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -285,7 +287,7 @@
 }
 ''');
     // on "for"
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'for (',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -296,7 +298,7 @@
 ''');
   }
 
-  void test_addTypeAnnotation_declaredIdentifier_OK_addImport_dartUri() {
+  test_addTypeAnnotation_declaredIdentifier_OK_addImport_dartUri() async {
     addSource(
         '/my_lib.dart',
         r'''
@@ -310,7 +312,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'future in',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -323,14 +325,14 @@
 ''');
   }
 
-  void test_addTypeAnnotation_declaredIdentifier_OK_final() {
+  test_addTypeAnnotation_declaredIdentifier_OK_final() async {
     resolveTestUnit('''
 main(List<String> items) {
   for (final item in items) {
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'item in',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -341,7 +343,54 @@
 ''');
   }
 
-  void test_addTypeAnnotation_local_generic_OK_literal() {
+  test_addTypeAnnotation_local_BAD_hasTypeAnnotation() async {
+    resolveTestUnit('''
+main() {
+  int v = 42;
+}
+''');
+    await assertNoAssistAt(' = 42', DartAssistKind.ADD_TYPE_ANNOTATION);
+  }
+
+  test_addTypeAnnotation_local_BAD_multiple() async {
+    resolveTestUnit('''
+main() {
+  var a = 1, b = '';
+}
+''');
+    await assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
+  }
+
+  test_addTypeAnnotation_local_BAD_noValue() async {
+    verifyNoTestUnitErrors = false;
+    resolveTestUnit('''
+main() {
+  var v;
+}
+''');
+    await assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
+  }
+
+  test_addTypeAnnotation_local_BAD_null() async {
+    resolveTestUnit('''
+main() {
+  var v = null;
+}
+''');
+    await assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
+  }
+
+  test_addTypeAnnotation_local_BAD_unknown() async {
+    verifyNoTestUnitErrors = false;
+    resolveTestUnit('''
+main() {
+  var v = unknownVar;
+}
+''');
+    await assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
+  }
+
+  test_addTypeAnnotation_local_generic_OK_literal() async {
     resolveTestUnit('''
 class A {
   main(List<int> items) {
@@ -349,7 +398,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'v =',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -361,7 +410,7 @@
 ''');
   }
 
-  void test_addTypeAnnotation_local_generic_OK_local() {
+  test_addTypeAnnotation_local_generic_OK_local() async {
     resolveTestUnit('''
 class A<T> {
   main(List<T> items) {
@@ -369,7 +418,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'v =',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -381,7 +430,7 @@
 ''');
   }
 
-  void test_addTypeAnnotation_local_OK_addImport_dartUri() {
+  test_addTypeAnnotation_local_OK_addImport_dartUri() async {
     addSource(
         '/my_lib.dart',
         r'''
@@ -394,7 +443,7 @@
   var v = getFutureInt();
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'v =',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -406,7 +455,7 @@
 ''');
   }
 
-  void test_addTypeAnnotation_local_OK_addImport_notLibraryUnit() {
+  test_addTypeAnnotation_local_OK_addImport_notLibraryUnit() async {
     // prepare library
     addSource(
         '/my_lib.dart',
@@ -437,7 +486,7 @@
     testLibraryElement = testUnitElement.library;
     // prepare the assist
     offset = findOffset('v = ');
-    assist = _assertHasAssist(DartAssistKind.ADD_TYPE_ANNOTATION);
+    assist = await _assertHasAssist(DartAssistKind.ADD_TYPE_ANNOTATION);
     change = assist.change;
     // verify
     {
@@ -466,7 +515,7 @@
     }
   }
 
-  void test_addTypeAnnotation_local_OK_addImport_relUri() {
+  test_addTypeAnnotation_local_OK_addImport_relUri() async {
     addSource(
         '/aa/bbb/lib_a.dart',
         r'''
@@ -484,7 +533,7 @@
   var v = newMyClass();
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'v =',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -496,13 +545,13 @@
 ''');
   }
 
-  void test_addTypeAnnotation_local_OK_Function() {
+  test_addTypeAnnotation_local_OK_Function() async {
     resolveTestUnit('''
 main() {
   var v = () => 1;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'v =',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -512,13 +561,13 @@
 ''');
   }
 
-  void test_addTypeAnnotation_local_OK_int() {
+  test_addTypeAnnotation_local_OK_int() async {
     resolveTestUnit('''
 main() {
   var v = 0;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'v =',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -528,13 +577,13 @@
 ''');
   }
 
-  void test_addTypeAnnotation_local_OK_List() {
+  test_addTypeAnnotation_local_OK_List() async {
     resolveTestUnit('''
 main() {
   var v = <String>[];
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'v =',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -544,7 +593,7 @@
 ''');
   }
 
-  void test_addTypeAnnotation_local_OK_localType() {
+  test_addTypeAnnotation_local_OK_localType() async {
     resolveTestUnit('''
 class C {}
 C f() => null;
@@ -552,7 +601,7 @@
   var x = f();
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'x =',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -564,13 +613,13 @@
 ''');
   }
 
-  void test_addTypeAnnotation_local_OK_onInitializer() {
+  test_addTypeAnnotation_local_OK_onInitializer() async {
     resolveTestUnit('''
 main() {
   var v = 123;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '23',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -580,13 +629,13 @@
 ''');
   }
 
-  void test_addTypeAnnotation_local_OK_onName() {
+  test_addTypeAnnotation_local_OK_onName() async {
     resolveTestUnit('''
 main() {
   var abc = 0;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'bc',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -596,13 +645,13 @@
 ''');
   }
 
-  void test_addTypeAnnotation_local_OK_onVar() {
+  test_addTypeAnnotation_local_OK_onVar() async {
     resolveTestUnit('''
 main() {
   var v = 0;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'var ',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -612,13 +661,13 @@
 ''');
   }
 
-  void test_addTypeAnnotation_local_OK_onVariableDeclarationStatement() {
+  test_addTypeAnnotation_local_OK_onVariableDeclarationStatement() async {
     resolveTestUnit('''
 main() {
   var v = 123; // marker
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         ' // marker',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -628,54 +677,7 @@
 ''');
   }
 
-  void test_addTypeAnnotation_local_wrong_hasTypeAnnotation() {
-    resolveTestUnit('''
-main() {
-  int v = 42;
-}
-''');
-    assertNoAssistAt(' = 42', DartAssistKind.ADD_TYPE_ANNOTATION);
-  }
-
-  void test_addTypeAnnotation_local_wrong_multiple() {
-    resolveTestUnit('''
-main() {
-  var a = 1, b = '';
-}
-''');
-    assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
-  }
-
-  void test_addTypeAnnotation_local_wrong_noValue() {
-    verifyNoTestUnitErrors = false;
-    resolveTestUnit('''
-main() {
-  var v;
-}
-''');
-    assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
-  }
-
-  void test_addTypeAnnotation_local_wrong_null() {
-    resolveTestUnit('''
-main() {
-  var v = null;
-}
-''');
-    assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
-  }
-
-  void test_addTypeAnnotation_local_wrong_unknown() {
-    verifyNoTestUnitErrors = false;
-    resolveTestUnit('''
-main() {
-  var v = unknownVar;
-}
-''');
-    assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
-  }
-
-  void test_addTypeAnnotation_OK_privateType_sameLibrary() {
+  test_addTypeAnnotation_OK_privateType_sameLibrary() async {
     resolveTestUnit('''
 class _A {}
 _A getValue() => new _A();
@@ -683,7 +685,7 @@
   var v = getValue();
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'var ',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -695,34 +697,34 @@
 ''');
   }
 
-  void test_addTypeAnnotation_parameter_BAD_hasExplicitType() {
+  test_addTypeAnnotation_parameter_BAD_hasExplicitType() async {
     resolveTestUnit('''
 foo(f(int p)) {}
 main() {
   foo((num test) {});
 }
 ''');
-    assertNoAssistAt('test', DartAssistKind.ADD_TYPE_ANNOTATION);
+    await assertNoAssistAt('test', DartAssistKind.ADD_TYPE_ANNOTATION);
   }
 
-  void test_addTypeAnnotation_parameter_BAD_noPropagatedType() {
+  test_addTypeAnnotation_parameter_BAD_noPropagatedType() async {
     resolveTestUnit('''
 foo(f(p)) {}
 main() {
   foo((test) {});
 }
 ''');
-    assertNoAssistAt('test', DartAssistKind.ADD_TYPE_ANNOTATION);
+    await assertNoAssistAt('test', DartAssistKind.ADD_TYPE_ANNOTATION);
   }
 
-  void test_addTypeAnnotation_parameter_OK() {
+  test_addTypeAnnotation_parameter_OK() async {
     resolveTestUnit('''
 foo(f(int p)) {}
 main() {
   foo((test) {});
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'test',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -733,11 +735,25 @@
 ''');
   }
 
-  void test_addTypeAnnotation_topLevelField_OK_int() {
+  test_addTypeAnnotation_topLevelField_BAD_multiple() async {
+    resolveTestUnit('''
+var A = 1, V = '';
+''');
+    await assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
+  }
+
+  test_addTypeAnnotation_topLevelField_BAD_noValue() async {
+    resolveTestUnit('''
+var V;
+''');
+    await assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
+  }
+
+  test_addTypeAnnotation_topLevelField_OK_int() async {
     resolveTestUnit('''
 var V = 0;
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'var ',
         DartAssistKind.ADD_TYPE_ANNOTATION,
         '''
@@ -745,21 +761,7 @@
 ''');
   }
 
-  void test_addTypeAnnotation_topLevelField_wrong_multiple() {
-    resolveTestUnit('''
-var A = 1, V = '';
-''');
-    assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
-  }
-
-  void test_addTypeAnnotation_topLevelField_wrong_noValue() {
-    resolveTestUnit('''
-var V;
-''');
-    assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
-  }
-
-  void test_assignToLocalVariable() {
+  test_assignToLocalVariable() async {
     resolveTestUnit('''
 main() {
   List<int> bytes;
@@ -767,7 +769,7 @@
 }
 List<int> readBytes() => <int>[];
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'readBytes();',
         DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE,
         '''
@@ -784,17 +786,17 @@
             ['list', 'bytes2', 'readBytes']));
   }
 
-  void test_assignToLocalVariable_alreadyAssignment() {
+  test_assignToLocalVariable_alreadyAssignment() async {
     resolveTestUnit('''
 main() {
   var vvv;
   vvv = 42;
 }
 ''');
-    assertNoAssistAt('vvv =', DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE);
+    await assertNoAssistAt('vvv =', DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE);
   }
 
-  void test_assignToLocalVariable_inClosure() {
+  test_assignToLocalVariable_inClosure() async {
     resolveTestUnit(r'''
 main() {
   print(() {
@@ -802,7 +804,7 @@
   });
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '345',
         DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE,
         '''
@@ -814,42 +816,199 @@
 ''');
   }
 
-  void test_assignToLocalVariable_invocationArgument() {
+  test_assignToLocalVariable_invocationArgument() async {
     resolveTestUnit(r'''
 main() {
   f(12345);
 }
 int f(p) {}
 ''');
-    assertNoAssistAt('345', DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE);
+    await assertNoAssistAt('345', DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE);
   }
 
-  void test_assignToLocalVariable_throw() {
+  test_assignToLocalVariable_throw() async {
     resolveTestUnit('''
 main() {
   throw 42;
 }
 ''');
-    assertNoAssistAt('throw ', DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE);
+    await assertNoAssistAt('throw ', DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE);
   }
 
-  void test_assignToLocalVariable_void() {
+  test_assignToLocalVariable_void() async {
     resolveTestUnit('''
 main() {
   f();
 }
 void f() {}
 ''');
-    assertNoAssistAt('f();', DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE);
+    await assertNoAssistAt('f();', DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE);
   }
 
-  void test_convertToBlockBody_OK_async() {
+  test_convertDocumentationIntoBlock_BAD_alreadyBlock() async {
+    resolveTestUnit('''
+/**
+ * AAAAAAA
+ */
+class A {}
+''');
+    await assertNoAssistAt(
+        'AAA', DartAssistKind.CONVERT_DOCUMENTATION_INTO_BLOCK);
+  }
+
+  test_convertDocumentationIntoBlock_BAD_notDocumentation() async {
+    resolveTestUnit('''
+// AAAA
+class A {}
+''');
+    await assertNoAssistAt(
+        'AAA', DartAssistKind.CONVERT_DOCUMENTATION_INTO_BLOCK);
+  }
+
+  test_convertDocumentationIntoBlock_OK_onReference() async {
+    resolveTestUnit('''
+/// AAAAAAA [int] AAAAAAA
+class A {}
+''');
+    await assertHasAssistAt(
+        'nt]',
+        DartAssistKind.CONVERT_DOCUMENTATION_INTO_BLOCK,
+        '''
+/**
+ * AAAAAAA [int] AAAAAAA
+ */
+class A {}
+''');
+  }
+
+  test_convertDocumentationIntoBlock_OK_onText() async {
+    resolveTestUnit('''
+class A {
+  /// AAAAAAA [int] AAAAAAA
+  /// BBBBBBBB BBBB BBBB
+  /// CCC [A] CCCCCCCCCCC
+  mmm() {}
+}
+''');
+    await assertHasAssistAt(
+        'AAA [',
+        DartAssistKind.CONVERT_DOCUMENTATION_INTO_BLOCK,
+        '''
+class A {
+  /**
+   * AAAAAAA [int] AAAAAAA
+   * BBBBBBBB BBBB BBBB
+   * CCC [A] CCCCCCCCCCC
+   */
+  mmm() {}
+}
+''');
+  }
+
+  test_convertDocumentationIntoLine_BAD_alreadyLine() async {
+    resolveTestUnit('''
+/// AAAAAAA
+class A {}
+''');
+    await assertNoAssistAt(
+        'AAA', DartAssistKind.CONVERT_DOCUMENTATION_INTO_LINE);
+  }
+
+  test_convertDocumentationIntoLine_BAD_notDocumentation() async {
+    resolveTestUnit('''
+/* AAAA */
+class A {}
+''');
+    await assertNoAssistAt(
+        'AAA', DartAssistKind.CONVERT_DOCUMENTATION_INTO_LINE);
+  }
+
+  test_convertDocumentationIntoLine_OK_onReference() async {
+    resolveTestUnit('''
+/**
+ * AAAAAAA [int] AAAAAAA
+ */
+class A {}
+''');
+    await assertHasAssistAt(
+        'nt]',
+        DartAssistKind.CONVERT_DOCUMENTATION_INTO_LINE,
+        '''
+/// AAAAAAA [int] AAAAAAA
+class A {}
+''');
+  }
+
+  test_convertDocumentationIntoLine_OK_onText() async {
+    resolveTestUnit('''
+class A {
+  /**
+   * AAAAAAA [int] AAAAAAA
+   * BBBBBBBB BBBB BBBB
+   * CCC [A] CCCCCCCCCCC
+   */
+  mmm() {}
+}
+''');
+    await assertHasAssistAt(
+        'AAA [',
+        DartAssistKind.CONVERT_DOCUMENTATION_INTO_LINE,
+        '''
+class A {
+  /// AAAAAAA [int] AAAAAAA
+  /// BBBBBBBB BBBB BBBB
+  /// CCC [A] CCCCCCCCCCC
+  mmm() {}
+}
+''');
+  }
+
+  test_convertDocumentationIntoLine_OK_onText_hasFirstLine() async {
+    resolveTestUnit('''
+class A {
+  /** AAAAAAA [int] AAAAAAA
+   * BBBBBBBB BBBB BBBB
+   * CCC [A] CCCCCCCCCCC
+   */
+  mmm() {}
+}
+''');
+    await assertHasAssistAt(
+        'AAA [',
+        DartAssistKind.CONVERT_DOCUMENTATION_INTO_LINE,
+        '''
+class A {
+  /// AAAAAAA [int] AAAAAAA
+  /// BBBBBBBB BBBB BBBB
+  /// CCC [A] CCCCCCCCCCC
+  mmm() {}
+}
+''');
+  }
+
+  test_convertToBlockBody_BAD_noEnclosingFunction() async {
+    resolveTestUnit('''
+var v = 123;
+''');
+    await assertNoAssistAt('v =', DartAssistKind.CONVERT_INTO_BLOCK_BODY);
+  }
+
+  test_convertToBlockBody_BAD_notExpressionBlock() async {
+    resolveTestUnit('''
+fff() {
+  return 123;
+}
+''');
+    await assertNoAssistAt('fff() {', DartAssistKind.CONVERT_INTO_BLOCK_BODY);
+  }
+
+  test_convertToBlockBody_OK_async() async {
     resolveTestUnit('''
 class A {
   mmm() async => 123;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'mmm()',
         DartAssistKind.CONVERT_INTO_BLOCK_BODY,
         '''
@@ -861,14 +1020,14 @@
 ''');
   }
 
-  void test_convertToBlockBody_OK_closure() {
+  test_convertToBlockBody_OK_closure() async {
     resolveTestUnit('''
 setup(x) {}
 main() {
   setup(() => 42);
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '() => 42',
         DartAssistKind.CONVERT_INTO_BLOCK_BODY,
         '''
@@ -887,14 +1046,14 @@
     }
   }
 
-  void test_convertToBlockBody_OK_closure_voidExpression() {
+  test_convertToBlockBody_OK_closure_voidExpression() async {
     resolveTestUnit('''
 setup(x) {}
 main() {
   setup(() => print('done'));
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '() => print',
         DartAssistKind.CONVERT_INTO_BLOCK_BODY,
         '''
@@ -913,13 +1072,13 @@
     }
   }
 
-  void test_convertToBlockBody_OK_constructor() {
+  test_convertToBlockBody_OK_constructor() async {
     resolveTestUnit('''
 class A {
   factory A() => null;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'A()',
         DartAssistKind.CONVERT_INTO_BLOCK_BODY,
         '''
@@ -931,13 +1090,13 @@
 ''');
   }
 
-  void test_convertToBlockBody_OK_method() {
+  test_convertToBlockBody_OK_method() async {
     resolveTestUnit('''
 class A {
   mmm() => 123;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'mmm()',
         DartAssistKind.CONVERT_INTO_BLOCK_BODY,
         '''
@@ -949,11 +1108,11 @@
 ''');
   }
 
-  void test_convertToBlockBody_OK_onName() {
+  test_convertToBlockBody_OK_onName() async {
     resolveTestUnit('''
 fff() => 123;
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'fff()',
         DartAssistKind.CONVERT_INTO_BLOCK_BODY,
         '''
@@ -963,11 +1122,11 @@
 ''');
   }
 
-  void test_convertToBlockBody_OK_onValue() {
+  test_convertToBlockBody_OK_onValue() async {
     resolveTestUnit('''
 fff() => 123;
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '23;',
         DartAssistKind.CONVERT_INTO_BLOCK_BODY,
         '''
@@ -977,23 +1136,53 @@
 ''');
   }
 
-  void test_convertToBlockBody_wrong_noEnclosingFunction() {
+  test_convertToExpressionBody_BAD_already() async {
     resolveTestUnit('''
-var v = 123;
+fff() => 42;
 ''');
-    assertNoAssistAt('v =', DartAssistKind.CONVERT_INTO_BLOCK_BODY);
+    await assertNoAssistAt(
+        'fff()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
   }
 
-  void test_convertToBlockBody_wrong_notExpressionBlock() {
+  test_convertToExpressionBody_BAD_moreThanOneStatement() async {
     resolveTestUnit('''
 fff() {
-  return 123;
+  var v = 42;
+  return v;
 }
 ''');
-    assertNoAssistAt('fff() {', DartAssistKind.CONVERT_INTO_BLOCK_BODY);
+    await assertNoAssistAt(
+        'fff()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
   }
 
-  void test_convertToExpressionBody_OK_async() {
+  test_convertToExpressionBody_BAD_noEnclosingFunction() async {
+    resolveTestUnit('''
+var V = 42;
+''');
+    await assertNoAssistAt('V = ', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
+  }
+
+  test_convertToExpressionBody_BAD_noReturn() async {
+    resolveTestUnit('''
+fff() {
+  var v = 42;
+}
+''');
+    await assertNoAssistAt(
+        'fff()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
+  }
+
+  test_convertToExpressionBody_BAD_noReturnValue() async {
+    resolveTestUnit('''
+fff() {
+  return;
+}
+''');
+    await assertNoAssistAt(
+        'fff()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
+  }
+
+  test_convertToExpressionBody_OK_async() async {
     resolveTestUnit('''
 class A {
   mmm() async {
@@ -1001,7 +1190,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'mmm',
         DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
         '''
@@ -1011,7 +1200,7 @@
 ''');
   }
 
-  void test_convertToExpressionBody_OK_closure() {
+  test_convertToExpressionBody_OK_closure() async {
     resolveTestUnit('''
 setup(x) {}
 main() {
@@ -1020,7 +1209,7 @@
   });
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '42;',
         DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
         '''
@@ -1031,7 +1220,7 @@
 ''');
   }
 
-  void test_convertToExpressionBody_OK_closure_voidExpression() {
+  test_convertToExpressionBody_OK_closure_voidExpression() async {
     resolveTestUnit('''
 setup(x) {}
 main() {
@@ -1040,7 +1229,7 @@
   });
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'print(',
         DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
         '''
@@ -1051,7 +1240,7 @@
 ''');
   }
 
-  void test_convertToExpressionBody_OK_constructor() {
+  test_convertToExpressionBody_OK_constructor() async {
     resolveTestUnit('''
 class A {
   factory A() {
@@ -1059,7 +1248,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'A()',
         DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
         '''
@@ -1069,13 +1258,13 @@
 ''');
   }
 
-  void test_convertToExpressionBody_OK_function_onBlock() {
+  test_convertToExpressionBody_OK_function_onBlock() async {
     resolveTestUnit('''
 fff() {
   return 42;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '{',
         DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
         '''
@@ -1083,13 +1272,13 @@
 ''');
   }
 
-  void test_convertToExpressionBody_OK_function_onName() {
+  test_convertToExpressionBody_OK_function_onName() async {
     resolveTestUnit('''
 fff() {
   return 42;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'ff()',
         DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
         '''
@@ -1097,7 +1286,7 @@
 ''');
   }
 
-  void test_convertToExpressionBody_OK_method_onBlock() {
+  test_convertToExpressionBody_OK_method_onBlock() async {
     resolveTestUnit('''
 class A {
   m() { // marker
@@ -1105,7 +1294,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '{ // marker',
         DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
         '''
@@ -1115,13 +1304,13 @@
 ''');
   }
 
-  void test_convertToExpressionBody_OK_topFunction_onReturnStatement() {
+  test_convertToExpressionBody_OK_topFunction_onReturnStatement() async {
     resolveTestUnit('''
 fff() {
   return 42;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'return',
         DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
         '''
@@ -1129,49 +1318,7 @@
 ''');
   }
 
-  void test_convertToExpressionBody_wrong_already() {
-    resolveTestUnit('''
-fff() => 42;
-''');
-    assertNoAssistAt('fff()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
-  }
-
-  void test_convertToExpressionBody_wrong_moreThanOneStatement() {
-    resolveTestUnit('''
-fff() {
-  var v = 42;
-  return v;
-}
-''');
-    assertNoAssistAt('fff()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
-  }
-
-  void test_convertToExpressionBody_wrong_noEnclosingFunction() {
-    resolveTestUnit('''
-var V = 42;
-''');
-    assertNoAssistAt('V = ', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
-  }
-
-  void test_convertToExpressionBody_wrong_noReturn() {
-    resolveTestUnit('''
-fff() {
-  var v = 42;
-}
-''');
-    assertNoAssistAt('fff()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
-  }
-
-  void test_convertToExpressionBody_wrong_noReturnValue() {
-    resolveTestUnit('''
-fff() {
-  return;
-}
-''');
-    assertNoAssistAt('fff()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
-  }
-
-  void test_convertToFieldParameter_BAD_additionalUse() {
+  test_convertToFieldParameter_BAD_additionalUse() async {
     resolveTestUnit('''
 class A {
   int aaa2;
@@ -1179,20 +1326,20 @@
   A(int aaa) : aaa2 = aaa, bbb2 = aaa;
 }
 ''');
-    assertNoAssistAt('aaa)', DartAssistKind.CONVERT_TO_FIELD_PARAMETER);
+    await assertNoAssistAt('aaa)', DartAssistKind.CONVERT_TO_FIELD_PARAMETER);
   }
 
-  void test_convertToFieldParameter_BAD_notPureAssignment() {
+  test_convertToFieldParameter_BAD_notPureAssignment() async {
     resolveTestUnit('''
 class A {
   int aaa2;
   A(int aaa) : aaa2 = aaa * 2;
 }
 ''');
-    assertNoAssistAt('aaa)', DartAssistKind.CONVERT_TO_FIELD_PARAMETER);
+    await assertNoAssistAt('aaa)', DartAssistKind.CONVERT_TO_FIELD_PARAMETER);
   }
 
-  void test_convertToFieldParameter_OK_firstInitializer() {
+  test_convertToFieldParameter_OK_firstInitializer() async {
     resolveTestUnit('''
 class A {
   double aaa2;
@@ -1200,7 +1347,7 @@
   A(int aaa, int bbb) : aaa2 = aaa, bbb2 = bbb;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'aaa, ',
         DartAssistKind.CONVERT_TO_FIELD_PARAMETER,
         '''
@@ -1212,7 +1359,7 @@
 ''');
   }
 
-  void test_convertToFieldParameter_OK_onParameterName_inInitializer() {
+  test_convertToFieldParameter_OK_onParameterName_inInitializer() async {
     resolveTestUnit('''
 class A {
   int test2;
@@ -1220,7 +1367,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'test {',
         DartAssistKind.CONVERT_TO_FIELD_PARAMETER,
         '''
@@ -1232,7 +1379,7 @@
 ''');
   }
 
-  void test_convertToFieldParameter_OK_onParameterName_inParameters() {
+  test_convertToFieldParameter_OK_onParameterName_inParameters() async {
     resolveTestUnit('''
 class A {
   int test;
@@ -1240,7 +1387,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'test)',
         DartAssistKind.CONVERT_TO_FIELD_PARAMETER,
         '''
@@ -1252,7 +1399,7 @@
 ''');
   }
 
-  void test_convertToFieldParameter_OK_secondInitializer() {
+  test_convertToFieldParameter_OK_secondInitializer() async {
     resolveTestUnit('''
 class A {
   double aaa2;
@@ -1260,7 +1407,7 @@
   A(int aaa, int bbb) : aaa2 = aaa, bbb2 = bbb;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'bbb)',
         DartAssistKind.CONVERT_TO_FIELD_PARAMETER,
         '''
@@ -1272,16 +1419,17 @@
 ''');
   }
 
-  void test_convertToForIndex_BAD_bodyNotBlock() {
+  test_convertToForIndex_BAD_bodyNotBlock() async {
     resolveTestUnit('''
 main(List<String> items) {
   for (String item in items) print(item);
 }
 ''');
-    assertNoAssistAt('for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX);
+    await assertNoAssistAt(
+        'for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX);
   }
 
-  void test_convertToForIndex_BAD_doesNotDeclareVariable() {
+  test_convertToForIndex_BAD_doesNotDeclareVariable() async {
     resolveTestUnit('''
 main(List<String> items) {
   String item;
@@ -1290,10 +1438,10 @@
   }
 }
 ''');
-    assertNoAssistAt('for (item', DartAssistKind.CONVERT_INTO_FOR_INDEX);
+    await assertNoAssistAt('for (item', DartAssistKind.CONVERT_INTO_FOR_INDEX);
   }
 
-  void test_convertToForIndex_BAD_iterableIsNotVariable() {
+  test_convertToForIndex_BAD_iterableIsNotVariable() async {
     resolveTestUnit('''
 main() {
   for (String item in ['a', 'b', 'c']) {
@@ -1301,10 +1449,11 @@
   }
 }
 ''');
-    assertNoAssistAt('for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX);
+    await assertNoAssistAt(
+        'for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX);
   }
 
-  void test_convertToForIndex_BAD_iterableNotList() {
+  test_convertToForIndex_BAD_iterableNotList() async {
     resolveTestUnit('''
 main(Iterable<String> items) {
   for (String item in items) {
@@ -1312,10 +1461,11 @@
   }
 }
 ''');
-    assertNoAssistAt('for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX);
+    await assertNoAssistAt(
+        'for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX);
   }
 
-  void test_convertToForIndex_BAD_usesIJK() {
+  test_convertToForIndex_BAD_usesIJK() async {
     resolveTestUnit('''
 main(List<String> items) {
   for (String item in items) {
@@ -1324,10 +1474,11 @@
   }
 }
 ''');
-    assertNoAssistAt('for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX);
+    await assertNoAssistAt(
+        'for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX);
   }
 
-  void test_convertToForIndex_OK_onDeclaredIdentifier_name() {
+  test_convertToForIndex_OK_onDeclaredIdentifier_name() async {
     resolveTestUnit('''
 main(List<String> items) {
   for (String item in items) {
@@ -1335,7 +1486,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'item in',
         DartAssistKind.CONVERT_INTO_FOR_INDEX,
         '''
@@ -1348,7 +1499,7 @@
 ''');
   }
 
-  void test_convertToForIndex_OK_onDeclaredIdentifier_type() {
+  test_convertToForIndex_OK_onDeclaredIdentifier_type() async {
     resolveTestUnit('''
 main(List<String> items) {
   for (String item in items) {
@@ -1356,7 +1507,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'tring item',
         DartAssistKind.CONVERT_INTO_FOR_INDEX,
         '''
@@ -1369,7 +1520,7 @@
 ''');
   }
 
-  void test_convertToForIndex_OK_onFor() {
+  test_convertToForIndex_OK_onFor() async {
     resolveTestUnit('''
 main(List<String> items) {
   for (String item in items) {
@@ -1377,7 +1528,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'for (String',
         DartAssistKind.CONVERT_INTO_FOR_INDEX,
         '''
@@ -1390,7 +1541,7 @@
 ''');
   }
 
-  void test_convertToForIndex_OK_usesI() {
+  test_convertToForIndex_OK_usesI() async {
     resolveTestUnit('''
 main(List<String> items) {
   for (String item in items) {
@@ -1398,7 +1549,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'for (String',
         DartAssistKind.CONVERT_INTO_FOR_INDEX,
         '''
@@ -1411,7 +1562,7 @@
 ''');
   }
 
-  void test_convertToForIndex_OK_usesIJ() {
+  test_convertToForIndex_OK_usesIJ() async {
     resolveTestUnit('''
 main(List<String> items) {
   for (String item in items) {
@@ -1420,7 +1571,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'for (String',
         DartAssistKind.CONVERT_INTO_FOR_INDEX,
         '''
@@ -1434,13 +1585,96 @@
 ''');
   }
 
-  void test_convertToIsNot_OK_childOfIs_left() {
+  test_convertToIsNot_BAD_is_alreadyIsNot() async {
+    resolveTestUnit('''
+main(p) {
+  p is! String;
+}
+''');
+    await assertNoAssistAt('is!', DartAssistKind.CONVERT_INTO_IS_NOT);
+  }
+
+  test_convertToIsNot_BAD_is_noEnclosingParenthesis() async {
+    resolveTestUnit('''
+main(p) {
+  p is String;
+}
+''');
+    await assertNoAssistAt('is String', DartAssistKind.CONVERT_INTO_IS_NOT);
+  }
+
+  test_convertToIsNot_BAD_is_noPrefix() async {
+    resolveTestUnit('''
+main(p) {
+  (p is String);
+}
+''');
+    await assertNoAssistAt('is String', DartAssistKind.CONVERT_INTO_IS_NOT);
+  }
+
+  test_convertToIsNot_BAD_is_notIsExpression() async {
+    resolveTestUnit('''
+main(p) {
+  123 + 456;
+}
+''');
+    await assertNoAssistAt('123 +', DartAssistKind.CONVERT_INTO_IS_NOT);
+  }
+
+  test_convertToIsNot_BAD_is_notTheNotOperator() async {
+    verifyNoTestUnitErrors = false;
+    resolveTestUnit('''
+main(p) {
+  ++(p is String);
+}
+''');
+    await assertNoAssistAt('is String', DartAssistKind.CONVERT_INTO_IS_NOT);
+  }
+
+  test_convertToIsNot_BAD_not_alreadyIsNot() async {
+    resolveTestUnit('''
+main(p) {
+  !(p is! String);
+}
+''');
+    await assertNoAssistAt('!(p', DartAssistKind.CONVERT_INTO_IS_NOT);
+  }
+
+  test_convertToIsNot_BAD_not_noEnclosingParenthesis() async {
+    resolveTestUnit('''
+main(p) {
+  !p;
+}
+''');
+    await assertNoAssistAt('!p', DartAssistKind.CONVERT_INTO_IS_NOT);
+  }
+
+  test_convertToIsNot_BAD_not_notIsExpression() async {
+    resolveTestUnit('''
+main(p) {
+  !(p == null);
+}
+''');
+    await assertNoAssistAt('!(p', DartAssistKind.CONVERT_INTO_IS_NOT);
+  }
+
+  test_convertToIsNot_BAD_not_notTheNotOperator() async {
+    verifyNoTestUnitErrors = false;
+    resolveTestUnit('''
+main(p) {
+  ++(p is String);
+}
+''');
+    await assertNoAssistAt('++(', DartAssistKind.CONVERT_INTO_IS_NOT);
+  }
+
+  test_convertToIsNot_OK_childOfIs_left() async {
     resolveTestUnit('''
 main(p) {
   !(p is String);
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'p is',
         DartAssistKind.CONVERT_INTO_IS_NOT,
         '''
@@ -1450,13 +1684,13 @@
 ''');
   }
 
-  void test_convertToIsNot_OK_childOfIs_right() {
+  test_convertToIsNot_OK_childOfIs_right() async {
     resolveTestUnit('''
 main(p) {
   !(p is String);
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'String)',
         DartAssistKind.CONVERT_INTO_IS_NOT,
         '''
@@ -1466,13 +1700,13 @@
 ''');
   }
 
-  void test_convertToIsNot_OK_is() {
+  test_convertToIsNot_OK_is() async {
     resolveTestUnit('''
 main(p) {
   !(p is String);
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'is String',
         DartAssistKind.CONVERT_INTO_IS_NOT,
         '''
@@ -1482,13 +1716,13 @@
 ''');
   }
 
-  void test_convertToIsNot_OK_is_higherPrecedencePrefix() {
+  test_convertToIsNot_OK_is_higherPrecedencePrefix() async {
     resolveTestUnit('''
 main(p) {
   !!(p is String);
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'is String',
         DartAssistKind.CONVERT_INTO_IS_NOT,
         '''
@@ -1498,13 +1732,13 @@
 ''');
   }
 
-  void test_convertToIsNot_OK_is_not_higherPrecedencePrefix() {
+  test_convertToIsNot_OK_is_not_higherPrecedencePrefix() async {
     resolveTestUnit('''
 main(p) {
   !!(p is String);
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '!(p',
         DartAssistKind.CONVERT_INTO_IS_NOT,
         '''
@@ -1514,13 +1748,13 @@
 ''');
   }
 
-  void test_convertToIsNot_OK_not() {
+  test_convertToIsNot_OK_not() async {
     resolveTestUnit('''
 main(p) {
   !(p is String);
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '!(p',
         DartAssistKind.CONVERT_INTO_IS_NOT,
         '''
@@ -1530,13 +1764,13 @@
 ''');
   }
 
-  void test_convertToIsNot_OK_parentheses() {
+  test_convertToIsNot_OK_parentheses() async {
     resolveTestUnit('''
 main(p) {
   !(p is String);
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '(p is',
         DartAssistKind.CONVERT_INTO_IS_NOT,
         '''
@@ -1546,96 +1780,56 @@
 ''');
   }
 
-  void test_convertToIsNot_wrong_is_alreadyIsNot() {
-    resolveTestUnit('''
-main(p) {
-  p is! String;
-}
-''');
-    assertNoAssistAt('is!', DartAssistKind.CONVERT_INTO_IS_NOT);
-  }
-
-  void test_convertToIsNot_wrong_is_noEnclosingParenthesis() {
-    resolveTestUnit('''
-main(p) {
-  p is String;
-}
-''');
-    assertNoAssistAt('is String', DartAssistKind.CONVERT_INTO_IS_NOT);
-  }
-
-  void test_convertToIsNot_wrong_is_noPrefix() {
-    resolveTestUnit('''
-main(p) {
-  (p is String);
-}
-''');
-    assertNoAssistAt('is String', DartAssistKind.CONVERT_INTO_IS_NOT);
-  }
-
-  void test_convertToIsNot_wrong_is_notIsExpression() {
-    resolveTestUnit('''
-main(p) {
-  123 + 456;
-}
-''');
-    assertNoAssistAt('123 +', DartAssistKind.CONVERT_INTO_IS_NOT);
-  }
-
-  void test_convertToIsNot_wrong_is_notTheNotOperator() {
+  test_convertToIsNotEmpty_BAD_noBang() async {
     verifyNoTestUnitErrors = false;
     resolveTestUnit('''
-main(p) {
-  ++(p is String);
+main(String str) {
+  ~str.isEmpty;
 }
 ''');
-    assertNoAssistAt('is String', DartAssistKind.CONVERT_INTO_IS_NOT);
+    await assertNoAssistAt(
+        'isEmpty;', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY);
   }
 
-  void test_convertToIsNot_wrong_not_alreadyIsNot() {
+  test_convertToIsNotEmpty_BAD_noIsNotEmpty() async {
     resolveTestUnit('''
-main(p) {
-  !(p is! String);
+class A {
+  bool get isEmpty => false;
+}
+main(A a) {
+  !a.isEmpty;
 }
 ''');
-    assertNoAssistAt('!(p', DartAssistKind.CONVERT_INTO_IS_NOT);
+    await assertNoAssistAt(
+        'isEmpty;', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY);
   }
 
-  void test_convertToIsNot_wrong_not_noEnclosingParenthesis() {
+  test_convertToIsNotEmpty_BAD_notInPrefixExpression() async {
     resolveTestUnit('''
-main(p) {
-  !p;
+main(String str) {
+  str.isEmpty;
 }
 ''');
-    assertNoAssistAt('!p', DartAssistKind.CONVERT_INTO_IS_NOT);
+    await assertNoAssistAt(
+        'isEmpty;', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY);
   }
 
-  void test_convertToIsNot_wrong_not_notIsExpression() {
+  test_convertToIsNotEmpty_BAD_notIsEmpty() async {
     resolveTestUnit('''
-main(p) {
-  !(p == null);
+main(int p) {
+  !p.isEven;
 }
 ''');
-    assertNoAssistAt('!(p', DartAssistKind.CONVERT_INTO_IS_NOT);
+    await assertNoAssistAt('isEven;', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY);
   }
 
-  void test_convertToIsNot_wrong_not_notTheNotOperator() {
-    verifyNoTestUnitErrors = false;
-    resolveTestUnit('''
-main(p) {
-  ++(p is String);
-}
-''');
-    assertNoAssistAt('++(', DartAssistKind.CONVERT_INTO_IS_NOT);
-  }
-
-  void test_convertToIsNotEmpty_OK_on_isEmpty() {
+  test_convertToIsNotEmpty_OK_on_isEmpty() async {
     resolveTestUnit('''
 main(String str) {
   !str.isEmpty;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'isEmpty',
         DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY,
         '''
@@ -1645,13 +1839,13 @@
 ''');
   }
 
-  void test_convertToIsNotEmpty_OK_on_str() {
+  test_convertToIsNotEmpty_OK_on_str() async {
     resolveTestUnit('''
 main(String str) {
   !str.isEmpty;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'str.',
         DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY,
         '''
@@ -1661,13 +1855,13 @@
 ''');
   }
 
-  void test_convertToIsNotEmpty_OK_propertyAccess() {
+  test_convertToIsNotEmpty_OK_propertyAccess() async {
     resolveTestUnit('''
 main(String str) {
   !'text'.isEmpty;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'isEmpty',
         DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY,
         '''
@@ -1677,47 +1871,7 @@
 ''');
   }
 
-  void test_convertToIsNotEmpty_wrong_noBang() {
-    verifyNoTestUnitErrors = false;
-    resolveTestUnit('''
-main(String str) {
-  ~str.isEmpty;
-}
-''');
-    assertNoAssistAt('isEmpty;', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY);
-  }
-
-  void test_convertToIsNotEmpty_wrong_noIsNotEmpty() {
-    resolveTestUnit('''
-class A {
-  bool get isEmpty => false;
-}
-main(A a) {
-  !a.isEmpty;
-}
-''');
-    assertNoAssistAt('isEmpty;', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY);
-  }
-
-  void test_convertToIsNotEmpty_wrong_notInPrefixExpression() {
-    resolveTestUnit('''
-main(String str) {
-  str.isEmpty;
-}
-''');
-    assertNoAssistAt('isEmpty;', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY);
-  }
-
-  void test_convertToIsNotEmpty_wrong_notIsEmpty() {
-    resolveTestUnit('''
-main(int p) {
-  !p.isEven;
-}
-''');
-    assertNoAssistAt('isEven;', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY);
-  }
-
-  void test_convertToNormalParameter_OK_dynamic() {
+  test_convertToNormalParameter_OK_dynamic() async {
     resolveTestUnit('''
 class A {
   var test;
@@ -1725,7 +1879,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'test)',
         DartAssistKind.CONVERT_TO_NORMAL_PARAMETER,
         '''
@@ -1737,7 +1891,7 @@
 ''');
   }
 
-  void test_convertToNormalParameter_OK_firstInitializer() {
+  test_convertToNormalParameter_OK_firstInitializer() async {
     resolveTestUnit('''
 class A {
   int test;
@@ -1745,7 +1899,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'test)',
         DartAssistKind.CONVERT_TO_NORMAL_PARAMETER,
         '''
@@ -1757,7 +1911,7 @@
 ''');
   }
 
-  void test_convertToNormalParameter_OK_secondInitializer() {
+  test_convertToNormalParameter_OK_secondInitializer() async {
     resolveTestUnit('''
 class A {
   double aaa;
@@ -1765,7 +1919,7 @@
   A(this.bbb) : aaa = 1.0;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'bbb)',
         DartAssistKind.CONVERT_TO_NORMAL_PARAMETER,
         '''
@@ -1777,7 +1931,7 @@
 ''');
   }
 
-  void test_encapsulateField_BAD_alreadyPrivate() {
+  test_encapsulateField_BAD_alreadyPrivate() async {
     resolveTestUnit('''
 class A {
   int _test = 42;
@@ -1786,19 +1940,19 @@
   print(a._test);
 }
 ''');
-    assertNoAssistAt('_test =', DartAssistKind.ENCAPSULATE_FIELD);
+    await assertNoAssistAt('_test =', DartAssistKind.ENCAPSULATE_FIELD);
   }
 
-  void test_encapsulateField_BAD_final() {
+  test_encapsulateField_BAD_final() async {
     resolveTestUnit('''
 class A {
   final int test = 42;
 }
 ''');
-    assertNoAssistAt('test =', DartAssistKind.ENCAPSULATE_FIELD);
+    await assertNoAssistAt('test =', DartAssistKind.ENCAPSULATE_FIELD);
   }
 
-  void test_encapsulateField_BAD_multipleFields() {
+  test_encapsulateField_BAD_multipleFields() async {
     resolveTestUnit('''
 class A {
   int aaa, bbb, ccc;
@@ -1807,19 +1961,19 @@
   print(a.bbb);
 }
 ''');
-    assertNoAssistAt('bbb, ', DartAssistKind.ENCAPSULATE_FIELD);
+    await assertNoAssistAt('bbb, ', DartAssistKind.ENCAPSULATE_FIELD);
   }
 
-  void test_encapsulateField_BAD_notOnName() {
+  test_encapsulateField_BAD_notOnName() async {
     resolveTestUnit('''
 class A {
   int test = 1 + 2 + 3;
 }
 ''');
-    assertNoAssistAt('+ 2', DartAssistKind.ENCAPSULATE_FIELD);
+    await assertNoAssistAt('+ 2', DartAssistKind.ENCAPSULATE_FIELD);
   }
 
-  void test_encapsulateField_BAD_parseError() {
+  test_encapsulateField_BAD_parseError() async {
     verifyNoTestUnitErrors = false;
     resolveTestUnit('''
 class A {
@@ -1829,19 +1983,19 @@
   print(a.test);
 }
 ''');
-    assertNoAssistAt('; // marker', DartAssistKind.ENCAPSULATE_FIELD);
+    await assertNoAssistAt('; // marker', DartAssistKind.ENCAPSULATE_FIELD);
   }
 
-  void test_encapsulateField_BAD_static() {
+  test_encapsulateField_BAD_static() async {
     resolveTestUnit('''
 class A {
   static int test = 42;
 }
 ''');
-    assertNoAssistAt('test =', DartAssistKind.ENCAPSULATE_FIELD);
+    await assertNoAssistAt('test =', DartAssistKind.ENCAPSULATE_FIELD);
   }
 
-  void test_encapsulateField_OK_hasType() {
+  test_encapsulateField_OK_hasType() async {
     resolveTestUnit('''
 class A {
   int test = 42;
@@ -1851,7 +2005,7 @@
   print(a.test);
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'test = 42',
         DartAssistKind.ENCAPSULATE_FIELD,
         '''
@@ -1871,7 +2025,7 @@
 ''');
   }
 
-  void test_encapsulateField_OK_noType() {
+  test_encapsulateField_OK_noType() async {
     resolveTestUnit('''
 class A {
   var test = 42;
@@ -1880,7 +2034,7 @@
   print(a.test);
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'test = 42',
         DartAssistKind.ENCAPSULATE_FIELD,
         '''
@@ -1899,20 +2053,48 @@
 ''');
   }
 
-  void test_exchangeBinaryExpressionArguments_OK_compare() {
-    Map<String, String> operatorMap = {
-      '<': '>',
-      '<=': '>=',
-      '>': '<',
-      '>=': '<='
-    };
-    operatorMap.forEach((initialOperator, resultOperator) {
+  test_exchangeBinaryExpressionArguments_BAD_extraLength() async {
+    resolveTestUnit('''
+main() {
+  111 + 222;
+}
+''');
+    length = 3;
+    await assertNoAssistAt('+ 222', DartAssistKind.EXCHANGE_OPERANDS);
+  }
+
+  test_exchangeBinaryExpressionArguments_BAD_onOperand() async {
+    resolveTestUnit('''
+main() {
+  111 + 222;
+}
+''');
+    length = 3;
+    await assertNoAssistAt('11 +', DartAssistKind.EXCHANGE_OPERANDS);
+  }
+
+  test_exchangeBinaryExpressionArguments_BAD_selectionWithBinary() async {
+    resolveTestUnit('''
+main() {
+  1 + 2 + 3;
+}
+''');
+    length = '1 + 2 + 3'.length;
+    await assertNoAssistAt('1 + 2 + 3', DartAssistKind.EXCHANGE_OPERANDS);
+  }
+
+  test_exchangeBinaryExpressionArguments_OK_compare() async {
+    const initialOperators = const ['<', '<=', '>', '>='];
+    const resultOperators = const ['>', '>=', '<', '<='];
+    for (int i = 0; i <= 0; i++) {
+      String initialOperator = initialOperators[i];
+      String resultOperator = resultOperators[i];
       resolveTestUnit('''
 bool main(int a, int b) {
   return a $initialOperator b;
 }
 ''');
-      assertHasAssistAt(
+      await assertHasAssistAt(
           initialOperator,
           DartAssistKind.EXCHANGE_OPERANDS,
           '''
@@ -1920,16 +2102,16 @@
   return b $resultOperator a;
 }
 ''');
-    });
+    }
   }
 
-  void test_exchangeBinaryExpressionArguments_OK_extended_mixOperator_1() {
+  test_exchangeBinaryExpressionArguments_OK_extended_mixOperator_1() async {
     resolveTestUnit('''
 main() {
   1 * 2 * 3 + 4;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '* 2',
         DartAssistKind.EXCHANGE_OPERANDS,
         '''
@@ -1939,13 +2121,13 @@
 ''');
   }
 
-  void test_exchangeBinaryExpressionArguments_OK_extended_mixOperator_2() {
+  test_exchangeBinaryExpressionArguments_OK_extended_mixOperator_2() async {
     resolveTestUnit('''
 main() {
   1 + 2 - 3 + 4;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '+ 2',
         DartAssistKind.EXCHANGE_OPERANDS,
         '''
@@ -1955,13 +2137,13 @@
 ''');
   }
 
-  void test_exchangeBinaryExpressionArguments_OK_extended_sameOperator_afterFirst() {
+  test_exchangeBinaryExpressionArguments_OK_extended_sameOperator_afterFirst() async {
     resolveTestUnit('''
 main() {
   1 + 2 + 3;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '+ 2',
         DartAssistKind.EXCHANGE_OPERANDS,
         '''
@@ -1971,13 +2153,13 @@
 ''');
   }
 
-  void test_exchangeBinaryExpressionArguments_OK_extended_sameOperator_afterSecond() {
+  test_exchangeBinaryExpressionArguments_OK_extended_sameOperator_afterSecond() async {
     resolveTestUnit('''
 main() {
   1 + 2 + 3;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '+ 3',
         DartAssistKind.EXCHANGE_OPERANDS,
         '''
@@ -1987,13 +2169,13 @@
 ''');
   }
 
-  void test_exchangeBinaryExpressionArguments_OK_simple_afterOperator() {
+  test_exchangeBinaryExpressionArguments_OK_simple_afterOperator() async {
     resolveTestUnit('''
 main() {
   1 + 2;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         ' 2',
         DartAssistKind.EXCHANGE_OPERANDS,
         '''
@@ -2003,13 +2185,13 @@
 ''');
   }
 
-  void test_exchangeBinaryExpressionArguments_OK_simple_beforeOperator() {
+  test_exchangeBinaryExpressionArguments_OK_simple_beforeOperator() async {
     resolveTestUnit('''
 main() {
   1 + 2;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '+ 2',
         DartAssistKind.EXCHANGE_OPERANDS,
         '''
@@ -2019,14 +2201,14 @@
 ''');
   }
 
-  void test_exchangeBinaryExpressionArguments_OK_simple_fullSelection() {
+  test_exchangeBinaryExpressionArguments_OK_simple_fullSelection() async {
     resolveTestUnit('''
 main() {
   1 + 2;
 }
 ''');
     length = '1 + 2'.length;
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '1 + 2',
         DartAssistKind.EXCHANGE_OPERANDS,
         '''
@@ -2036,14 +2218,14 @@
 ''');
   }
 
-  void test_exchangeBinaryExpressionArguments_OK_simple_withLength() {
+  test_exchangeBinaryExpressionArguments_OK_simple_withLength() async {
     resolveTestUnit('''
 main() {
   1 + 2;
 }
 ''');
     length = 2;
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '+ 2',
         DartAssistKind.EXCHANGE_OPERANDS,
         '''
@@ -2053,61 +2235,31 @@
 ''');
   }
 
-  void test_exchangeBinaryExpressionArguments_wrong_extraLength() {
-    resolveTestUnit('''
-main() {
-  111 + 222;
-}
-''');
-    length = 3;
-    assertNoAssistAt('+ 222', DartAssistKind.EXCHANGE_OPERANDS);
-  }
-
-  void test_exchangeBinaryExpressionArguments_wrong_onOperand() {
-    resolveTestUnit('''
-main() {
-  111 + 222;
-}
-''');
-    length = 3;
-    assertNoAssistAt('11 +', DartAssistKind.EXCHANGE_OPERANDS);
-  }
-
-  void test_exchangeBinaryExpressionArguments_wrong_selectionWithBinary() {
-    resolveTestUnit('''
-main() {
-  1 + 2 + 3;
-}
-''');
-    length = '1 + 2 + 3'.length;
-    assertNoAssistAt('1 + 2 + 3', DartAssistKind.EXCHANGE_OPERANDS);
-  }
-
-  void test_importAddShow_BAD_hasShow() {
+  test_importAddShow_BAD_hasShow() async {
     resolveTestUnit('''
 import 'dart:math' show PI;
 main() {
   PI;
 }
 ''');
-    assertNoAssistAt('import ', DartAssistKind.IMPORT_ADD_SHOW);
+    await assertNoAssistAt('import ', DartAssistKind.IMPORT_ADD_SHOW);
   }
 
-  void test_importAddShow_BAD_unresolvedUri() {
+  test_importAddShow_BAD_unresolvedUri() async {
     resolveTestUnit('''
 import '/no/such/lib.dart';
 ''');
-    assertNoAssistAt('import ', DartAssistKind.IMPORT_ADD_SHOW);
+    await assertNoAssistAt('import ', DartAssistKind.IMPORT_ADD_SHOW);
   }
 
-  void test_importAddShow_BAD_unused() {
+  test_importAddShow_BAD_unused() async {
     resolveTestUnit('''
 import 'dart:math';
 ''');
-    assertNoAssistAt('import ', DartAssistKind.IMPORT_ADD_SHOW);
+    await assertNoAssistAt('import ', DartAssistKind.IMPORT_ADD_SHOW);
   }
 
-  void test_importAddShow_OK_hasUnresolvedIdentifier() {
+  test_importAddShow_OK_hasUnresolvedIdentifier() async {
     resolveTestUnit('''
 import 'dart:math';
 main(x) {
@@ -2115,7 +2267,7 @@
   return x.foo();
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'import ',
         DartAssistKind.IMPORT_ADD_SHOW,
         '''
@@ -2127,7 +2279,7 @@
 ''');
   }
 
-  void test_importAddShow_OK_onDirective() {
+  test_importAddShow_OK_onDirective() async {
     resolveTestUnit('''
 import 'dart:math';
 main() {
@@ -2136,7 +2288,7 @@
   max(1, 2);
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'import ',
         DartAssistKind.IMPORT_ADD_SHOW,
         '''
@@ -2149,7 +2301,7 @@
 ''');
   }
 
-  void test_importAddShow_OK_onUri() {
+  test_importAddShow_OK_onUri() async {
     resolveTestUnit('''
 import 'dart:math';
 main() {
@@ -2158,7 +2310,7 @@
   max(1, 2);
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'art:math',
         DartAssistKind.IMPORT_ADD_SHOW,
         '''
@@ -2171,27 +2323,27 @@
 ''');
   }
 
-  void test_introduceLocalTestedType_BAD_notBlock() {
+  test_introduceLocalTestedType_BAD_notBlock() async {
     resolveTestUnit('''
 main(p) {
   if (p is String)
     print('not a block');
 }
 ''');
-    assertNoAssistAt('if (p', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE);
+    await assertNoAssistAt('if (p', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE);
   }
 
-  void test_introduceLocalTestedType_BAD_notIsExpression() {
+  test_introduceLocalTestedType_BAD_notIsExpression() async {
     resolveTestUnit('''
 main(p) {
   if (p == null) {
   }
 }
 ''');
-    assertNoAssistAt('if (p', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE);
+    await assertNoAssistAt('if (p', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE);
   }
 
-  void test_introduceLocalTestedType_OK_if_is() {
+  test_introduceLocalTestedType_OK_if_is() async {
     resolveTestUnit('''
 class MyTypeName {}
 main(p) {
@@ -2209,7 +2361,7 @@
   p = null;
 }
 ''';
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'is MyType', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE, expected);
     _assertLinkedGroup(
         change.linkedEditGroups[0],
@@ -2217,11 +2369,11 @@
         expectedSuggestions(LinkedEditSuggestionKind.VARIABLE,
             ['myTypeName', 'typeName', 'name']));
     // another good location
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (p', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE, expected);
   }
 
-  void test_introduceLocalTestedType_OK_if_isNot() {
+  test_introduceLocalTestedType_OK_if_isNot() async {
     resolveTestUnit('''
 class MyTypeName {}
 main(p) {
@@ -2239,7 +2391,7 @@
   MyTypeName myTypeName = p;
 }
 ''';
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'is! MyType', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE, expected);
     _assertLinkedGroup(
         change.linkedEditGroups[0],
@@ -2247,11 +2399,11 @@
         expectedSuggestions(LinkedEditSuggestionKind.VARIABLE,
             ['myTypeName', 'typeName', 'name']));
     // another good location
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (p', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE, expected);
   }
 
-  void test_introduceLocalTestedType_OK_while() {
+  test_introduceLocalTestedType_OK_while() async {
     resolveTestUnit('''
 main(p) {
   while (p is String) {
@@ -2267,20 +2419,20 @@
   p = null;
 }
 ''';
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'is String', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE, expected);
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'while (p', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE, expected);
   }
 
-  void test_invalidSelection() {
+  test_invalidSelection() async {
     resolveTestUnit('');
     List<Assist> assists =
-        computeAssists(plugin, context, testUnit.element.source, -1, 0);
+        await computeAssists(plugin, context, testUnit.element.source, -1, 0);
     expect(assists, isEmpty);
   }
 
-  void test_invertIfStatement_blocks() {
+  test_invertIfStatement_blocks() async {
     resolveTestUnit('''
 main() {
   if (true) {
@@ -2290,7 +2442,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (',
         DartAssistKind.INVERT_IF_STATEMENT,
         '''
@@ -2304,7 +2456,7 @@
 ''');
   }
 
-  void test_invertIfStatement_statements() {
+  test_invertIfStatement_statements() async {
     resolveTestUnit('''
 main() {
   if (true)
@@ -2313,7 +2465,7 @@
     1;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (',
         DartAssistKind.INVERT_IF_STATEMENT,
         '''
@@ -2326,7 +2478,85 @@
 ''');
   }
 
-  void test_joinIfStatementInner_OK_conditionAndOr() {
+  test_joinIfStatementInner_BAD_innerNotIf() async {
+    resolveTestUnit('''
+main() {
+  if (1 == 1) {
+    print(0);
+  }
+}
+''');
+    await assertNoAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER);
+  }
+
+  test_joinIfStatementInner_BAD_innerWithElse() async {
+    resolveTestUnit('''
+main() {
+  if (1 == 1) {
+    if (2 == 2) {
+      print(0);
+    } else {
+      print(1);
+    }
+  }
+}
+''');
+    await assertNoAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER);
+  }
+
+  test_joinIfStatementInner_BAD_statementAfterInner() async {
+    resolveTestUnit('''
+main() {
+  if (1 == 1) {
+    if (2 == 2) {
+      print(2);
+    }
+    print(1);
+  }
+}
+''');
+    await assertNoAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER);
+  }
+
+  test_joinIfStatementInner_BAD_statementBeforeInner() async {
+    resolveTestUnit('''
+main() {
+  if (1 == 1) {
+    print(1);
+    if (2 == 2) {
+      print(2);
+    }
+  }
+}
+''');
+    await assertNoAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER);
+  }
+
+  test_joinIfStatementInner_BAD_targetNotIf() async {
+    resolveTestUnit('''
+main() {
+  print(0);
+}
+''');
+    await assertNoAssistAt('print', DartAssistKind.JOIN_IF_WITH_INNER);
+  }
+
+  test_joinIfStatementInner_BAD_targetWithElse() async {
+    resolveTestUnit('''
+main() {
+  if (1 == 1) {
+    if (2 == 2) {
+      print(0);
+    }
+  } else {
+    print(1);
+  }
+}
+''');
+    await assertNoAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER);
+  }
+
+  test_joinIfStatementInner_OK_conditionAndOr() async {
     resolveTestUnit('''
 main() {
   if (1 == 1) {
@@ -2336,7 +2566,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (1 ==',
         DartAssistKind.JOIN_IF_WITH_INNER,
         '''
@@ -2348,7 +2578,7 @@
 ''');
   }
 
-  void test_joinIfStatementInner_OK_conditionInvocation() {
+  test_joinIfStatementInner_OK_conditionInvocation() async {
     resolveTestUnit('''
 main() {
   if (isCheck()) {
@@ -2359,7 +2589,7 @@
 }
 bool isCheck() => false;
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (isCheck',
         DartAssistKind.JOIN_IF_WITH_INNER,
         '''
@@ -2372,7 +2602,7 @@
 ''');
   }
 
-  void test_joinIfStatementInner_OK_conditionOrAnd() {
+  test_joinIfStatementInner_OK_conditionOrAnd() async {
     resolveTestUnit('''
 main() {
   if (1 == 1 || 2 == 2) {
@@ -2382,7 +2612,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (1 ==',
         DartAssistKind.JOIN_IF_WITH_INNER,
         '''
@@ -2394,7 +2624,7 @@
 ''');
   }
 
-  void test_joinIfStatementInner_OK_onCondition() {
+  test_joinIfStatementInner_OK_onCondition() async {
     resolveTestUnit('''
 main() {
   if (1 == 1) {
@@ -2404,7 +2634,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '1 ==',
         DartAssistKind.JOIN_IF_WITH_INNER,
         '''
@@ -2416,7 +2646,7 @@
 ''');
   }
 
-  void test_joinIfStatementInner_OK_simpleConditions_block_block() {
+  test_joinIfStatementInner_OK_simpleConditions_block_block() async {
     resolveTestUnit('''
 main() {
   if (1 == 1) {
@@ -2426,7 +2656,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (1 ==',
         DartAssistKind.JOIN_IF_WITH_INNER,
         '''
@@ -2438,7 +2668,7 @@
 ''');
   }
 
-  void test_joinIfStatementInner_OK_simpleConditions_block_single() {
+  test_joinIfStatementInner_OK_simpleConditions_block_single() async {
     resolveTestUnit('''
 main() {
   if (1 == 1) {
@@ -2447,7 +2677,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (1 ==',
         DartAssistKind.JOIN_IF_WITH_INNER,
         '''
@@ -2459,7 +2689,7 @@
 ''');
   }
 
-  void test_joinIfStatementInner_OK_simpleConditions_single_blockMulti() {
+  test_joinIfStatementInner_OK_simpleConditions_single_blockMulti() async {
     resolveTestUnit('''
 main() {
   if (1 == 1) {
@@ -2471,7 +2701,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (1 ==',
         DartAssistKind.JOIN_IF_WITH_INNER,
         '''
@@ -2485,7 +2715,7 @@
 ''');
   }
 
-  void test_joinIfStatementInner_OK_simpleConditions_single_blockOne() {
+  test_joinIfStatementInner_OK_simpleConditions_single_blockOne() async {
     resolveTestUnit('''
 main() {
   if (1 == 1)
@@ -2494,7 +2724,7 @@
     }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (1 ==',
         DartAssistKind.JOIN_IF_WITH_INNER,
         '''
@@ -2506,7 +2736,7 @@
 ''');
   }
 
-  void test_joinIfStatementInner_wrong_innerNotIf() {
+  test_joinIfStatementOuter_BAD_outerNotIf() async {
     resolveTestUnit('''
 main() {
   if (1 == 1) {
@@ -2514,34 +2744,10 @@
   }
 }
 ''');
-    assertNoAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER);
+    await assertNoAssistAt('if (1 == 1', DartAssistKind.JOIN_IF_WITH_OUTER);
   }
 
-  void test_joinIfStatementInner_wrong_innerWithElse() {
-    resolveTestUnit('''
-main() {
-  if (1 == 1) {
-    if (2 == 2) {
-      print(0);
-    } else {
-      print(1);
-    }
-  }
-}
-''');
-    assertNoAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER);
-  }
-
-  void test_joinIfStatementInner_wrong_targetNotIf() {
-    resolveTestUnit('''
-main() {
-  print(0);
-}
-''');
-    assertNoAssistAt('print', DartAssistKind.JOIN_IF_WITH_INNER);
-  }
-
-  void test_joinIfStatementInner_wrong_targetWithElse() {
+  test_joinIfStatementOuter_BAD_outerWithElse() async {
     resolveTestUnit('''
 main() {
   if (1 == 1) {
@@ -2553,10 +2759,62 @@
   }
 }
 ''');
-    assertNoAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER);
+    await assertNoAssistAt('if (2 == 2', DartAssistKind.JOIN_IF_WITH_OUTER);
   }
 
-  void test_joinIfStatementOuter_OK_conditionAndOr() {
+  test_joinIfStatementOuter_BAD_statementAfterInner() async {
+    resolveTestUnit('''
+main() {
+  if (1 == 1) {
+    if (2 == 2) {
+      print(2);
+    }
+    print(1);
+  }
+}
+''');
+    await assertNoAssistAt('if (2 == 2', DartAssistKind.JOIN_IF_WITH_OUTER);
+  }
+
+  test_joinIfStatementOuter_BAD_statementBeforeInner() async {
+    resolveTestUnit('''
+main() {
+  if (1 == 1) {
+    print(1);
+    if (2 == 2) {
+      print(2);
+    }
+  }
+}
+''');
+    await assertNoAssistAt('if (2 == 2', DartAssistKind.JOIN_IF_WITH_OUTER);
+  }
+
+  test_joinIfStatementOuter_BAD_targetNotIf() async {
+    resolveTestUnit('''
+main() {
+  print(0);
+}
+''');
+    await assertNoAssistAt('print', DartAssistKind.JOIN_IF_WITH_OUTER);
+  }
+
+  test_joinIfStatementOuter_BAD_targetWithElse() async {
+    resolveTestUnit('''
+main() {
+  if (1 == 1) {
+    if (2 == 2) {
+      print(0);
+    } else {
+      print(1);
+    }
+  }
+}
+''');
+    await assertNoAssistAt('if (2 == 2', DartAssistKind.JOIN_IF_WITH_OUTER);
+  }
+
+  test_joinIfStatementOuter_OK_conditionAndOr() async {
     resolveTestUnit('''
 main() {
   if (1 == 1) {
@@ -2566,7 +2824,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (2 ==',
         DartAssistKind.JOIN_IF_WITH_OUTER,
         '''
@@ -2578,7 +2836,7 @@
 ''');
   }
 
-  void test_joinIfStatementOuter_OK_conditionInvocation() {
+  test_joinIfStatementOuter_OK_conditionInvocation() async {
     resolveTestUnit('''
 main() {
   if (1 == 1) {
@@ -2589,7 +2847,7 @@
 }
 bool isCheck() => false;
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (isCheck',
         DartAssistKind.JOIN_IF_WITH_OUTER,
         '''
@@ -2602,7 +2860,7 @@
 ''');
   }
 
-  void test_joinIfStatementOuter_OK_conditionOrAnd() {
+  test_joinIfStatementOuter_OK_conditionOrAnd() async {
     resolveTestUnit('''
 main() {
   if (1 == 1 || 2 == 2) {
@@ -2612,7 +2870,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (3 == 3',
         DartAssistKind.JOIN_IF_WITH_OUTER,
         '''
@@ -2624,7 +2882,7 @@
 ''');
   }
 
-  void test_joinIfStatementOuter_OK_onCondition() {
+  test_joinIfStatementOuter_OK_onCondition() async {
     resolveTestUnit('''
 main() {
   if (1 == 1) {
@@ -2634,7 +2892,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (2 == 2',
         DartAssistKind.JOIN_IF_WITH_OUTER,
         '''
@@ -2646,7 +2904,7 @@
 ''');
   }
 
-  void test_joinIfStatementOuter_OK_simpleConditions_block_block() {
+  test_joinIfStatementOuter_OK_simpleConditions_block_block() async {
     resolveTestUnit('''
 main() {
   if (1 == 1) {
@@ -2656,7 +2914,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (2 == 2',
         DartAssistKind.JOIN_IF_WITH_OUTER,
         '''
@@ -2668,7 +2926,7 @@
 ''');
   }
 
-  void test_joinIfStatementOuter_OK_simpleConditions_block_single() {
+  test_joinIfStatementOuter_OK_simpleConditions_block_single() async {
     resolveTestUnit('''
 main() {
   if (1 == 1) {
@@ -2677,7 +2935,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (2 == 2',
         DartAssistKind.JOIN_IF_WITH_OUTER,
         '''
@@ -2689,7 +2947,7 @@
 ''');
   }
 
-  void test_joinIfStatementOuter_OK_simpleConditions_single_blockMulti() {
+  test_joinIfStatementOuter_OK_simpleConditions_single_blockMulti() async {
     resolveTestUnit('''
 main() {
   if (1 == 1) {
@@ -2701,7 +2959,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (2 == 2',
         DartAssistKind.JOIN_IF_WITH_OUTER,
         '''
@@ -2715,7 +2973,7 @@
 ''');
   }
 
-  void test_joinIfStatementOuter_OK_simpleConditions_single_blockOne() {
+  test_joinIfStatementOuter_OK_simpleConditions_single_blockOne() async {
     resolveTestUnit('''
 main() {
   if (1 == 1)
@@ -2724,7 +2982,7 @@
     }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (2 == 2',
         DartAssistKind.JOIN_IF_WITH_OUTER,
         '''
@@ -2736,64 +2994,98 @@
 ''');
   }
 
-  void test_joinIfStatementOuter_wrong_outerNotIf() {
+  test_joinVariableDeclaration_onAssignment_BAD_hasInitializer() async {
     resolveTestUnit('''
 main() {
-  if (1 == 1) {
-    print(0);
+  var v = 1;
+  v = 2;
+}
+''');
+    await assertNoAssistAt('v = 2', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+  }
+
+  test_joinVariableDeclaration_onAssignment_BAD_notAdjacent() async {
+    resolveTestUnit('''
+main() {
+  var v;
+  var bar;
+  v = 1;
+}
+''');
+    await assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+  }
+
+  test_joinVariableDeclaration_onAssignment_BAD_notAssignment() async {
+    resolveTestUnit('''
+main() {
+  var v;
+  v += 1;
+}
+''');
+    await assertNoAssistAt('v += 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+  }
+
+  test_joinVariableDeclaration_onAssignment_BAD_notDeclaration() async {
+    resolveTestUnit('''
+main(var v) {
+  v = 1;
+}
+''');
+    await assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+  }
+
+  test_joinVariableDeclaration_onAssignment_BAD_notLeftArgument() async {
+    resolveTestUnit('''
+main() {
+  var v;
+  1 + v; // marker
+}
+''');
+    await assertNoAssistAt(
+        'v; // marker', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+  }
+
+  test_joinVariableDeclaration_onAssignment_BAD_notOneVariable() async {
+    resolveTestUnit('''
+main() {
+  var v, v2;
+  v = 1;
+}
+''');
+    await assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+  }
+
+  test_joinVariableDeclaration_onAssignment_BAD_notResolved() async {
+    verifyNoTestUnitErrors = false;
+    resolveTestUnit('''
+main() {
+  var v;
+  x = 1;
+}
+''');
+    await assertNoAssistAt('x = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+  }
+
+  test_joinVariableDeclaration_onAssignment_BAD_notSameBlock() async {
+    resolveTestUnit('''
+main() {
+  var v;
+  {
+    v = 1;
   }
 }
 ''');
-    assertNoAssistAt('if (1 == 1', DartAssistKind.JOIN_IF_WITH_OUTER);
+    await assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
   }
 
-  void test_joinIfStatementOuter_wrong_outerWithElse() {
-    resolveTestUnit('''
-main() {
-  if (1 == 1) {
-    if (2 == 2) {
-      print(0);
-    }
-  } else {
-    print(1);
-  }
-}
-''');
-    assertNoAssistAt('if (2 == 2', DartAssistKind.JOIN_IF_WITH_OUTER);
-  }
-
-  void test_joinIfStatementOuter_wrong_targetNotIf() {
-    resolveTestUnit('''
-main() {
-  print(0);
-}
-''');
-    assertNoAssistAt('print', DartAssistKind.JOIN_IF_WITH_OUTER);
-  }
-
-  void test_joinIfStatementOuter_wrong_targetWithElse() {
-    resolveTestUnit('''
-main() {
-  if (1 == 1) {
-    if (2 == 2) {
-      print(0);
-    } else {
-      print(1);
-    }
-  }
-}
-''');
-    assertNoAssistAt('if (2 == 2', DartAssistKind.JOIN_IF_WITH_OUTER);
-  }
-
-  void test_joinVariableDeclaration_onAssignment_OK() {
+  test_joinVariableDeclaration_onAssignment_OK() async {
     resolveTestUnit('''
 main() {
   var v;
   v = 1;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'v =',
         DartAssistKind.JOIN_VARIABLE_DECLARATION,
         '''
@@ -2803,97 +3095,74 @@
 ''');
   }
 
-  void test_joinVariableDeclaration_onAssignment_wrong_hasInitializer() {
+  test_joinVariableDeclaration_onDeclaration_BAD_hasInitializer() async {
     resolveTestUnit('''
 main() {
   var v = 1;
   v = 2;
 }
 ''');
-    assertNoAssistAt('v = 2', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+    await assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
   }
 
-  void test_joinVariableDeclaration_onAssignment_wrong_notAdjacent() {
+  test_joinVariableDeclaration_onDeclaration_BAD_lastStatement() async {
+    resolveTestUnit('''
+main() {
+  if (true)
+    var v;
+}
+''');
+    await assertNoAssistAt('v;', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+  }
+
+  test_joinVariableDeclaration_onDeclaration_BAD_nextNotAssignmentExpression() async {
     resolveTestUnit('''
 main() {
   var v;
-  var bar;
-  v = 1;
+  42;
 }
 ''');
-    assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+    await assertNoAssistAt('v;', DartAssistKind.JOIN_VARIABLE_DECLARATION);
   }
 
-  void test_joinVariableDeclaration_onAssignment_wrong_notAssignment() {
+  test_joinVariableDeclaration_onDeclaration_BAD_nextNotExpressionStatement() async {
+    resolveTestUnit('''
+main() {
+  var v;
+  if (true) return;
+}
+''');
+    await assertNoAssistAt('v;', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+  }
+
+  test_joinVariableDeclaration_onDeclaration_BAD_nextNotPureAssignment() async {
     resolveTestUnit('''
 main() {
   var v;
   v += 1;
 }
 ''');
-    assertNoAssistAt('v += 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+    await assertNoAssistAt('v;', DartAssistKind.JOIN_VARIABLE_DECLARATION);
   }
 
-  void test_joinVariableDeclaration_onAssignment_wrong_notDeclaration() {
-    resolveTestUnit('''
-main(var v) {
-  v = 1;
-}
-''');
-    assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
-  }
-
-  void test_joinVariableDeclaration_onAssignment_wrong_notLeftArgument() {
-    resolveTestUnit('''
-main() {
-  var v;
-  1 + v; // marker
-}
-''');
-    assertNoAssistAt('v; // marker', DartAssistKind.JOIN_VARIABLE_DECLARATION);
-  }
-
-  void test_joinVariableDeclaration_onAssignment_wrong_notOneVariable() {
+  test_joinVariableDeclaration_onDeclaration_BAD_notOneVariable() async {
     resolveTestUnit('''
 main() {
   var v, v2;
   v = 1;
 }
 ''');
-    assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+    await assertNoAssistAt('v, ', DartAssistKind.JOIN_VARIABLE_DECLARATION);
   }
 
-  void test_joinVariableDeclaration_onAssignment_wrong_notResolved() {
-    verifyNoTestUnitErrors = false;
-    resolveTestUnit('''
-main() {
-  var v;
-  x = 1;
-}
-''');
-    assertNoAssistAt('x = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
-  }
-
-  void test_joinVariableDeclaration_onAssignment_wrong_notSameBlock() {
-    resolveTestUnit('''
-main() {
-  var v;
-  {
-    v = 1;
-  }
-}
-''');
-    assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
-  }
-
-  void test_joinVariableDeclaration_onDeclaration_OK_onName() {
+  test_joinVariableDeclaration_onDeclaration_OK_onName() async {
     resolveTestUnit('''
 main() {
   var v;
   v = 1;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'v;',
         DartAssistKind.JOIN_VARIABLE_DECLARATION,
         '''
@@ -2903,14 +3172,14 @@
 ''');
   }
 
-  void test_joinVariableDeclaration_onDeclaration_OK_onType() {
+  test_joinVariableDeclaration_onDeclaration_OK_onType() async {
     resolveTestUnit('''
 main() {
   int v;
   v = 1;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'int v',
         DartAssistKind.JOIN_VARIABLE_DECLARATION,
         '''
@@ -2920,14 +3189,14 @@
 ''');
   }
 
-  void test_joinVariableDeclaration_onDeclaration_OK_onVar() {
+  test_joinVariableDeclaration_onDeclaration_OK_onVar() async {
     resolveTestUnit('''
 main() {
   var v;
   v = 1;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'var v',
         DartAssistKind.JOIN_VARIABLE_DECLARATION,
         '''
@@ -2937,73 +3206,13 @@
 ''');
   }
 
-  void test_joinVariableDeclaration_onDeclaration_wrong_hasInitializer() {
-    resolveTestUnit('''
-main() {
-  var v = 1;
-  v = 2;
-}
-''');
-    assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
-  }
-
-  void test_joinVariableDeclaration_onDeclaration_wrong_lastStatement() {
-    resolveTestUnit('''
-main() {
-  if (true)
-    var v;
-}
-''');
-    assertNoAssistAt('v;', DartAssistKind.JOIN_VARIABLE_DECLARATION);
-  }
-
-  void test_joinVariableDeclaration_onDeclaration_wrong_nextNotAssignmentExpression() {
-    resolveTestUnit('''
-main() {
-  var v;
-  42;
-}
-''');
-    assertNoAssistAt('v;', DartAssistKind.JOIN_VARIABLE_DECLARATION);
-  }
-
-  void test_joinVariableDeclaration_onDeclaration_wrong_nextNotExpressionStatement() {
-    resolveTestUnit('''
-main() {
-  var v;
-  if (true) return;
-}
-''');
-    assertNoAssistAt('v;', DartAssistKind.JOIN_VARIABLE_DECLARATION);
-  }
-
-  void test_joinVariableDeclaration_onDeclaration_wrong_nextNotPureAssignment() {
-    resolveTestUnit('''
-main() {
-  var v;
-  v += 1;
-}
-''');
-    assertNoAssistAt('v;', DartAssistKind.JOIN_VARIABLE_DECLARATION);
-  }
-
-  void test_joinVariableDeclaration_onDeclaration_wrong_notOneVariable() {
-    resolveTestUnit('''
-main() {
-  var v, v2;
-  v = 1;
-}
-''');
-    assertNoAssistAt('v, ', DartAssistKind.JOIN_VARIABLE_DECLARATION);
-  }
-
-  void test_removeTypeAnnotation_classField_OK() {
+  test_removeTypeAnnotation_classField_OK() async {
     resolveTestUnit('''
 class A {
   int v = 1;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'v = ',
         DartAssistKind.REMOVE_TYPE_ANNOTATION,
         '''
@@ -3013,13 +3222,13 @@
 ''');
   }
 
-  void test_removeTypeAnnotation_classField_OK_final() {
+  test_removeTypeAnnotation_classField_OK_final() async {
     resolveTestUnit('''
 class A {
   final int v = 1;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'v = ',
         DartAssistKind.REMOVE_TYPE_ANNOTATION,
         '''
@@ -3029,13 +3238,13 @@
 ''');
   }
 
-  void test_removeTypeAnnotation_localVariable_OK() {
+  test_removeTypeAnnotation_localVariable_OK() async {
     resolveTestUnit('''
 main() {
   int a = 1, b = 2;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'int ',
         DartAssistKind.REMOVE_TYPE_ANNOTATION,
         '''
@@ -3045,13 +3254,13 @@
 ''');
   }
 
-  void test_removeTypeAnnotation_localVariable_OK_const() {
+  test_removeTypeAnnotation_localVariable_OK_const() async {
     resolveTestUnit('''
 main() {
   const int v = 1;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'int ',
         DartAssistKind.REMOVE_TYPE_ANNOTATION,
         '''
@@ -3061,13 +3270,13 @@
 ''');
   }
 
-  void test_removeTypeAnnotation_localVariable_OK_final() {
+  test_removeTypeAnnotation_localVariable_OK_final() async {
     resolveTestUnit('''
 main() {
   final int v = 1;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'int ',
         DartAssistKind.REMOVE_TYPE_ANNOTATION,
         '''
@@ -3077,11 +3286,11 @@
 ''');
   }
 
-  void test_removeTypeAnnotation_topLevelVariable_OK() {
+  test_removeTypeAnnotation_topLevelVariable_OK() async {
     resolveTestUnit('''
 int V = 1;
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'int ',
         DartAssistKind.REMOVE_TYPE_ANNOTATION,
         '''
@@ -3089,11 +3298,11 @@
 ''');
   }
 
-  void test_removeTypeAnnotation_topLevelVariable_OK_final() {
+  test_removeTypeAnnotation_topLevelVariable_OK_final() async {
     resolveTestUnit('''
 final int V = 1;
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'int ',
         DartAssistKind.REMOVE_TYPE_ANNOTATION,
         '''
@@ -3101,7 +3310,25 @@
 ''');
   }
 
-  void test_replaceConditionalWithIfElse_OK_assignment() {
+  test_replaceConditionalWithIfElse_BAD_noEnclosingStatement() async {
+    resolveTestUnit('''
+var v = true ? 111 : 222;
+''');
+    await assertNoAssistAt(
+        '? 111', DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE);
+  }
+
+  test_replaceConditionalWithIfElse_BAD_notConditional() async {
+    resolveTestUnit('''
+main() {
+  var v = 42;
+}
+''');
+    await assertNoAssistAt(
+        'v = 42', DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE);
+  }
+
+  test_replaceConditionalWithIfElse_OK_assignment() async {
     resolveTestUnit('''
 main() {
   var v;
@@ -3109,7 +3336,7 @@
 }
 ''');
     // on conditional
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '11 :',
         DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE,
         '''
@@ -3123,7 +3350,7 @@
 }
 ''');
     // on variable
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'v =',
         DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE,
         '''
@@ -3138,13 +3365,13 @@
 ''');
   }
 
-  void test_replaceConditionalWithIfElse_OK_return() {
+  test_replaceConditionalWithIfElse_OK_return() async {
     resolveTestUnit('''
 main() {
   return true ? 111 : 222;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'return ',
         DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE,
         '''
@@ -3158,13 +3385,13 @@
 ''');
   }
 
-  void test_replaceConditionalWithIfElse_OK_variableDeclaration() {
+  test_replaceConditionalWithIfElse_OK_variableDeclaration() async {
     resolveTestUnit('''
 main() {
   int a = 1, vvv = true ? 111 : 222, b = 2;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '11 :',
         DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE,
         '''
@@ -3179,23 +3406,48 @@
 ''');
   }
 
-  void test_replaceConditionalWithIfElse_wrong_noEnclosingStatement() {
-    resolveTestUnit('''
-var v = true ? 111 : 222;
-''');
-    assertNoAssistAt('? 111', DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE);
-  }
-
-  void test_replaceConditionalWithIfElse_wrong_notConditional() {
+  test_replaceIfElseWithConditional_BAD_expressionVsReturn() async {
     resolveTestUnit('''
 main() {
-  var v = 42;
+  if (true) {
+    print(42);
+  } else {
+    return;
+  }
 }
 ''');
-    assertNoAssistAt('v = 42', DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE);
+    await assertNoAssistAt(
+        'else', DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL);
   }
 
-  void test_replaceIfElseWithConditional_OK_assignment() {
+  test_replaceIfElseWithConditional_BAD_notIfStatement() async {
+    resolveTestUnit('''
+main() {
+  print(0);
+}
+''');
+    await assertNoAssistAt(
+        'print', DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL);
+  }
+
+  test_replaceIfElseWithConditional_BAD_notSingleStatement() async {
+    resolveTestUnit('''
+main() {
+  int vvv;
+  if (true) {
+    print(0);
+    vvv = 111;
+  } else {
+    print(0);
+    vvv = 222;
+  }
+}
+''');
+    await assertNoAssistAt(
+        'if (true)', DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL);
+  }
+
+  test_replaceIfElseWithConditional_OK_assignment() async {
     resolveTestUnit('''
 main() {
   int vvv;
@@ -3206,7 +3458,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (true)',
         DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL,
         '''
@@ -3217,7 +3469,7 @@
 ''');
   }
 
-  void test_replaceIfElseWithConditional_OK_return() {
+  test_replaceIfElseWithConditional_OK_return() async {
     resolveTestUnit('''
 main() {
   if (true) {
@@ -3227,7 +3479,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'if (true)',
         DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL,
         '''
@@ -3237,46 +3489,55 @@
 ''');
   }
 
-  void test_replaceIfElseWithConditional_wrong_expressionVsReturn() {
+  test_splitAndCondition_BAD_hasElse() async {
     resolveTestUnit('''
 main() {
-  if (true) {
-    print(42);
+  if (1 == 1 && 2 == 2) {
+    print(1);
   } else {
-    return;
+    print(2);
   }
 }
 ''');
-    assertNoAssistAt('else', DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL);
+    await assertNoAssistAt('&& 2', DartAssistKind.SPLIT_AND_CONDITION);
   }
 
-  void test_replaceIfElseWithConditional_wrong_notIfStatement() {
+  test_splitAndCondition_BAD_notAnd() async {
     resolveTestUnit('''
 main() {
-  print(0);
+  if (1 == 1 || 2 == 2) {
+    print(0);
+  }
 }
 ''');
-    assertNoAssistAt('print', DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL);
+    await assertNoAssistAt('|| 2', DartAssistKind.SPLIT_AND_CONDITION);
   }
 
-  void test_replaceIfElseWithConditional_wrong_notSingleStatememt() {
+  test_splitAndCondition_BAD_notPartOfIf() async {
     resolveTestUnit('''
 main() {
-  int vvv;
-  if (true) {
+  print(1 == 1 && 2 == 2);
+}
+''');
+    await assertNoAssistAt('&& 2', DartAssistKind.SPLIT_AND_CONDITION);
+  }
+
+  test_splitAndCondition_BAD_notTopLevelAnd() async {
+    resolveTestUnit('''
+main() {
+  if (true || (1 == 1 && 2 == 2)) {
     print(0);
-    vvv = 111;
-  } else {
+  }
+  if (true && (3 == 3 && 4 == 4)) {
     print(0);
-    vvv = 222;
   }
 }
 ''');
-    assertNoAssistAt(
-        'if (true)', DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL);
+    await assertNoAssistAt('&& 2', DartAssistKind.SPLIT_AND_CONDITION);
+    await assertNoAssistAt('&& 4', DartAssistKind.SPLIT_AND_CONDITION);
   }
 
-  void test_splitAndCondition_OK_innerAndExpression() {
+  test_splitAndCondition_OK_innerAndExpression() async {
     resolveTestUnit('''
 main() {
   if (1 == 1 && 2 == 2 && 3 == 3) {
@@ -3284,7 +3545,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '&& 2 == 2',
         DartAssistKind.SPLIT_AND_CONDITION,
         '''
@@ -3298,7 +3559,7 @@
 ''');
   }
 
-  void test_splitAndCondition_OK_thenBlock() {
+  test_splitAndCondition_OK_thenBlock() async {
     resolveTestUnit('''
 main() {
   if (true && false) {
@@ -3309,7 +3570,7 @@
   }
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '&& false',
         DartAssistKind.SPLIT_AND_CONDITION,
         '''
@@ -3326,14 +3587,14 @@
 ''');
   }
 
-  void test_splitAndCondition_OK_thenStatement() {
+  test_splitAndCondition_OK_thenStatement() async {
     resolveTestUnit('''
 main() {
   if (true && false)
     print(0);
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         '&& false',
         DartAssistKind.SPLIT_AND_CONDITION,
         '''
@@ -3345,7 +3606,7 @@
 ''');
   }
 
-  void test_splitAndCondition_wrong() {
+  test_splitAndCondition_wrong() async {
     resolveTestUnit('''
 main() {
   if (1 == 1 && 2 == 2) {
@@ -3355,69 +3616,30 @@
 }
 ''');
     // not binary expression
-    assertNoAssistAt('main() {', DartAssistKind.SPLIT_AND_CONDITION);
+    await assertNoAssistAt('main() {', DartAssistKind.SPLIT_AND_CONDITION);
     // selection is not empty and includes more than just operator
     {
       length = 5;
-      assertNoAssistAt('&& 2 == 2', DartAssistKind.SPLIT_AND_CONDITION);
+      await assertNoAssistAt('&& 2 == 2', DartAssistKind.SPLIT_AND_CONDITION);
     }
   }
 
-  void test_splitAndCondition_wrong_hasElse() {
+  test_splitVariableDeclaration_BAD_notOneVariable() async {
     resolveTestUnit('''
 main() {
-  if (1 == 1 && 2 == 2) {
-    print(1);
-  } else {
-    print(2);
-  }
+  var v = 1, v2;
 }
 ''');
-    assertNoAssistAt('&& 2', DartAssistKind.SPLIT_AND_CONDITION);
+    await assertNoAssistAt('v = 1', DartAssistKind.SPLIT_VARIABLE_DECLARATION);
   }
 
-  void test_splitAndCondition_wrong_notAnd() {
-    resolveTestUnit('''
-main() {
-  if (1 == 1 || 2 == 2) {
-    print(0);
-  }
-}
-''');
-    assertNoAssistAt('|| 2', DartAssistKind.SPLIT_AND_CONDITION);
-  }
-
-  void test_splitAndCondition_wrong_notPartOfIf() {
-    resolveTestUnit('''
-main() {
-  print(1 == 1 && 2 == 2);
-}
-''');
-    assertNoAssistAt('&& 2', DartAssistKind.SPLIT_AND_CONDITION);
-  }
-
-  void test_splitAndCondition_wrong_notTopLevelAnd() {
-    resolveTestUnit('''
-main() {
-  if (true || (1 == 1 && 2 == 2)) {
-    print(0);
-  }
-  if (true && (3 == 3 && 4 == 4)) {
-    print(0);
-  }
-}
-''');
-    assertNoAssistAt('&& 2', DartAssistKind.SPLIT_AND_CONDITION);
-    assertNoAssistAt('&& 4', DartAssistKind.SPLIT_AND_CONDITION);
-  }
-
-  void test_splitVariableDeclaration_OK_onName() {
+  test_splitVariableDeclaration_OK_onName() async {
     resolveTestUnit('''
 main() {
   var v = 1;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'v =',
         DartAssistKind.SPLIT_VARIABLE_DECLARATION,
         '''
@@ -3428,13 +3650,13 @@
 ''');
   }
 
-  void test_splitVariableDeclaration_OK_onType() {
+  test_splitVariableDeclaration_OK_onType() async {
     resolveTestUnit('''
 main() {
   int v = 1;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'int ',
         DartAssistKind.SPLIT_VARIABLE_DECLARATION,
         '''
@@ -3445,13 +3667,13 @@
 ''');
   }
 
-  void test_splitVariableDeclaration_OK_onVar() {
+  test_splitVariableDeclaration_OK_onVar() async {
     resolveTestUnit('''
 main() {
   var v = 1;
 }
 ''');
-    assertHasAssistAt(
+    await assertHasAssistAt(
         'var ',
         DartAssistKind.SPLIT_VARIABLE_DECLARATION,
         '''
@@ -3462,16 +3684,7 @@
 ''');
   }
 
-  void test_splitVariableDeclaration_wrong_notOneVariable() {
-    resolveTestUnit('''
-main() {
-  var v = 1, v2;
-}
-''');
-    assertNoAssistAt('v = 1', DartAssistKind.SPLIT_VARIABLE_DECLARATION);
-  }
-
-  void test_surroundWith_block() {
+  test_surroundWith_block() async {
     resolveTestUnit('''
 main() {
 // start
@@ -3481,7 +3694,7 @@
 }
 ''');
     _setStartEndSelection();
-    assertHasAssist(
+    await assertHasAssist(
         DartAssistKind.SURROUND_WITH_BLOCK,
         '''
 main() {
@@ -3495,7 +3708,7 @@
 ''');
   }
 
-  void test_surroundWith_doWhile() {
+  test_surroundWith_doWhile() async {
     resolveTestUnit('''
 main() {
 // start
@@ -3505,7 +3718,7 @@
 }
 ''');
     _setStartEndSelection();
-    assertHasAssist(
+    await assertHasAssist(
         DartAssistKind.SURROUND_WITH_DO_WHILE,
         '''
 main() {
@@ -3519,7 +3732,7 @@
 ''');
   }
 
-  void test_surroundWith_for() {
+  test_surroundWith_for() async {
     resolveTestUnit('''
 main() {
 // start
@@ -3529,7 +3742,7 @@
 }
 ''');
     _setStartEndSelection();
-    assertHasAssist(
+    await assertHasAssist(
         DartAssistKind.SURROUND_WITH_FOR,
         '''
 main() {
@@ -3543,7 +3756,7 @@
 ''');
   }
 
-  void test_surroundWith_forIn() {
+  test_surroundWith_forIn() async {
     resolveTestUnit('''
 main() {
 // start
@@ -3553,7 +3766,7 @@
 }
 ''');
     _setStartEndSelection();
-    assertHasAssist(
+    await assertHasAssist(
         DartAssistKind.SURROUND_WITH_FOR_IN,
         '''
 main() {
@@ -3567,7 +3780,7 @@
 ''');
   }
 
-  void test_surroundWith_if() {
+  test_surroundWith_if() async {
     resolveTestUnit('''
 main() {
 // start
@@ -3577,7 +3790,7 @@
 }
 ''');
     _setStartEndSelection();
-    assertHasAssist(
+    await assertHasAssist(
         DartAssistKind.SURROUND_WITH_IF,
         '''
 main() {
@@ -3591,7 +3804,7 @@
 ''');
   }
 
-  void test_surroundWith_tryCatch() {
+  test_surroundWith_tryCatch() async {
     resolveTestUnit('''
 main() {
 // start
@@ -3601,7 +3814,7 @@
 }
 ''');
     _setStartEndSelection();
-    assertHasAssist(
+    await assertHasAssist(
         DartAssistKind.SURROUND_WITH_TRY_CATCH,
         '''
 main() {
@@ -3617,7 +3830,7 @@
 ''');
   }
 
-  void test_surroundWith_tryFinally() {
+  test_surroundWith_tryFinally() async {
     resolveTestUnit('''
 main() {
 // start
@@ -3627,7 +3840,7 @@
 }
 ''');
     _setStartEndSelection();
-    assertHasAssist(
+    await assertHasAssist(
         DartAssistKind.SURROUND_WITH_TRY_FINALLY,
         '''
 main() {
@@ -3643,7 +3856,7 @@
 ''');
   }
 
-  void test_surroundWith_while() {
+  test_surroundWith_while() async {
     resolveTestUnit('''
 main() {
 // start
@@ -3653,7 +3866,7 @@
 }
 ''');
     _setStartEndSelection();
-    assertHasAssist(
+    await assertHasAssist(
         DartAssistKind.SURROUND_WITH_WHILE,
         '''
 main() {
@@ -3670,8 +3883,8 @@
   /**
    * Computes assists and verifies that there is an assist of the given kind.
    */
-  Assist _assertHasAssist(AssistKind kind) {
-    List<Assist> assists = computeAssists(
+  Future<Assist> _assertHasAssist(AssistKind kind) async {
+    List<Assist> assists = await computeAssists(
         plugin, context, testUnit.element.source, offset, length);
     for (Assist assist in assists) {
       if (assist.kind == kind) {
diff --git a/pkg/analysis_server/test/services/correction/fix_test.dart b/pkg/analysis_server/test/services/correction/fix_test.dart
index 5d124f0..a6ec27a 100644
--- a/pkg/analysis_server/test/services/correction/fix_test.dart
+++ b/pkg/analysis_server/test/services/correction/fix_test.dart
@@ -4,7 +4,10 @@
 
 library test.services.correction.fix;
 
+import 'dart:async';
+
 import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
+import 'package:analysis_server/plugin/edit/fix/fix_dart.dart';
 import 'package:analysis_server/plugin/protocol/protocol.dart'
     hide AnalysisError;
 import 'package:analysis_server/src/services/correction/fix.dart';
@@ -42,14 +45,14 @@
   SourceChange change;
   String resultCode;
 
-  void assert_undefinedFunction_create_returnType_bool(String lineWithTest) {
+  assert_undefinedFunction_create_returnType_bool(String lineWithTest) async {
     resolveTestUnit('''
 main() {
   bool b = true;
   $lineWithTest
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 main() {
@@ -62,9 +65,9 @@
 ''');
   }
 
-  void assertHasFix(FixKind kind, String expected) {
+  assertHasFix(FixKind kind, String expected) async {
     AnalysisError error = _findErrorToFix();
-    fix = _assertHasFix(kind, error);
+    fix = await _assertHasFix(kind, error);
     change = fix.change;
     // apply to "file"
     List<SourceFileEdit> fileEdits = change.edits;
@@ -74,9 +77,9 @@
     expect(resultCode, expected);
   }
 
-  void assertNoFix(FixKind kind) {
+  assertNoFix(FixKind kind) async {
     AnalysisError error = _findErrorToFix();
-    List<Fix> fixes = _computeFixes(error);
+    List<Fix> fixes = await _computeFixes(error);
     for (Fix fix in fixes) {
       if (fix.kind == kind) {
         throw fail('Unexpected fix $kind in\n${fixes.join('\n')}');
@@ -109,7 +112,7 @@
     verifyNoTestUnitErrors = false;
   }
 
-  void test_addFieldFormalParameters_hasRequiredParameter() {
+  test_addFieldFormalParameters_hasRequiredParameter() async {
     resolveTestUnit('''
 class Test {
   final int a;
@@ -118,7 +121,7 @@
   Test(this.a);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.ADD_FIELD_FORMAL_PARAMETERS,
         '''
 class Test {
@@ -130,7 +133,7 @@
 ''');
   }
 
-  void test_addFieldFormalParameters_noParameters() {
+  test_addFieldFormalParameters_noParameters() async {
     resolveTestUnit('''
 class Test {
   final int a;
@@ -139,7 +142,7 @@
   Test();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.ADD_FIELD_FORMAL_PARAMETERS,
         '''
 class Test {
@@ -151,7 +154,7 @@
 ''');
   }
 
-  void test_addFieldFormalParameters_noRequiredParameter() {
+  test_addFieldFormalParameters_noRequiredParameter() async {
     resolveTestUnit('''
 class Test {
   final int a;
@@ -160,7 +163,7 @@
   Test([this.c]);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.ADD_FIELD_FORMAL_PARAMETERS,
         '''
 class Test {
@@ -172,14 +175,24 @@
 ''');
   }
 
-  void test_addMissingParameter_function_positional_hasZero() {
+  test_addMissingParameter_function_positional_hasNamed() async {
+    resolveTestUnit('''
+test({int a}) {}
+main() {
+  test(1);
+}
+''');
+    await assertNoFix(DartFixKind.ADD_MISSING_PARAMETER_POSITIONAL);
+  }
+
+  test_addMissingParameter_function_positional_hasZero() async {
     resolveTestUnit('''
 test() {}
 main() {
   test(1);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.ADD_MISSING_PARAMETER_POSITIONAL,
         '''
 test([int i]) {}
@@ -189,14 +202,31 @@
 ''');
   }
 
-  void test_addMissingParameter_function_required_hasOne() {
+  test_addMissingParameter_function_required_hasNamed() async {
+    resolveTestUnit('''
+test({int a}) {}
+main() {
+  test(1);
+}
+''');
+    await assertHasFix(
+        DartFixKind.ADD_MISSING_PARAMETER_REQUIRED,
+        '''
+test(int i, {int a}) {}
+main() {
+  test(1);
+}
+''');
+  }
+
+  test_addMissingParameter_function_required_hasOne() async {
     resolveTestUnit('''
 test(int a) {}
 main() {
   test(1, 2.0);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.ADD_MISSING_PARAMETER_REQUIRED,
         '''
 test(int a, double d) {}
@@ -206,14 +236,14 @@
 ''');
   }
 
-  void test_addMissingParameter_function_required_hasZero() {
+  test_addMissingParameter_function_required_hasZero() async {
     resolveTestUnit('''
 test() {}
 main() {
   test(1);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.ADD_MISSING_PARAMETER_REQUIRED,
         '''
 test(int i) {}
@@ -223,7 +253,7 @@
 ''');
   }
 
-  void test_addMissingParameter_method_positional_hasOne() {
+  test_addMissingParameter_method_positional_hasOne() async {
     resolveTestUnit('''
 class A {
   test(int a) {}
@@ -232,7 +262,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.ADD_MISSING_PARAMETER_POSITIONAL,
         '''
 class A {
@@ -244,7 +274,7 @@
 ''');
   }
 
-  void test_addMissingParameter_method_required_hasOne() {
+  test_addMissingParameter_method_required_hasOne() async {
     resolveTestUnit('''
 class A {
   test(int a) {}
@@ -253,7 +283,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.ADD_MISSING_PARAMETER_REQUIRED,
         '''
 class A {
@@ -265,7 +295,7 @@
 ''');
   }
 
-  void test_addMissingParameter_method_required_hasZero() {
+  test_addMissingParameter_method_required_hasZero() async {
     resolveTestUnit('''
 class A {
   test() {}
@@ -274,7 +304,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.ADD_MISSING_PARAMETER_REQUIRED,
         '''
 class A {
@@ -286,7 +316,7 @@
 ''');
   }
 
-  void test_addPartOfDirective() {
+  test_addPartOfDirective() async {
     String partCode = r'''
 // Comment first.
 // Comment second.
@@ -300,7 +330,7 @@
 ''');
     _performAnalysis();
     AnalysisError error = _findErrorToFix();
-    fix = _assertHasFix(DartFixKind.ADD_PART_OF, error);
+    fix = await _assertHasFix(DartFixKind.ADD_PART_OF, error);
     change = fix.change;
     // apply to "file"
     List<SourceFileEdit> fileEdits = change.edits;
@@ -319,14 +349,14 @@
 ''');
   }
 
-  void test_addSync_BAD_nullFunctionBody() {
+  test_addSync_BAD_nullFunctionBody() async {
     resolveTestUnit('''
 var F = await;
 ''');
-    assertNoFix(DartFixKind.ADD_ASYNC);
+    await assertNoFix(DartFixKind.ADD_ASYNC);
   }
 
-  void test_addSync_blockFunctionBody() {
+  test_addSync_blockFunctionBody() async {
     resolveTestUnit('''
 foo() {}
 main() {
@@ -340,11 +370,11 @@
     expect(errors.map((e) => e.message), unorderedEquals([message1, message2]));
     for (AnalysisError error in errors) {
       if (error.message == message1) {
-        List<Fix> fixes = _computeFixes(error);
+        List<Fix> fixes = await _computeFixes(error);
         expect(fixes, isEmpty);
       }
       if (error.message == message2) {
-        List<Fix> fixes = _computeFixes(error);
+        List<Fix> fixes = await _computeFixes(error);
         // has exactly one fix
         expect(fixes, hasLength(1));
         Fix fix = fixes[0];
@@ -366,7 +396,7 @@
     }
   }
 
-  void test_addSync_expressionFunctionBody() {
+  test_addSync_expressionFunctionBody() async {
     errorFilter = (AnalysisError error) {
       return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER;
     };
@@ -374,7 +404,7 @@
 foo() {}
 main() => await foo();
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.ADD_ASYNC,
         '''
 foo() {}
@@ -382,13 +412,13 @@
 ''');
   }
 
-  void test_boolean() {
+  test_boolean() async {
     resolveTestUnit('''
 main() {
   boolean v;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REPLACE_BOOLEAN_WITH_BOOL,
         '''
 main() {
@@ -397,13 +427,13 @@
 ''');
   }
 
-  void test_canBeNullAfterNullAware_chain() {
+  test_canBeNullAfterNullAware_chain() async {
     resolveTestUnit('''
 main(x) {
   x?.a.b.c;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REPLACE_WITH_NULL_AWARE,
         '''
 main(x) {
@@ -412,13 +442,13 @@
 ''');
   }
 
-  void test_canBeNullAfterNullAware_methodInvocation() {
+  test_canBeNullAfterNullAware_methodInvocation() async {
     resolveTestUnit('''
 main(x) {
   x?.a.b();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REPLACE_WITH_NULL_AWARE,
         '''
 main(x) {
@@ -427,13 +457,13 @@
 ''');
   }
 
-  void test_canBeNullAfterNullAware_propertyAccess() {
+  test_canBeNullAfterNullAware_propertyAccess() async {
     resolveTestUnit('''
 main(x) {
   x?.a().b;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REPLACE_WITH_NULL_AWARE,
         '''
 main(x) {
@@ -442,7 +472,7 @@
 ''');
   }
 
-  void test_changeToStaticAccess_method() {
+  test_changeToStaticAccess_method() async {
     resolveTestUnit('''
 class A {
   static foo() {}
@@ -451,7 +481,7 @@
   a.foo();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO_STATIC_ACCESS,
         '''
 class A {
@@ -463,7 +493,7 @@
 ''');
   }
 
-  void test_changeToStaticAccess_method_importType() {
+  test_changeToStaticAccess_method_importType() async {
     addSource(
         '/libA.dart',
         r'''
@@ -485,7 +515,7 @@
   b.foo();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO_STATIC_ACCESS,
         '''
 import 'libB.dart';
@@ -496,14 +526,14 @@
 ''');
   }
 
-  void test_changeToStaticAccess_method_prefixLibrary() {
+  test_changeToStaticAccess_method_prefixLibrary() async {
     resolveTestUnit('''
 import 'dart:async' as pref;
 main(pref.Future f) {
   f.wait([]);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO_STATIC_ACCESS,
         '''
 import 'dart:async' as pref;
@@ -513,7 +543,7 @@
 ''');
   }
 
-  void test_changeToStaticAccess_property() {
+  test_changeToStaticAccess_property() async {
     resolveTestUnit('''
 class A {
   static get foo => 42;
@@ -522,7 +552,7 @@
   a.foo;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO_STATIC_ACCESS,
         '''
 class A {
@@ -534,7 +564,7 @@
 ''');
   }
 
-  void test_changeToStaticAccess_property_importType() {
+  test_changeToStaticAccess_property_importType() async {
     addSource(
         '/libA.dart',
         r'''
@@ -556,7 +586,7 @@
   b.foo;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO_STATIC_ACCESS,
         '''
 import 'libB.dart';
@@ -567,13 +597,62 @@
 ''');
   }
 
-  void test_createClass() {
+  test_changeTypeAnnotation_BAD_multipleVariables() async {
+    resolveTestUnit('''
+main() {
+  String a, b = 42;
+}
+''');
+    await assertNoFix(DartFixKind.CHANGE_TYPE_ANNOTATION);
+  }
+
+  test_changeTypeAnnotation_BAD_notVariableDeclaration() async {
+    resolveTestUnit('''
+main() {
+  String v;
+  v = 42;
+}
+''');
+    await assertNoFix(DartFixKind.CHANGE_TYPE_ANNOTATION);
+  }
+
+  test_changeTypeAnnotation_OK_generic() async {
+    resolveTestUnit('''
+main() {
+  String v = <int>[];
+}
+''');
+    await assertHasFix(
+        DartFixKind.CHANGE_TYPE_ANNOTATION,
+        '''
+main() {
+  List<int> v = <int>[];
+}
+''');
+  }
+
+  test_changeTypeAnnotation_OK_simple() async {
+    resolveTestUnit('''
+main() {
+  String v = 'abc'.length;
+}
+''');
+    await assertHasFix(
+        DartFixKind.CHANGE_TYPE_ANNOTATION,
+        '''
+main() {
+  int v = 'abc'.length;
+}
+''');
+  }
+
+  test_createClass() async {
     resolveTestUnit('''
 main() {
   Test v = null;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_CLASS,
         '''
 main() {
@@ -586,16 +665,16 @@
     _assertLinkedGroup(change.linkedEditGroups[0], ['Test v =', 'Test {']);
   }
 
-  void test_createClass_BAD_hasUnresolvedPrefix() {
+  test_createClass_BAD_hasUnresolvedPrefix() async {
     resolveTestUnit('''
 main() {
   prefix.Test v = null;
 }
 ''');
-    assertNoFix(DartFixKind.CREATE_CLASS);
+    await assertNoFix(DartFixKind.CREATE_CLASS);
   }
 
-  void test_createClass_inLibraryOfPrefix() {
+  test_createClass_inLibraryOfPrefix() async {
     String libCode = r'''
 library my.lib;
 
@@ -611,7 +690,7 @@
 }
 ''');
     AnalysisError error = _findErrorToFix();
-    fix = _assertHasFix(DartFixKind.CREATE_CLASS, error);
+    fix = await _assertHasFix(DartFixKind.CREATE_CLASS, error);
     change = fix.change;
     // apply to "lib.dart"
     List<SourceFileEdit> fileEdits = change.edits;
@@ -631,7 +710,7 @@
     expect(change.linkedEditGroups, isEmpty);
   }
 
-  void test_createClass_innerLocalFunction() {
+  test_createClass_innerLocalFunction() async {
     resolveTestUnit('''
 f() {
   g() {
@@ -639,7 +718,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_CLASS,
         '''
 f() {
@@ -654,13 +733,13 @@
     _assertLinkedGroup(change.linkedEditGroups[0], ['Test v =', 'Test {']);
   }
 
-  void test_createClass_itemOfList() {
+  test_createClass_itemOfList() async {
     resolveTestUnit('''
 main() {
   var a = [Test];
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_CLASS,
         '''
 main() {
@@ -673,7 +752,7 @@
     _assertLinkedGroup(change.linkedEditGroups[0], ['Test];', 'Test {']);
   }
 
-  void test_createClass_itemOfList_inAnnotation() {
+  test_createClass_itemOfList_inAnnotation() async {
     errorFilter = (AnalysisError error) {
       return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER;
     };
@@ -684,7 +763,7 @@
 @MyAnnotation(int, const [Test])
 main() {}
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_CLASS,
         '''
 class MyAnnotation {
@@ -699,7 +778,7 @@
     _assertLinkedGroup(change.linkedEditGroups[0], ['Test])', 'Test {']);
   }
 
-  void test_createConstructor_forFinalFields() {
+  test_createConstructor_forFinalFields() async {
     errorFilter = (AnalysisError error) {
       return error.message.contains("'a'");
     };
@@ -710,7 +789,7 @@
   final int c;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS,
         '''
 class Test {
@@ -723,7 +802,7 @@
 ''');
   }
 
-  void test_createConstructor_insteadOfSyntheticDefault() {
+  test_createConstructor_insteadOfSyntheticDefault() async {
     resolveTestUnit('''
 class A {
   int field;
@@ -734,7 +813,7 @@
   new A(1, 2.0);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_CONSTRUCTOR,
         '''
 class A {
@@ -751,7 +830,7 @@
 ''');
   }
 
-  void test_createConstructor_named() {
+  test_createConstructor_named() async {
     resolveTestUnit('''
 class A {
   method() {}
@@ -760,7 +839,7 @@
   new A.named(1, 2.0);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_CONSTRUCTOR,
         '''
 class A {
@@ -776,23 +855,23 @@
     _assertLinkedGroup(change.linkedEditGroups[0], ['named(int ', 'named(1']);
   }
 
-  void test_createConstructorForFinalFields_inTopLevelMethod() {
+  test_createConstructorForFinalFields_inTopLevelMethod() async {
     resolveTestUnit('''
 main() {
   final int v;
 }
 ''');
-    assertNoFix(DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS);
+    await assertNoFix(DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS);
   }
 
-  void test_createConstructorForFinalFields_topLevelField() {
+  test_createConstructorForFinalFields_topLevelField() async {
     resolveTestUnit('''
 final int v;
 ''');
-    assertNoFix(DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS);
+    await assertNoFix(DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS);
   }
 
-  void test_createConstructorSuperExplicit() {
+  test_createConstructorSuperExplicit() async {
     resolveTestUnit('''
 class A {
   A(bool p1, int p2, double p3, String p4, {p5});
@@ -801,7 +880,7 @@
   B() {}
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION,
         '''
 class A {
@@ -813,7 +892,7 @@
 ''');
   }
 
-  void test_createConstructorSuperExplicit_hasInitializers() {
+  test_createConstructorSuperExplicit_hasInitializers() async {
     resolveTestUnit('''
 class A {
   A(int p);
@@ -823,7 +902,7 @@
   B() : field = 42 {}
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION,
         '''
 class A {
@@ -836,7 +915,7 @@
 ''');
   }
 
-  void test_createConstructorSuperExplicit_named() {
+  test_createConstructorSuperExplicit_named() async {
     resolveTestUnit('''
 class A {
   A.named(int p);
@@ -845,7 +924,7 @@
   B() {}
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION,
         '''
 class A {
@@ -857,7 +936,7 @@
 ''');
   }
 
-  void test_createConstructorSuperExplicit_named_private() {
+  test_createConstructorSuperExplicit_named_private() async {
     resolveTestUnit('''
 class A {
   A._named(int p);
@@ -866,10 +945,10 @@
   B() {}
 }
 ''');
-    assertNoFix(DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION);
+    await assertNoFix(DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION);
   }
 
-  void test_createConstructorSuperExplicit_typeArgument() {
+  test_createConstructorSuperExplicit_typeArgument() async {
     resolveTestUnit('''
 class A<T> {
   A(T p);
@@ -878,7 +957,7 @@
   B();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION,
         '''
 class A<T> {
@@ -890,7 +969,7 @@
 ''');
   }
 
-  void test_createConstructorSuperImplicit() {
+  test_createConstructorSuperImplicit() async {
     resolveTestUnit('''
 class A {
   A(p1, int p2, List<String> p3, [int p4]);
@@ -901,7 +980,7 @@
   void existingMethod() {}
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_CONSTRUCTOR_SUPER,
         '''
 class A {
@@ -917,7 +996,7 @@
 ''');
   }
 
-  void test_createConstructorSuperImplicit_fieldInitializer() {
+  test_createConstructorSuperImplicit_fieldInitializer() async {
     resolveTestUnit('''
 class A {
   int _field;
@@ -929,7 +1008,7 @@
   void existingMethod() {}
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_CONSTRUCTOR_SUPER,
         '''
 class A {
@@ -946,7 +1025,7 @@
 ''');
   }
 
-  void test_createConstructorSuperImplicit_importType() {
+  test_createConstructorSuperImplicit_importType() async {
     addSource(
         '/libA.dart',
         r'''
@@ -967,7 +1046,7 @@
 class C extends B {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_CONSTRUCTOR_SUPER,
         '''
 import 'libB.dart';
@@ -978,7 +1057,7 @@
 ''');
   }
 
-  void test_createConstructorSuperImplicit_named() {
+  test_createConstructorSuperImplicit_named() async {
     resolveTestUnit('''
 class A {
   A.named(p1, int p2);
@@ -989,7 +1068,7 @@
   void existingMethod() {}
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_CONSTRUCTOR_SUPER,
         '''
 class A {
@@ -1005,7 +1084,7 @@
 ''');
   }
 
-  void test_createConstructorSuperImplicit_private() {
+  test_createConstructorSuperImplicit_private() async {
     resolveTestUnit('''
 class A {
   A._named(p);
@@ -1013,10 +1092,10 @@
 class B extends A {
 }
 ''');
-    assertNoFix(DartFixKind.CREATE_CONSTRUCTOR_SUPER);
+    await assertNoFix(DartFixKind.CREATE_CONSTRUCTOR_SUPER);
   }
 
-  void test_createConstructorSuperImplicit_typeArgument() {
+  test_createConstructorSuperImplicit_typeArgument() async {
     resolveTestUnit('''
 class C<T> {
   final T x;
@@ -1024,7 +1103,7 @@
 }
 class D extends C<int> {
 }''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_CONSTRUCTOR_SUPER,
         '''
 class C<T> {
@@ -1036,7 +1115,7 @@
 }''');
   }
 
-  void test_createField_BAD_inEnum() {
+  test_createField_BAD_inEnum() async {
     resolveTestUnit('''
 enum MyEnum {
   AAA, BBB
@@ -1045,19 +1124,19 @@
   MyEnum.foo;
 }
 ''');
-    assertNoFix(DartFixKind.CREATE_FIELD);
+    await assertNoFix(DartFixKind.CREATE_FIELD);
   }
 
-  void test_createField_BAD_inSDK() {
+  test_createField_BAD_inSDK() async {
     resolveTestUnit('''
 main(List p) {
   p.foo = 1;
 }
 ''');
-    assertNoFix(DartFixKind.CREATE_FIELD);
+    await assertNoFix(DartFixKind.CREATE_FIELD);
   }
 
-  void test_createField_getter_multiLevel() {
+  test_createField_getter_multiLevel() async {
     resolveTestUnit('''
 class A {
 }
@@ -1071,7 +1150,7 @@
   int v = c.b.a.test;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FIELD,
         '''
 class A {
@@ -1089,7 +1168,7 @@
 ''');
   }
 
-  void test_createField_getter_qualified_instance() {
+  test_createField_getter_qualified_instance() async {
     resolveTestUnit('''
 class A {
 }
@@ -1097,7 +1176,7 @@
   int v = a.test;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FIELD,
         '''
 class A {
@@ -1109,7 +1188,7 @@
 ''');
   }
 
-  void test_createField_getter_qualified_instance_dynamicType() {
+  test_createField_getter_qualified_instance_dynamicType() async {
     resolveTestUnit('''
 class A {
   B b;
@@ -1120,7 +1199,7 @@
 class B {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FIELD,
         '''
 class A {
@@ -1135,7 +1214,7 @@
 ''');
   }
 
-  void test_createField_getter_unqualified_instance_asInvocationArgument() {
+  test_createField_getter_unqualified_instance_asInvocationArgument() async {
     resolveTestUnit('''
 class A {
   main() {
@@ -1144,7 +1223,7 @@
 }
 f(String s) {}
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FIELD,
         '''
 class A {
@@ -1158,7 +1237,7 @@
 ''');
   }
 
-  void test_createField_getter_unqualified_instance_assignmentRhs() {
+  test_createField_getter_unqualified_instance_assignmentRhs() async {
     resolveTestUnit('''
 class A {
   main() {
@@ -1166,7 +1245,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FIELD,
         '''
 class A {
@@ -1179,7 +1258,7 @@
 ''');
   }
 
-  void test_createField_getter_unqualified_instance_asStatement() {
+  test_createField_getter_unqualified_instance_asStatement() async {
     resolveTestUnit('''
 class A {
   main() {
@@ -1187,7 +1266,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FIELD,
         '''
 class A {
@@ -1200,7 +1279,7 @@
 ''');
   }
 
-  void test_createField_hint() {
+  test_createField_hint() async {
     resolveTestUnit('''
 class A {
 }
@@ -1209,7 +1288,7 @@
   int v = x.test;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FIELD,
         '''
 class A {
@@ -1222,7 +1301,7 @@
 ''');
   }
 
-  void test_createField_hint_setter() {
+  test_createField_hint_setter() async {
     resolveTestUnit('''
 class A {
 }
@@ -1231,7 +1310,7 @@
   x.test = 0;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FIELD,
         '''
 class A {
@@ -1244,7 +1323,7 @@
 ''');
   }
 
-  void test_createField_importType() {
+  test_createField_importType() async {
     addSource(
         '/libA.dart',
         r'''
@@ -1266,7 +1345,7 @@
   c.test = getA();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FIELD,
         '''
 import 'libB.dart';
@@ -1280,7 +1359,7 @@
 ''');
   }
 
-  void test_createField_setter_generic_BAD() {
+  test_createField_setter_generic_BAD() async {
     resolveTestUnit('''
 class A {
 }
@@ -1291,7 +1370,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FIELD,
         '''
 class A {
@@ -1306,7 +1385,7 @@
 ''');
   }
 
-  void test_createField_setter_generic_OK_local() {
+  test_createField_setter_generic_OK_local() async {
     resolveTestUnit('''
 class A<T> {
   List<T> items;
@@ -1316,7 +1395,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FIELD,
         '''
 class A<T> {
@@ -1331,7 +1410,7 @@
 ''');
   }
 
-  void test_createField_setter_qualified_instance_hasField() {
+  test_createField_setter_qualified_instance_hasField() async {
     resolveTestUnit('''
 class A {
   int aaa;
@@ -1343,7 +1422,7 @@
   a.test = 5;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FIELD,
         '''
 class A {
@@ -1360,7 +1439,7 @@
 ''');
   }
 
-  void test_createField_setter_qualified_instance_hasMethod() {
+  test_createField_setter_qualified_instance_hasMethod() async {
     resolveTestUnit('''
 class A {
   existingMethod() {}
@@ -1369,7 +1448,7 @@
   a.test = 5;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FIELD,
         '''
 class A {
@@ -1383,7 +1462,7 @@
 ''');
   }
 
-  void test_createField_setter_qualified_static() {
+  test_createField_setter_qualified_static() async {
     resolveTestUnit('''
 class A {
 }
@@ -1391,7 +1470,7 @@
   A.test = 5;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FIELD,
         '''
 class A {
@@ -1403,7 +1482,7 @@
 ''');
   }
 
-  void test_createField_setter_unqualified_instance() {
+  test_createField_setter_unqualified_instance() async {
     resolveTestUnit('''
 class A {
   main() {
@@ -1411,7 +1490,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FIELD,
         '''
 class A {
@@ -1424,7 +1503,7 @@
 ''');
   }
 
-  void test_createField_setter_unqualified_static() {
+  test_createField_setter_unqualified_static() async {
     resolveTestUnit('''
 class A {
   static main() {
@@ -1432,7 +1511,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FIELD,
         '''
 class A {
@@ -1445,13 +1524,13 @@
 ''');
   }
 
-  void test_createFile_forImport() {
+  test_createFile_forImport() async {
     testFile = '/my/project/bin/test.dart';
     resolveTestUnit('''
 import 'my_file.dart';
 ''');
     AnalysisError error = _findErrorToFix();
-    fix = _assertHasFix(DartFixKind.CREATE_FILE, error);
+    fix = await _assertHasFix(DartFixKind.CREATE_FILE, error);
     change = fix.change;
     // validate change
     List<SourceFileEdit> fileEdits = change.edits;
@@ -1463,7 +1542,24 @@
     expect(fileEdit.edits[0].replacement, contains('library my_file;'));
   }
 
-  void test_createFile_forImport_inPackage_lib() {
+  test_createFile_forImport_BAD_inPackage_lib_justLib() async {
+    provider.newFile('/projects/my_package/pubspec.yaml', 'name: my_package');
+    testFile = '/projects/my_package/test.dart';
+    resolveTestUnit('''
+import 'lib';
+''');
+    await assertNoFix(DartFixKind.CREATE_FILE);
+  }
+
+  test_createFile_forImport_BAD_notDart() async {
+    testFile = '/my/project/bin/test.dart';
+    resolveTestUnit('''
+import 'my_file.txt';
+''');
+    await assertNoFix(DartFixKind.CREATE_FILE);
+  }
+
+  test_createFile_forImport_inPackage_lib() async {
     provider.newFile('/projects/my_package/pubspec.yaml', 'name: my_package');
     testFile = '/projects/my_package/lib/test.dart';
     provider.newFolder('/projects/my_package/lib');
@@ -1471,7 +1567,7 @@
 import 'a/bb/c_cc/my_lib.dart';
 ''');
     AnalysisError error = _findErrorToFix();
-    fix = _assertHasFix(DartFixKind.CREATE_FILE, error);
+    fix = await _assertHasFix(DartFixKind.CREATE_FILE, error);
     change = fix.change;
     // validate change
     List<SourceFileEdit> fileEdits = change.edits;
@@ -1484,14 +1580,14 @@
         contains('library my_package.a.bb.c_cc.my_lib;'));
   }
 
-  void test_createFile_forImport_inPackage_test() {
+  test_createFile_forImport_inPackage_test() async {
     provider.newFile('/projects/my_package/pubspec.yaml', 'name: my_package');
     testFile = '/projects/my_package/test/misc/test_all.dart';
     resolveTestUnit('''
 import 'a/bb/my_lib.dart';
 ''');
     AnalysisError error = _findErrorToFix();
-    fix = _assertHasFix(DartFixKind.CREATE_FILE, error);
+    fix = await _assertHasFix(DartFixKind.CREATE_FILE, error);
     change = fix.change;
     // validate change
     List<SourceFileEdit> fileEdits = change.edits;
@@ -1504,14 +1600,14 @@
         contains('library my_package.test.misc.a.bb.my_lib;'));
   }
 
-  void test_createFile_forPart() {
+  test_createFile_forPart() async {
     testFile = '/my/project/bin/test.dart';
     resolveTestUnit('''
 library my.lib;
 part 'my_part.dart';
 ''');
     AnalysisError error = _findErrorToFix();
-    fix = _assertHasFix(DartFixKind.CREATE_FILE, error);
+    fix = await _assertHasFix(DartFixKind.CREATE_FILE, error);
     change = fix.change;
     // validate change
     List<SourceFileEdit> fileEdits = change.edits;
@@ -1523,7 +1619,7 @@
     expect(fileEdit.edits[0].replacement, contains('part of my.lib;'));
   }
 
-  void test_createFile_forPart_inPackageLib() {
+  test_createFile_forPart_inPackageLib() async {
     provider.newFile(
         '/my/pubspec.yaml',
         r'''
@@ -1545,7 +1641,7 @@
     // prepare fix
     testUnit = resolveLibraryUnit(testSource);
     AnalysisError error = _findErrorToFix();
-    fix = _assertHasFix(DartFixKind.CREATE_FILE, error);
+    fix = await _assertHasFix(DartFixKind.CREATE_FILE, error);
     change = fix.change;
     // validate change
     List<SourceFileEdit> fileEdits = change.edits;
@@ -1557,16 +1653,16 @@
     expect(fileEdit.edits[0].replacement, contains('part of my.lib;'));
   }
 
-  void test_createGetter_BAD_inSDK() {
+  test_createGetter_BAD_inSDK() async {
     resolveTestUnit('''
 main(List p) {
   int v = p.foo;
 }
 ''');
-    assertNoFix(DartFixKind.CREATE_GETTER);
+    await assertNoFix(DartFixKind.CREATE_GETTER);
   }
 
-  void test_createGetter_hint_getter() {
+  test_createGetter_hint_getter() async {
     resolveTestUnit('''
 class A {
 }
@@ -1575,7 +1671,7 @@
   int v = x.test;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_GETTER,
         '''
 class A {
@@ -1588,7 +1684,7 @@
 ''');
   }
 
-  void test_createGetter_location_afterLastGetter() {
+  test_createGetter_location_afterLastGetter() async {
     resolveTestUnit('''
 class A {
   int existingField;
@@ -1601,7 +1697,7 @@
   int v = a.test;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_GETTER,
         '''
 class A {
@@ -1619,7 +1715,7 @@
 ''');
   }
 
-  void test_createGetter_multiLevel() {
+  test_createGetter_multiLevel() async {
     resolveTestUnit('''
 class A {
 }
@@ -1633,7 +1729,7 @@
   int v = c.b.a.test;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_GETTER,
         '''
 class A {
@@ -1651,7 +1747,7 @@
 ''');
   }
 
-  void test_createGetter_qualified_instance() {
+  test_createGetter_qualified_instance() async {
     resolveTestUnit('''
 class A {
 }
@@ -1659,7 +1755,7 @@
   int v = a.test;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_GETTER,
         '''
 class A {
@@ -1671,7 +1767,7 @@
 ''');
   }
 
-  void test_createGetter_qualified_instance_dynamicType() {
+  test_createGetter_qualified_instance_dynamicType() async {
     resolveTestUnit('''
 class A {
   B b;
@@ -1682,7 +1778,7 @@
 class B {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_GETTER,
         '''
 class A {
@@ -1697,7 +1793,7 @@
 ''');
   }
 
-  void test_createGetter_setterContext() {
+  test_createGetter_setterContext() async {
     resolveTestUnit('''
 class A {
 }
@@ -1705,10 +1801,10 @@
   a.test = 42;
 }
 ''');
-    assertNoFix(DartFixKind.CREATE_GETTER);
+    await assertNoFix(DartFixKind.CREATE_GETTER);
   }
 
-  void test_createGetter_unqualified_instance_asInvocationArgument() {
+  test_createGetter_unqualified_instance_asInvocationArgument() async {
     resolveTestUnit('''
 class A {
   main() {
@@ -1717,7 +1813,7 @@
 }
 f(String s) {}
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_GETTER,
         '''
 class A {
@@ -1731,7 +1827,7 @@
 ''');
   }
 
-  void test_createGetter_unqualified_instance_assignmentLhs() {
+  test_createGetter_unqualified_instance_assignmentLhs() async {
     resolveTestUnit('''
 class A {
   main() {
@@ -1739,10 +1835,10 @@
   }
 }
 ''');
-    assertNoFix(DartFixKind.CREATE_GETTER);
+    await assertNoFix(DartFixKind.CREATE_GETTER);
   }
 
-  void test_createGetter_unqualified_instance_assignmentRhs() {
+  test_createGetter_unqualified_instance_assignmentRhs() async {
     resolveTestUnit('''
 class A {
   main() {
@@ -1750,7 +1846,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_GETTER,
         '''
 class A {
@@ -1763,7 +1859,7 @@
 ''');
   }
 
-  void test_createGetter_unqualified_instance_asStatement() {
+  test_createGetter_unqualified_instance_asStatement() async {
     resolveTestUnit('''
 class A {
   main() {
@@ -1771,7 +1867,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_GETTER,
         '''
 class A {
@@ -1784,7 +1880,7 @@
 ''');
   }
 
-  void test_createLocalVariable_functionType_named() {
+  test_createLocalVariable_functionType_named() async {
     resolveTestUnit('''
 typedef MY_FUNCTION(int p);
 foo(MY_FUNCTION f) {}
@@ -1792,7 +1888,7 @@
   foo(bar);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_LOCAL_VARIABLE,
         '''
 typedef MY_FUNCTION(int p);
@@ -1804,23 +1900,23 @@
 ''');
   }
 
-  void test_createLocalVariable_functionType_synthetic() {
+  test_createLocalVariable_functionType_synthetic() async {
     resolveTestUnit('''
 foo(f(int p)) {}
 main() {
   foo(bar);
 }
 ''');
-    assertNoFix(DartFixKind.CREATE_LOCAL_VARIABLE);
+    await assertNoFix(DartFixKind.CREATE_LOCAL_VARIABLE);
   }
 
-  void test_createLocalVariable_read_typeAssignment() {
+  test_createLocalVariable_read_typeAssignment() async {
     resolveTestUnit('''
 main() {
   int a = test;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_LOCAL_VARIABLE,
         '''
 main() {
@@ -1830,7 +1926,7 @@
 ''');
   }
 
-  void test_createLocalVariable_read_typeCondition() {
+  test_createLocalVariable_read_typeCondition() async {
     resolveTestUnit('''
 main() {
   if (!test) {
@@ -1838,7 +1934,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_LOCAL_VARIABLE,
         '''
 main() {
@@ -1850,14 +1946,14 @@
 ''');
   }
 
-  void test_createLocalVariable_read_typeInvocationArgument() {
+  test_createLocalVariable_read_typeInvocationArgument() async {
     resolveTestUnit('''
 main() {
   f(test);
 }
 f(String p) {}
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_LOCAL_VARIABLE,
         '''
 main() {
@@ -1870,13 +1966,13 @@
     _assertLinkedGroup(change.linkedEditGroups[1], ['test;', 'test);']);
   }
 
-  void test_createLocalVariable_read_typeInvocationTarget() {
+  test_createLocalVariable_read_typeInvocationTarget() async {
     resolveTestUnit('''
 main() {
   test.add('hello');
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_LOCAL_VARIABLE,
         '''
 main() {
@@ -1887,13 +1983,13 @@
     _assertLinkedGroup(change.linkedEditGroups[0], ['test;', 'test.add(']);
   }
 
-  void test_createLocalVariable_write_assignment() {
+  test_createLocalVariable_write_assignment() async {
     resolveTestUnit('''
 main() {
   test = 42;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_LOCAL_VARIABLE,
         '''
 main() {
@@ -1902,13 +1998,13 @@
 ''');
   }
 
-  void test_createLocalVariable_write_assignment_compound() {
+  test_createLocalVariable_write_assignment_compound() async {
     resolveTestUnit('''
 main() {
   test += 42;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_LOCAL_VARIABLE,
         '''
 main() {
@@ -1918,7 +2014,7 @@
 ''');
   }
 
-  void test_createMissingOverrides_functionTypeAlias() {
+  test_createMissingOverrides_functionTypeAlias() async {
     resolveTestUnit('''
 typedef int Binary(int left, int right);
 
@@ -1929,7 +2025,7 @@
 class MyEmulator extends Emulator {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_MISSING_OVERRIDES,
         '''
 typedef int Binary(int left, int right);
@@ -1947,7 +2043,7 @@
 ''');
   }
 
-  void test_createMissingOverrides_functionTypedParameter() {
+  test_createMissingOverrides_functionTypedParameter() async {
     resolveTestUnit('''
 abstract class A {
   forEach(int f(double p1, String p2));
@@ -1956,7 +2052,7 @@
 class B extends A {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_MISSING_OVERRIDES,
         '''
 abstract class A {
@@ -1972,7 +2068,7 @@
 ''');
   }
 
-  void test_createMissingOverrides_generics_typeArguments() {
+  test_createMissingOverrides_generics_typeArguments() async {
     resolveTestUnit('''
 class Iterator<T> {
 }
@@ -1984,7 +2080,7 @@
 class Test extends IterableMixin<int> {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_MISSING_OVERRIDES,
         '''
 class Iterator<T> {
@@ -2002,7 +2098,7 @@
 ''');
   }
 
-  void test_createMissingOverrides_generics_typeParameters() {
+  test_createMissingOverrides_generics_typeParameters() async {
     resolveTestUnit('''
 abstract class ItemProvider<T> {
   List<T> getItems();
@@ -2011,7 +2107,7 @@
 class Test<V> extends ItemProvider<V> {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_MISSING_OVERRIDES,
         '''
 abstract class ItemProvider<T> {
@@ -2027,7 +2123,7 @@
 ''');
   }
 
-  void test_createMissingOverrides_getter() {
+  test_createMissingOverrides_getter() async {
     resolveTestUnit('''
 abstract class A {
   get g1;
@@ -2037,7 +2133,7 @@
 class B extends A {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_MISSING_OVERRIDES,
         '''
 abstract class A {
@@ -2057,7 +2153,7 @@
 ''');
   }
 
-  void test_createMissingOverrides_importPrefix() {
+  test_createMissingOverrides_importPrefix() async {
     resolveTestUnit('''
 import 'dart:async' as aaa;
 abstract class A {
@@ -2067,7 +2163,7 @@
 class B extends A {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_MISSING_OVERRIDES,
         '''
 import 'dart:async' as aaa;
@@ -2084,7 +2180,7 @@
 ''');
   }
 
-  void test_createMissingOverrides_mergeToField_getterSetter() {
+  test_createMissingOverrides_mergeToField_getterSetter() async {
     resolveTestUnit('''
 class A {
   int ma;
@@ -2095,7 +2191,7 @@
 class B implements A {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_MISSING_OVERRIDES,
         '''
 class A {
@@ -2117,7 +2213,7 @@
 ''');
   }
 
-  void test_createMissingOverrides_method() {
+  test_createMissingOverrides_method() async {
     resolveTestUnit('''
 abstract class A {
   m1();
@@ -2173,7 +2269,7 @@
   }
 }
 ''';
-    assertHasFix(DartFixKind.CREATE_MISSING_OVERRIDES, expectedCode);
+    await assertHasFix(DartFixKind.CREATE_MISSING_OVERRIDES, expectedCode);
     // end position should be on "m1", not on "m2", "m3", etc
     {
       Position endPosition = change.selection;
@@ -2190,7 +2286,7 @@
     }
   }
 
-  void test_createMissingOverrides_operator() {
+  test_createMissingOverrides_operator() async {
     resolveTestUnit('''
 abstract class A {
   int operator [](int index);
@@ -2200,7 +2296,7 @@
 class B extends A {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_MISSING_OVERRIDES,
         '''
 abstract class A {
@@ -2222,7 +2318,7 @@
 ''');
   }
 
-  void test_createMissingOverrides_setter() {
+  test_createMissingOverrides_setter() async {
     resolveTestUnit('''
 abstract class A {
   set s1(x);
@@ -2233,7 +2329,7 @@
 class B extends A {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_MISSING_OVERRIDES,
         '''
 abstract class A {
@@ -2261,7 +2357,7 @@
 ''');
   }
 
-  void test_createNoSuchMethod() {
+  test_createNoSuchMethod() async {
     resolveTestUnit('''
 abstract class A {
   m1();
@@ -2272,7 +2368,7 @@
   existing() {}
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_NO_SUCH_METHOD,
         '''
 abstract class A {
@@ -2288,7 +2384,7 @@
 ''');
   }
 
-  void test_creationFunction_forFunctionType_cascadeSecond() {
+  test_creationFunction_forFunctionType_cascadeSecond() async {
     resolveTestUnit('''
 class A {
   B ma() => null;
@@ -2302,7 +2398,7 @@
   a..ma().useFunction(test);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 class A {
@@ -2322,14 +2418,14 @@
 ''');
   }
 
-  void test_creationFunction_forFunctionType_coreFunction() {
+  test_creationFunction_forFunctionType_coreFunction() async {
     resolveTestUnit('''
 main() {
   useFunction(g: test);
 }
 useFunction({Function g}) {}
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 main() {
@@ -2342,14 +2438,14 @@
 ''');
   }
 
-  void test_creationFunction_forFunctionType_dynamicArgument() {
+  test_creationFunction_forFunctionType_dynamicArgument() async {
     resolveTestUnit('''
 main() {
   useFunction(test);
 }
 useFunction(int g(a, b)) {}
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 main() {
@@ -2362,14 +2458,14 @@
 ''');
   }
 
-  void test_creationFunction_forFunctionType_function() {
+  test_creationFunction_forFunctionType_function() async {
     resolveTestUnit('''
 main() {
   useFunction(test);
 }
 useFunction(int g(double a, String b)) {}
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 main() {
@@ -2382,14 +2478,14 @@
 ''');
   }
 
-  void test_creationFunction_forFunctionType_function_namedArgument() {
+  test_creationFunction_forFunctionType_function_namedArgument() async {
     resolveTestUnit('''
 main() {
   useFunction(g: test);
 }
 useFunction({int g(double a, String b)}) {}
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 main() {
@@ -2402,7 +2498,7 @@
 ''');
   }
 
-  void test_creationFunction_forFunctionType_importType() {
+  test_creationFunction_forFunctionType_importType() async {
     addSource(
         '/libA.dart',
         r'''
@@ -2422,7 +2518,7 @@
   useFunction(test);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 import 'libB.dart';
@@ -2436,7 +2532,7 @@
 ''');
   }
 
-  void test_creationFunction_forFunctionType_method_enclosingClass_static() {
+  test_creationFunction_forFunctionType_method_enclosingClass_static() async {
     resolveTestUnit('''
 class A {
   static foo() {
@@ -2445,7 +2541,7 @@
 }
 useFunction(int g(double a, String b)) {}
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_METHOD,
         '''
 class A {
@@ -2460,7 +2556,7 @@
 ''');
   }
 
-  void test_creationFunction_forFunctionType_method_enclosingClass_static2() {
+  test_creationFunction_forFunctionType_method_enclosingClass_static2() async {
     resolveTestUnit('''
 class A {
   var f;
@@ -2468,7 +2564,7 @@
 }
 useFunction(int g(double a, String b)) {}
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_METHOD,
         '''
 class A {
@@ -2482,7 +2578,7 @@
 ''');
   }
 
-  void test_creationFunction_forFunctionType_method_targetClass() {
+  test_creationFunction_forFunctionType_method_targetClass() async {
     resolveTestUnit('''
 main(A a) {
   useFunction(a.test);
@@ -2491,7 +2587,7 @@
 }
 useFunction(int g(double a, String b)) {}
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_METHOD,
         '''
 main(A a) {
@@ -2505,7 +2601,7 @@
 ''');
   }
 
-  void test_creationFunction_forFunctionType_method_targetClass_hasOtherMember() {
+  test_creationFunction_forFunctionType_method_targetClass_hasOtherMember() async {
     resolveTestUnit('''
 main(A a) {
   useFunction(a.test);
@@ -2515,7 +2611,7 @@
 }
 useFunction(int g(double a, String b)) {}
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_METHOD,
         '''
 main(A a) {
@@ -2531,7 +2627,7 @@
 ''');
   }
 
-  void test_creationFunction_forFunctionType_notFunctionType() {
+  test_creationFunction_forFunctionType_notFunctionType() async {
     resolveTestUnit('''
 main(A a) {
   useFunction(a.test);
@@ -2539,11 +2635,11 @@
 typedef A();
 useFunction(g) {}
 ''');
-    assertNoFix(DartFixKind.CREATE_METHOD);
-    assertNoFix(DartFixKind.CREATE_FUNCTION);
+    await assertNoFix(DartFixKind.CREATE_METHOD);
+    await assertNoFix(DartFixKind.CREATE_FUNCTION);
   }
 
-  void test_creationFunction_forFunctionType_unknownTarget() {
+  test_creationFunction_forFunctionType_unknownTarget() async {
     resolveTestUnit('''
 main(A a) {
   useFunction(a.test);
@@ -2552,16 +2648,16 @@
 }
 useFunction(g) {}
 ''');
-    assertNoFix(DartFixKind.CREATE_METHOD);
+    await assertNoFix(DartFixKind.CREATE_METHOD);
   }
 
-  void test_expectedToken_semicolon() {
+  test_expectedToken_semicolon() async {
     resolveTestUnit('''
 main() {
   print(0)
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.INSERT_SEMICOLON,
         '''
 main() {
@@ -2570,7 +2666,23 @@
 ''');
   }
 
-  void test_illegalAsyncReturnType_asyncLibrary_import() {
+  test_illegalAsyncReturnType_adjacentNodes() async {
+    errorFilter = (AnalysisError error) {
+      return error.errorCode == StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE;
+    };
+    resolveTestUnit('''
+import 'dart:async';
+var v;int main() async => 0;
+''');
+    await assertHasFix(
+        DartFixKind.REPLACE_RETURN_TYPE_FUTURE,
+        '''
+import 'dart:async';
+var v;Future<int> main() async => 0;
+''');
+  }
+
+  test_illegalAsyncReturnType_asyncLibrary_import() async {
     errorFilter = (AnalysisError error) {
       return error.errorCode == StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE;
     };
@@ -2579,7 +2691,7 @@
 int main() async {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REPLACE_RETURN_TYPE_FUTURE,
         '''
 library main;
@@ -2589,7 +2701,7 @@
 ''');
   }
 
-  void test_illegalAsyncReturnType_asyncLibrary_usePrefix() {
+  test_illegalAsyncReturnType_asyncLibrary_usePrefix() async {
     errorFilter = (AnalysisError error) {
       return error.errorCode == StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE;
     };
@@ -2598,7 +2710,7 @@
 int main() async {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REPLACE_RETURN_TYPE_FUTURE,
         '''
 import 'dart:async' as al;
@@ -2607,7 +2719,7 @@
 ''');
   }
 
-  void test_illegalAsyncReturnType_complexTypeName() {
+  test_illegalAsyncReturnType_complexTypeName() async {
     errorFilter = (AnalysisError error) {
       return error.errorCode == StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE;
     };
@@ -2616,7 +2728,7 @@
 List<int> main() async {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REPLACE_RETURN_TYPE_FUTURE,
         '''
 import 'dart:async';
@@ -2625,7 +2737,7 @@
 ''');
   }
 
-  void test_illegalAsyncReturnType_void() {
+  test_illegalAsyncReturnType_void() async {
     errorFilter = (AnalysisError error) {
       return error.errorCode == StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE;
     };
@@ -2634,7 +2746,7 @@
 void main() async {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REPLACE_RETURN_TYPE_FUTURE,
         '''
 import 'dart:async';
@@ -2643,7 +2755,7 @@
 ''');
   }
 
-  void test_importLibraryPackage_withClass() {
+  test_importLibraryPackage_withClass() async {
     _configureMyPkg('''
 library my_lib;
 class Test {}
@@ -2655,7 +2767,7 @@
 }
 ''');
     performAllAnalysisTasks();
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_PROJECT,
         '''
 import 'package:my_pkg/my_lib.dart';
@@ -2666,7 +2778,7 @@
 ''');
   }
 
-  void test_importLibraryProject_withClass_annotation() {
+  test_importLibraryProject_withClass_annotation() async {
     addSource(
         '/lib.dart',
         '''
@@ -2681,7 +2793,7 @@
 }
 ''');
     performAllAnalysisTasks();
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_PROJECT,
         '''
 import 'lib.dart';
@@ -2692,7 +2804,7 @@
 ''');
   }
 
-  void test_importLibraryProject_withClass_hasOtherLibraryWithPrefix() {
+  test_importLibraryProject_withClass_hasOtherLibraryWithPrefix() async {
     testFile = '/project/bin/test.dart';
     addSource(
         '/project/bin/a.dart',
@@ -2715,7 +2827,7 @@
 }
 ''');
     performAllAnalysisTasks();
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_PROJECT,
         '''
 import 'b.dart' show Two;
@@ -2727,7 +2839,7 @@
 ''');
   }
 
-  void test_importLibraryProject_withClass_inParentFolder() {
+  test_importLibraryProject_withClass_inParentFolder() async {
     testFile = '/project/bin/test.dart';
     addSource(
         '/project/lib.dart',
@@ -2741,7 +2853,7 @@
 }
 ''');
     performAllAnalysisTasks();
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_PROJECT,
         '''
 import '../lib.dart';
@@ -2752,7 +2864,7 @@
 ''');
   }
 
-  void test_importLibraryProject_withClass_inRelativeFolder() {
+  test_importLibraryProject_withClass_inRelativeFolder() async {
     testFile = '/project/bin/test.dart';
     addSource(
         '/project/lib/sub/folder/lib.dart',
@@ -2766,7 +2878,7 @@
 }
 ''');
     performAllAnalysisTasks();
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_PROJECT,
         '''
 import '../lib/sub/folder/lib.dart';
@@ -2777,7 +2889,7 @@
 ''');
   }
 
-  void test_importLibraryProject_withClass_inSameFolder() {
+  test_importLibraryProject_withClass_inSameFolder() async {
     testFile = '/project/bin/test.dart';
     addSource(
         '/project/bin/lib.dart',
@@ -2791,7 +2903,7 @@
 }
 ''');
     performAllAnalysisTasks();
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_PROJECT,
         '''
 import 'lib.dart';
@@ -2802,7 +2914,7 @@
 ''');
   }
 
-  void test_importLibraryProject_withFunction() {
+  test_importLibraryProject_withFunction() async {
     addSource(
         '/lib.dart',
         '''
@@ -2815,7 +2927,7 @@
 }
 ''');
     performAllAnalysisTasks();
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_PROJECT,
         '''
 import 'lib.dart';
@@ -2826,7 +2938,7 @@
 ''');
   }
 
-  void test_importLibraryProject_withFunction_unresolvedMethod() {
+  test_importLibraryProject_withFunction_unresolvedMethod() async {
     addSource(
         '/lib.dart',
         '''
@@ -2841,7 +2953,7 @@
 }
 ''');
     performAllAnalysisTasks();
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_PROJECT,
         '''
 import 'lib.dart';
@@ -2854,7 +2966,7 @@
 ''');
   }
 
-  void test_importLibraryProject_withFunctionTypeAlias() {
+  test_importLibraryProject_withFunctionTypeAlias() async {
     testFile = '/project/bin/test.dart';
     addSource(
         '/project/bin/lib.dart',
@@ -2868,7 +2980,7 @@
 }
 ''');
     performAllAnalysisTasks();
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_PROJECT,
         '''
 import 'lib.dart';
@@ -2879,7 +2991,7 @@
 ''');
   }
 
-  void test_importLibraryProject_withTopLevelVariable() {
+  test_importLibraryProject_withTopLevelVariable() async {
     addSource(
         '/lib.dart',
         '''
@@ -2892,7 +3004,7 @@
 }
 ''');
     performAllAnalysisTasks();
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_PROJECT,
         '''
 import 'lib.dart';
@@ -2903,13 +3015,13 @@
 ''');
   }
 
-  void test_importLibrarySdk_withClass_AsExpression() {
+  test_importLibrarySdk_withClass_AsExpression() async {
     resolveTestUnit('''
 main(p) {
   p as Future;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_SDK,
         '''
 import 'dart:async';
@@ -2920,13 +3032,13 @@
 ''');
   }
 
-  void test_importLibrarySdk_withClass_invocationTarget() {
+  test_importLibrarySdk_withClass_invocationTarget() async {
     resolveTestUnit('''
 main() {
   Future.wait(null);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_SDK,
         '''
 import 'dart:async';
@@ -2937,13 +3049,13 @@
 ''');
   }
 
-  void test_importLibrarySdk_withClass_IsExpression() {
+  test_importLibrarySdk_withClass_IsExpression() async {
     resolveTestUnit('''
 main(p) {
   p is Future;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_SDK,
         '''
 import 'dart:async';
@@ -2954,14 +3066,14 @@
 ''');
   }
 
-  void test_importLibrarySdk_withClass_itemOfList() {
+  test_importLibrarySdk_withClass_itemOfList() async {
     resolveTestUnit('''
 main() {
   var a = [Future];
 }
 ''');
     performAllAnalysisTasks();
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_SDK,
         '''
 import 'dart:async';
@@ -2972,7 +3084,7 @@
 ''');
   }
 
-  void test_importLibrarySdk_withClass_itemOfList_inAnnotation() {
+  test_importLibrarySdk_withClass_itemOfList_inAnnotation() async {
     errorFilter = (AnalysisError error) {
       return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER;
     };
@@ -2983,7 +3095,7 @@
 @MyAnnotation(int, const [Future])
 main() {}
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_SDK,
         '''
 import 'dart:async';
@@ -2996,13 +3108,13 @@
 ''');
   }
 
-  void test_importLibrarySdk_withClass_typeAnnotation() {
+  test_importLibrarySdk_withClass_typeAnnotation() async {
     resolveTestUnit('''
 main() {
   Future f = null;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_SDK,
         '''
 import 'dart:async';
@@ -3013,13 +3125,13 @@
 ''');
   }
 
-  void test_importLibrarySdk_withClass_typeAnnotation_PrefixedIdentifier() {
+  test_importLibrarySdk_withClass_typeAnnotation_PrefixedIdentifier() async {
     resolveTestUnit('''
 main() {
   Future.wait;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_SDK,
         '''
 import 'dart:async';
@@ -3030,13 +3142,13 @@
 ''');
   }
 
-  void test_importLibrarySdk_withClass_typeArgument() {
+  test_importLibrarySdk_withClass_typeArgument() async {
     resolveTestUnit('''
 main() {
   List<Future> futures = [];
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_SDK,
         '''
 import 'dart:async';
@@ -3047,14 +3159,14 @@
 ''');
   }
 
-  void test_importLibrarySdk_withTopLevelVariable() {
+  test_importLibrarySdk_withTopLevelVariable() async {
     resolveTestUnit('''
 main() {
   print(PI);
 }
 ''');
     performAllAnalysisTasks();
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_SDK,
         '''
 import 'dart:math';
@@ -3065,14 +3177,14 @@
 ''');
   }
 
-  void test_importLibrarySdk_withTopLevelVariable_annotation() {
+  test_importLibrarySdk_withTopLevelVariable_annotation() async {
     resolveTestUnit('''
 @PI
 main() {
 }
 ''');
     performAllAnalysisTasks();
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_SDK,
         '''
 import 'dart:math';
@@ -3083,7 +3195,7 @@
 ''');
   }
 
-  void test_importLibraryShow() {
+  test_importLibraryShow() async {
     resolveTestUnit('''
 import 'dart:async' show Stream;
 main() {
@@ -3091,7 +3203,7 @@
   Future f = null;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_SHOW,
         '''
 import 'dart:async' show Future, Stream;
@@ -3102,13 +3214,13 @@
 ''');
   }
 
-  void test_isNotNull() {
+  test_isNotNull() async {
     resolveTestUnit('''
 main(p) {
   p is! Null;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.USE_NOT_EQ_NULL,
         '''
 main(p) {
@@ -3117,13 +3229,13 @@
 ''');
   }
 
-  void test_isNull() {
+  test_isNull() async {
     resolveTestUnit('''
 main(p) {
   p is Null;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.USE_EQ_EQ_NULL,
         '''
 main(p) {
@@ -3132,13 +3244,13 @@
 ''');
   }
 
-  void test_makeEnclosingClassAbstract_declaresAbstractMethod() {
+  test_makeEnclosingClassAbstract_declaresAbstractMethod() async {
     resolveTestUnit('''
 class A {
   m();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.MAKE_CLASS_ABSTRACT,
         '''
 abstract class A {
@@ -3147,7 +3259,7 @@
 ''');
   }
 
-  void test_makeEnclosingClassAbstract_inheritsAbstractMethod() {
+  test_makeEnclosingClassAbstract_inheritsAbstractMethod() async {
     resolveTestUnit('''
 abstract class A {
   m();
@@ -3155,7 +3267,7 @@
 class B extends A {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.MAKE_CLASS_ABSTRACT,
         '''
 abstract class A {
@@ -3166,18 +3278,18 @@
 ''');
   }
 
-  void test_noException_1() {
+  test_noException_1() async {
     resolveTestUnit('''
 main(p) {
   p i s Null;
 }''');
     List<AnalysisError> errors = context.computeErrors(testSource);
     for (var error in errors) {
-      _computeFixes(error);
+      await _computeFixes(error);
     }
   }
 
-  void test_nonBoolCondition_addNotNull() {
+  test_nonBoolCondition_addNotNull() async {
     resolveTestUnit('''
 main(String p) {
   if (p) {
@@ -3185,7 +3297,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.ADD_NE_NULL,
         '''
 main(String p) {
@@ -3196,7 +3308,7 @@
 ''');
   }
 
-  void test_removeDeadCode_condition() {
+  test_removeDeadCode_condition() async {
     resolveTestUnit('''
 main(int p) {
   if (true || p > 5) {
@@ -3204,7 +3316,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REMOVE_DEAD_CODE,
         '''
 main(int p) {
@@ -3215,7 +3327,7 @@
 ''');
   }
 
-  void test_removeDeadCode_statements_one() {
+  test_removeDeadCode_statements_one() async {
     resolveTestUnit('''
 int main() {
   print(0);
@@ -3223,7 +3335,7 @@
   print(1);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REMOVE_DEAD_CODE,
         '''
 int main() {
@@ -3233,7 +3345,7 @@
 ''');
   }
 
-  void test_removeDeadCode_statements_two() {
+  test_removeDeadCode_statements_two() async {
     resolveTestUnit('''
 int main() {
   print(0);
@@ -3242,7 +3354,7 @@
   print(2);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REMOVE_DEAD_CODE,
         '''
 int main() {
@@ -3252,13 +3364,13 @@
 ''');
   }
 
-  void test_removeParentheses_inGetterDeclaration() {
+  test_removeParentheses_inGetterDeclaration() async {
     resolveTestUnit('''
 class A {
   int get foo() => 0;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REMOVE_PARAMETERS_IN_GETTER_DECLARATION,
         '''
 class A {
@@ -3267,7 +3379,7 @@
 ''');
   }
 
-  void test_removeParentheses_inGetterInvocation() {
+  test_removeParentheses_inGetterInvocation() async {
     resolveTestUnit('''
 class A {
   int get foo => 0;
@@ -3276,7 +3388,7 @@
   a.foo();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REMOVE_PARENTHESIS_IN_GETTER_INVOCATION,
         '''
 class A {
@@ -3288,7 +3400,7 @@
 ''');
   }
 
-  void test_removeUnnecessaryCast_assignment() {
+  test_removeUnnecessaryCast_assignment() async {
     resolveTestUnit('''
 main(Object p) {
   if (p is String) {
@@ -3296,7 +3408,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REMOVE_UNNECESSARY_CAST,
         '''
 main(Object p) {
@@ -3307,7 +3419,7 @@
 ''');
   }
 
-  void test_removeUnusedCatchClause() {
+  test_removeUnusedCatchClause() async {
     errorFilter = (AnalysisError error) => true;
     resolveTestUnit('''
 main() {
@@ -3317,7 +3429,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REMOVE_UNUSED_CATCH_CLAUSE,
         '''
 main() {
@@ -3329,7 +3441,7 @@
 ''');
   }
 
-  void test_removeUnusedCatchStack() {
+  test_removeUnusedCatchStack() async {
     errorFilter = (AnalysisError error) => true;
     resolveTestUnit('''
 main() {
@@ -3339,7 +3451,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REMOVE_UNUSED_CATCH_STACK,
         '''
 main() {
@@ -3351,13 +3463,13 @@
 ''');
   }
 
-  void test_removeUnusedImport() {
+  test_removeUnusedImport() async {
     resolveTestUnit('''
 import 'dart:math';
 main() {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REMOVE_UNUSED_IMPORT,
         '''
 main() {
@@ -3365,7 +3477,7 @@
 ''');
   }
 
-  void test_removeUnusedImport_anotherImportOnLine() {
+  test_removeUnusedImport_anotherImportOnLine() async {
     resolveTestUnit('''
 import 'dart:math'; import 'dart:async';
 
@@ -3373,7 +3485,7 @@
   Future f;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REMOVE_UNUSED_IMPORT,
         '''
 import 'dart:async';
@@ -3384,14 +3496,14 @@
 ''');
   }
 
-  void test_removeUnusedImport_severalLines() {
+  test_removeUnusedImport_severalLines() async {
     resolveTestUnit('''
 import
   'dart:math';
 main() {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REMOVE_UNUSED_IMPORT,
         '''
 main() {
@@ -3399,34 +3511,34 @@
 ''');
   }
 
-  void test_replaceImportUri_inProject() {
+  test_replaceImportUri_inProject() async {
     testFile = '/project/bin/test.dart';
     addSource('/project/foo/bar/lib.dart', '');
     resolveTestUnit('''
 import 'no/matter/lib.dart';
 ''');
     performAllAnalysisTasks();
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REPLACE_IMPORT_URI,
         '''
 import '../foo/bar/lib.dart';
 ''');
   }
 
-  void test_replaceImportUri_package() {
+  test_replaceImportUri_package() async {
     _configureMyPkg('');
     resolveTestUnit('''
 import 'no/matter/my_lib.dart';
 ''');
     performAllAnalysisTasks();
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REPLACE_IMPORT_URI,
         '''
 import 'package:my_pkg/my_lib.dart';
 ''');
   }
 
-  void test_replaceVarWithDynamic() {
+  test_replaceVarWithDynamic() async {
     errorFilter = (AnalysisError error) {
       return error.errorCode == ParserErrorCode.VAR_AS_TYPE_NAME;
     };
@@ -3435,7 +3547,7 @@
   Map<String, var> m;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.REPLACE_VAR_WITH_DYNAMIC,
         '''
 class A {
@@ -3444,14 +3556,14 @@
 ''');
   }
 
-  void test_replaceWithConstInstanceCreation() {
+  test_replaceWithConstInstanceCreation() async {
     resolveTestUnit('''
 class A {
   const A();
 }
 const a = new A();
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.USE_CONST,
         '''
 class A {
@@ -3461,13 +3573,13 @@
 ''');
   }
 
-  void test_undefinedClass_useSimilar_fromImport() {
+  test_undefinedClass_useSimilar_fromImport() async {
     resolveTestUnit('''
 main() {
   Stirng s = 'abc';
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO,
         '''
 main() {
@@ -3476,14 +3588,14 @@
 ''');
   }
 
-  void test_undefinedClass_useSimilar_fromThisLibrary() {
+  test_undefinedClass_useSimilar_fromThisLibrary() async {
     resolveTestUnit('''
 class MyClass {}
 main() {
   MyCalss v = null;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO,
         '''
 class MyClass {}
@@ -3493,14 +3605,14 @@
 ''');
   }
 
-  void test_undefinedFunction_create_dynamicArgument() {
+  test_undefinedFunction_create_dynamicArgument() async {
     resolveTestUnit('''
 main() {
   dynamic v;
   test(v);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 main() {
@@ -3513,13 +3625,13 @@
 ''');
   }
 
-  void test_undefinedFunction_create_dynamicReturnType() {
+  test_undefinedFunction_create_dynamicReturnType() async {
     resolveTestUnit('''
 main() {
   dynamic v = test();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 main() {
@@ -3531,13 +3643,13 @@
 ''');
   }
 
-  void test_undefinedFunction_create_fromFunction() {
+  test_undefinedFunction_create_fromFunction() async {
     resolveTestUnit('''
 main() {
   int v = myUndefinedFunction(1, 2.0, '3');
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 main() {
@@ -3549,7 +3661,7 @@
 ''');
   }
 
-  void test_undefinedFunction_create_fromMethod() {
+  test_undefinedFunction_create_fromMethod() async {
     resolveTestUnit('''
 class A {
   main() {
@@ -3557,7 +3669,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 class A {
@@ -3571,7 +3683,7 @@
 ''');
   }
 
-  void test_undefinedFunction_create_generic_BAD() {
+  test_undefinedFunction_create_generic_BAD() async {
     resolveTestUnit('''
 class A<T> {
   Map<int, T> items;
@@ -3580,7 +3692,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 class A<T> {
@@ -3595,7 +3707,7 @@
 ''');
   }
 
-  void test_undefinedFunction_create_generic_OK() {
+  test_undefinedFunction_create_generic_OK() async {
     resolveTestUnit('''
 class A {
   List<int> items;
@@ -3604,7 +3716,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 class A {
@@ -3619,7 +3731,7 @@
 ''');
   }
 
-  void test_undefinedFunction_create_importType() {
+  test_undefinedFunction_create_importType() async {
     addSource(
         '/lib.dart',
         r'''
@@ -3633,7 +3745,7 @@
   test(getFuture());
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 import 'lib.dart';
@@ -3647,13 +3759,13 @@
 ''');
   }
 
-  void test_undefinedFunction_create_nullArgument() {
+  test_undefinedFunction_create_nullArgument() async {
     resolveTestUnit('''
 main() {
   test(null);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 main() {
@@ -3665,29 +3777,31 @@
 ''');
   }
 
-  void test_undefinedFunction_create_returnType_bool_expressions() {
-    assert_undefinedFunction_create_returnType_bool("!test();");
-    assert_undefinedFunction_create_returnType_bool("b && test();");
-    assert_undefinedFunction_create_returnType_bool("test() && b;");
-    assert_undefinedFunction_create_returnType_bool("b || test();");
-    assert_undefinedFunction_create_returnType_bool("test() || b;");
+  test_undefinedFunction_create_returnType_bool_expressions() async {
+    await assert_undefinedFunction_create_returnType_bool("!test();");
+    await assert_undefinedFunction_create_returnType_bool("b && test();");
+    await assert_undefinedFunction_create_returnType_bool("test() && b;");
+    await assert_undefinedFunction_create_returnType_bool("b || test();");
+    await assert_undefinedFunction_create_returnType_bool("test() || b;");
   }
 
-  void test_undefinedFunction_create_returnType_bool_statements() {
-    assert_undefinedFunction_create_returnType_bool("assert ( test() );");
-    assert_undefinedFunction_create_returnType_bool("if ( test() ) {}");
-    assert_undefinedFunction_create_returnType_bool("while ( test() ) {}");
-    assert_undefinedFunction_create_returnType_bool("do {} while ( test() );");
+  test_undefinedFunction_create_returnType_bool_statements() async {
+    await assert_undefinedFunction_create_returnType_bool("assert ( test() );");
+    await assert_undefinedFunction_create_returnType_bool("if ( test() ) {}");
+    await assert_undefinedFunction_create_returnType_bool(
+        "while ( test() ) {}");
+    await assert_undefinedFunction_create_returnType_bool(
+        "do {} while ( test() );");
   }
 
-  void test_undefinedFunction_create_returnType_fromAssignment_eq() {
+  test_undefinedFunction_create_returnType_fromAssignment_eq() async {
     resolveTestUnit('''
 main() {
   int v;
   v = myUndefinedFunction();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 main() {
@@ -3700,14 +3814,14 @@
 ''');
   }
 
-  void test_undefinedFunction_create_returnType_fromAssignment_plusEq() {
+  test_undefinedFunction_create_returnType_fromAssignment_plusEq() async {
     resolveTestUnit('''
 main() {
   int v;
   v += myUndefinedFunction();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 main() {
@@ -3720,13 +3834,13 @@
 ''');
   }
 
-  void test_undefinedFunction_create_returnType_fromBinary_right() {
+  test_undefinedFunction_create_returnType_fromBinary_right() async {
     resolveTestUnit('''
 main() {
   0 + myUndefinedFunction();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 main() {
@@ -3738,13 +3852,13 @@
 ''');
   }
 
-  void test_undefinedFunction_create_returnType_fromInitializer() {
+  test_undefinedFunction_create_returnType_fromInitializer() async {
     resolveTestUnit('''
 main() {
   int v = myUndefinedFunction();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 main() {
@@ -3756,14 +3870,14 @@
 ''');
   }
 
-  void test_undefinedFunction_create_returnType_fromInvocationArgument() {
+  test_undefinedFunction_create_returnType_fromInvocationArgument() async {
     resolveTestUnit('''
 foo(int p) {}
 main() {
   foo( myUndefinedFunction() );
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 foo(int p) {}
@@ -3776,13 +3890,13 @@
 ''');
   }
 
-  void test_undefinedFunction_create_returnType_fromReturn() {
+  test_undefinedFunction_create_returnType_fromReturn() async {
     resolveTestUnit('''
 int main() {
   return myUndefinedFunction();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 int main() {
@@ -3794,13 +3908,13 @@
 ''');
   }
 
-  void test_undefinedFunction_create_returnType_void() {
+  test_undefinedFunction_create_returnType_void() async {
     resolveTestUnit('''
 main() {
   myUndefinedFunction();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_FUNCTION,
         '''
 main() {
@@ -3812,13 +3926,13 @@
 ''');
   }
 
-  void test_undefinedFunction_useSimilar_fromImport() {
+  test_undefinedFunction_useSimilar_fromImport() async {
     resolveTestUnit('''
 main() {
   pritn(0);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO,
         '''
 main() {
@@ -3827,14 +3941,14 @@
 ''');
   }
 
-  void test_undefinedFunction_useSimilar_thisLibrary() {
+  test_undefinedFunction_useSimilar_thisLibrary() async {
     resolveTestUnit('''
 myFunction() {}
 main() {
   myFuntcion();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO,
         '''
 myFunction() {}
@@ -3844,7 +3958,7 @@
 ''');
   }
 
-  void test_undefinedGetter_useSimilar_hint() {
+  test_undefinedGetter_useSimilar_hint() async {
     resolveTestUnit('''
 class A {
   int myField;
@@ -3854,7 +3968,7 @@
   print(x.myFild);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO,
         '''
 class A {
@@ -3867,7 +3981,7 @@
 ''');
   }
 
-  void test_undefinedGetter_useSimilar_qualified() {
+  test_undefinedGetter_useSimilar_qualified() async {
     resolveTestUnit('''
 class A {
   int myField;
@@ -3876,7 +3990,7 @@
   print(a.myFild);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO,
         '''
 class A {
@@ -3888,7 +4002,7 @@
 ''');
   }
 
-  void test_undefinedGetter_useSimilar_qualified_static() {
+  test_undefinedGetter_useSimilar_qualified_static() async {
     resolveTestUnit('''
 class A {
   static int MY_NAME = 1;
@@ -3897,7 +4011,7 @@
   A.MY_NAM;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO,
         '''
 class A {
@@ -3909,7 +4023,7 @@
 ''');
   }
 
-  void test_undefinedGetter_useSimilar_unqualified() {
+  test_undefinedGetter_useSimilar_unqualified() async {
     resolveTestUnit('''
 class A {
   int myField;
@@ -3918,7 +4032,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO,
         '''
 class A {
@@ -3930,16 +4044,16 @@
 ''');
   }
 
-  void test_undefinedMethod_create_BAD_inSDK() {
+  test_undefinedMethod_create_BAD_inSDK() async {
     resolveTestUnit('''
 main() {
   List.foo();
 }
 ''');
-    assertNoFix(DartFixKind.CREATE_METHOD);
+    await assertNoFix(DartFixKind.CREATE_METHOD);
   }
 
-  void test_undefinedMethod_create_generic_BAD_argumentType() {
+  test_undefinedMethod_create_generic_BAD_argumentType() async {
     resolveTestUnit('''
 class A<T> {
   B b;
@@ -3952,7 +4066,7 @@
 class B {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_METHOD,
         '''
 class A<T> {
@@ -3970,7 +4084,7 @@
 ''');
   }
 
-  void test_undefinedMethod_create_generic_BAD_returnType() {
+  test_undefinedMethod_create_generic_BAD_returnType() async {
     resolveTestUnit('''
 class A<T> {
   main() {
@@ -3981,7 +4095,7 @@
 class B {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_METHOD,
         '''
 class A<T> {
@@ -3997,7 +4111,7 @@
 ''');
   }
 
-  void test_undefinedMethod_create_generic_OK_literal() {
+  test_undefinedMethod_create_generic_OK_literal() async {
     resolveTestUnit('''
 class A {
   B b;
@@ -4010,7 +4124,7 @@
 class B {
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_METHOD,
         '''
 class A {
@@ -4028,7 +4142,7 @@
 ''');
   }
 
-  void test_undefinedMethod_create_generic_OK_local() {
+  test_undefinedMethod_create_generic_OK_local() async {
     resolveTestUnit('''
 class A<T> {
   List<T> items;
@@ -4037,7 +4151,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_METHOD,
         '''
 class A<T> {
@@ -4052,7 +4166,7 @@
 ''');
   }
 
-  void test_undefinedMethod_createQualified_fromClass() {
+  test_undefinedMethod_createQualified_fromClass() async {
     resolveTestUnit('''
 class A {
 }
@@ -4060,7 +4174,7 @@
   A.myUndefinedMethod();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_METHOD,
         '''
 class A {
@@ -4073,7 +4187,7 @@
 ''');
   }
 
-  void test_undefinedMethod_createQualified_fromClass_hasOtherMember() {
+  test_undefinedMethod_createQualified_fromClass_hasOtherMember() async {
     resolveTestUnit('''
 class A {
   foo() {}
@@ -4082,7 +4196,7 @@
   A.myUndefinedMethod();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_METHOD,
         '''
 class A {
@@ -4097,7 +4211,7 @@
 ''');
   }
 
-  void test_undefinedMethod_createQualified_fromInstance() {
+  test_undefinedMethod_createQualified_fromInstance() async {
     resolveTestUnit('''
 class A {
 }
@@ -4105,7 +4219,7 @@
   a.myUndefinedMethod();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_METHOD,
         '''
 class A {
@@ -4118,26 +4232,26 @@
 ''');
   }
 
-  void test_undefinedMethod_createQualified_targetIsFunctionType() {
+  test_undefinedMethod_createQualified_targetIsFunctionType() async {
     resolveTestUnit('''
 typedef A();
 main() {
   A.myUndefinedMethod();
 }
 ''');
-    assertNoFix(DartFixKind.CREATE_METHOD);
+    await assertNoFix(DartFixKind.CREATE_METHOD);
   }
 
-  void test_undefinedMethod_createQualified_targetIsUnresolved() {
+  test_undefinedMethod_createQualified_targetIsUnresolved() async {
     resolveTestUnit('''
 main() {
   NoSuchClass.myUndefinedMethod();
 }
 ''');
-    assertNoFix(DartFixKind.CREATE_METHOD);
+    await assertNoFix(DartFixKind.CREATE_METHOD);
   }
 
-  void test_undefinedMethod_createUnqualified_parameters() {
+  test_undefinedMethod_createUnqualified_parameters() async {
     resolveTestUnit('''
 class A {
   main() {
@@ -4145,7 +4259,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_METHOD,
         '''
 class A {
@@ -4183,7 +4297,51 @@
     _assertLinkedGroup(change.linkedEditGroups[index++], ['s)']);
   }
 
-  void test_undefinedMethod_createUnqualified_returnType() {
+  test_undefinedMethod_createUnqualified_parameters_named() async {
+    resolveTestUnit('''
+class A {
+  main() {
+    myUndefinedMethod(0, bbb: 1.0, ccc: '2');
+  }
+}
+''');
+    await assertHasFix(
+        DartFixKind.CREATE_METHOD,
+        '''
+class A {
+  main() {
+    myUndefinedMethod(0, bbb: 1.0, ccc: '2');
+  }
+
+  void myUndefinedMethod(int i, {double bbb, String ccc}) {
+  }
+}
+''');
+    // linked positions
+    int index = 0;
+    _assertLinkedGroup(
+        change.linkedEditGroups[index++], ['void myUndefinedMethod(']);
+    _assertLinkedGroup(change.linkedEditGroups[index++],
+        ['myUndefinedMethod(0', 'myUndefinedMethod(int']);
+    _assertLinkedGroup(
+        change.linkedEditGroups[index++],
+        ['int i'],
+        expectedSuggestions(LinkedEditSuggestionKind.TYPE,
+            ['int', 'num', 'Object', 'Comparable']));
+    _assertLinkedGroup(change.linkedEditGroups[index++], ['i,']);
+    _assertLinkedGroup(
+        change.linkedEditGroups[index++],
+        ['double bbb'],
+        expectedSuggestions(LinkedEditSuggestionKind.TYPE,
+            ['double', 'num', 'Object', 'Comparable']));
+    _assertLinkedGroup(
+        change.linkedEditGroups[index++],
+        ['String ccc'],
+        expectedSuggestions(
+            LinkedEditSuggestionKind.TYPE, ['String', 'Object', 'Comparable']));
+  }
+
+  test_undefinedMethod_createUnqualified_returnType() async {
     resolveTestUnit('''
 class A {
   main() {
@@ -4191,7 +4349,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_METHOD,
         '''
 class A {
@@ -4209,13 +4367,13 @@
         ['myUndefinedMethod();', 'myUndefinedMethod() {']);
   }
 
-  void test_undefinedMethod_createUnqualified_staticFromField() {
+  test_undefinedMethod_createUnqualified_staticFromField() async {
     resolveTestUnit('''
 class A {
   static var f = myUndefinedMethod();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_METHOD,
         '''
 class A {
@@ -4227,7 +4385,7 @@
 ''');
   }
 
-  void test_undefinedMethod_createUnqualified_staticFromMethod() {
+  test_undefinedMethod_createUnqualified_staticFromMethod() async {
     resolveTestUnit('''
 class A {
   static main() {
@@ -4235,7 +4393,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_METHOD,
         '''
 class A {
@@ -4249,7 +4407,7 @@
 ''');
   }
 
-  void test_undefinedMethod_hint_createQualified_fromInstance() {
+  test_undefinedMethod_hint_createQualified_fromInstance() async {
     resolveTestUnit('''
 class A {
 }
@@ -4258,7 +4416,7 @@
   a.myUndefinedMethod();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CREATE_METHOD,
         '''
 class A {
@@ -4272,7 +4430,7 @@
 ''');
   }
 
-  void test_undefinedMethod_parameterType_differentPrefixInTargetUnit() {
+  test_undefinedMethod_parameterType_differentPrefixInTargetUnit() async {
     String code2 = r'''
 library test2;
 import 'test3.dart' as bbb;
@@ -4295,7 +4453,7 @@
 }
 ''');
     AnalysisError error = _findErrorToFix();
-    fix = _assertHasFix(DartFixKind.CREATE_METHOD, error);
+    fix = await _assertHasFix(DartFixKind.CREATE_METHOD, error);
     change = fix.change;
     // apply to "test2.dart"
     List<SourceFileEdit> fileEdits = change.edits;
@@ -4315,7 +4473,7 @@
 ''');
   }
 
-  void test_undefinedMethod_parameterType_inTargetUnit() {
+  test_undefinedMethod_parameterType_inTargetUnit() async {
     String code2 = r'''
 library test2;
 class D {
@@ -4331,7 +4489,7 @@
 }
 ''');
     AnalysisError error = _findErrorToFix();
-    fix = _assertHasFix(DartFixKind.CREATE_METHOD, error);
+    fix = await _assertHasFix(DartFixKind.CREATE_METHOD, error);
     change = fix.change;
     // apply to "test2.dart"
     List<SourceFileEdit> fileEdits = change.edits;
@@ -4350,16 +4508,16 @@
 ''');
   }
 
-  void test_undefinedMethod_useSimilar_ignoreOperators() {
+  test_undefinedMethod_useSimilar_ignoreOperators() async {
     resolveTestUnit('''
 main(Object object) {
   object.then();
 }
 ''');
-    assertNoFix(DartFixKind.CHANGE_TO);
+    await assertNoFix(DartFixKind.CHANGE_TO);
   }
 
-  void test_undefinedMethod_useSimilar_qualified() {
+  test_undefinedMethod_useSimilar_qualified() async {
     resolveTestUnit('''
 class A {
   myMethod() {}
@@ -4369,7 +4527,7 @@
   a.myMehtod();
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO,
         '''
 class A {
@@ -4382,7 +4540,7 @@
 ''');
   }
 
-  void test_undefinedMethod_useSimilar_unqualified_superClass() {
+  test_undefinedMethod_useSimilar_unqualified_superClass() async {
     resolveTestUnit('''
 class A {
   myMethod() {}
@@ -4393,7 +4551,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO,
         '''
 class A {
@@ -4407,7 +4565,7 @@
 ''');
   }
 
-  void test_undefinedMethod_useSimilar_unqualified_thisClass() {
+  test_undefinedMethod_useSimilar_unqualified_thisClass() async {
     resolveTestUnit('''
 class A {
   myMethod() {}
@@ -4416,7 +4574,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO,
         '''
 class A {
@@ -4428,7 +4586,7 @@
 ''');
   }
 
-  void test_undefinedSetter_useSimilar_hint() {
+  test_undefinedSetter_useSimilar_hint() async {
     resolveTestUnit('''
 class A {
   int myField;
@@ -4438,7 +4596,7 @@
   x.myFild = 42;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO,
         '''
 class A {
@@ -4451,7 +4609,7 @@
 ''');
   }
 
-  void test_undefinedSetter_useSimilar_qualified() {
+  test_undefinedSetter_useSimilar_qualified() async {
     resolveTestUnit('''
 class A {
   int myField;
@@ -4460,7 +4618,7 @@
   a.myFild = 42;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO,
         '''
 class A {
@@ -4472,7 +4630,7 @@
 ''');
   }
 
-  void test_undefinedSetter_useSimilar_unqualified() {
+  test_undefinedSetter_useSimilar_unqualified() async {
     resolveTestUnit('''
 class A {
   int myField;
@@ -4481,7 +4639,7 @@
   }
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.CHANGE_TO,
         '''
 class A {
@@ -4493,7 +4651,7 @@
 ''');
   }
 
-  void test_useEffectiveIntegerDivision() {
+  test_useEffectiveIntegerDivision() async {
     resolveTestUnit('''
 main() {
   var a = 5;
@@ -4501,7 +4659,7 @@
   print((a / b).toInt());
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.USE_EFFECTIVE_INTEGER_DIVISION,
         '''
 main() {
@@ -4512,7 +4670,7 @@
 ''');
   }
 
-  void test_useImportPrefix_withClass() {
+  test_useImportPrefix_withClass() async {
     resolveTestUnit('''
 import 'dart:async' as pref;
 main() {
@@ -4520,7 +4678,7 @@
   Future f = null;
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_PREFIX,
         '''
 import 'dart:async' as pref;
@@ -4531,7 +4689,7 @@
 ''');
   }
 
-  void test_useImportPrefix_withTopLevelVariable() {
+  test_useImportPrefix_withTopLevelVariable() async {
     resolveTestUnit('''
 import 'dart:math' as pref;
 main() {
@@ -4539,7 +4697,7 @@
   print(PI);
 }
 ''');
-    assertHasFix(
+    await assertHasFix(
         DartFixKind.IMPORT_LIBRARY_PREFIX,
         '''
 import 'dart:math' as pref;
@@ -4553,8 +4711,8 @@
   /**
    * Computes fixes and verifies that there is a fix of the given kind.
    */
-  Fix _assertHasFix(FixKind kind, AnalysisError error) {
-    List<Fix> fixes = _computeFixes(error);
+  Future<Fix> _assertHasFix(FixKind kind, AnalysisError error) async {
+    List<Fix> fixes = await _computeFixes(error);
     for (Fix fix in fixes) {
       if (fix.kind == kind) {
         return fix;
@@ -4575,8 +4733,10 @@
   /**
    * Computes fixes for the given [error] in [testUnit].
    */
-  List<Fix> _computeFixes(AnalysisError error) {
-    FixProcessor processor = new FixProcessor(provider, testUnit, error);
+  Future<List<Fix>> _computeFixes(AnalysisError error) async {
+    DartFixContext dartContext = new DartFixContextImpl(
+        new FixContextImpl(provider, context, error), testUnit);
+    FixProcessor processor = new FixProcessor(dartContext);
     return processor.compute();
   }
 
diff --git a/pkg/analysis_server/test/services/dependencies/library_dependencies_test.dart b/pkg/analysis_server/test/services/dependencies/library_dependencies_test.dart
index 69ccf4b..2c1b7b9 100644
--- a/pkg/analysis_server/test/services/dependencies/library_dependencies_test.dart
+++ b/pkg/analysis_server/test/services/dependencies/library_dependencies_test.dart
@@ -34,7 +34,7 @@
     // Cycles
     expect(libs, contains('/lib1.dart'));
     expect(libs, contains('/lib2.dart'));
-    // Regular sourcs
+    // Regular sources
     expect(libs, contains('/lib3.dart'));
     expect(libs, contains('/lib4.dart'));
     // Non-source, referenced by source
diff --git a/pkg/analysis_server/test/services/dependencies/reachable_source_collector_test.dart b/pkg/analysis_server/test/services/dependencies/reachable_source_collector_test.dart
new file mode 100644
index 0000000..b040926
--- /dev/null
+++ b/pkg/analysis_server/test/services/dependencies/reachable_source_collector_test.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.services.dependencies.import_collector;
+
+import 'package:analysis_server/src/services/dependencies/reachable_source_collector.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../abstract_context.dart';
+import '../../utils.dart';
+
+main() {
+  initializeTestEnvironment();
+  defineReflectiveTests(ReachableSourceCollectorTest);
+}
+
+@reflectiveTest
+class ReachableSourceCollectorTest extends AbstractContextTest {
+  CompilationUnit addLibrary(String path, String contents) =>
+      resolveLibraryUnit(addSource(path, contents));
+
+  Map<String, List<String>> importsFor(Source source) =>
+      new ReachableSourceCollector(source, context).collectSources();
+
+  test_null_context() {
+    Source lib = addSource('/lib.dart', '');
+    expect(() => new ReachableSourceCollector(lib, null),
+        throwsA(new isInstanceOf<ArgumentError>()));
+  }
+
+  test_null_source() {
+    expect(() => new ReachableSourceCollector(null, context),
+        throwsA(new isInstanceOf<ArgumentError>()));
+  }
+
+  test_sources() {
+    Source lib1 = addSource(
+        '/lib1.dart',
+        '''
+import "lib2.dart";
+import "dart:html";''');
+    Source lib2 = addSource('/lib2.dart', 'import "lib1.dart";');
+
+    Source lib3 = addSource('/lib3.dart', 'import "lib4.dart";');
+    addSource('/lib4.dart', 'import "lib3.dart";');
+
+    Map<String, List<String>> imports = importsFor(lib1);
+
+    // Verify keys.
+    expect(
+        imports.keys,
+        unorderedEquals([
+          'dart:_internal',
+          'dart:async',
+          'dart:core',
+          'dart:html',
+          'dart:math',
+          'file:///lib1.dart',
+          'file:///lib2.dart',
+        ]));
+    // Values.
+    expect(imports['file:///lib1.dart'],
+        unorderedEquals(['dart:core', 'dart:html', 'file:///lib2.dart']));
+
+    // Check transitivity.
+    expect(importsFor(lib2).keys, contains('dart:html'));
+
+    // Cycles should be OK.
+    expect(
+        importsFor(lib3).keys,
+        unorderedEquals([
+          'dart:_internal',
+          'dart:async',
+          'dart:core',
+          'dart:math',
+          'file:///lib3.dart',
+          'file:///lib4.dart'
+        ]));
+  }
+}
diff --git a/pkg/analysis_server/test/services/dependencies/test_all.dart b/pkg/analysis_server/test/services/dependencies/test_all.dart
index 1874a07..b26ac82 100644
--- a/pkg/analysis_server/test/services/dependencies/test_all.dart
+++ b/pkg/analysis_server/test/services/dependencies/test_all.dart
@@ -7,12 +7,14 @@
 import 'package:unittest/unittest.dart';
 
 import '../../utils.dart';
-import 'library_dependencies_test.dart' as library_dependencies_test;
+import 'library_dependencies_test.dart' as library_dependencies;
+import 'reachable_source_collector_test.dart' as reachable_source_collector;
 
 /// Utility for manually running all tests.
 main() {
   initializeTestEnvironment();
   group('dependencies', () {
-    library_dependencies_test.main();
+    library_dependencies.main();
+    reachable_source_collector.main();
   });
 }
diff --git a/pkg/analysis_server/test/services/index/dart_index_contributor_test.dart b/pkg/analysis_server/test/services/index/dart_index_contributor_test.dart
index 1830a28..9ba6cae 100644
--- a/pkg/analysis_server/test/services/index/dart_index_contributor_test.dart
+++ b/pkg/analysis_server/test/services/index/dart_index_contributor_test.dart
@@ -4,7 +4,7 @@
 
 library test.services.src.index.dart_index_contributor;
 
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
 import 'package:analysis_server/src/services/index/index.dart';
 import 'package:analysis_server/src/services/index/index_contributor.dart';
 import 'package:analysis_server/src/services/index/index_store.dart';
@@ -94,27 +94,6 @@
     });
   }
 
-  void test_isReferencedBy_PrefixElement() {
-    _indexTestUnit('''
-import 'dart:async' as ppp;
-main() {
-  ppp.Future a;
-  ppp.Stream b;
-}
-''');
-    // prepare elements
-    PrefixElement element = findNodeElementAtString('ppp;');
-    Element elementA = findElement('a');
-    Element elementB = findElement('b');
-    IndexableElement indexable = new IndexableElement(element);
-    // verify
-    _assertRecordedRelation(indexable, IndexConstants.IS_REFERENCED_BY,
-        _expectedLocation(elementA, 'ppp.Future'));
-    _assertRecordedRelation(indexable, IndexConstants.IS_REFERENCED_BY,
-        _expectedLocation(elementB, 'ppp.Stream'));
-    _assertNoRecordedRelation(indexable, null, _expectedLocation(null, 'ppp;'));
-  }
-
   void test_bad_unresolvedFieldFormalParameter() {
     verifyNoTestUnitErrors = false;
     _indexTestUnit('''
@@ -1423,6 +1402,27 @@
         _expectedLocation(mainElement, 'p: 1'));
   }
 
+  void test_isReferencedBy_PrefixElement() {
+    _indexTestUnit('''
+import 'dart:async' as ppp;
+main() {
+  ppp.Future a;
+  ppp.Stream b;
+}
+''');
+    // prepare elements
+    PrefixElement element = findNodeElementAtString('ppp;');
+    Element elementA = findElement('a');
+    Element elementB = findElement('b');
+    IndexableElement indexable = new IndexableElement(element);
+    // verify
+    _assertRecordedRelation(indexable, IndexConstants.IS_REFERENCED_BY,
+        _expectedLocation(elementA, 'ppp.Future'));
+    _assertRecordedRelation(indexable, IndexConstants.IS_REFERENCED_BY,
+        _expectedLocation(elementB, 'ppp.Stream'));
+    _assertNoRecordedRelation(indexable, null, _expectedLocation(null, 'ppp;'));
+  }
+
   void test_isReferencedBy_TopLevelVariableElement() {
     addSource(
         '/lib.dart',
diff --git a/pkg/analysis_server/test/services/index/store/codec_test.dart b/pkg/analysis_server/test/services/index/store/codec_test.dart
index cfc6b97..15adf15 100644
--- a/pkg/analysis_server/test/services/index/store/codec_test.dart
+++ b/pkg/analysis_server/test/services/index/store/codec_test.dart
@@ -4,7 +4,7 @@
 
 library test.services.src.index.store.codec;
 
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
 import 'package:analysis_server/src/services/index/index.dart';
 import 'package:analysis_server/src/services/index/indexable_element.dart';
 import 'package:analysis_server/src/services/index/store/codec.dart';
diff --git a/pkg/analysis_server/test/services/index/store/split_store_test.dart b/pkg/analysis_server/test/services/index/store/split_store_test.dart
index ab91ca6..17c7e8b 100644
--- a/pkg/analysis_server/test/services/index/store/split_store_test.dart
+++ b/pkg/analysis_server/test/services/index/store/split_store_test.dart
@@ -6,7 +6,7 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
 import 'package:analysis_server/src/services/index/index.dart';
 import 'package:analysis_server/src/services/index/indexable_element.dart';
 import 'package:analysis_server/src/services/index/store/codec.dart';
diff --git a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
index 4dfb55d..46a6e67 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
@@ -69,17 +69,16 @@
         expectedMessage: 'Cannot extract the left-hand side of an assignment.');
   }
 
-  test_checkInitialConditions_methodName_reference() async {
+  test_checkInitialConditions_namePartOfDeclaration_function() async {
     indexTestUnit('''
 main() {
-  main();
 }
 ''');
-    _createRefactoringWithSuffix('main', '();');
+    _createRefactoringWithSuffix('main', '()');
     // check conditions
     RefactoringStatus status = await refactoring.checkAllConditions();
     assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL,
-        expectedMessage: 'Cannot extract a single method name.');
+        expectedMessage: 'Cannot extract the name part of a declaration.');
   }
 
   test_checkInitialConditions_namePartOfDeclaration_variable() async {
@@ -333,16 +332,40 @@
     _createRefactoring(testCode.indexOf('bb * 2'), 0);
     // check conditions
     await refactoring.checkInitialConditions();
-    List<String> subExpressions = <String>[];
-    for (int i = 0; i < refactoring.coveringExpressionOffsets.length; i++) {
-      int offset = refactoring.coveringExpressionOffsets[i];
-      int length = refactoring.coveringExpressionLengths[i];
-      subExpressions.add(testCode.substring(offset, offset + length));
-    }
+    List<String> subExpressions = _getCoveringExpressions();
     expect(subExpressions,
         ['bbb', 'bbb * 2', 'aaa + bbb * 2', 'aaa + bbb * 2 + 3']);
   }
 
+  test_coveringExpressions_inArgumentList() async {
+    indexTestUnit('''
+main() {
+  foo(111 + 222);
+}
+int foo(int x) => x;
+''');
+    _createRefactoring(testCode.indexOf('11 +'), 0);
+    // check conditions
+    await refactoring.checkInitialConditions();
+    List<String> subExpressions = _getCoveringExpressions();
+    expect(subExpressions, ['111', '111 + 222', 'foo(111 + 222)']);
+  }
+
+  test_coveringExpressions_skipAssignments() async {
+    indexTestUnit('''
+main() {
+  int v;
+  foo(v = 111 + 222);
+}
+int foo(x) => 42;
+''');
+    _createRefactoring(testCode.indexOf('11 +'), 0);
+    // check conditions
+    await refactoring.checkInitialConditions();
+    List<String> subExpressions = _getCoveringExpressions();
+    expect(subExpressions, ['111', '111 + 222', 'foo(v = 111 + 222)']);
+  }
+
   test_fragmentExpression() {
     indexTestUnit('''
 main() {
@@ -859,6 +882,24 @@
 ''');
   }
 
+  test_singleExpression_methodName_reference() async {
+    indexTestUnit('''
+main() {
+  var v = foo().length;
+}
+String foo() => '';
+''');
+    _createRefactoringWithSuffix('foo', '().');
+    // apply refactoring
+    return _assertSuccessfulRefactoring('''
+main() {
+  var res = foo();
+  var v = res.length;
+}
+String foo() => '';
+''');
+  }
+
   test_singleExpression_nameOfProperty_prefixedIdentifier() async {
     indexTestUnit('''
 main(p) {
@@ -894,7 +935,7 @@
   }
 
   /**
-   * Here we use knowledge how exactly `1 + 2 + 3 + 41 is parsed. We know that
+   * Here we use knowledge how exactly `1 + 2 + 3 + 4` is parsed. We know that
    * `1 + 2` will be a separate and complete binary expression, so it can be
    * handled as a single expression.
    */
@@ -1036,4 +1077,14 @@
     int length = selectionSearch.length;
     _createRefactoring(offset, length);
   }
+
+  List<String> _getCoveringExpressions() {
+    List<String> subExpressions = <String>[];
+    for (int i = 0; i < refactoring.coveringExpressionOffsets.length; i++) {
+      int offset = refactoring.coveringExpressionOffsets[i];
+      int length = refactoring.coveringExpressionLengths[i];
+      subExpressions.add(testCode.substring(offset, offset + length));
+    }
+    return subExpressions;
+  }
 }
diff --git a/pkg/analysis_server/test/source/caching_put_package_map_provider_test.dart b/pkg/analysis_server/test/source/caching_put_package_map_provider_test.dart
index 2c1d252..9aa321b 100644
--- a/pkg/analysis_server/test/source/caching_put_package_map_provider_test.dart
+++ b/pkg/analysis_server/test/source/caching_put_package_map_provider_test.dart
@@ -49,7 +49,9 @@
       for (String path in inputFiles) {
         resProvider.newFile(path, '');
       }
-      return resProvider.getResource(inputFiles[0]).parent;
+      Folder projectFolder = resProvider.getResource(inputFiles[0]).parent;
+      resProvider.newFile(projectFolder.path + '/pubspec.lock', '');
+      return projectFolder;
     }
 
     int mockWriteFile(File cacheFile, String content) {
diff --git a/pkg/analysis_server/test/src/utilities/change_builder_core_test.dart b/pkg/analysis_server/test/src/utilities/change_builder_core_test.dart
index 43adc4e..4eb855f 100644
--- a/pkg/analysis_server/test/src/utilities/change_builder_core_test.dart
+++ b/pkg/analysis_server/test/src/utilities/change_builder_core_test.dart
@@ -4,8 +4,8 @@
 
 library analysis_server.test.src.utilities.change_builder_core_test;
 
-import 'package:analysis_server/plugin/edit/utilities/change_builder_core.dart';
 import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analysis_server/src/provisional/edit/utilities/change_builder_core.dart';
 import 'package:analysis_server/src/utilities/change_builder_core.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 import 'package:unittest/unittest.dart';
diff --git a/pkg/analysis_server/test/src/utilities/change_builder_dart_test.dart b/pkg/analysis_server/test/src/utilities/change_builder_dart_test.dart
index 7c6442b..5db934d 100644
--- a/pkg/analysis_server/test/src/utilities/change_builder_dart_test.dart
+++ b/pkg/analysis_server/test/src/utilities/change_builder_dart_test.dart
@@ -4,8 +4,8 @@
 
 library analysis_server.test.src.utilities.change_builder_dart_test;
 
-import 'package:analysis_server/plugin/edit/utilities/change_builder_dart.dart';
 import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analysis_server/src/provisional/edit/utilities/change_builder_dart.dart';
 import 'package:analysis_server/src/utilities/change_builder_dart.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/source.dart';
diff --git a/pkg/analysis_server/test/stress/replay/operation.dart b/pkg/analysis_server/test/stress/replay/operation.dart
new file mode 100644
index 0000000..d7af722
--- /dev/null
+++ b/pkg/analysis_server/test/stress/replay/operation.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Operations to be performed during the simulation.
+ */
+library analysis_server.test.stress.replay.replay;
+
+import '../utilities/server.dart';
+
+/**
+ * An operation that will send an 'analysis.updateContent' request.
+ */
+class AnalysisUpdateContent extends ServerOperation {
+  /**
+   * The path of the file whose content is being updated.
+   */
+  String filePath;
+
+  /**
+   * The overlay used to update the content.
+   */
+  dynamic overlay;
+
+  /**
+   * Initialize an operation to send an 'analysis.updateContent' request with
+   * the given [filePath] and [overlay] as parameters.
+   */
+  AnalysisUpdateContent(this.filePath, this.overlay);
+
+  @override
+  void perform(Server server) {
+    server.sendAnalysisUpdateContent({filePath: overlay});
+//    if (overlay is ChangeContentOverlay) {
+//      List<SourceEdit> edits = (overlay as ChangeContentOverlay).edits;
+//      if (edits.length == 1) {
+//        SourceEdit edit = edits[0];
+//        if (edit.replacement.endsWith('.')) {
+//          int offset = edit.offset + edit.replacement.length - 1;
+//          server.sendCompletionGetSuggestions(filePath, offset);
+//        }
+//      }
+//    }
+  }
+}
+
+/**
+ * An operation to be performed during the simulation.
+ */
+abstract class ServerOperation {
+  /**
+   * Perform this operation by communicating with the given [server].
+   */
+  void perform(Server server);
+}
diff --git a/pkg/analysis_server/test/stress/replay/replay.dart b/pkg/analysis_server/test/stress/replay/replay.dart
new file mode 100644
index 0000000..37de911
--- /dev/null
+++ b/pkg/analysis_server/test/stress/replay/replay.dart
@@ -0,0 +1,467 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * A stress test for the analysis server.
+ */
+library analysis_server.test.stress.replay.replay;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/util/glob.dart';
+import 'package:args/args.dart';
+import 'package:path/path.dart' as path;
+
+import '../utilities/git.dart';
+import '../utilities/server.dart';
+import 'operation.dart';
+
+/**
+ * Run the simulation based on the given command-line [arguments].
+ */
+Future main(List<String> arguments) async {
+  Driver driver = new Driver();
+  await driver.run(arguments);
+}
+
+/**
+ * The driver class that runs the simulation.
+ */
+class Driver {
+  /**
+   * The name of the command-line flag that will print help text.
+   */
+  static String HELP_FLAG_NAME = 'help';
+
+  /**
+   * The name of the pubspec file.
+   */
+  static const String PUBSPEC_FILE_NAME = 'pubspec.yaml';
+
+  /**
+   * The name of the branch used to clean-up after making temporary changes.
+   */
+  static const String TEMP_BRANCH_NAME = 'temp';
+
+  /**
+   * The absolute path of the repository.
+   */
+  String repositoryPath;
+
+  /**
+   * The absolute paths to the analysis roots.
+   */
+  List<String> analysisRoots;
+
+  /**
+   * The git repository.
+   */
+  GitRepository repository;
+
+  /**
+   * The connection to the analysis server.
+   */
+  Server server = new Server();
+
+  /**
+   * A list of the glob patterns used to identify the files being analyzed by
+   * the server.
+   */
+  List<Glob> fileGlobs;
+
+  /**
+   * An object gathering statistics about the simulation.
+   */
+  Statistics statistics;
+
+  /**
+   * Initialize a newly created driver.
+   */
+  Driver() {
+    statistics = new Statistics(this);
+  }
+
+  /**
+   * Run the test based on the given command-line arguments ([args]).
+   */
+  Future run(List<String> args) async {
+    //
+    // Process the command-line arguments.
+    //
+    ArgParser parser = _createArgParser();
+    ArgResults results;
+    try {
+      results = parser.parse(args);
+    } catch (exception) {
+      _showUsage(parser);
+      return null;
+    }
+
+    if (results[HELP_FLAG_NAME]) {
+      _showUsage(parser);
+      return null;
+    }
+
+    List<String> arguments = results.arguments;
+    if (arguments.length < 2) {
+      _showUsage(parser);
+      return null;
+    }
+    repositoryPath = path.normalize(arguments[0]);
+    repository = new GitRepository(repositoryPath);
+
+    analysisRoots = arguments
+        .sublist(1)
+        .map((String analysisRoot) => path.normalize(analysisRoot))
+        .toList();
+    for (String analysisRoot in analysisRoots) {
+      if (repositoryPath != analysisRoot &&
+          !path.isWithin(repositoryPath, analysisRoot)) {
+        _showUsage(parser,
+            'Analysis roots must be contained within the repository: $analysisRoot');
+        return null;
+      }
+    }
+    //
+    // Replay the commit history.
+    //
+    Stopwatch stopwatch = new Stopwatch();
+    statistics.stopwatch = stopwatch;
+    stopwatch.start();
+    await server.start();
+    server.sendServerSetSubscriptions([ServerService.STATUS]);
+    server.sendAnalysisSetGeneralSubscriptions(
+        [GeneralAnalysisService.ANALYZED_FILES]);
+    // TODO(brianwilkerson) Get the list of glob patterns from the server after
+    // an API for getting them has been implemented.
+    fileGlobs = <Glob>[
+      new Glob(path.context.separator, '**.dart'),
+      new Glob(path.context.separator, '**.html'),
+      new Glob(path.context.separator, '**.htm'),
+      new Glob(path.context.separator, '**/.analysisOptions')
+    ];
+    try {
+      _replayChanges();
+    } finally {
+      server.sendServerShutdown();
+      repository.checkout('master');
+    }
+    stopwatch.stop();
+    //
+    // Print out statistics gathered while performing the simulation.
+    //
+    statistics.print();
+    return null;
+  }
+
+  /**
+   * Create and return a parser that can be used to parse the command-line
+   * arguments.
+   */
+  ArgParser _createArgParser() {
+    ArgParser parser = new ArgParser();
+    parser.addFlag(HELP_FLAG_NAME,
+        abbr: 'h',
+        help: 'Print usage information',
+        defaultsTo: false,
+        negatable: false);
+    return parser;
+  }
+
+  void _createSourceEdits(FileEdit fileEdit, BlobDiff blobDiff) {
+    LineInfo info = fileEdit.lineInfo;
+    for (DiffHunk hunk in blobDiff.hunks) {
+      List<SourceEdit> sourceEdits = <SourceEdit>[];
+      int srcStart = info.getOffsetOfLine(hunk.srcLine);
+      int srcEnd = info.getOffsetOfLine(hunk.srcLine + hunk.removeLines.length);
+      // TODO(brianwilkerson) Create multiple edits instead of a single edit.
+      sourceEdits.add(new SourceEdit(
+          srcStart, srcEnd - srcStart + 1, _join(hunk.addLines)));
+      fileEdit.addSourceEdits(sourceEdits);
+    }
+  }
+
+  /**
+   * Return athe absolute paths of all of the pubspec files in all of the
+   * analysis roots.
+   */
+  Iterable<String> _findPubspecsInAnalysisRoots() {
+    List<String> pubspecFiles = <String>[];
+    for (String directoryPath in analysisRoots) {
+      Directory directory = new Directory(directoryPath);
+      List<FileSystemEntity> children =
+          directory.listSync(recursive: true, followLinks: false);
+      for (FileSystemEntity child in children) {
+        String filePath = child.path;
+        if (path.basename(filePath) == PUBSPEC_FILE_NAME) {
+          pubspecFiles.add(filePath);
+        }
+      }
+    }
+    return pubspecFiles;
+  }
+
+  String _join(List<String> lines) {
+    StringBuffer buffer = new StringBuffer();
+    for (int i = 0; i < lines.length; i++) {
+      buffer.writeln(lines[i]);
+    }
+    return buffer.toString();
+  }
+
+  /**
+   * Replay the changes in each commit.
+   */
+  void _replayChanges() {
+    //
+    // Get the revision history of the repo.
+    //
+    LinearCommitHistory history = repository.getCommitHistory();
+    statistics.commitCount = history.commitIds.length;
+    LinearCommitHistoryIterator iterator = history.iterator();
+    //
+    // Iterate over the history, applying changes.
+    //
+    bool firstCheckout = true;
+//    Map<String, List<AnalysisError>> expectedErrors = null;
+    Iterable<String> changedPubspecs;
+    while (iterator.moveNext()) {
+      //
+      // Checkout the commit on which the changes are based.
+      //
+      repository.checkout(iterator.srcCommit);
+//      if (expectedErrors != null) {
+//        await server.analysisFinished;
+//        server.expectErrorState(expectedErrors);
+//      }
+      if (firstCheckout) {
+        changedPubspecs = _findPubspecsInAnalysisRoots();
+        server.sendAnalysisSetAnalysisRoots(analysisRoots, []);
+        firstCheckout = false;
+      } else {
+        server.removeAllOverlays();
+      }
+//      await server.analysisFinished;
+//      expectedErrors = server.errorMap;
+      for (String filePath in changedPubspecs) {
+        _runPub(filePath);
+      }
+      //
+      // Apply the changes.
+      //
+      CommitDelta commitDelta = iterator.next();
+      commitDelta.filterDiffs(analysisRoots, fileGlobs);
+      if (commitDelta.hasDiffs) {
+        statistics.commitsWithChangeInRootCount++;
+        _replayDiff(commitDelta);
+      }
+      changedPubspecs = commitDelta.filesMatching(PUBSPEC_FILE_NAME);
+    }
+    server.removeAllOverlays();
+  }
+
+  void _replayDiff(CommitDelta commitDelta) {
+    List<FileEdit> editList = <FileEdit>[];
+    for (DiffRecord record in commitDelta.diffRecords) {
+      FileEdit edit = new FileEdit(record);
+      _createSourceEdits(edit, record.getBlobDiff());
+      editList.add(edit);
+    }
+    // TODO(brianwilkerson) Randomize.
+    // Randomly select operations from different files to simulate a user
+    // editing multiple files simultaneously.
+    for (FileEdit edit in editList) {
+      List<String> currentFile = <String>[edit.filePath];
+      server.sendAnalysisSetPriorityFiles(currentFile);
+      server.sendAnalysisSetSubscriptions({
+        AnalysisService.FOLDING: currentFile,
+        AnalysisService.HIGHLIGHTS: currentFile,
+        AnalysisService.IMPLEMENTED: currentFile,
+        AnalysisService.NAVIGATION: currentFile,
+        AnalysisService.OCCURRENCES: currentFile,
+        AnalysisService.OUTLINE: currentFile,
+        AnalysisService.OVERRIDES: currentFile
+      });
+      for (ServerOperation operation in edit.getOperations()) {
+        operation.perform(server);
+      }
+    }
+  }
+
+  /**
+   * Run `pub` on the pubspec with the given [filePath].
+   */
+  void _runPub(String filePath) {
+    String directoryPath = path.dirname(filePath);
+    if (new Directory(directoryPath).existsSync()) {
+      Process.runSync(
+          '/Users/brianwilkerson/Dev/dart/dart-sdk/bin/pub', ['get'],
+          workingDirectory: directoryPath);
+    }
+  }
+
+  /**
+   * Display usage information, preceeded by the [errorMessage] if one is given.
+   */
+  void _showUsage(ArgParser parser, [String errorMessage = null]) {
+    if (errorMessage != null) {
+      stderr.writeln(errorMessage);
+      stderr.writeln();
+    }
+    stderr.writeln('''
+Usage: replay [options...] repositoryPath analysisRoot...
+
+Uses the commit history of the git repository at the given repository path to
+simulate the development of a code base while using the analysis server to
+analyze the code base.
+
+The repository path must be the absolute path of a directory containing a git
+repository.
+
+There must be at least one analysis root, and all of the analysis roots must be
+the absolute path of a directory contained within the repository directory. The
+analysis roots represent the portion of the repository that will be analyzed by
+the analysis server.
+
+OPTIONS:''');
+    stderr.writeln(parser.usage);
+  }
+}
+
+/**
+ * A representation of the edits to be applied to a single file.
+ */
+class FileEdit {
+  /**
+   * The absolute path of the file to be edited.
+   */
+  String filePath;
+
+  /**
+   * The content of the file before any edits have been applied.
+   */
+  String content;
+
+  /**
+   * The line info for the file before any edits have been applied.
+   */
+  LineInfo lineInfo;
+
+  /**
+   * The lists of source edits, one list for each hunk being edited.
+   */
+  List<List<SourceEdit>> editLists = <List<SourceEdit>>[];
+
+  /**
+   * Initialize a collection of edits to be associated with the file at the
+   * given [filePath].
+   */
+  FileEdit(DiffRecord record) {
+    filePath = record.srcPath;
+    if (record.isAddition) {
+      content = '';
+      lineInfo = new LineInfo(<int>[0]);
+    } else if (record.isCopy || record.isRename || record.isTypeChange) {
+      throw new ArgumentError('Unhandled change of type ${record.status}');
+    } else {
+      content = new File(filePath).readAsStringSync();
+      lineInfo = new LineInfo(StringUtilities.computeLineStarts(content));
+    }
+  }
+
+  /**
+   * Add a list of source edits that, taken together, transform a single hunk in
+   * the file.
+   */
+  void addSourceEdits(List<SourceEdit> sourceEdits) {
+    editLists.add(sourceEdits);
+  }
+
+  /**
+   * Return a list of operations to be sent to the server.
+   */
+  List<ServerOperation> getOperations() {
+    // TODO(brianwilkerson) Randomize.
+    // Make the order of edits random. Doing so will require updating the
+    // offsets of edits after the selected edit point.
+    List<ServerOperation> operations = <ServerOperation>[];
+    operations.add(
+        new AnalysisUpdateContent(filePath, new AddContentOverlay(content)));
+    for (List<SourceEdit> editList in editLists.reversed) {
+      for (SourceEdit edit in editList.reversed) {
+        operations.add(new AnalysisUpdateContent(
+            filePath, new ChangeContentOverlay([edit])));
+      }
+    }
+    operations
+        .add(new AnalysisUpdateContent(filePath, new RemoveContentOverlay()));
+    return operations;
+  }
+}
+
+/**
+ * A set of statistics related to the execution of the simulation.
+ */
+class Statistics {
+  /**
+   * The driver driving the simulation.
+   */
+  final Driver driver;
+
+  /**
+   * The stopwatch being used to time the simulation.
+   */
+  Stopwatch stopwatch;
+
+  /**
+   * The total number of commits in the repository.
+   */
+  int commitCount;
+
+  /**
+   * The number of commits in the repository that touched one of the files in
+   * one of the analysis roots.
+   */
+  int commitsWithChangeInRootCount = 0;
+
+  /**
+   * Initialize a newly created set of statistics.
+   */
+  Statistics(this.driver);
+
+  void print() {
+    stdout.write('Replay commits in ');
+    stdout.writeln(driver.repositoryPath);
+    stdout.write('  replay took ');
+    stdout.writeln(_printTime(stopwatch.elapsedMilliseconds));
+    stdout.write('  analysis roots = ');
+    stdout.writeln(driver.analysisRoots);
+    stdout.write('  number of commits = ');
+    stdout.writeln(commitCount);
+    stdout.write('  number of commits with a change in an analysis root = ');
+    stdout.writeln(commitsWithChangeInRootCount);
+  }
+
+  String _printTime(int milliseconds) {
+    int seconds = milliseconds ~/ 1000;
+    milliseconds -= seconds * 1000;
+    int minutes = seconds ~/ 60;
+    seconds -= minutes * 60;
+    int hours = minutes ~/ 60;
+    minutes -= hours * 60;
+
+    if (hours > 0) {
+      return '$hours:$minutes:$seconds.$milliseconds';
+    } else if (minutes > 0) {
+      return '$minutes:$seconds.$milliseconds m';
+    } else if (seconds > 0) {
+      return '$seconds.$milliseconds s';
+    }
+    return '$milliseconds ms';
+  }
+}
diff --git a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
index 43a520f..e465571 100644
--- a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
+++ b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
@@ -119,6 +119,20 @@
   public void analysis_getNavigation(String file, int offset, int length, GetNavigationConsumer consumer);
 
   /**
+   * {@code analysis.getReachableSources}
+   *
+   * Return the transitive closure of reachable sources for a given file.
+   *
+   * If a request is made for a file which does not exist, or which is not currently subject to
+   * analysis (e.g. because it is not associated with any analysis root specified to
+   * analysis.setAnalysisRoots), an error of type GET_REACHABLE_SOURCES_INVALID_FILE will be
+   * generated.
+   *
+   * @param file The file for which reachable source information is being requested.
+   */
+  public void analysis_getReachableSources(String file, GetReachableSourcesConsumer consumer);
+
+  /**
    * {@code analysis.reanalyze}
    *
    * Force the re-analysis of everything contained in the specified analysis roots. This will cause
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/ContextData.java b/pkg/analysis_server/tool/spec/generated/java/types/ContextData.java
index ab4020c..af83c5e 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/ContextData.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/ContextData.java
@@ -64,6 +64,11 @@
   private final int workItemQueueLength;
 
   /**
+   * A rolling average of work items in the queue. (A double encoded as a String.)
+   */
+  private final String workItemQueueLengthAverage;
+
+  /**
    * Exceptions associated with cache entries.
    */
   private final List<String> cacheEntryExceptions;
@@ -71,11 +76,12 @@
   /**
    * Constructor for {@link ContextData}.
    */
-  public ContextData(String name, int explicitFileCount, int implicitFileCount, int workItemQueueLength, List<String> cacheEntryExceptions) {
+  public ContextData(String name, int explicitFileCount, int implicitFileCount, int workItemQueueLength, String workItemQueueLengthAverage, List<String> cacheEntryExceptions) {
     this.name = name;
     this.explicitFileCount = explicitFileCount;
     this.implicitFileCount = implicitFileCount;
     this.workItemQueueLength = workItemQueueLength;
+    this.workItemQueueLengthAverage = workItemQueueLengthAverage;
     this.cacheEntryExceptions = cacheEntryExceptions;
   }
 
@@ -88,6 +94,7 @@
         other.explicitFileCount == explicitFileCount &&
         other.implicitFileCount == implicitFileCount &&
         other.workItemQueueLength == workItemQueueLength &&
+        ObjectUtilities.equals(other.workItemQueueLengthAverage, workItemQueueLengthAverage) &&
         ObjectUtilities.equals(other.cacheEntryExceptions, cacheEntryExceptions);
     }
     return false;
@@ -98,8 +105,9 @@
     int explicitFileCount = jsonObject.get("explicitFileCount").getAsInt();
     int implicitFileCount = jsonObject.get("implicitFileCount").getAsInt();
     int workItemQueueLength = jsonObject.get("workItemQueueLength").getAsInt();
+    String workItemQueueLengthAverage = jsonObject.get("workItemQueueLengthAverage").getAsString();
     List<String> cacheEntryExceptions = JsonUtilities.decodeStringList(jsonObject.get("cacheEntryExceptions").getAsJsonArray());
-    return new ContextData(name, explicitFileCount, implicitFileCount, workItemQueueLength, cacheEntryExceptions);
+    return new ContextData(name, explicitFileCount, implicitFileCount, workItemQueueLength, workItemQueueLengthAverage, cacheEntryExceptions);
   }
 
   public static List<ContextData> fromJsonArray(JsonArray jsonArray) {
@@ -149,6 +157,13 @@
     return workItemQueueLength;
   }
 
+  /**
+   * A rolling average of work items in the queue. (A double encoded as a String.)
+   */
+  public String getWorkItemQueueLengthAverage() {
+    return workItemQueueLengthAverage;
+  }
+
   @Override
   public int hashCode() {
     HashCodeBuilder builder = new HashCodeBuilder();
@@ -156,6 +171,7 @@
     builder.append(explicitFileCount);
     builder.append(implicitFileCount);
     builder.append(workItemQueueLength);
+    builder.append(workItemQueueLengthAverage);
     builder.append(cacheEntryExceptions);
     return builder.toHashCode();
   }
@@ -166,6 +182,7 @@
     jsonObject.addProperty("explicitFileCount", explicitFileCount);
     jsonObject.addProperty("implicitFileCount", implicitFileCount);
     jsonObject.addProperty("workItemQueueLength", workItemQueueLength);
+    jsonObject.addProperty("workItemQueueLengthAverage", workItemQueueLengthAverage);
     JsonArray jsonArrayCacheEntryExceptions = new JsonArray();
     for (String elt : cacheEntryExceptions) {
       jsonArrayCacheEntryExceptions.add(new JsonPrimitive(elt));
@@ -186,6 +203,8 @@
     builder.append(implicitFileCount + ", ");
     builder.append("workItemQueueLength=");
     builder.append(workItemQueueLength + ", ");
+    builder.append("workItemQueueLengthAverage=");
+    builder.append(workItemQueueLengthAverage + ", ");
     builder.append("cacheEntryExceptions=");
     builder.append(StringUtils.join(cacheEntryExceptions, ", "));
     builder.append("]");
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
index b8ba4c0..a5e439f 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
@@ -59,6 +59,12 @@
   public static final String GET_NAVIGATION_INVALID_FILE = "GET_NAVIGATION_INVALID_FILE";
 
   /**
+   * An "analysis.getReachableSources" request specified a FilePath which does not match a file
+   * currently subject to analysis.
+   */
+  public static final String GET_REACHABLE_SOURCES_INVALID_FILE = "GET_REACHABLE_SOURCES_INVALID_FILE";
+
+  /**
    * A path passed as an argument to a request (such as analysis.reanalyze) is required to be an
    * analysis root, but isn't.
    */
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index d519a21..fcddc94 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -6,7 +6,7 @@
   </head>
   <body>
     <h1>Analysis Server API Specification</h1>
-    <h1 style="color:#999999">Version <version>1.12.0</version></h1>
+    <h1 style="color:#999999">Version <version>1.13.0</version></h1>
     <p>
       This document contains a specification of the API provided by the
       analysis server.  The API in this document is currently under
@@ -395,6 +395,42 @@
           </field>
         </result>
       </request>
+      <request method="getReachableSources">
+        <p>
+          Return the transitive closure of reachable sources for a given file.
+        </p>
+        <p>
+          If a request is made for a file which does not exist, or
+          which is not currently subject to analysis (e.g. because it
+          is not associated with any analysis root specified to
+          analysis.setAnalysisRoots), an error of type
+          <tt>GET_REACHABLE_SOURCES_INVALID_FILE</tt> will be generated.
+        </p>
+        <params>
+          <field name="file">
+            <ref>FilePath</ref>
+            <p>
+              The file for which reachable source information is being requested.
+            </p>
+          </field>
+        </params>
+        <result>
+          <field name="sources">
+            <map>
+              <key><ref>String</ref></key>
+              <value><list>><ref>String</ref></list></value>
+            </map>
+            <p>
+              A mapping from source URIs to directly reachable source URIs. For example,
+              a file "foo.dart" that imports "bar.dart" would have the corresponding mapping
+              { "file:///foo.dart" : ["file:///bar.dart"] }.  If "bar.dart" has further imports
+              (or exports) there will be a mapping from the URI "file:///bar.dart" to them.
+              To check if a specific URI is reachable from a given file, clients can check
+              for its presence in the resulting key set.
+            </p>
+          </field>
+        </result>
+      </request>
       <request method="getLibraryDependencies">
         <p>
           Return library dependency information for use in client-side indexing
@@ -2489,6 +2525,12 @@
               The number of work items in the queue.
             </p>
           </field>
+          <field name="workItemQueueLengthAverage">
+            <ref>String</ref>
+            <p>
+              A rolling average of work items in the queue. (A double encoded as a String.)
+            </p>
+          </field>
           <field name="cacheEntryExceptions">
             <list><ref>String</ref></list>
             <p>
@@ -3644,6 +3686,14 @@
             </p>
           </value>
           <value>
+            <code>GET_REACHABLE_SOURCES_INVALID_FILE</code>
+            <p>
+              An "analysis.getReachableSources" request specified a FilePath
+              which does not match a file currently subject to
+              analysis.
+            </p>
+          </value>
+          <value>
             <code>INVALID_ANALYSIS_ROOT</code>
             <p>
               A path passed as an argument to a request (such as
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index d0af2b9..6ff682d 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 0.26.3
+* (Internal) Support for `_embedder.yaml` discovery and processing.
+
 ## 0.26.2
 * Add code generation utilities for use in both analyzer and analysis server.
 
diff --git a/pkg/analyzer/lib/file_system/file_system.dart b/pkg/analyzer/lib/file_system/file_system.dart
index 21e8d05..cbe175f 100644
--- a/pkg/analyzer/lib/file_system/file_system.dart
+++ b/pkg/analyzer/lib/file_system/file_system.dart
@@ -14,7 +14,7 @@
 /**
  * [File]s are leaf [Resource]s which contain data.
  */
-abstract class File extends Resource {
+abstract class File implements Resource {
   /**
    * Watch for changes to this file
    */
@@ -53,7 +53,7 @@
 /**
  * [Folder]s are [Resource]s which may contain files and/or other folders.
  */
-abstract class Folder extends Resource {
+abstract class Folder implements Resource {
   /**
    * Watch for changes to the files inside this folder (and in any nested
    * folders, including folders reachable via links).
diff --git a/pkg/analyzer/lib/source/pub_package_map_provider.dart b/pkg/analyzer/lib/source/pub_package_map_provider.dart
index 07fdba7..5daf61d 100644
--- a/pkg/analyzer/lib/source/pub_package_map_provider.dart
+++ b/pkg/analyzer/lib/source/pub_package_map_provider.dart
@@ -59,6 +59,13 @@
 
   @override
   PackageMapInfo computePackageMap(Folder folder) {
+    // If the pubspec.lock file does not exist, no need to run anything.
+    {
+      String lockPath = getPubspecLockPath(folder);
+      if (!resourceProvider.getFile(lockPath).exists) {
+        return computePackageMapError(folder);
+      }
+    }
     // TODO(paulberry) make this asynchronous so that we can (a) do other
     // analysis while it's in progress, and (b) time out if it takes too long
     // to respond.
@@ -96,13 +103,18 @@
     // we'll know when to try running "pub list-package-dirs" again.
     // Unfortunately, "pub list-package-dirs" doesn't tell us dependencies when
     // an error occurs, so just assume there is one dependency, "pubspec.lock".
-    List<String> dependencies = <String>[
-      resourceProvider.pathContext.join(folder.path, PUBSPEC_LOCK_NAME)
-    ];
+    String lockPath = getPubspecLockPath(folder);
+    List<String> dependencies = <String>[lockPath];
     return new PackageMapInfo(null, dependencies.toSet());
   }
 
   /**
+   * Return the path to the `pubspec.lock` file in the given [folder].
+   */
+  String getPubspecLockPath(Folder folder) =>
+      resourceProvider.pathContext.join(folder.path, PUBSPEC_LOCK_NAME);
+
+  /**
    * Decode the JSON output from pub into a package map.  Paths in the
    * output are considered relative to [folder].
    */
diff --git a/pkg/analyzer/lib/src/context/cache.dart b/pkg/analyzer/lib/src/context/cache.dart
index a609421..2b81cdd 100644
--- a/pkg/analyzer/lib/src/context/cache.dart
+++ b/pkg/analyzer/lib/src/context/cache.dart
@@ -66,7 +66,7 @@
    */
   Iterable<Source> get sources {
     return _partitions
-        .map((CachePartition partition) => partition._sources)
+        .map((CachePartition partition) => partition.sources)
         .expand((Iterable<Source> sources) => sources);
   }
 
@@ -191,7 +191,7 @@
         <Map<AnalysisTarget, CacheEntry>>[];
     for (CachePartition partition in _partitions) {
       if (context == null || partition.context == context) {
-        maps.add(partition.map);
+        maps.add(partition.entryMap);
       }
     }
     return new MultipleMapIterator<AnalysisTarget, CacheEntry>(maps);
@@ -495,7 +495,7 @@
 //      }
 //      valueStr = valueStr.replaceAll('\n', '\\n');
 //      print(
-//          'setValue $descriptor for $target value=$valueStr deps=$dependedOn');
+//          'setValue $descriptor for $target value=$valueStr $dependedOn=$dependedOn');
 //    }
     _validateStateChange(descriptor, CacheState.VALID);
     TargetedResult thisResult = new TargetedResult(target, descriptor);
@@ -509,14 +509,16 @@
   }
 
   /**
-   * Set the value of the result represented by the given [descriptor] to the
-   * given [value], keep its dependency, invalidate all the dependent result.
+   * If the result represented by the given [descriptor] is valid, set
+   * it to the given [value], keep its dependency, and if [invalidateDependent]
+   * invalidate all the dependent result.
    */
   void setValueIncremental(
       ResultDescriptor descriptor, dynamic value, bool invalidateDependent) {
     ResultData data = getResultData(descriptor);
-    data.state = CacheState.VALID;
-    data.value = value;
+    if (data.state == CacheState.VALID || data.state == CacheState.FLUSHED) {
+      data.value = value;
+    }
     if (invalidateDependent) {
       _invalidateDependentResults(nextInvalidateId++, data, null, 0);
     }
@@ -583,7 +585,7 @@
     _invalidateDependentResults(id, thisData, delta, level + 1);
     // If empty and not explicitly added, remove the entry altogether.
     if (_resultMap.isEmpty && !explicitlyAdded) {
-      _partition._targetMap.remove(target);
+      _partition.entryMap.remove(target);
       _partition._removeIfSource(target);
     }
     // Notify controller.
@@ -856,18 +858,18 @@
    * A table mapping the targets belonging to this partition to the information
    * known about those targets.
    */
-  HashMap<AnalysisTarget, CacheEntry> _targetMap =
+  final HashMap<AnalysisTarget, CacheEntry> entryMap =
       new HashMap<AnalysisTarget, CacheEntry>();
 
   /**
    * A set of the [Source] targets.
    */
-  final HashSet<Source> _sources = new HashSet<Source>();
+  final HashSet<Source> sources = new HashSet<Source>();
 
   /**
    * A table mapping full paths to lists of [Source]s with these full paths.
    */
-  final Map<String, List<Source>> _pathToSources = <String, List<Source>>{};
+  final Map<String, List<Source>> pathToSource = <String, List<Source>>{};
 
   /**
    * Initialize a newly created cache partition, belonging to the given
@@ -876,35 +878,28 @@
   CachePartition(this.context);
 
   /**
-   * Return a table mapping the targets known to the context to the information
-   * known about the target.
-   *
-   * <b>Note:</b> This method is only visible for use by [AnalysisCache] and
-   * should not be used for any other purpose.
-   */
-  Map<AnalysisTarget, CacheEntry> get map => _targetMap;
-
-  /**
    * Notifies the partition that the client is going to stop using it.
    */
   void dispose() {
-    for (CacheEntry entry in _targetMap.values) {
+    for (CacheEntry entry in entryMap.values) {
       entry.dispose();
     }
-    _targetMap.clear();
+    entryMap.clear();
+    sources.clear();
+    pathToSource.clear();
   }
 
   /**
    * Return the entry associated with the given [target].
    */
-  CacheEntry get(AnalysisTarget target) => _targetMap[target];
+  CacheEntry get(AnalysisTarget target) => entryMap[target];
 
   /**
    * Return [Source]s whose full path is equal to the given [path].
    * Maybe empty, but not `null`.
    */
   List<Source> getSourcesWithFullName(String path) {
-    List<Source> sources = _pathToSources[path];
+    List<Source> sources = pathToSource[path];
     return sources != null ? sources : Source.EMPTY_LIST;
   }
 
@@ -918,7 +913,7 @@
    * cache entries.
    */
   MapIterator<AnalysisTarget, CacheEntry> iterator() =>
-      new SingleMapIterator<AnalysisTarget, CacheEntry>(_targetMap);
+      new SingleMapIterator<AnalysisTarget, CacheEntry>(entryMap);
 
   /**
    * Puts the given [entry] into the partition.
@@ -931,7 +926,7 @@
     }
     entry._partition = this;
     entry.fixExceptionState();
-    _targetMap[target] = entry;
+    entryMap[target] = entry;
     _addIfSource(target);
   }
 
@@ -944,7 +939,7 @@
     for (CacheFlushManager flushManager in _flushManagerMap.values) {
       flushManager.targetRemoved(target);
     }
-    CacheEntry entry = _targetMap.remove(target);
+    CacheEntry entry = entryMap.remove(target);
     if (entry != null) {
       entry._invalidateAll();
     }
@@ -983,16 +978,16 @@
   /**
    * Return the number of targets that are mapped to cache entries.
    */
-  int size() => _targetMap.length;
+  int size() => entryMap.length;
 
   /**
-   * If the given [target] is a [Source], adds it to [_sources].
+   * If the given [target] is a [Source], adds it to [sources].
    */
   void _addIfSource(AnalysisTarget target) {
     if (target is Source) {
-      _sources.add(target);
+      sources.add(target);
       String fullName = target.fullName;
-      _pathToSources.putIfAbsent(fullName, () => <Source>[]).add(target);
+      pathToSource.putIfAbsent(fullName, () => <Source>[]).add(target);
     }
   }
 
@@ -1022,17 +1017,17 @@
   }
 
   /**
-   * If the given [target] is a [Source], remove it from the list of [_sources].
+   * If the given [target] is a [Source], remove it from the list of [sources].
    */
   void _removeIfSource(AnalysisTarget target) {
     if (target is Source) {
-      _sources.remove(target);
-      String fullName = target.fullName;
-      List<Source> sources = _pathToSources[fullName];
-      if (sources != null) {
-        sources.remove(target);
-        if (sources.isEmpty) {
-          _pathToSources.remove(fullName);
+      sources.remove(target);
+      String path = target.fullName;
+      List<Source> pathSources = pathToSource[path];
+      if (pathSources != null) {
+        pathSources.remove(target);
+        if (pathSources.isEmpty) {
+          pathToSource.remove(path);
         }
       }
     }
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index 9b2fa81..4d3651b 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -256,9 +256,6 @@
   AnalysisOptions get analysisOptions => _options;
 
   @override
-  EmbedderYamlLocator get embedderYamlLocator => _embedderYamlLocator;
-
-  @override
   void set analysisOptions(AnalysisOptions options) {
     bool needsRecompute = this._options.analyzeFunctionBodiesPredicate !=
             options.analyzeFunctionBodiesPredicate ||
@@ -270,6 +267,9 @@
         (this._options.lint && !options.lint) ||
         this._options.preserveComments != options.preserveComments ||
         this._options.strongMode != options.strongMode ||
+        ((options is AnalysisOptionsImpl)
+            ? this._options.strongModeHints != options.strongModeHints
+            : false) ||
         this._options.enableStrictCallChecks !=
             options.enableStrictCallChecks ||
         this._options.enableGenericMethods != options.enableGenericMethods ||
@@ -293,6 +293,9 @@
     this._options.lint = options.lint;
     this._options.preserveComments = options.preserveComments;
     this._options.strongMode = options.strongMode;
+    if (options is AnalysisOptionsImpl) {
+      this._options.strongModeHints = options.strongModeHints;
+    }
     if (needsRecompute) {
       for (WorkManager workManager in workManagers) {
         workManager.onAnalysisOptionsChanged();
@@ -329,6 +332,9 @@
   DeclaredVariables get declaredVariables => _declaredVariables;
 
   @override
+  EmbedderYamlLocator get embedderYamlLocator => _embedderYamlLocator;
+
+  @override
   List<AnalysisTarget> get explicitTargets {
     List<AnalysisTarget> targets = <AnalysisTarget>[];
     MapIterator<AnalysisTarget, CacheEntry> iterator = _cache.iterator();
@@ -1155,6 +1161,8 @@
       setValue(LIBRARY_ELEMENT3, library);
       setValue(LIBRARY_ELEMENT4, library);
       setValue(LIBRARY_ELEMENT5, library);
+      setValue(LIBRARY_ELEMENT6, library);
+      setValue(LIBRARY_ELEMENT7, library);
       setValue(LINE_INFO, new LineInfo(<int>[0]));
       setValue(PARSE_ERRORS, AnalysisError.NO_ERRORS);
       entry.setState(PARSED_UNIT, CacheState.FLUSHED);
@@ -1183,6 +1191,7 @@
       entry.setState(RESOLVED_UNIT8, CacheState.FLUSHED);
       entry.setState(RESOLVED_UNIT9, CacheState.FLUSHED);
       entry.setState(RESOLVED_UNIT10, CacheState.FLUSHED);
+      entry.setState(RESOLVED_UNIT11, CacheState.FLUSHED);
       // USED_IMPORTED_ELEMENTS
       // USED_LOCAL_ELEMENTS
       setValue(STRONG_MODE_ERRORS, AnalysisError.NO_ERRORS);
@@ -1268,6 +1277,7 @@
     entry.setState(RESOLVED_UNIT8, CacheState.FLUSHED);
     entry.setState(RESOLVED_UNIT9, CacheState.FLUSHED);
     entry.setState(RESOLVED_UNIT10, CacheState.FLUSHED);
+    entry.setState(RESOLVED_UNIT11, CacheState.FLUSHED);
     entry.setState(RESOLVED_UNIT, CacheState.FLUSHED);
   }
 
diff --git a/pkg/analyzer/lib/src/generated/ast.dart b/pkg/analyzer/lib/src/generated/ast.dart
index 03cb8f1..f04a15e 100644
--- a/pkg/analyzer/lib/src/generated/ast.dart
+++ b/pkg/analyzer/lib/src/generated/ast.dart
@@ -5855,6 +5855,7 @@
  * > constructorInitializer ::=
  * >     [SuperConstructorInvocation]
  * >   | [ConstructorFieldInitializer]
+ * >   | [RedirectingConstructorInvocation]
  */
 abstract class ConstructorInitializer extends AstNode {}
 
@@ -12946,6 +12947,95 @@
 }
 
 /**
+ * An object used to locate the [AstNode] associated with a source range.
+ * More specifically, they will return the deepest [AstNode] which completely
+ * encompasses the specified range.
+ */
+class NodeLocator2 extends UnifyingAstVisitor<Object> {
+  /**
+   * The inclusive start offset of the range used to identify the node.
+   */
+  int _startOffset = 0;
+
+  /**
+   * The inclusive end offset of the range used to identify the node.
+   */
+  int _endOffset = 0;
+
+  /**
+   * The found node or `null` if there is no such node.
+   */
+  AstNode _foundNode;
+
+  /**
+   * Initialize a newly created locator to locate the deepest [AstNode] for
+   * which `node.offset <= [startOffset]` and `[endOffset] < node.end`.
+   *
+   * If [endOffset] is not provided, then it is considered the same as the
+   * given [startOffset].
+   */
+  NodeLocator2(int startOffset, [int endOffset])
+      : this._startOffset = startOffset,
+        this._endOffset = endOffset == null ? startOffset : endOffset;
+
+  /**
+   * Search within the given AST [node] and return the node that was found,
+   * or `null` if no node was found.
+   */
+  AstNode searchWithin(AstNode node) {
+    if (node == null) {
+      return null;
+    }
+    try {
+      node.accept(this);
+    } on NodeLocator_NodeFoundException {} catch (exception, stackTrace) {
+      AnalysisEngine.instance.logger.logInformation(
+          "Unable to locate element at offset ($_startOffset - $_endOffset)",
+          new CaughtException(exception, stackTrace));
+      return null;
+    }
+    return _foundNode;
+  }
+
+  @override
+  Object visitNode(AstNode node) {
+    Token beginToken = node.beginToken;
+    Token endToken = node.endToken;
+    // Don't include synthetic tokens.
+    while (endToken != beginToken) {
+      if (endToken.type == TokenType.EOF || !endToken.isSynthetic) {
+        break;
+      }
+      endToken = endToken.previous;
+    }
+    int end = endToken.end;
+    int start = node.offset;
+    if (end <= _startOffset) {
+      return null;
+    }
+    if (start > _endOffset) {
+      return null;
+    }
+    try {
+      node.visitChildren(this);
+    } on NodeLocator_NodeFoundException {
+      rethrow;
+    } catch (exception, stackTrace) {
+      // Ignore the exception and proceed in order to visit the rest of the
+      // structure.
+      AnalysisEngine.instance.logger.logInformation(
+          "Exception caught while traversing an AST structure.",
+          new CaughtException(exception, stackTrace));
+    }
+    if (start <= _startOffset && _endOffset < end) {
+      _foundNode = node;
+      throw new NodeLocator_NodeFoundException();
+    }
+    return null;
+  }
+}
+
+/**
  * An exception used by [NodeLocator] to cancel visiting after a node has been
  * found.
  */
diff --git a/pkg/analyzer/lib/src/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
index 2412506..8638c84 100644
--- a/pkg/analyzer/lib/src/generated/constant.dart
+++ b/pkg/analyzer/lib/src/generated/constant.dart
@@ -704,6 +704,13 @@
           field is ConstFieldElementImpl) {
         validator.beforeGetFieldEvaluationResult(field);
         EvaluationResultImpl evaluationResult = field.evaluationResult;
+        // It is possible that the evaluation result is null.
+        // This happens for example when we have duplicate fields.
+        // class Test {final x = 1; final x = 2; const Test();}
+        if (evaluationResult == null) {
+          continue;
+        }
+        // Match the value and the type.
         DartType fieldType =
             FieldMember.from(field, constructor.returnType).type;
         DartObjectImpl fieldValue = evaluationResult.value;
@@ -713,7 +720,7 @@
               node,
               [fieldValue.type, field.name, fieldType]);
         }
-        fieldMap[field.name] = evaluationResult.value;
+        fieldMap[field.name] = fieldValue;
       }
     }
     // Now evaluate the constructor declaration.
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index 7793d0d..334f4e8 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -9,12 +9,11 @@
 
 import 'package:analyzer/src/generated/utilities_general.dart';
 import 'package:analyzer/src/task/dart.dart';
-import 'package:analyzer/task/model.dart'
-    show AnalysisTarget, ConstantEvaluationTarget;
+import 'package:analyzer/task/model.dart' show AnalysisTarget;
 
 import 'ast.dart';
 import 'constant.dart' show DartObject, EvaluationResultImpl;
-import 'engine.dart' show AnalysisContext, AnalysisEngine, AnalysisException;
+import 'engine.dart' show AnalysisContext, AnalysisEngine;
 import 'html.dart' show XmlAttributeNode, XmlTagNode;
 import 'java_core.dart';
 import 'java_engine.dart';
@@ -4540,6 +4539,15 @@
  */
 abstract class FunctionType implements ParameterizedType {
   /**
+   * The type parameters of this generic function. For example `<T> T -> T`.
+   *
+   * These are distinct from the [typeParameters] list, which contains type
+   * parameters from surrounding contexts, and thus are free type variables from
+   * the perspective of this function type.
+   */
+  List<TypeParameterElement> get boundTypeParameters;
+
+  /**
    * Return a map from the names of named parameters to the types of the named
    * parameters of this type of function. The entries in the map will be
    * iterated in the same order as the order in which the named parameters were
@@ -4577,6 +4585,12 @@
   DartType get returnType;
 
   /**
+   * Return the type resulting from instantiating (replacing) the given
+   * [argumentTypes] for this function's bound type parameters.
+   */
+  FunctionType instantiate(List<DartType> argumentTypes);
+
+  /**
    * Return `true` if this type is a subtype of the given [type].
    *
    * A function type <i>(T<sub>1</sub>, &hellip;, T<sub>n</sub>) &rarr; T</i> is
@@ -4647,6 +4661,7 @@
    * this type's parameters. This is fully equivalent to
    * `substitute(argumentTypes, getTypeArguments())`.
    */
+  @deprecated // use instantiate
   FunctionType substitute3(List<DartType> argumentTypes);
 }
 
@@ -4844,7 +4859,17 @@
   /**
    * The list of [typeArguments].
    */
-  List<DartType> _typeArguments = DartType.EMPTY_LIST;
+  List<DartType> _typeArguments;
+
+  /**
+   * The list of [typeParameters].
+   */
+  List<TypeParameterElement> _typeParameters;
+
+  /**
+   * The list of [boundTypeParameters].
+   */
+  List<TypeParameterElement> _boundTypeParameters;
 
   /**
    * The set of typedefs which should not be expanded when exploring this type,
@@ -4859,7 +4884,7 @@
    */
   FunctionTypeImpl(ExecutableElement element,
       [List<FunctionTypeAliasElement> prunedTypedefs])
-      : this._(element, null, prunedTypedefs, null);
+      : this._(element, null, prunedTypedefs, null, null, null);
 
   /**
    * Initialize a newly created function type to be declared by the given
@@ -4882,29 +4907,51 @@
    */
   FunctionTypeImpl.forTypedef(FunctionTypeAliasElement element,
       [List<FunctionTypeAliasElement> prunedTypedefs])
-      : this._(element, element?.name, prunedTypedefs, null);
+      : this._(element, element?.name, prunedTypedefs, null, null, null);
 
   /**
    * Private constructor.
    */
-  FunctionTypeImpl._(Element element, String name, this.prunedTypedefs,
-      List<DartType> typeArguments)
+  FunctionTypeImpl._(
+      TypeParameterizedElement element,
+      String name,
+      this.prunedTypedefs,
+      List<DartType> typeArguments,
+      List<TypeParameterElement> typeParameters,
+      List<TypeParameterElement> boundTypeParameters)
       : super(element, name) {
-    if (typeArguments != null) {
-      _typeArguments = typeArguments;
-    } else {
-      List<TypeParameterElement> typeParameters = this.typeParameters;
+    _boundTypeParameters = boundTypeParameters ??
+        element?.typeParameters ??
+        TypeParameterElement.EMPTY_LIST;
+
+    if (typeParameters == null) {
+      // Combine the generic type variables from all enclosing contexts, except
+      // for this generic function's type variables. Those variables are
+      // tracked in [boundTypeParameters].
+      typeParameters = <TypeParameterElement>[];
+      Element e = element?.enclosingElement;
+      while (e != null) {
+        if (e is TypeParameterizedElement) {
+          typeParameters.addAll((e as TypeParameterizedElement).typeParameters);
+        }
+        e = e.enclosingElement;
+      }
+    }
+    _typeParameters = typeParameters;
+
+    if (typeArguments == null) {
       // TODO(jmesserly): reuse TypeParameterTypeImpl.getTypes once we can
       // make it generic, which will allow it to return List<DartType> instead
       // of List<TypeParameterType>.
       if (typeParameters.isEmpty) {
-        _typeArguments = DartType.EMPTY_LIST;
+        typeArguments = DartType.EMPTY_LIST;
       } else {
-        _typeArguments = new List<DartType>.from(
+        typeArguments = new List<DartType>.from(
             typeParameters.map((t) => t.type),
             growable: false);
       }
     }
+    _typeArguments = typeArguments;
   }
 
   /**
@@ -4932,6 +4979,9 @@
   }
 
   @override
+  List<TypeParameterElement> get boundTypeParameters => _boundTypeParameters;
+
+  @override
   String get displayName {
     String name = this.name;
     if (name == null || name.length == 0) {
@@ -5163,18 +5213,7 @@
   List<DartType> get typeArguments => _typeArguments;
 
   @override
-  List<TypeParameterElement> get typeParameters {
-    // Combine the generic type arguments from all enclosing contexts.
-    // For example, this could be a generic method in a class, or a local
-    // function within another function.
-    List<TypeParameterElement> typeParams = <TypeParameterElement>[];
-    for (Element e = element; e != null; e = e.enclosingElement) {
-      if (e is TypeParameterizedElement) {
-        typeParams.addAll(e.typeParameters);
-      }
-    }
-    return typeParams;
-  }
+  List<TypeParameterElement> get typeParameters => _typeParameters;
 
   @override
   bool operator ==(Object object) {
@@ -5182,6 +5221,24 @@
       return false;
     }
     FunctionTypeImpl otherType = object as FunctionTypeImpl;
+    if (boundTypeParameters.length != otherType.boundTypeParameters.length) {
+      return false;
+    }
+    // `<T>T -> T` should be equal to `<U>U -> U`
+    // To test this, we instantiate both types with the same (unique) type
+    // variables, and see if the result is equal.
+    if (boundTypeParameters.isNotEmpty) {
+      List<DartType> instantiateTypeArgs = new List<DartType>();
+      for (TypeParameterElement e in boundTypeParameters) {
+        instantiateTypeArgs.add(new TypeParameterTypeImpl(
+            new TypeParameterElementImpl(e.name, -1)));
+      }
+      // After instantiation, they will no longer have boundTypeParameters,
+      // so we will continue below.
+      return this.instantiate(instantiateTypeArgs) ==
+          otherType.instantiate(instantiateTypeArgs);
+    }
+
     return returnType == otherType.returnType &&
         TypeImpl.equalArrays(
             normalParameterTypes, otherType.normalParameterTypes) &&
@@ -5192,13 +5249,56 @@
 
   @override
   void appendTo(StringBuffer buffer) {
+    if (boundTypeParameters.isNotEmpty) {
+      // To print a type with type variables, first make sure we have unique
+      // variable names to print.
+      Set<TypeParameterType> freeVariables = new HashSet<TypeParameterType>();
+      _freeVariablesInFunctionType(this, freeVariables);
+
+      Set<String> namesToAvoid = new HashSet<String>();
+      for (DartType arg in freeVariables) {
+        if (arg is TypeParameterType) {
+          namesToAvoid.add(arg.displayName);
+        }
+      }
+
+      List<DartType> instantiateTypeArgs = new List<DartType>();
+      buffer.write("<");
+      for (TypeParameterElement e in boundTypeParameters) {
+        if (e != boundTypeParameters[0]) {
+          buffer.write(",");
+        }
+        String name = e.name;
+        int counter = 0;
+        while (!namesToAvoid.add(name)) {
+          // Unicode subscript-zero is U+2080, zero is U+0030. Other digits
+          // are sequential from there. Thus +0x2050 will get us the subscript.
+          String subscript = new String.fromCharCodes(
+              counter.toString().codeUnits.map((n) => n + 0x2050));
+
+          name = e.name + subscript;
+          counter++;
+        }
+        TypeParameterTypeImpl t =
+            new TypeParameterTypeImpl(new TypeParameterElementImpl(name, -1));
+        t.appendTo(buffer);
+        instantiateTypeArgs.add(t);
+      }
+      buffer.write(">");
+
+      // Instantiate it and print the resulting type. After instantiation, it
+      // will no longer have boundTypeParameters, so we will continue below.
+      this.instantiate(instantiateTypeArgs).appendTo(buffer);
+      return;
+    }
+
     List<DartType> normalParameterTypes = this.normalParameterTypes;
     List<DartType> optionalParameterTypes = this.optionalParameterTypes;
     Map<String, DartType> namedParameterTypes = this.namedParameterTypes;
     DartType returnType = this.returnType;
     buffer.write("(");
     bool needsComma = false;
-    if (normalParameterTypes.length > 0) {
+    if (normalParameterTypes.isNotEmpty) {
       for (DartType type in normalParameterTypes) {
         if (needsComma) {
           buffer.write(", ");
@@ -5208,7 +5308,7 @@
         (type as TypeImpl).appendTo(buffer);
       }
     }
-    if (optionalParameterTypes.length > 0) {
+    if (optionalParameterTypes.isNotEmpty) {
       if (needsComma) {
         buffer.write(", ");
         needsComma = false;
@@ -5225,7 +5325,7 @@
       buffer.write("]");
       needsComma = true;
     }
-    if (namedParameterTypes.length > 0) {
+    if (namedParameterTypes.isNotEmpty) {
       if (needsComma) {
         buffer.write(", ");
         needsComma = false;
@@ -5254,6 +5354,33 @@
   }
 
   @override
+  FunctionTypeImpl instantiate(List<DartType> argumentTypes) {
+    if (argumentTypes.length != boundTypeParameters.length) {
+      throw new IllegalArgumentException(
+          "argumentTypes.length (${argumentTypes.length}) != "
+          "boundTypeParameters.length (${boundTypeParameters.length})");
+    }
+    if (argumentTypes.isEmpty) {
+      return this;
+    }
+
+    // Given:
+    //     {U/T} <S> T -> S
+    // Where {U/T} represents the typeArguments (U) and typeParameters (T) list,
+    // and <S> represents the boundTypeParameters.
+    //
+    // Now instantiate([V]), and the result should be:
+    //     {U/T, V/S} T -> S.
+    List<TypeParameterElement> newTypeParams = typeParameters.toList();
+    List<DartType> newTypeArgs = typeArguments.toList();
+    newTypeParams.addAll(boundTypeParameters);
+    newTypeArgs.addAll(argumentTypes);
+
+    return new FunctionTypeImpl._(element, name, prunedTypedefs, newTypeArgs,
+        newTypeParams, TypeParameterElement.EMPTY_LIST);
+  }
+
+  @override
   bool isAssignableTo(DartType type) {
     // A function type T may be assigned to a function type S, written T <=> S,
     // iff T <: S.
@@ -5502,7 +5629,8 @@
       List<DartType> typeArgs = typeArguments
           .map((TypeImpl t) => t.pruned(prune))
           .toList(growable: false);
-      return new FunctionTypeImpl._(element, name, prune, typeArgs);
+      return new FunctionTypeImpl._(element, name, prune, typeArgs,
+          _typeParameters, _boundTypeParameters);
     }
   }
 
@@ -5528,13 +5656,51 @@
     }
     List<DartType> typeArgs =
         TypeImpl.substitute(typeArguments, argumentTypes, parameterTypes);
-    return new FunctionTypeImpl._(element, name, prune, typeArgs);
+    return new FunctionTypeImpl._(
+        element, name, prune, typeArgs, _typeParameters, _boundTypeParameters);
   }
 
   @override
   FunctionTypeImpl substitute3(List<DartType> argumentTypes) =>
       substitute2(argumentTypes, typeArguments);
 
+  void _freeVariablesInFunctionType(
+      FunctionType type, Set<TypeParameterType> free) {
+    // Make some fresh variables to avoid capture.
+    List<DartType> typeArgs = DartType.EMPTY_LIST;
+    if (type.boundTypeParameters.isNotEmpty) {
+      typeArgs = new List<DartType>.from(type.boundTypeParameters.map((e) =>
+          new TypeParameterTypeImpl(new TypeParameterElementImpl(e.name, -1))));
+
+      type = type.instantiate(typeArgs);
+    }
+
+    for (ParameterElement p in type.parameters) {
+      _freeVariablesInType(p.type, free);
+    }
+    _freeVariablesInType(type.returnType, free);
+
+    // Remove all of our bound variables.
+    free.removeAll(typeArgs);
+  }
+
+  void _freeVariablesInInterfaceType(
+      InterfaceType type, Set<TypeParameterType> free) {
+    for (DartType typeArg in type.typeArguments) {
+      _freeVariablesInType(typeArg, free);
+    }
+  }
+
+  void _freeVariablesInType(DartType type, Set<TypeParameterType> free) {
+    if (type is TypeParameterType) {
+      free.add(type);
+    } else if (type is FunctionType) {
+      _freeVariablesInFunctionType(type, free);
+    } else if (type is InterfaceType) {
+      _freeVariablesInInterfaceType(type, free);
+    }
+  }
+
   /**
    * Compute the least upper bound of types [f] and [g], both of which are
    * known to be function types.
@@ -6356,6 +6522,12 @@
   InterfaceType substitute2(
       List<DartType> argumentTypes, List<DartType> parameterTypes);
 
+  // TODO(jmesserly): introduce a new "instantiate" and deprecate this.
+  // The new "instantiate" should work similar to FunctionType.instantiate,
+  // which uses [boundTypeParameters] to model type parameters that haven't been
+  // filled in yet. Those are kept separate from already-substituted type
+  // parameters or free variables from the enclosing scopes, which allows nested
+  // generics to work, such as a generic method in a generic class.
   /**
    * Return the type resulting from substituting the given arguments for this
    * type's parameters. This is fully equivalent to `substitute2(argumentTypes,
@@ -7054,10 +7226,6 @@
   InterfaceTypeImpl substitute2(
       List<DartType> argumentTypes, List<DartType> parameterTypes,
       [List<FunctionTypeAliasElement> prune]) {
-    // Pruned types should only ever result from performing type variable
-    // substitution, and it doesn't make sense to substitute again after
-    // substituting once.
-    assert(this.prunedTypedefs == null);
     if (argumentTypes.length != parameterTypes.length) {
       throw new IllegalArgumentException(
           "argumentTypes.length (${argumentTypes.length}) != parameterTypes.length (${parameterTypes.length})");
@@ -9284,6 +9452,9 @@
   Element get enclosingElement => baseElement.enclosingElement;
 
   @override
+  int get hashCode => baseElement.hashCode;
+
+  @override
   bool get isInitializingFormal => baseElement.isInitializingFormal;
 
   @override
@@ -9312,6 +9483,10 @@
   SourceRange get visibleRange => baseElement.visibleRange;
 
   @override
+  bool operator ==(Object object) =>
+      object is ParameterMember && baseElement == object.baseElement;
+
+  @override
   accept(ElementVisitor visitor) => visitor.visitParameterElement(this);
 
   @override
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index a715f9a..8c981ff 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -622,13 +622,17 @@
       bool isConditional = node.operator.type == sc.TokenType.QUESTION_PERIOD;
       ClassElementImpl typeReference = getTypeReference(target);
       if (typeReference != null) {
-        staticElement =
-            propagatedElement = _resolveElement(typeReference, methodName);
+        staticElement = _resolveElement(typeReference, methodName);
       } else {
         staticElement = _resolveInvokedElementWithTarget(
             target, staticType, methodName, isConditional);
-        propagatedElement = _resolveInvokedElementWithTarget(
-            target, propagatedType, methodName, isConditional);
+        // If we have propagated type information use it (since it should
+        // not be redundant with the staticType).  Otherwise, don't produce
+        // a propagatedElement which duplicates the staticElement.
+        if (propagatedType is InterfaceType) {
+          propagatedElement = _resolveInvokedElementWithTarget(
+              target, propagatedType, methodName, isConditional);
+        }
       }
     }
     staticElement = _convertSetterToGetter(staticElement);
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 597d381..fbb9825 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -1160,9 +1160,6 @@
   AnalysisOptions get analysisOptions => _options;
 
   @override
-  EmbedderYamlLocator get embedderYamlLocator => _embedderYamlLocator;
-
-  @override
   void set analysisOptions(AnalysisOptions options) {
     bool needsRecompute = this._options.analyzeFunctionBodiesPredicate !=
             options.analyzeFunctionBodiesPredicate ||
@@ -1173,6 +1170,9 @@
         (this._options.hint && !options.hint) ||
         this._options.preserveComments != options.preserveComments ||
         this._options.strongMode != options.strongMode ||
+        ((options is AnalysisOptionsImpl)
+            ? this._options.strongModeHints != options.strongModeHints
+            : false) ||
         this._options.enableStrictCallChecks !=
             options.enableStrictCallChecks ||
         this._options.enableSuperMixins != options.enableSuperMixins;
@@ -1209,6 +1209,9 @@
     this._options.lint = options.lint;
     this._options.preserveComments = options.preserveComments;
     this._options.strongMode = options.strongMode;
+    if (options is AnalysisOptionsImpl) {
+      this._options.strongModeHints = options.strongModeHints;
+    }
     _generateImplicitErrors = options.generateImplicitErrors;
     _generateSdkErrors = options.generateSdkErrors;
     if (needsRecompute) {
@@ -1258,6 +1261,9 @@
   DeclaredVariables get declaredVariables => _declaredVariables;
 
   @override
+  EmbedderYamlLocator get embedderYamlLocator => _embedderYamlLocator;
+
+  @override
   List<AnalysisTarget> get explicitTargets {
     List<AnalysisTarget> targets = <AnalysisTarget>[];
     MapIterator<Source, SourceEntry> iterator = _cache.iterator();
@@ -6462,6 +6468,14 @@
   bool strongMode = false;
 
   /**
+   * A flag indicating whether strong-mode inference hints should be
+   * used.  This flag is not exposed in the interface, and should be
+   * replaced by something more general.
+   */
+  // TODO(leafp): replace this with something more general
+  bool strongModeHints = false;
+
+  /**
    * Initialize a newly created set of analysis options to have their default
    * values.
    */
@@ -6488,6 +6502,9 @@
     lint = options.lint;
     preserveComments = options.preserveComments;
     strongMode = options.strongMode;
+    if (options is AnalysisOptionsImpl) {
+      strongModeHints = options.strongModeHints;
+    }
   }
 
   /**
@@ -6510,6 +6527,9 @@
     lint = options.lint;
     preserveComments = options.preserveComments;
     strongMode = options.strongMode;
+    if (options is AnalysisOptionsImpl) {
+      strongModeHints = options.strongModeHints;
+    }
   }
 
   bool get analyzeFunctionBodies {
@@ -9420,6 +9440,9 @@
    */
   set contentCache(ContentCache value);
 
+  /// Get the [EmbedderYamlLocator] for this context.
+  EmbedderYamlLocator get embedderYamlLocator;
+
   /**
    * Return a list of the explicit targets being analyzed by this context.
    */
@@ -9449,9 +9472,6 @@
    */
   dynamic get privateAnalysisCachePartition;
 
-  /// Get the [EmbedderYamlLocator] for this context.
-  EmbedderYamlLocator get embedderYamlLocator;
-  
   /**
    * A factory to override how [ResolverVisitor] is created.
    */
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index c15f247..1192f2c 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -904,12 +904,14 @@
         isByTask(ComputeConstantDependenciesTask.DESCRIPTOR) ||
         isByTask(ComputeConstantValueTask.DESCRIPTOR) ||
         isByTask(ComputeLibraryCycleTask.DESCRIPTOR) ||
+        isByTask(ComputePropagableVariableDependenciesTask.DESCRIPTOR) ||
         isByTask(DartErrorsTask.DESCRIPTOR) ||
         isByTask(ReadyLibraryElement2Task.DESCRIPTOR) ||
         isByTask(ReadyLibraryElement5Task.DESCRIPTOR) ||
+        isByTask(ReadyLibraryElement6Task.DESCRIPTOR) ||
         isByTask(ReadyResolvedUnitTask.DESCRIPTOR) ||
-        isByTask(ReadyResolvedUnit9Task.DESCRIPTOR) ||
         isByTask(ReadyResolvedUnit10Task.DESCRIPTOR) ||
+        isByTask(ReadyResolvedUnit11Task.DESCRIPTOR) ||
         isByTask(EvaluateUnitConstantsTask.DESCRIPTOR) ||
         isByTask(GenerateHintsTask.DESCRIPTOR) ||
         isByTask(InferInstanceMembersInUnitTask.DESCRIPTOR) ||
@@ -918,6 +920,10 @@
         isByTask(LibraryUnitErrorsTask.DESCRIPTOR) ||
         isByTask(ParseDartTask.DESCRIPTOR) ||
         isByTask(PartiallyResolveUnitReferencesTask.DESCRIPTOR) ||
+        isByTask(PropagateVariableTypesInLibraryClosureTask.DESCRIPTOR) ||
+        isByTask(PropagateVariableTypesInLibraryTask.DESCRIPTOR) ||
+        isByTask(PropagateVariableTypesInUnitTask.DESCRIPTOR) ||
+        isByTask(PropagateVariableTypeTask.DESCRIPTOR) ||
         isByTask(ScanDartTask.DESCRIPTOR) ||
         isByTask(ResolveInstanceFieldsInUnitTask.DESCRIPTOR) ||
         isByTask(ResolveLibraryReferencesTask.DESCRIPTOR) ||
diff --git a/pkg/analyzer/lib/src/generated/java_engine.dart b/pkg/analyzer/lib/src/generated/java_engine.dart
index 8b10e71..affcf8d 100644
--- a/pkg/analyzer/lib/src/generated/java_engine.dart
+++ b/pkg/analyzer/lib/src/generated/java_engine.dart
@@ -97,7 +97,9 @@
       }
     } else {
       buffer.writeln(exception.toString());
-      buffer.writeln(stackTrace.toString());
+      if (stackTrace != null) {
+        buffer.writeln(stackTrace.toString());
+      }
     }
   }
 }
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 42872c1..2074525 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -5189,9 +5189,10 @@
       _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
       return null;
     } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
+      TypeName returnType = _parseOptionalTypeNameComment();
       _validateModifiersForTopLevelFunction(modifiers);
       return _parseFunctionDeclaration(
-          commentAndMetadata, modifiers.externalKeyword, null);
+          commentAndMetadata, modifiers.externalKeyword, returnType);
     } else if (_peek()
         .matchesAny([TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
       if (modifiers.constKeyword == null &&
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index ad1cd60..0d17e72 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -6,6 +6,8 @@
 
 import 'dart:collection';
 
+import '../task/strong/info.dart' show InferredType, StaticInfo;
+import '../task/strong/rules.dart' show TypeRules;
 import 'ast.dart';
 import 'constant.dart';
 import 'element.dart';
@@ -2152,13 +2154,18 @@
               _findIdentifier(_enclosingUnit.functions, functionName);
         }
       } else {
-        PropertyAccessorElement accessor =
-            _findIdentifier(_enclosingUnit.accessors, functionName);
-        if ((property as sc.KeywordToken).keyword == sc.Keyword.SET) {
-          accessor = accessor.variable.setter;
-          functionName.staticElement = accessor;
+        if (_enclosingExecutable != null) {
+          _enclosingExecutable =
+              _findIdentifier(_enclosingExecutable.functions, functionName);
+        } else {
+          PropertyAccessorElement accessor =
+              _findIdentifier(_enclosingUnit.accessors, functionName);
+          if ((property as sc.KeywordToken).keyword == sc.Keyword.SET) {
+            accessor = accessor.variable.setter;
+            functionName.staticElement = accessor;
+          }
+          _enclosingExecutable = accessor;
         }
-        _enclosingExecutable = accessor;
       }
       node.functionExpression.element = _enclosingExecutable;
       return super.visitFunctionDeclaration(node);
@@ -5755,6 +5762,232 @@
 }
 
 /**
+ * Maintains and manages contextual type information used for
+ * inferring types.
+ */
+class InferenceContext {
+  // TODO(leafp): Consider replacing these node properties with a
+  // hash table help in an instance of this class.
+  static const String _typeProperty =
+      'analyzer.src.generated.InferenceContext.contextType';
+
+  /**
+   * The error listener on which to record inference information.
+   */
+  final AnalysisErrorListener _errorListener;
+
+  /**
+   * If true, emit hints when types are inferred
+   */
+  final bool _inferenceHints;
+
+  /**
+   * Type provider, needed for type matching.
+   */
+  final TypeProvider _typeProvider;
+
+  /**
+   * The type system in use.
+   */
+  final TypeSystem _typeSystem;
+
+  /**
+   * The DDC type rules, used to create the inference info nodes.
+   */
+  final TypeRules _rules;
+
+  /**
+   * A stack of return types for all of the enclosing
+   * functions and methods.
+   */
+  List<DartType> _returnStack = <DartType>[];
+
+  InferenceContext._(this._errorListener, TypeProvider typeProvider,
+      this._typeSystem, this._inferenceHints)
+      : _typeProvider = typeProvider,
+        _rules = new TypeRules(typeProvider);
+
+  /**
+   * Get the return type of the current enclosing function, if any.
+   */
+  DartType get returnContext =>
+      (_returnStack.isNotEmpty) ? _returnStack.last : null;
+
+  /**
+   * Match type [t1] against type [t2] as follows.
+   * If `t1 = I<dynamic, ..., dynamic>`, then look for a supertype
+   * of t1 of the form `K<S0, ..., Sm>` where `t2 = K<S0', ..., Sm'>`
+   * If the supertype exists, use the constraints `S0 <: S0', ... Sm <: Sm'`
+   * to derive a concrete instantation for I of the form `<T0, ..., Tn>`,
+   * such that `I<T0, .., Tn> <: t2`
+   */
+  List<DartType> matchTypes(DartType t1, DartType t2) =>
+      (t1 is InterfaceType && t2 is InterfaceType) ? _matchTypes(t1, t2) : null;
+
+  /**
+   * Pop a return type off of the return stack.
+   */
+  void popReturnContext() {
+    assert(_returnStack.isNotEmpty);
+    if (_returnStack.isNotEmpty) {
+      _returnStack.removeLast();
+    }
+  }
+
+  /**
+   * Push a [returnType] onto the return stack.
+   */
+  void pushReturnContext(DartType returnType) {
+    _returnStack.add(returnType);
+  }
+
+  /**
+   * Place an info node into the error stream indicating that a
+   * [type] has been inferred as the type of [node].
+   */
+  void recordInference(Expression node, DartType type) {
+    StaticInfo info = InferredType.create(_rules, node, type);
+    if (!_inferenceHints || info == null) {
+      return;
+    }
+    AnalysisError error = info.toAnalysisError();
+    _errorListener.onError(error);
+  }
+
+  List<DartType> _matchTypes(InterfaceType t1, InterfaceType t2) {
+    if (t1 == t2) {
+      return t2.typeArguments;
+    }
+    List<DartType> tArgs1 = t1.typeArguments;
+    List<DartType> tArgs2 = t2.typeArguments;
+    // If t1 isn't a raw type, bail out
+    if (tArgs1 != null && tArgs1.any((t) => !t.isDynamic)) {
+      return null;
+    }
+
+    // This is our inferred type argument list.  We start at all dynamic,
+    // and fill in with inferred types when we reach a match.
+    List<DartType> actuals =
+        new List<DartType>.filled(tArgs1.length, _typeProvider.dynamicType);
+
+    // When we find the supertype of t1 with the same
+    // classname as t2 (see below), we have the following:
+    // If t1 is an instantiation of a class T1<X0, ..., Xn>
+    // and t2 is an instantiation of a class T2<Y0, ...., Ym>
+    // of the form t2 = T2<S0, ..., Sm>
+    // then we want to choose instantiations for the Xi
+    // T0, ..., Tn such that T1<T0, ..., Tn> <: t2 .
+    // To find this, we simply instantate T1 with
+    // X0, ..., Xn, and then find its superclass
+    // T2<T0', ..., Tn'>.  We then solve the constraint
+    // set T0' <: S0, ..., Tn' <: Sn for the Xi.
+    // Currently, we only handle constraints where
+    // the Ti' is one of the Xi'.  If there are multiple
+    // constraints on some Xi, we choose the lower of the
+    // two (if it exists).
+    bool permute(List<DartType> permutedArgs) {
+      if (permutedArgs == null) {
+        return false;
+      }
+      List<TypeParameterElement> ps = t1.typeParameters;
+      List<DartType> ts = ps.map((p) => p.type).toList();
+      for (int i = 0; i < permutedArgs.length; i++) {
+        DartType tVar = permutedArgs[i];
+        DartType tActual = tArgs2[i];
+        int index = ts.indexOf(tVar);
+        if (index >= 0 && _typeSystem.isSubtypeOf(tActual, actuals[index])) {
+          actuals[index] = tActual;
+        }
+      }
+      return actuals.any((x) => !x.isDynamic);
+    }
+
+    // Look for the first supertype of t1 with the same class name as t2.
+    bool match(InterfaceType t1, Set<Element> visited) {
+      if (t1.element == t2.element) {
+        return permute(t1.typeArguments);
+      }
+
+      if (t1 == _typeProvider.objectType) {
+        return false;
+      }
+
+      Element element = t1.element;
+      if (visited == null) {
+        visited = new HashSet<Element>();
+      }
+      if (element == null || !visited.add(element)) {
+        return false;
+      }
+      try {
+        if (match(t1.superclass, visited)) {
+          return true;
+        }
+
+        for (final parent in t1.mixins) {
+          if (match(parent, visited)) {
+            return true;
+          }
+        }
+
+        for (final parent in t1.interfaces) {
+          if (match(parent, visited)) {
+            return true;
+          }
+        }
+      } finally {
+        visited.remove(element);
+      }
+      return false;
+    }
+
+    // We have that t1 = T1<dynamic, ..., dynamic>.
+    // To match t1 against t2, we use the uninstantiated version
+    // of t1, essentially treating it as an instantiation with
+    // fresh variables, and solve for the variables.
+    // t1.element.type will be of the form T1<X0, ..., Xn>
+    if (!match(t1.element.type, null)) {
+      return null;
+    }
+    DartType newT1 = t1.element.type.substitute4(actuals);
+    // If we found a solution, return it.
+    if (_typeSystem.isSubtypeOf(newT1, t2)) {
+      return actuals;
+    }
+    return null;
+  }
+
+  /**
+   * Clear the type information assocated with [node].
+   */
+  static void clearType(AstNode node) {
+    node?.setProperty(_typeProperty, null);
+  }
+
+  /**
+   * Look for contextual type information attached to [node].  Returns
+   * the type if found, otherwise null.
+   */
+  static DartType getType(AstNode node) => node?.getProperty(_typeProperty);
+
+  /**
+   * Attach contextual type information [type] to [node] for use during
+   * inference.
+   */
+  static void setType(AstNode node, DartType type) {
+    node?.setProperty(_typeProperty, type);
+  }
+
+  /**
+   * Attach contextual type information [type] to [node] for use during
+   * inference.
+   */
+  static void setTypeFromNode(AstNode innerNode, AstNode outerNode) {
+    setType(innerNode, getType(outerNode));
+  }
+}
+
+/**
  * Instances of the class `InheritanceManager` manage the knowledge of where class members
  * (methods, getters & setters) are inherited from.
  */
@@ -9725,18 +9958,18 @@
  */
 class PartialResolverVisitor extends ResolverVisitor {
   /**
-   * A flag indicating whether the resolver is being run in strong mode.
-   */
-  final bool strongMode;
-
-  /**
    * The static variables and fields that have an initializer. These are the
    * variables that need to be re-resolved after static variables have their
    * types inferred. A subset of these variables are those whose types should
-   * be inferred. The list will be empty unless the resolver is being run in
-   * strong mode.
+   * be inferred.
    */
-  final List<VariableElement> variablesAndFields = <VariableElement>[];
+  final List<VariableElement> staticVariables = <VariableElement>[];
+
+  /**
+   * The static and instance variables and fields that have an initializer.
+   * These are the variables whose types might be propagated.
+   */
+  final List<VariableElement> propagableVariables = <VariableElement>[];
 
   /**
    * Initialize a newly created visitor to resolve the nodes in an AST node.
@@ -9760,8 +9993,7 @@
       {Scope nameScope,
       InheritanceManager inheritanceManager,
       StaticTypeAnalyzerFactory typeAnalyzerFactory})
-      : strongMode = definingLibrary.context.analysisOptions.strongMode,
-        super(definingLibrary, source, typeProvider, errorListener);
+      : super(definingLibrary, source, typeProvider, errorListener);
 
   @override
   Object visitBlockFunctionBody(BlockFunctionBody node) {
@@ -9781,8 +10013,9 @@
 
   @override
   Object visitFieldDeclaration(FieldDeclaration node) {
-    if (strongMode && node.isStatic) {
-      _addVariables(node.fields.variables);
+    _addPropagableVariables(node.fields.variables);
+    if (node.isStatic) {
+      _addStaticVariables(node.fields.variables);
     }
     return super.visitFieldDeclaration(node);
   }
@@ -9794,23 +10027,36 @@
 
   @override
   Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
-    if (strongMode) {
-      _addVariables(node.variables.variables);
-    }
+    _addPropagableVariables(node.variables.variables);
+    _addStaticVariables(node.variables.variables);
     return super.visitTopLevelVariableDeclaration(node);
   }
 
   /**
+   * Add all of the [variables] with initializers to [propagableVariables].
+   */
+  void _addPropagableVariables(List<VariableDeclaration> variables) {
+    for (VariableDeclaration variable in variables) {
+      if (variable.initializer != null) {
+        VariableElement element = variable.element;
+        if (element.isConst || element.isFinal) {
+          propagableVariables.add(element);
+        }
+      }
+    }
+  }
+
+  /**
    * Add all of the [variables] with initializers to the list of variables whose
    * type can be inferred. Technically, we only infer the types of variables
    * that do not have a static type, but all variables with initializers
    * potentially need to be re-resolved after inference because they might
    * refer to a field whose type was inferred.
    */
-  void _addVariables(NodeList<VariableDeclaration> variables) {
+  void _addStaticVariables(List<VariableDeclaration> variables) {
     for (VariableDeclaration variable in variables) {
       if (variable.initializer != null) {
-        variablesAndFields.add(variable.element);
+        staticVariables.add(variable.element);
       }
     }
   }
@@ -10372,8 +10618,8 @@
   StaticTypeAnalyzer typeAnalyzer;
 
   /*
-  * The type system in use during resolution.
-  */
+   * The type system in use during resolution.
+   */
   TypeSystem typeSystem;
 
   /**
@@ -10406,6 +10652,8 @@
    */
   Comment _commentBeforeFunction = null;
 
+  InferenceContext inferenceContext = null;
+
   /**
    * The object keeping track of which elements have had their types overridden.
    */
@@ -10457,6 +10705,13 @@
     }
     this.elementResolver = new ElementResolver(this);
     this.typeSystem = definingLibrary.context.typeSystem;
+    bool strongModeHints = false;
+    AnalysisOptions options = definingLibrary.context.analysisOptions;
+    if (options is AnalysisOptionsImpl) {
+      strongModeHints = options.strongModeHints;
+    }
+    this.inferenceContext = new InferenceContext._(
+        errorListener, typeProvider, typeSystem, strongModeHints);
     if (typeAnalyzerFactory == null) {
       this.typeAnalyzer = new StaticTypeAnalyzer(this);
     } else {
@@ -10729,11 +10984,65 @@
         identical(parent, _enclosingFunctionTypeAlias)) {
       return null;
     }
-    return super.visitAnnotation(node);
+    safelyVisit(node.name);
+    safelyVisit(node.constructorName);
+    Element element = node.element;
+    if (element is ExecutableElement) {
+      InferenceContext.setType(node.arguments, element.type);
+    }
+    safelyVisit(node.arguments);
+    node.accept(elementResolver);
+    node.accept(typeAnalyzer);
+    return null;
+  }
+
+  @override
+  Object visitArgumentList(ArgumentList node) {
+    DartType callerType = InferenceContext.getType(node);
+    if (callerType is FunctionType) {
+      Map<String, DartType> namedParameterTypes =
+          callerType.namedParameterTypes;
+      List<DartType> normalParameterTypes = callerType.normalParameterTypes;
+      List<DartType> optionalParameterTypes = callerType.optionalParameterTypes;
+      int normalCount = normalParameterTypes.length;
+      int optionalCount = optionalParameterTypes.length;
+
+      NodeList<Expression> arguments = node.arguments;
+      Iterable<Expression> positional =
+          arguments.takeWhile((l) => l is! NamedExpression);
+      Iterable<Expression> required = positional.take(normalCount);
+      Iterable<Expression> optional =
+          positional.skip(normalCount).take(optionalCount);
+      Iterable<Expression> named =
+          arguments.skipWhile((l) => l is! NamedExpression);
+
+      //TODO(leafp): Consider using the parameter elements here instead.
+      //TODO(leafp): Make sure that the parameter elements are getting
+      // setup correctly with inference.
+      int index = 0;
+      for (Expression argument in required) {
+        InferenceContext.setType(argument, normalParameterTypes[index++]);
+      }
+      index = 0;
+      for (Expression argument in optional) {
+        InferenceContext.setType(argument, optionalParameterTypes[index++]);
+      }
+
+      for (Expression argument in named) {
+        if (argument is NamedExpression) {
+          DartType type = namedParameterTypes[argument.name.label.name];
+          if (type != null) {
+            InferenceContext.setType(argument, type);
+          }
+        }
+      }
+    }
+    return super.visitArgumentList(node);
   }
 
   @override
   Object visitAsExpression(AsExpression node) {
+    InferenceContext.setType(node.expression, node.type.type);
     super.visitAsExpression(node);
     // Since an as-statement doesn't actually change the type, we don't
     // let it affect the propagated type when it would result in a loss
@@ -10750,6 +11059,33 @@
   }
 
   @override
+  Object visitAssignmentExpression(AssignmentExpression node) {
+    safelyVisit(node.leftHandSide);
+    sc.TokenType operator = node.operator.type;
+    if (operator == sc.TokenType.EQ ||
+        operator == sc.TokenType.QUESTION_QUESTION_EQ) {
+      InferenceContext.setType(
+          node.rightHandSide, node.leftHandSide.staticType);
+    }
+    safelyVisit(node.rightHandSide);
+    node.accept(elementResolver);
+    node.accept(typeAnalyzer);
+    return null;
+  }
+
+  @override
+  Object visitAwaitExpression(AwaitExpression node) {
+    //TODO(leafp): Handle the implicit union type here
+    DartType contextType = InferenceContext.getType(node);
+    if (contextType != null) {
+      InterfaceType futureT =
+          typeProvider.futureType.substitute4([contextType]);
+      InferenceContext.setType(node.expression, futureT);
+    }
+    return super.visitAwaitExpression(node);
+  }
+
+  @override
   Object visitBinaryExpression(BinaryExpression node) {
     sc.TokenType operatorType = node.operator.type;
     Expression leftOperand = node.leftOperand;
@@ -10789,6 +11125,8 @@
         }
       }
     } else {
+      // TODO(leafp): Do downwards inference using the declared type
+      // of the binary operator.
       safelyVisit(leftOperand);
       safelyVisit(rightOperand);
     }
@@ -10802,9 +11140,11 @@
     safelyVisit(_commentBeforeFunction);
     _overrideManager.enterScope();
     try {
+      inferenceContext.pushReturnContext(InferenceContext.getType(node));
       super.visitBlockFunctionBody(node);
     } finally {
       _overrideManager.exitScope();
+      inferenceContext.popReturnContext();
     }
     return null;
   }
@@ -10821,6 +11161,12 @@
   }
 
   @override
+  Object visitCascadeExpression(CascadeExpression node) {
+    InferenceContext.setTypeFromNode(node.target, node);
+    return super.visitCascadeExpression(node);
+  }
+
+  @override
   Object visitClassDeclaration(ClassDeclaration node) {
     //
     // Resolve the metadata in the library scope.
@@ -10953,6 +11299,7 @@
           _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated(
               thenExpression);
           // Visit "then" expression.
+          InferenceContext.setTypeFromNode(thenExpression, node);
           thenExpression.accept(this);
         } finally {
           _promoteManager.exitScope();
@@ -10966,6 +11313,7 @@
       _overrideManager.enterScope();
       try {
         _propagateFalseState(condition);
+        InferenceContext.setTypeFromNode(elseExpression, node);
         elseExpression.accept(this);
       } finally {
         _overrideManager.exitScope();
@@ -10990,6 +11338,8 @@
     ExecutableElement outerFunction = _enclosingFunction;
     try {
       _enclosingFunction = node.element;
+      FunctionType type = _enclosingFunction.type;
+      InferenceContext.setType(node.body, type.returnType);
       super.visitConstructorDeclaration(node);
     } finally {
       _enclosingFunction = outerFunction;
@@ -11006,6 +11356,8 @@
     // We visit the expression, but do not visit the field name because it needs
     // to be visited in the context of the constructor field initializer node.
     //
+    FieldElement fieldElement = enclosingClass.getField(node.fieldName.name);
+    InferenceContext.setType(node.expression, fieldElement?.type);
     safelyVisit(node.expression);
     node.accept(elementResolver);
     node.accept(typeAnalyzer);
@@ -11037,6 +11389,7 @@
 
   @override
   Object visitDefaultFormalParameter(DefaultFormalParameter node) {
+    InferenceContext.setType(node.defaultValue, node.parameter.element?.type);
     super.visitDefaultFormalParameter(node);
     ParameterElement element = node.element;
     if (element.initializer != null && node.defaultValue != null) {
@@ -11115,6 +11468,7 @@
     }
     _overrideManager.enterScope();
     try {
+      InferenceContext.setTypeFromNode(node.expression, node);
       super.visitExpressionFunctionBody(node);
     } finally {
       _overrideManager.exitScope();
@@ -11154,9 +11508,16 @@
     // cannot be in scope while visiting the iterator.
     //
     Expression iterable = node.iterable;
-    safelyVisit(iterable);
     DeclaredIdentifier loopVariable = node.loopVariable;
     SimpleIdentifier identifier = node.identifier;
+    if (loopVariable?.type?.type != null) {
+      InterfaceType targetType = (node.awaitKeyword == null)
+          ? typeProvider.iterableType
+          : typeProvider.streamType;
+      InferenceContext.setType(
+          iterable, targetType.substitute4([loopVariable.type.type]));
+    }
+    safelyVisit(iterable);
     safelyVisit(loopVariable);
     safelyVisit(identifier);
     Statement body = node.body;
@@ -11229,6 +11590,8 @@
     try {
       SimpleIdentifier functionName = node.name;
       _enclosingFunction = functionName.staticElement as ExecutableElement;
+      InferenceContext.setType(
+          node.functionExpression, _enclosingFunction.type);
       super.visitFunctionDeclaration(node);
     } finally {
       _enclosingFunction = outerFunction;
@@ -11243,6 +11606,11 @@
       _enclosingFunction = node.element;
       _overrideManager.enterScope();
       try {
+        DartType functionType = InferenceContext.getType(node);
+        if (functionType is FunctionType) {
+          _inferFormalParameterList(node.parameters, functionType);
+          InferenceContext.setType(node.body, functionType.returnType);
+        }
         super.visitFunctionExpression(node);
       } finally {
         _overrideManager.exitScope();
@@ -11258,6 +11626,7 @@
     safelyVisit(node.function);
     node.accept(elementResolver);
     _inferFunctionExpressionsParametersTypes(node.argumentList);
+    InferenceContext.setType(node.argumentList, node.function.staticType);
     safelyVisit(node.argumentList);
     node.accept(typeAnalyzer);
     return null;
@@ -11345,16 +11714,99 @@
   }
 
   @override
+  Object visitInstanceCreationExpression(InstanceCreationExpression node) {
+    TypeName classTypeName = node.constructorName.type;
+    if (classTypeName.typeArguments == null) {
+      DartType contextType = InferenceContext.getType(node);
+      if (contextType is InterfaceType &&
+          contextType.typeArguments != null &&
+          contextType.typeArguments.length > 0) {
+        List<DartType> targs =
+            inferenceContext.matchTypes(classTypeName.type, contextType);
+        if (targs != null && targs.any((t) => !t.isDynamic)) {
+          ClassElement classElement = classTypeName.type.element;
+          InterfaceType rawType = classElement.type;
+          InterfaceType fullType =
+              rawType.substitute2(targs, rawType.typeArguments);
+          // The element resolver uses the type on the constructor name, so
+          // infer it first
+          typeAnalyzer.inferConstructorName(node.constructorName, fullType);
+        }
+      }
+    }
+    safelyVisit(node.constructorName);
+    FunctionType constructorType = node.constructorName.staticElement?.type;
+    if (constructorType != null) {
+      InferenceContext.setType(node.argumentList, constructorType);
+    }
+    safelyVisit(node.argumentList);
+    node.accept(elementResolver);
+    node.accept(typeAnalyzer);
+    return null;
+  }
+
+  @override
   Object visitLabel(Label node) => null;
 
   @override
   Object visitLibraryIdentifier(LibraryIdentifier node) => null;
 
   @override
+  Object visitListLiteral(ListLiteral node) {
+    DartType contextType = InferenceContext.getType(node);
+    if (node.typeArguments == null && contextType is InterfaceType) {
+      InterfaceType listD =
+          typeProvider.listType.substitute4([typeProvider.dynamicType]);
+      List<DartType> targs = inferenceContext.matchTypes(listD, contextType);
+      if (targs != null &&
+          targs.length == 1 &&
+          targs.any((t) => !t.isDynamic)) {
+        DartType eType = targs[0];
+        InterfaceType listT = typeProvider.listType.substitute4([eType]);
+        for (Expression child in node.elements) {
+          InferenceContext.setType(child, eType);
+        }
+        InferenceContext.setType(node, listT);
+      } else {
+        InferenceContext.clearType(node);
+      }
+    }
+    super.visitListLiteral(node);
+    return null;
+  }
+
+  @override
+  Object visitMapLiteral(MapLiteral node) {
+    DartType contextType = InferenceContext.getType(node);
+    if (node.typeArguments == null && contextType is InterfaceType) {
+      InterfaceType mapD = typeProvider.mapType
+          .substitute4([typeProvider.dynamicType, typeProvider.dynamicType]);
+      List<DartType> targs = inferenceContext.matchTypes(mapD, contextType);
+      if (targs != null &&
+          targs.length == 2 &&
+          targs.any((t) => !t.isDynamic)) {
+        DartType kType = targs[0];
+        DartType vType = targs[1];
+        InterfaceType mapT = typeProvider.mapType.substitute4([kType, vType]);
+        for (MapLiteralEntry entry in node.entries) {
+          InferenceContext.setType(entry.key, kType);
+          InferenceContext.setType(entry.value, vType);
+        }
+        InferenceContext.setType(node, mapT);
+      } else {
+        InferenceContext.clearType(node);
+      }
+    }
+    super.visitMapLiteral(node);
+    return null;
+  }
+
+  @override
   Object visitMethodDeclaration(MethodDeclaration node) {
     ExecutableElement outerFunction = _enclosingFunction;
     try {
       _enclosingFunction = node.element;
+      InferenceContext.setType(node.body, node.element.type?.returnType);
       super.visitMethodDeclaration(node);
     } finally {
       _enclosingFunction = outerFunction;
@@ -11371,12 +11823,22 @@
     safelyVisit(node.target);
     node.accept(elementResolver);
     _inferFunctionExpressionsParametersTypes(node.argumentList);
+    Element methodElement = node.methodName.staticElement;
+    if (methodElement is ExecutableElement) {
+      InferenceContext.setType(node.argumentList, methodElement.type);
+    }
     safelyVisit(node.argumentList);
     node.accept(typeAnalyzer);
     return null;
   }
 
   @override
+  Object visitNamedExpression(NamedExpression node) {
+    InferenceContext.setType(node.expression, InferenceContext.getType(node));
+    return super.visitNamedExpression(node);
+  }
+
+  @override
   Object visitNode(AstNode node) {
     node.visitChildren(this);
     node.accept(elementResolver);
@@ -11385,6 +11847,12 @@
   }
 
   @override
+  Object visitParenthesizedExpression(ParenthesizedExpression node) {
+    InferenceContext.setType(node.expression, InferenceContext.getType(node));
+    return super.visitParenthesizedExpression(node);
+  }
+
+  @override
   Object visitPrefixedIdentifier(PrefixedIdentifier node) {
     //
     // We visit the prefix, but do not visit the identifier because it needs to
@@ -11416,6 +11884,7 @@
     // because it needs to be visited in the context of the constructor
     // invocation.
     //
+    InferenceContext.setType(node.argumentList, node.staticElement?.type);
     safelyVisit(node.argumentList);
     node.accept(elementResolver);
     node.accept(typeAnalyzer);
@@ -11423,6 +11892,12 @@
   }
 
   @override
+  Object visitReturnStatement(ReturnStatement node) {
+    InferenceContext.setType(node.expression, inferenceContext.returnContext);
+    return super.visitReturnStatement(node);
+  }
+
+  @override
   Object visitShowCombinator(ShowCombinator node) => null;
 
   @override
@@ -11432,6 +11907,7 @@
     // because it needs to be visited in the context of the constructor
     // invocation.
     //
+    InferenceContext.setType(node.argumentList, node.staticElement?.type);
     safelyVisit(node.argumentList);
     node.accept(elementResolver);
     node.accept(typeAnalyzer);
@@ -11479,6 +11955,7 @@
 
   @override
   Object visitVariableDeclaration(VariableDeclaration node) {
+    InferenceContext.setType(node.initializer, InferenceContext.getType(node));
     super.visitVariableDeclaration(node);
     VariableElement element = node.element;
     if (element.initializer != null && node.initializer != null) {
@@ -11500,6 +11977,13 @@
     return null;
   }
 
+  @override visitVariableDeclarationList(VariableDeclarationList node) {
+    for (VariableDeclaration decl in node.variables) {
+      InferenceContext.setType(decl, node.type?.type);
+    }
+    super.visitVariableDeclarationList(node);
+  }
+
   @override
   Object visitWhileStatement(WhileStatement node) {
     // Note: since we don't call the base class, we have to maintain
@@ -11529,6 +12013,32 @@
     return null;
   }
 
+  @override
+  Object visitYieldStatement(YieldStatement node) {
+    DartType returnType = inferenceContext.returnContext;
+    if (returnType != null && _enclosingFunction != null) {
+      // If we're not in a generator ([a]sync*, then we shouldn't have a yield.
+      // so don't infer
+      if (_enclosingFunction.isGenerator) {
+        // If this is a yield*, then we just propagate the return type downwards
+        DartType type = returnType;
+        // If this just a yield, then we need to get the element type
+        if (node.star == null) {
+          // If it's synchronous, we expect Iterable<T>, otherwise Stream<T>
+          InterfaceType wrapperD = _enclosingFunction.isSynchronous
+              ? typeProvider.iterableDynamicType
+              : typeProvider.streamDynamicType;
+          // Match the types to instantiate the type arguments if possible
+          List<DartType> targs =
+              inferenceContext.matchTypes(wrapperD, returnType);
+          type = (targs?.length == 1) ? targs[0] : null;
+        }
+        InferenceContext.setType(node.expression, type);
+      }
+    }
+    return super.visitYieldStatement(node);
+  }
+
   /**
    * Checks each promoted variable in the current scope for compliance with the following
    * specification statement:
@@ -11623,6 +12133,14 @@
     return null;
   }
 
+  void _inferFormalParameterList(FormalParameterList node, DartType type) {
+    if (typeAnalyzer.inferFormalParameterList(node, type)) {
+      // TODO(leafp): This gets dropped on the floor if we're in the field
+      // inference task.  We should probably keep these infos.
+      inferenceContext.recordInference(node.parent, type);
+    }
+  }
+
   /**
    * If given "mayBeClosure" is [FunctionExpression] without explicit parameters types and its
    * required type is [FunctionType], then infer parameters types from [FunctionType].
@@ -14439,7 +14957,7 @@
     if (argumentList != null) {
       NodeList<TypeName> arguments = argumentList.arguments;
       int argumentCount = arguments.length;
-      List<DartType> parameters = _getTypeArguments(type);
+      List<DartType> parameters = _getTypeParameters(type);
       int parameterCount = parameters.length;
       List<DartType> typeArguments = new List<DartType>(parameterCount);
       if (argumentCount == parameterCount) {
@@ -14458,21 +14976,13 @@
           typeArguments[i] = _dynamicType;
         }
       }
-      if (type is InterfaceTypeImpl) {
-        InterfaceTypeImpl interfaceType = type as InterfaceTypeImpl;
-        type = interfaceType.substitute4(typeArguments);
-      } else if (type is FunctionTypeImpl) {
-        FunctionTypeImpl functionType = type as FunctionTypeImpl;
-        type = functionType.substitute3(typeArguments);
-      } else {
-        // TODO(brianwilkerson) Report this internal error.
-      }
+      type = _instantiateType(type, typeArguments);
     } else {
       //
       // Check for the case where there are no type arguments given for a
       // parameterized type.
       //
-      List<DartType> parameters = _getTypeArguments(type);
+      List<DartType> parameters = _getTypeParameters(type);
       int parameterCount = parameters.length;
       if (parameterCount > 0) {
         DynamicTypeImpl dynamicType = DynamicTypeImpl.instance;
@@ -14480,7 +14990,7 @@
         for (int i = 0; i < parameterCount; i++) {
           arguments[i] = dynamicType;
         }
-        type = type.substitute2(arguments, parameters);
+        type = _instantiateType(type, arguments);
       }
     }
     typeName.staticType = type;
@@ -14665,11 +15175,11 @@
    * @param type the type whole type arguments are to be returned
    * @return the type arguments associated with the given type
    */
-  List<DartType> _getTypeArguments(DartType type) {
+  List<DartType> _getTypeParameters(DartType type) {
     if (type is InterfaceType) {
       return type.typeArguments;
     } else if (type is FunctionType) {
-      return type.typeArguments;
+      return TypeParameterTypeImpl.getTypes(type.boundTypeParameters);
     }
     return DartType.EMPTY_LIST;
   }
@@ -14708,6 +15218,17 @@
     return type;
   }
 
+  DartType _instantiateType(DartType type, List<DartType> typeArguments) {
+    if (type is InterfaceTypeImpl) {
+      return type.substitute4(typeArguments);
+    } else if (type is FunctionTypeImpl) {
+      return type.instantiate(typeArguments);
+    } else {
+      // TODO(brianwilkerson) Report this internal error.
+      return type;
+    }
+  }
+
   /**
    * Checks if the given type name is used as the type in an as expression.
    *
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 24fec62..79cd48f 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -208,17 +208,6 @@
     }
   }
 
-//  /**
-//   * Return the offset of the first character on the line with the given
-//   * [lineNumber].
-//   */
-//  int getLineOffset(int lineNumber) {
-//    if (lineNumber < 0 || lineNumber >= _lineStarts.length) {
-//      throw new ArgumentError('Invalid line number: $lineNumber');
-//    }
-//    return _lineStarts[lineNumber];
-//  }
-
   /**
    * Return the location information for the character at the given offset.
    *
@@ -258,6 +247,17 @@
 
     return new LineInfo_Location(min + 1, offset - _lineStarts[min] + 1);
   }
+
+  /**
+   * Return the offset of the first character on the line with the given
+   * [lineNumber].
+   */
+  int getOffsetOfLine(int lineNumber) {
+    if (lineNumber < 0 || lineNumber >= _lineStarts.length) {
+      throw new ArgumentError('Invalid line number: $lineNumber');
+    }
+    return _lineStarts[lineNumber];
+  }
 }
 
 /**
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 4343549..a746a1e 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -13,6 +13,7 @@
 import 'java_engine.dart';
 import 'resolver.dart';
 import 'scanner.dart' as sc;
+import 'utilities_dart.dart';
 
 /**
  * Instances of the class `StaticTypeAnalyzer` perform two type-related tasks. First, they
@@ -93,6 +94,83 @@
   }
 
   /**
+   * Given a constructor name [node] and a type [type], record an inferred type
+   * for the constructor if in strong mode. This is used to fill in any
+   * inferred type parameters found by the resolver.
+   */
+  void inferConstructorName(ConstructorName node, InterfaceType type) {
+    if (_strongMode) {
+      node.type.type = type;
+      _resolver.inferenceContext.recordInference(node.parent, type);
+    }
+    return;
+  }
+
+  /**
+   * Given a formal parameter list and a function type use the function type
+   * to infer types for any of the parameters which have implicit (missing)
+   * types.  Only infers types in strong mode.  Returns true if inference
+   * has occurred.
+   */
+  bool inferFormalParameterList(
+      FormalParameterList node, DartType functionType) {
+    bool inferred = false;
+    if (_strongMode && node != null && functionType is FunctionType) {
+      void inferType(ParameterElementImpl p, DartType inferredType) {
+        // Check that there is no declared type, and that we have not already
+        // inferred a type in some fashion.
+        if (p.hasImplicitType &&
+            (p.type == null || p.type.isDynamic) &&
+            !inferredType.isDynamic) {
+          p.type = inferredType;
+          inferred = true;
+        }
+      }
+
+      List<ParameterElement> parameters = node.parameterElements;
+
+      {
+        List<DartType> normalParameterTypes = functionType.normalParameterTypes;
+        int normalCount = normalParameterTypes.length;
+        Iterable<ParameterElement> required = parameters
+            .where((p) => p.parameterKind == ParameterKind.REQUIRED)
+            .take(normalCount);
+        int index = 0;
+        for (ParameterElementImpl p in required) {
+          inferType(p, normalParameterTypes[index++]);
+        }
+      }
+
+      {
+        List<DartType> optionalParameterTypes =
+            functionType.optionalParameterTypes;
+        int optionalCount = optionalParameterTypes.length;
+        Iterable<ParameterElement> optional = parameters
+            .where((p) => p.parameterKind == ParameterKind.POSITIONAL)
+            .take(optionalCount);
+        int index = 0;
+        for (ParameterElementImpl p in optional) {
+          inferType(p, optionalParameterTypes[index++]);
+        }
+      }
+
+      {
+        Map<String, DartType> namedParameterTypes =
+            functionType.namedParameterTypes;
+        Iterable<ParameterElement> named =
+            parameters.where((p) => p.parameterKind == ParameterKind.NAMED);
+        for (ParameterElementImpl p in named) {
+          if (!namedParameterTypes.containsKey(p.name)) {
+            continue;
+          }
+          inferType(p, namedParameterTypes[p.name]);
+        }
+      }
+    }
+    return inferred;
+  }
+
+  /**
    * The Dart Language Specification, 12.5: <blockquote>The static type of a string literal is
    * `String`.</blockquote>
    */
@@ -381,8 +459,19 @@
     }
     ExecutableElementImpl functionElement =
         node.element as ExecutableElementImpl;
-    functionElement.returnType =
-        _computeStaticReturnTypeOfFunctionExpression(node);
+    DartType computedType = _computeStaticReturnTypeOfFunctionExpression(node);
+    if (_strongMode) {
+      DartType functionType = InferenceContext.getType(node);
+      if (functionType is FunctionType) {
+        DartType returnType = functionType.returnType;
+        if ((computedType.isDynamic || computedType.isBottom) &&
+            !(returnType.isDynamic || returnType.isBottom)) {
+          computedType = returnType;
+          _resolver.inferenceContext.recordInference(node, functionType);
+        }
+      }
+    }
+    functionElement.returnType = computedType;
     _recordPropagatedTypeOfFunction(functionElement, node.body);
     _recordStaticType(node, node.element.type);
     return null;
@@ -522,6 +611,15 @@
           staticType = argumentType;
         }
       }
+    } else {
+      DartType contextType = InferenceContext.getType(node);
+      if (_strongMode &&
+          contextType is InterfaceType &&
+          contextType.typeArguments.length == 1 &&
+          contextType.element == _typeProvider.listType.element) {
+        staticType = contextType.typeArguments[0];
+        _resolver.inferenceContext.recordInference(node, contextType);
+      }
     }
     _recordStaticType(
         node, _typeProvider.listType.substitute4(<DartType>[staticType]));
@@ -559,6 +657,16 @@
           staticValueType = entryValueType;
         }
       }
+    } else {
+      DartType contextType = InferenceContext.getType(node);
+      if (_strongMode &&
+          contextType is InterfaceType &&
+          contextType.typeArguments.length == 2 &&
+          contextType.element == _typeProvider.mapType.element) {
+        staticKeyType = contextType.typeArguments[0] ?? staticKeyType;
+        staticValueType = contextType.typeArguments[1] ?? staticValueType;
+        _resolver.inferenceContext.recordInference(node, contextType);
+      }
     }
     _recordStaticType(
         node,
@@ -1679,6 +1787,25 @@
   }
 
   /**
+   * Given a local variable declaration and its initializer, attempt to infer
+   * a type for the local variable declaration based on the initializer.
+   * Inference is only done if an explicit type is not present, and if
+   * inferring a type improves the type.
+   */
+  void _inferLocalVariableType(
+      VariableDeclaration node, Expression initializer) {
+    if (initializer != null &&
+        (node.parent as VariableDeclarationList).type == null &&
+        (node.element is LocalVariableElementImpl) &&
+        (initializer.staticType != null) &&
+        (!initializer.staticType.isBottom)) {
+      LocalVariableElementImpl element = node.element;
+      element.type = initializer.staticType;
+      node.name.staticType = initializer.staticType;
+    }
+  }
+
+  /**
    * Given a method invocation [node], attempt to infer a better
    * type for the result.
    */
@@ -1689,17 +1816,44 @@
   }
 
   /**
-   * Given a method invocation [node], attempt to infer a better
-   * type for the result using an ad-hoc list of psuedo-generic methods.
+   * Given a generic method invocation [node], attempt to infer the method's
+   * type variables, using the actual types of the arguments.
    */
   bool _inferMethodInvocationGeneric(MethodInvocation node) {
-    DartType inferredType = _matchGeneric(node);
-    // TODO(vsm): If the inferred type is not a subtype,
-    // should we use a GLB instead?
-    if (inferredType != null &&
-        _typeSystem.isSubtypeOf(inferredType, node.staticType)) {
-      _recordStaticType(node, inferredType);
-      return true;
+    Element element = node.methodName.staticElement;
+    DartType fnType = node.methodName.staticType;
+    TypeSystem ts = _typeSystem;
+    // TODO(jmesserly): once we allow explicitly passed typeArguments, we need
+    // to only do this if node.typeArguments == null.
+    if (element is ExecutableElement &&
+        fnType is FunctionTypeImpl &&
+        ts is StrongTypeSystemImpl) {
+      // We may have too many (or too few) arguments.  Only use arguments
+      // which have been matched up with a static parameter.
+      Iterable<Expression> arguments = node.argumentList.arguments
+          .where((e) => e.staticParameterElement != null);
+      List<DartType> argTypes = arguments.map((e) => e.staticType).toList();
+      List<DartType> paramTypes =
+          arguments.map((e) => e.staticParameterElement.type).toList();
+
+      FunctionType inferred = ts.inferCallFromArguments(
+          _typeProvider, fnType, paramTypes, argTypes);
+      if (inferred != fnType) {
+        // TODO(jmesserly): inference should be happening earlier, which would
+        // allow these parameters to be correct from the get-go.
+
+        List<ParameterElement> inferredParameters = inferred.parameters;
+        List<ParameterElement> correspondingParams =
+            new List<ParameterElement>();
+        for (Expression arg in arguments) {
+          int i = element.parameters.indexOf(arg.staticParameterElement);
+          correspondingParams.add(inferredParameters[i]);
+        }
+        node.argumentList.correspondingStaticParameters = correspondingParams;
+        _recordStaticType(node.methodName, inferred);
+        _recordStaticType(node, inferred.returnType);
+        return true;
+      }
     }
     return false;
   }
@@ -1766,25 +1920,6 @@
   }
 
   /**
-   * Given a local variable declaration and its initializer, attempt to infer
-   * a type for the local variable declaration based on the initializer.
-   * Inference is only done if an explicit type is not present, and if
-   * inferring a type improves the type.
-   */
-  void _inferLocalVariableType(
-      VariableDeclaration node, Expression initializer) {
-    if (initializer != null &&
-        (node.parent as VariableDeclarationList).type == null &&
-        (node.element is LocalVariableElementImpl) &&
-        (initializer.staticType != null) &&
-        (!initializer.staticType.isBottom)) {
-      LocalVariableElementImpl element = node.element;
-      element.type = initializer.staticType;
-      node.name.staticType = initializer.staticType;
-    }
-  }
-
-  /**
    * Given a property access [node] with static type [nodeType],
    * and [id] is the property name being accessed, infer a type for the
    * access itself and its constituent components if the access is to one of the
@@ -1862,91 +1997,6 @@
   }
 
   /**
-   * Return a more specialized type for a method invocation based on
-   * an ad-hoc list of pseudo-generic methods.
-   */
-  DartType _matchGeneric(MethodInvocation node) {
-    Element e = node.methodName.staticElement;
-
-    if (e == null || e.name == null) {
-      return null;
-    }
-
-    List<DartType> arguments =
-        node.argumentList.arguments.map((arg) => arg.staticType).toList();
-
-    bool matchInvocation(DartType t, int c) {
-      return (node.realTarget != null) &&
-          node.realTarget.staticType.isSubtypeOf(t) &&
-          arguments.length == c;
-    }
-
-    switch (e.name) {
-      case 'max':
-      case 'min':
-        if (e.library.source.uri.toString() == 'dart:math' &&
-            arguments.length == 2) {
-          DartType tx = arguments[0];
-          DartType ty = arguments[1];
-          if (tx == ty &&
-              (tx == _typeProvider.intType || tx == _typeProvider.doubleType)) {
-            return tx;
-          }
-        }
-        return null;
-      case 'wait':
-        if (matchInvocation(_typeProvider.futureType, 1)) {
-          DartType tx = arguments[0];
-          // Iterable<Future<T>> -> Future<List<T>>
-          DartType futureType =
-              _findIteratedType(tx, _typeProvider.iterableType);
-          if (futureType.element != _typeProvider.futureType.element) {
-            return null;
-          }
-          List<DartType> typeArguments =
-              (futureType as InterfaceType).typeArguments;
-          if (typeArguments.length != 1) {
-            return null;
-          }
-          DartType baseType = typeArguments[0];
-          if (baseType.isDynamic) {
-            return null;
-          }
-          return _typeProvider.futureType.substitute4([
-            _typeProvider.listType.substitute4([baseType])
-          ]);
-        }
-        return null;
-      case 'map':
-        if (matchInvocation(_typeProvider.iterableDynamicType, 1)) {
-          DartType tx = arguments[0];
-          return (tx is FunctionType)
-              ? _typeProvider.iterableType.substitute4([tx.returnType])
-              : null;
-        }
-        return null;
-      case 'fold':
-        if (matchInvocation(_typeProvider.iterableDynamicType, 2)) {
-          DartType tx = arguments[0];
-          DartType ty = arguments[1];
-          // TODO(vsm): LUB?
-          return (ty is FunctionType && tx == ty.returnType) ? tx : null;
-        }
-        return null;
-      case 'then':
-        if (matchInvocation(_typeProvider.futureDynamicType, 1)) {
-          DartType tx = arguments[0];
-          return (tx is FunctionType)
-              ? _typeProvider.futureType.substitute4([tx.returnType])
-              : null;
-        }
-        return null;
-      default:
-        return null;
-    }
-  }
-
-  /**
    * Record that the propagated type of the given node is the given type.
    *
    * @param expression the node whose type is to be recorded
diff --git a/pkg/analyzer/lib/src/generated/testing/element_factory.dart b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
index dff33e9..4414103 100644
--- a/pkg/analyzer/lib/src/generated/testing/element_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
@@ -49,19 +49,10 @@
     if (parameterNames != null) {
       int count = parameterNames.length;
       if (count > 0) {
-        List<TypeParameterElementImpl> typeParameters =
-            new List<TypeParameterElementImpl>(count);
-        List<TypeParameterTypeImpl> typeParameterTypes =
-            new List<TypeParameterTypeImpl>(count);
-        for (int i = 0; i < count; i++) {
-          TypeParameterElementImpl typeParameter =
-              typeParameterElement(parameterNames[i]);
-          typeParameters[i] = typeParameter;
-          typeParameterTypes[i] = new TypeParameterTypeImpl(typeParameter);
-          typeParameter.type = typeParameterTypes[i];
-        }
-        element.typeParameters = typeParameters;
-        type.typeArguments = typeParameterTypes;
+        element.typeParameters = typeParameters(parameterNames);
+        type.typeArguments = new List<DartType>.from(
+            element.typeParameters.map((p) => p.type),
+            growable: false);
       }
     }
     return element;
@@ -243,12 +234,12 @@
       functionElement4(functionName, null, null, null, null);
 
   static FunctionElementImpl functionElement2(
-          String functionName, ClassElement returnElement) =>
+          String functionName, TypeDefiningElement returnElement) =>
       functionElement3(functionName, returnElement, null, null);
 
   static FunctionElementImpl functionElement3(
       String functionName,
-      ClassElement returnElement,
+      TypeDefiningElement returnElement,
       List<TypeDefiningElement> normalParameters,
       List<TypeDefiningElement> optionalParameters) {
     // We don't create parameter elements because we don't have parameter names
@@ -611,4 +602,25 @@
     element.type = new TypeParameterTypeImpl(element);
     return element;
   }
+
+  static List<TypeParameterElement> typeParameters(List<String> names) {
+    int count = names.length;
+    if (count == 0) {
+      return TypeParameterElement.EMPTY_LIST;
+    }
+    List<TypeParameterElementImpl> typeParameters =
+        new List<TypeParameterElementImpl>(count);
+    for (int i = 0; i < count; i++) {
+      typeParameters[i] = typeParameterWithType(names[i]);
+    }
+    return typeParameters;
+  }
+
+  static TypeParameterElementImpl typeParameterWithType(String name,
+      [DartType bound]) {
+    TypeParameterElementImpl typeParameter = typeParameterElement(name);
+    typeParameter.type = new TypeParameterTypeImpl(typeParameter);
+    typeParameter.bound = bound;
+    return typeParameter;
+  }
 }
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index ef6bbfb..f731360 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -11,10 +11,8 @@
 import 'resolver.dart' show TypeProvider;
 
 typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited);
-
 typedef bool _SubtypeChecker<T>(T t1, T t2);
 
-
 /**
  * Implementation of [TypeSystem] using the strong mode rules.
  * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md
@@ -31,6 +29,105 @@
     return _specTypeSystem.getLeastUpperBound(typeProvider, type1, type2);
   }
 
+  /// Given a function type with generic type parameters, infer the type
+  /// parameters from the actual argument types, and return it. If we can't.
+  /// returns the original function type.
+  ///
+  /// Concretely, given a function type with parameter types P0, P1, ... Pn,
+  /// result type R, and generic type parameters T0, T1, ... Tm, use the
+  /// argument types A0, A1, ... An to solve for the type parameters.
+  ///
+  /// For each parameter Pi, we want to ensure that Ai <: Pi. We can do this by
+  /// running the subtype algorithm, and when we reach a type parameter Pj,
+  /// recording the lower or upper bound it must satisfy. At the end, all
+  /// constraints can be combined to determine the type.
+  ///
+  /// As a simplification, we do not actually store all constraints on each type
+  /// parameter Pj. Instead we track Uj and Lj where U is the upper bound and
+  /// L is the lower bound of that type parameter.
+  FunctionType inferCallFromArguments(
+      TypeProvider typeProvider,
+      FunctionTypeImpl fnType,
+      List<DartType> correspondingParameterTypes,
+      List<DartType> argumentTypes) {
+    if (fnType.boundTypeParameters.isEmpty) {
+      return fnType;
+    }
+
+    List<TypeParameterType> fnTypeParams =
+        TypeParameterTypeImpl.getTypes(fnType.boundTypeParameters);
+
+    // Create a TypeSystem that will allow certain type parameters to be
+    // inferred. It will optimistically assume these type parameters can be
+    // subtypes (or supertypes) as necessary, and track the constraints that
+    // are implied by this.
+    var inferringTypeSystem =
+        new _StrongInferenceTypeSystem(typeProvider, fnTypeParams);
+
+    for (int i = 0; i < argumentTypes.length; i++) {
+      // Try to pass each argument to each parameter, recording any type
+      // parameter bounds that were implied by this assignment.
+      inferringTypeSystem.isSubtypeOf(
+          argumentTypes[i], correspondingParameterTypes[i]);
+    }
+
+    var inferredTypes = new List<DartType>.from(fnTypeParams, growable: false);
+    for (int i = 0; i < fnTypeParams.length; i++) {
+      TypeParameterType typeParam = fnTypeParams[i];
+      _TypeParameterBound bound = inferringTypeSystem._bounds[typeParam];
+
+      // Now we've computed lower and upper bounds for each type parameter.
+      //
+      // To decide on which type to assign, we look at the return type and see
+      // if the type parameter occurs in covariant or contravariant positions.
+      //
+      // If the type is "passed in" at all, or if our lower bound was bottom,
+      // we choose the upper bound as being the most useful.
+      //
+      // Otherwise we choose the more precise lower bound.
+      _TypeParameterVariance variance =
+          new _TypeParameterVariance.from(typeParam, fnType.returnType);
+
+      inferredTypes[i] =
+          variance.passedIn || bound.lower.isBottom ? bound.upper : bound.lower;
+
+      // Assumption: if the current type parameter has an "extends" clause
+      // that refers to another type variable we are inferring, it will appear
+      // before us or in this list position. For example:
+      //
+      //     <TFrom, TTo extends TFrom>
+      //
+      // We may infer TTo is TFrom. In that case, we already know what TFrom
+      // is inferred as, so we can substitute it now. This also handles more
+      // complex cases such as:
+      //
+      //     <TFrom, TTo extends Iterable<TFrom>>
+      //
+      // Or if the type parameter's bound depends on itself such as:
+      //
+      //     <T extends Clonable<T>>
+      inferredTypes[i] =
+          inferredTypes[i].substitute2(inferredTypes, fnTypeParams);
+
+      // See if this actually worked.
+      // If not, fall back to the known upper bound (if any) or `dynamic`.
+      if (inferredTypes[i].isBottom ||
+          !isSubtypeOf(inferredTypes[i],
+              bound.upper.substitute2(inferredTypes, fnTypeParams)) ||
+          !isSubtypeOf(bound.lower.substitute2(inferredTypes, fnTypeParams),
+              inferredTypes[i])) {
+        inferredTypes[i] = DynamicTypeImpl.instance;
+        if (typeParam.element.bound != null) {
+          inferredTypes[i] =
+              typeParam.element.bound.substitute2(inferredTypes, fnTypeParams);
+        }
+      }
+    }
+
+    // Return the instantiated type.
+    return fnType.instantiate(inferredTypes);
+  }
+
   // TODO(leafp): Document the rules in play here
   @override
   bool isAssignableTo(DartType fromType, DartType toType) {
@@ -68,6 +165,9 @@
     return _isSubtypeOf(leftType, rightType, null);
   }
 
+  // Given a type t, if t is an interface type with a call method
+  // defined, return the function type for the call method, otherwise
+  // return null.
   FunctionType _getCallMethodType(DartType t) {
     if (t is InterfaceType) {
       return t.lookUpInheritedMethod("call")?.type;
@@ -75,9 +175,6 @@
     return null;
   }
 
-  // Given a type t, if t is an interface type with a call method
-  // defined, return the function type for the call method, otherwise
-  // return null.
   _GuardedSubtypeChecker<DartType> _guard(
       _GuardedSubtypeChecker<DartType> check) {
     return (DartType t1, DartType t2, Set<Element> visited) {
@@ -96,6 +193,14 @@
     };
   }
 
+  /// If [t1] or [t2] is a type parameter we are inferring, update its bound.
+  /// Returns `true` if we could possibly find a compatible type,
+  /// otherwise `false`.
+  bool _inferTypeParameterSubtypeOf(
+      DartType t1, DartType t2, Set<Element> visited) {
+    return false;
+  }
+
   bool _isBottom(DartType t, {bool dynamicIsBottom: false}) {
     return (t.isDynamic && dynamicIsBottom) || t.isBottom;
   }
@@ -245,6 +350,8 @@
       {bool dynamicIsBottom: false}) {
     // Guard recursive calls
     _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf);
+    _GuardedSubtypeChecker<DartType> guardedInferTypeParameter =
+        _guard(_inferTypeParameterSubtypeOf);
 
     if (t1 == t2) {
       return true;
@@ -263,7 +370,7 @@
     // Trivially false.
     if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) ||
         _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) {
-      return false;
+      return guardedInferTypeParameter(t1, t2, visited);
     }
 
     // S <: T where S is a type variable
@@ -272,13 +379,15 @@
     //  So only true if bound of S is S' and
     //  S' <: T
     if (t1 is TypeParameterType) {
+      if (guardedInferTypeParameter(t1, t2, visited)) {
+        return true;
+      }
       DartType bound = t1.element.bound;
-      if (bound == null) return false;
-      return guardedSubtype(bound, t2, visited);
+      return bound == null ? false : guardedSubtype(bound, t2, visited);
     }
 
     if (t2 is TypeParameterType) {
-      return false;
+      return guardedInferTypeParameter(t1, t2, visited);
     }
 
     if (t1.isVoid || t2.isVoid) {
@@ -316,7 +425,6 @@
   }
 }
 
-
 /**
  * The interface `TypeSystem` defines the behavior of an object representing
  * the type system.  This provides a common location to put methods that act on
@@ -449,3 +557,161 @@
     return leftType.isSubtypeOf(rightType);
   }
 }
+
+/// Tracks upper and lower type bounds for a set of type parameters.
+class _StrongInferenceTypeSystem extends StrongTypeSystemImpl {
+  final TypeProvider _typeProvider;
+  final Map<TypeParameterType, _TypeParameterBound> _bounds;
+
+  _StrongInferenceTypeSystem(
+      this._typeProvider, Iterable<TypeParameterType> typeParams)
+      : _bounds = new Map.fromIterable(typeParams, value: (t) {
+          _TypeParameterBound bound = new _TypeParameterBound();
+          if (t.element.bound != null) bound.upper = t.element.bound;
+          return bound;
+        });
+
+  @override
+  bool _inferTypeParameterSubtypeOf(
+      DartType t1, DartType t2, Set<Element> visited) {
+    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;
+        }
+        // Optimistically assume we will be able to satisfy the constraint.
+        return true;
+      }
+    }
+    if (t2 is TypeParameterType) {
+      _TypeParameterBound bound = _bounds[t2];
+      if (bound != null) {
+        bound.lower = getLeastUpperBound(_typeProvider, bound.lower, t1);
+        // Optimistically assume we will be able to satisfy the constraint.
+        return true;
+      }
+    }
+    return false;
+  }
+}
+
+/// An [upper] and [lower] bound for a type variable.
+class _TypeParameterBound {
+  /// The upper bound of the type parameter. In other words, T <: upperBound.
+  ///
+  /// In Dart this can be written as `<T extends UpperBoundType>`.
+  ///
+  /// In inference, this can happen as a result of parameters of function type.
+  /// For example, consider a signature like:
+  ///
+  ///     T reduce<T>(List<T> values, T f(T x, T y));
+  ///
+  /// and a call to it like:
+  ///
+  ///     reduce(values, (num x, num y) => ...);
+  ///
+  /// From the function expression's parameters, we conclude `T <: num`. We may
+  /// still be able to conclude a different [lower] based on `values` or
+  /// the type of the elided `=> ...` body. For example:
+  ///
+  ///      reduce(['x'], (num x, num y) => 'hi');
+  ///
+  /// Here the [lower] will be `String` and the upper bound will be `num`,
+  /// which cannot be satisfied, so this is ill typed.
+  DartType upper = DynamicTypeImpl.instance;
+
+  /// The lower bound of the type parameter. In other words, lowerBound <: T.
+  ///
+  /// This kind of constraint cannot be expressed in Dart, but it applies when
+  /// we're doing inference. For example, consider a signature like:
+  ///
+  ///     T pickAtRandom<T>(T x, T y);
+  ///
+  /// and a call to it like:
+  ///
+  ///     pickAtRandom(1, 2.0)
+  ///
+  /// when we see the first parameter is an `int`, we know that `int <: T`.
+  /// When we see `double` this implies `double <: T`.
+  /// Combining these constraints results in a lower bound of `num`.
+  ///
+  /// In general, we choose the lower bound as our inferred type, so we can
+  /// offer the most constrained (strongest) result type.
+  DartType lower = BottomTypeImpl.instance;
+}
+
+/// Records what positions a type parameter is used in.
+class _TypeParameterVariance {
+  /// The type parameter is a value passed out. It must satisfy T <: S,
+  /// where T is the type parameter and S is what it's assigned to.
+  ///
+  /// For example, this could be the return type, or a parameter to a parameter:
+  ///
+  ///     TOut method<TOut>(void f(TOut t));
+  bool passedOut = false;
+
+  /// The type parameter is a value passed in. It must satisfy S <: T,
+  /// where T is the type parameter and S is what's being assigned to it.
+  ///
+  /// For example, this could be a parameter type, or the parameter of the
+  /// return value:
+  ///
+  ///     typedef void Func<T>(T t);
+  ///     Func<TIn> method<TIn>(TIn t);
+  bool passedIn = false;
+
+  _TypeParameterVariance.from(TypeParameterType typeParam, DartType type) {
+    _visitType(typeParam, type, false);
+  }
+
+  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
+      // "passed out" of F into L. Thus we invert the "passedIn" state.
+      _visitType(typeParam, p.type, !paramIn);
+    }
+    // If a lambda L is passed in to a function F, and we call L, the result of
+    // L is then "passed in" to F. So we keep the "passedIn" state.
+    _visitType(typeParam, type.returnType, paramIn);
+  }
+
+  void _visitInterfaceType(
+      TypeParameterType typeParam, InterfaceType type, bool paramIn) {
+    // Currently in "strong mode" generic type parameters are covariant.
+    //
+    // This means we treat them as "out" type parameters similar to the result
+    // of a function, and thus they follow the same rules.
+    //
+    // For example, we pass in Iterable<T> as a parameter. Then we iterate over
+    // it. The "T" is essentially an input. So it keeps the same state.
+    // Similarly, if we return an Iterable<T> it's equivalent to returning a T.
+    for (DartType typeArg in type.typeArguments) {
+      _visitType(typeParam, typeArg, paramIn);
+    }
+  }
+
+  void _visitType(TypeParameterType typeParam, DartType type, bool paramIn) {
+    if (type == typeParam) {
+      if (paramIn) {
+        passedIn = true;
+      } else {
+        passedOut = true;
+      }
+    } else if (type is FunctionType) {
+      _visitFunctionType(typeParam, type, paramIn);
+    } else if (type is InterfaceType) {
+      _visitInterfaceType(typeParam, type, paramIn);
+    }
+  }
+}
diff --git a/pkg/analyzer/lib/src/plugin/engine_plugin.dart b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
index a067dcc..dbd8963 100644
--- a/pkg/analyzer/lib/src/plugin/engine_plugin.dart
+++ b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
@@ -197,6 +197,8 @@
     registerExtension(
         taskId, ComputeInferableStaticVariableDependenciesTask.DESCRIPTOR);
     registerExtension(taskId, ComputeLibraryCycleTask.DESCRIPTOR);
+    registerExtension(
+        taskId, ComputePropagableVariableDependenciesTask.DESCRIPTOR);
     registerExtension(taskId, ContainingLibrariesTask.DESCRIPTOR);
     registerExtension(taskId, DartErrorsTask.DESCRIPTOR);
     registerExtension(taskId, EvaluateUnitConstantsTask.DESCRIPTOR);
@@ -211,11 +213,17 @@
     registerExtension(taskId, LibraryUnitErrorsTask.DESCRIPTOR);
     registerExtension(taskId, ParseDartTask.DESCRIPTOR);
     registerExtension(taskId, PartiallyResolveUnitReferencesTask.DESCRIPTOR);
+    registerExtension(
+        taskId, PropagateVariableTypesInLibraryClosureTask.DESCRIPTOR);
+    registerExtension(taskId, PropagateVariableTypesInLibraryTask.DESCRIPTOR);
+    registerExtension(taskId, PropagateVariableTypesInUnitTask.DESCRIPTOR);
+    registerExtension(taskId, PropagateVariableTypeTask.DESCRIPTOR);
     registerExtension(taskId, ReadyLibraryElement2Task.DESCRIPTOR);
     registerExtension(taskId, ReadyLibraryElement5Task.DESCRIPTOR);
+    registerExtension(taskId, ReadyLibraryElement6Task.DESCRIPTOR);
     registerExtension(taskId, ReadyResolvedUnitTask.DESCRIPTOR);
-    registerExtension(taskId, ReadyResolvedUnit9Task.DESCRIPTOR);
     registerExtension(taskId, ReadyResolvedUnit10Task.DESCRIPTOR);
+    registerExtension(taskId, ReadyResolvedUnit11Task.DESCRIPTOR);
     registerExtension(taskId, ResolveInstanceFieldsInUnitTask.DESCRIPTOR);
     registerExtension(taskId, ResolveLibraryReferencesTask.DESCRIPTOR);
     registerExtension(taskId, ResolveLibraryTypeNamesTask.DESCRIPTOR);
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 61a4978..4974b99 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -130,13 +130,16 @@
 class PrelinkedReference {
   int _dependency;
   PrelinkedReferenceKind _kind;
+  int _unit;
 
   PrelinkedReference.fromJson(Map json)
     : _dependency = json["dependency"],
-      _kind = json["kind"] == null ? null : PrelinkedReferenceKind.values[json["kind"]];
+      _kind = json["kind"] == null ? null : PrelinkedReferenceKind.values[json["kind"]],
+      _unit = json["unit"];
 
   int get dependency => _dependency ?? 0;
   PrelinkedReferenceKind get kind => _kind ?? PrelinkedReferenceKind.classOrEnum;
+  int get unit => _unit ?? 0;
 }
 
 class PrelinkedReferenceBuilder {
@@ -158,13 +161,21 @@
     }
   }
 
+  void set unit(int _value) {
+    assert(!_json.containsKey("unit"));
+    if (_value != null) {
+      _json["unit"] = _value;
+    }
+  }
+
   Map finish() => _json;
 }
 
-PrelinkedReferenceBuilder encodePrelinkedReference(builder.BuilderContext builderContext, {int dependency, PrelinkedReferenceKind kind}) {
+PrelinkedReferenceBuilder encodePrelinkedReference(builder.BuilderContext builderContext, {int dependency, PrelinkedReferenceKind kind, int unit}) {
   PrelinkedReferenceBuilder builder = new PrelinkedReferenceBuilder(builderContext);
   builder.dependency = dependency;
   builder.kind = kind;
+  builder.unit = unit;
   return builder;
 }
 
diff --git a/pkg/analyzer/lib/src/summary/summarize_elements.dart b/pkg/analyzer/lib/src/summary/summarize_elements.dart
index 79a73a3..1ad8dd7 100644
--- a/pkg/analyzer/lib/src/summary/summarize_elements.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_elements.dart
@@ -555,6 +555,10 @@
       } else {
         b.reference = referenceMap.putIfAbsent(element, () {
           assert(unlinkedReferences.length == prelinkedReferences.length);
+          CompilationUnitElement unitElement =
+              element.getAncestor((Element e) => e is CompilationUnitElement);
+          int unit = dependentLibrary.units.indexOf(unitElement);
+          assert(unit != -1);
           int index = unlinkedReferences.length;
           // TODO(paulberry): set UnlinkedReference.prefix.
           unlinkedReferences
@@ -563,7 +567,8 @@
               dependency: serializeDependency(dependentLibrary),
               kind: element is FunctionTypeAliasElement
                   ? PrelinkedReferenceKind.typedef
-                  : PrelinkedReferenceKind.classOrEnum));
+                  : PrelinkedReferenceKind.classOrEnum,
+              unit: unit));
           return index;
         });
       }
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index 2aae1a1..1a5046d 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -286,6 +286,28 @@
         cachingPolicy: ELEMENT_CACHING_POLICY);
 
 /**
+ * The partial [LibraryElement] associated with a library.
+ *
+ * [LIBRARY_ELEMENT5] plus propagated types for propagable variables.
+ *
+ * The result is only available for [Source]s representing a library.
+ */
+final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT6 =
+    new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT6', null,
+        cachingPolicy: ELEMENT_CACHING_POLICY);
+
+/**
+ * The partial [LibraryElement] associated with a library.
+ *
+ * [LIBRARY_ELEMENT6] for the library and its import/export closure.
+ *
+ * The result is only available for [Source]s representing a library.
+ */
+final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT7 =
+    new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT7', null,
+        cachingPolicy: ELEMENT_CACHING_POLICY);
+
+/**
  * The flag specifying whether all analysis errors are computed in a specific
  * library.
  *
@@ -338,6 +360,36 @@
         'PARSE_ERRORS', AnalysisError.NO_ERRORS);
 
 /**
+ * A list of the [VariableElement]s whose type should be known to propagate
+ * the type of another variable (the target).
+ *
+ * The result is only available for [VariableElement]s.
+ */
+final ListResultDescriptor<VariableElement> PROPAGABLE_VARIABLE_DEPENDENCIES =
+    new ListResultDescriptor<VariableElement>(
+        'PROPAGABLE_VARIABLE_DEPENDENCIES', null);
+
+/**
+ * A list of the [VariableElement]s defined in a unit whose type might be
+ * propagated. This includes variables defined at the library level as well as
+ * static and instance members inside classes.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<VariableElement> PROPAGABLE_VARIABLES_IN_UNIT =
+    new ListResultDescriptor<VariableElement>(
+        'PROPAGABLE_VARIABLES_IN_UNIT', null);
+
+/**
+ * An propagable variable ([VariableElement]) whose type has been propagated.
+ *
+ * The result is only available for [VariableElement]s.
+ */
+final ResultDescriptor<VariableElement> PROPAGATED_VARIABLE =
+    new ResultDescriptor<VariableElement>('PROPAGATED_VARIABLE', null,
+        cachingPolicy: ELEMENT_CACHING_POLICY);
+
+/**
  * The flag specifying that [LIBRARY_ELEMENT2] is ready for a library and its
  * import/export closure.
  *
@@ -356,6 +408,15 @@
     new ResultDescriptor<bool>('READY_LIBRARY_ELEMENT5', false);
 
 /**
+ * The flag specifying that [LIBRARY_ELEMENT6] is ready for a library and its
+ * import/export closure.
+ *
+ * The result is only available for [Source]s representing a library.
+ */
+final ResultDescriptor<bool> READY_LIBRARY_ELEMENT6 =
+    new ResultDescriptor<bool>('READY_LIBRARY_ELEMENT6', false);
+
+/**
  * The flag specifying that [RESOLVED_UNIT] is ready for all of the units of a
  * library and its import/export closure.
  *
@@ -374,13 +435,13 @@
     new ResultDescriptor<bool>('READY_RESOLVED_UNIT10', false);
 
 /**
- * The flag specifying that [RESOLVED_UNIT9] is ready for all of the units of a
+ * The flag specifying that [RESOLVED_UNIT11] is ready for all of the units of a
  * library and its import/export closure.
  *
  * The result is only available for [Source]s representing a library.
  */
-final ResultDescriptor<bool> READY_RESOLVED_UNIT9 =
-    new ResultDescriptor<bool>('READY_RESOLVED_UNIT9', false);
+final ResultDescriptor<bool> READY_RESOLVED_UNIT11 =
+    new ResultDescriptor<bool>('READY_RESOLVED_UNIT11', false);
 
 /**
  * The names (resolved and not) referenced by a unit.
@@ -427,7 +488,7 @@
 
 /**
  * The resolved [CompilationUnit] associated with a compilation unit, with
- * constants resolved.
+ * constants not yet resolved.
  *
  * The result is only available for [LibrarySpecificUnit]s.
  */
@@ -436,6 +497,16 @@
         cachingPolicy: AST_CACHING_POLICY);
 
 /**
+ * The resolved [CompilationUnit] associated with a compilation unit, with
+ * constants resolved.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ResultDescriptor<CompilationUnit> RESOLVED_UNIT11 =
+    new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT11', null,
+        cachingPolicy: AST_CACHING_POLICY);
+
+/**
  * The partially resolved [CompilationUnit] associated with a compilation unit.
  *
  * Tasks that use this value as an input can assume that the [SimpleIdentifier]s
@@ -493,7 +564,8 @@
  * The partially resolved [CompilationUnit] associated with a compilation unit.
  *
  * In addition to what is true of a [RESOLVED_UNIT5], tasks that use this value
- * as an input can assume that the types of static variables have been inferred.
+ * as an input can assume that the types of final variables have been
+ * propagated.
  *
  * The result is only available for [LibrarySpecificUnit]s.
  */
@@ -505,8 +577,7 @@
  * The partially resolved [CompilationUnit] associated with a compilation unit.
  *
  * In addition to what is true of a [RESOLVED_UNIT6], tasks that use this value
- * as an input can assume that the initializers of instance variables have been
- * re-resolved.
+ * as an input can assume that the types of static variables have been inferred.
  *
  * The result is only available for [LibrarySpecificUnit]s.
  */
@@ -515,9 +586,11 @@
         cachingPolicy: AST_CACHING_POLICY);
 
 /**
- * The resolved [CompilationUnit] associated with a compilation unit in which
- * the types of class members have been inferred in addition to everything that
- * is true of a [RESOLVED_UNIT7].
+ * The partially resolved [CompilationUnit] associated with a compilation unit.
+ *
+ * In addition to what is true of a [RESOLVED_UNIT7], tasks that use this value
+ * as an input can assume that the initializers of instance variables have been
+ * re-resolved.
  *
  * The result is only available for [LibrarySpecificUnit]s.
  */
@@ -526,8 +599,9 @@
         cachingPolicy: AST_CACHING_POLICY);
 
 /**
- * The resolved [CompilationUnit] associated with a compilation unit, with
- * constants not yet resolved.
+ * The resolved [CompilationUnit] associated with a compilation unit in which
+ * the types of class members have been inferred in addition to everything that
+ * is true of a [RESOLVED_UNIT8].
  *
  * The result is only available for [LibrarySpecificUnit]s.
  */
@@ -603,10 +677,20 @@
         'VERIFY_ERRORS', AnalysisError.NO_ERRORS);
 
 /**
+ * Return a list of unique errors for the [Source] of the given [target].
+ */
+List<AnalysisError> getTargetSourceErrors(
+    RecordingErrorListener listener, AnalysisTarget target) {
+  Source source = target.source;
+  List<AnalysisError> errors = listener.getErrorsForSource(source);
+  return getUniqueErrors(errors);
+}
+
+/**
  * Return a list of errors containing the errors from the given [errors] list
  * but with duplications removed.
  */
-List<AnalysisError> removeDuplicateErrors(List<AnalysisError> errors) {
+List<AnalysisError> getUniqueErrors(List<AnalysisError> errors) {
   if (errors.isEmpty) {
     return errors;
   }
@@ -1638,7 +1722,7 @@
           'Cannot build inputs for a ${target.runtimeType}');
     }
     return <String, TaskInput>{
-      'resolvedUnit': RESOLVED_UNIT9
+      'resolvedUnit': RESOLVED_UNIT10
           .of(new LibrarySpecificUnit(librarySource, target.source)),
       TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
     };
@@ -1752,7 +1836,7 @@
  * static variable whose type should be inferred.
  */
 class ComputeInferableStaticVariableDependenciesTask
-    extends ConstantEvaluationAnalysisTask {
+    extends InferStaticVariableTask {
   /**
    * The name of the [RESOLVED_UNIT5] input.
    */
@@ -1776,19 +1860,11 @@
     //
     // Prepare inputs.
     //
-    VariableElement variable = target;
     CompilationUnit unit = getRequiredInput(UNIT_INPUT);
     //
     // Compute dependencies.
     //
-    NodeLocator locator = new NodeLocator(variable.nameOffset);
-    AstNode node = locator.searchWithin(unit);
-    VariableDeclaration declaration =
-        node.getAncestor((AstNode ancestor) => ancestor is VariableDeclaration);
-    if (declaration == null || declaration.name != node) {
-      throw new AnalysisException(
-          "NodeLocator failed to find a variable's declaration");
-    }
+    VariableDeclaration declaration = getDeclaration(unit);
     VariableGatherer gatherer = new VariableGatherer(_isInferableStatic);
     declaration.initializer.accept(gatherer);
     //
@@ -1940,6 +2016,85 @@
 }
 
 /**
+ * A task that computes the [PROPAGABLE_VARIABLE_DEPENDENCIES] for a variable.
+ */
+class ComputePropagableVariableDependenciesTask
+    extends InferStaticVariableTask {
+  /**
+   * The name of the [RESOLVED_UNIT5] input.
+   */
+  static const String UNIT_INPUT = 'UNIT_INPUT';
+
+  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+      'ComputePropagableVariableDependenciesTask',
+      createTask,
+      buildInputs,
+      <ResultDescriptor>[PROPAGABLE_VARIABLE_DEPENDENCIES]);
+
+  ComputePropagableVariableDependenciesTask(
+      InternalAnalysisContext context, VariableElement variable)
+      : super(context, variable);
+
+  @override
+  TaskDescriptor get descriptor => DESCRIPTOR;
+
+  @override
+  void internalPerform() {
+    //
+    // Prepare inputs.
+    //
+    CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+    //
+    // Compute dependencies.
+    //
+    VariableDeclaration declaration = getDeclaration(unit);
+    VariableGatherer gatherer = new VariableGatherer(_isPropagable);
+    declaration.initializer.accept(gatherer);
+    //
+    // Record outputs.
+    //
+    outputs[PROPAGABLE_VARIABLE_DEPENDENCIES] = gatherer.results.toList();
+  }
+
+  /**
+   * Return `true` if the given [variable] is a variable whose type can be
+   * propagated.
+   */
+  bool _isPropagable(VariableElement variable) =>
+      variable is PropertyInducingElement &&
+          (variable.isConst || variable.isFinal) &&
+          variable.hasImplicitType &&
+          variable.initializer != null;
+
+  /**
+   * 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) {
+    if (target is VariableElement) {
+      CompilationUnitElementImpl unit = target
+          .getAncestor((Element element) => element is CompilationUnitElement);
+      return <String, TaskInput>{
+        UNIT_INPUT: RESOLVED_UNIT5
+            .of(new LibrarySpecificUnit(unit.librarySource, unit.source))
+      };
+    }
+    throw new AnalysisException(
+        'Cannot build inputs for a ${target.runtimeType}');
+  }
+
+  /**
+   * Create a [ComputePropagableVariableDependenciesTask] based on the
+   * given [target] in the given [context].
+   */
+  static ComputePropagableVariableDependenciesTask createTask(
+      AnalysisContext context, AnalysisTarget target) {
+    return new ComputePropagableVariableDependenciesTask(context, target);
+  }
+}
+
+/**
  * A base class for analysis tasks whose target is expected to be a
  * [ConstantEvaluationTarget].
  */
@@ -2202,11 +2357,11 @@
 }
 
 /**
- * A task that builds [RESOLVED_UNIT10] for a unit.
+ * A task that builds [RESOLVED_UNIT11] for a unit.
  */
 class EvaluateUnitConstantsTask extends SourceBasedAnalysisTask {
   /**
-   * The name of the [RESOLVED_UNIT9] input.
+   * The name of the [RESOLVED_UNIT10] input.
    */
   static const String UNIT_INPUT = 'UNIT_INPUT';
 
@@ -2222,7 +2377,7 @@
       'EvaluateUnitConstantsTask',
       createTask,
       buildInputs,
-      <ResultDescriptor>[RESOLVED_UNIT10]);
+      <ResultDescriptor>[RESOLVED_UNIT11]);
 
   EvaluateUnitConstantsTask(AnalysisContext context, LibrarySpecificUnit target)
       : super(context, target);
@@ -2235,7 +2390,7 @@
     // No actual work needs to be performed; the task manager will ensure that
     // all constants are evaluated before this method is called.
     CompilationUnit unit = getRequiredInput(UNIT_INPUT);
-    outputs[RESOLVED_UNIT10] = unit;
+    outputs[RESOLVED_UNIT11] = unit;
   }
 
   /**
@@ -2247,7 +2402,7 @@
     LibrarySpecificUnit unit = target;
     return <String, TaskInput>{
       'libraryElement': LIBRARY_ELEMENT.of(unit.library),
-      UNIT_INPUT: RESOLVED_UNIT9.of(unit),
+      UNIT_INPUT: RESOLVED_UNIT10.of(unit),
       CONSTANT_VALUES:
           COMPILATION_UNIT_CONSTANTS.of(unit).toListOf(CONSTANT_VALUE)
     };
@@ -2371,7 +2526,7 @@
  */
 class GatherUsedImportedElementsTask extends SourceBasedAnalysisTask {
   /**
-   * The name of the [RESOLVED_UNIT9] input.
+   * The name of the [RESOLVED_UNIT10] input.
    */
   static const String UNIT_INPUT = 'UNIT_INPUT';
 
@@ -2415,7 +2570,7 @@
    */
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
     LibrarySpecificUnit unit = target;
-    return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT9.of(unit)};
+    return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT10.of(unit)};
   }
 
   /**
@@ -2433,7 +2588,7 @@
  */
 class GatherUsedLocalElementsTask extends SourceBasedAnalysisTask {
   /**
-   * The name of the [RESOLVED_UNIT9] input.
+   * The name of the [RESOLVED_UNIT10] input.
    */
   static const String UNIT_INPUT = 'UNIT_INPUT';
 
@@ -2477,7 +2632,7 @@
    */
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
     LibrarySpecificUnit unit = target;
-    return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT9.of(unit)};
+    return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT10.of(unit)};
   }
 
   /**
@@ -2495,7 +2650,7 @@
  */
 class GenerateHintsTask extends SourceBasedAnalysisTask {
   /**
-   * The name of the [RESOLVED_UNIT9] input.
+   * The name of the [RESOLVED_UNIT10] input.
    */
   static const String RESOLVED_UNIT_INPUT = 'RESOLVED_UNIT';
 
@@ -2701,7 +2856,7 @@
   static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
 
   /**
-   * The name of the input whose value is the [RESOLVED_UNIT6] for the
+   * The name of the input whose value is the [RESOLVED_UNIT7] for the
    * compilation unit.
    */
   static const String UNIT_INPUT = 'UNIT_INPUT';
@@ -2713,7 +2868,7 @@
       'InferInstanceMembersInUnitTask',
       createTask,
       buildInputs,
-      <ResultDescriptor>[RESOLVED_UNIT8]);
+      <ResultDescriptor>[RESOLVED_UNIT9]);
 
   /**
    * Initialize a newly created task to build a library element for the given
@@ -2744,7 +2899,7 @@
     //
     // Record outputs.
     //
-    outputs[RESOLVED_UNIT8] = unit;
+    outputs[RESOLVED_UNIT9] = unit;
   }
 
   /**
@@ -2755,7 +2910,7 @@
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
     LibrarySpecificUnit unit = target;
     return <String, TaskInput>{
-      UNIT_INPUT: RESOLVED_UNIT7.of(unit),
+      UNIT_INPUT: RESOLVED_UNIT8.of(unit),
       TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request),
       // In strong mode, add additional dependencies to enforce inference
       // ordering.
@@ -2763,12 +2918,12 @@
       // Require that field re-resolution be complete for all units in the
       // current library cycle.
       'orderLibraryCycleTasks': LIBRARY_CYCLE_UNITS.of(unit).toList(
-          (CompilationUnitElementImpl unit) => RESOLVED_UNIT7
+          (CompilationUnitElementImpl unit) => RESOLVED_UNIT8
               .of(new LibrarySpecificUnit(unit.librarySource, unit.source))),
       // Require that full inference be complete for all dependencies of the
       // current library cycle.
       'orderLibraryCycles': LIBRARY_CYCLE_DEPENDENCIES.of(unit).toList(
-          (CompilationUnitElementImpl unit) => RESOLVED_UNIT8
+          (CompilationUnitElementImpl unit) => RESOLVED_UNIT9
               .of(new LibrarySpecificUnit(unit.librarySource, unit.source)))
     };
   }
@@ -2798,13 +2953,13 @@
    */
   VariableDeclaration getDeclaration(CompilationUnit unit) {
     VariableElement variable = target;
-    NodeLocator locator = new NodeLocator(variable.nameOffset);
-    AstNode node = locator.searchWithin(unit);
+    AstNode node = new NodeLocator2(variable.nameOffset).searchWithin(unit);
     VariableDeclaration declaration =
         node.getAncestor((AstNode ancestor) => ancestor is VariableDeclaration);
     if (declaration == null || declaration.name != node) {
       throw new AnalysisException(
-          "Failed to find the declaration of the variable ${variable.displayName} in ${variable.source}");
+          "Failed to find the declaration of the variable "
+          "${variable.displayName} in ${variable.source}");
     }
     return declaration;
   }
@@ -2816,7 +2971,7 @@
  */
 class InferStaticVariableTypesInUnitTask extends SourceBasedAnalysisTask {
   /**
-   * The name of the input whose value is the [RESOLVED_UNIT5] for the
+   * The name of the input whose value is the [RESOLVED_UNIT6] for the
    * compilation unit.
    */
   static const String UNIT_INPUT = 'UNIT_INPUT';
@@ -2834,7 +2989,7 @@
       'InferStaticVariableTypesInUnitTask',
       createTask,
       buildInputs,
-      <ResultDescriptor>[RESOLVED_UNIT6]);
+      <ResultDescriptor>[RESOLVED_UNIT7]);
 
   /**
    * Initialize a newly created task to build a library element for the given
@@ -2858,7 +3013,7 @@
     // because the work has implicitly been done by virtue of the task model
     // preparing all of the inputs.
     //
-    outputs[RESOLVED_UNIT6] = unit;
+    outputs[RESOLVED_UNIT7] = unit;
   }
 
   /**
@@ -2872,7 +3027,7 @@
       INFERRED_VARIABLES_INPUT: INFERABLE_STATIC_VARIABLES_IN_UNIT
           .of(unit)
           .toListOf(INFERRED_STATIC_VARIABLE),
-      UNIT_INPUT: RESOLVED_UNIT5.of(unit)
+      UNIT_INPUT: RESOLVED_UNIT6.of(unit)
     };
   }
 
@@ -2903,7 +3058,7 @@
   static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
 
   /**
-   * The name of the [RESOLVED_UNIT5] input.
+   * The name of the [RESOLVED_UNIT6] input.
    */
   static const String UNIT_INPUT = 'UNIT_INPUT';
 
@@ -3001,14 +3156,14 @@
           .of(variable)
           .toListOf(INFERRED_STATIC_VARIABLE),
       TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request),
-      UNIT_INPUT: RESOLVED_UNIT5.of(unit),
+      UNIT_INPUT: RESOLVED_UNIT6.of(unit),
       // In strong mode, add additional dependencies to enforce inference
       // ordering.
 
       // Require that full inference be complete for all dependencies of the
       // current library cycle.
       'orderLibraryCycles': LIBRARY_CYCLE_DEPENDENCIES.of(unit).toList(
-          (CompilationUnitElementImpl unit) => RESOLVED_UNIT8
+          (CompilationUnitElementImpl unit) => RESOLVED_UNIT9
               .of(new LibrarySpecificUnit(unit.librarySource, unit.source)))
     };
   }
@@ -3315,8 +3470,7 @@
     List<Source> exportedSources = exportedSourceSet.toList();
     List<Source> importedSources = importedSourceSet.toList();
     List<Source> includedSources = includedSourceSet.toList();
-    List<AnalysisError> parseErrors =
-        removeDuplicateErrors(errorListener.errors);
+    List<AnalysisError> parseErrors = getUniqueErrors(errorListener.errors);
     List<Source> unitSources = <Source>[source]..addAll(includedSourceSet);
     List<LibrarySpecificUnit> librarySpecificUnits =
         unitSources.map((s) => new LibrarySpecificUnit(source, s)).toList();
@@ -3334,13 +3488,13 @@
   /**
    * 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
-   * [source].
+   * [target].
    */
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
     return <String, TaskInput>{
       LINE_INFO_INPUT_NAME: LINE_INFO.of(target),
       MODIFICATION_TIME_INPUT_NAME: MODIFICATION_TIME.of(target),
-      TOKEN_STREAM_INPUT_NAME: TOKEN_STREAM.of(target)
+      TOKEN_STREAM_INPUT_NAME: TOKEN_STREAM.of(target, flushOnAccess: true)
     };
   }
 
@@ -3418,8 +3572,11 @@
   static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
       'PartiallyResolveUnitReferencesTask',
       createTask,
-      buildInputs,
-      <ResultDescriptor>[INFERABLE_STATIC_VARIABLES_IN_UNIT, RESOLVED_UNIT5]);
+      buildInputs, <ResultDescriptor>[
+    INFERABLE_STATIC_VARIABLES_IN_UNIT,
+    PROPAGABLE_VARIABLES_IN_UNIT,
+    RESOLVED_UNIT5
+  ]);
 
   PartiallyResolveUnitReferencesTask(
       InternalAnalysisContext context, AnalysisTarget target)
@@ -3440,21 +3597,21 @@
     //
     // Resolve references and record outputs.
     //
+    InheritanceManager inheritanceManager =
+        new InheritanceManager(libraryElement);
+    PartialResolverVisitor visitor = new PartialResolverVisitor(libraryElement,
+        unitElement.source, typeProvider, AnalysisErrorListener.NULL_LISTENER,
+        inheritanceManager: inheritanceManager);
+    unit.accept(visitor);
+    //
+    // Record outputs.
+    //
     if (context.analysisOptions.strongMode) {
-      InheritanceManager inheritanceManager =
-          new InheritanceManager(libraryElement);
-      PartialResolverVisitor visitor = new PartialResolverVisitor(
-          libraryElement,
-          unitElement.source,
-          typeProvider,
-          AnalysisErrorListener.NULL_LISTENER,
-          inheritanceManager: inheritanceManager);
-      unit.accept(visitor);
-
-      outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT] = visitor.variablesAndFields;
+      outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT] = visitor.staticVariables;
     } else {
-      outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT] = [];
+      outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT] = VariableElement.EMPTY_LIST;
     }
+    outputs[PROPAGABLE_VARIABLES_IN_UNIT] = visitor.propagableVariables;
     outputs[RESOLVED_UNIT5] = unit;
   }
 
@@ -3476,7 +3633,7 @@
       // Require that full inference be complete for all dependencies of the
       // current library cycle.
       'orderLibraryCycles': LIBRARY_CYCLE_DEPENDENCIES.of(unit).toList(
-          (CompilationUnitElementImpl unit) => RESOLVED_UNIT8
+          (CompilationUnitElementImpl unit) => RESOLVED_UNIT9
               .of(new LibrarySpecificUnit(unit.librarySource, unit.source)))
     };
   }
@@ -3492,6 +3649,285 @@
 }
 
 /**
+ * An artificial task that does nothing except to force propagated types for
+ * all propagable variables in the import/export closure a library.
+ */
+class PropagateVariableTypesInLibraryClosureTask
+    extends SourceBasedAnalysisTask {
+  /**
+   * The name of the [LIBRARY_ELEMENT6] input.
+   */
+  static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
+
+  /**
+   * The task descriptor describing this kind of task.
+   */
+  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+      'PropagateVariableTypesInLibraryClosureTask',
+      createTask,
+      buildInputs,
+      <ResultDescriptor>[LIBRARY_ELEMENT7]);
+
+  PropagateVariableTypesInLibraryClosureTask(
+      InternalAnalysisContext context, AnalysisTarget target)
+      : super(context, target);
+
+  @override
+  TaskDescriptor get descriptor => DESCRIPTOR;
+
+  @override
+  void internalPerform() {
+    LibraryElement library = getRequiredInput(LIBRARY_INPUT);
+    outputs[LIBRARY_ELEMENT7] = library;
+  }
+
+  /**
+   * 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) {
+    Source source = target;
+    return <String, TaskInput>{
+      'readyForClosure': READY_LIBRARY_ELEMENT6.of(source),
+      LIBRARY_INPUT: LIBRARY_ELEMENT6.of(source),
+    };
+  }
+
+  /**
+   * Create a [PropagateVariableTypesInLibraryClosureTask] based on the given
+   * [target] in the given [context].
+   */
+  static PropagateVariableTypesInLibraryClosureTask createTask(
+      AnalysisContext context, AnalysisTarget target) {
+    return new PropagateVariableTypesInLibraryClosureTask(context, target);
+  }
+}
+
+/**
+ * An artificial task that does nothing except to force propagated types for
+ * all propagable variables in the defining and part units of a library.
+ */
+class PropagateVariableTypesInLibraryTask extends SourceBasedAnalysisTask {
+  /**
+   * The name of the [LIBRARY_ELEMENT5] input.
+   */
+  static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
+
+  /**
+   * The task descriptor describing this kind of task.
+   */
+  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+      'PropagateVariableTypesInLibraryTask',
+      createTask,
+      buildInputs,
+      <ResultDescriptor>[LIBRARY_ELEMENT6]);
+
+  PropagateVariableTypesInLibraryTask(
+      InternalAnalysisContext context, AnalysisTarget target)
+      : super(context, target);
+
+  @override
+  TaskDescriptor get descriptor => DESCRIPTOR;
+
+  @override
+  void internalPerform() {
+    LibraryElement library = getRequiredInput(LIBRARY_INPUT);
+    outputs[LIBRARY_ELEMENT6] = library;
+  }
+
+  /**
+   * 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) {
+    Source source = target;
+    return <String, TaskInput>{
+      'propagatedVariableTypesInUnits':
+          LIBRARY_SPECIFIC_UNITS.of(source).toListOf(RESOLVED_UNIT6),
+      LIBRARY_INPUT: LIBRARY_ELEMENT5.of(source),
+    };
+  }
+
+  /**
+   * Create a [PropagateVariableTypesInLibraryTask] based on the given [target]
+   * in the given [context].
+   */
+  static PropagateVariableTypesInLibraryTask createTask(
+      AnalysisContext context, AnalysisTarget target) {
+    return new PropagateVariableTypesInLibraryTask(context, target);
+  }
+}
+
+/**
+ * A task that ensures that all of the propagable variables in a compilation
+ * unit have had their type propagated.
+ */
+class PropagateVariableTypesInUnitTask extends SourceBasedAnalysisTask {
+  /**
+   * The name of the input whose value is the [RESOLVED_UNIT5] for the
+   * compilation unit.
+   */
+  static const String UNIT_INPUT = 'UNIT_INPUT';
+
+  /**
+   * The task descriptor describing this kind of task.
+   */
+  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+      'PropagateVariableTypesInUnitTask',
+      createTask,
+      buildInputs,
+      <ResultDescriptor>[RESOLVED_UNIT6]);
+
+  PropagateVariableTypesInUnitTask(
+      InternalAnalysisContext context, LibrarySpecificUnit unit)
+      : super(context, unit);
+
+  @override
+  TaskDescriptor get descriptor => DESCRIPTOR;
+
+  @override
+  void internalPerform() {
+    //
+    // Prepare inputs.
+    //
+    CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+    //
+    // Record outputs. There is no additional work to be done at this time
+    // because the work has implicitly been done by virtue of the task model
+    // preparing all of the inputs.
+    //
+    outputs[RESOLVED_UNIT6] = unit;
+  }
+
+  /**
+   * 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>{
+      'variables':
+          PROPAGABLE_VARIABLES_IN_UNIT.of(unit).toListOf(PROPAGATED_VARIABLE),
+      UNIT_INPUT: RESOLVED_UNIT5.of(unit)
+    };
+  }
+
+  /**
+   * Create a [PropagateVariableTypesInUnitTask] based on the given [target]
+   * in the given [context].
+   */
+  static PropagateVariableTypesInUnitTask createTask(
+      AnalysisContext context, AnalysisTarget target) {
+    return new PropagateVariableTypesInUnitTask(context, target);
+  }
+}
+
+/**
+ * A task that computes the propagated type of an propagable variable and
+ * stores it in the element model.
+ */
+class PropagateVariableTypeTask extends InferStaticVariableTask {
+  /**
+   * The name of the [TYPE_PROVIDER] input.
+   */
+  static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
+
+  /**
+   * The name of the [RESOLVED_UNIT5] input.
+   */
+  static const String UNIT_INPUT = 'UNIT_INPUT';
+
+  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+      'PropagateVariableTypeTask',
+      createTask,
+      buildInputs,
+      <ResultDescriptor>[PROPAGATED_VARIABLE]);
+
+  PropagateVariableTypeTask(
+      InternalAnalysisContext context, VariableElement variable)
+      : super(context, variable);
+
+  @override
+  TaskDescriptor get descriptor => DESCRIPTOR;
+
+  @override
+  bool get handlesDependencyCycles => true;
+
+  @override
+  void internalPerform() {
+    //
+    // Prepare inputs.
+    //
+    PropertyInducingElementImpl variable = target;
+    TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
+    CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+
+    // If we're not in a dependency cycle, and we have no type annotation,
+    // re-resolve the right hand side and do propagation.
+    if (dependencyCycle == null && variable.hasImplicitType) {
+      VariableDeclaration declaration = getDeclaration(unit);
+      //
+      // Re-resolve the variable's initializer with the propagated types of
+      // other variables.
+      //
+      Expression initializer = declaration.initializer;
+      ResolutionContext resolutionContext = ResolutionContextBuilder.contextFor(
+          initializer, AnalysisErrorListener.NULL_LISTENER);
+      ResolverVisitor visitor = new ResolverVisitor(variable.library,
+          variable.source, typeProvider, AnalysisErrorListener.NULL_LISTENER,
+          nameScope: resolutionContext.scope);
+      if (resolutionContext.enclosingClassDeclaration != null) {
+        visitor.prepareToResolveMembersInClass(
+            resolutionContext.enclosingClassDeclaration);
+      }
+      visitor.initForIncrementalResolution();
+      initializer.accept(visitor);
+      //
+      // Record the type of the variable.
+      //
+      DartType newType = initializer.bestType;
+      if (newType != null && !newType.isBottom && !newType.isDynamic) {
+        variable.propagatedType = newType;
+      }
+    }
+    //
+    // Record outputs.
+    //
+    outputs[PROPAGATED_VARIABLE] = variable;
+  }
+
+  /**
+   * 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) {
+    VariableElement variable = target;
+    LibrarySpecificUnit unit =
+        new LibrarySpecificUnit(variable.library.source, variable.source);
+    return <String, TaskInput>{
+      'dependencies': PROPAGABLE_VARIABLE_DEPENDENCIES
+          .of(variable)
+          .toListOf(PROPAGATED_VARIABLE),
+      TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request),
+      UNIT_INPUT: RESOLVED_UNIT5.of(unit),
+    };
+  }
+
+  /**
+   * Create a [PropagateVariableTypeTask] based on the given [target] in the
+   * given [context].
+   */
+  static PropagateVariableTypeTask createTask(
+      AnalysisContext context, AnalysisTarget target) {
+    return new PropagateVariableTypeTask(context, target);
+  }
+}
+
+/**
  * The helper for building the public [Namespace] of a [LibraryElement].
  */
 class PublicNamespaceBuilder {
@@ -3617,6 +4053,49 @@
 }
 
 /**
+ * A task that ensures that [LIBRARY_ELEMENT6] is ready for the target library
+ * source and its import/export closure.
+ */
+class ReadyLibraryElement6Task extends SourceBasedAnalysisTask {
+  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+      'ReadyLibraryElement6Task',
+      createTask,
+      buildInputs,
+      <ResultDescriptor>[READY_LIBRARY_ELEMENT6]);
+
+  ReadyLibraryElement6Task(
+      InternalAnalysisContext context, AnalysisTarget target)
+      : super(context, target);
+
+  @override
+  TaskDescriptor get descriptor => DESCRIPTOR;
+
+  @override
+  bool get handlesDependencyCycles => true;
+
+  @override
+  void internalPerform() {
+    outputs[READY_LIBRARY_ELEMENT6] = true;
+  }
+
+  static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+    Source source = target;
+    return <String, TaskInput>{
+      'thisLibraryElementReady': LIBRARY_ELEMENT6.of(source),
+      'directlyImportedLibrariesReady':
+          IMPORTED_LIBRARIES.of(source).toListOf(READY_LIBRARY_ELEMENT6),
+      'directlyExportedLibrariesReady':
+          EXPORTED_LIBRARIES.of(source).toListOf(READY_LIBRARY_ELEMENT6),
+    };
+  }
+
+  static ReadyLibraryElement6Task createTask(
+      AnalysisContext context, AnalysisTarget target) {
+    return new ReadyLibraryElement6Task(context, target);
+  }
+}
+
+/**
  * A task that ensures that [RESOLVED_UNIT10] is ready for every unit of the
  * target library source and its import/export closure.
  */
@@ -3661,17 +4140,18 @@
 }
 
 /**
- * A task that ensures that [RESOLVED_UNIT9] is ready for every unit of the
+ * A task that ensures that [RESOLVED_UNIT11] is ready for every unit of the
  * target library source and its import/export closure.
  */
-class ReadyResolvedUnit9Task extends SourceBasedAnalysisTask {
+class ReadyResolvedUnit11Task extends SourceBasedAnalysisTask {
   static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
-      'ReadyResolvedUnit9Task',
+      'ReadyResolvedUnit11Task',
       createTask,
       buildInputs,
-      <ResultDescriptor>[READY_RESOLVED_UNIT9]);
+      <ResultDescriptor>[READY_RESOLVED_UNIT11]);
 
-  ReadyResolvedUnit9Task(InternalAnalysisContext context, AnalysisTarget target)
+  ReadyResolvedUnit11Task(
+      InternalAnalysisContext context, AnalysisTarget target)
       : super(context, target);
 
   @override
@@ -3682,24 +4162,24 @@
 
   @override
   void internalPerform() {
-    outputs[READY_RESOLVED_UNIT9] = true;
+    outputs[READY_RESOLVED_UNIT11] = true;
   }
 
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
     Source source = target;
     return <String, TaskInput>{
       'thisLibraryUnitsReady':
-          LIBRARY_SPECIFIC_UNITS.of(source).toListOf(RESOLVED_UNIT9),
+          LIBRARY_SPECIFIC_UNITS.of(source).toListOf(RESOLVED_UNIT11),
       'directlyImportedLibrariesReady':
-          IMPORTED_LIBRARIES.of(source).toListOf(READY_RESOLVED_UNIT9),
+          IMPORTED_LIBRARIES.of(source).toListOf(READY_RESOLVED_UNIT11),
       'directlyExportedLibrariesReady':
-          EXPORTED_LIBRARIES.of(source).toListOf(READY_RESOLVED_UNIT9),
+          EXPORTED_LIBRARIES.of(source).toListOf(READY_RESOLVED_UNIT11),
     };
   }
 
-  static ReadyResolvedUnit9Task createTask(
+  static ReadyResolvedUnit11Task createTask(
       AnalysisContext context, AnalysisTarget target) {
-    return new ReadyResolvedUnit9Task(context, target);
+    return new ReadyResolvedUnit11Task(context, target);
   }
 }
 
@@ -3860,7 +4340,7 @@
   static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
 
   /**
-   * The name of the input whose value is the [RESOLVED_UNIT6] for the
+   * The name of the input whose value is the [RESOLVED_UNIT7] for the
    * compilation unit.
    */
   static const String UNIT_INPUT = 'UNIT_INPUT';
@@ -3872,7 +4352,7 @@
       'ResolveInstanceFieldsInUnitTask',
       createTask,
       buildInputs,
-      <ResultDescriptor>[RESOLVED_UNIT7]);
+      <ResultDescriptor>[RESOLVED_UNIT8]);
 
   /**
    * Initialize a newly created task to build a library element for the given
@@ -3920,7 +4400,7 @@
     //
     // Record outputs.
     //
-    outputs[RESOLVED_UNIT7] = unit;
+    outputs[RESOLVED_UNIT8] = unit;
   }
 
   /**
@@ -3931,7 +4411,7 @@
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
     LibrarySpecificUnit unit = target;
     return <String, TaskInput>{
-      UNIT_INPUT: RESOLVED_UNIT6.of(unit),
+      UNIT_INPUT: RESOLVED_UNIT7.of(unit),
       LIBRARY_INPUT: LIBRARY_ELEMENT5.of(unit.library),
       TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request),
       // In strong mode, add additional dependencies to enforce inference
@@ -3940,12 +4420,12 @@
       // Require that static variable inference  be complete for all units in
       // the current library cycle.
       'orderLibraryCycleTasks': LIBRARY_CYCLE_UNITS.of(unit).toList(
-          (CompilationUnitElementImpl unit) => RESOLVED_UNIT6
+          (CompilationUnitElementImpl unit) => RESOLVED_UNIT7
               .of(new LibrarySpecificUnit(unit.librarySource, unit.source))),
       // Require that full inference be complete for all dependencies of the
       // current library cycle.
       'orderLibraryCycles': LIBRARY_CYCLE_DEPENDENCIES.of(unit).toList(
-          (CompilationUnitElementImpl unit) => RESOLVED_UNIT8
+          (CompilationUnitElementImpl unit) => RESOLVED_UNIT9
               .of(new LibrarySpecificUnit(unit.librarySource, unit.source)))
     };
   }
@@ -3961,7 +4441,7 @@
 }
 
 /**
- * A task that finishes resolution by requesting [RESOLVED_UNIT9] for every
+ * A task that finishes resolution by requesting [RESOLVED_UNIT10] for every
  * unit in the libraries closure and produces [LIBRARY_ELEMENT].
  */
 class ResolveLibraryReferencesTask extends SourceBasedAnalysisTask {
@@ -3971,7 +4451,7 @@
   static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
 
   /**
-   * The name of the list of [RESOLVED_UNIT9] input.
+   * The name of the list of [RESOLVED_UNIT10] input.
    */
   static const String UNITS_INPUT = 'UNITS_INPUT';
 
@@ -4019,8 +4499,8 @@
     Source source = target;
     return <String, TaskInput>{
       LIBRARY_INPUT: LIBRARY_ELEMENT5.of(source),
-      UNITS_INPUT: LIBRARY_SPECIFIC_UNITS.of(source).toListOf(RESOLVED_UNIT9),
-      'thisLibraryClosureIsReady': READY_RESOLVED_UNIT9.of(source),
+      UNITS_INPUT: LIBRARY_SPECIFIC_UNITS.of(source).toListOf(RESOLVED_UNIT10),
+      'thisLibraryClosureIsReady': READY_RESOLVED_UNIT10.of(source),
     };
   }
 
@@ -4113,7 +4593,7 @@
  */
 class ResolveUnitTask extends SourceBasedAnalysisTask {
   /**
-   * The name of the input whose value is the defining [LIBRARY_ELEMENT5].
+   * The name of the input whose value is the defining [LIBRARY_ELEMENT7].
    */
   static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
 
@@ -4123,7 +4603,7 @@
   static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
 
   /**
-   * The name of the [RESOLVED_UNIT8] input.
+   * The name of the [RESOLVED_UNIT9] input.
    */
   static const String UNIT_INPUT = 'UNIT_INPUT';
 
@@ -4131,7 +4611,7 @@
       'ResolveUnitTask',
       createTask,
       buildInputs,
-      <ResultDescriptor>[RESOLVE_UNIT_ERRORS, RESOLVED_UNIT9]);
+      <ResultDescriptor>[RESOLVE_UNIT_ERRORS, RESOLVED_UNIT10]);
 
   ResolveUnitTask(
       InternalAnalysisContext context, LibrarySpecificUnit compilationUnit)
@@ -4163,8 +4643,8 @@
     // AST's for constructor initializers into it) but does not produce an
     // updated version of the element model.
     //
-    outputs[RESOLVE_UNIT_ERRORS] = errorListener.errors;
-    outputs[RESOLVED_UNIT9] = unit;
+    outputs[RESOLVE_UNIT_ERRORS] = getTargetSourceErrors(errorListener, target);
+    outputs[RESOLVED_UNIT10] = unit;
   }
 
   /**
@@ -4175,16 +4655,16 @@
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
     LibrarySpecificUnit unit = target;
     return <String, TaskInput>{
-      LIBRARY_INPUT: LIBRARY_ELEMENT5.of(unit.library),
+      LIBRARY_INPUT: LIBRARY_ELEMENT7.of(unit.library),
       TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request),
-      UNIT_INPUT: RESOLVED_UNIT8.of(unit),
+      UNIT_INPUT: RESOLVED_UNIT9.of(unit),
       // In strong mode, add additional dependencies to enforce inference
       // ordering.
 
       // Require that inference be complete for all units in the
       // current library cycle.
       'orderLibraryCycleTasks': LIBRARY_CYCLE_UNITS.of(unit).toList(
-          (CompilationUnitElementImpl unit) => RESOLVED_UNIT8
+          (CompilationUnitElementImpl unit) => RESOLVED_UNIT9
               .of(new LibrarySpecificUnit(unit.librarySource, unit.source)))
     };
   }
@@ -4254,7 +4734,7 @@
     // Record outputs.
     //
     outputs[RESOLVE_TYPE_NAMES_ERRORS] =
-        removeDuplicateErrors(errorListener.errors);
+        getTargetSourceErrors(errorListener, target);
     outputs[RESOLVED_UNIT3] = unit;
   }
 
@@ -4345,7 +4825,7 @@
     //
     outputs[RESOLVED_UNIT4] = unit;
     outputs[VARIABLE_REFERENCE_ERRORS] =
-        removeDuplicateErrors(errorListener.errors);
+        getTargetSourceErrors(errorListener, target);
   }
 
   /**
@@ -4442,7 +4922,7 @@
 
       outputs[TOKEN_STREAM] = scanner.tokenize();
       outputs[LINE_INFO] = new LineInfo(scanner.lineStarts);
-      outputs[SCAN_ERRORS] = removeDuplicateErrors(errorListener.errors);
+      outputs[SCAN_ERRORS] = getUniqueErrors(errorListener.errors);
     } else if (target is Source) {
       String content = getRequiredInput(CONTENT_INPUT_NAME);
 
@@ -4453,7 +4933,7 @@
 
       outputs[TOKEN_STREAM] = scanner.tokenize();
       outputs[LINE_INFO] = new LineInfo(scanner.lineStarts);
-      outputs[SCAN_ERRORS] = removeDuplicateErrors(errorListener.errors);
+      outputs[SCAN_ERRORS] = getUniqueErrors(errorListener.errors);
     } else {
       throw new AnalysisException(
           'Cannot scan Dart code from a ${target.runtimeType}');
@@ -4493,7 +4973,7 @@
  */
 class StrongModeVerifyUnitTask extends SourceBasedAnalysisTask {
   /**
-   * The name of the [RESOLVED_UNIT10] input.
+   * The name of the [RESOLVED_UNIT11] input.
    */
   static const String UNIT_INPUT = 'UNIT_INPUT';
 
@@ -4533,7 +5013,7 @@
     //
     // Record outputs.
     //
-    outputs[STRONG_MODE_ERRORS] = removeDuplicateErrors(errorListener.errors);
+    outputs[STRONG_MODE_ERRORS] = getUniqueErrors(errorListener.errors);
     outputs[RESOLVED_UNIT] = unit;
   }
 
@@ -4545,9 +5025,9 @@
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
     LibrarySpecificUnit unit = target;
     return <String, TaskInput>{
-      UNIT_INPUT: RESOLVED_UNIT10.of(unit),
+      UNIT_INPUT: RESOLVED_UNIT11.of(unit),
       TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request),
-      'thisLibraryClosureIsReady': READY_RESOLVED_UNIT10.of(unit.library),
+      'thisLibraryClosureIsReady': READY_RESOLVED_UNIT11.of(unit.library),
     };
   }
 
@@ -4628,7 +5108,7 @@
     //
     // Record outputs.
     //
-    outputs[VERIFY_ERRORS] = removeDuplicateErrors(errorListener.errors);
+    outputs[VERIFY_ERRORS] = getUniqueErrors(errorListener.errors);
   }
 
   /**
diff --git a/pkg/analyzer/lib/src/task/options.dart b/pkg/analyzer/lib/src/task/options.dart
index 45faf41..0596490 100644
--- a/pkg/analyzer/lib/src/task/options.dart
+++ b/pkg/analyzer/lib/src/task/options.dart
@@ -12,6 +12,7 @@
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_general.dart';
 import 'package:analyzer/src/task/general.dart';
+import 'package:analyzer/src/task/strong/info.dart';
 import 'package:analyzer/task/general.dart';
 import 'package:analyzer/task/model.dart';
 import 'package:source_span/source_span.dart';
@@ -125,6 +126,10 @@
       new List.from(AnalyzerOptions.ignoreSynonyms)
         ..addAll(AnalyzerOptions.includeSynonyms));
 
+  bool recognizedErrorCode(String name) =>
+      ErrorCode.values.any((ErrorCode code) => code.name == name) ||
+          StaticInfo.names.contains(name);
+
   @override
   void validate(ErrorReporter reporter, Map<String, YamlNode> options) {
     var analyzer = options[AnalyzerOptions.analyzer];
@@ -138,7 +143,7 @@
       filters.nodes.forEach((k, v) {
         if (k is YamlScalar) {
           value = toUpperCase(k.value);
-          if (!ErrorCode.values.any((ErrorCode code) => code.name == value)) {
+          if (!recognizedErrorCode(value)) {
             reporter.reportErrorForSpan(
                 AnalysisOptionsWarningCode.UNRECOGNIZED_ERROR_CODE,
                 k.span,
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index 5a6bcaa..d557eb2 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -467,6 +467,10 @@
     if (node.typeArguments != null) {
       var targs = node.typeArguments.arguments;
       if (targs.length > 0) type = targs[0].type;
+    } else if (node.staticType is InterfaceType) {
+      InterfaceType listT = node.staticType;
+      var targs = listT.typeArguments;
+      if (targs != null && targs.length > 0) type = targs[0];
     }
     var elements = node.elements;
     for (int i = 0; i < elements.length; i++) {
@@ -483,6 +487,13 @@
       var targs = node.typeArguments.arguments;
       if (targs.length > 0) ktype = targs[0].type;
       if (targs.length > 1) vtype = targs[1].type;
+    } else if (node.staticType is InterfaceType) {
+      InterfaceType mapT = node.staticType;
+      var targs = mapT.typeArguments;
+      if (targs != null) {
+        if (targs.length > 0) ktype = targs[0];
+        if (targs.length > 1) vtype = targs[1];
+      }
     }
     var entries = node.entries;
     for (int i = 0; i < entries.length; i++) {
@@ -572,8 +583,13 @@
   @override
   void visitRedirectingConstructorInvocation(
       RedirectingConstructorInvocation node) {
-    var type = node.staticElement.type;
-    checkArgumentList(node.argumentList, type);
+    var type = node.staticElement?.type;
+    // TODO(leafp): There's a TODO in visitRedirectingConstructorInvocation
+    // in the element_resolver to handle the case that the element is null
+    // and emit an error.  In the meantime, just be defensive here.
+    if (type != null) {
+      checkArgumentList(node.argumentList, type);
+    }
     node.visitChildren(this);
   }
 
@@ -597,6 +613,14 @@
       // analyzer error in this case.
       return;
     }
+    InterfaceType futureType = rules.provider.futureType;
+    DartType actualType = expression.staticType;
+    if (body.isAsynchronous &&
+        !body.isGenerator &&
+        actualType is InterfaceType &&
+        actualType.element == futureType.element) {
+      type = futureType.substitute4([type]);
+    }
     // TODO(vsm): Enforce void or dynamic (to void?) when expression is null.
     if (expression != null) checkAssignment(expression, type);
   }
@@ -947,7 +971,6 @@
   void _recordMessage(StaticInfo info) {
     if (info == null) return;
     var error = info.toAnalysisError();
-
     var severity = error.errorCode.errorSeverity;
     if (severity == ErrorSeverity.ERROR) _failure = true;
     if (severity != ErrorSeverity.INFO || _hints) {
diff --git a/pkg/analyzer/lib/src/task/strong/info.dart b/pkg/analyzer/lib/src/task/strong/info.dart
index 9d4812f..dbdc4e0 100644
--- a/pkg/analyzer/lib/src/task/strong/info.dart
+++ b/pkg/analyzer/lib/src/task/strong/info.dart
@@ -14,6 +14,25 @@
 
 import 'rules.dart';
 
+// A down cast due to a variable declaration to a ground type.  E.g.,
+//   T x = expr;
+// where T is ground.  We exclude non-ground types as these behave differently
+// compared to standard Dart.
+class AssignmentCast extends DownCast {
+  AssignmentCast(TypeRules rules, Expression expression, Cast cast)
+      : super._internal(rules, expression, cast);
+
+  @override
+  String get name => 'STRONG_MODE_ASSIGNMENT_CAST';
+
+  toErrorCode() => new HintCode(name, message);
+}
+
+// Coercion which casts one type to another
+class Cast extends Coercion {
+  Cast(DartType fromType, DartType toType) : super(fromType, toType);
+}
+
 // The abstract type of coercions mapping one type to another.
 // This class also exposes static builder functions which
 // check for errors and reduce redundant coercions to the identity.
@@ -22,18 +41,8 @@
   final DartType toType;
   Coercion(this.fromType, this.toType);
   static Coercion cast(DartType fromT, DartType toT) => new Cast(fromT, toT);
-  static Coercion identity(DartType type) => new Identity(type);
   static Coercion error() => new CoercionError();
-}
-
-// Coercion which casts one type to another
-class Cast extends Coercion {
-  Cast(DartType fromType, DartType toType) : super(fromType, toType);
-}
-
-// The identity coercion
-class Identity extends Coercion {
-  Identity(DartType fromType) : super(fromType, fromType);
+  static Coercion identity(DartType type) => new Identity(type);
 }
 
 // The error coercion.  This coercion signals that a coercion
@@ -43,50 +52,23 @@
   CoercionError() : super(null, null);
 }
 
-// TODO(jmesserly): this could use some refactoring. These are essentially
-// like ErrorCodes in analyzer, but we're including some details in our message.
-// Analyzer instead has template strings, and replaces '{0}' with the first
-// argument.
-abstract class StaticInfo {
-  /// AST Node this info is attached to.
-  AstNode get node;
-
-  // TODO(jmesserly): review the usage of error codes. We probably want our own,
-  // as well as some DDC specific [ErrorType]s.
-  ErrorCode toErrorCode();
-
-  // TODO(jmesserly): what convention to use here?
-  String get name => 'dev_compiler.$runtimeType';
-
-  List<Object> get arguments => [node];
-
-  AnalysisError toAnalysisError() {
-    int begin = node is AnnotatedNode
-        ? (node as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset
-        : node.offset;
-    int length = node.end - begin;
-    var source = (node.root as CompilationUnit).element.source;
-    return new AnalysisError(source, begin, length, toErrorCode(), arguments);
-  }
-}
-
 /// Implicitly injected expression conversion.
 abstract class CoercionInfo extends StaticInfo {
+  static const String _propertyName = 'dev_compiler.src.info.CoercionInfo';
+
   final TypeRules rules;
 
   final Expression node;
 
-  DartType get convertedType;
-
   CoercionInfo(this.rules, this.node);
 
   DartType get baseType => rules.getStaticType(node);
-  DartType get staticType => convertedType;
+  DartType get convertedType;
 
   String get message;
-  toErrorCode() => new HintCode(name, message);
+  DartType get staticType => convertedType;
 
-  static const String _propertyName = 'dev_compiler.src.info.CoercionInfo';
+  toErrorCode() => new HintCode(name, message);
 
   /// Gets the coercion info associated with this node.
   static CoercionInfo get(AstNode node) => node.getProperty(_propertyName);
@@ -112,11 +94,11 @@
             baseType.isAssignableTo(_cast.toType)));
   }
 
+  @override List<Object> get arguments => [node, baseType, convertedType];
+
   Cast get cast => _cast;
 
   DartType get convertedType => _cast.toType;
-
-  @override List<Object> get arguments => [node, baseType, convertedType];
   @override String get message => '{0} ({1}) will need runtime check '
       'to cast to type {2}';
 
@@ -195,55 +177,17 @@
 }
 
 //
-// Standard down casts.  These casts are implicitly injected by the compiler.
-//
-
-// A down cast from dynamic to T.
-class DynamicCast extends DownCast {
-  DynamicCast(TypeRules rules, Expression expression, Cast cast)
-      : super._internal(rules, expression, cast);
-
-  toErrorCode() => new HintCode(name, message);
-}
-
-// A down cast due to a variable declaration to a ground type.  E.g.,
-//   T x = expr;
-// where T is ground.  We exclude non-ground types as these behave differently
-// compared to standard Dart.
-class AssignmentCast extends DownCast {
-  AssignmentCast(TypeRules rules, Expression expression, Cast cast)
-      : super._internal(rules, expression, cast);
-
-  toErrorCode() => new HintCode(name, message);
-}
-
-//
-// Temporary "casts" of allocation sites - literals, constructor invocations,
-// and closures.  These should be handled by contextual inference.  In most
-// cases, inference will be sufficient, though in some it may unmask an actual
-// error: e.g.,
-//   List<int> l = [1, 2, 3]; // Inference succeeds
-//   List<String> l = [1, 2, 3]; // Inference reveals static type error
-// We're marking all as warnings for now.
-//
-// TODO(vsm,leafp): Remove this.
-class UninferredClosure extends DownCast {
-  UninferredClosure(TypeRules rules, FunctionExpression expression, Cast cast)
-      : super._internal(rules, expression, cast);
-
-  toErrorCode() => new StaticTypeWarningCode(name, message);
-}
-
-//
 // Implicit down casts.  These are only injected by the compiler by flag.
 //
-
 // A down cast to a non-ground type.  These behave differently from standard
 // Dart and may be more likely to fail at runtime.
 class DownCastComposite extends DownCast {
   DownCastComposite(TypeRules rules, Expression expression, Cast cast)
       : super._internal(rules, expression, cast);
 
+  @override
+  String get name => 'STRONG_MODE_DOWN_CAST_COMPOSITE';
+
   toErrorCode() => new StaticTypeWarningCode(name, message);
 }
 
@@ -253,30 +197,64 @@
   DownCastImplicit(TypeRules rules, Expression expression, Cast cast)
       : super._internal(rules, expression, cast);
 
+  @override
+  String get name => 'STRONG_MODE_DOWN_CAST_IMPLICIT';
+
   toErrorCode() => new HintCode(name, message);
 }
 
-// An inferred type for the wrapped expression, which may need to be
-// reified into the term
-abstract class InferredTypeBase extends CoercionInfo {
-  final DartType _type;
+// A down cast from dynamic to T.
+class DynamicCast extends DownCast {
+  DynamicCast(TypeRules rules, Expression expression, Cast cast)
+      : super._internal(rules, expression, cast);
 
-  InferredTypeBase._internal(TypeRules rules, Expression expression, this._type)
-      : super(rules, expression);
-
-  DartType get type => _type;
-  DartType get convertedType => type;
-  @override String get message => '{0} has inferred type {1}';
-  @override List get arguments => [node, type];
+  @override
+  String get name => 'STRONG_MODE_DYNAMIC_CAST';
 
   toErrorCode() => new HintCode(name, message);
 }
 
+class DynamicInvoke extends CoercionInfo {
+  static const String _propertyName = 'dev_compiler.src.info.DynamicInvoke';
+
+  DynamicInvoke(TypeRules rules, Expression expression)
+      : super(rules, expression);
+  DartType get convertedType => rules.provider.dynamicType;
+  String get message => '{0} requires dynamic invoke';
+
+  @override
+  String get name => 'STRONG_MODE_DYNAMIC_INVOKE';
+
+  toErrorCode() => new HintCode(name, message);
+
+  /// Whether this [node] is the target of a dynamic operation.
+  static bool get(AstNode node) {
+    var value = node.getProperty(_propertyName);
+    return value != null ? value : false;
+  }
+
+  /// Sets whether this node is the target of a dynamic operation.
+  static bool set(AstNode node, bool value) {
+    // Free the storage for things that aren't dynamic.
+    if (value == false) value = null;
+    node.setProperty(_propertyName, value);
+    return value;
+  }
+}
+
+// The identity coercion
+class Identity extends Coercion {
+  Identity(DartType fromType) : super(fromType, fromType);
+}
+
 // Standard / unspecialized inferred type
 class InferredType extends InferredTypeBase {
   InferredType(TypeRules rules, Expression expression, DartType type)
       : super._internal(rules, expression, type);
 
+  @override
+  String get name => 'STRONG_MODE_INFERRED_TYPE';
+
   // Factory to create correct InferredType variant.
   static InferredTypeBase create(
       TypeRules rules, Expression expression, DartType type) {
@@ -294,110 +272,72 @@
   }
 }
 
-// An infered type for a literal expression.
-class InferredTypeLiteral extends InferredTypeBase {
-  InferredTypeLiteral(TypeRules rules, Expression expression, DartType type)
-      : super._internal(rules, expression, type);
-}
-
 // An inferred type for a non-literal allocation site.
 class InferredTypeAllocation extends InferredTypeBase {
   InferredTypeAllocation(TypeRules rules, Expression expression, DartType type)
       : super._internal(rules, expression, type);
+
+  @override
+  String get name => 'STRONG_MODE_INFERRED_TYPE_ALLOCATION';
+}
+
+// An inferred type for the wrapped expression, which may need to be
+// reified into the term
+abstract class InferredTypeBase extends CoercionInfo {
+  final DartType _type;
+
+  InferredTypeBase._internal(TypeRules rules, Expression expression, this._type)
+      : super(rules, expression);
+
+  @override List get arguments => [node, type];
+  DartType get convertedType => type;
+  @override String get message => '{0} has inferred type {1}';
+  DartType get type => _type;
+
+  toErrorCode() => new HintCode(name, message);
 }
 
 // An inferred type for a closure expression
 class InferredTypeClosure extends InferredTypeBase {
   InferredTypeClosure(TypeRules rules, Expression expression, DartType type)
       : super._internal(rules, expression, type);
+
+  @override
+  String get name => 'STRONG_MODE_INFERRED_TYPE_CLOSURE';
 }
 
-class DynamicInvoke extends CoercionInfo {
-  DynamicInvoke(TypeRules rules, Expression expression)
-      : super(rules, expression);
+// An inferred type for a literal expression.
+class InferredTypeLiteral extends InferredTypeBase {
+  InferredTypeLiteral(TypeRules rules, Expression expression, DartType type)
+      : super._internal(rules, expression, type);
 
-  DartType get convertedType => rules.provider.dynamicType;
-  String get message => '{0} requires dynamic invoke';
-  toErrorCode() => new HintCode(name, message);
-
-  static const String _propertyName = 'dev_compiler.src.info.DynamicInvoke';
-
-  /// Whether this [node] is the target of a dynamic operation.
-  static bool get(AstNode node) {
-    var value = node.getProperty(_propertyName);
-    return value != null ? value : false;
-  }
-
-  /// Sets whether this node is the target of a dynamic operation.
-  static bool set(AstNode node, bool value) {
-    // Free the storage for things that aren't dynamic.
-    if (value == false) value = null;
-    node.setProperty(_propertyName, value);
-    return value;
-  }
+  @override
+  String get name => 'STRONG_MODE_INFERRED_TYPE_LITERAL';
 }
 
-abstract class StaticError extends StaticInfo {
-  final AstNode node;
+class InvalidFieldOverride extends InvalidOverride {
+  InvalidFieldOverride(AstNode node, ExecutableElement element,
+      InterfaceType base, DartType subType, DartType baseType)
+      : super(node, element, base, subType, baseType);
 
-  StaticError(this.node);
+  String get message => 'Field declaration {3}.{1} cannot be '
+      'overridden in {0}.';
 
-  String get message;
-
-  toErrorCode() => new CompileTimeErrorCode(name, message);
+  @override
+  String get name => 'STRONG_MODE_INVALID_FIELD_OVERRIDE';
 }
 
-class StaticTypeError extends StaticError {
-  final DartType baseType;
-  final DartType expectedType;
-  String reason = null;
+// Invalid override due to incompatible type.  I.e., the overridden signature
+// is not compatible with the original.
+class InvalidMethodOverride extends InvalidOverride {
+  InvalidMethodOverride(AstNode node, ExecutableElement element,
+      InterfaceType base, FunctionType subType, FunctionType baseType)
+      : super(node, element, base, subType, baseType);
 
-  StaticTypeError(TypeRules rules, Expression expression, this.expectedType,
-      {this.reason})
-      : baseType = rules.getStaticType(expression),
-        super(expression);
+  String get message => _messageHelper('Invalid override');
 
-  @override List<Object> get arguments => [node, baseType, expectedType];
-  @override String get message =>
-      'Type check failed: {0} ({1}) is not of type {2}' +
-          ((reason == null) ? '' : ' because $reason');
-}
-
-class InvalidVariableDeclaration extends StaticError {
-  final DartType expectedType;
-
-  InvalidVariableDeclaration(
-      TypeRules rules, AstNode declaration, this.expectedType)
-      : super(declaration);
-
-  @override List<Object> get arguments => [expectedType];
-  @override String get message => 'Type check failed: null is not of type {0}';
-}
-
-class InvalidParameterDeclaration extends StaticError {
-  final DartType expectedType;
-
-  InvalidParameterDeclaration(
-      TypeRules rules, FormalParameter declaration, this.expectedType)
-      : super(declaration);
-
-  @override List<Object> get arguments => [node, expectedType];
-  @override String get message => 'Type check failed: {0} is not of type {1}';
-}
-
-class NonGroundTypeCheckInfo extends StaticInfo {
-  final DartType type;
-  final AstNode node;
-
-  NonGroundTypeCheckInfo(this.node, this.type) {
-    assert(node is IsExpression || node is AsExpression);
-  }
-
-  @override List<Object> get arguments => [type];
-  String get message =>
-      "Runtime check on non-ground type {0} may throw StrongModeError";
-
-  toErrorCode() => new HintCode(name, message);
+  @override
+  String get name => 'STRONG_MODE_INVALID_METHOD_OVERRIDE';
 }
 
 // Invalid override of an instance member of a class.
@@ -427,11 +367,11 @@
         fromMixin = node.parent is WithClause,
         super(node);
 
-  ClassElement get parent => element.enclosingElement;
-
   @override List<Object> get arguments =>
       [parent.name, element.name, subType, base, baseType];
 
+  ClassElement get parent => element.enclosingElement;
+
   String _messageHelper(String errorName) {
     var lcErrorName = errorName.toLowerCase();
     var intro = fromBaseClass
@@ -442,23 +382,17 @@
   }
 }
 
-// Invalid override due to incompatible type.  I.e., the overridden signature
-// is not compatible with the original.
-class InvalidMethodOverride extends InvalidOverride {
-  InvalidMethodOverride(AstNode node, ExecutableElement element,
-      InterfaceType base, FunctionType subType, FunctionType baseType)
-      : super(node, element, base, subType, baseType);
+class InvalidParameterDeclaration extends StaticError {
+  final DartType expectedType;
 
-  String get message => _messageHelper('Invalid override');
-}
+  InvalidParameterDeclaration(
+      TypeRules rules, FormalParameter declaration, this.expectedType)
+      : super(declaration);
 
-class InvalidFieldOverride extends InvalidOverride {
-  InvalidFieldOverride(AstNode node, ExecutableElement element,
-      InterfaceType base, DartType subType, DartType baseType)
-      : super(node, element, base, subType, baseType);
-
-  String get message => 'Field declaration {3}.{1} cannot be '
-      'overridden in {0}.';
+  @override List<Object> get arguments => [node, expectedType];
+  @override String get message => 'Type check failed: {0} is not of type {1}';
+  @override
+  String get name => 'STRONG_MODE_INVALID_PARAMETER_DECLARATION';
 }
 
 /// Dart constructors have one weird quirk, illustrated with this example:
@@ -495,4 +429,140 @@
 
   @override String get message => "super call must be last in an initializer "
       "list (see http://goo.gl/q1T4BB): {0}";
+
+  @override
+  String get name => 'STRONG_MODE_INVALID_SUPER_INVOCATION';
+}
+
+class InvalidVariableDeclaration extends StaticError {
+  final DartType expectedType;
+
+  InvalidVariableDeclaration(
+      TypeRules rules, AstNode declaration, this.expectedType)
+      : super(declaration);
+
+  @override List<Object> get arguments => [expectedType];
+  @override String get message => 'Type check failed: null is not of type {0}';
+
+  @override
+  String get name => 'STRONG_MODE_INVALID_VARIABLE_DECLARATION';
+}
+
+class NonGroundTypeCheckInfo extends StaticInfo {
+  final DartType type;
+  final AstNode node;
+
+  NonGroundTypeCheckInfo(this.node, this.type) {
+    assert(node is IsExpression || node is AsExpression);
+  }
+
+  @override List<Object> get arguments => [type];
+  String get message =>
+      "Runtime check on non-ground type {0} may throw StrongModeError";
+
+  @override
+  String get name => 'STRONG_MODE_NON_GROUND_TYPE_CHECK_INFO';
+
+  toErrorCode() => new HintCode(name, message);
+}
+
+abstract class StaticError extends StaticInfo {
+  final AstNode node;
+
+  StaticError(this.node);
+
+  String get message;
+
+  toErrorCode() => new CompileTimeErrorCode(name, message);
+}
+
+// TODO(jmesserly): this could use some refactoring. These are essentially
+// like ErrorCodes in analyzer, but we're including some details in our message.
+// Analyzer instead has template strings, and replaces '{0}' with the first
+// argument.
+abstract class StaticInfo {
+  /// Strong-mode error code names.
+  ///
+  /// Used for error code configuration validation in `.analysis_options`.
+  static const List<String> names = const [
+    //
+    // Manually populated.
+    //
+    'STRONG_MODE_ASSIGNMENT_CAST',
+    'STRONG_MODE_DOWN_CAST_COMPOSITE',
+    'STRONG_MODE_DOWN_CAST_IMPLICIT',
+    'STRONG_MODE_DYNAMIC_CAST',
+    'STRONG_MODE_DYNAMIC_INVOKE',
+    'STRONG_MODE_INFERRED_TYPE',
+    'STRONG_MODE_INFERRED_TYPE_ALLOCATION',
+    'STRONG_MODE_INFERRED_TYPE_CLOSURE',
+    'STRONG_MODE_INFERRED_TYPE_LITERAL',
+    'STRONG_MODE_INVALID_FIELD_OVERRIDE',
+    'STRONG_MODE_INVALID_METHOD_OVERRIDE',
+    'STRONG_MODE_INVALID_PARAMETER_DECLARATION',
+    'STRONG_MODE_INVALID_SUPER_INVOCATION',
+    'STRONG_MODE_INVALID_VARIABLE_DECLARATION',
+    'STRONG_MODE_NON_GROUND_TYPE_CHECK_INFO',
+    'STRONG_MODE_STATIC_TYPE_ERROR',
+    'STRONG_MODE_UNINFERRED_CLOSURE',
+  ];
+
+  List<Object> get arguments => [node];
+
+  String get name;
+
+  /// AST Node this info is attached to.
+  AstNode get node;
+
+  AnalysisError toAnalysisError() {
+    int begin = node is AnnotatedNode
+        ? (node as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset
+        : node.offset;
+    int length = node.end - begin;
+    var source = (node.root as CompilationUnit).element.source;
+    return new AnalysisError(source, begin, length, toErrorCode(), arguments);
+  }
+
+  // TODO(jmesserly): review the usage of error codes. We probably want our own,
+  // as well as some DDC specific [ErrorType]s.
+  ErrorCode toErrorCode();
+}
+
+class StaticTypeError extends StaticError {
+  final DartType baseType;
+  final DartType expectedType;
+  String reason = null;
+
+  StaticTypeError(TypeRules rules, Expression expression, this.expectedType,
+      {this.reason})
+      : baseType = rules.getStaticType(expression),
+        super(expression);
+
+  @override List<Object> get arguments => [node, baseType, expectedType];
+  @override String get message =>
+      'Type check failed: {0} ({1}) is not of type {2}' +
+          ((reason == null) ? '' : ' because $reason');
+
+  @override
+  String get name => 'STRONG_MODE_STATIC_TYPE_ERROR';
+}
+
+//
+// Temporary "casts" of allocation sites - literals, constructor invocations,
+// and closures.  These should be handled by contextual inference.  In most
+// cases, inference will be sufficient, though in some it may unmask an actual
+// error: e.g.,
+//   List<int> l = [1, 2, 3]; // Inference succeeds
+//   List<String> l = [1, 2, 3]; // Inference reveals static type error
+// We're marking all as warnings for now.
+//
+// TODO(vsm,leafp): Remove this.
+class UninferredClosure extends DownCast {
+  UninferredClosure(TypeRules rules, FunctionExpression expression, Cast cast)
+      : super._internal(rules, expression, cast);
+
+  @override
+  String get name => 'STRONG_MODE_UNINFERRED_CLOSURE';
+
+  toErrorCode() => new StaticTypeWarningCode(name, message);
 }
diff --git a/pkg/analyzer/lib/src/task/strong/rules.dart b/pkg/analyzer/lib/src/task/strong/rules.dart
index 32236a8..909a6fb 100644
--- a/pkg/analyzer/lib/src/task/strong/rules.dart
+++ b/pkg/analyzer/lib/src/task/strong/rules.dart
@@ -321,6 +321,10 @@
       return false;
     }
 
+    if (t1.isVoid || t2.isVoid) {
+      return false;
+    }
+
     if (t2.isDartCoreFunction) {
       if (t1 is FunctionType) return true;
       if (t1.element is ClassElement) {
@@ -421,6 +425,7 @@
     var reason = null;
 
     var errors = <String>[];
+
     var ok = inferrer.inferExpression(expr, toT, errors);
     if (ok) return InferredType.create(this, expr, toT);
     reason = (errors.isNotEmpty) ? errors.first : null;
@@ -508,264 +513,12 @@
   /// Downward inference
   bool _inferExpression(Expression e, DartType t, List<String> errors,
       {cast: true}) {
-    if (e is ConditionalExpression) {
-      return _inferConditionalExpression(e, t, errors);
-    }
-    if (e is ParenthesizedExpression) {
-      return _inferParenthesizedExpression(e, t, errors);
-    }
     if (rules.isSubTypeOf(rules.getStaticType(e), t)) return true;
     if (cast && rules.getStaticType(e).isDynamic) {
       annotateCastFromDynamic(e, t);
       return true;
     }
-    if (e is FunctionExpression) return _inferFunctionExpression(e, t, errors);
-    if (e is ListLiteral) return _inferListLiteral(e, t, errors);
-    if (e is MapLiteral) return _inferMapLiteral(e, t, errors);
-    if (e is NamedExpression) return _inferNamedExpression(e, t, errors);
-    if (e is InstanceCreationExpression) {
-      return _inferInstanceCreationExpression(e, t, errors);
-    }
     errors.add("$e cannot be typed as $t");
     return false;
   }
-
-  /// If t1 = I<dynamic, ..., dynamic>, then look for a supertype
-  /// of t1 of the form K<S0, ..., Sm> where t2 = K<S0', ..., Sm'>
-  /// If the supertype exists, use the constraints S0 <: S0', ... Sm <: Sm'
-  /// to derive a concrete instantation for I of the form <T0, ..., Tn>,
-  /// such that I<T0, .., Tn> <: t2
-  List<DartType> _matchTypes(InterfaceType t1, InterfaceType t2) {
-    if (t1 == t2) return t2.typeArguments;
-    var tArgs1 = t1.typeArguments;
-    var tArgs2 = t2.typeArguments;
-    // If t1 isn't a raw type, bail out
-    if (tArgs1 != null && tArgs1.any((t) => !t.isDynamic)) return null;
-
-    // This is our inferred type argument list.  We start at all dynamic,
-    // and fill in with inferred types when we reach a match.
-    var actuals =
-        new List<DartType>.filled(tArgs1.length, rules.provider.dynamicType);
-
-    // When we find the supertype of t1 with the same
-    // classname as t2 (see below), we have the following:
-    // If t1 is an instantiation of a class T1<X0, ..., Xn>
-    // and t2 is an instantiation of a class T2<Y0, ...., Ym>
-    // of the form t2 = T2<S0, ..., Sm>
-    // then we want to choose instantiations for the Xi
-    // T0, ..., Tn such that T1<T0, ..., Tn> <: t2 .
-    // To find this, we simply instantate T1 with
-    // X0, ..., Xn, and then find its superclass
-    // T2<T0', ..., Tn'>.  We then solve the constraint
-    // set T0' <: S0, ..., Tn' <: Sn for the Xi.
-    // Currently, we only handle constraints where
-    // the Ti' is one of the Xi'.  If there are multiple
-    // constraints on some Xi, we choose the lower of the
-    // two (if it exists).
-    bool permute(List<DartType> permutedArgs) {
-      if (permutedArgs == null) return false;
-      var ps = t1.typeParameters;
-      var ts = ps.map((p) => p.type).toList();
-      for (int i = 0; i < permutedArgs.length; i++) {
-        var tVar = permutedArgs[i];
-        var tActual = tArgs2[i];
-        var index = ts.indexOf(tVar);
-        if (index >= 0 && rules.isSubTypeOf(tActual, actuals[index])) {
-          actuals[index] = tActual;
-        }
-      }
-      return actuals.any((x) => !x.isDynamic);
-    }
-
-    // Look for the first supertype of t1 with the same class name as t2.
-    bool match(InterfaceType t1) {
-      if (t1.element == t2.element) {
-        return permute(t1.typeArguments);
-      }
-
-      if (t1 == rules.provider.objectType) return false;
-
-      if (match(t1.superclass)) return true;
-
-      for (final parent in t1.interfaces) {
-        if (match(parent)) return true;
-      }
-
-      for (final parent in t1.mixins) {
-        if (match(parent)) return true;
-      }
-      return false;
-    }
-
-    // We have that t1 = T1<dynamic, ..., dynamic>.
-    // To match t1 against t2, we use the uninstantiated version
-    // of t1, essentially treating it as an instantiation with
-    // fresh variables, and solve for the variables.
-    // t1.element.type will be of the form T1<X0, ..., Xn>
-    if (!match(t1.element.type)) return null;
-    var newT1 = t1.element.type.substitute4(actuals);
-    // If we found a solution, return it.
-    if (rules.isSubTypeOf(newT1, t2)) return actuals;
-    return null;
-  }
-
-  /// These assume that e is not already a subtype of t
-
-  bool _inferConditionalExpression(
-      ConditionalExpression e, DartType t, errors) {
-    return _inferExpression(e.thenExpression, t, errors) &&
-        _inferExpression(e.elseExpression, t, errors);
-  }
-
-  bool _inferParenthesizedExpression(
-      ParenthesizedExpression e, DartType t, errors) {
-    return _inferExpression(e.expression, t, errors);
-  }
-
-  bool _inferInstanceCreationExpression(
-      InstanceCreationExpression e, DartType t, errors) {
-    var arguments = e.argumentList.arguments;
-    var rawType = rules.getStaticType(e);
-    // rawType is the instantiated type of the instance
-    if (rawType is! InterfaceType) return false;
-    var type = (rawType as InterfaceType);
-    if (type.typeParameters == null ||
-        type.typeParameters.length == 0) return false;
-    if (e.constructorName.type == null) return false;
-    // classTypeName is the type name of the class being instantiated
-    var classTypeName = e.constructorName.type;
-    // Check that we were not passed any type arguments
-    if (classTypeName.typeArguments != null) return false;
-    // Infer type arguments
-    if (t is! InterfaceType) return false;
-    var targs = _matchTypes(type, t);
-    if (targs == null) return false;
-    if (e.staticElement == null) return false;
-    var constructorElement = e.staticElement;
-    // From the constructor element get:
-    //  the instantiated type of the constructor, then
-    //     the uninstantiated element for the constructor, then
-    //        the uninstantiated type for the constructor
-    var rawConstructorElement =
-        constructorElement.type.element as ConstructorElement;
-    var baseType = rawConstructorElement.type;
-    if (baseType == null) return false;
-    // From the interface type (instantiated), get:
-    //  the uninstantiated element, then
-    //    the uninstantiated type, then
-    //      the type arguments (aka the type parameters)
-    var tparams = type.element.type.typeArguments;
-    // Take the uninstantiated constructor type, and replace the type
-    // parameters with the inferred arguments.
-    var fType = baseType.substitute2(targs, tparams);
-    {
-      var rTypes = fType.normalParameterTypes;
-      var oTypes = fType.optionalParameterTypes;
-      var pTypes = new List.from(rTypes)..addAll(oTypes);
-      var pArgs = arguments.where((x) => x is! NamedExpression);
-      var pi = 0;
-      for (var arg in pArgs) {
-        if (pi >= pTypes.length) return false;
-        var argType = pTypes[pi];
-        if (!_inferExpression(arg, argType, errors)) return false;
-        pi++;
-      }
-      var nTypes = fType.namedParameterTypes;
-      for (var arg0 in arguments) {
-        if (arg0 is! NamedExpression) continue;
-        var arg = arg0 as NamedExpression;
-        SimpleIdentifier nameNode = arg.name.label;
-        String name = nameNode.name;
-        var argType = nTypes[name];
-        if (argType == null) return false;
-        if (!_inferExpression(arg, argType, errors)) return false;
-      }
-    }
-    annotateInstanceCreationExpression(e, targs);
-    return true;
-  }
-
-  bool _inferNamedExpression(NamedExpression e, DartType t, errors) {
-    return _inferExpression(e.expression, t, errors);
-  }
-
-  bool _inferFunctionExpression(FunctionExpression e, DartType t, errors) {
-    if (t is! FunctionType) return false;
-    var fType = t as FunctionType;
-    var eType = e.staticType as FunctionType;
-    if (eType is! FunctionType) return false;
-
-    // We have a function literal, so we can treat the arrow type
-    // as non-fuzzy.  Since we're not improving on parameter types
-    // currently, if this check fails then we cannot succeed, so
-    // bail out.  Otherwise, we never need to check the parameter types
-    // again.
-    if (!rules.isFunctionSubTypeOf(eType, fType,
-        fuzzyArrows: false, ignoreReturn: true)) return false;
-
-    // This only entered inference because of fuzzy typing.
-    // The function type is already specific enough, we can just
-    // succeed and treat it as a successful inference
-    if (rules.isSubTypeOf(eType.returnType, fType.returnType)) return true;
-
-    // Fuzzy typing again, handle the void case (not caught by the previous)
-    if (fType.returnType.isVoid) return true;
-
-    if (e.body is! ExpressionFunctionBody) return false;
-    var body = (e.body as ExpressionFunctionBody).expression;
-    if (!_inferExpression(body, fType.returnType, errors)) return false;
-
-    // TODO(leafp): Try narrowing the argument types if possible
-    // to get better code in the function body.  This requires checking
-    // that the body is well-typed at the more specific type.
-
-    // At this point, we know that the parameter types are in the appropriate subtype
-    // relation, and we have checked that we can type the body at the appropriate return
-    // type, so we can are done.
-    annotateFunctionExpression(e, fType.returnType);
-    return true;
-  }
-
-  bool _inferListLiteral(ListLiteral e, DartType t, errors) {
-    var dyn = rules.provider.dynamicType;
-    var listT = rules.provider.listType.substitute4([dyn]);
-    // List <: t (using dart rules) must be true
-    if (!listT.isSubtypeOf(t)) return false;
-    // The list literal must have no type arguments
-    if (e.typeArguments != null) return false;
-    if (t is! InterfaceType) return false;
-    var targs = _matchTypes(listT, t);
-    if (targs == null) return false;
-    assert(targs.length == 1);
-    var etype = targs[0];
-    assert(!etype.isDynamic);
-    var elements = e.elements;
-    var b = elements.every((e) => _inferExpression(e, etype, errors));
-    if (b) annotateListLiteral(e, targs);
-    return b;
-  }
-
-  bool _inferMapLiteral(MapLiteral e, DartType t, errors) {
-    var dyn = rules.provider.dynamicType;
-    var mapT = rules.provider.mapType.substitute4([dyn, dyn]);
-    // Map <: t (using dart rules) must be true
-    if (!mapT.isSubtypeOf(t)) return false;
-    // The map literal must have no type arguments
-    if (e.typeArguments != null) return false;
-    if (t is! InterfaceType) return false;
-    var targs = _matchTypes(mapT, t);
-    if (targs == null) return false;
-    assert(targs.length == 2);
-    var kType = targs[0];
-    var vType = targs[1];
-    assert(!(kType.isDynamic && vType.isDynamic));
-    var entries = e.entries;
-    bool inferEntry(MapLiteralEntry entry) {
-      return _inferExpression(entry.key, kType, errors) &&
-          _inferExpression(entry.value, vType, errors);
-    }
-    var b = entries.every(inferEntry);
-    if (b) annotateMapLiteral(e, targs);
-    return b;
-  }
 }
diff --git a/pkg/analyzer/lib/task/model.dart b/pkg/analyzer/lib/task/model.dart
index af67453..c7d0c57 100644
--- a/pkg/analyzer/lib/task/model.dart
+++ b/pkg/analyzer/lib/task/model.dart
@@ -350,7 +350,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-abstract class ListTaskInput<E> extends TaskInput<List<E>> {
+abstract class ListTaskInput<E> implements TaskInput<List<E>> {
   /**
    * Return a task input that can be used to compute a flatten list whose
    * elements are combined [subListResult]'s associated with those elements.
@@ -392,7 +392,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-abstract class MapTaskInput<K, V> extends TaskInput<Map<K, V>> {
+abstract class MapTaskInput<K, V> implements TaskInput<Map<K, V>> {
   /**
    * [V] must be a [List].
    * Return a task input that can be used to compute a list whose elements are
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 1973fb9..a3c4b51 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 0.26.2+1
+version: 0.26.3
 author: Dart Team <misc@dartlang.org>
 description: Static analyzer for Dart.
 homepage: http://www.dartlang.org
diff --git a/pkg/analyzer/test/generated/ast_test.dart b/pkg/analyzer/test/generated/ast_test.dart
index e25c253..947ca7f 100644
--- a/pkg/analyzer/test/generated/ast_test.dart
+++ b/pkg/analyzer/test/generated/ast_test.dart
@@ -29,6 +29,7 @@
   runReflectiveTests(IndexExpressionTest);
   runReflectiveTests(NodeListTest);
   runReflectiveTests(NodeLocatorTest);
+  runReflectiveTests(NodeLocator2Test);
   runReflectiveTests(SimpleIdentifierTest);
   runReflectiveTests(SimpleStringLiteralTest);
   runReflectiveTests(StringInterpolationTest);
@@ -945,6 +946,50 @@
 }
 
 @reflectiveTest
+class NodeLocator2Test extends ParserTestCase {
+  void test_onlyStartOffset() {
+    String code = ' int vv; ';
+    //             012345678
+    CompilationUnit unit = ParserTestCase.parseCompilationUnit(code);
+    TopLevelVariableDeclaration declaration = unit.declarations[0];
+    VariableDeclarationList variableList = declaration.variables;
+    Identifier typeName = variableList.type.name;
+    SimpleIdentifier varName = variableList.variables[0].name;
+    expect(new NodeLocator2(0).searchWithin(unit), same(unit));
+    expect(new NodeLocator2(1).searchWithin(unit), same(typeName));
+    expect(new NodeLocator2(2).searchWithin(unit), same(typeName));
+    expect(new NodeLocator2(3).searchWithin(unit), same(typeName));
+    expect(new NodeLocator2(4).searchWithin(unit), same(variableList));
+    expect(new NodeLocator2(5).searchWithin(unit), same(varName));
+    expect(new NodeLocator2(6).searchWithin(unit), same(varName));
+    expect(new NodeLocator2(7).searchWithin(unit), same(declaration));
+    expect(new NodeLocator2(8).searchWithin(unit), same(unit));
+    expect(new NodeLocator2(9).searchWithin(unit), isNull);
+    expect(new NodeLocator2(100).searchWithin(unit), isNull);
+  }
+
+  void test_startEndOffset() {
+    String code = ' int vv; ';
+    //             012345678
+    CompilationUnit unit = ParserTestCase.parseCompilationUnit(code);
+    TopLevelVariableDeclaration declaration = unit.declarations[0];
+    VariableDeclarationList variableList = declaration.variables;
+    Identifier typeName = variableList.type.name;
+    SimpleIdentifier varName = variableList.variables[0].name;
+    expect(new NodeLocator2(-1, 2).searchWithin(unit), isNull);
+    expect(new NodeLocator2(0, 2).searchWithin(unit), same(unit));
+    expect(new NodeLocator2(1, 2).searchWithin(unit), same(typeName));
+    expect(new NodeLocator2(1, 3).searchWithin(unit), same(typeName));
+    expect(new NodeLocator2(1, 4).searchWithin(unit), same(variableList));
+    expect(new NodeLocator2(5, 6).searchWithin(unit), same(varName));
+    expect(new NodeLocator2(5, 7).searchWithin(unit), same(declaration));
+    expect(new NodeLocator2(5, 8).searchWithin(unit), same(unit));
+    expect(new NodeLocator2(5, 100).searchWithin(unit), isNull);
+    expect(new NodeLocator2(100, 200).searchWithin(unit), isNull);
+  }
+}
+
+@reflectiveTest
 class NodeLocatorTest extends ParserTestCase {
   void test_range() {
     CompilationUnit unit =
@@ -2290,6 +2335,13 @@
     _assertSource("continue;", AstFactory.continueStatement());
   }
 
+  void test_visitDefaultFormalParameter_annotation() {
+    DefaultFormalParameter parameter = AstFactory.positionalFormalParameter(
+        AstFactory.simpleFormalParameter3("p"), AstFactory.integer(0));
+    parameter.metadata.add(AstFactory.annotation(AstFactory.identifier3("A")));
+    _assertSource('@A p = 0', parameter);
+  }
+
   void test_visitDefaultFormalParameter_named_noValue() {
     _assertSource(
         "p",
@@ -2318,13 +2370,6 @@
             AstFactory.simpleFormalParameter3("p"), AstFactory.integer(0)));
   }
 
-  void test_visitDefaultFormalParameter_annotation() {
-    DefaultFormalParameter parameter = AstFactory.positionalFormalParameter(
-        AstFactory.simpleFormalParameter3("p"), AstFactory.integer(0));
-    parameter.metadata.add(AstFactory.annotation(AstFactory.identifier3("A")));
-    _assertSource('@A p = 0', parameter);
-  }
-
   void test_visitDoStatement() {
     _assertSource(
         "do {} while (c);",
@@ -2423,6 +2468,12 @@
     _assertSource("@deprecated var a;", declaration);
   }
 
+  void test_visitFieldFormalParameter_annotation() {
+    FieldFormalParameter parameter = AstFactory.fieldFormalParameter2('f');
+    parameter.metadata.add(AstFactory.annotation(AstFactory.identifier3("A")));
+    _assertSource('@A this.f', parameter);
+  }
+
   void test_visitFieldFormalParameter_functionTyped() {
     _assertSource(
         "A this.a(b)",
@@ -2467,12 +2518,6 @@
         AstFactory.fieldFormalParameter(null, AstFactory.typeName4("A"), "a"));
   }
 
-  void test_visitFieldFormalParameter_annotation() {
-    FieldFormalParameter parameter = AstFactory.fieldFormalParameter2('f');
-    parameter.metadata.add(AstFactory.annotation(AstFactory.identifier3("A")));
-    _assertSource('@A this.f', parameter);
-  }
-
   void test_visitForEachStatement_declared() {
     _assertSource(
         "for (var a in b) {}",
@@ -2907,16 +2952,17 @@
     _assertSource("@deprecated typedef A F();", declaration);
   }
 
-  void test_visitFunctionTypedFormalParameter_noType() {
-    _assertSource("f()", AstFactory.functionTypedFormalParameter(null, "f"));
-  }
-
   void test_visitFunctionTypedFormalParameter_annotation() {
-    FunctionTypedFormalParameter parameter = AstFactory.functionTypedFormalParameter(null, "f");
+    FunctionTypedFormalParameter parameter =
+        AstFactory.functionTypedFormalParameter(null, "f");
     parameter.metadata.add(AstFactory.annotation(AstFactory.identifier3("A")));
     _assertSource('@A f()', parameter);
   }
 
+  void test_visitFunctionTypedFormalParameter_noType() {
+    _assertSource("f()", AstFactory.functionTypedFormalParameter(null, "f"));
+  }
+
   void test_visitFunctionTypedFormalParameter_type() {
     _assertSource(
         "T f()",
@@ -3524,6 +3570,12 @@
     _assertSource(scriptTag, AstFactory.scriptTag(scriptTag));
   }
 
+  void test_visitSimpleFormalParameter_annotation() {
+    SimpleFormalParameter parameter = AstFactory.simpleFormalParameter3('x');
+    parameter.metadata.add(AstFactory.annotation(AstFactory.identifier3("A")));
+    _assertSource('@A x', parameter);
+  }
+
   void test_visitSimpleFormalParameter_keyword() {
     _assertSource("var a", AstFactory.simpleFormalParameter(Keyword.VAR, "a"));
   }
@@ -3540,12 +3592,6 @@
         AstFactory.simpleFormalParameter4(AstFactory.typeName4("A"), "a"));
   }
 
-  void test_visitSimpleFormalParameter_annotation() {
-    SimpleFormalParameter parameter = AstFactory.simpleFormalParameter3('x');
-    parameter.metadata.add(AstFactory.annotation(AstFactory.identifier3("A")));
-    _assertSource('@A x', parameter);
-  }
-
   void test_visitSimpleIdentifier() {
     _assertSource("a", AstFactory.identifier3("a"));
   }
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
index 851a4ee..154d448 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -1635,9 +1635,28 @@
 class A {}''');
     computeLibrarySourceErrors(librarySource);
     assertErrors(sourceB, [CompileTimeErrorCode.DUPLICATE_DEFINITION]);
+    assertNoErrors(librarySource);
     verify([librarySource, sourceA, sourceB]);
   }
 
+  void test_duplicateDefinition_inPart() {
+    Source librarySource = addNamedSource(
+        "/lib.dart",
+        r'''
+library test;
+part 'a.dart';
+class A {}''');
+    Source sourceA = addNamedSource(
+        "/a.dart",
+        r'''
+part of test;
+class A {}''');
+    computeLibrarySourceErrors(librarySource);
+    assertErrors(sourceA, [CompileTimeErrorCode.DUPLICATE_DEFINITION]);
+    assertNoErrors(librarySource);
+    verify([librarySource, sourceA]);
+  }
+
   void test_duplicateDefinition_catch() {
     Source source = addSource(r'''
 main() {
diff --git a/pkg/analyzer/test/generated/declaration_resolver_test.dart b/pkg/analyzer/test/generated/declaration_resolver_test.dart
new file mode 100644
index 0000000..a3d0b66
--- /dev/null
+++ b/pkg/analyzer/test/generated/declaration_resolver_test.dart
@@ -0,0 +1,98 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library engine.declaration_resolver_test;
+
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:unittest/unittest.dart';
+
+import '../reflective_tests.dart';
+import '../utils.dart';
+import 'resolver_test.dart';
+import 'test_support.dart';
+
+main() {
+  initializeTestEnvironment();
+  runReflectiveTests(DeclarationResolverTest);
+}
+
+@reflectiveTest
+class DeclarationResolverTest extends ResolverTestCase {
+  @override
+  void setUp() {
+    super.setUp();
+  }
+
+  void test_functionDeclaration_getter() {
+    String code = r'''
+int get zzz => 42;
+''';
+    CompilationUnit unit = resolveSource(code);
+    PropertyAccessorElement getterElement =
+        findSimpleIdentifier(unit, code, 'zzz =>').staticElement;
+    expect(getterElement.isGetter, isTrue);
+    // re-resolve
+    CompilationUnit unit2 = _cloneResolveUnit(unit);
+    SimpleIdentifier getterName = findSimpleIdentifier(unit2, code, 'zzz =>');
+    expect(getterName.staticElement, same(getterElement));
+  }
+
+  void test_functionDeclaration_setter() {
+    String code = r'''
+void set zzz(_) {}
+''';
+    CompilationUnit unit = resolveSource(code);
+    PropertyAccessorElement setterElement =
+        findSimpleIdentifier(unit, code, 'zzz(_)').staticElement;
+    expect(setterElement.isSetter, isTrue);
+    // re-resolve
+    CompilationUnit unit2 = _cloneResolveUnit(unit);
+    SimpleIdentifier getterName = findSimpleIdentifier(unit2, code, 'zzz(_)');
+    expect(getterName.staticElement, same(setterElement));
+  }
+
+  void test_invalid_functionDeclaration_getter_inFunction() {
+    String code = r'''
+main() {
+  int get zzz => 42;
+}
+''';
+    CompilationUnit unit = resolveSource(code);
+    FunctionElement getterElement =
+        findSimpleIdentifier(unit, code, 'zzz =>').staticElement;
+    // re-resolve
+    CompilationUnit unit2 = _cloneResolveUnit(unit);
+    SimpleIdentifier getterName = findSimpleIdentifier(unit2, code, 'zzz =>');
+    expect(getterName.staticElement, same(getterElement));
+  }
+
+  void test_invalid_functionDeclaration_setter_inFunction() {
+    String code = r'''
+main() {
+  set zzz(x) {}
+}
+''';
+    CompilationUnit unit = resolveSource(code);
+    FunctionElement setterElement =
+        findSimpleIdentifier(unit, code, 'zzz(x)').staticElement;
+    // re-resolve
+    CompilationUnit unit2 = _cloneResolveUnit(unit);
+    SimpleIdentifier setterName = findSimpleIdentifier(unit2, code, 'zzz(x)');
+    expect(setterName.staticElement, same(setterElement));
+  }
+
+  static SimpleIdentifier findSimpleIdentifier(
+      AstNode root, String code, String search) {
+    return EngineTestCase.findNode(
+        root, code, search, (n) => n is SimpleIdentifier);
+  }
+
+  static CompilationUnit _cloneResolveUnit(CompilationUnit unit) {
+    CompilationUnit clonedUnit = AstCloner.clone(unit);
+    new DeclarationResolver().resolve(clonedUnit, unit.element);
+    return clonedUnit;
+  }
+}
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index eaef165..dd9394c 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -5,9 +5,10 @@
 library engine.incremental_resolver_test;
 
 import 'package:analyzer/src/context/cache.dart' as task;
+import 'package:analyzer/src/context/cache.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
-import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/engine.dart' hide AnalysisCache;
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/incremental_logger.dart' as log;
 import 'package:analyzer/src/generated/incremental_resolution_validator.dart';
@@ -19,6 +20,7 @@
 import 'package:analyzer/src/generated/source_io.dart';
 import 'package:analyzer/src/generated/testing/ast_factory.dart';
 import 'package:analyzer/src/generated/testing/element_factory.dart';
+import 'package:analyzer/src/task/dart.dart';
 import 'package:analyzer/task/dart.dart';
 import 'package:unittest/unittest.dart';
 
@@ -3519,17 +3521,10 @@
 
   @override
   void setUp() {
-    AnalysisEngine.instance.useTaskModel = true;
     super.setUp();
     _resetWithIncremental(true);
   }
 
-  @override
-  void tearDown() {
-    super.tearDown();
-    AnalysisEngine.instance.useTaskModel = false;
-  }
-
   void test_computeConstants() {
     _resolveUnit(r'''
 int f() => 0;
@@ -4460,6 +4455,41 @@
 ''');
   }
 
+  void test_updateErrors_invalidVerifyErrors() {
+    _resolveUnit(r'''
+main() {
+  foo('aaa');
+}
+main2() {
+  foo('bbb');
+}
+foo(int p) {}
+''');
+    // Complete analysis, e.g. compute VERIFY_ERRORS.
+    _runTasks();
+    // Invalidate VERIFY_ERRORS.
+    AnalysisCache cache = analysisContext2.analysisCache;
+    LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+    task.CacheEntry cacheEntry = cache.get(target);
+    expect(cacheEntry.getValue(VERIFY_ERRORS), hasLength(2));
+    cacheEntry.setState(VERIFY_ERRORS, CacheState.INVALID);
+    // Don't run tasks, so don't recompute VERIFY_ERRORS before incremental.
+    _updateAndValidate(
+        r'''
+main() {
+  foo(0);
+}
+main2() {
+  foo('bbb');
+}
+foo(int p) {}
+''',
+        runTasksBeforeIncremental: false);
+    // Incremental analysis should have left VERIFY_ERRORS invalid,
+    // so it was correctly recomputed later during the full analysis.
+    expect(cacheEntry.getValue(VERIFY_ERRORS), hasLength(1));
+  }
+
   void test_updateErrors_removeExisting_hint() {
     _resolveUnit(r'''
 int main() {
@@ -4595,9 +4625,13 @@
   }
 
   void _updateAndValidate(String newCode,
-      {bool expectedSuccess: true, bool compareWithFull: true}) {
+      {bool expectedSuccess: true,
+      bool compareWithFull: true,
+      bool runTasksBeforeIncremental: true}) {
     // Run any pending tasks tasks.
-    _runTasks();
+    if (runTasksBeforeIncremental) {
+      _runTasks();
+    }
     // Update the source - currently this may cause incremental resolution.
     // Then request the updated resolved unit.
     _resetWithIncremental(true);
@@ -4613,7 +4647,8 @@
     // The existing CompilationUnit[Element] should be updated.
     expect(newUnit, same(oldUnit));
     expect(newUnit.element, same(oldUnitElement));
-    expect(analysisContext.parseCompilationUnit(source), same(oldUnit));
+    expect(analysisContext.getResolvedCompilationUnit(source, oldLibrary),
+        same(oldUnit));
     // The only expected pending task should return the same resolved
     // "newUnit", so all clients will get it using the usual way.
     AnalysisResult analysisResult = analysisContext.performAnalysisTask();
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 42e49e4..d3c995c 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -6954,6 +6954,12 @@
     expect(declaration.propertyKeyword, isNull);
   }
 
+  void test_parseCompilationUnitMember_function_void() {
+    FunctionDeclaration declaration = parse("parseCompilationUnitMember",
+        <Object>[emptyCommentAndMetadata()], "void f() {}");
+    expect(declaration.returnType, isNotNull);
+  }
+
   void test_parseCompilationUnitMember_function_withTypeParameters() {
     enableGenericMethods = true;
     FunctionDeclaration declaration = parse("parseCompilationUnitMember",
@@ -6962,12 +6968,6 @@
     expect(declaration.propertyKeyword, isNull);
   }
 
-  void test_parseCompilationUnitMember_function_void() {
-    FunctionDeclaration declaration = parse("parseCompilationUnitMember",
-        <Object>[emptyCommentAndMetadata()], "void f() {}");
-    expect(declaration.returnType, isNotNull);
-  }
-
   void test_parseCompilationUnitMember_getter_external_noType() {
     FunctionDeclaration declaration = parse("parseCompilationUnitMember",
         <Object>[emptyCommentAndMetadata()], "external get p;");
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 7c6bece..da69a28 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -68,6 +68,7 @@
   runReflectiveTests(SimpleResolverTest);
   runReflectiveTests(StrictModeTest);
   runReflectiveTests(TypePropagationTest);
+  runReflectiveTests(StrongModeDownwardsInferenceTest);
   runReflectiveTests(StrongModeStaticTypeAnalyzer2Test);
   runReflectiveTests(StrongModeTypePropagationTest);
 }
@@ -203,23 +204,27 @@
     futureConstructor.factory = true;
     futureElement.constructors = <ConstructorElement>[futureConstructor];
     //   Future then(onValue(T value), { Function onError });
-    List<ParameterElement> parameters = <ParameterElement>[
-      ElementFactory.requiredParameter2(
-          "value", futureElement.typeParameters[0].type)
-    ];
-    FunctionElementImpl onValueFunction = new FunctionElementImpl.forNode(null);
-    onValueFunction.synthetic = true;
-    onValueFunction.parameters = parameters;
-    onValueFunction.returnType = provider.dynamicType;
-    onValueFunction.enclosingElement = futureElement;
-    onValueFunction.type = new FunctionTypeImpl(onValueFunction);
-    DartType futureDynamicType =
-        futureElement.type.substitute4([provider.dynamicType]);
-    MethodElement thenMethod = ElementFactory.methodElementWithParameters(
-        futureElement, "then", futureDynamicType, [
-      ElementFactory.requiredParameter2("onValue", onValueFunction.type),
+    TypeDefiningElement futureThenR = DynamicElementImpl.instance;
+    if (context.analysisOptions.strongMode) {
+      futureThenR = ElementFactory.typeParameterWithType('R');
+    }
+    FunctionElementImpl thenOnValue = ElementFactory.functionElement3(
+        'onValue', futureThenR, [futureElement.typeParameters[0]], null);
+
+    DartType futureRType = futureElement.type.substitute4([futureThenR.type]);
+    MethodElementImpl thenMethod = ElementFactory.methodElementWithParameters(
+        futureElement, "then", futureRType, [
+      ElementFactory.requiredParameter2("onValue", thenOnValue.type),
       ElementFactory.namedParameter2("onError", provider.functionType)
     ]);
+    if (!futureThenR.type.isDynamic) {
+      thenMethod.typeParameters = [futureThenR];
+    }
+    thenOnValue.enclosingElement = thenMethod;
+    thenOnValue.type = new FunctionTypeImpl(thenOnValue);
+    (thenMethod.parameters[0] as ParameterElementImpl).type = thenOnValue.type;
+    thenMethod.type = new FunctionTypeImpl(thenMethod);
+
     futureElement.methods = <MethodElement>[thenMethod];
     // Completer
     ClassElementImpl completerElement =
@@ -340,11 +345,12 @@
         ClassElement.EMPTY_LIST);
     TopLevelVariableElement ln10Element = ElementFactory
         .topLevelVariableElement3("LN10", true, false, provider.doubleType);
-    FunctionElement maxElement = ElementFactory.functionElement3(
-        "max",
-        provider.numType.element,
-        <ClassElement>[provider.numType.element, provider.numType.element],
-        ClassElement.EMPTY_LIST);
+    TypeParameterElement maxT =
+        ElementFactory.typeParameterWithType('T', provider.numType);
+    FunctionElementImpl maxElement = ElementFactory.functionElement3(
+        "max", maxT, [maxT, maxT], ClassElement.EMPTY_LIST);
+    maxElement.typeParameters = [maxT];
+    maxElement.type = new FunctionTypeImpl(maxElement);
     TopLevelVariableElement piElement = ElementFactory.topLevelVariableElement3(
         "PI", true, false, provider.doubleType);
     ClassElementImpl randomElement = ElementFactory.classElement2("Random");
@@ -12127,6 +12133,983 @@
 }
 
 /**
+ * Strong mode static analyzer downwards inference tests
+ */
+@reflectiveTest
+class StrongModeDownwardsInferenceTest extends ResolverTestCase {
+  TypeAssertions _assertions;
+  AsserterBuilder<Element, DartType> _hasElement;
+  AsserterBuilder<DartType, DartType> _isType;
+  AsserterBuilder2<Asserter<DartType>, Asserter<DartType>,
+      DartType> _isFunction2Of;
+  AsserterBuilderBuilder<Asserter<DartType>, List<Asserter<DartType>>,
+      DartType> _isInstantiationOf;
+  Asserter<DartType> _isInt;
+  Asserter<DartType> _isNum;
+  Asserter<DartType> _isString;
+  Asserter<DartType> _isDynamic;
+  AsserterBuilder<Asserter<DartType>, InterfaceType> _isListOf;
+  AsserterBuilder2<Asserter<DartType>, Asserter<DartType>,
+      InterfaceType> _isMapOf;
+
+  @override
+  void setUp() {
+    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+    options.strongMode = true;
+    resetWithOptions(options);
+    _assertions = new TypeAssertions(typeProvider);
+    _isType = _assertions.isType;
+    _hasElement = _assertions.hasElement;
+    _isInstantiationOf = _assertions.isInstantiationOf;
+    _isInt = _assertions.isInt;
+    _isNum = _assertions.isNum;
+    _isString = _assertions.isString;
+    _isDynamic = _assertions.isDynamic;
+    _isListOf = _assertions.isListOf;
+    _isMapOf = _assertions.isMapOf;
+    _isFunction2Of = _assertions.isFunction2Of;
+  }
+
+  void test_cascadeExpression() {
+    String code = r'''
+      class A<T> {
+        List<T> map(T a, List<T> mapper(T x)) => mapper(a);
+      }
+
+      void main () {
+        A<int> a = new A()..map(0, (x) => [x]);
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    CascadeExpression fetch(int i) {
+      VariableDeclarationStatement stmt = statements[i];
+      VariableDeclaration decl = stmt.variables.variables[0];
+      CascadeExpression exp = decl.initializer;
+      return exp;
+    }
+    Element elementA = AstFinder.getClass(unit, "A").element;
+
+    CascadeExpression cascade = fetch(0);
+    _isInstantiationOf(_hasElement(elementA))([_isInt])(cascade.staticType);
+    MethodInvocation invoke = cascade.cascadeSections[0];
+    FunctionExpression function = invoke.argumentList.arguments[1];
+    ExecutableElement f0 = function.element;
+    _isListOf(_isInt)(f0.type.returnType);
+    expect(f0.type.normalParameterTypes[0], typeProvider.intType);
+  }
+
+  void test_constructorInitializer_propagation() {
+    String code = r'''
+      class A {
+        List<String> x;
+        A() : this.x = [];
+      }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    ConstructorDeclaration constructor =
+        AstFinder.getConstructorInClass(unit, "A", null);
+    ConstructorFieldInitializer assignment = constructor.initializers[0];
+    Expression exp = assignment.expression;
+    _isListOf(_isString)(exp.staticType);
+  }
+
+  void test_factoryConstructor_propagation() {
+    String code = r'''
+      class A<T> {
+        factory A() { return new B(); }
+      }
+      class B<S> extends A<S> {}
+   ''';
+    CompilationUnit unit = resolveSource(code);
+
+    ConstructorDeclaration constructor =
+        AstFinder.getConstructorInClass(unit, "A", null);
+    BlockFunctionBody body = constructor.body;
+    ReturnStatement stmt = body.block.statements[0];
+    InstanceCreationExpression exp = stmt.expression;
+    ClassElement elementB = AstFinder.getClass(unit, "B").element;
+    ClassElement elementA = AstFinder.getClass(unit, "A").element;
+    expect(exp.constructorName.type.type.element, elementB);
+    _isInstantiationOf(_hasElement(elementB))(
+        [_isType(elementA.typeParameters[0].type)])(exp.staticType);
+  }
+
+  void test_fieldDeclaration_propagation() {
+    String code = r'''
+      class A {
+        List<String> f0 = ["hello"];
+      }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+
+    VariableDeclaration field = AstFinder.getFieldInClass(unit, "A", "f0");
+
+    _isListOf(_isString)(field.initializer.staticType);
+  }
+
+  void test_functionDeclaration_body_propagation() {
+    String code = r'''
+      typedef T Function2<S, T>(S x);
+
+      List<int> test1() => [];
+
+      Function2<int, int> test2 (int x) {
+        Function2<String, int> inner() {
+          return (x) => x.length;
+        }
+        return (x) => x;
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+
+    Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
+
+    FunctionDeclaration test1 = AstFinder.getTopLevelFunction(unit, "test1");
+    ExpressionFunctionBody body = test1.functionExpression.body;
+    assertListOfInt(body.expression.staticType);
+
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "test2");
+
+    FunctionDeclaration inner =
+        (statements[0] as FunctionDeclarationStatement).functionDeclaration;
+    BlockFunctionBody body0 = inner.functionExpression.body;
+    ReturnStatement return0 = body0.block.statements[0];
+    Expression anon0 = return0.expression;
+    FunctionType type0 = anon0.staticType;
+    expect(type0.returnType, typeProvider.intType);
+    expect(type0.normalParameterTypes[0], typeProvider.stringType);
+
+    FunctionExpression anon1 = (statements[1] as ReturnStatement).expression;
+    FunctionType type1 = anon1.element.type;
+    expect(type1.returnType, typeProvider.intType);
+    expect(type1.normalParameterTypes[0], typeProvider.intType);
+  }
+
+  void test_functionLiteral_assignment_typedArguments() {
+    String code = r'''
+      typedef T Function2<S, T>(S x);
+
+      void main () {
+        Function2<int, String> l0 = (int x) => null;
+        Function2<int, String> l1 = (int x) => "hello";
+        Function2<int, String> l2 = (String x) => "hello";
+        Function2<int, String> l3 = (int x) => 3;
+        Function2<int, String> l4 = (int x) {return 3;};
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    DartType literal(int i) {
+      VariableDeclarationStatement stmt = statements[i];
+      VariableDeclaration decl = stmt.variables.variables[0];
+      FunctionExpression exp = decl.initializer;
+      return exp.element.type;
+    }
+    _isFunction2Of(_isInt, _isString)(literal(0));
+    _isFunction2Of(_isInt, _isString)(literal(1));
+    _isFunction2Of(_isString, _isString)(literal(2));
+    _isFunction2Of(_isInt, _isInt)(literal(3));
+    _isFunction2Of(_isInt, _isString)(literal(4));
+  }
+
+  void test_functionLiteral_assignment_unTypedArguments() {
+    String code = r'''
+      typedef T Function2<S, T>(S x);
+
+      void main () {
+        Function2<int, String> l0 = (x) => null;
+        Function2<int, String> l1 = (x) => "hello";
+        Function2<int, String> l2 = (x) => "hello";
+        Function2<int, String> l3 = (x) => 3;
+        Function2<int, String> l4 = (x) {return 3;};
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    DartType literal(int i) {
+      VariableDeclarationStatement stmt = statements[i];
+      VariableDeclaration decl = stmt.variables.variables[0];
+      FunctionExpression exp = decl.initializer;
+      return exp.element.type;
+    }
+    _isFunction2Of(_isInt, _isString)(literal(0));
+    _isFunction2Of(_isInt, _isString)(literal(1));
+    _isFunction2Of(_isInt, _isString)(literal(2));
+    _isFunction2Of(_isInt, _isInt)(literal(3));
+    _isFunction2Of(_isInt, _isString)(literal(4));
+  }
+
+  void test_functionLiteral_body_propagation() {
+    String code = r'''
+      typedef T Function2<S, T>(S x);
+
+      void main () {
+        Function2<int, List<String>> l0 = (int x) => ["hello"];
+        Function2<int, List<String>> l1 = (String x) => ["hello"];
+        Function2<int, List<String>> l2 = (int x) => [3];
+        Function2<int, List<String>> l3 = (int x) {return [3];};
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    Expression functionReturnValue(int i) {
+      VariableDeclarationStatement stmt = statements[i];
+      VariableDeclaration decl = stmt.variables.variables[0];
+      FunctionExpression exp = decl.initializer;
+      FunctionBody body = exp.body;
+      if (body is ExpressionFunctionBody) {
+        return body.expression;
+      } else {
+        Statement stmt = (body as BlockFunctionBody).block.statements[0];
+        return (stmt as ReturnStatement).expression;
+      }
+    }
+    Asserter<InterfaceType> assertListOfString = _isListOf(_isString);
+    assertListOfString(functionReturnValue(0).staticType);
+    assertListOfString(functionReturnValue(1).staticType);
+    assertListOfString(functionReturnValue(2).staticType);
+    assertListOfString(functionReturnValue(3).staticType);
+  }
+
+  void test_functionLiteral_functionExpressionInvocation_typedArguments() {
+    String code = r'''
+      class Mapper<F, T> {
+        T map(T mapper(F x)) => mapper(null);
+      }
+
+      void main () {
+        (new Mapper<int, String>().map)((int x) => null);
+        (new Mapper<int, String>().map)((int x) => "hello");
+        (new Mapper<int, String>().map)((String x) => "hello");
+        (new Mapper<int, String>().map)((int x) => 3);
+        (new Mapper<int, String>().map)((int x) {return 3;});
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    DartType literal(int i) {
+      ExpressionStatement stmt = statements[i];
+      FunctionExpressionInvocation invk = stmt.expression;
+      FunctionExpression exp = invk.argumentList.arguments[0];
+      return exp.element.type;
+    }
+    _isFunction2Of(_isInt, _isString)(literal(0));
+    _isFunction2Of(_isInt, _isString)(literal(1));
+    _isFunction2Of(_isString, _isString)(literal(2));
+    _isFunction2Of(_isInt, _isInt)(literal(3));
+    _isFunction2Of(_isInt, _isString)(literal(4));
+  }
+
+  void test_functionLiteral_functionExpressionInvocation_unTypedArguments() {
+    String code = r'''
+      class Mapper<F, T> {
+        T map(T mapper(F x)) => mapper(null);
+      }
+
+      void main () {
+        (new Mapper<int, String>().map)((x) => null);
+        (new Mapper<int, String>().map)((x) => "hello");
+        (new Mapper<int, String>().map)((x) => "hello");
+        (new Mapper<int, String>().map)((x) => 3);
+        (new Mapper<int, String>().map)((x) {return 3;});
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    DartType literal(int i) {
+      ExpressionStatement stmt = statements[i];
+      FunctionExpressionInvocation invk = stmt.expression;
+      FunctionExpression exp = invk.argumentList.arguments[0];
+      return exp.element.type;
+    }
+    _isFunction2Of(_isInt, _isString)(literal(0));
+    _isFunction2Of(_isInt, _isString)(literal(1));
+    _isFunction2Of(_isInt, _isString)(literal(2));
+    _isFunction2Of(_isInt, _isInt)(literal(3));
+    _isFunction2Of(_isInt, _isString)(literal(4));
+  }
+
+  void test_functionLiteral_functionInvocation_typedArguments() {
+    String code = r'''
+      String map(String mapper(int x)) => mapper(null);
+
+      void main () {
+        map((int x) => null);
+        map((int x) => "hello");
+        map((String x) => "hello");
+        map((int x) => 3);
+        map((int x) {return 3;});
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    DartType literal(int i) {
+      ExpressionStatement stmt = statements[i];
+      MethodInvocation invk = stmt.expression;
+      FunctionExpression exp = invk.argumentList.arguments[0];
+      return exp.element.type;
+    }
+    _isFunction2Of(_isInt, _isString)(literal(0));
+    _isFunction2Of(_isInt, _isString)(literal(1));
+    _isFunction2Of(_isString, _isString)(literal(2));
+    _isFunction2Of(_isInt, _isInt)(literal(3));
+    _isFunction2Of(_isInt, _isString)(literal(4));
+  }
+
+  void test_functionLiteral_functionInvocation_unTypedArguments() {
+    String code = r'''
+      String map(String mapper(int x)) => mapper(null);
+
+      void main () {
+        map((x) => null);
+        map((x) => "hello");
+        map((x) => "hello");
+        map((x) => 3);
+        map((x) {return 3;});
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    DartType literal(int i) {
+      ExpressionStatement stmt = statements[i];
+      MethodInvocation invk = stmt.expression;
+      FunctionExpression exp = invk.argumentList.arguments[0];
+      return exp.element.type;
+    }
+    _isFunction2Of(_isInt, _isString)(literal(0));
+    _isFunction2Of(_isInt, _isString)(literal(1));
+    _isFunction2Of(_isInt, _isString)(literal(2));
+    _isFunction2Of(_isInt, _isInt)(literal(3));
+    _isFunction2Of(_isInt, _isString)(literal(4));
+  }
+
+  void test_functionLiteral_methodInvocation_typedArguments() {
+    String code = r'''
+      class Mapper<F, T> {
+        T map(T mapper(F x)) => mapper(null);
+      }
+
+      void main () {
+        new Mapper<int, String>().map((int x) => null);
+        new Mapper<int, String>().map((int x) => "hello");
+        new Mapper<int, String>().map((String x) => "hello");
+        new Mapper<int, String>().map((int x) => 3);
+        new Mapper<int, String>().map((int x) {return 3;});
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    DartType literal(int i) {
+      ExpressionStatement stmt = statements[i];
+      MethodInvocation invk = stmt.expression;
+      FunctionExpression exp = invk.argumentList.arguments[0];
+      return exp.element.type;
+    }
+    _isFunction2Of(_isInt, _isString)(literal(0));
+    _isFunction2Of(_isInt, _isString)(literal(1));
+    _isFunction2Of(_isString, _isString)(literal(2));
+    _isFunction2Of(_isInt, _isInt)(literal(3));
+    _isFunction2Of(_isInt, _isString)(literal(4));
+  }
+
+  void test_functionLiteral_methodInvocation_unTypedArguments() {
+    String code = r'''
+      class Mapper<F, T> {
+        T map(T mapper(F x)) => mapper(null);
+      }
+
+      void main () {
+        new Mapper<int, String>().map((x) => null);
+        new Mapper<int, String>().map((x) => "hello");
+        new Mapper<int, String>().map((x) => "hello");
+        new Mapper<int, String>().map((x) => 3);
+        new Mapper<int, String>().map((x) {return 3;});
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    DartType literal(int i) {
+      ExpressionStatement stmt = statements[i];
+      MethodInvocation invk = stmt.expression;
+      FunctionExpression exp = invk.argumentList.arguments[0];
+      return exp.element.type;
+    }
+    _isFunction2Of(_isInt, _isString)(literal(0));
+    _isFunction2Of(_isInt, _isString)(literal(1));
+    _isFunction2Of(_isInt, _isString)(literal(2));
+    _isFunction2Of(_isInt, _isInt)(literal(3));
+    _isFunction2Of(_isInt, _isString)(literal(4));
+  }
+
+  void test_functionLiteral_unTypedArgument_propagation() {
+    String code = r'''
+      typedef T Function2<S, T>(S x);
+
+      void main () {
+        Function2<int, int> l0 = (x) => x;
+        Function2<int, int> l1 = (x) => x+1;
+        Function2<int, String> l2 = (x) => x;
+        Function2<int, String> l3 = (x) => x.toLowerCase();
+        Function2<String, String> l4 = (x) => x.toLowerCase();
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    Expression functionReturnValue(int i) {
+      VariableDeclarationStatement stmt = statements[i];
+      VariableDeclaration decl = stmt.variables.variables[0];
+      FunctionExpression exp = decl.initializer;
+      FunctionBody body = exp.body;
+      if (body is ExpressionFunctionBody) {
+        return body.expression;
+      } else {
+        Statement stmt = (body as BlockFunctionBody).block.statements[0];
+        return (stmt as ReturnStatement).expression;
+      }
+    }
+    expect(functionReturnValue(0).staticType, typeProvider.intType);
+    expect(functionReturnValue(1).staticType, typeProvider.intType);
+    expect(functionReturnValue(2).staticType, typeProvider.intType);
+    expect(functionReturnValue(3).staticType, typeProvider.dynamicType);
+    expect(functionReturnValue(4).staticType, typeProvider.stringType);
+  }
+
+  void test_inference_hints() {
+    Source source = addSource(r'''
+      void main () {
+        var x = 3;
+        List<int> l0 = [];
+     }
+   ''');
+    LibraryElement library = resolve2(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  void test_instanceCreation() {
+    String code = r'''
+      class A<S, T> {
+        S x;
+        T y;
+        A(this.x, this.y);
+        A.named(this.x, this.y);
+      }
+
+      class B<S, T> extends A<T, S> {
+        B(S y, T x) : super(x, y);
+        B.named(S y, T x) : super.named(x, y);
+      }
+
+      class C<S> extends B<S, S> {
+        C(S a) : super(a, a);
+        C.named(S a) : super.named(a, a);
+      }
+
+      class D<S, T> extends B<T, int> {
+        D(T a) : super(a, 3);
+        D.named(T a) : super.named(a, 3);
+      }
+
+      class E<S, T> extends A<C<S>, T> {
+        E(T a) : super(null, a);
+      }
+
+      class F<S, T> extends A<S, T> {
+        F(S x, T y, {List<S> a, List<T> b}) : super(x, y);
+        F.named(S x, T y, [S a, T b]) : super(a, b);
+      }
+
+      void test0() {
+        A<int, String> a0 = new A(3, "hello");
+        A<int, String> a1 = new A.named(3, "hello");
+        A<int, String> a2 = new A<int, String>(3, "hello");
+        A<int, String> a3 = new A<int, String>.named(3, "hello");
+        A<int, String> a4 = new A<int, dynamic>(3, "hello");
+        A<int, String> a5 = new A<dynamic, dynamic>.named(3, "hello");
+      }
+      void test1()  {
+        A<int, String> a0 = new A("hello", 3);
+        A<int, String> a1 = new A.named("hello", 3);
+      }
+      void test2() {
+        A<int, String> a0 = new B("hello", 3);
+        A<int, String> a1 = new B.named("hello", 3);
+        A<int, String> a2 = new B<String, int>("hello", 3);
+        A<int, String> a3 = new B<String, int>.named("hello", 3);
+        A<int, String> a4 = new B<String, dynamic>("hello", 3);
+        A<int, String> a5 = new B<dynamic, dynamic>.named("hello", 3);
+      }
+      void test3() {
+        A<int, String> a0 = new B(3, "hello");
+        A<int, String> a1 = new B.named(3, "hello");
+      }
+      void test4() {
+        A<int, int> a0 = new C(3);
+        A<int, int> a1 = new C.named(3);
+        A<int, int> a2 = new C<int>(3);
+        A<int, int> a3 = new C<int>.named(3);
+        A<int, int> a4 = new C<dynamic>(3);
+        A<int, int> a5 = new C<dynamic>.named(3);
+      }
+      void test5() {
+        A<int, int> a0 = new C("hello");
+        A<int, int> a1 = new C.named("hello");
+      }
+      void test6()  {
+        A<int, String> a0 = new D("hello");
+        A<int, String> a1 = new D.named("hello");
+        A<int, String> a2 = new D<int, String>("hello");
+        A<int, String> a3 = new D<String, String>.named("hello");
+        A<int, String> a4 = new D<num, dynamic>("hello");
+        A<int, String> a5 = new D<dynamic, dynamic>.named("hello");
+      }
+      void test7() {
+        A<int, String> a0 = new D(3);
+        A<int, String> a1 = new D.named(3);
+      }
+      void test8() {
+        // Currently we only allow variable constraints.  Test that we reject.
+        A<C<int>, String> a0 = new E("hello");
+      }
+      void test9() { // Check named and optional arguments
+        A<int, String> a0 = new F(3, "hello", a: [3], b: ["hello"]);
+        A<int, String> a1 = new F(3, "hello", a: ["hello"], b:[3]);
+        A<int, String> a2 = new F.named(3, "hello", 3, "hello");
+        A<int, String> a3 = new F.named(3, "hello");
+        A<int, String> a4 = new F.named(3, "hello", "hello", 3);
+        A<int, String> a5 = new F.named(3, "hello", "hello");
+      }
+    }''';
+    CompilationUnit unit = resolveSource(code);
+
+    Expression rhs(VariableDeclarationStatement stmt) {
+      VariableDeclaration decl = stmt.variables.variables[0];
+      Expression exp = decl.initializer;
+      return exp;
+    }
+
+    void hasType(Asserter<DartType> assertion, Expression exp) =>
+        assertion(exp.staticType);
+
+    Element elementA = AstFinder.getClass(unit, "A").element;
+    Element elementB = AstFinder.getClass(unit, "B").element;
+    Element elementC = AstFinder.getClass(unit, "C").element;
+    Element elementD = AstFinder.getClass(unit, "D").element;
+    Element elementE = AstFinder.getClass(unit, "E").element;
+    Element elementF = AstFinder.getClass(unit, "F").element;
+
+    AsserterBuilder<List<Asserter<DartType>>, DartType> assertAOf =
+        _isInstantiationOf(_hasElement(elementA));
+    AsserterBuilder<List<Asserter<DartType>>, DartType> assertBOf =
+        _isInstantiationOf(_hasElement(elementB));
+    AsserterBuilder<List<Asserter<DartType>>, DartType> assertCOf =
+        _isInstantiationOf(_hasElement(elementC));
+    AsserterBuilder<List<Asserter<DartType>>, DartType> assertDOf =
+        _isInstantiationOf(_hasElement(elementD));
+    AsserterBuilder<List<Asserter<DartType>>, DartType> assertEOf =
+        _isInstantiationOf(_hasElement(elementE));
+    AsserterBuilder<List<Asserter<DartType>>, DartType> assertFOf =
+        _isInstantiationOf(_hasElement(elementF));
+
+    {
+      List<Statement> statements =
+          AstFinder.getStatementsInTopLevelFunction(unit, "test0");
+
+      hasType(assertAOf([_isInt, _isString]), rhs(statements[0]));
+      hasType(assertAOf([_isInt, _isString]), rhs(statements[0]));
+      hasType(assertAOf([_isInt, _isString]), rhs(statements[1]));
+      hasType(assertAOf([_isInt, _isString]), rhs(statements[2]));
+      hasType(assertAOf([_isInt, _isString]), rhs(statements[3]));
+      hasType(assertAOf([_isInt, _isDynamic]), rhs(statements[4]));
+      hasType(assertAOf([_isDynamic, _isDynamic]), rhs(statements[5]));
+    }
+
+    {
+      List<Statement> statements =
+          AstFinder.getStatementsInTopLevelFunction(unit, "test1");
+      hasType(assertAOf([_isInt, _isString]), rhs(statements[0]));
+      hasType(assertAOf([_isInt, _isString]), rhs(statements[1]));
+    }
+
+    {
+      List<Statement> statements =
+          AstFinder.getStatementsInTopLevelFunction(unit, "test2");
+      hasType(assertBOf([_isString, _isInt]), rhs(statements[0]));
+      hasType(assertBOf([_isString, _isInt]), rhs(statements[1]));
+      hasType(assertBOf([_isString, _isInt]), rhs(statements[2]));
+      hasType(assertBOf([_isString, _isInt]), rhs(statements[3]));
+      hasType(assertBOf([_isString, _isDynamic]), rhs(statements[4]));
+      hasType(assertBOf([_isDynamic, _isDynamic]), rhs(statements[5]));
+    }
+
+    {
+      List<Statement> statements =
+          AstFinder.getStatementsInTopLevelFunction(unit, "test3");
+      hasType(assertBOf([_isString, _isInt]), rhs(statements[0]));
+      hasType(assertBOf([_isString, _isInt]), rhs(statements[1]));
+    }
+
+    {
+      List<Statement> statements =
+          AstFinder.getStatementsInTopLevelFunction(unit, "test4");
+      hasType(assertCOf([_isInt]), rhs(statements[0]));
+      hasType(assertCOf([_isInt]), rhs(statements[1]));
+      hasType(assertCOf([_isInt]), rhs(statements[2]));
+      hasType(assertCOf([_isInt]), rhs(statements[3]));
+      hasType(assertCOf([_isDynamic]), rhs(statements[4]));
+      hasType(assertCOf([_isDynamic]), rhs(statements[5]));
+    }
+
+    {
+      List<Statement> statements =
+          AstFinder.getStatementsInTopLevelFunction(unit, "test5");
+      hasType(assertCOf([_isInt]), rhs(statements[0]));
+      hasType(assertCOf([_isInt]), rhs(statements[1]));
+    }
+
+    {
+      // The first type parameter is not constrained by the
+      // context.  We could choose a tighter type, but currently
+      // we just use dynamic.
+      List<Statement> statements =
+          AstFinder.getStatementsInTopLevelFunction(unit, "test6");
+      hasType(assertDOf([_isDynamic, _isString]), rhs(statements[0]));
+      hasType(assertDOf([_isDynamic, _isString]), rhs(statements[1]));
+      hasType(assertDOf([_isInt, _isString]), rhs(statements[2]));
+      hasType(assertDOf([_isString, _isString]), rhs(statements[3]));
+      hasType(assertDOf([_isNum, _isDynamic]), rhs(statements[4]));
+      hasType(assertDOf([_isDynamic, _isDynamic]), rhs(statements[5]));
+    }
+
+    {
+      List<Statement> statements =
+          AstFinder.getStatementsInTopLevelFunction(unit, "test7");
+      hasType(assertDOf([_isDynamic, _isString]), rhs(statements[0]));
+      hasType(assertDOf([_isDynamic, _isString]), rhs(statements[1]));
+    }
+
+    {
+      List<Statement> statements =
+          AstFinder.getStatementsInTopLevelFunction(unit, "test8");
+      hasType(assertEOf([_isDynamic, _isDynamic]), rhs(statements[0]));
+    }
+
+    {
+      List<Statement> statements =
+          AstFinder.getStatementsInTopLevelFunction(unit, "test9");
+      hasType(assertFOf([_isInt, _isString]), rhs(statements[0]));
+      hasType(assertFOf([_isInt, _isString]), rhs(statements[1]));
+      hasType(assertFOf([_isInt, _isString]), rhs(statements[2]));
+      hasType(assertFOf([_isInt, _isString]), rhs(statements[3]));
+      hasType(assertFOf([_isInt, _isString]), rhs(statements[4]));
+      hasType(assertFOf([_isInt, _isString]), rhs(statements[5]));
+    }
+  }
+
+  void test_listLiteral_nested() {
+    String code = r'''
+      void main () {
+        List<List<int>> l0 = [[]];
+        Iterable<List<int>> l1 = [[3]];
+        Iterable<List<int>> l2 = [[3], [4]];
+        List<List<int>> l3 = [["hello", 3], []];
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    ListLiteral literal(int i) {
+      VariableDeclarationStatement stmt = statements[i];
+      VariableDeclaration decl = stmt.variables.variables[0];
+      ListLiteral exp = decl.initializer;
+      return exp;
+    }
+
+    Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
+    Asserter<InterfaceType> assertListOfListOfInt = _isListOf(assertListOfInt);
+
+    assertListOfListOfInt(literal(0).staticType);
+    assertListOfListOfInt(literal(1).staticType);
+    assertListOfListOfInt(literal(2).staticType);
+    assertListOfListOfInt(literal(3).staticType);
+
+    assertListOfInt(literal(1).elements[0].staticType);
+    assertListOfInt(literal(2).elements[0].staticType);
+    assertListOfInt(literal(3).elements[0].staticType);
+  }
+
+  void test_listLiteral_simple() {
+    String code = r'''
+      void main () {
+        List<int> l0 = [];
+        List<int> l1 = [3];
+        List<int> l2 = ["hello"];
+        List<int> l3 = ["hello", 3];
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    DartType literal(int i) {
+      VariableDeclarationStatement stmt = statements[i];
+      VariableDeclaration decl = stmt.variables.variables[0];
+      ListLiteral exp = decl.initializer;
+      return exp.staticType;
+    }
+
+    Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
+
+    assertListOfInt(literal(0));
+    assertListOfInt(literal(1));
+    assertListOfInt(literal(2));
+    assertListOfInt(literal(3));
+  }
+
+  void test_listLiteral_simple_const() {
+    String code = r'''
+      void main () {
+        const List<int> c0 = const [];
+        const List<int> c1 = const [3];
+        const List<int> c2 = const ["hello"];
+        const List<int> c3 = const ["hello", 3];
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    DartType literal(int i) {
+      VariableDeclarationStatement stmt = statements[i];
+      VariableDeclaration decl = stmt.variables.variables[0];
+      ListLiteral exp = decl.initializer;
+      return exp.staticType;
+    }
+
+    Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
+
+    assertListOfInt(literal(0));
+    assertListOfInt(literal(1));
+    assertListOfInt(literal(2));
+    assertListOfInt(literal(3));
+  }
+
+  void test_listLiteral_simple_disabled() {
+    String code = r'''
+      void main () {
+        List<int> l0 = <num>[];
+        List<int> l1 = <num>[3];
+        List<int> l2 = <String>["hello"];
+        List<int> l3 = <dynamic>["hello", 3];
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    DartType literal(int i) {
+      VariableDeclarationStatement stmt = statements[i];
+      VariableDeclaration decl = stmt.variables.variables[0];
+      ListLiteral exp = decl.initializer;
+      return exp.staticType;
+    }
+
+    _isListOf(_isNum)(literal(0));
+    _isListOf(_isNum)(literal(1));
+    _isListOf(_isString)(literal(2));
+    _isListOf(_isDynamic)(literal(3));
+  }
+
+  void test_listLiteral_simple_subtype() {
+    String code = r'''
+      void main () {
+        Iterable<int> l0 = [];
+        Iterable<int> l1 = [3];
+        Iterable<int> l2 = ["hello"];
+        Iterable<int> l3 = ["hello", 3];
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    DartType literal(int i) {
+      VariableDeclarationStatement stmt = statements[i];
+      VariableDeclaration decl = stmt.variables.variables[0];
+      ListLiteral exp = decl.initializer;
+      return exp.staticType;
+    }
+
+    Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
+
+    assertListOfInt(literal(0));
+    assertListOfInt(literal(1));
+    assertListOfInt(literal(2));
+    assertListOfInt(literal(3));
+  }
+
+  void test_mapLiteral_nested() {
+    String code = r'''
+      void main () {
+        Map<int, List<String>> l0 = {};
+        Map<int, List<String>> l1 = {3: ["hello"]};
+        Map<int, List<String>> l2 = {"hello": ["hello"]};
+        Map<int, List<String>> l3 = {3: [3]};
+        Map<int, List<String>> l4 = {3:["hello"], "hello": [3]};
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    MapLiteral literal(int i) {
+      VariableDeclarationStatement stmt = statements[i];
+      VariableDeclaration decl = stmt.variables.variables[0];
+      MapLiteral exp = decl.initializer;
+      return exp;
+    }
+
+    Asserter<InterfaceType> assertListOfString = _isListOf(_isString);
+    Asserter<InterfaceType> assertMapOfIntToListOfString =
+        _isMapOf(_isInt, assertListOfString);
+
+    assertMapOfIntToListOfString(literal(0).staticType);
+    assertMapOfIntToListOfString(literal(1).staticType);
+    assertMapOfIntToListOfString(literal(2).staticType);
+    assertMapOfIntToListOfString(literal(3).staticType);
+    assertMapOfIntToListOfString(literal(4).staticType);
+
+    assertListOfString(literal(1).entries[0].value.staticType);
+    assertListOfString(literal(2).entries[0].value.staticType);
+    assertListOfString(literal(3).entries[0].value.staticType);
+    assertListOfString(literal(4).entries[0].value.staticType);
+  }
+
+  void test_mapLiteral_simple() {
+    String code = r'''
+      void main () {
+        Map<int, String> l0 = {};
+        Map<int, String> l1 = {3: "hello"};
+        Map<int, String> l2 = {"hello": "hello"};
+        Map<int, String> l3 = {3: 3};
+        Map<int, String> l4 = {3:"hello", "hello": 3};
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    DartType literal(int i) {
+      VariableDeclarationStatement stmt = statements[i];
+      VariableDeclaration decl = stmt.variables.variables[0];
+      MapLiteral exp = decl.initializer;
+      return exp.staticType;
+    }
+
+    Asserter<InterfaceType> assertMapOfIntToString =
+        _isMapOf(_isInt, _isString);
+
+    assertMapOfIntToString(literal(0));
+    assertMapOfIntToString(literal(1));
+    assertMapOfIntToString(literal(2));
+    assertMapOfIntToString(literal(3));
+  }
+
+  void test_mapLiteral_simple_disabled() {
+    String code = r'''
+      void main () {
+        Map<int, String> l0 = <int, dynamic>{};
+        Map<int, String> l1 = <int, dynamic>{3: "hello"};
+        Map<int, String> l2 = <int, dynamic>{"hello": "hello"};
+        Map<int, String> l3 = <int, dynamic>{3: 3};
+     }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
+    DartType literal(int i) {
+      VariableDeclarationStatement stmt = statements[i];
+      VariableDeclaration decl = stmt.variables.variables[0];
+      MapLiteral exp = decl.initializer;
+      return exp.staticType;
+    }
+
+    Asserter<InterfaceType> assertMapOfIntToDynamic =
+        _isMapOf(_isInt, _isDynamic);
+
+    assertMapOfIntToDynamic(literal(0));
+    assertMapOfIntToDynamic(literal(1));
+    assertMapOfIntToDynamic(literal(2));
+    assertMapOfIntToDynamic(literal(3));
+  }
+
+  void test_methodDeclaration_body_propagation() {
+    String code = r'''
+      class A {
+        List<String> m0(int x) => ["hello"];
+        List<String> m1(int x) {return [3];};
+      }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+    Expression methodReturnValue(String methodName) {
+      MethodDeclaration method =
+          AstFinder.getMethodInClass(unit, "A", methodName);
+      FunctionBody body = method.body;
+      if (body is ExpressionFunctionBody) {
+        return body.expression;
+      } else {
+        Statement stmt = (body as BlockFunctionBody).block.statements[0];
+        return (stmt as ReturnStatement).expression;
+      }
+    }
+    Asserter<InterfaceType> assertListOfString = _isListOf(_isString);
+    assertListOfString(methodReturnValue("m0").staticType);
+    assertListOfString(methodReturnValue("m1").staticType);
+  }
+
+  void test_redirectingConstructor_propagation() {
+    String code = r'''
+      class A {
+        A() : this.named([]);
+        A.named(List<String> x);
+      }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+
+    ConstructorDeclaration constructor =
+        AstFinder.getConstructorInClass(unit, "A", null);
+    RedirectingConstructorInvocation invocation = constructor.initializers[0];
+    Expression exp = invocation.argumentList.arguments[0];
+    _isListOf(_isString)(exp.staticType);
+  }
+
+  void test_superConstructorInvocation_propagation() {
+    String code = r'''
+      class B {
+        B(List<String>);
+      }
+      class A extends B {
+        A() : super([]);
+      }
+   ''';
+    CompilationUnit unit = resolveSource(code);
+
+    ConstructorDeclaration constructor =
+        AstFinder.getConstructorInClass(unit, "A", null);
+    SuperConstructorInvocation invocation = constructor.initializers[0];
+    Expression exp = invocation.argumentList.arguments[0];
+    _isListOf(_isString)(exp.staticType);
+  }
+}
+
+/**
  * Strong mode static analyzer end to end tests
  */
 @reflectiveTest
@@ -12173,21 +13156,15 @@
     if (!AnalysisEngine.instance.useTaskModel) {
       return;
     }
-    // TODO(jmesserly): we're missing a case in the parser for the return type,
-    // so "dynamic" must be used to workaround this.
-    _resolveTestUnit(r'''
-dynamic/*=T*/ f/*<T>*/(/*=T*/ x) => null;
-''');
+    _resolveTestUnit(r'/*=T*/ f/*<T>*/(/*=T*/ x) => null;');
     SimpleIdentifier f = _findIdentifier('f');
     FunctionElementImpl e = f.staticElement;
     expect(e.typeParameters.toString(), '[T]');
-    expect(e.type.typeParameters.toString(), '[T]');
-    expect(e.type.typeParameters[0].type, e.type.typeArguments[0]);
-    expect(e.type.toString(), '(T) → T');
+    expect(e.type.boundTypeParameters.toString(), '[T]');
+    expect(e.type.typeParameters.toString(), '[]');
+    expect(e.type.toString(), '<T>(T) → T');
 
-    // Substitute for T
-    DartType t = e.typeParameters[0].type;
-    FunctionType ft = e.type.substitute2([typeProvider.stringType], [t]);
+    FunctionType ft = e.type.instantiate([typeProvider.stringType]);
     expect(ft.toString(), '(String) → String');
   }
 
@@ -12206,16 +13183,17 @@
     SimpleIdentifier f = _findIdentifier('f');
     MethodElementImpl e = f.staticElement;
     expect(e.typeParameters.toString(), '[T]');
-    expect(e.type.typeParameters.toString(), '[T, E]');
-    expect(e.type.typeArguments.toString(), '[T, E]');
-    expect(e.type.toString(), '(E) → List<T>');
+    expect(e.type.boundTypeParameters.toString(), '[T]');
+    expect(e.type.typeParameters.toString(), '[E]');
+    expect(e.type.typeArguments.toString(), '[E]');
+    expect(e.type.toString(), '<T>(E) → List<T>');
 
     SimpleIdentifier c = _findIdentifier('cOfString');
     FunctionType ft = (c.staticType as InterfaceType).getMethod('f').type;
-    expect(ft.toString(), '(String) → List<T>');
-    DartType t = e.typeParameters[0].type;
-    ft = ft.substitute2([typeProvider.intType], [t]);
+    expect(ft.toString(), '<T>(String) → List<T>');
+    ft = ft.instantiate([typeProvider.intType]);
     expect(ft.toString(), '(String) → List<int>');
+    expect('${ft.typeArguments}/${ft.typeParameters}', '[String, int]/[E, T]');
   }
 
   void test_genericMethod_functionTypedParameter() {
@@ -12233,18 +13211,50 @@
     SimpleIdentifier f = _findIdentifier('f');
     MethodElementImpl e = f.staticElement;
     expect(e.typeParameters.toString(), '[T]');
-    expect(e.type.typeParameters.toString(), '[T, E]');
-    expect(e.type.typeArguments.toString(), '[T, E]');
-    expect(e.type.toString(), '((E) → T) → List<T>');
+    expect(e.type.boundTypeParameters.toString(), '[T]');
+    expect(e.type.typeParameters.toString(), '[E]');
+    expect(e.type.typeArguments.toString(), '[E]');
+    expect(e.type.toString(), '<T>((E) → T) → List<T>');
 
     SimpleIdentifier c = _findIdentifier('cOfString');
     FunctionType ft = (c.staticType as InterfaceType).getMethod('f').type;
-    expect(ft.toString(), '((String) → T) → List<T>');
-    DartType t = e.typeParameters[0].type;
-    ft = ft.substitute2([typeProvider.intType], [t]);
+    expect(ft.toString(), '<T>((String) → T) → List<T>');
+    ft = ft.instantiate([typeProvider.intType]);
     expect(ft.toString(), '((String) → int) → List<int>');
   }
 
+  void test_genericMethod_nestedCapture() {
+    _resolveTestUnit(r'''
+class C<T> {
+  /*=T*/ f/*<S>*/(/*=S*/ x) {
+    new C<S>().f/*<int>*/(3);
+    new C<S>().f; // tear-off
+    return null;
+  }
+}
+''');
+    SimpleIdentifier f = _findIdentifier('f/*<int>*/(3);');
+    expect(f.staticType.toString(), '(int) → S');
+    FunctionType ft = f.staticType;
+    expect('${ft.typeArguments}/${ft.typeParameters}', '[S, int]/[T, S]');
+
+    f = _findIdentifier('f;');
+    expect(f.staticType.toString(), '<Sâ‚€>(Sâ‚€) → S');
+  }
+
+  void test_genericMethod_nestedFunctions() {
+    _resolveTestUnit(r'''
+/*=S*/ f/*<S>*/(/*=S*/ x) {
+  g/*<S>*/(/*=S*/ x) => f;
+  return null;
+}
+''');
+    SimpleIdentifier g = _findIdentifier('f');
+    expect(g.staticType.toString(), '<S>(S) → S');
+    SimpleIdentifier f = _findIdentifier('g');
+    expect(f.staticType.toString(), '<S>(S) → dynamic');
+  }
+
   void test_pseudoGeneric_max_doubleDouble() {
     String code = r'''
 import 'dart:math';
@@ -12261,6 +13271,22 @@
     expect(declaration.initializer.propagatedType, isNull);
   }
 
+  void test_pseudoGeneric_max_doubleDouble_prefixed() {
+    String code = r'''
+import 'dart:math' as math;
+main() {
+  var foo = math.max(1.0, 2.0);
+}
+''';
+    _resolveTestUnit(code);
+
+    SimpleIdentifier identifier = _findIdentifier('foo');
+    VariableDeclaration declaration =
+        identifier.getAncestor((node) => node is VariableDeclaration);
+    expect(declaration.initializer.staticType.name, 'double');
+    expect(declaration.initializer.propagatedType, isNull);
+  }
+
   void test_pseudoGeneric_max_doubleInt() {
     String code = r'''
 import 'dart:math';
@@ -12328,6 +13354,25 @@
     expect(declaration.initializer.propagatedType, isNull);
   }
 
+  void test_pseudoGeneric_then_prefixed() {
+    String code = r'''
+import 'dart:async' as async;
+String toString(int x) => x.toString();
+main() {
+  async.Future<int> bar = null;
+  var foo = bar.then(toString);
+}
+''';
+    _resolveTestUnit(code);
+
+    SimpleIdentifier identifier = _findIdentifier('foo');
+    VariableDeclaration declaration =
+        identifier.getAncestor((node) => node is VariableDeclaration);
+
+    expect(declaration.initializer.staticType.toString(), "Future<String>");
+    expect(declaration.initializer.propagatedType, isNull);
+  }
+
   void test_ternaryOperator_null_left() {
     String code = r'''
 main() {
@@ -12801,108 +13846,6 @@
 
 @reflectiveTest
 class TypePropagationTest extends ResolverTestCase {
-  void fail_finalPropertyInducingVariable_classMember_instance() {
-    addNamedSource(
-        "/lib.dart",
-        r'''
-class A {
-  final v = 0;
-}''');
-    String code = r'''
-import 'lib.dart';
-f(A a) {
-  return a.v; // marker
-}''';
-    _assertTypeOfMarkedExpression(
-        code, typeProvider.dynamicType, typeProvider.intType);
-  }
-
-  void fail_finalPropertyInducingVariable_classMember_instance_inherited() {
-    addNamedSource(
-        "/lib.dart",
-        r'''
-class A {
-  final v = 0;
-}''');
-    String code = r'''
-import 'lib.dart';
-class B extends A {
-  m() {
-    return v; // marker
-  }
-}''';
-    _assertTypeOfMarkedExpression(
-        code, typeProvider.dynamicType, typeProvider.intType);
-  }
-
-  void fail_finalPropertyInducingVariable_classMember_instance_propagatedTarget() {
-    addNamedSource(
-        "/lib.dart",
-        r'''
-class A {
-  final v = 0;
-}''');
-    String code = r'''
-import 'lib.dart';
-f(p) {
-  if (p is A) {
-    return p.v; // marker
-  }
-}''';
-    _assertTypeOfMarkedExpression(
-        code, typeProvider.dynamicType, typeProvider.intType);
-  }
-
-  void fail_finalPropertyInducingVariable_classMember_instance_unprefixed() {
-    String code = r'''
-class A {
-  final v = 0;
-  m() {
-    v; // marker
-  }
-}''';
-    _assertTypeOfMarkedExpression(
-        code, typeProvider.dynamicType, typeProvider.intType);
-  }
-
-  void fail_finalPropertyInducingVariable_classMember_static() {
-    addNamedSource(
-        "/lib.dart",
-        r'''
-class A {
-  static final V = 0;
-}''');
-    String code = r'''
-import 'lib.dart';
-f() {
-  return A.V; // marker
-}''';
-    _assertTypeOfMarkedExpression(
-        code, typeProvider.dynamicType, typeProvider.intType);
-  }
-
-  void fail_finalPropertyInducingVariable_topLevelVaraible_prefixed() {
-    addNamedSource("/lib.dart", "final V = 0;");
-    String code = r'''
-import 'lib.dart' as p;
-f() {
-  var v2 = p.V; // marker prefixed
-}''';
-    _assertTypeOfMarkedExpression(
-        code, typeProvider.dynamicType, typeProvider.intType);
-  }
-
-  void fail_finalPropertyInducingVariable_topLevelVaraible_simple() {
-    addNamedSource("/lib.dart", "final V = 0;");
-    String code = r'''
-import 'lib.dart';
-f() {
-  return V; // marker simple
-}''';
-    _assertTypeOfMarkedExpression(
-        code, typeProvider.dynamicType, typeProvider.intType);
-  }
-
   void fail_mergePropagatedTypesAtJoinPoint_1() {
     // https://code.google.com/p/dart/issues/detail?id=19929
     _assertTypeOfMarkedExpression(
@@ -13187,6 +14130,122 @@
     expect(identifier.propagatedType.name, "CanvasRenderingContext2D");
   }
 
+  void test_finalPropertyInducingVariable_classMember_instance() {
+    // TODO(scheglov) remove after switching to the task model
+    if (!AnalysisEngine.instance.useTaskModel) return;
+    addNamedSource(
+        "/lib.dart",
+        r'''
+class A {
+  final v = 0;
+}''');
+    String code = r'''
+import 'lib.dart';
+f(A a) {
+  return a.v; // marker
+}''';
+    _assertTypeOfMarkedExpression(
+        code, typeProvider.dynamicType, typeProvider.intType);
+  }
+
+  void test_finalPropertyInducingVariable_classMember_instance_inherited() {
+    // TODO(scheglov) remove after switching to the task model
+    if (!AnalysisEngine.instance.useTaskModel) return;
+    addNamedSource(
+        "/lib.dart",
+        r'''
+class A {
+  final v = 0;
+}''');
+    String code = r'''
+import 'lib.dart';
+class B extends A {
+  m() {
+    return v; // marker
+  }
+}''';
+    _assertTypeOfMarkedExpression(
+        code, typeProvider.dynamicType, typeProvider.intType);
+  }
+
+  void test_finalPropertyInducingVariable_classMember_instance_propagatedTarget() {
+    // TODO(scheglov) remove after switching to the task model
+    if (!AnalysisEngine.instance.useTaskModel) return;
+    addNamedSource(
+        "/lib.dart",
+        r'''
+class A {
+  final v = 0;
+}''');
+    String code = r'''
+import 'lib.dart';
+f(p) {
+  if (p is A) {
+    return p.v; // marker
+  }
+}''';
+    _assertTypeOfMarkedExpression(
+        code, typeProvider.dynamicType, typeProvider.intType);
+  }
+
+  void test_finalPropertyInducingVariable_classMember_instance_unprefixed() {
+    // TODO(scheglov) remove after switching to the task model
+    if (!AnalysisEngine.instance.useTaskModel) return;
+    String code = r'''
+class A {
+  final v = 0;
+  m() {
+    v; // marker
+  }
+}''';
+    _assertTypeOfMarkedExpression(
+        code, typeProvider.dynamicType, typeProvider.intType);
+  }
+
+  void test_finalPropertyInducingVariable_classMember_static() {
+    // TODO(scheglov) remove after switching to the task model
+    if (!AnalysisEngine.instance.useTaskModel) return;
+    addNamedSource(
+        "/lib.dart",
+        r'''
+class A {
+  static final V = 0;
+}''');
+    String code = r'''
+import 'lib.dart';
+f() {
+  return A.V; // marker
+}''';
+    _assertTypeOfMarkedExpression(
+        code, typeProvider.dynamicType, typeProvider.intType);
+  }
+
+  void test_finalPropertyInducingVariable_topLevelVariable_prefixed() {
+    // TODO(scheglov) remove after switching to the task model
+    if (!AnalysisEngine.instance.useTaskModel) return;
+    addNamedSource("/lib.dart", "final V = 0;");
+    String code = r'''
+import 'lib.dart' as p;
+f() {
+  var v2 = p.V; // marker prefixed
+}''';
+    _assertTypeOfMarkedExpression(
+        code, typeProvider.dynamicType, typeProvider.intType);
+  }
+
+  void test_finalPropertyInducingVariable_topLevelVariable_simple() {
+    // TODO(scheglov) remove after switching to the task model
+    if (!AnalysisEngine.instance.useTaskModel) return;
+    addNamedSource("/lib.dart", "final V = 0;");
+    String code = r'''
+import 'lib.dart';
+f() {
+  return V; // marker simple
+}''';
+    _assertTypeOfMarkedExpression(
+        code, typeProvider.dynamicType, typeProvider.intType);
+  }
+
   void test_forEach() {
     String code = r'''
 main() {
@@ -13606,6 +14665,25 @@
     }
   }
 
+  void test_invocation_target_prefixed() {
+    addNamedSource(
+        '/helper.dart',
+        '''
+library helper;
+int max(int x, int y) => 0;
+''');
+    String code = '''
+import 'helper.dart' as helper;
+main() {
+  helper.max(10, 10); // marker
+}''';
+    SimpleIdentifier methodName =
+        _findMarkedIdentifier(code, "(10, 10); // marker");
+    MethodInvocation methodInvoke = methodName.parent;
+    expect(methodInvoke.methodName.staticElement, isNotNull);
+    expect(methodInvoke.methodName.propagatedElement, isNull);
+  }
+
   void test_is_conditional() {
     Source source = addSource(r'''
 class A {}
diff --git a/pkg/analyzer/test/generated/test_all.dart b/pkg/analyzer/test/generated/test_all.dart
index fb84d46..0a9a727 100644
--- a/pkg/analyzer/test/generated/test_all.dart
+++ b/pkg/analyzer/test/generated/test_all.dart
@@ -10,6 +10,7 @@
 import 'all_the_rest_test.dart' as all_the_rest;
 import 'ast_test.dart' as ast_test;
 import 'compile_time_error_code_test.dart' as compile_time_error_code_test;
+import 'declaration_resolver_test.dart' as declaration_resolver_test;
 import 'element_test.dart' as element_test;
 import 'engine_test.dart' as engine_test;
 import 'incremental_resolver_test.dart' as incremental_resolver_test;
@@ -33,6 +34,7 @@
     all_the_rest.main();
     ast_test.main();
     compile_time_error_code_test.main();
+    declaration_resolver_test.main();
     element_test.main();
     engine_test.main();
     incremental_resolver_test.main();
diff --git a/pkg/analyzer/test/generated/type_system_test.dart b/pkg/analyzer/test/generated/type_system_test.dart
index 289249a..e4501be 100644
--- a/pkg/analyzer/test/generated/type_system_test.dart
+++ b/pkg/analyzer/test/generated/type_system_test.dart
@@ -20,6 +20,7 @@
   runReflectiveTests(TypeSystemTest);
   runReflectiveTests(StrongSubtypingTest);
   runReflectiveTests(StrongAssignabilityTest);
+  runReflectiveTests(StrongGenericFunctionInferenceTest);
 }
 
 @reflectiveTest
@@ -296,6 +297,202 @@
 }
 
 @reflectiveTest
+class StrongGenericFunctionInferenceTest {
+  TypeProvider typeProvider;
+  StrongTypeSystemImpl typeSystem;
+
+  DartType get bottomType => typeProvider.bottomType;
+  InterfaceType get doubleType => typeProvider.doubleType;
+  DartType get dynamicType => typeProvider.dynamicType;
+  InterfaceType get functionType => typeProvider.functionType;
+  InterfaceType get intType => typeProvider.intType;
+  InterfaceType get iterableType => typeProvider.iterableType;
+  InterfaceType get listType => typeProvider.listType;
+  InterfaceType get numType => typeProvider.numType;
+  InterfaceType get objectType => typeProvider.objectType;
+  InterfaceType get stringType => typeProvider.stringType;
+  DartType get voidType => VoidTypeImpl.instance;
+
+  void setUp() {
+    typeProvider = new TestTypeProvider();
+    typeSystem = new StrongTypeSystemImpl();
+  }
+
+  void test_boundedByAnotherTypeParameter() {
+    // <TFrom, TTo extends Iterable<TFrom>>(TFrom) -> TTo
+    var tFrom = _typeParameter('TFrom');
+    var tTo = _typeParameter('TTo', iterableType.substitute4([tFrom]));
+    var cast = _functionType([tFrom, tTo], [tFrom], tTo);
+    expect(_inferCall(cast, [stringType]), [
+      stringType,
+      iterableType.substitute4([stringType])
+    ]);
+  }
+
+  void test_boundedRecursively() {
+    // class Clonable<T extends Clonable<T>>
+    ClassElementImpl clonable =
+        ElementFactory.classElement('Clonable', objectType, ['T']);
+    (clonable.typeParameters[0] as TypeParameterElementImpl).bound =
+        clonable.type;
+    // class Foo extends Clonable<Foo>
+    ClassElementImpl foo = ElementFactory.classElement('Foo', null);
+    foo.supertype = clonable.type.substitute4([foo.type]);
+
+    // <S extends Clonable<S>>
+    var s = _typeParameter('S');
+    (s.element as TypeParameterElementImpl).bound =
+        clonable.type.substitute4([s]);
+    // (S, S) -> S
+    var clone = _functionType([s], [s, s], s);
+    expect(_inferCall(clone, [foo.type, foo.type]), [foo.type]);
+
+    // Something invalid...
+    expect(_inferCall(clone, [stringType, numType]), [
+      clonable.type.substitute4([dynamicType])
+    ]);
+  }
+
+  void test_genericCastFunction() {
+    // <TFrom, TTo>(TFrom) -> TTo
+    var tFrom = _typeParameter('TFrom');
+    var tTo = _typeParameter('TTo');
+    var cast = _functionType([tFrom, tTo], [tFrom], tTo);
+    expect(_inferCall(cast, [intType]), [intType, dynamicType]);
+  }
+
+  void test_genericCastFunctionWithUpperBound() {
+    // <TFrom, TTo extends TFrom>(TFrom) -> TTo
+    var tFrom = _typeParameter('TFrom');
+    var tTo = _typeParameter('TTo', tFrom);
+    var cast = _functionType([tFrom, tTo], [tFrom], tTo);
+    expect(_inferCall(cast, [intType]), [intType, intType]);
+  }
+
+  void test_parametersToFunctionParam() {
+    // <T>(f(T t)) -> T
+    var t = _typeParameter('T');
+    var cast = _functionType([
+      t
+    ], [
+      _functionType([], [t], dynamicType)
+    ], t);
+    expect(
+        _inferCall(cast, [
+          _functionType([], [numType], dynamicType)
+        ]),
+        [numType]);
+  }
+
+  void test_parametersUseLeastUpperBound() {
+    // <T>(T x, T y) -> T
+    var t = _typeParameter('T');
+    var cast = _functionType([t], [t, t], t);
+    expect(_inferCall(cast, [intType, doubleType]), [numType]);
+  }
+
+  void test_parameterTypeUsesUpperBound() {
+    // <T extends num>(T) -> dynamic
+    var t = _typeParameter('T', numType);
+    var f = _functionType([t], [t], dynamicType);
+    expect(_inferCall(f, [intType]), [intType]);
+  }
+
+  void test_returnFunctionWithGenericParameter() {
+    // <T>(T -> T) -> (T -> void)
+    var t = _typeParameter('T');
+    var f = _functionType([
+      t
+    ], [
+      _functionType([], [t], t)
+    ], _functionType([], [t], voidType));
+    expect(
+        _inferCall(f, [
+          _functionType([], [numType], intType)
+        ]),
+        [numType]);
+  }
+
+  void test_returnFunctionWithGenericParameterAndReturn() {
+    // <T>(T -> T) -> (T -> T)
+    var t = _typeParameter('T');
+    var f = _functionType([
+      t
+    ], [
+      _functionType([], [t], t)
+    ], _functionType([], [t], t));
+    expect(
+        _inferCall(f, [
+          _functionType([], [numType], intType)
+        ]),
+        [numType]);
+  }
+
+  void test_returnFunctionWithGenericReturn() {
+    // <T>(T -> T) -> (() -> T)
+    var t = _typeParameter('T');
+    var f = _functionType([
+      t
+    ], [
+      _functionType([], [t], t)
+    ], _functionType([], [], t));
+    expect(
+        _inferCall(f, [
+          _functionType([], [numType], intType)
+        ]),
+        [intType]);
+  }
+
+  void test_unifyParametersToFunctionParam() {
+    // <T>(f(T t), g(T t)) -> T
+    var t = _typeParameter('T');
+    var cast = _functionType([
+      t
+    ], [
+      _functionType([], [t], dynamicType),
+      _functionType([], [t], dynamicType)
+    ], t);
+    expect(
+        _inferCall(cast, [
+          _functionType([], [intType], dynamicType),
+          _functionType([], [doubleType], dynamicType)
+        ]),
+        [dynamicType]);
+  }
+
+  void test_unusedReturnTypeIsDynamic() {
+    // <T>() -> T
+    var t = _typeParameter('T');
+    var f = _functionType([t], [], t);
+    expect(_inferCall(f, []), [dynamicType]);
+  }
+
+  void test_unusedReturnTypeWithUpperBound() {
+    // <T extends num>() -> T
+    var t = _typeParameter('T', numType);
+    var f = _functionType([t], [], t);
+    expect(_inferCall(f, []), [numType]);
+  }
+
+  FunctionTypeImpl _functionType(
+      List<DartType> typeParams, List<DartType> params, DartType result) {
+    FunctionElementImpl f = ElementFactory.functionElement8(params, result);
+    f.typeParameters =
+        new List<TypeParameterElement>.from(typeParams.map((t) => t.element));
+    return f.type = new FunctionTypeImpl(f);
+  }
+
+  List<DartType> _inferCall(FunctionTypeImpl ft, List<DartType> arguments) {
+    FunctionType inferred = typeSystem.inferCallFromArguments(
+        typeProvider, ft, ft.parameters.map((p) => p.type).toList(), arguments);
+    return inferred.typeArguments;
+  }
+
+  TypeParameterType _typeParameter(String name, [DartType bound]) =>
+      ElementFactory.typeParameterWithType(name, bound).type;
+}
+
+@reflectiveTest
 class StrongSubtypingTest {
   TypeProvider typeProvider;
   TypeSystem typeSystem;
@@ -478,6 +675,13 @@
         subtypes: subtypes);
   }
 
+  // Regression test for https://github.com/dart-lang/sdk/issues/25069
+  void test_isSubtypeOf_simple_function_void() {
+    FunctionType functionType =
+        TypeBuilder.functionType(<DartType>[intType], objectType);
+    _checkIsNotSubtypeOf(voidType, functionType);
+  }
+
   void test_isSubtypeOf_simple_function() {
     FunctionType top =
         TypeBuilder.functionType(<DartType>[intType], objectType);
diff --git a/pkg/analyzer/test/source/package_map_provider_test.dart b/pkg/analyzer/test/source/package_map_provider_test.dart
index af5bedf..3701630 100644
--- a/pkg/analyzer/test/source/package_map_provider_test.dart
+++ b/pkg/analyzer/test/source/package_map_provider_test.dart
@@ -8,119 +8,132 @@
 import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/source/package_map_provider.dart';
 import 'package:analyzer/source/pub_package_map_provider.dart';
+import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/sdk_io.dart';
 import 'package:unittest/unittest.dart';
 
+import '../reflective_tests.dart';
 import '../utils.dart';
 
 main() {
   initializeTestEnvironment();
+  runReflectiveTests(PubPackageMapProviderTest);
+}
 
-  group('PubPackageMapProvider', () {
-    group('parsePackageMap', () {
-      MemoryResourceProvider resourceProvider;
-      PubPackageMapProvider packageMapProvider;
-      const String projectPath = '/path/to/project';
-      Folder projectFolder;
+@reflectiveTest
+class PubPackageMapProviderTest {
+  static const String projectPath = '/path/to/project';
 
-      setUp(() {
-        resourceProvider = new MemoryResourceProvider();
-        packageMapProvider = new PubPackageMapProvider(
-            resourceProvider, DirectoryBasedDartSdk.defaultSdk);
-        projectFolder = resourceProvider.newFolder(projectPath);
-      });
+  DartSdk sdk = DirectoryBasedDartSdk.defaultSdk;
+  MemoryResourceProvider resourceProvider;
+  PubPackageMapProvider packageMapProvider;
+  Folder projectFolder;
 
-      PackageMapInfo parsePackageMap(Object obj) {
-        return packageMapProvider.parsePackageMap(obj, projectFolder);
-      }
+  PackageMapInfo parsePackageMap(Map obj) {
+    return packageMapProvider.parsePackageMap(obj, projectFolder);
+  }
 
-      test('normal folder', () {
-        String packageName = 'foo';
-        String folderPath = '/path/to/folder';
-        resourceProvider.newFolder(folderPath);
-        Map<String, List<Folder>> result = parsePackageMap({
-          'packages': {packageName: folderPath}
-        }).packageMap;
-        expect(result, hasLength(1));
-        expect(result.keys, contains(packageName));
-        expect(result[packageName], hasLength(1));
-        expect(result[packageName][0], new isInstanceOf<Folder>());
-        expect(result[packageName][0].path, equals(folderPath));
-      });
+  void setUp() {
+    resourceProvider = new MemoryResourceProvider();
+    packageMapProvider = new PubPackageMapProvider(resourceProvider, sdk);
+    projectFolder = resourceProvider.newFolder(projectPath);
+  }
 
-      test("don't ignore nonexistent folder", () {
-        String packageName = 'foo';
-        String folderPath = '/path/to/folder';
-        Map<String, List<Folder>> result = parsePackageMap({
-          'packages': {packageName: folderPath}
-        }).packageMap;
-        expect(result, hasLength(1));
-        expect(result.keys, contains(packageName));
-        expect(result[packageName], hasLength(1));
-        expect(result[packageName][0], new isInstanceOf<Folder>());
-        expect(result[packageName][0].path, equals(folderPath));
-      });
-
-      test('package maps to list', () {
-        String packageName = 'foo';
-        String folderPath1 = '/path/to/folder1';
-        String folderPath2 = '/path/to/folder2';
-        resourceProvider.newFolder(folderPath1);
-        resourceProvider.newFolder(folderPath2);
-        Map<String, List<Folder>> result = parsePackageMap({
-          'packages': {
-            packageName: [folderPath1, folderPath2]
-          }
-        }).packageMap;
-        expect(result, hasLength(1));
-        expect(result.keys, contains(packageName));
-        expect(result[packageName], hasLength(2));
-        for (int i = 0; i < 2; i++) {
-          expect(result[packageName][i], new isInstanceOf<Folder>());
-          expect(result[packageName][i].path, isIn([folderPath1, folderPath2]));
-        }
-      });
-
-      test('Handle dependencies', () {
-        String path1 = '/path/to/folder1/pubspec.lock';
-        String path2 = '/path/to/folder2/pubspec.lock';
-        resourceProvider.newFile(path1, '...');
-        resourceProvider.newFile(path2, '...');
-        Set<String> dependencies = parsePackageMap({
-          'packages': {},
-          'input_files': [path1, path2]
-        }).dependencies;
-        expect(dependencies, hasLength(2));
-        expect(dependencies, contains(path1));
-        expect(dependencies, contains(path2));
-      });
-
-      test('Relative path in packages', () {
-        String packagePath = '/path/to/package';
-        String relativePackagePath = '../package';
-        String packageName = 'foo';
-        resourceProvider.newFolder(projectPath);
-        resourceProvider.newFolder(packagePath);
-        Map<String, List<Folder>> result = parsePackageMap({
-          'packages': {
-            packageName: [relativePackagePath]
-          }
-        }).packageMap;
-        expect(result[packageName][0].path, equals(packagePath));
-      });
-
-      test('Relative path in dependencies', () {
-        String dependencyPath = '/path/to/pubspec.lock';
-        String relativeDependencyPath = '../pubspec.lock';
-        resourceProvider.newFolder(projectPath);
-        resourceProvider.newFile(dependencyPath, 'contents');
-        Set<String> dependencies = parsePackageMap({
-          'packages': {},
-          'input_files': [relativeDependencyPath]
-        }).dependencies;
-        expect(dependencies, hasLength(1));
-        expect(dependencies, contains(dependencyPath));
-      });
+  void test_computePackageMap_noLockFile() {
+    packageMapProvider =
+        new PubPackageMapProvider(resourceProvider, sdk, (Folder folder) {
+      fail('Unexpected "pub list" invocation');
     });
-  });
+    PackageMapInfo info = packageMapProvider.computePackageMap(projectFolder);
+    expect(info.packageMap, isNull);
+    expect(info.dependencies, unorderedEquals(['$projectPath/pubspec.lock']));
+  }
+
+  void test_parsePackageMap_dontIgnoreNonExistingFolder() {
+    String packageName = 'foo';
+    String folderPath = '/path/to/folder';
+    Map<String, List<Folder>> result = parsePackageMap({
+      'packages': {packageName: folderPath}
+    }).packageMap;
+    expect(result, hasLength(1));
+    expect(result.keys, contains(packageName));
+    expect(result[packageName], hasLength(1));
+    expect(result[packageName][0], new isInstanceOf<Folder>());
+    expect(result[packageName][0].path, equals(folderPath));
+  }
+
+  void test_parsePackageMap_handleDependencies() {
+    String path1 = '/path/to/folder1/pubspec.lock';
+    String path2 = '/path/to/folder2/pubspec.lock';
+    resourceProvider.newFile(path1, '...');
+    resourceProvider.newFile(path2, '...');
+    Set<String> dependencies = parsePackageMap({
+      'packages': {},
+      'input_files': [path1, path2]
+    }).dependencies;
+    expect(dependencies, hasLength(2));
+    expect(dependencies, contains(path1));
+    expect(dependencies, contains(path2));
+  }
+
+  void test_parsePackageMap_normalFolder() {
+    String packageName = 'foo';
+    String folderPath = '/path/to/folder';
+    resourceProvider.newFolder(folderPath);
+    Map<String, List<Folder>> result = parsePackageMap({
+      'packages': {packageName: folderPath}
+    }).packageMap;
+    expect(result, hasLength(1));
+    expect(result.keys, contains(packageName));
+    expect(result[packageName], hasLength(1));
+    expect(result[packageName][0], new isInstanceOf<Folder>());
+    expect(result[packageName][0].path, equals(folderPath));
+  }
+
+  void test_parsePackageMap_packageMapsToList() {
+    String packageName = 'foo';
+    String folderPath1 = '/path/to/folder1';
+    String folderPath2 = '/path/to/folder2';
+    resourceProvider.newFolder(folderPath1);
+    resourceProvider.newFolder(folderPath2);
+    Map<String, List<Folder>> result = parsePackageMap({
+      'packages': {
+        packageName: [folderPath1, folderPath2]
+      }
+    }).packageMap;
+    expect(result, hasLength(1));
+    expect(result.keys, contains(packageName));
+    expect(result[packageName], hasLength(2));
+    for (int i = 0; i < 2; i++) {
+      expect(result[packageName][i], new isInstanceOf<Folder>());
+      expect(result[packageName][i].path, isIn([folderPath1, folderPath2]));
+    }
+  }
+
+  void test_parsePackageMap_relativePahInPackages() {
+    String packagePath = '/path/to/package';
+    String relativePackagePath = '../package';
+    String packageName = 'foo';
+    resourceProvider.newFolder(projectPath);
+    resourceProvider.newFolder(packagePath);
+    Map<String, List<Folder>> result = parsePackageMap({
+      'packages': {
+        packageName: [relativePackagePath]
+      }
+    }).packageMap;
+    expect(result[packageName][0].path, equals(packagePath));
+  }
+
+  void test_parsePackageMap_relativePathInDependencies() {
+    String dependencyPath = '/path/to/pubspec.lock';
+    String relativeDependencyPath = '../pubspec.lock';
+    resourceProvider.newFolder(projectPath);
+    resourceProvider.newFile(dependencyPath, 'contents');
+    Set<String> dependencies = parsePackageMap({
+      'packages': {},
+      'input_files': [relativeDependencyPath]
+    }).dependencies;
+    expect(dependencies, hasLength(1));
+    expect(dependencies, contains(dependencyPath));
+  }
 }
diff --git a/pkg/analyzer/test/src/context/cache_test.dart b/pkg/analyzer/test/src/context/cache_test.dart
index 75c156a..0962474 100644
--- a/pkg/analyzer/test/src/context/cache_test.dart
+++ b/pkg/analyzer/test/src/context/cache_test.dart
@@ -961,12 +961,31 @@
     expect(createPartition(), isNotNull);
   }
 
+  void test_dispose() {
+    CachePartition partition = createPartition();
+    Source source1 = new TestSource('/1.dart');
+    Source source2 = new TestSource('/2.dart');
+    CacheEntry entry1 = new CacheEntry(source1);
+    CacheEntry entry2 = new CacheEntry(source2);
+    // add two sources
+    partition.put(entry1);
+    partition.put(entry2);
+    expect(partition.entryMap, hasLength(2));
+    expect(partition.pathToSource, hasLength(2));
+    expect(partition.sources, unorderedEquals([source1, source2]));
+    // dispose, no sources
+    partition.dispose();
+    expect(partition.entryMap, isEmpty);
+    expect(partition.pathToSource, isEmpty);
+    expect(partition.sources, isEmpty);
+  }
+
   void test_entrySet() {
     CachePartition partition = createPartition();
     AnalysisTarget target = new TestSource();
     CacheEntry entry = new CacheEntry(target);
     partition.put(entry);
-    Map<AnalysisTarget, CacheEntry> entryMap = partition.map;
+    Map<AnalysisTarget, CacheEntry> entryMap = partition.entryMap;
     expect(entryMap, hasLength(1));
     AnalysisTarget entryKey = entryMap.keys.first;
     expect(entryKey, target);
diff --git a/pkg/analyzer/test/src/context/mock_sdk.dart b/pkg/analyzer/test/src/context/mock_sdk.dart
index 121fb5d..ad1c2f6 100644
--- a/pkg/analyzer/test/src/context/mock_sdk.dart
+++ b/pkg/analyzer/test/src/context/mock_sdk.dart
@@ -86,6 +86,11 @@
 abstract class Iterable<E> {
   Iterator<E> get iterator;
   bool get isEmpty;
+
+  Iterable/*<R>*/ map/*<R>*/(/*=R*/ f(E e));
+
+  /*=R*/ fold/*<R>*/(/*=R*/ initialValue,
+      /*=R*/ combine(/*=R*/ previousValue, E element));
 }
 
 abstract class List<E> implements Iterable<E> {
@@ -123,7 +128,10 @@
 class Future<T> {
   factory Future.delayed(Duration duration, [T computation()]) => null;
   factory Future.value([value]) => null;
-  static Future wait(List<Future> futures) => null;
+
+  static Future<List</*<T>*/> wait/*<T>*/(
+      Iterable<Future/*<T>*/> futures) => null;
+  Future/*<R>*/ then/*<R>*/(/*=R*/ onValue(T value)) => null;
 }
 ''',
       const <_MockSdkFile>[
@@ -162,11 +170,14 @@
       '/lib/math/math.dart',
       '''
 library dart.math;
+
 const double E = 2.718281828459045;
 const double PI = 3.1415926535897932;
 const double LN10 =  2.302585092994046;
-num min(num a, num b) => 0;
-num max(num a, num b) => 0;
+
+num/*=T*/ min/*<T extends num>*/(num/*=T*/ a, num/*=T*/ b) => null;
+num/*=T*/ max/*<T extends num>*/(num/*=T*/ a, num/*=T*/ b) => null;
+
 external double cos(num x);
 external double sin(num x);
 external double sqrt(num x);
diff --git a/pkg/analyzer/test/src/summary/summary_test.dart b/pkg/analyzer/test/src/summary/summary_test.dart
index e0cfbca..be2844e 100644
--- a/pkg/analyzer/test/src/summary/summary_test.dart
+++ b/pkg/analyzer/test/src/summary/summary_test.dart
@@ -209,8 +209,8 @@
       String relativeUri, String expectedName,
       {String expectedPrefix,
       bool allowTypeParameters: false,
-      PrelinkedReferenceKind expectedKind:
-          PrelinkedReferenceKind.classOrEnum}) {
+      PrelinkedReferenceKind expectedKind: PrelinkedReferenceKind.classOrEnum,
+      int expectedUnit: 0}) {
     expect(typeRef, new isInstanceOf<UnlinkedTypeRef>());
     expect(typeRef.paramReference, 0);
     int index = typeRef.reference;
@@ -239,6 +239,7 @@
       }
     }
     expect(referenceResolution.kind, expectedKind);
+    expect(referenceResolution.unit, expectedUnit);
   }
 
   /**
@@ -1658,7 +1659,8 @@
             otherDeclarations: 'library my.lib; import "a.dart";'),
         absUri('/a.dart'),
         'a.dart',
-        'C');
+        'C',
+        expectedUnit: 1);
   }
 
   test_type_reference_to_imported_part_with_prefix() {
@@ -1670,7 +1672,8 @@
         absUri('/a.dart'),
         'a.dart',
         'C',
-        expectedPrefix: 'p');
+        expectedPrefix: 'p',
+        expectedUnit: 1);
   }
 
   test_type_reference_to_internal_class() {
@@ -1699,7 +1702,8 @@
             otherDeclarations: 'library my.lib; part "a.dart";'),
         null,
         null,
-        'C');
+        'C',
+        expectedUnit: 1);
   }
 
   test_type_reference_to_nonexistent_file_via_prefix() {
@@ -1723,7 +1727,7 @@
     // The referenced unit should be 2, since unit 0 is a.dart and unit 1 is
     // b.dart.  a.dart and b.dart are counted even though nothing is imported
     // from them.
-    checkTypeRef(typeRef, absUri('/a.dart'), 'a.dart', 'C');
+    checkTypeRef(typeRef, absUri('/a.dart'), 'a.dart', 'C', expectedUnit: 2);
   }
 
   test_type_unresolved() {
diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart
index c0ad43b..dcb6980 100644
--- a/pkg/analyzer/test/src/task/dart_test.dart
+++ b/pkg/analyzer/test/src/task/dart_test.dart
@@ -44,6 +44,7 @@
   runReflectiveTests(ComputeConstantValueTaskTest);
   runReflectiveTests(ComputeInferableStaticVariableDependenciesTaskTest);
   runReflectiveTests(ComputeLibraryCycleTaskTest);
+  runReflectiveTests(ComputePropagableVariableDependenciesTaskTest);
   runReflectiveTests(ContainingLibrariesTaskTest);
   runReflectiveTests(DartErrorsTaskTest);
   runReflectiveTests(ErrorFilterTest);
@@ -59,6 +60,8 @@
   runReflectiveTests(LibraryUnitErrorsTaskTest);
   runReflectiveTests(ParseDartTaskTest);
   runReflectiveTests(PartiallyResolveUnitReferencesTaskTest);
+  runReflectiveTests(PropagateVariableTypesInUnitTaskTest);
+  runReflectiveTests(PropagateVariableTypeTaskTest);
   runReflectiveTests(ResolveInstanceFieldsInUnitTaskTest);
   runReflectiveTests(ResolveLibraryTypeNamesTaskTest);
   runReflectiveTests(ResolveUnitTaskTest);
@@ -92,6 +95,8 @@
     new isInstanceOf<ComputeConstantValueTask>();
 isInstanceOf isComputeInferableStaticVariableDependenciesTask =
     new isInstanceOf<ComputeInferableStaticVariableDependenciesTask>();
+isInstanceOf isComputePropagableVariableDependenciesTask =
+    new isInstanceOf<ComputePropagableVariableDependenciesTask>();
 isInstanceOf isContainingLibrariesTask =
     new isInstanceOf<ContainingLibrariesTask>();
 isInstanceOf isDartErrorsTask = new isInstanceOf<DartErrorsTask>();
@@ -116,6 +121,10 @@
 isInstanceOf isParseDartTask = new isInstanceOf<ParseDartTask>();
 isInstanceOf isPartiallyResolveUnitReferencesTask =
     new isInstanceOf<PartiallyResolveUnitReferencesTask>();
+isInstanceOf isPropagateVariableTypesInUnitTask =
+    new isInstanceOf<PropagateVariableTypesInUnitTask>();
+isInstanceOf isPropagateVariableTypeTask =
+    new isInstanceOf<PropagateVariableTypeTask>();
 isInstanceOf isResolveLibraryTypeNamesTask =
     new isInstanceOf<ResolveLibraryTypeNamesTask>();
 isInstanceOf isResolveUnitTask = new isInstanceOf<ResolveUnitTask>();
@@ -1275,7 +1284,7 @@
     // should be set to the same error state.
     for (String otherVariableName in otherVariables) {
       PropertyInducingElement otherVariableElement =
-          _findVariable(unit, otherVariableName);
+          AstFinder.getTopLevelVariableElement(unit, otherVariableName);
       _expectCircularityError((otherVariableElement
           as TopLevelVariableElementImpl).evaluationResult);
     }
@@ -1289,7 +1298,8 @@
   EvaluationResultImpl _evaluateConstant(
       CompilationUnit unit, String variableName) {
     // Find the element for the given constant.
-    PropertyInducingElement variableElement = _findVariable(unit, variableName);
+    PropertyInducingElement variableElement =
+        AstFinder.getTopLevelVariableElement(unit, variableName);
     // Now compute the value of the constant.
     computeResult(variableElement, CONSTANT_VALUE,
         matcher: isComputeConstantValueTask);
@@ -1307,13 +1317,6 @@
         CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT);
   }
 
-  PropertyInducingElement _findVariable(
-      CompilationUnit unit, String variableName) {
-    // Find the element for the given constant.
-    return unit.element.topLevelVariables.firstWhere(
-        (TopLevelVariableElement variable) => variable.name == variableName);
-  }
-
   CompilationUnit _resolveSource(Source source) {
     LibrarySpecificUnit librarySpecificUnit =
         new LibrarySpecificUnit(source, source);
@@ -1761,6 +1764,134 @@
 }
 
 @reflectiveTest
+class ComputePropagableVariableDependenciesTaskTest
+    extends _AbstractDartTaskTest {
+  test_perform_instanceField() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+class A {
+  final a = a1 + a2 + a3 + a4 + B.b1 + B.b2 + B.b3 + B.b4;
+  static const a1 = 1;
+  final a2 = 2;
+  final a3;
+  var   a4 = 4;
+}
+class B {
+  static const b1 = 1;
+  static final b2 = 2;
+  static final b3;
+  static var   b4 = 4;
+}
+''');
+    LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+    computeResult(target, RESOLVED_UNIT5);
+    CompilationUnit unit = outputs[RESOLVED_UNIT5];
+    FieldElement elementA = AstFinder.getFieldInClassElement(unit, 'A', 'a');
+    // compute
+    computeResult(elementA, PROPAGABLE_VARIABLE_DEPENDENCIES,
+        matcher: isComputePropagableVariableDependenciesTask);
+    // verify
+    expect(outputs, hasLength(1));
+    List<VariableElement> dependencies =
+        outputs[PROPAGABLE_VARIABLE_DEPENDENCIES];
+    expect(
+        dependencies,
+        unorderedEquals([
+          AstFinder.getFieldInClassElement(unit, 'A', 'a1'),
+          AstFinder.getFieldInClassElement(unit, 'A', 'a2'),
+          AstFinder.getFieldInClassElement(unit, 'B', 'b1'),
+          AstFinder.getFieldInClassElement(unit, 'B', 'b2')
+        ]));
+  }
+
+  test_perform_topLevel() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+const a = d1 + d2 + d3 + d4;
+const d1 = 1;
+final d2 = 2;
+final d3;
+var   d4 = 4;
+''');
+    LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+    computeResult(target, RESOLVED_UNIT5);
+    CompilationUnit unit = outputs[RESOLVED_UNIT5];
+    TopLevelVariableElement elementA =
+        AstFinder.getTopLevelVariableElement(unit, 'a');
+    // compute
+    computeResult(elementA, PROPAGABLE_VARIABLE_DEPENDENCIES,
+        matcher: isComputePropagableVariableDependenciesTask);
+    // verify
+    expect(outputs, hasLength(1));
+    List<VariableElement> dependencies =
+        outputs[PROPAGABLE_VARIABLE_DEPENDENCIES];
+    expect(
+        dependencies,
+        unorderedEquals([
+          AstFinder.getTopLevelVariableElement(unit, 'd1'),
+          AstFinder.getTopLevelVariableElement(unit, 'd2')
+        ]));
+  }
+
+  test_perform_topLevel_ignoreLocal() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+final a = () {
+  const b = 2;
+  const c = 3;
+  return b + c;
+}() + d;
+final d = 4;
+''');
+    LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+    computeResult(target, RESOLVED_UNIT5);
+    CompilationUnit unit = outputs[RESOLVED_UNIT5];
+    TopLevelVariableElement elementA =
+        AstFinder.getTopLevelVariableElement(unit, 'a');
+    // compute
+    computeResult(elementA, PROPAGABLE_VARIABLE_DEPENDENCIES,
+        matcher: isComputePropagableVariableDependenciesTask);
+    // verify
+    expect(outputs, hasLength(1));
+    List<VariableElement> dependencies =
+        outputs[PROPAGABLE_VARIABLE_DEPENDENCIES];
+    expect(dependencies,
+        unorderedEquals([AstFinder.getTopLevelVariableElement(unit, 'd')]));
+  }
+
+  test_perform_topLevel_withoutSpaceAfterType() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+const List<int>a=[b, c];
+const b = 1;
+const c = 2;
+''');
+    LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+    computeResult(target, RESOLVED_UNIT5);
+    CompilationUnit unit = outputs[RESOLVED_UNIT5];
+    TopLevelVariableElement elementA =
+        AstFinder.getTopLevelVariableElement(unit, 'a');
+    // compute
+    computeResult(elementA, PROPAGABLE_VARIABLE_DEPENDENCIES,
+        matcher: isComputePropagableVariableDependenciesTask);
+    // verify
+    expect(outputs, hasLength(1));
+    List<VariableElement> dependencies =
+        outputs[PROPAGABLE_VARIABLE_DEPENDENCIES];
+    expect(
+        dependencies,
+        unorderedEquals([
+          AstFinder.getTopLevelVariableElement(unit, 'b'),
+          AstFinder.getTopLevelVariableElement(unit, 'c')
+        ]));
+  }
+}
+
+@reflectiveTest
 class ContainingLibrariesTaskTest extends _AbstractDartTaskTest {
   test_perform_definingCompilationUnit() {
     AnalysisTarget library = newSource('/test.dart', 'library test;');
@@ -1831,6 +1962,32 @@
 }
 
 @reflectiveTest
+class ErrorFilterTest extends _AbstractDartTaskTest {
+  @override
+  setUp() {
+    super.setUp();
+    context.setConfigurationData(CONFIGURED_ERROR_FILTERS, [
+      (AnalysisError error) => error.errorCode.name == 'INVALID_ASSIGNMENT'
+    ]);
+  }
+
+  test_error_filters() {
+    AnalysisTarget library = newSource(
+        '/test.dart',
+        '''
+main() {
+  int x = ""; // INVALID_ASSIGNMENT (suppressed)
+  // UNUSED_LOCAL_VARIABLE
+}''');
+    computeResult(library, DART_ERRORS, matcher: isDartErrorsTask);
+    expect(outputs, hasLength(1));
+    List<AnalysisError> errors = outputs[DART_ERRORS];
+    expect(errors, hasLength(1));
+    expect(errors.first.errorCode, HintCode.UNUSED_LOCAL_VARIABLE);
+  }
+}
+
+@reflectiveTest
 class EvaluateUnitConstantsTaskTest extends _AbstractDartTaskTest {
   test_perform() {
     Source source = newSource(
@@ -1846,9 +2003,9 @@
 const x = const C();
 ''');
     LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
-    computeResult(target, RESOLVED_UNIT10,
+    computeResult(target, RESOLVED_UNIT11,
         matcher: isEvaluateUnitConstantsTask);
-    CompilationUnit unit = outputs[RESOLVED_UNIT10];
+    CompilationUnit unit = outputs[RESOLVED_UNIT11];
     CompilationUnitElement unitElement = unit.element;
     expect(
         (unitElement.types[0].constructors[0] as ConstructorElementImpl)
@@ -2241,30 +2398,6 @@
 }
 
 @reflectiveTest
-class ErrorFilterTest extends _AbstractDartTaskTest {
-  @override
-  setUp() {
-    super.setUp();
-    context.setConfigurationData(CONFIGURED_ERROR_FILTERS, [
-      (AnalysisError error) => error.errorCode.name == 'INVALID_ASSIGNMENT'
-    ]);
-  }
-
-  test_error_filters() {
-    AnalysisTarget library = newSource('/test.dart', '''
-main() {
-  int x = ""; // INVALID_ASSIGNMENT (suppressed)
-  // UNUSED_LOCAL_VARIABLE
-}''');
-    computeResult(library, DART_ERRORS, matcher: isDartErrorsTask);
-    expect(outputs, hasLength(1));
-    List<AnalysisError> errors = outputs[DART_ERRORS];
-    expect(errors, hasLength(1));
-    expect(errors.first.errorCode, HintCode.UNUSED_LOCAL_VARIABLE);
-  }
-}
-
-@reflectiveTest
 class GenerateLintsTaskTest extends _AbstractDartTaskTest {
   void enableLints() {
     AnalysisOptionsImpl options = context.analysisOptions;
@@ -2337,14 +2470,14 @@
 class Y {}
 class Z {}
 ''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8,
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9,
         matcher: isInferInstanceMembersInUnitTask);
-    CompilationUnit unit = outputs[RESOLVED_UNIT8];
-    VariableDeclaration field = getFieldInClass(unit, 'B', 'f');
-    MethodDeclaration method = getMethodInClass(unit, 'B', 'm');
-    DartType typeX = getClass(unit, 'X').element.type;
-    DartType typeY = getClass(unit, 'Y').element.type;
-    DartType typeZ = getClass(unit, 'Z').element.type;
+    CompilationUnit unit = outputs[RESOLVED_UNIT9];
+    VariableDeclaration field = AstFinder.getFieldInClass(unit, 'B', 'f');
+    MethodDeclaration method = AstFinder.getMethodInClass(unit, 'B', 'm');
+    DartType typeX = AstFinder.getClass(unit, 'X').element.type;
+    DartType typeY = AstFinder.getClass(unit, 'Y').element.type;
+    DartType typeZ = AstFinder.getClass(unit, 'Z').element.type;
 
     expect(field.element.type, typeX);
     expect(method.element.returnType, typeY);
@@ -2371,16 +2504,19 @@
 }
 ''');
     computeResult(
-        new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT8,
+        new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT9,
         matcher: isInferInstanceMembersInUnitTask);
-    CompilationUnit firstUnit = outputs[RESOLVED_UNIT8];
+    CompilationUnit firstUnit = outputs[RESOLVED_UNIT9];
     computeResult(
-        new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT8);
-    CompilationUnit secondUnit = outputs[RESOLVED_UNIT8];
+        new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT9);
+    CompilationUnit secondUnit = outputs[RESOLVED_UNIT9];
 
-    VariableDeclaration variableA = getTopLevelVariable(firstUnit, 'a');
-    VariableDeclaration variableB = getTopLevelVariable(secondUnit, 'b');
-    VariableDeclaration variableC = getFieldInClass(secondUnit, 'M', 'c');
+    VariableDeclaration variableA =
+        AstFinder.getTopLevelVariable(firstUnit, 'a');
+    VariableDeclaration variableB =
+        AstFinder.getTopLevelVariable(secondUnit, 'b');
+    VariableDeclaration variableC =
+        AstFinder.getFieldInClass(secondUnit, 'M', 'c');
     InterfaceType stringType = context.typeProvider.stringType;
 
     expect(variableA.element.type, stringType);
@@ -2400,10 +2536,12 @@
   String field = topLevel;
 }
 ''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
-    CompilationUnit unit = outputs[RESOLVED_UNIT8];
-    VariableDeclaration topLevelDecl = getTopLevelVariable(unit, 'topLevel');
-    VariableDeclaration fieldDecl = getFieldInClass(unit, 'C', 'field');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9);
+    CompilationUnit unit = outputs[RESOLVED_UNIT9];
+    VariableDeclaration topLevelDecl =
+        AstFinder.getTopLevelVariable(unit, 'topLevel');
+    VariableDeclaration fieldDecl =
+        AstFinder.getFieldInClass(unit, 'C', 'field');
     VariableElement topLevel = topLevelDecl.name.staticElement;
     VariableElement field = fieldDecl.name.staticElement;
 
@@ -2425,10 +2563,10 @@
   static const X = "";
 }
 ''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6,
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT7,
         matcher: isInferStaticVariableTypesInUnitTask);
-    CompilationUnit unit = outputs[RESOLVED_UNIT6];
-    VariableDeclaration declaration = getFieldInClass(unit, 'M', 'X');
+    CompilationUnit unit = outputs[RESOLVED_UNIT7];
+    VariableDeclaration declaration = AstFinder.getFieldInClass(unit, 'M', 'X');
     InterfaceType stringType = context.typeProvider.stringType;
     expect(declaration.element.type, stringType);
   }
@@ -2444,7 +2582,7 @@
   return xSquared;
 };
 ''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6,
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT7,
         matcher: isInferStaticVariableTypesInUnitTask);
   }
 
@@ -2467,17 +2605,20 @@
 class M {}
 ''');
     computeResult(
-        new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT6,
+        new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT7,
         matcher: isInferStaticVariableTypesInUnitTask);
-    CompilationUnit firstUnit = outputs[RESOLVED_UNIT6];
+    CompilationUnit firstUnit = outputs[RESOLVED_UNIT7];
     computeResult(
-        new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT6);
-    CompilationUnit secondUnit = outputs[RESOLVED_UNIT6];
+        new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT7);
+    CompilationUnit secondUnit = outputs[RESOLVED_UNIT7];
 
-    VariableDeclaration variableA = getTopLevelVariable(firstUnit, 'a');
-    VariableDeclaration variableB = getTopLevelVariable(secondUnit, 'b');
-    VariableDeclaration variableC = getTopLevelVariable(firstUnit, 'c');
-    ClassDeclaration classM = getClass(secondUnit, 'M');
+    VariableDeclaration variableA =
+        AstFinder.getTopLevelVariable(firstUnit, 'a');
+    VariableDeclaration variableB =
+        AstFinder.getTopLevelVariable(secondUnit, 'b');
+    VariableDeclaration variableC =
+        AstFinder.getTopLevelVariable(firstUnit, 'c');
+    ClassDeclaration classM = AstFinder.getClass(secondUnit, 'M');
     DartType typeM = classM.element.type;
 
     expect(variableA.element.type, typeM);
@@ -2498,9 +2639,9 @@
   return 1 + X;
 };
 ''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6,
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT7,
         matcher: isInferStaticVariableTypesInUnitTask);
-    CompilationUnit unit = outputs[RESOLVED_UNIT6];
+    CompilationUnit unit = outputs[RESOLVED_UNIT7];
     TopLevelVariableDeclaration declaration = unit.declarations[1];
     FunctionExpression function =
         declaration.variables.variables[0].initializer;
@@ -2524,7 +2665,8 @@
 ''');
     computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
     CompilationUnit unit = outputs[RESOLVED_UNIT5];
-    VariableDeclaration declaration = getFieldInClass(unit, 'C', 'field');
+    VariableDeclaration declaration =
+        AstFinder.getFieldInClass(unit, 'C', 'field');
     VariableElement variable = declaration.name.staticElement;
     InferStaticVariableTypeTask inferTask =
         new InferStaticVariableTypeTask(task.context, variable);
@@ -2539,7 +2681,8 @@
 ''');
     computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
     CompilationUnit unit = outputs[RESOLVED_UNIT5];
-    VariableDeclaration declaration = getTopLevelVariable(unit, 'topLevel');
+    VariableDeclaration declaration =
+        AstFinder.getTopLevelVariable(unit, 'topLevel');
     VariableElement variable = declaration.name.staticElement;
     InferStaticVariableTypeTask inferTask =
         new InferStaticVariableTypeTask(task.context, variable);
@@ -2558,8 +2701,10 @@
 ''');
     computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
     CompilationUnit unit = outputs[RESOLVED_UNIT5];
-    VariableDeclaration topLevelDecl = getTopLevelVariable(unit, 'topLevel3');
-    VariableDeclaration fieldDecl = getFieldInClass(unit, 'C', 'field3');
+    VariableDeclaration topLevelDecl =
+        AstFinder.getTopLevelVariable(unit, 'topLevel3');
+    VariableDeclaration fieldDecl =
+        AstFinder.getFieldInClass(unit, 'C', 'field3');
     VariableElement topLevel = topLevelDecl.name.staticElement;
     VariableElement field = fieldDecl.name.staticElement;
 
@@ -2584,9 +2729,9 @@
     computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
     CompilationUnit unit = outputs[RESOLVED_UNIT5];
     VariableElement topLevel =
-        getTopLevelVariable(unit, 'topLevel').name.staticElement;
+        AstFinder.getTopLevelVariable(unit, 'topLevel').name.staticElement;
     VariableElement field =
-        getFieldInClass(unit, 'C', 'field').name.staticElement;
+        AstFinder.getFieldInClass(unit, 'C', 'field').name.staticElement;
 
     computeResult(field, INFERRED_STATIC_VARIABLE,
         matcher: isInferStaticVariableTypeTask);
@@ -2607,9 +2752,11 @@
     computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
     CompilationUnit unit = outputs[RESOLVED_UNIT5];
     VariableElement piFirst =
-        getTopLevelVariable(unit, 'piFirst').name.staticElement;
-    VariableElement pi = getTopLevelVariable(unit, 'pi').name.staticElement;
-    VariableElement tau = getTopLevelVariable(unit, 'tau').name.staticElement;
+        AstFinder.getTopLevelVariable(unit, 'piFirst').name.staticElement;
+    VariableElement pi =
+        AstFinder.getTopLevelVariable(unit, 'pi').name.staticElement;
+    VariableElement tau =
+        AstFinder.getTopLevelVariable(unit, 'tau').name.staticElement;
 
     computeResult(piFirst, INFERRED_STATIC_VARIABLE,
         matcher: isInferStaticVariableTypeTask);
@@ -2627,7 +2774,8 @@
 ''');
     computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
     CompilationUnit unit = outputs[RESOLVED_UNIT5];
-    VariableElement a = getTopLevelVariable(unit, 'a').name.staticElement;
+    VariableElement a =
+        AstFinder.getTopLevelVariable(unit, 'a').name.staticElement;
 
     computeResult(a, INFERRED_STATIC_VARIABLE,
         matcher: isInferStaticVariableTypeTask);
@@ -2643,7 +2791,8 @@
 ''');
     computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
     CompilationUnit unit = outputs[RESOLVED_UNIT5];
-    VariableElement a = getTopLevelVariable(unit, 'a').name.staticElement;
+    VariableElement a =
+        AstFinder.getTopLevelVariable(unit, 'a').name.staticElement;
 
     computeResult(a, INFERRED_STATIC_VARIABLE,
         matcher: isInferStaticVariableTypeTask);
@@ -2764,6 +2913,13 @@
     expect(outputs[UNITS], hasLength(1));
   }
 
+  test_perform_flushTokenStream() {
+    _performParseTask(r'''
+class Test {}
+''');
+    expect(analysisCache.getState(source, TOKEN_STREAM), CacheState.FLUSHED);
+  }
+
   test_perform_invalidDirectives() {
     _performParseTask(r'''
 library lib;
@@ -2842,35 +2998,36 @@
 
 @reflectiveTest
 class PartiallyResolveUnitReferencesTaskTest extends _AbstractDartTaskTest {
-  test_perform() {
+  test_perform_propagable() {
     enableStrongMode();
     Source source = newSource(
         '/test.dart',
         '''
-int a = b;
-int b = c;
-var d = 0;
-class A {}
+const t1 = 1;
+final t2 = 2;
+var   t3 = 3;
+final t4;
 class C {
-  static final f = '';
-  var g = 0;
+  static const fs1 = 1;
+  static final fs2 = 2;
+  static var   fs3 = 3;
+  static final fs4;
+  const fi1 = 1;
+  final fi2 = 2;
+  var   fi3 = 3;
+  final fi4;
 }
 ''');
     LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
-    computeResult(target, RESOLVED_UNIT5,
+    computeResult(target, PROPAGABLE_VARIABLES_IN_UNIT,
         matcher: isPartiallyResolveUnitReferencesTask);
-    // Test the outputs
-    expect(outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT], hasLength(4));
-    CompilationUnit unit = outputs[RESOLVED_UNIT5];
-    expect(unit, same(outputs[RESOLVED_UNIT5]));
-    // Test the state of the AST
-    TopLevelVariableDeclaration a = unit.declarations[0];
-    VariableDeclaration variableA = a.variables.variables[0];
-    SimpleIdentifier initializer = variableA.initializer;
-    expect(initializer.staticElement, isNotNull);
+    // PROPAGABLE_VARIABLES_IN_UNIT
+    List<VariableElement> variables = outputs[PROPAGABLE_VARIABLES_IN_UNIT];
+    expect(variables.map((v) => v.displayName),
+        unorderedEquals(['t1', 't2', 'fs1', 'fs2', 'fi1', 'fi2']));
   }
 
-  test_perform_importExport() {
+  test_perform_strong_importExport() {
     newSource(
         '/a.dart',
         '''
@@ -2911,7 +3068,40 @@
     expect(methodElement, isNull);
   }
 
-  test_perform_notResolved() {
+  test_perform_strong_inferable() {
+    enableStrongMode();
+    Source source = newSource(
+        '/test.dart',
+        '''
+int a = b;
+int b = c;
+var d = 0;
+class A {}
+class C {
+  static final f = '';
+  var g = 0;
+}
+''');
+    LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+    computeResult(target, RESOLVED_UNIT5,
+        matcher: isPartiallyResolveUnitReferencesTask);
+    CompilationUnit unit = outputs[RESOLVED_UNIT5];
+    // INFERABLE_STATIC_VARIABLES_IN_UNIT
+    {
+      List<VariableElement> variables =
+          outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT];
+      expect(variables, hasLength(4));
+      expect(variables.map((v) => v.displayName),
+          unorderedEquals(['a', 'b', 'd', 'f']));
+    }
+    // Test the state of the AST
+    TopLevelVariableDeclaration a = unit.declarations[0];
+    VariableDeclaration variableA = a.variables.variables[0];
+    SimpleIdentifier initializer = variableA.initializer;
+    expect(initializer.staticElement, isNotNull);
+  }
+
+  test_perform_strong_notResolved() {
     enableStrongMode();
     Source source = newSource(
         '/test.dart',
@@ -2978,6 +3168,125 @@
 }
 
 @reflectiveTest
+class PropagateVariableTypesInUnitTaskTest extends _AbstractDartTaskTest {
+  void test_perform_cycle() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+final piFirst = true;
+final pi = piFirst ? 3.14 : tau / 2;
+final tau = piFirst ? pi * 2 : 6.28;
+''');
+    // compute
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6,
+        matcher: isPropagateVariableTypesInUnitTask);
+    CompilationUnit unit = outputs[RESOLVED_UNIT6];
+    // verify
+    TopLevelVariableElement piFirst =
+        AstFinder.getTopLevelVariableElement(unit, 'piFirst');
+    TopLevelVariableElement pi =
+        AstFinder.getTopLevelVariableElement(unit, 'pi');
+    TopLevelVariableElement tau =
+        AstFinder.getTopLevelVariableElement(unit, 'tau');
+    expect(piFirst.propagatedType, context.typeProvider.boolType);
+    expect(pi.propagatedType, isNull);
+    expect(tau.propagatedType, isNull);
+  }
+
+  void test_perform_topLevel() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+//final a = b + c.length;
+final a = b;
+final b = 1;
+final c = '2';
+''');
+    // compute
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6,
+        matcher: isPropagateVariableTypesInUnitTask);
+    CompilationUnit unit = outputs[RESOLVED_UNIT6];
+    // verify
+    InterfaceType intType = context.typeProvider.intType;
+    InterfaceType stringType = context.typeProvider.stringType;
+    expect(AstFinder.getTopLevelVariableElement(unit, 'a').propagatedType,
+        intType);
+    expect(AstFinder.getTopLevelVariableElement(unit, 'b').propagatedType,
+        intType);
+    expect(AstFinder.getTopLevelVariableElement(unit, 'c').propagatedType,
+        stringType);
+  }
+}
+
+@reflectiveTest
+class PropagateVariableTypeTaskTest extends _AbstractDartTaskTest {
+  void test_perform_cycle() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+final piFirst = true;
+final pi = piFirst ? 3.14 : tau / 2;
+final tau = piFirst ? pi * 2 : 6.28;
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
+    CompilationUnit unit = outputs[RESOLVED_UNIT5];
+    TopLevelVariableElement piFirst =
+        AstFinder.getTopLevelVariableElement(unit, 'piFirst');
+    TopLevelVariableElement pi =
+        AstFinder.getTopLevelVariableElement(unit, 'pi');
+    TopLevelVariableElement tau =
+        AstFinder.getTopLevelVariableElement(unit, 'tau');
+    // compute
+    computeResult(piFirst, PROPAGATED_VARIABLE,
+        matcher: isPropagateVariableTypeTask);
+    expect(piFirst.propagatedType, context.typeProvider.boolType);
+    expect(pi.propagatedType, isNull);
+    expect(tau.propagatedType, isNull);
+  }
+
+  void test_perform_null() {
+    enableStrongMode();
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+var a = null;
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
+    CompilationUnit unit = outputs[RESOLVED_UNIT5];
+    TopLevelVariableElement a = AstFinder.getTopLevelVariableElement(unit, 'a');
+    // compute
+    computeResult(a, PROPAGATED_VARIABLE, matcher: isPropagateVariableTypeTask);
+    expect(a.propagatedType, isNull);
+  }
+
+  void test_perform_topLevel() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+final a = b + c.length;
+final b = 1;
+final c = '2';
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
+    CompilationUnit unit = outputs[RESOLVED_UNIT5];
+    TopLevelVariableElement elementA =
+        AstFinder.getTopLevelVariableElement(unit, 'a');
+    TopLevelVariableElement elementB =
+        AstFinder.getTopLevelVariableElement(unit, 'b');
+    TopLevelVariableElement elementC =
+        AstFinder.getTopLevelVariableElement(unit, 'c');
+    // compute
+    computeResult(elementA, PROPAGATED_VARIABLE,
+        matcher: isPropagateVariableTypeTask);
+    InterfaceType intType = context.typeProvider.intType;
+    InterfaceType stringType = context.typeProvider.stringType;
+    expect(elementA.propagatedType, intType);
+    expect(elementB.propagatedType, intType);
+    expect(elementC.propagatedType, stringType);
+  }
+}
+
+@reflectiveTest
 class ResolveInstanceFieldsInUnitTaskTest extends _AbstractDartTaskTest {
   @override
   void setUp() {
@@ -3012,34 +3321,34 @@
     DartType dynamicType = context.typeProvider.dynamicType;
 
     computeResult(
-        new LibrarySpecificUnit(sources[1], sources[1]), RESOLVED_UNIT7);
-    CompilationUnit unit1 = outputs[RESOLVED_UNIT7];
+        new LibrarySpecificUnit(sources[1], sources[1]), RESOLVED_UNIT8);
+    CompilationUnit unit1 = outputs[RESOLVED_UNIT8];
 
     // B.b2 shoud be resolved on the rhs, but not yet inferred.
     assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "B", "b2"), dynamicType, intType);
+        AstFinder.getFieldInClass(unit1, "B", "b2"), dynamicType, intType);
 
     computeResult(
-        new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT7);
-    CompilationUnit unit0 = outputs[RESOLVED_UNIT7];
+        new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT8);
+    CompilationUnit unit0 = outputs[RESOLVED_UNIT8];
 
     // B.b2 should now be fully resolved and inferred.
     assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "B", "b2"), intType, intType);
+        AstFinder.getFieldInClass(unit1, "B", "b2"), intType, intType);
 
     // A.a2 should now be resolved on the rhs, but not yet inferred.
     assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a2"), dynamicType, intType);
+        AstFinder.getFieldInClass(unit0, "A", "a2"), dynamicType, intType);
 
     computeResult(
-        new LibrarySpecificUnit(sources[2], sources[2]), RESOLVED_UNIT7);
+        new LibrarySpecificUnit(sources[2], sources[2]), RESOLVED_UNIT8);
 
     // A.a2 should now be fully resolved and inferred.
     assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a2"), intType, intType);
+        AstFinder.getFieldInClass(unit0, "A", "a2"), intType, intType);
 
     assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "B", "b2"), intType, intType);
+        AstFinder.getFieldInClass(unit1, "B", "b2"), intType, intType);
   }
 
   // Test inference of instance fields across units
@@ -3069,19 +3378,19 @@
     DartType dynamicType = context.typeProvider.dynamicType;
 
     computeResult(
-        new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT7);
-    CompilationUnit unit0 = outputs[RESOLVED_UNIT7];
+        new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT8);
+    CompilationUnit unit0 = outputs[RESOLVED_UNIT8];
 
     // A.a2 should now be resolved on the rhs, but not yet inferred.
     assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType);
+        AstFinder.getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType);
 
     computeResult(
-        new LibrarySpecificUnit(sources[2], sources[2]), RESOLVED_UNIT7);
+        new LibrarySpecificUnit(sources[2], sources[2]), RESOLVED_UNIT8);
 
     // A.a2 should now be fully resolved and inferred.
     assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType);
+        AstFinder.getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType);
   }
 
   // Test inference of instance fields across units with cycles
@@ -3115,40 +3424,40 @@
     DartType dynamicType = context.typeProvider.dynamicType;
 
     computeResult(
-        new LibrarySpecificUnit(sources[1], sources[1]), RESOLVED_UNIT7);
-    CompilationUnit unit1 = outputs[RESOLVED_UNIT7];
+        new LibrarySpecificUnit(sources[1], sources[1]), RESOLVED_UNIT8);
+    CompilationUnit unit1 = outputs[RESOLVED_UNIT8];
 
     assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "B", "b1"), intType, intType);
+        AstFinder.getFieldInClass(unit1, "B", "b1"), intType, intType);
     assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "B", "b2"), dynamicType, intType);
+        AstFinder.getFieldInClass(unit1, "B", "b2"), dynamicType, intType);
 
     computeResult(
-        new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT7);
-    CompilationUnit unit0 = outputs[RESOLVED_UNIT7];
+        new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT8);
+    CompilationUnit unit0 = outputs[RESOLVED_UNIT8];
 
     assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a1"), intType, intType);
+        AstFinder.getFieldInClass(unit0, "A", "a1"), intType, intType);
     assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a2"), dynamicType, intType);
+        AstFinder.getFieldInClass(unit0, "A", "a2"), dynamicType, intType);
 
     assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "B", "b1"), intType, intType);
+        AstFinder.getFieldInClass(unit1, "B", "b1"), intType, intType);
     assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "B", "b2"), intType, intType);
+        AstFinder.getFieldInClass(unit1, "B", "b2"), intType, intType);
 
     computeResult(
-        new LibrarySpecificUnit(sources[2], sources[2]), RESOLVED_UNIT7);
+        new LibrarySpecificUnit(sources[2], sources[2]), RESOLVED_UNIT8);
 
     assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a1"), intType, intType);
+        AstFinder.getFieldInClass(unit0, "A", "a1"), intType, intType);
     assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a2"), intType, intType);
+        AstFinder.getFieldInClass(unit0, "A", "a2"), intType, intType);
 
     assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "B", "b1"), intType, intType);
+        AstFinder.getFieldInClass(unit1, "B", "b1"), intType, intType);
     assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "B", "b2"), intType, intType);
+        AstFinder.getFieldInClass(unit1, "B", "b2"), intType, intType);
   }
 
   // Test inference between static and instance fields
@@ -3177,27 +3486,27 @@
     DartType dynamicType = context.typeProvider.dynamicType;
 
     computeResult(
-        new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT7);
-    CompilationUnit unit0 = outputs[RESOLVED_UNIT7];
+        new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT8);
+    CompilationUnit unit0 = outputs[RESOLVED_UNIT8];
 
     // A.a2 should now be resolved on the rhs, but not yet inferred.
     assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType);
+        AstFinder.getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType);
 
     // B.b2 shoud be resolved on the rhs, but not yet inferred.
     assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "B", "b2"), dynamicType, intType);
+        AstFinder.getFieldInClass(unit0, "B", "b2"), dynamicType, intType);
 
     computeResult(
-        new LibrarySpecificUnit(sources[1], sources[1]), RESOLVED_UNIT7);
+        new LibrarySpecificUnit(sources[1], sources[1]), RESOLVED_UNIT8);
 
     // A.a2 should now be fully resolved and inferred.
     assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType);
+        AstFinder.getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType);
 
     // B.b2 should now be fully resolved and inferred.
     assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "B", "b2"), intType, intType);
+        AstFinder.getFieldInClass(unit0, "B", "b2"), intType, intType);
   }
 }
 
@@ -3278,9 +3587,9 @@
   }
 }
 ''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9,
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT10,
         matcher: isResolveUnitTask);
-    CompilationUnit unit = outputs[RESOLVED_UNIT9];
+    CompilationUnit unit = outputs[RESOLVED_UNIT10];
 
     FunctionDeclaration f = unit.declarations[0];
     _assertResolved(f.functionExpression.body);
@@ -3291,6 +3600,33 @@
     expect(outputs[RESOLVE_UNIT_ERRORS], hasLength(0));
   }
 
+  void test_perform_ensurePropagatedVariableTypes() {
+    newSource(
+        '/lib.dart',
+        '''
+class A {
+  final v = 1;
+}
+''');
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+import 'lib.dart';
+main(A a) {
+  a.v.isEven;
+}
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT10,
+        matcher: isResolveUnitTask);
+    expect(outputs[RESOLVE_UNIT_ERRORS], hasLength(0));
+    CompilationUnit unit = outputs[RESOLVED_UNIT10];
+    FunctionDeclaration main = unit.declarations[0];
+    BlockFunctionBody body = main.functionExpression.body;
+    ExpressionStatement statement = body.block.statements.single;
+    Expression expression = statement.expression;
+    expect(expression.bestType, context.typeProvider.boolType);
+  }
+
   void _assertResolved(FunctionBody body) {
     ResolutionVerifier verifier = new ResolutionVerifier();
     body.accept(verifier);
@@ -3534,14 +3870,17 @@
 var pi = piFirst ? 3.14 : tau / 2;
 var tau = piFirst ? pi * 2 : 6.28;
 ''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9);
-    CompilationUnit unit = outputs[RESOLVED_UNIT9];
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT10);
+    CompilationUnit unit = outputs[RESOLVED_UNIT10];
     VariableElement piFirst =
-        getTopLevelVariable(unit, 'piFirst').name.staticElement;
-    VariableElement pi = getTopLevelVariable(unit, 'pi').name.staticElement;
-    VariableElement tau = getTopLevelVariable(unit, 'tau').name.staticElement;
-    Expression piFirstUse = (getTopLevelVariable(unit, 'tau').initializer
-        as ConditionalExpression).condition;
+        AstFinder.getTopLevelVariable(unit, 'piFirst').name.staticElement;
+    VariableElement pi =
+        AstFinder.getTopLevelVariable(unit, 'pi').name.staticElement;
+    VariableElement tau =
+        AstFinder.getTopLevelVariable(unit, 'tau').name.staticElement;
+    Expression piFirstUse = (AstFinder
+        .getTopLevelVariable(unit, 'tau')
+        .initializer as ConditionalExpression).condition;
 
     expect(piFirstUse.staticType, context.typeProvider.boolType);
     expect(piFirst.type, context.typeProvider.boolType);
@@ -3573,26 +3912,26 @@
           }
 ''');
     computeResult(
-        new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT9);
-    CompilationUnit unit1 = outputs[RESOLVED_UNIT9];
+        new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT10);
+    CompilationUnit unit1 = outputs[RESOLVED_UNIT10];
     computeResult(
-        new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT9);
-    CompilationUnit unit2 = outputs[RESOLVED_UNIT9];
+        new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT10);
+    CompilationUnit unit2 = outputs[RESOLVED_UNIT10];
 
     InterfaceType intType = context.typeProvider.intType;
 
     assertVariableDeclarationTypes(
-        getTopLevelVariable(unit1, "x"), intType, intType);
+        AstFinder.getTopLevelVariable(unit1, "x"), intType, intType);
     assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "A", "x"), intType, intType);
+        AstFinder.getFieldInClass(unit1, "A", "x"), intType, intType);
 
     assertVariableDeclarationTypes(
-        getTopLevelVariable(unit2, "y"), intType, intType);
+        AstFinder.getTopLevelVariable(unit2, "y"), intType, intType);
     assertVariableDeclarationTypes(
-        getFieldInClass(unit2, "B", "y"), intType, intType);
+        AstFinder.getFieldInClass(unit2, "B", "y"), intType, intType);
 
     List<Statement> statements =
-        getStatementsInTopLevelFunction(unit2, "test1");
+        AstFinder.getStatementsInTopLevelFunction(unit2, "test1");
 
     assertAssignmentStatementTypes(statements[1], intType, intType);
     assertAssignmentStatementTypes(statements[2], intType, intType);
@@ -3624,7 +3963,7 @@
     '''
     });
     List<dynamic> units =
-        computeLibraryResults(sources, RESOLVED_UNIT9).toList();
+        computeLibraryResults(sources, RESOLVED_UNIT10).toList();
     CompilationUnit unit0 = units[0];
     CompilationUnit unit1 = units[1];
     CompilationUnit unit2 = units[2];
@@ -3632,13 +3971,13 @@
     InterfaceType intType = context.typeProvider.intType;
 
     assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a2"), intType, intType);
+        AstFinder.getFieldInClass(unit0, "A", "a2"), intType, intType);
 
     assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "B", "b2"), intType, intType);
+        AstFinder.getFieldInClass(unit1, "B", "b2"), intType, intType);
 
     List<Statement> statements =
-        getStatementsInTopLevelFunction(unit2, "test1");
+        AstFinder.getStatementsInTopLevelFunction(unit2, "test1");
 
     assertAssignmentStatementTypes(statements[1], intType, intType);
   }
@@ -3671,7 +4010,7 @@
     '''
     });
     List<dynamic> units =
-        computeLibraryResults(sources, RESOLVED_UNIT9).toList();
+        computeLibraryResults(sources, RESOLVED_UNIT10).toList();
     CompilationUnit unit0 = units[0];
     CompilationUnit unit2 = units[2];
 
@@ -3679,9 +4018,13 @@
     InterfaceType stringType = context.typeProvider.stringType;
 
     assertVariableDeclarationStatementTypes(
-        getStatementsInTopLevelFunction(unit0, "foo")[0], stringType, intType);
+        AstFinder.getStatementsInTopLevelFunction(unit0, "foo")[0],
+        stringType,
+        intType);
     assertVariableDeclarationStatementTypes(
-        getStatementsInTopLevelFunction(unit2, "foo")[0], stringType, intType);
+        AstFinder.getStatementsInTopLevelFunction(unit2, "foo")[0],
+        stringType,
+        intType);
   }
 
   // Test inference interactions between local variables and top level
@@ -3708,27 +4051,27 @@
           }
 ''');
     computeResult(
-        new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT9);
-    CompilationUnit unit1 = outputs[RESOLVED_UNIT9];
+        new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT10);
+    CompilationUnit unit1 = outputs[RESOLVED_UNIT10];
     computeResult(
-        new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT9);
-    CompilationUnit unit2 = outputs[RESOLVED_UNIT9];
+        new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT10);
+    CompilationUnit unit2 = outputs[RESOLVED_UNIT10];
 
     InterfaceType intType = context.typeProvider.intType;
     InterfaceType stringType = context.typeProvider.stringType;
 
     assertVariableDeclarationTypes(
-        getTopLevelVariable(unit1, "x"), intType, intType);
+        AstFinder.getTopLevelVariable(unit1, "x"), intType, intType);
     assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "A", "x"), intType, intType);
+        AstFinder.getFieldInClass(unit1, "A", "x"), intType, intType);
 
     assertVariableDeclarationTypes(
-        getTopLevelVariable(unit2, "y"), intType, intType);
+        AstFinder.getTopLevelVariable(unit2, "y"), intType, intType);
     assertVariableDeclarationTypes(
-        getFieldInClass(unit2, "B", "y"), intType, intType);
+        AstFinder.getFieldInClass(unit2, "B", "y"), intType, intType);
 
     List<Statement> statements =
-        getStatementsInTopLevelFunction(unit2, "test1");
+        AstFinder.getStatementsInTopLevelFunction(unit2, "test1");
 
     assertAssignmentStatementTypes(statements[0], intType, stringType);
     assertAssignmentStatementTypes(statements[1], intType, stringType);
@@ -3762,7 +4105,7 @@
     '''
     });
     List<dynamic> units =
-        computeLibraryResults(sources, RESOLVED_UNIT9).toList();
+        computeLibraryResults(sources, RESOLVED_UNIT10).toList();
     CompilationUnit unit0 = units[0];
     CompilationUnit unit1 = units[1];
     CompilationUnit unit2 = units[2];
@@ -3770,17 +4113,17 @@
     InterfaceType intType = context.typeProvider.intType;
 
     assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a1"), intType, intType);
+        AstFinder.getFieldInClass(unit0, "A", "a1"), intType, intType);
     assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a2"), intType, intType);
+        AstFinder.getFieldInClass(unit0, "A", "a2"), intType, intType);
 
     assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "B", "b1"), intType, intType);
+        AstFinder.getFieldInClass(unit1, "B", "b1"), intType, intType);
     assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "B", "b2"), intType, intType);
+        AstFinder.getFieldInClass(unit1, "B", "b2"), intType, intType);
 
     List<Statement> statements =
-        getStatementsInTopLevelFunction(unit2, "test1");
+        AstFinder.getStatementsInTopLevelFunction(unit2, "test1");
 
     assertAssignmentStatementTypes(statements[1], intType, intType);
     assertAssignmentStatementTypes(statements[2], intType, intType);
@@ -3798,13 +4141,14 @@
         y = "hi";
       }
 ''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9);
-    CompilationUnit unit = outputs[RESOLVED_UNIT9];
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT10);
+    CompilationUnit unit = outputs[RESOLVED_UNIT10];
 
     InterfaceType intType = context.typeProvider.intType;
     InterfaceType stringType = context.typeProvider.stringType;
 
-    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "test");
 
     assertVariableDeclarationStatementTypes(statements[0], intType, intType);
     assertAssignmentStatementTypes(statements[1], intType, stringType);
@@ -3836,13 +4180,14 @@
         final z = 42; // should infer `int`
       }
 ''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9);
-    CompilationUnit unit = outputs[RESOLVED_UNIT9];
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT10);
+    CompilationUnit unit = outputs[RESOLVED_UNIT10];
 
     InterfaceType intType = context.typeProvider.intType;
     InterfaceType stringType = context.typeProvider.stringType;
 
-    List<Statement> statements = getStatementsInMethod(unit, "A", "test1");
+    List<Statement> statements =
+        AstFinder.getStatementsInMethod(unit, "A", "test1");
 
     assertVariableDeclarationStatementTypes(statements[0], intType, intType);
     assertAssignmentStatementTypes(statements[1], intType, stringType);
@@ -3857,9 +4202,9 @@
     assertAssignmentStatementTypes(statements[8], intType, intType);
 
     assertVariableDeclarationTypes(
-        getFieldInClass(unit, "A", "x"), intType, intType);
+        AstFinder.getFieldInClass(unit, "A", "x"), intType, intType);
     assertVariableDeclarationTypes(
-        getFieldInClass(unit, "A", "z"), intType, intType);
+        AstFinder.getFieldInClass(unit, "A", "z"), intType, intType);
   }
 
   // Test inference of instance fields across units
@@ -3884,13 +4229,14 @@
       int y = 0; // field def after use
       final z = 42; // should infer `int`
 ''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9);
-    CompilationUnit unit = outputs[RESOLVED_UNIT9];
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT10);
+    CompilationUnit unit = outputs[RESOLVED_UNIT10];
 
     InterfaceType intType = context.typeProvider.intType;
     InterfaceType stringType = context.typeProvider.stringType;
 
-    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test1");
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "test1");
 
     assertVariableDeclarationStatementTypes(statements[0], intType, intType);
     assertAssignmentStatementTypes(statements[1], intType, stringType);
@@ -3905,11 +4251,11 @@
     assertAssignmentStatementTypes(statements[8], intType, intType);
 
     assertVariableDeclarationTypes(
-        getTopLevelVariable(unit, "x"), intType, intType);
+        AstFinder.getTopLevelVariable(unit, "x"), intType, intType);
     assertVariableDeclarationTypes(
-        getTopLevelVariable(unit, "y"), intType, intType);
+        AstFinder.getTopLevelVariable(unit, "y"), intType, intType);
     assertVariableDeclarationTypes(
-        getTopLevelVariable(unit, "z"), intType, intType);
+        AstFinder.getTopLevelVariable(unit, "z"), intType, intType);
   }
 
   // Test inference between static and instance fields
@@ -3936,8 +4282,8 @@
         new A().y2 = /*severe:StaticTypeError*/"hi";
       }
 ''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9);
-    CompilationUnit unit = outputs[RESOLVED_UNIT9];
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT10);
+    CompilationUnit unit = outputs[RESOLVED_UNIT10];
 
     InterfaceType intType = context.typeProvider.intType;
     InterfaceType stringType = context.typeProvider.stringType;
@@ -3945,19 +4291,20 @@
     DartType dynamicType = context.typeProvider.dynamicType;
 
     assertVariableDeclarationTypes(
-        getTopLevelVariable(unit, "x"), dynamicType, bottomType);
+        AstFinder.getTopLevelVariable(unit, "x"), dynamicType, bottomType);
     assertVariableDeclarationTypes(
-        getTopLevelVariable(unit, "y"), intType, intType);
+        AstFinder.getTopLevelVariable(unit, "y"), intType, intType);
     assertVariableDeclarationTypes(
-        getFieldInClass(unit, "A", "x"), dynamicType, bottomType);
+        AstFinder.getFieldInClass(unit, "A", "x"), dynamicType, bottomType);
     assertVariableDeclarationTypes(
-        getFieldInClass(unit, "A", "y"), intType, intType);
+        AstFinder.getFieldInClass(unit, "A", "y"), intType, intType);
     assertVariableDeclarationTypes(
-        getFieldInClass(unit, "A", "x2"), dynamicType, bottomType);
+        AstFinder.getFieldInClass(unit, "A", "x2"), dynamicType, bottomType);
     assertVariableDeclarationTypes(
-        getFieldInClass(unit, "A", "y2"), intType, intType);
+        AstFinder.getFieldInClass(unit, "A", "y2"), intType, intType);
 
-    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "test");
 
     assertAssignmentStatementTypes(statements[0], dynamicType, stringType);
     assertAssignmentStatementTypes(statements[1], intType, stringType);
@@ -3977,13 +4324,14 @@
         x = "hi";
       }
 ''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9);
-    CompilationUnit unit = outputs[RESOLVED_UNIT9];
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT10);
+    CompilationUnit unit = outputs[RESOLVED_UNIT10];
 
     InterfaceType intType = context.typeProvider.intType;
     InterfaceType stringType = context.typeProvider.stringType;
 
-    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "test");
     VariableDeclaration decl =
         (statements[0] as VariableDeclarationStatement).variables.variables[0];
     expect(decl.element.type, intType);
@@ -4021,7 +4369,8 @@
     _fillErrorListener(STRONG_MODE_ERRORS);
     expect(errorListener.errors, isEmpty);
 
-    List<Statement> statements = getStatementsInTopLevelFunction(unit, "main");
+    List<Statement> statements =
+        AstFinder.getStatementsInTopLevelFunction(unit, "main");
     ExpressionStatement statement = statements[1];
     IndexExpression idx = statement.expression;
     expect(DynamicInvoke.get(idx.target), isNotNull);
@@ -4045,7 +4394,7 @@
 
     var errors = errorListener.errors;
     expect(errors.length, 1);
-    expect(errors[0].errorCode.name, "dev_compiler.StaticTypeError");
+    expect(errors[0].errorCode.name, "STRONG_MODE_STATIC_TYPE_ERROR");
   }
 }
 
@@ -4068,6 +4417,27 @@
     ]);
   }
 
+  test_perform_ConstantValidator_duplicateFields() {
+    Source source = newSource(
+        '/test.dart',
+        '''
+class Test {
+  final int x = 1;
+  final int x = 2;
+  const Test();
+}
+
+main() {
+  const Test();
+}
+''');
+    LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+    computeResult(target, VERIFY_ERRORS, matcher: isVerifyUnitTask);
+    // validate
+    _fillErrorListener(VERIFY_ERRORS);
+    errorListener.assertNoErrors();
+  }
+
   test_perform_directiveError() {
     Source source = newSource(
         '/test.dart',
@@ -4214,114 +4584,6 @@
     context.analysisOptions = options;
   }
 
-  /**
-   * Return the declaration of the class with the given [className] in the given
-   * compilation [unit].
-   */
-  ClassDeclaration getClass(CompilationUnit unit, String className) {
-    NodeList<CompilationUnitMember> unitMembers = unit.declarations;
-    for (CompilationUnitMember unitMember in unitMembers) {
-      if (unitMember is ClassDeclaration && unitMember.name.name == className) {
-        return unitMember;
-      }
-    }
-    fail('No class named $className in ${unit.element.source}');
-    return null;
-  }
-
-  /**
-   * Return the declaration of the field with the given [fieldName] in the class
-   * with the given [className] in the given compilation [unit].
-   */
-  VariableDeclaration getFieldInClass(
-      CompilationUnit unit, String className, String fieldName) {
-    ClassDeclaration unitMember = getClass(unit, className);
-    NodeList<ClassMember> classMembers = unitMember.members;
-    for (ClassMember classMember in classMembers) {
-      if (classMember is FieldDeclaration) {
-        NodeList<VariableDeclaration> fields = classMember.fields.variables;
-        for (VariableDeclaration field in fields) {
-          if (field.name.name == fieldName) {
-            return field;
-          }
-        }
-      }
-    }
-    fail('No field named $fieldName in $className');
-    return null;
-  }
-
-  /**
-   * Return the declaration of the method with the given [methodName] in the
-   * class with the given [className] in the given compilation [unit].
-   */
-  MethodDeclaration getMethodInClass(
-      CompilationUnit unit, String className, String methodName) {
-    ClassDeclaration unitMember = getClass(unit, className);
-    NodeList<ClassMember> classMembers = unitMember.members;
-    for (ClassMember classMember in classMembers) {
-      if (classMember is MethodDeclaration) {
-        if (classMember.name.name == methodName) {
-          return classMember;
-        }
-      }
-    }
-    fail('No method named $methodName in $className');
-    return null;
-  }
-
-  List<Statement> getStatementsInMethod(
-      CompilationUnit unit, String className, String methodName) {
-    MethodDeclaration method = getMethodInClass(unit, className, methodName);
-    BlockFunctionBody body = method.body;
-    return body.block.statements;
-  }
-
-  List<Statement> getStatementsInTopLevelFunction(
-      CompilationUnit unit, String functionName) {
-    FunctionDeclaration function = getTopLevelFunction(unit, functionName);
-    BlockFunctionBody body = function.functionExpression.body;
-    return body.block.statements;
-  }
-
-  /**
-   * Return the declaration of the top-level function with the given
-   * [functionName] in the given compilation [unit].
-   */
-  FunctionDeclaration getTopLevelFunction(
-      CompilationUnit unit, String functionName) {
-    NodeList<CompilationUnitMember> unitMembers = unit.declarations;
-    for (CompilationUnitMember unitMember in unitMembers) {
-      if (unitMember is FunctionDeclaration) {
-        if (unitMember.name.name == functionName) {
-          return unitMember;
-        }
-      }
-    }
-    return null;
-  }
-
-  /**
-   * Return the declaration of the top-level variable with the given
-   * [variableName] in the given compilation [unit].
-   */
-  VariableDeclaration getTopLevelVariable(
-      CompilationUnit unit, String variableName) {
-    NodeList<CompilationUnitMember> unitMembers = unit.declarations;
-    for (CompilationUnitMember unitMember in unitMembers) {
-      if (unitMember is TopLevelVariableDeclaration) {
-        NodeList<VariableDeclaration> variables =
-            unitMember.variables.variables;
-        for (VariableDeclaration variable in variables) {
-          if (variable.name.name == variableName) {
-            return variable;
-          }
-        }
-      }
-    }
-    return null;
-  }
-
   void setUp() {
     super.setUp();
     emptySource = newSource('/test.dart');
diff --git a/pkg/analyzer/test/src/task/options_test.dart b/pkg/analyzer/test/src/task/options_test.dart
index 75c0a5a..eacff89 100644
--- a/pkg/analyzer/test/src/task/options_test.dart
+++ b/pkg/analyzer/test/src/task/options_test.dart
@@ -284,6 +284,16 @@
         [AnalysisOptionsWarningCode.UNSUPPORTED_VALUE]);
   }
 
+  test_analyzer_strong_mode_error_code_supported() {
+    validate(
+        '''
+analyzer:
+  errors:
+    strong_mode_assignment_cast: ignore
+''',
+        []);
+  }
+
   test_analyzer_supported_exclude() {
     validate(
         '''
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index 6e8ba4b..a1170ef 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -32,10 +32,15 @@
           // it requires inference to work because of dartbug.com/23381
           SplayTreeMap([int compare(K key1, K key2),
                         bool isValidKey(potentialKey)]) {
-            : _comparator = /*warning:DownCastComposite*/(compare == null) ? Comparable.compare : compare,
-              _validKey = /*info:InferredType should be pass*/(isValidKey != null) ? isValidKey : ((v) => true);
-              _Predicate<Object> _v = /*warning:DownCastComposite*/(isValidKey != null) ? isValidKey : ((v) => true);
-              _v = /*info:InferredType should be pass*/(isValidKey != null) ? _v : ((v) => true);
+            : _comparator = /*warning:DOWN_CAST_COMPOSITE*/(compare == null)
+                           ? Comparable.compare : compare,
+              _validKey = /*warning:DOWN_CAST_COMPOSITE*/(isValidKey != null)
+                         ? isValidKey : ((v) => true);
+             _Predicate<Object> _v = /*warning:DOWN_CAST_COMPOSITE*/(isValidKey != null)
+                                    ? isValidKey : (/*info:INFERRED_TYPE_CLOSURE*/(v) => true);
+        // TODO(leafp): Fix unimplemented LUB in analyzer
+        _v = /*warning:DOWN_CAST_COMPOSITE*/(isValidKey != null)
+             ? _v : (/*info:INFERRED_TYPE_CLOSURE*/(v) => true);
           }
         }
         void main() {
@@ -44,9 +49,9 @@
           int i = 42;
 
           // Check the boolean conversion of the condition.
-          print((/*severe:StaticTypeError*/i) ? false : true);
-          print((/*info:DownCastImplicit*/obj) ? false : true);
-          print((/*info:DynamicCast*/dyn) ? false : true);
+          print((/*severe:STATIC_TYPE_ERROR*/i) ? false : true);
+          print((/*info:DOWN_CAST_IMPLICIT*/obj) ? false : true);
+          print((/*info:DYNAMIC_CAST*/dyn) ? false : true);
         }
       '''
   });
@@ -60,24 +65,24 @@
         bool b = false;
 
         if (b) {}
-        if (/*info:DynamicCast*/dyn) {}
-        if (/*info:DownCastImplicit*/obj) {}
-        if (/*severe:StaticTypeError*/i) {}
+        if (/*info:DYNAMIC_CAST*/dyn) {}
+        if (/*info:DOWN_CAST_IMPLICIT*/obj) {}
+        if (/*severe:STATIC_TYPE_ERROR*/i) {}
 
         while (b) {}
-        while (/*info:DynamicCast*/dyn) {}
-        while (/*info:DownCastImplicit*/obj) {}
-        while (/*severe:StaticTypeError*/i) {}
+        while (/*info:DYNAMIC_CAST*/dyn) {}
+        while (/*info:DOWN_CAST_IMPLICIT*/obj) {}
+        while (/*severe:STATIC_TYPE_ERROR*/i) {}
 
         do {} while (b);
-        do {} while (/*info:DynamicCast*/dyn);
-        do {} while (/*info:DownCastImplicit*/obj);
-        do {} while (/*severe:StaticTypeError*/i);
+        do {} while (/*info:DYNAMIC_CAST*/dyn);
+        do {} while (/*info:DOWN_CAST_IMPLICIT*/obj);
+        do {} while (/*severe:STATIC_TYPE_ERROR*/i);
 
         for (;b;) {}
-        for (;/*info:DynamicCast*/dyn;) {}
-        for (;/*info:DownCastImplicit*/obj;) {}
-        for (;/*severe:StaticTypeError*/i;) {}
+        for (;/*info:DYNAMIC_CAST*/dyn;) {}
+        for (;/*info:DOWN_CAST_IMPLICIT*/obj;) {}
+        for (;/*severe:STATIC_TYPE_ERROR*/i;) {}
       }
     '''
   });
@@ -99,43 +104,43 @@
           double y;
           // The analyzer has what I believe is a bug (dartbug.com/23252) which
           // causes the return type of calls to f to be treated as dynamic.
-          x = /*info:DynamicCast should be pass*/f(3);
-          x = /*severe:StaticTypeError*/f.col(3.0);
-          y = /*info:DynamicCast should be severe:StaticTypeError*/f(3);
+          x = /*info:DYNAMIC_CAST should be pass*/f(3);
+          x = /*severe:STATIC_TYPE_ERROR*/f.col(3.0);
+          y = /*info:DYNAMIC_CAST should be severe:STATIC_TYPE_ERROR*/f(3);
           y = f.col(3.0);
-          f(/*severe:StaticTypeError*/3.0);
-          f.col(/*severe:StaticTypeError*/3);
+          f(/*severe:STATIC_TYPE_ERROR*/3.0);
+          f.col(/*severe:STATIC_TYPE_ERROR*/3);
         }
         {
           Function f = new B();
           int x;
           double y;
-          x = /*info:DynamicCast, info:DynamicInvoke*/f(3);
-          x = /*info:DynamicCast, info:DynamicInvoke*/f.col(3.0);
-          y = /*info:DynamicCast, info:DynamicInvoke*/f(3);
-          y = /*info:DynamicCast, info:DynamicInvoke*/f.col(3.0);
-          (/*info:DynamicInvoke*/f(3.0));
-          (/*info:DynamicInvoke*/f.col(3));
+          x = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f(3);
+          x = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f.col(3.0);
+          y = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f(3);
+          y = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f.col(3.0);
+          (/*info:DYNAMIC_INVOKE*/f(3.0));
+          (/*info:DYNAMIC_INVOKE*/f.col(3));
         }
         {
           A f = new B();
           int x;
           double y;
-          x = /*info:DynamicCast, info:DynamicInvoke*/f(3);
-          y = /*info:DynamicCast, info:DynamicInvoke*/f(3);
-          (/*info:DynamicInvoke*/f(3.0));
+          x = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f(3);
+          y = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f(3);
+          (/*info:DYNAMIC_INVOKE*/f(3.0));
         }
         {
           dynamic g = new B();
-          (/*info:DynamicInvoke*/g.call(32.0));
-          (/*info:DynamicInvoke*/g.col(42.0));
-          (/*info:DynamicInvoke*/g.foo(42.0));
-          (/*info:DynamicInvoke*/g.x);
+          (/*info:DYNAMIC_INVOKE*/g.call(32.0));
+          (/*info:DYNAMIC_INVOKE*/g.col(42.0));
+          (/*info:DYNAMIC_INVOKE*/g.foo(42.0));
+          (/*info:DYNAMIC_INVOKE*/g.x);
           A f = new B();
           f.call(32.0);
-          (/*info:DynamicInvoke*/f.col(42.0));
-          (/*info:DynamicInvoke*/f.foo(42.0));
-          (/*info:DynamicInvoke*/f.x);
+          (/*info:DYNAMIC_INVOKE*/f.col(42.0));
+          (/*info:DYNAMIC_INVOKE*/f.foo(42.0));
+          (/*info:DYNAMIC_INVOKE*/f.x);
         }
       }
     '''
@@ -152,8 +157,8 @@
       class A {
         String x = "hello world";
 
-        void baz1(y) => x + /*info:DynamicCast*/y;
-        static baz2(y) => /*info:DynamicInvoke*/y + y;
+        void baz1(y) => x + /*info:DYNAMIC_CAST*/y;
+        static baz2(y) => /*info:DYNAMIC_INVOKE*/y + y;
       }
 
       void foo(String str) {
@@ -165,7 +170,7 @@
       }
 
       void bar(a) {
-        foo(/*info:DynamicCast,info:DynamicInvoke*/a.x);
+        foo(/*info:DYNAMIC_CAST,info:DYNAMIC_INVOKE*/a.x);
       }
 
       baz() => new B();
@@ -178,42 +183,42 @@
       void main() {
         var a = new A();
         bar(a);
-        (/*info:DynamicInvoke*/bar1(a));
+        (/*info:DYNAMIC_INVOKE*/bar1(a));
         var b = bar;
-        (/*info:DynamicInvoke*/b(a));
+        (/*info:DYNAMIC_INVOKE*/b(a));
         var f1 = foo;
         f1("hello");
         dynamic f2 = foo;
-        (/*info:DynamicInvoke*/f2("hello"));
+        (/*info:DYNAMIC_INVOKE*/f2("hello"));
         DynFun f3 = foo;
-        (/*info:DynamicInvoke*/f3("hello"));
-        (/*info:DynamicInvoke*/f3(42));
+        (/*info:DYNAMIC_INVOKE*/f3("hello"));
+        (/*info:DYNAMIC_INVOKE*/f3(42));
         StrFun f4 = foo;
         f4("hello");
         a.baz1("hello");
         var b1 = a.baz1;
-        (/*info:DynamicInvoke*/b1("hello"));
+        (/*info:DYNAMIC_INVOKE*/b1("hello"));
         A.baz2("hello");
         var b2 = A.baz2;
-        (/*info:DynamicInvoke*/b2("hello"));
+        (/*info:DYNAMIC_INVOKE*/b2("hello"));
 
         dynamic a1 = new B();
-        (/*info:DynamicInvoke*/a1.x);
+        (/*info:DYNAMIC_INVOKE*/a1.x);
         a1.toString();
-        (/*info:DynamicInvoke*/a1.toString(42));
+        (/*info:DYNAMIC_INVOKE*/a1.toString(42));
         var toStringClosure = a1.toString;
-        (/*info:DynamicInvoke*/a1.toStringClosure());
-        (/*info:DynamicInvoke*/a1.toStringClosure(42));
-        (/*info:DynamicInvoke*/a1.toStringClosure("hello"));
+        (/*info:DYNAMIC_INVOKE*/a1.toStringClosure());
+        (/*info:DYNAMIC_INVOKE*/a1.toStringClosure(42));
+        (/*info:DYNAMIC_INVOKE*/a1.toStringClosure("hello"));
         a1.hashCode;
 
         dynamic toString = () => null;
-        (/*info:DynamicInvoke*/toString());
+        (/*info:DYNAMIC_INVOKE*/toString());
 
-        (/*info:DynamicInvoke*/helper.toString());
+        (/*info:DYNAMIC_INVOKE*/helper.toString());
         var toStringClosure2 = helper.toString;
-        (/*info:DynamicInvoke*/toStringClosure2());
-        int hashCode = /*info:DynamicCast*/helper.hashCode;
+        (/*info:DYNAMIC_INVOKE*/toStringClosure2());
+        int hashCode = /*info:DYNAMIC_CAST*/helper.hashCode;
 
         baz().toString();
         baz().hashCode;
@@ -230,27 +235,27 @@
         int x;
         String y;
 
-        A(this.x) : this.y = /*severe:StaticTypeError*/42;
+        A(this.x) : this.y = /*severe:STATIC_TYPE_ERROR*/42;
 
-        A.c1(p): this.x = /*info:DownCastImplicit*/z, this.y = /*info:DynamicCast*/p;
+        A.c1(p): this.x = /*info:DOWN_CAST_IMPLICIT*/z, this.y = /*info:DYNAMIC_CAST*/p;
 
         A.c2(this.x, this.y);
 
-        A.c3(/*severe:InvalidParameterDeclaration*/num this.x, String this.y);
+        A.c3(/*severe:INVALID_PARAMETER_DECLARATION*/num this.x, String this.y);
       }
 
       class B extends A {
-        B() : super(/*severe:StaticTypeError*/"hello");
+        B() : super(/*severe:STATIC_TYPE_ERROR*/"hello");
 
-        B.c2(int x, String y) : super.c2(/*severe:StaticTypeError*/y, 
-                                         /*severe:StaticTypeError*/x);
+        B.c2(int x, String y) : super.c2(/*severe:STATIC_TYPE_ERROR*/y, 
+                                         /*severe:STATIC_TYPE_ERROR*/x);
 
-        B.c3(num x, Object y) : super.c3(x, /*info:DownCastImplicit*/y);
+        B.c3(num x, Object y) : super.c3(x, /*info:DOWN_CAST_IMPLICIT*/y);
       }
 
       void main() {
-         A a = new A.c2(/*info:DownCastImplicit*/z, /*severe:StaticTypeError*/z);
-         var b = new B.c2(/*severe:StaticTypeError*/"hello", /*info:DownCastImplicit*/obj);
+         A a = new A.c2(/*info:DOWN_CAST_IMPLICIT*/z, /*severe:STATIC_TYPE_ERROR*/z);
+         var b = new B.c2(/*severe:STATIC_TYPE_ERROR*/"hello", /*info:DOWN_CAST_IMPLICIT*/obj);
       }
    '''
   });
@@ -258,7 +263,7 @@
   testChecker('Unbound variable', {
     '/main.dart': '''
       void main() {
-         dynamic y = /*pass should be severe:StaticTypeError*/unboundVariable;
+         dynamic y = /*pass should be severe:STATIC_TYPE_ERROR*/unboundVariable;
       }
    '''
   });
@@ -266,7 +271,18 @@
   testChecker('Unbound type name', {
     '/main.dart': '''
       void main() {
-         /*pass should be severe:StaticTypeError*/AToB y;
+         /*pass should be severe:STATIC_TYPE_ERROR*/AToB y;
+      }
+   '''
+  });
+
+  // Regression test for https://github.com/dart-lang/sdk/issues/25069
+  testChecker('Void subtyping', {
+    '/main.dart': '''
+      typedef int Foo();
+      void foo() {}
+      void main () {
+        Foo x = /*severe:STATIC_TYPE_ERROR*/foo();
       }
    '''
   });
@@ -310,11 +326,11 @@
          A a;
          B b;
          o = y;
-         i = /*info:DynamicCast*/y;
-         d = /*info:DynamicCast*/y;
-         n = /*info:DynamicCast*/y;
-         a = /*info:DynamicCast*/y;
-         b = /*info:DynamicCast*/y;
+         i = /*info:DYNAMIC_CAST*/y;
+         d = /*info:DYNAMIC_CAST*/y;
+         n = /*info:DYNAMIC_CAST*/y;
+         a = /*info:DYNAMIC_CAST*/y;
+         b = /*info:DYNAMIC_CAST*/y;
       }
    '''
   });
@@ -335,11 +351,11 @@
          B b;
          y = a;
          o = a;
-         i = /*severe:StaticTypeError*/a;
-         d = /*severe:StaticTypeError*/a;
-         n = /*severe:StaticTypeError*/a;
+         i = /*severe:STATIC_TYPE_ERROR*/a;
+         d = /*severe:STATIC_TYPE_ERROR*/a;
+         n = /*severe:STATIC_TYPE_ERROR*/a;
          a = a;
-         b = /*info:DownCastImplicit*/a;
+         b = /*info:DOWN_CAST_IMPLICIT*/a;
       }
    '''
   });
@@ -362,12 +378,12 @@
          C c;
          y = b;
          o = b;
-         i = /*severe:StaticTypeError*/b;
-         d = /*severe:StaticTypeError*/b;
-         n = /*severe:StaticTypeError*/b;
+         i = /*severe:STATIC_TYPE_ERROR*/b;
+         d = /*severe:STATIC_TYPE_ERROR*/b;
+         n = /*severe:STATIC_TYPE_ERROR*/b;
          a = b;
          b = b;
-         c = /*severe:StaticTypeError*/b;
+         c = /*severe:STATIC_TYPE_ERROR*/b;
       }
    '''
   });
@@ -392,21 +408,21 @@
            top = bot;
          }
          {
-           left = /*info:DownCastImplicit*/top;
+           left = /*info:DOWN_CAST_IMPLICIT*/top;
            left = left;
-           left = /*severe:StaticTypeError*/right;
+           left = /*severe:STATIC_TYPE_ERROR*/right;
            left = bot;
          }
          {
-           right = /*info:DownCastImplicit*/top;
-           right = /*severe:StaticTypeError*/left;
+           right = /*info:DOWN_CAST_IMPLICIT*/top;
+           right = /*severe:STATIC_TYPE_ERROR*/left;
            right = right;
            right = bot;
          }
          {
-           bot = /*info:DownCastImplicit*/top;
-           bot = /*info:DownCastImplicit*/left;
-           bot = /*info:DownCastImplicit*/right;
+           bot = /*info:DOWN_CAST_IMPLICIT*/top;
+           bot = /*info:DOWN_CAST_IMPLICIT*/left;
+           bot = /*info:DOWN_CAST_IMPLICIT*/right;
            bot = bot;
          }
       }
@@ -425,7 +441,7 @@
       Object top(int x) => x;
       int left(int x) => x;
       Object right(Object x) => x;
-      int _bot(Object x) => /*info:DownCastImplicit*/x;
+      int _bot(Object x) => /*info:DOWN_CAST_IMPLICIT*/x;
       int bot(Object x) => x as int;
 
       void main() {
@@ -442,23 +458,23 @@
         }
         {
           Left f;
-          f = /*warning:DownCastComposite*/top;
+          f = /*warning:DOWN_CAST_COMPOSITE*/top;
           f = left;
-          f = /*warning:DownCastComposite*/right; // Should we reject this?
+          f = /*warning:DOWN_CAST_COMPOSITE*/right; // Should we reject this?
           f = bot;
         }
         {
           Right f;
-          f = /*warning:DownCastComposite*/top;
-          f = /*warning:DownCastComposite*/left; // Should we reject this?
+          f = /*warning:DOWN_CAST_COMPOSITE*/top;
+          f = /*warning:DOWN_CAST_COMPOSITE*/left; // Should we reject this?
           f = right;
           f = bot;
         }
         {
           Bot f;
-          f = /*warning:DownCastComposite*/top;
-          f = /*warning:DownCastComposite*/left;
-          f = /*warning:DownCastComposite*/right;
+          f = /*warning:DOWN_CAST_COMPOSITE*/top;
+          f = /*warning:DOWN_CAST_COMPOSITE*/left;
+          f = /*warning:DOWN_CAST_COMPOSITE*/right;
           f = bot;
         }
       }
@@ -478,7 +494,7 @@
       typedef B Bot(A x);   // Bottom of the lattice
 
       B left(B x) => x;
-      B _bot(A x) => /*info:DownCastImplicit*/x;
+      B _bot(A x) => /*info:DOWN_CAST_IMPLICIT*/x;
       B bot(A x) => x as B;
       A top(B x) => x;
       A right(A x) => x;
@@ -497,23 +513,23 @@
         }
         {
           Left f;
-          f = /*warning:DownCastComposite*/top;
+          f = /*warning:DOWN_CAST_COMPOSITE*/top;
           f = left;
-          f = /*warning:DownCastComposite*/right; // Should we reject this?
+          f = /*warning:DOWN_CAST_COMPOSITE*/right; // Should we reject this?
           f = bot;
         }
         {
           Right f;
-          f = /*warning:DownCastComposite*/top;
-          f = /*warning:DownCastComposite*/left; // Should we reject this?
+          f = /*warning:DOWN_CAST_COMPOSITE*/top;
+          f = /*warning:DOWN_CAST_COMPOSITE*/left; // Should we reject this?
           f = right;
           f = bot;
         }
         {
           Bot f;
-          f = /*warning:DownCastComposite*/top;
-          f = /*warning:DownCastComposite*/left;
-          f = /*warning:DownCastComposite*/right;
+          f = /*warning:DOWN_CAST_COMPOSITE*/top;
+          f = /*warning:DOWN_CAST_COMPOSITE*/left;
+          f = /*warning:DOWN_CAST_COMPOSITE*/right;
           f = bot;
         }
       }
@@ -533,7 +549,7 @@
       dynamic left(A x) => x;
       A bot(A x) => x;
       dynamic top(dynamic x) => x;
-      A right(dynamic x) => /*info:DynamicCast*/x;
+      A right(dynamic x) => /*info:DYNAMIC_CAST*/x;
 
       void main() {
         {
@@ -545,23 +561,23 @@
         }
         {
           Left f;
-          f = /*warning:DownCastComposite*/top;
+          f = /*warning:DOWN_CAST_COMPOSITE*/top;
           f = left;
-          f = /*warning:DownCastComposite*/right;
+          f = /*warning:DOWN_CAST_COMPOSITE*/right;
           f = bot;
         }
         {
           Right f;
-          f = /*warning:DownCastComposite*/top;
-          f = /*warning:DownCastComposite*/left;
+          f = /*warning:DOWN_CAST_COMPOSITE*/top;
+          f = /*warning:DOWN_CAST_COMPOSITE*/left;
           f = right;
           f = bot;
         }
         {
           Bottom f;
-          f = /*warning:DownCastComposite*/top;
-          f = /*warning:DownCastComposite*/left;
-          f = /*warning:DownCastComposite*/right;
+          f = /*warning:DOWN_CAST_COMPOSITE*/top;
+          f = /*warning:DOWN_CAST_COMPOSITE*/left;
+          f = /*warning:DOWN_CAST_COMPOSITE*/right;
           f = bot;
         }
       }
@@ -591,23 +607,23 @@
         }
         {
           Function2<B, B> f;
-          f = /*warning:DownCastComposite*/top;
+          f = /*warning:DOWN_CAST_COMPOSITE*/top;
           f = left;
-          f = /*warning:DownCastComposite*/right; // Should we reject this?
+          f = /*warning:DOWN_CAST_COMPOSITE*/right; // Should we reject this?
           f = bot;
         }
         {
           Function2<A, A> f;
-          f = /*warning:DownCastComposite*/top;
-          f = /*warning:DownCastComposite*/left; // Should we reject this?
+          f = /*warning:DOWN_CAST_COMPOSITE*/top;
+          f = /*warning:DOWN_CAST_COMPOSITE*/left; // Should we reject this?
           f = right;
           f = bot;
         }
         {
           Function2<A, B> f;
-          f = /*warning:DownCastComposite*/top;
-          f = /*warning:DownCastComposite*/left;
-          f = /*warning:DownCastComposite*/right;
+          f = /*warning:DOWN_CAST_COMPOSITE*/top;
+          f = /*warning:DOWN_CAST_COMPOSITE*/left;
+          f = /*warning:DOWN_CAST_COMPOSITE*/right;
           f = bot;
         }
       }
@@ -634,19 +650,19 @@
           top = top;
           top = left;
 
-          left = /*warning:DownCastComposite*/top;
+          left = /*warning:DOWN_CAST_COMPOSITE*/top;
           left = left;
-          left = /*warning:DownCastComposite*/right; // Should we reject this?
+          left = /*warning:DOWN_CAST_COMPOSITE*/right; // Should we reject this?
           left = bot;
 
-          right = /*warning:DownCastComposite*/top;
-          right = /*warning:DownCastComposite*/left; // Should we reject this?
+          right = /*warning:DOWN_CAST_COMPOSITE*/top;
+          right = /*warning:DOWN_CAST_COMPOSITE*/left; // Should we reject this?
           right = right;
           right = bot;
 
-          bot = /*warning:DownCastComposite*/top;
-          bot = /*warning:DownCastComposite*/left;
-          bot = /*warning:DownCastComposite*/right;
+          bot = /*warning:DOWN_CAST_COMPOSITE*/top;
+          bot = /*warning:DOWN_CAST_COMPOSITE*/left;
+          bot = /*warning:DOWN_CAST_COMPOSITE*/right;
           bot = bot;
         }
       }
@@ -667,20 +683,20 @@
       BToA top(AToB f) => f;
       AToB left(AToB f) => f;
       BToA right(BToA f) => f;
-      AToB _bot(BToA f) => /*warning:DownCastComposite*/f;
+      AToB _bot(BToA f) => /*warning:DOWN_CAST_COMPOSITE*/f;
       AToB bot(BToA f) => f as AToB;
 
       Function2<B, A> top(AToB f) => f;
       Function2<A, B> left(AToB f) => f;
       Function2<B, A> right(BToA f) => f;
-      Function2<A, B> _bot(BToA f) => /*warning:DownCastComposite*/f;
+      Function2<A, B> _bot(BToA f) => /*warning:DOWN_CAST_COMPOSITE*/f;
       Function2<A, B> bot(BToA f) => f as Function2<A, B>;
 
 
       BToA top(Function2<A, B> f) => f;
       AToB left(Function2<A, B> f) => f;
       BToA right(Function2<B, A> f) => f;
-      AToB _bot(Function2<B, A> f) => /*warning:DownCastComposite*/f;
+      AToB _bot(Function2<B, A> f) => /*warning:DOWN_CAST_COMPOSITE*/f;
       AToB bot(Function2<B, A> f) => f as AToB;
 
       void main() {
@@ -693,24 +709,24 @@
         }
         {
           Function2<AToB, AToB> f; // Left
-          f = /*warning:DownCastComposite*/top;
+          f = /*warning:DOWN_CAST_COMPOSITE*/top;
           f = left;
-          f = /*warning:DownCastComposite*/right; // Should we reject this?
+          f = /*warning:DOWN_CAST_COMPOSITE*/right; // Should we reject this?
           f = bot;
         }
         {
           Function2<BToA, BToA> f; // Right
-          f = /*warning:DownCastComposite*/top;
-          f = /*warning:DownCastComposite*/left; // Should we reject this?
+          f = /*warning:DOWN_CAST_COMPOSITE*/top;
+          f = /*warning:DOWN_CAST_COMPOSITE*/left; // Should we reject this?
           f = right;
           f = bot;
         }
         {
           Function2<BToA, AToB> f; // Bot
           f = bot;
-          f = /*warning:DownCastComposite*/left;
-          f = /*warning:DownCastComposite*/top;
-          f = /*warning:DownCastComposite*/left;
+          f = /*warning:DOWN_CAST_COMPOSITE*/left;
+          f = /*warning:DOWN_CAST_COMPOSITE*/top;
+          f = /*warning:DOWN_CAST_COMPOSITE*/left;
         }
       }
    '''
@@ -737,21 +753,21 @@
         top = top;
         top = left;
 
-        left = /*warning:DownCastComposite*/top;
+        left = /*warning:DOWN_CAST_COMPOSITE*/top;
         left = left;
         left =
-            /*warning:DownCastComposite should be severe:StaticTypeError*/right;
+            /*warning:DOWN_CAST_COMPOSITE should be severe:STATIC_TYPE_ERROR*/right;
         left = bot;
 
-        right = /*warning:DownCastComposite*/top;
+        right = /*warning:DOWN_CAST_COMPOSITE*/top;
         right =
-            /*warning:DownCastComposite should be severe:StaticTypeError*/left;
+            /*warning:DOWN_CAST_COMPOSITE should be severe:STATIC_TYPE_ERROR*/left;
         right = right;
         right = bot;
 
-        bot = /*warning:DownCastComposite*/top;
-        bot = /*warning:DownCastComposite*/left;
-        bot = /*warning:DownCastComposite*/right;
+        bot = /*warning:DOWN_CAST_COMPOSITE*/top;
+        bot = /*warning:DOWN_CAST_COMPOSITE*/left;
+        bot = /*warning:DOWN_CAST_COMPOSITE*/right;
         bot = bot;
       }
     }
@@ -786,92 +802,92 @@
 
          r = r;
          r = o;
-         r = /*severe:StaticTypeError*/n;
-         r = /*severe:StaticTypeError*/rr;
+         r = /*severe:STATIC_TYPE_ERROR*/n;
+         r = /*severe:STATIC_TYPE_ERROR*/rr;
          r = ro;
          r = rn;
          r = oo;
-         r = /*severe:StaticTypeError*/nn;
-         r = /*severe:StaticTypeError*/nnn;
+         r = /*severe:STATIC_TYPE_ERROR*/nn;
+         r = /*severe:STATIC_TYPE_ERROR*/nnn;
 
-         o = /*warning:DownCastComposite*/r;
+         o = /*warning:DOWN_CAST_COMPOSITE*/r;
          o = o;
-         o = /*severe:StaticTypeError*/n;
-         o = /*severe:StaticTypeError*/rr;
-         o = /*severe:StaticTypeError*/ro;
-         o = /*severe:StaticTypeError*/rn;
+         o = /*severe:STATIC_TYPE_ERROR*/n;
+         o = /*severe:STATIC_TYPE_ERROR*/rr;
+         o = /*severe:STATIC_TYPE_ERROR*/ro;
+         o = /*severe:STATIC_TYPE_ERROR*/rn;
          o = oo;
-         o = /*severe:StaticTypeError*/nn
-         o = /*severe:StaticTypeError*/nnn;
+         o = /*severe:STATIC_TYPE_ERROR*/nn
+         o = /*severe:STATIC_TYPE_ERROR*/nnn;
 
-         n = /*severe:StaticTypeError*/r;
-         n = /*severe:StaticTypeError*/o;
+         n = /*severe:STATIC_TYPE_ERROR*/r;
+         n = /*severe:STATIC_TYPE_ERROR*/o;
          n = n;
-         n = /*severe:StaticTypeError*/rr;
-         n = /*severe:StaticTypeError*/ro;
-         n = /*severe:StaticTypeError*/rn;
-         n = /*severe:StaticTypeError*/oo;
+         n = /*severe:STATIC_TYPE_ERROR*/rr;
+         n = /*severe:STATIC_TYPE_ERROR*/ro;
+         n = /*severe:STATIC_TYPE_ERROR*/rn;
+         n = /*severe:STATIC_TYPE_ERROR*/oo;
          n = nn;
          n = nnn;
 
-         rr = /*severe:StaticTypeError*/r;
-         rr = /*severe:StaticTypeError*/o;
-         rr = /*severe:StaticTypeError*/n;
+         rr = /*severe:STATIC_TYPE_ERROR*/r;
+         rr = /*severe:STATIC_TYPE_ERROR*/o;
+         rr = /*severe:STATIC_TYPE_ERROR*/n;
          rr = rr;
          rr = ro;
-         rr = /*severe:StaticTypeError*/rn;
+         rr = /*severe:STATIC_TYPE_ERROR*/rn;
          rr = oo;
-         rr = /*severe:StaticTypeError*/nn;
-         rr = /*severe:StaticTypeError*/nnn;
+         rr = /*severe:STATIC_TYPE_ERROR*/nn;
+         rr = /*severe:STATIC_TYPE_ERROR*/nnn;
 
-         ro = /*warning:DownCastComposite*/r;
-         ro = /*severe:StaticTypeError*/o;
-         ro = /*severe:StaticTypeError*/n;
-         ro = /*warning:DownCastComposite*/rr;
+         ro = /*warning:DOWN_CAST_COMPOSITE*/r;
+         ro = /*severe:STATIC_TYPE_ERROR*/o;
+         ro = /*severe:STATIC_TYPE_ERROR*/n;
+         ro = /*warning:DOWN_CAST_COMPOSITE*/rr;
          ro = ro;
-         ro = /*severe:StaticTypeError*/rn;
+         ro = /*severe:STATIC_TYPE_ERROR*/rn;
          ro = oo;
-         ro = /*severe:StaticTypeError*/nn;
-         ro = /*severe:StaticTypeError*/nnn;
+         ro = /*severe:STATIC_TYPE_ERROR*/nn;
+         ro = /*severe:STATIC_TYPE_ERROR*/nnn;
 
-         rn = /*warning:DownCastComposite*/r;
-         rn = /*severe:StaticTypeError*/o;
-         rn = /*severe:StaticTypeError*/n;
-         rn = /*severe:StaticTypeError*/rr;
-         rn = /*severe:StaticTypeError*/ro;
+         rn = /*warning:DOWN_CAST_COMPOSITE*/r;
+         rn = /*severe:STATIC_TYPE_ERROR*/o;
+         rn = /*severe:STATIC_TYPE_ERROR*/n;
+         rn = /*severe:STATIC_TYPE_ERROR*/rr;
+         rn = /*severe:STATIC_TYPE_ERROR*/ro;
          rn = rn;
-         rn = /*severe:StaticTypeError*/oo;
-         rn = /*severe:StaticTypeError*/nn;
-         rn = /*severe:StaticTypeError*/nnn;
+         rn = /*severe:STATIC_TYPE_ERROR*/oo;
+         rn = /*severe:STATIC_TYPE_ERROR*/nn;
+         rn = /*severe:STATIC_TYPE_ERROR*/nnn;
 
-         oo = /*warning:DownCastComposite*/r;
-         oo = /*warning:DownCastComposite*/o;
-         oo = /*severe:StaticTypeError*/n;
-         oo = /*warning:DownCastComposite*/rr;
-         oo = /*warning:DownCastComposite*/ro;
-         oo = /*severe:StaticTypeError*/rn;
+         oo = /*warning:DOWN_CAST_COMPOSITE*/r;
+         oo = /*warning:DOWN_CAST_COMPOSITE*/o;
+         oo = /*severe:STATIC_TYPE_ERROR*/n;
+         oo = /*warning:DOWN_CAST_COMPOSITE*/rr;
+         oo = /*warning:DOWN_CAST_COMPOSITE*/ro;
+         oo = /*severe:STATIC_TYPE_ERROR*/rn;
          oo = oo;
-         oo = /*severe:StaticTypeError*/nn;
-         oo = /*severe:StaticTypeError*/nnn;
+         oo = /*severe:STATIC_TYPE_ERROR*/nn;
+         oo = /*severe:STATIC_TYPE_ERROR*/nnn;
 
-         nn = /*severe:StaticTypeError*/r;
-         nn = /*severe:StaticTypeError*/o;
-         nn = /*warning:DownCastComposite*/n;
-         nn = /*severe:StaticTypeError*/rr;
-         nn = /*severe:StaticTypeError*/ro;
-         nn = /*severe:StaticTypeError*/rn;
-         nn = /*severe:StaticTypeError*/oo;
+         nn = /*severe:STATIC_TYPE_ERROR*/r;
+         nn = /*severe:STATIC_TYPE_ERROR*/o;
+         nn = /*warning:DOWN_CAST_COMPOSITE*/n;
+         nn = /*severe:STATIC_TYPE_ERROR*/rr;
+         nn = /*severe:STATIC_TYPE_ERROR*/ro;
+         nn = /*severe:STATIC_TYPE_ERROR*/rn;
+         nn = /*severe:STATIC_TYPE_ERROR*/oo;
          nn = nn;
          nn = nnn;
 
-         nnn = /*severe:StaticTypeError*/r;
-         nnn = /*severe:StaticTypeError*/o;
-         nnn = /*warning:DownCastComposite*/n;
-         nnn = /*severe:StaticTypeError*/rr;
-         nnn = /*severe:StaticTypeError*/ro;
-         nnn = /*severe:StaticTypeError*/rn;
-         nnn = /*severe:StaticTypeError*/oo;
-         nnn = /*warning:DownCastComposite*/nn;
+         nnn = /*severe:STATIC_TYPE_ERROR*/r;
+         nnn = /*severe:STATIC_TYPE_ERROR*/o;
+         nnn = /*warning:DOWN_CAST_COMPOSITE*/n;
+         nnn = /*severe:STATIC_TYPE_ERROR*/rr;
+         nnn = /*severe:STATIC_TYPE_ERROR*/ro;
+         nnn = /*severe:STATIC_TYPE_ERROR*/rn;
+         nnn = /*severe:STATIC_TYPE_ERROR*/oo;
+         nnn = /*warning:DOWN_CAST_COMPOSITE*/nn;
          nnn = nnn;
       }
    '''
@@ -894,38 +910,38 @@
          {
            I2I f;
            f = new A();
-           f = /*severe:StaticTypeError*/new B();
+           f = /*severe:STATIC_TYPE_ERROR*/new B();
            f = i2i;
-           f = /*warning:DownCastComposite*/n2n;
-           f = /*warning:DownCastComposite*/i2i as Object;
-           f = /*warning:DownCastComposite*/n2n as Function;
+           f = /*warning:DOWN_CAST_COMPOSITE*/n2n;
+           f = /*warning:DOWN_CAST_COMPOSITE*/i2i as Object;
+           f = /*warning:DOWN_CAST_COMPOSITE*/n2n as Function;
          }
          {
            N2N f;
-           f = /*severe:StaticTypeError*/new A();
+           f = /*severe:STATIC_TYPE_ERROR*/new A();
            f = new B();
-           f = /*warning:DownCastComposite*/i2i;
+           f = /*warning:DOWN_CAST_COMPOSITE*/i2i;
            f = n2n;
-           f = /*warning:DownCastComposite*/i2i as Object;
-           f = /*warning:DownCastComposite*/n2n as Function;
+           f = /*warning:DOWN_CAST_COMPOSITE*/i2i as Object;
+           f = /*warning:DOWN_CAST_COMPOSITE*/n2n as Function;
          }
          {
            A f;
            f = new A();
-           f = /*severe:StaticTypeError*/new B();
-           f = /*severe:StaticTypeError*/i2i;
-           f = /*severe:StaticTypeError*/n2n;
-           f = /*info:DownCastImplicit*/i2i as Object;
-           f = /*info:DownCastImplicit*/n2n as Function;
+           f = /*severe:STATIC_TYPE_ERROR*/new B();
+           f = /*severe:STATIC_TYPE_ERROR*/i2i;
+           f = /*severe:STATIC_TYPE_ERROR*/n2n;
+           f = /*info:DOWN_CAST_IMPLICIT*/i2i as Object;
+           f = /*info:DOWN_CAST_IMPLICIT*/n2n as Function;
          }
          {
            B f;
-           f = /*severe:StaticTypeError*/new A();
+           f = /*severe:STATIC_TYPE_ERROR*/new A();
            f = new B();
-           f = /*severe:StaticTypeError*/i2i;
-           f = /*severe:StaticTypeError*/n2n;
-           f = /*info:DownCastImplicit*/i2i as Object;
-           f = /*info:DownCastImplicit*/n2n as Function;
+           f = /*severe:STATIC_TYPE_ERROR*/i2i;
+           f = /*severe:STATIC_TYPE_ERROR*/n2n;
+           f = /*info:DOWN_CAST_IMPLICIT*/i2i as Object;
+           f = /*info:DOWN_CAST_IMPLICIT*/n2n as Function;
          }
          {
            Function f;
@@ -933,7 +949,7 @@
            f = new B();
            f = i2i;
            f = n2n;
-           f = /*info:DownCastImplicit*/i2i as Object;
+           f = /*info:DOWN_CAST_IMPLICIT*/i2i as Object;
            f = (n2n as Function);
          }
       }
@@ -992,36 +1008,36 @@
           lOfOs = lOfAs;
         }
         {
-          lOfAs = /*warning:DownCastComposite*/mOfDs;
-          lOfAs = /*severe:StaticTypeError*/mOfOs;
+          lOfAs = /*warning:DOWN_CAST_COMPOSITE*/mOfDs;
+          lOfAs = /*severe:STATIC_TYPE_ERROR*/mOfOs;
           lOfAs = mOfAs;
-          lOfAs = /*warning:DownCastComposite*/lOfDs;
-          lOfAs = /*info:DownCastImplicit*/lOfOs;
+          lOfAs = /*warning:DOWN_CAST_COMPOSITE*/lOfDs;
+          lOfAs = /*info:DOWN_CAST_IMPLICIT*/lOfOs;
           lOfAs = lOfAs;
         }
         {
           mOfDs = mOfDs;
           mOfDs = mOfOs;
           mOfDs = mOfAs;
-          mOfDs = /*info:DownCastImplicit*/lOfDs;
-          mOfDs = /*info:DownCastImplicit*/lOfOs;
-          mOfDs = /*warning:DownCastComposite*/lOfAs;
+          mOfDs = /*info:DOWN_CAST_IMPLICIT*/lOfDs;
+          mOfDs = /*info:DOWN_CAST_IMPLICIT*/lOfOs;
+          mOfDs = /*warning:DOWN_CAST_COMPOSITE*/lOfAs;
         }
         {
           mOfOs = mOfDs;
           mOfOs = mOfOs;
           mOfOs = mOfAs;
-          mOfOs = /*info:DownCastImplicit*/lOfDs;
-          mOfOs = /*info:DownCastImplicit*/lOfOs;
-          mOfOs = /*severe:StaticTypeError*/lOfAs;
+          mOfOs = /*info:DOWN_CAST_IMPLICIT*/lOfDs;
+          mOfOs = /*info:DOWN_CAST_IMPLICIT*/lOfOs;
+          mOfOs = /*severe:STATIC_TYPE_ERROR*/lOfAs;
         }
         {
-          mOfAs = /*warning:DownCastComposite*/mOfDs;
-          mOfAs = /*info:DownCastImplicit*/mOfOs;
+          mOfAs = /*warning:DOWN_CAST_COMPOSITE*/mOfDs;
+          mOfAs = /*info:DOWN_CAST_IMPLICIT*/mOfOs;
           mOfAs = mOfAs;
-          mOfAs = /*warning:DownCastComposite*/lOfDs;
-          mOfAs = /*info:DownCastImplicit*/lOfOs;
-          mOfAs = /*info:DownCastImplicit*/lOfAs;
+          mOfAs = /*warning:DOWN_CAST_COMPOSITE*/lOfDs;
+          mOfAs = /*info:DOWN_CAST_IMPLICIT*/lOfOs;
+          mOfAs = /*info:DOWN_CAST_IMPLICIT*/lOfAs;
         }
 
       }
@@ -1036,9 +1052,9 @@
             String s = "hello";
             {
                List<int> l = <int>[i];
-               l = <int>[/*severe:StaticTypeError*/s];
-               l = <int>[/*info:DownCastImplicit*/n];
-               l = <int>[i, /*info:DownCastImplicit*/n, /*severe:StaticTypeError*/s];
+               l = <int>[/*severe:STATIC_TYPE_ERROR*/s];
+               l = <int>[/*info:DOWN_CAST_IMPLICIT*/n];
+               l = <int>[i, /*info:DOWN_CAST_IMPLICIT*/n, /*severe:STATIC_TYPE_ERROR*/s];
             }
             {
                List l = [i];
@@ -1048,11 +1064,11 @@
             }
             {
                Map<String, int> m = <String, int>{s: i};
-               m = <String, int>{s: /*severe:StaticTypeError*/s};
-               m = <String, int>{s: /*info:DownCastImplicit*/n};
+               m = <String, int>{s: /*severe:STATIC_TYPE_ERROR*/s};
+               m = <String, int>{s: /*info:DOWN_CAST_IMPLICIT*/n};
                m = <String, int>{s: i,
-                                 s: /*info:DownCastImplicit*/n,
-                                 s: /*severe:StaticTypeError*/s};
+                                 s: /*info:DOWN_CAST_IMPLICIT*/n,
+                                 s: /*severe:STATIC_TYPE_ERROR*/s};
             }
            // TODO(leafp): We can't currently test for key errors since the
            // error marker binds to the entire entry.
@@ -1075,15 +1091,15 @@
     '/main.dart': '''
           class A {
             static const num n = 3.0;
-            static const int i = /*info:AssignmentCast*/n;
+            static const int i = /*info:ASSIGNMENT_CAST*/n;
             final int fi;
-            const A(num a) : this.fi = /*info:DownCastImplicit*/a;
+            const A(num a) : this.fi = /*info:DOWN_CAST_IMPLICIT*/a;
           }
           class B extends A {
-            const B(Object a) : super(/*info:DownCastImplicit*/a);
+            const B(Object a) : super(/*info:DOWN_CAST_IMPLICIT*/a);
           }
           void foo(Object o) {
-            var a = const A(/*info:DownCastImplicit*/o);
+            var a = const A(/*info:DOWN_CAST_IMPLICIT*/o);
           }
      '''
   });
@@ -1093,18 +1109,27 @@
           main() {
             bool b = true;
             num x = b ? 1 : 2.3;
-            int y = /*info:AssignmentCast*/b ? 1 : 2.3;
+            int y = /*info:ASSIGNMENT_CAST*/b ? 1 : 2.3;
             String z = !b ? "hello" : null;
             z = b ? null : "hello";
           }
       '''
   });
 
+  // This is a regression test for https://github.com/dart-lang/sdk/issues/25071
+  testChecker('unbound redirecting constructor', {
+    '/main.dart': '''
+      class Foo {
+        Foo() : this.init();
+      }
+       '''
+  });
+
   testChecker('redirecting constructor', {
     '/main.dart': '''
           class A {
             A(A x) {}
-            A.two() : this(/*severe:StaticTypeError*/3);
+            A.two() : this(/*severe:STATIC_TYPE_ERROR*/3);
           }
        '''
   });
@@ -1113,7 +1138,7 @@
     '/main.dart': '''
           class A { A(A x) {} }
           class B extends A {
-            B() : super(/*severe:StaticTypeError*/3);
+            B() : super(/*severe:STATIC_TYPE_ERROR*/3);
           }
        '''
   });
@@ -1132,17 +1157,17 @@
           }
 
           class Child extends Base {
-            /*severe:InvalidFieldOverride,severe:InvalidMethodOverride*/A f1; // invalid for getter
-            /*severe:InvalidFieldOverride,severe:InvalidMethodOverride*/C f2; // invalid for setter
-            /*severe:InvalidFieldOverride*/var f3;
-            /*severe:InvalidFieldOverride,severe:InvalidMethodOverride,severe:InvalidMethodOverride*/dynamic f4;
+            /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/A f1; // invalid for getter
+            /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/C f2; // invalid for setter
+            /*severe:INVALID_FIELD_OVERRIDE*/var f3;
+            /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/dynamic f4;
           }
 
           class Child2 implements Base {
-            /*severe:InvalidMethodOverride*/A f1; // invalid for getter
-            /*severe:InvalidMethodOverride*/C f2; // invalid for setter
+            /*severe:INVALID_METHOD_OVERRIDE*/A f1; // invalid for getter
+            /*severe:INVALID_METHOD_OVERRIDE*/C f2; // invalid for setter
             var f3;
-            /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/dynamic f4;
+            /*severe:INVALID_METHOD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/dynamic f4;
           }
        '''
   });
@@ -1161,18 +1186,18 @@
           }
 
           class GrandChild extends main.Child {
-            /*severe:InvalidFieldOverride*/var _f2;
-            /*severe:InvalidFieldOverride*/var _f3;
+            /*severe:INVALID_FIELD_OVERRIDE*/var _f2;
+            /*severe:INVALID_FIELD_OVERRIDE*/var _f3;
             var _f4;
 
-            /*severe:InvalidMethodOverride*/String _m1();
+            /*severe:INVALID_METHOD_OVERRIDE*/String _m1();
           }
     ''',
     '/main.dart': '''
           import 'helper.dart' as helper;
 
           class Child extends helper.Base {
-            /*severe:InvalidFieldOverride*/var f1;
+            /*severe:INVALID_FIELD_OVERRIDE*/var f1;
             var _f2;
             var _f4;
 
@@ -1195,10 +1220,10 @@
           }
 
           class Child extends Base {
-            /*severe:InvalidMethodOverride*/A get f1 => null;
+            /*severe:INVALID_METHOD_OVERRIDE*/A get f1 => null;
             C get f2 => null;
             get f3 => null;
-            /*severe:InvalidMethodOverride*/dynamic get f4 => null;
+            /*severe:INVALID_METHOD_OVERRIDE*/dynamic get f4 => null;
           }
        '''
   });
@@ -1217,17 +1242,17 @@
           }
 
           class Child extends Base {
-            /*severe:InvalidFieldOverride,severe:InvalidMethodOverride*/A get f1 => null;
-            /*severe:InvalidFieldOverride*/C get f2 => null;
-            /*severe:InvalidFieldOverride*/get f3 => null;
-            /*severe:InvalidFieldOverride,severe:InvalidMethodOverride*/dynamic get f4 => null;
+            /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/A get f1 => null;
+            /*severe:INVALID_FIELD_OVERRIDE*/C get f2 => null;
+            /*severe:INVALID_FIELD_OVERRIDE*/get f3 => null;
+            /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/dynamic get f4 => null;
           }
 
           class Child2 implements Base {
-            /*severe:InvalidMethodOverride*/A get f1 => null;
+            /*severe:INVALID_METHOD_OVERRIDE*/A get f1 => null;
             C get f2 => null;
             get f3 => null;
-            /*severe:InvalidMethodOverride*/dynamic get f4 => null;
+            /*severe:INVALID_METHOD_OVERRIDE*/dynamic get f4 => null;
           }
        '''
   });
@@ -1248,9 +1273,9 @@
 
           class Child extends Base {
             void set f1(A value) {}
-            /*severe:InvalidMethodOverride*/void set f2(C value) {}
+            /*severe:INVALID_METHOD_OVERRIDE*/void set f2(C value) {}
             void set f3(value) {}
-            /*severe:InvalidMethodOverride*/void set f4(dynamic value) {}
+            /*severe:INVALID_METHOD_OVERRIDE*/void set f4(dynamic value) {}
             set f5(B value) {}
           }
        '''
@@ -1271,17 +1296,17 @@
           }
 
           class Child extends Base {
-            /*severe:InvalidFieldOverride*/B get f1 => null;
-            /*severe:InvalidFieldOverride*/B get f2 => null;
-            /*severe:InvalidFieldOverride*/B get f3 => null;
-            /*severe:InvalidFieldOverride*/B get f4 => null;
-            /*severe:InvalidFieldOverride*/B get f5 => null;
+            /*severe:INVALID_FIELD_OVERRIDE*/B get f1 => null;
+            /*severe:INVALID_FIELD_OVERRIDE*/B get f2 => null;
+            /*severe:INVALID_FIELD_OVERRIDE*/B get f3 => null;
+            /*severe:INVALID_FIELD_OVERRIDE*/B get f4 => null;
+            /*severe:INVALID_FIELD_OVERRIDE*/B get f5 => null;
 
-            /*severe:InvalidFieldOverride*/void set f1(A value) {}
-            /*severe:InvalidFieldOverride,severe:InvalidMethodOverride*/void set f2(C value) {}
-            /*severe:InvalidFieldOverride*/void set f3(value) {}
-            /*severe:InvalidFieldOverride,severe:InvalidMethodOverride*/void set f4(dynamic value) {}
-            /*severe:InvalidFieldOverride*/set f5(B value) {}
+            /*severe:INVALID_FIELD_OVERRIDE*/void set f1(A value) {}
+            /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/void set f2(C value) {}
+            /*severe:INVALID_FIELD_OVERRIDE*/void set f3(value) {}
+            /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/void set f4(dynamic value) {}
+            /*severe:INVALID_FIELD_OVERRIDE*/set f5(B value) {}
           }
 
           class Child2 implements Base {
@@ -1292,9 +1317,9 @@
             B get f5 => null;
 
             void set f1(A value) {}
-            /*severe:InvalidMethodOverride*/void set f2(C value) {}
+            /*severe:INVALID_METHOD_OVERRIDE*/void set f2(C value) {}
             void set f3(value) {}
-            /*severe:InvalidMethodOverride*/void set f4(dynamic value) {}
+            /*severe:INVALID_METHOD_OVERRIDE*/void set f4(dynamic value) {}
             set f5(B value) {}
           }
        '''
@@ -1316,12 +1341,12 @@
           }
 
           class Child extends Base {
-            /*severe:InvalidMethodOverride*/A m1(A value) {}
-            /*severe:InvalidMethodOverride*/C m2(C value) {}
-            /*severe:InvalidMethodOverride*/A m3(C value) {}
+            /*severe:INVALID_METHOD_OVERRIDE*/A m1(A value) {}
+            /*severe:INVALID_METHOD_OVERRIDE*/C m2(C value) {}
+            /*severe:INVALID_METHOD_OVERRIDE*/A m3(C value) {}
             C m4(A value) {}
             m5(value) {}
-            /*severe:InvalidMethodOverride*/dynamic m6(dynamic value) {}
+            /*severe:INVALID_METHOD_OVERRIDE*/dynamic m6(dynamic value) {}
           }
        '''
   });
@@ -1342,23 +1367,23 @@
         var c = foo();
 
         ~a;
-        (/*info:DynamicInvoke*/~d);
+        (/*info:DYNAMIC_INVOKE*/~d);
 
-        !/*severe:StaticTypeError*/a;
-        !/*info:DynamicCast*/d;
+        !/*severe:STATIC_TYPE_ERROR*/a;
+        !/*info:DYNAMIC_CAST*/d;
 
         -a;
-        (/*info:DynamicInvoke*/-d);
+        (/*info:DYNAMIC_INVOKE*/-d);
 
         ++a;
         --a;
-        (/*info:DynamicInvoke*/++d);
-        (/*info:DynamicInvoke*/--d);
+        (/*info:DYNAMIC_INVOKE*/++d);
+        (/*info:DYNAMIC_INVOKE*/--d);
 
         a++;
         a--;
-        (/*info:DynamicInvoke*/d++);
-        (/*info:DynamicInvoke*/d--);
+        (/*info:DYNAMIC_INVOKE*/d++);
+        (/*info:DYNAMIC_INVOKE*/d--);
       }'''
   });
 
@@ -1390,39 +1415,39 @@
             B b = new B();
             var c = foo();
             a = a * b;
-            a = a * /*info:DynamicCast*/c;
+            a = a * /*info:DYNAMIC_CAST*/c;
             a = a / b;
             a = a ~/ b;
             a = a % b;
             a = a + b;
-            a = a + /*severe:StaticTypeError*/a;
+            a = a + /*severe:STATIC_TYPE_ERROR*/a;
             a = a - b;
-            b = /*severe:StaticTypeError*/b - b;
+            b = /*severe:STATIC_TYPE_ERROR*/b - b;
             a = a << b;
             a = a >> b;
             a = a & b;
             a = a ^ b;
             a = a | b;
-            c = (/*info:DynamicInvoke*/c + b);
+            c = (/*info:DYNAMIC_INVOKE*/c + b);
 
             String x = 'hello';
             int y = 42;
             x = x + x;
-            x = x + /*info:DynamicCast*/c;
-            x = x + /*severe:StaticTypeError*/y;
+            x = x + /*info:DYNAMIC_CAST*/c;
+            x = x + /*severe:STATIC_TYPE_ERROR*/y;
 
             bool p = true;
             p = p && p;
-            p = p && /*info:DynamicCast*/c;
-            p = (/*info:DynamicCast*/c) && p;
-            p = (/*info:DynamicCast*/c) && /*info:DynamicCast*/c;
-            p = (/*severe:StaticTypeError*/y) && p;
+            p = p && /*info:DYNAMIC_CAST*/c;
+            p = (/*info:DYNAMIC_CAST*/c) && p;
+            p = (/*info:DYNAMIC_CAST*/c) && /*info:DYNAMIC_CAST*/c;
+            p = (/*severe:STATIC_TYPE_ERROR*/y) && p;
             p = c == y;
 
             a = a[b];
-            a = a[/*info:DynamicCast*/c];
-            c = (/*info:DynamicInvoke*/c[b]);
-            a[/*severe:StaticTypeError*/y];
+            a = a[/*info:DYNAMIC_CAST*/c];
+            c = (/*info:DYNAMIC_INVOKE*/c[b]);
+            a[/*severe:STATIC_TYPE_ERROR*/y];
           }
        '''
   });
@@ -1458,7 +1483,7 @@
           test() {
             int x = 0;
             x += 5;
-            (/*severe:StaticTypeError*/x += 3.14);
+            (/*severe:STATIC_TYPE_ERROR*/x += 3.14);
 
             double y = 0.0;
             y += 5;
@@ -1468,43 +1493,43 @@
             z += 5;
             z += 3.14;
 
-            x = /*info:DownCastImplicit*/x + z;
-            x += /*info:DownCastImplicit*/z;
-            y = /*info:DownCastImplicit*/y + z;
-            y += /*info:DownCastImplicit*/z;
+            x = /*info:DOWN_CAST_IMPLICIT*/x + z;
+            x += /*info:DOWN_CAST_IMPLICIT*/z;
+            y = /*info:DOWN_CAST_IMPLICIT*/y + z;
+            y += /*info:DOWN_CAST_IMPLICIT*/z;
 
             dynamic w = 42;
-            x += /*info:DynamicCast*/w;
-            y += /*info:DynamicCast*/w;
-            z += /*info:DynamicCast*/w;
+            x += /*info:DYNAMIC_CAST*/w;
+            y += /*info:DYNAMIC_CAST*/w;
+            z += /*info:DYNAMIC_CAST*/w;
 
             A a = new A();
             B b = new B();
             var c = foo();
             a = a * b;
             a *= b;
-            a *= /*info:DynamicCast*/c;
+            a *= /*info:DYNAMIC_CAST*/c;
             a /= b;
             a ~/= b;
             a %= b;
             a += b;
-            a += /*severe:StaticTypeError*/a;
+            a += /*severe:STATIC_TYPE_ERROR*/a;
             a -= b;
-            (/*severe:StaticTypeError*/b -= b);
+            (/*severe:STATIC_TYPE_ERROR*/b -= b);
             a <<= b;
             a >>= b;
             a &= b;
             a ^= b;
             a |= b;
-            (/*info:DynamicInvoke*/c += b);
+            (/*info:DYNAMIC_INVOKE*/c += b);
 
             var d = new D();
             a[b] += d;
-            a[/*info:DynamicCast*/c] += d;
-            a[/*severe:StaticTypeError*/z] += d;
-            a[b] += /*info:DynamicCast*/c;
-            a[b] += /*severe:StaticTypeError*/z;
-            (/*info:DynamicInvoke*/(/*info:DynamicInvoke*/c[b]) += d);
+            a[/*info:DYNAMIC_CAST*/c] += d;
+            a[/*severe:STATIC_TYPE_ERROR*/z] += d;
+            a[b] += /*info:DYNAMIC_CAST*/c;
+            a[b] += /*severe:STATIC_TYPE_ERROR*/z;
+            (/*info:DYNAMIC_INVOKE*/(/*info:DYNAMIC_INVOKE*/c[b]) += d);
           }
        '''
   });
@@ -1520,7 +1545,7 @@
             var y, z;
             Derived()
                 : y = print('Derived.1'),
-                  /*severe:InvalidSuperInvocation*/super(),
+                  /*severe:INVALID_SUPER_INVOCATION*/super(),
                   z = print('Derived.2') {
               print('Derived.3');
             }
@@ -1548,7 +1573,7 @@
     '/main.dart': '''
           foo() {
             for (int i = 0; i < 10; i++) {
-              i = /*severe:StaticTypeError*/"hi";
+              i = /*severe:STATIC_TYPE_ERROR*/"hi";
             }
           }
           bar() {
@@ -1570,35 +1595,35 @@
             }
 
             class T1 extends Base {
-              /*severe:InvalidFieldOverride,severe:InvalidMethodOverride*/B get f => null;
+              /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/B get f => null;
             }
 
             class T2 extends Base {
-              /*severe:InvalidFieldOverride,severe:InvalidMethodOverride*/set f(B b) => null;
+              /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/set f(B b) => null;
             }
 
             class T3 extends Base {
-              /*severe:InvalidFieldOverride,severe:InvalidMethodOverride*/final B f;
+              /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/final B f;
             }
             class T4 extends Base {
               // two: one for the getter one for the setter.
-              /*severe:InvalidFieldOverride,severe:InvalidMethodOverride,severe:InvalidMethodOverride*/B f;
+              /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/B f;
             }
 
             class T5 implements Base {
-              /*severe:InvalidMethodOverride*/B get f => null;
+              /*severe:INVALID_METHOD_OVERRIDE*/B get f => null;
             }
 
             class T6 implements Base {
-              /*severe:InvalidMethodOverride*/set f(B b) => null;
+              /*severe:INVALID_METHOD_OVERRIDE*/set f(B b) => null;
             }
 
             class T7 implements Base {
-              /*severe:InvalidMethodOverride*/final B f;
+              /*severe:INVALID_METHOD_OVERRIDE*/final B f;
             }
             class T8 implements Base {
               // two: one for the getter one for the setter.
-              /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/B f;
+              /*severe:INVALID_METHOD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/B f;
             }
          '''
     });
@@ -1613,7 +1638,7 @@
             }
 
             class Test extends Base {
-                /*severe:InvalidMethodOverride*/m(B a) {}
+                /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
             }
          '''
     });
@@ -1630,8 +1655,8 @@
             }
 
             class Test extends Parent {
-                /*severe:InvalidMethodOverride*/m(B a) {}
-                /*severe:InvalidFieldOverride*/int x;
+                /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
+                /*severe:INVALID_FIELD_OVERRIDE*/int x;
             }
          '''
     });
@@ -1650,7 +1675,7 @@
 
             class Test extends Parent {
                 // Reported only once
-                /*severe:InvalidMethodOverride*/m(B a) {}
+                /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
             }
          '''
     });
@@ -1664,7 +1689,7 @@
                 m(A a) {}
             }
             class Parent extends Grandparent {
-                /*severe:InvalidMethodOverride*/m(B a) {}
+                /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
             }
 
             class Test extends Parent {
@@ -1691,9 +1716,9 @@
                 int x;
             }
 
-            class T1 extends Base with /*severe:InvalidMethodOverride*/M1 {}
-            class T2 extends Base with /*severe:InvalidMethodOverride*/M1, /*severe:InvalidFieldOverride*/M2 {}
-            class T3 extends Base with /*severe:InvalidFieldOverride*/M2, /*severe:InvalidMethodOverride*/M1 {}
+            class T1 extends Base with /*severe:INVALID_METHOD_OVERRIDE*/M1 {}
+            class T2 extends Base with /*severe:INVALID_METHOD_OVERRIDE*/M1, /*severe:INVALID_FIELD_OVERRIDE*/M2 {}
+            class T3 extends Base with /*severe:INVALID_FIELD_OVERRIDE*/M2, /*severe:INVALID_METHOD_OVERRIDE*/M1 {}
          '''
     });
 
@@ -1715,7 +1740,7 @@
                 int x;
             }
 
-            class T1 extends Base with M1, /*severe:InvalidMethodOverride,severe:InvalidFieldOverride*/M2 {}
+            class T1 extends Base with M1, /*severe:INVALID_METHOD_OVERRIDE,severe:INVALID_FIELD_OVERRIDE*/M2 {}
          '''
     });
 
@@ -1744,7 +1769,7 @@
             }
 
             class T1 extends Base
-                with M1, /*severe:InvalidMethodOverride*/M2, M3 {}
+                with M1, /*severe:INVALID_METHOD_OVERRIDE*/M2, M3 {}
          '''
     });
 
@@ -1758,7 +1783,7 @@
             }
 
             class T1 implements I {
-                /*severe:InvalidMethodOverride*/m(B a) {}
+                /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
             }
          '''
     });
@@ -1777,7 +1802,7 @@
             }
 
 
-            class T1 /*severe:InvalidMethodOverride*/extends Base implements I {
+            class T1 /*severe:INVALID_METHOD_OVERRIDE*/extends Base implements I {
             }
          '''
     });
@@ -1795,7 +1820,7 @@
                 m(B a) {}
             }
 
-            class T1 extends Object with /*severe:InvalidMethodOverride*/M
+            class T1 extends Object with /*severe:INVALID_METHOD_OVERRIDE*/M
                implements I {}
          '''
     });
@@ -1816,18 +1841,18 @@
                 m(B a) {}
             }
 
-            class T1 /*severe:InvalidMethodOverride*/extends Base
+            class T1 /*severe:INVALID_METHOD_OVERRIDE*/extends Base
                 implements I1 {}
 
             class T2 extends Base implements I1 {
-                /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/m(a) {}
+                /*severe:INVALID_METHOD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/m(a) {}
             }
 
-            class T3 extends Object with /*severe:InvalidMethodOverride*/Base
+            class T3 extends Object with /*severe:INVALID_METHOD_OVERRIDE*/Base
                 implements I1 {}
 
             class T4 extends Object with Base implements I1 {
-                /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/m(a) {}
+                /*severe:INVALID_METHOD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/m(a) {}
             }
          '''
     });
@@ -1845,7 +1870,7 @@
               abstract class I2 implements I1 {}
 
               class T1 implements I2 {
-                  /*severe:InvalidMethodOverride*/m(B a) {}
+                  /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
               }
            '''
     });
@@ -1860,7 +1885,7 @@
               abstract class I2 extends I1 {}
 
               class T1 implements I2 {
-                  /*severe:InvalidMethodOverride*/m(B a) {}
+                  /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
               }
            '''
     });
@@ -1875,7 +1900,7 @@
               abstract class I2 extends Object with M1 {}
 
               class T1 implements I2 {
-                  /*severe:InvalidMethodOverride*/m(B a) {}
+                  /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
               }
            '''
     });
@@ -1890,7 +1915,7 @@
               abstract class Base implements I1 {}
 
               class T1 extends Base {
-                  /*severe:InvalidMethodOverride*/m(B a) {}
+                  /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
               }
            '''
     });
@@ -1932,7 +1957,7 @@
                   m(B a) {}
               }
 
-              class T1 extends Object with /*severe:InvalidMethodOverride*/M
+              class T1 extends Object with /*severe:INVALID_METHOD_OVERRIDE*/M
                   implements I2 {
               }
            '''
@@ -1951,7 +1976,7 @@
                   m(B a) {}
               }
 
-              class T1 extends Object with /*severe:InvalidMethodOverride*/M
+              class T1 extends Object with /*severe:INVALID_METHOD_OVERRIDE*/M
                   implements I2 {
               }
            '''
@@ -1970,7 +1995,7 @@
                   m(B a) {}
               }
 
-              class T1 extends Object with /*severe:InvalidMethodOverride*/M
+              class T1 extends Object with /*severe:INVALID_METHOD_OVERRIDE*/M
                   implements I2 {
               }
            '''
@@ -1989,7 +2014,7 @@
                   m(B a) {}
               }
 
-              class T1 extends Base with /*severe:InvalidMethodOverride*/M {
+              class T1 extends Base with /*severe:INVALID_METHOD_OVERRIDE*/M {
               }
            '''
     });
@@ -2031,7 +2056,7 @@
                   m(B a) {}
               }
 
-              class T1 /*severe:InvalidMethodOverride*/extends Base
+              class T1 /*severe:INVALID_METHOD_OVERRIDE*/extends Base
                   implements I2 {
               }
            '''
@@ -2050,7 +2075,7 @@
                   m(B a) {}
               }
 
-              class T1 /*severe:InvalidMethodOverride*/extends Base
+              class T1 /*severe:INVALID_METHOD_OVERRIDE*/extends Base
                   implements I2 {
               }
            '''
@@ -2069,7 +2094,7 @@
                   m(B a) {}
               }
 
-              class T1 /*severe:InvalidMethodOverride*/extends Base
+              class T1 /*severe:INVALID_METHOD_OVERRIDE*/extends Base
                   implements I2 {
               }
            '''
@@ -2084,7 +2109,7 @@
               }
 
               abstract class Base implements I1 {
-                  /*severe:InvalidMethodOverride*/m(B a) {}
+                  /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
               }
 
               class T1 extends Base {
@@ -2093,7 +2118,7 @@
                   // TODO(sigmund): consider tracking overrides in a fine-grain
                   // manner, then this and the double-overrides would not be
                   // reported.
-                  /*severe:InvalidMethodOverride*/m(B a) {}
+                  /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
               }
            '''
     });
@@ -2107,7 +2132,7 @@
               }
 
               class Base implements I1 {
-                  /*severe:InvalidMethodOverride*/m(B a) {}
+                  /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
               }
 
               class T1 extends Base {
@@ -2134,7 +2159,7 @@
               }
 
               class T1 implements I2 {
-                /*severe:InvalidMethodOverride*/m(B a) {}
+                /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
               }
            '''
     });
@@ -2155,12 +2180,12 @@
               // Note: no error reported in `extends Base` to avoid duplicating
               // the error in T1.
               class T1 extends Base implements I1 {
-                /*severe:InvalidMethodOverride*/m(B a) {}
+                /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
               }
 
               // If there is no error in the class, we do report the error at
               // the base class:
-              class T2 /*severe:InvalidMethodOverride*/extends Base
+              class T2 /*severe:INVALID_METHOD_OVERRIDE*/extends Base
                   implements I1 {
               }
            '''
@@ -2180,10 +2205,10 @@
               }
 
               class T1 extends Object with M implements I1 {
-                /*severe:InvalidMethodOverride*/m(B a) {}
+                /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
               }
 
-              class T2 extends Object with /*severe:InvalidMethodOverride*/M
+              class T2 extends Object with /*severe:INVALID_METHOD_OVERRIDE*/M
                   implements I1 {
               }
            '''
@@ -2209,10 +2234,10 @@
               }
 
               // Note: otherwise both errors would be reported on this line
-              class T1 /*severe:InvalidMethodOverride*/extends Parent1
+              class T1 /*severe:INVALID_METHOD_OVERRIDE*/extends Parent1
                   implements I1 {
               }
-              class T2 /*severe:InvalidMethodOverride*/extends Parent2
+              class T2 /*severe:INVALID_METHOD_OVERRIDE*/extends Parent2
                   implements I1 {
               }
            '''
@@ -2239,8 +2264,8 @@
               // different.
               // TODO(sigmund): should we merge these as well?
               class T1 extends Object
-                  with /*severe:InvalidMethodOverride*/M1
-                  with /*severe:InvalidMethodOverride*/M2
+                  with /*severe:INVALID_METHOD_OVERRIDE*/M1
+                  with /*severe:INVALID_METHOD_OVERRIDE*/M2
                   implements I1 {
               }
            '''
@@ -2266,8 +2291,8 @@
               // Here we want to report both, because the error location is
               // different.
               // TODO(sigmund): should we merge these as well?
-              class T1 /*severe:InvalidMethodOverride*/extends Base
-                  with /*severe:InvalidMethodOverride*/M
+              class T1 /*severe:INVALID_METHOD_OVERRIDE*/extends Base
+                  with /*severe:INVALID_METHOD_OVERRIDE*/M
                   implements I1 {
               }
            '''
@@ -2295,18 +2320,18 @@
 
           void main() {
             bool b;
-            b = /*info:NonGroundTypeCheckInfo*/foo is I2I;
-            b = /*info:NonGroundTypeCheckInfo*/foo is D2I;
-            b = /*info:NonGroundTypeCheckInfo*/foo is I2D;
+            b = /*info:NON_GROUND_TYPE_CHECK_INFO*/foo is I2I;
+            b = /*info:NON_GROUND_TYPE_CHECK_INFO*/foo is D2I;
+            b = /*info:NON_GROUND_TYPE_CHECK_INFO*/foo is I2D;
             b = foo is D2D;
 
-            b = /*info:NonGroundTypeCheckInfo*/bar is II2I;
-            b = /*info:NonGroundTypeCheckInfo*/bar is DI2I;
-            b = /*info:NonGroundTypeCheckInfo*/bar is ID2I;
-            b = /*info:NonGroundTypeCheckInfo*/bar is II2D;
-            b = /*info:NonGroundTypeCheckInfo*/bar is DD2I;
-            b = /*info:NonGroundTypeCheckInfo*/bar is DI2D;
-            b = /*info:NonGroundTypeCheckInfo*/bar is ID2D;
+            b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is II2I;
+            b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is DI2I;
+            b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is ID2I;
+            b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is II2D;
+            b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is DD2I;
+            b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is DI2D;
+            b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is ID2D;
             b = bar is DD2D;
 
             // For as, the validity of checks is deferred to runtime.
@@ -2338,22 +2363,24 @@
 
         foo1() async => x;
         Future foo2() async => x;
-        Future<int> foo3() async => (/*info:DynamicCast*/x);
-        Future<int> foo4() async => (/*severe:StaticTypeError*/new Future<int>.value(/*info:DynamicCast*/x));
+        Future<int> foo3() async => (/*info:DYNAMIC_CAST*/x);
+        Future<int> foo4() async => (new Future<int>.value(/*info:DYNAMIC_CAST*/x));
+        Future<int> foo5() async => (/*severe:STATIC_TYPE_ERROR*/new Future<String>.value(/*info:DYNAMIC_CAST*/x));
 
         bar1() async { return x; }
         Future bar2() async { return x; }
-        Future<int> bar3() async { return (/*info:DynamicCast*/x); }
-        Future<int> bar4() async { return (/*severe:StaticTypeError*/new Future<int>.value(/*info:DynamicCast*/x)); }
+        Future<int> bar3() async { return (/*info:DYNAMIC_CAST*/x); }
+        Future<int> bar4() async { return (new Future<int>.value(/*info:DYNAMIC_CAST*/x)); }
+        Future<int> bar5() async { return (/*severe:STATIC_TYPE_ERROR*/new Future<String>.value(/*info:DYNAMIC_CAST*/x)); }
 
         int y;
         Future<int> z;
 
         void baz() async {
-          int a = /*info:DynamicCast*/await x;
+          int a = /*info:DYNAMIC_CAST*/await x;
           int b = await y;
           int c = await z;
-          String d = /*severe:StaticTypeError*/await z;
+          String d = /*severe:STATIC_TYPE_ERROR*/await z;
         }
 
         Future<bool> get issue_264 async {
@@ -2361,7 +2388,7 @@
           if (new Random().nextBool()) {
             return true;
           } else {
-            return /*severe:StaticTypeError*/new Future<bool>.value(false);
+            return new Future<bool>.value(false);
           }
         }
     '''
@@ -2375,14 +2402,14 @@
 
         bar1() async* { yield x; }
         Stream bar2() async* { yield x; }
-        Stream<int> bar3() async* { yield (/*info:DynamicCast*/x); }
-        Stream<int> bar4() async* { yield (/*severe:StaticTypeError*/new Stream<int>()); }
+        Stream<int> bar3() async* { yield (/*info:DYNAMIC_CAST*/x); }
+        Stream<int> bar4() async* { yield (/*severe:STATIC_TYPE_ERROR*/new Stream<int>()); }
 
-        baz1() async* { yield* (/*info:DynamicCast*/x); }
-        Stream baz2() async* { yield* (/*info:DynamicCast*/x); }
-        Stream<int> baz3() async* { yield* (/*warning:DownCastComposite*/x); }
+        baz1() async* { yield* (/*info:DYNAMIC_CAST*/x); }
+        Stream baz2() async* { yield* (/*info:DYNAMIC_CAST*/x); }
+        Stream<int> baz3() async* { yield* (/*warning:DOWN_CAST_COMPOSITE*/x); }
         Stream<int> baz4() async* { yield* new Stream<int>(); }
-        Stream<int> baz5() async* { yield* (/*info:InferredTypeAllocation*/new Stream()); }
+        Stream<int> baz5() async* { yield* (/*info:INFERRED_TYPE_ALLOCATION*/new Stream()); }
     '''
     });
 
@@ -2394,14 +2421,14 @@
 
         bar1() sync* { yield x; }
         Iterable bar2() sync* { yield x; }
-        Iterable<int> bar3() sync* { yield (/*info:DynamicCast*/x); }
-        Iterable<int> bar4() sync* { yield (/*severe:StaticTypeError*/new Iterable<int>()); }
+        Iterable<int> bar3() sync* { yield (/*info:DYNAMIC_CAST*/x); }
+        Iterable<int> bar4() sync* { yield (/*severe:STATIC_TYPE_ERROR*/new Iterable<int>()); }
 
-        baz1() sync* { yield* (/*info:DynamicCast*/x); }
-        Iterable baz2() sync* { yield* (/*info:DynamicCast*/x); }
-        Iterable<int> baz3() sync* { yield* (/*warning:DownCastComposite*/x); }
+        baz1() sync* { yield* (/*info:DYNAMIC_CAST*/x); }
+        Iterable baz2() sync* { yield* (/*info:DYNAMIC_CAST*/x); }
+        Iterable<int> baz3() sync* { yield* (/*warning:DOWN_CAST_COMPOSITE*/x); }
         Iterable<int> baz4() sync* { yield* new Iterable<int>(); }
-        Iterable<int> baz5() sync* { yield* (/*info:InferredTypeAllocation*/new Iterable()); }
+        Iterable<int> baz5() sync* { yield* (/*info:INFERRED_TYPE_ALLOCATION*/new Iterable()); }
     '''
     });
   });
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 2a051be..8fe4b37 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -17,7 +17,7 @@
     '/main.dart': '''
       test1() {
         int x = 3;
-        x = /*severe:StaticTypeError*/"hi";
+        x = /*severe:STATIC_TYPE_ERROR*/"hi";
       }
     '''
   });
@@ -27,7 +27,7 @@
     '/main.dart': '''
       test2() {
         var x = 3;
-        x = /*severe:StaticTypeError*/"hi";
+        x = /*severe:STATIC_TYPE_ERROR*/"hi";
       }
     '''
   });
@@ -67,13 +67,13 @@
 
         test1() {
           var a = x;
-          a = /*severe:StaticTypeError*/"hi";
+          a = /*severe:STATIC_TYPE_ERROR*/"hi";
           a = 3;
           var b = y;
-          b = /*severe:StaticTypeError*/"hi";
+          b = /*severe:STATIC_TYPE_ERROR*/"hi";
           b = 4;
           var c = z;
-          c = /*severe:StaticTypeError*/"hi";
+          c = /*severe:STATIC_TYPE_ERROR*/"hi";
           c = 4;
         }
 
@@ -89,13 +89,13 @@
 
       test1() {
         var a = x;
-        a = /*severe:StaticTypeError*/"hi";
+        a = /*severe:STATIC_TYPE_ERROR*/"hi";
         a = 3;
         var b = y;
-        b = /*severe:StaticTypeError*/"hi";
+        b = /*severe:STATIC_TYPE_ERROR*/"hi";
         b = 4;
         var c = z;
-        c = /*severe:StaticTypeError*/"hi";
+        c = /*severe:STATIC_TYPE_ERROR*/"hi";
         c = 4;
       }
 
@@ -118,11 +118,11 @@
 
       test() {
         x = "hi";
-        y = /*severe:StaticTypeError*/"hi";
+        y = /*severe:STATIC_TYPE_ERROR*/"hi";
         A.x = "hi";
-        A.y = /*severe:StaticTypeError*/"hi";
+        A.y = /*severe:STATIC_TYPE_ERROR*/"hi";
         new A().x2 = "hi";
-        new A().y2 = /*severe:StaticTypeError*/"hi";
+        new A().y2 = /*severe:STATIC_TYPE_ERROR*/"hi";
       }
     '''
   });
@@ -136,8 +136,8 @@
           var y = x;
 
           test1() {
-            x = /*severe:StaticTypeError*/"hi";
-            y = /*severe:StaticTypeError*/"hi";
+            x = /*severe:STATIC_TYPE_ERROR*/"hi";
+            y = /*severe:STATIC_TYPE_ERROR*/"hi";
           }
     '''
   });
@@ -151,8 +151,8 @@
           class B { static var y = A.x; }
 
           test1() {
-            A.x = /*severe:StaticTypeError*/"hi";
-            B.y = /*severe:StaticTypeError*/"hi";
+            A.x = /*severe:STATIC_TYPE_ERROR*/"hi";
+            B.y = /*severe:STATIC_TYPE_ERROR*/"hi";
           }
     '''
   });
@@ -286,7 +286,7 @@
             x = D.d2;
             x = new C().c2;
             x = new D().d3;
-            x = /*info:DynamicCast*/new D().d4;
+            x = /*info:DYNAMIC_CAST*/new D().d4;
 
 
             // Similarly if the library contains parts.
@@ -294,7 +294,7 @@
             x = E.e2;
             x = E.e3;
             x = new E().e4;
-            x = /*info:DynamicCast*/new E().e5;
+            x = /*info:DYNAMIC_CAST*/new E().e5;
             x = new E().e6;
             x = F.f1;
             x = new F().f2;
@@ -323,28 +323,28 @@
         var j = null as B;
 
         test1() {
-          a = /*severe:StaticTypeError*/"hi";
+          a = /*severe:STATIC_TYPE_ERROR*/"hi";
           a = new B(3);
-          b = /*severe:StaticTypeError*/"hi";
+          b = /*severe:STATIC_TYPE_ERROR*/"hi";
           b = new B(3);
           c1 = [];
-          c1 = /*severe:StaticTypeError*/{};
+          c1 = /*severe:STATIC_TYPE_ERROR*/{};
           c2 = [];
-          c2 = /*severe:StaticTypeError*/{};
+          c2 = /*severe:STATIC_TYPE_ERROR*/{};
           d = {};
-          d = /*severe:StaticTypeError*/3;
+          d = /*severe:STATIC_TYPE_ERROR*/3;
           e = new A();
-          e = /*severe:StaticTypeError*/{};
+          e = /*severe:STATIC_TYPE_ERROR*/{};
           f = 3;
-          f = /*severe:StaticTypeError*/false;
+          f = /*severe:STATIC_TYPE_ERROR*/false;
           g = 1;
-          g = /*severe:StaticTypeError*/false;
-          h = /*severe:StaticTypeError*/false;
+          g = /*severe:STATIC_TYPE_ERROR*/false;
+          h = /*severe:STATIC_TYPE_ERROR*/false;
           h = new B();
           i = false;
           j = new B();
-          j = /*severe:StaticTypeError*/false;
-          j = /*severe:StaticTypeError*/[];
+          j = /*severe:STATIC_TYPE_ERROR*/false;
+          j = /*severe:STATIC_TYPE_ERROR*/[];
         }
     '''
   });
@@ -373,7 +373,7 @@
           a = t1;
           i = t2;
           b = t3;
-          i = /*info:DynamicCast*/t4;
+          i = /*info:DYNAMIC_CAST*/t4;
           i = new B().y; // B.y was inferred though
         }
     '''
@@ -389,7 +389,7 @@
       class Bar<T extends Iterable<String>> {
         void foo(T t) {
           for (var i in t) {
-            int x = /*severe:StaticTypeError*/i;
+            int x = /*severe:STATIC_TYPE_ERROR*/i;
           }
         }
       }
@@ -397,7 +397,7 @@
       class Baz<T, E extends Iterable<T>, S extends E> {
         void foo(S t) {
           for (var i in t) {
-            int x = /*severe:StaticTypeError*/i;
+            int x = /*severe:STATIC_TYPE_ERROR*/i;
             T y = i;
           }
         }
@@ -406,36 +406,36 @@
       test() {
         var list = <Foo>[];
         for (var x in list) {
-          String y = /*severe:StaticTypeError*/x;
+          String y = /*severe:STATIC_TYPE_ERROR*/x;
         }
 
         for (dynamic x in list) {
-          String y = /*info:DynamicCast*/x;
+          String y = /*info:DYNAMIC_CAST*/x;
         }
 
-        for (String x in /*severe:StaticTypeError*/list) {
+        for (String x in /*severe:STATIC_TYPE_ERROR*/list) {
           String y = x;
         }
 
         var z;
         for(z in list) {
-          String y = /*info:DynamicCast*/z;
+          String y = /*info:DYNAMIC_CAST*/z;
         }
 
         Iterable iter = list;
-        for (Foo x in /*warning:DownCastComposite*/iter) {
+        for (Foo x in /*warning:DOWN_CAST_COMPOSITE*/iter) {
           var y = x;
         }
 
         dynamic iter2 = list;
-        for (Foo x in /*warning:DownCastComposite*/iter2) {
+        for (Foo x in /*warning:DOWN_CAST_COMPOSITE*/iter2) {
           var y = x;
         }
 
         var map = <String, Foo>{};
         // Error: map must be an Iterable.
-        for (var x in /*severe:StaticTypeError*/map) {
-          String y = /*info:DynamicCast*/x;
+        for (var x in /*severe:STATIC_TYPE_ERROR*/map) {
+          String y = /*info:DYNAMIC_CAST*/x;
         }
 
         // We're not properly inferring that map.keys is an Iterable<String>
@@ -481,9 +481,9 @@
 
       test() {
         dynamic a = new A();
-        A b = /*info:DynamicCast*/a;
-        print(/*info:DynamicInvoke*/a.x);
-        print(/*info:DynamicInvoke*/(/*info:DynamicInvoke*/a.x) + 2);
+        A b = /*info:DYNAMIC_CAST*/a;
+        print(/*info:DYNAMIC_INVOKE*/a.x);
+        print(/*info:DYNAMIC_INVOKE*/(/*info:DYNAMIC_INVOKE*/a.x) + 2);
       }
     '''
   });
@@ -496,10 +496,10 @@
 
       test5() {
         var a1 = new A();
-        a1.x = /*severe:StaticTypeError*/"hi";
+        a1.x = /*severe:STATIC_TYPE_ERROR*/"hi";
 
         A a2 = new A();
-        a2.x = /*severe:StaticTypeError*/"hi";
+        a2.x = /*severe:STATIC_TYPE_ERROR*/"hi";
       }
     '''
   });
@@ -540,11 +540,11 @@
         }
 
         class B extends A {
-          /*severe:InvalidFieldOverride*/get x => 3;
+          /*severe:INVALID_FIELD_OVERRIDE*/get x => 3;
         }
 
         foo() {
-          String y = /*severe:StaticTypeError*/new B().x;
+          String y = /*severe:STATIC_TYPE_ERROR*/new B().x;
           int z = new B().x;
         }
     '''
@@ -561,7 +561,7 @@
         }
 
         foo() {
-          String y = /*severe:StaticTypeError*/new B().x;
+          String y = /*severe:STATIC_TYPE_ERROR*/new B().x;
           int z = new B().x;
         }
     '''
@@ -576,12 +576,12 @@
         }
 
         class B implements A<int> {
-          /*severe:InvalidMethodOverride*/dynamic get x => 3;
+          /*severe:INVALID_METHOD_OVERRIDE*/dynamic get x => 3;
         }
 
         foo() {
-          String y = /*info:DynamicCast*/new B().x;
-          int z = /*info:DynamicCast*/new B().x;
+          String y = /*info:DYNAMIC_CAST*/new B().x;
+          int z = /*info:DYNAMIC_CAST*/new B().x;
         }
     '''
     });
@@ -595,11 +595,11 @@
 
         class B implements A<int> {
           get x => 3;
-          get w => /*severe:StaticTypeError*/"hello";
+          get w => /*severe:STATIC_TYPE_ERROR*/"hello";
         }
 
         foo() {
-          String y = /*severe:StaticTypeError*/new B().x;
+          String y = /*severe:STATIC_TYPE_ERROR*/new B().x;
           int z = new B().x;
         }
     '''
@@ -613,11 +613,11 @@
 
         class B<E> extends A<E> {
           E y;
-          /*severe:InvalidFieldOverride*/get x => y;
+          /*severe:INVALID_FIELD_OVERRIDE*/get x => y;
         }
 
         foo() {
-          int y = /*severe:StaticTypeError*/new B<String>().x;
+          int y = /*severe:STATIC_TYPE_ERROR*/new B<String>().x;
           String z = new B<String>().x;
         }
     '''
@@ -646,7 +646,7 @@
         }
 
         foo () {
-          int y = /*severe:StaticTypeError*/new B().m(null, null);
+          int y = /*severe:STATIC_TYPE_ERROR*/new B().m(null, null);
           String z = new B().m(null, null);
         }
     '''
@@ -669,7 +669,7 @@
         }
         foo () {
           int y = new C().x;
-          String y = /*severe:StaticTypeError*/new C().x;
+          String y = /*severe:STATIC_TYPE_ERROR*/new C().x;
         }
     '''
   });
@@ -705,7 +705,7 @@
         }
 
         foo () {
-          int y = /*severe:StaticTypeError*/new B<String>().m(null, null).value;
+          int y = /*severe:STATIC_TYPE_ERROR*/new B<String>().m(null, null).value;
           String z = new B<String>().m(null, null).value;
         }
     '''
@@ -719,12 +719,12 @@
           }
 
           class B implements A {
-            /*severe:InvalidMethodOverride*/dynamic get x => 3;
+            /*severe:INVALID_METHOD_OVERRIDE*/dynamic get x => 3;
           }
 
           foo() {
-            String y = /*info:DynamicCast*/new B().x;
-            int z = /*info:DynamicCast*/new B().x;
+            String y = /*info:DYNAMIC_CAST*/new B().x;
+            int z = /*info:DYNAMIC_CAST*/new B().x;
           }
       '''
     });
@@ -748,12 +748,12 @@
         }
 
         class C1 implements A, B {
-          /*severe:InvalidMethodOverride*/get a => null;
+          /*severe:INVALID_METHOD_OVERRIDE*/get a => null;
         }
 
         // Still ambiguous
         class C2 implements B, A {
-          /*severe:InvalidMethodOverride*/get a => null;
+          /*severe:INVALID_METHOD_OVERRIDE*/get a => null;
         }
     '''
   });
@@ -785,7 +785,7 @@
         }
 
         class C2 implements A, B {
-          /*severe:InvalidMethodOverride*/get a => null;
+          /*severe:INVALID_METHOD_OVERRIDE*/get a => null;
         }
     '''
   });
@@ -802,8 +802,8 @@
         }
 
         foo() {
-          String y = /*info:DynamicCast*/new B().x;
-          int z = /*info:DynamicCast*/new B().x;
+          String y = /*info:DYNAMIC_CAST*/new B().x;
+          int z = /*info:DYNAMIC_CAST*/new B().x;
         }
     '''
   });
@@ -820,7 +820,7 @@
         }
 
         foo() {
-          String y = /*severe:StaticTypeError*/new B().x;
+          String y = /*severe:STATIC_TYPE_ERROR*/new B().x;
           int z = new B().x;
         }
     '''
@@ -840,14 +840,14 @@
           String s;
           int i;
 
-          s = /*info:DynamicCast*/new B().x;
-          s = /*severe:StaticTypeError*/new B().y;
+          s = /*info:DYNAMIC_CAST*/new B().x;
+          s = /*severe:STATIC_TYPE_ERROR*/new B().y;
           s = new B().z;
-          s = /*severe:StaticTypeError*/new B().w;
+          s = /*severe:STATIC_TYPE_ERROR*/new B().w;
 
-          i = /*info:DynamicCast*/new B().x;
+          i = /*info:DYNAMIC_CAST*/new B().x;
           i = new B().y;
-          i = /*severe:StaticTypeError*/new B().z;
+          i = /*severe:STATIC_TYPE_ERROR*/new B().z;
           i = new B().w;
         }
     '''
@@ -960,9 +960,9 @@
 
   testChecker('downwards inference: miscellaneous', {
     '/main.dart': '''
-      typedef (T x);
+      typedef T Function2<S, T>(S x);
       class A<T> {
-        Function2<T> x;
+        Function2<T, T> x;
         A(this.x);
       }
       void main() {
@@ -970,18 +970,18 @@
             var x = "hello";
             var y = 3;
             void f(List<Map<int, String>> l) {};
-            f(/*info:InferredTypeLiteral*/[{y: x}]);
+            f(/*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/{y: x}]);
           }
           {
             int f(int x) {};
-            A<int> a = /*info:InferredTypeAllocation*/new A(f);
+            A<int> a = /*info:INFERRED_TYPE_ALLOCATION*/new A(f);
           }
       }
       '''
   });
 
   group('downwards inference on instance creations', () {
-    String info = 'info:InferredTypeAllocation';
+    String info = 'info:INFERRED_TYPE_ALLOCATION';
     String code = '''
       class A<S, T> {
         S x;
@@ -1020,59 +1020,59 @@
           A<int, String> a1 = /*$info*/new A.named(3, "hello");
           A<int, String> a2 = new A<int, String>(3, "hello");
           A<int, String> a3 = new A<int, String>.named(3, "hello");
-          A<int, String> a4 = /*severe:StaticTypeError*/new A<int, dynamic>(3, "hello");
-          A<int, String> a5 = /*severe:StaticTypeError*/new A<dynamic, dynamic>.named(3, "hello");
+          A<int, String> a4 = /*severe:STATIC_TYPE_ERROR*/new A<int, dynamic>(3, "hello");
+          A<int, String> a5 = /*severe:STATIC_TYPE_ERROR*/new A<dynamic, dynamic>.named(3, "hello");
         }
         {
-          A<int, String> a0 = /*severe:StaticTypeError*/new A("hello", 3);
-          A<int, String> a1 = /*severe:StaticTypeError*/new A.named("hello", 3);
+          A<int, String> a0 = /*info:INFERRED_TYPE_ALLOCATION*/new A(/*severe:STATIC_TYPE_ERROR*/"hello", /*severe:STATIC_TYPE_ERROR*/3);
+          A<int, String> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new A.named(/*severe:STATIC_TYPE_ERROR*/"hello", /*severe:STATIC_TYPE_ERROR*/3);
         }
         {
           A<int, String> a0 = /*$info*/new B("hello", 3);
           A<int, String> a1 = /*$info*/new B.named("hello", 3);
           A<int, String> a2 = new B<String, int>("hello", 3);
           A<int, String> a3 = new B<String, int>.named("hello", 3);
-          A<int, String> a4 = /*severe:StaticTypeError*/new B<String, dynamic>("hello", 3);
-          A<int, String> a5 = /*severe:StaticTypeError*/new B<dynamic, dynamic>.named("hello", 3);
+          A<int, String> a4 = /*severe:STATIC_TYPE_ERROR*/new B<String, dynamic>("hello", 3);
+          A<int, String> a5 = /*severe:STATIC_TYPE_ERROR*/new B<dynamic, dynamic>.named("hello", 3);
         }
         {
-          A<int, String> a0 = /*severe:StaticTypeError*/new B(3, "hello");
-          A<int, String> a1 = /*severe:StaticTypeError*/new B.named(3, "hello");
+          A<int, String> a0 = /*info:INFERRED_TYPE_ALLOCATION*/new B(/*severe:STATIC_TYPE_ERROR*/3, /*severe:STATIC_TYPE_ERROR*/"hello");
+          A<int, String> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new B.named(/*severe:STATIC_TYPE_ERROR*/3, /*severe:STATIC_TYPE_ERROR*/"hello");
         }
         {
           A<int, int> a0 = /*$info*/new C(3);
           A<int, int> a1 = /*$info*/new C.named(3);
           A<int, int> a2 = new C<int>(3);
           A<int, int> a3 = new C<int>.named(3);
-          A<int, int> a4 = /*severe:StaticTypeError*/new C<dynamic>(3);
-          A<int, int> a5 = /*severe:StaticTypeError*/new C<dynamic>.named(3);
+          A<int, int> a4 = /*severe:STATIC_TYPE_ERROR*/new C<dynamic>(3);
+          A<int, int> a5 = /*severe:STATIC_TYPE_ERROR*/new C<dynamic>.named(3);
         }
         {
-          A<int, int> a0 = /*severe:StaticTypeError*/new C("hello");
-          A<int, int> a1 = /*severe:StaticTypeError*/new C.named("hello");
+          A<int, int> a0 = /*info:INFERRED_TYPE_ALLOCATION*/new C(/*severe:STATIC_TYPE_ERROR*/"hello");
+          A<int, int> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new C.named(/*severe:STATIC_TYPE_ERROR*/"hello");
         }
         {
           A<int, String> a0 = /*$info*/new D("hello");
           A<int, String> a1 = /*$info*/new D.named("hello");
           A<int, String> a2 = new D<int, String>("hello");
           A<int, String> a3 = new D<String, String>.named("hello");
-          A<int, String> a4 = /*severe:StaticTypeError*/new D<num, dynamic>("hello");
-          A<int, String> a5 = /*severe:StaticTypeError*/new D<dynamic, dynamic>.named("hello");
+          A<int, String> a4 = /*severe:STATIC_TYPE_ERROR*/new D<num, dynamic>("hello");
+          A<int, String> a5 = /*severe:STATIC_TYPE_ERROR*/new D<dynamic, dynamic>.named("hello");
         }
         {
-          A<int, String> a0 = /*severe:StaticTypeError*/new D(3);
-          A<int, String> a1 = /*severe:StaticTypeError*/new D.named(3);
+          A<int, String> a0 = /*info:INFERRED_TYPE_ALLOCATION*/new D(/*severe:STATIC_TYPE_ERROR*/3);
+          A<int, String> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new D.named(/*severe:STATIC_TYPE_ERROR*/3);
         }
         { // Currently we only allow variable constraints.  Test that we reject.
-          A<C<int>, String> a0 = /*severe:StaticTypeError*/new E("hello");
+          A<C<int>, String> a0 = /*severe:STATIC_TYPE_ERROR*/new E("hello");
         }
         { // Check named and optional arguments
-          A<int, String> a0 = /*$info*/new F(3, "hello", a: [3], b: ["hello"]);
-          A<int, String> a1 = /*severe:StaticTypeError*/new F(3, "hello", a: ["hello"], b:[3]);
+          A<int, String> a0 = /*$info*/new F(3, "hello", a: /*info:INFERRED_TYPE_LITERAL*/[3], b: /*info:INFERRED_TYPE_LITERAL*/["hello"]);
+          A<int, String> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new F(3, "hello", a: /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"], b: /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/3]);
           A<int, String> a2 = /*$info*/new F.named(3, "hello", 3, "hello");
           A<int, String> a3 = /*$info*/new F.named(3, "hello");
-          A<int, String> a4 = /*severe:StaticTypeError*/new F.named(3, "hello", "hello", 3);
-          A<int, String> a5 = /*severe:StaticTypeError*/new F.named(3, "hello", "hello");
+          A<int, String> a4 = /*info:INFERRED_TYPE_ALLOCATION*/new F.named(3, "hello", /*severe:STATIC_TYPE_ERROR*/"hello", /*severe:STATIC_TYPE_ERROR*/3);
+          A<int, String> a5 = /*info:INFERRED_TYPE_ALLOCATION*/new F.named(3, "hello", /*severe:STATIC_TYPE_ERROR*/"hello");
         }
       }
         ''';
@@ -1080,18 +1080,18 @@
   });
 
   group('downwards inference on list literals', () {
-    String info = "info:InferredTypeLiteral";
+    String info = "info:INFERRED_TYPE_LITERAL";
     String code = '''
       void foo([List<String> list1 = /*$info*/const [],
-                List<String> list2 = /*severe:StaticTypeError*/const [42]]) {
+                List<String> list2 = /*info:INFERRED_TYPE_LITERAL*/const [/*severe:STATIC_TYPE_ERROR*/42]]) {
       }
 
       void main() {
         {
           List<int> l0 = /*$info*/[];
           List<int> l1 = /*$info*/[3];
-          List<int> l2 = /*severe:StaticTypeError*/["hello"];
-          List<int> l3 = /*severe:StaticTypeError*/["hello", 3];
+          List<int> l2 = /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"];
+          List<int> l3 = /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3];
         }
         {
           List<dynamic> l0 = [];
@@ -1100,22 +1100,22 @@
           List<dynamic> l3 = ["hello", 3];
         }
         {
-          List<int> l0 = /*severe:StaticTypeError*/<num>[];
-          List<int> l1 = /*severe:StaticTypeError*/<num>[3];
-          List<int> l2 = /*severe:StaticTypeError*/<num>[/*severe:StaticTypeError*/"hello"];
-          List<int> l3 = /*severe:StaticTypeError*/<num>[/*severe:StaticTypeError*/"hello", 3];
+          List<int> l0 = /*severe:STATIC_TYPE_ERROR*/<num>[];
+          List<int> l1 = /*severe:STATIC_TYPE_ERROR*/<num>[3];
+          List<int> l2 = /*severe:STATIC_TYPE_ERROR*/<num>[/*severe:STATIC_TYPE_ERROR*/"hello"];
+          List<int> l3 = /*severe:STATIC_TYPE_ERROR*/<num>[/*severe:STATIC_TYPE_ERROR*/"hello", 3];
         }
         {
           Iterable<int> i0 = /*$info*/[];
           Iterable<int> i1 = /*$info*/[3];
-          Iterable<int> i2 = /*severe:StaticTypeError*/["hello"];
-          Iterable<int> i3 = /*severe:StaticTypeError*/["hello", 3];
+          Iterable<int> i2 = /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"];
+          Iterable<int> i3 = /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3];
         }
         {
           const List<int> c0 = /*$info*/const [];
           const List<int> c1 = /*$info*/const [3];
-          const List<int> c2 = /*severe:StaticTypeError*/const ["hello"];
-          const List<int> c3 = /*severe:StaticTypeError*/const ["hello", 3];
+          const List<int> c2 = /*info:INFERRED_TYPE_LITERAL*/const [/*severe:STATIC_TYPE_ERROR*/"hello"];
+          const List<int> c3 = /*info:INFERRED_TYPE_LITERAL*/const [/*severe:STATIC_TYPE_ERROR*/"hello", 3];
         }
       }
       ''';
@@ -1123,7 +1123,7 @@
   });
 
   group('downwards inference on function arguments', () {
-    String info = "info:InferredTypeLiteral";
+    String info = "info:INFERRED_TYPE_LITERAL";
     String code = '''
       void f0(List<int> a) {};
       void f1({List<int> a}) {};
@@ -1133,46 +1133,158 @@
       void main() {
         f0(/*$info*/[]);
         f0(/*$info*/[3]);
-        f0(/*severe:StaticTypeError*/["hello"]);
-        f0(/*severe:StaticTypeError*/["hello", 3]);
+        f0(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+        f0(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
 
         f1(a: /*$info*/[]);
         f1(a: /*$info*/[3]);
-        f1(a: /*severe:StaticTypeError*/["hello"]);
-        f1(a: /*severe:StaticTypeError*/["hello", 3]);
+        f1(a: /*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+        f1(a: /*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
 
         f2(/*$info*/[]);
         f2(/*$info*/[3]);
-        f2(/*severe:StaticTypeError*/["hello"]);
-        f2(/*severe:StaticTypeError*/["hello", 3]);
+        f2(/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+        f2(/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
 
         f3(/*$info*/[]);
-        f3(/*$info*/[[3]]);
-        f3(/*severe:StaticTypeError*/[["hello"]]);
-        f3(/*severe:StaticTypeError*/[["hello"], [3]]);
+        f3(/*$info*/[/*$info*/[3]]);
+        f3(/*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
+        f3(/*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"], /*$info*/[3]]);
 
         f4(a: /*$info*/[]);
-        f4(a: /*$info*/[[3]]);
-        f4(a: /*severe:StaticTypeError*/[["hello"]]);
-        f4(a: /*severe:StaticTypeError*/[["hello"], [3]]);
+        f4(a: /*$info*/[/*$info*/[3]]);
+        f4(a: /*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
+        f4(a: /*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"], /*$info*/[3]]);
+      }
+      ''';
+    testChecker('infer downwards', {'/main.dart': code});
+  });
+
+  group('downwards inference on constructor arguments', () {
+    String info = "info:INFERRED_TYPE_LITERAL";
+    String code = '''
+      class F0 {
+        F0(List<int> a) {};
+      }
+      class F1 {
+        F1({List<int> a}) {};
+      }
+      class F2 {
+        F2(Iterable<int> a) {};
+      }
+      class F3 {
+        F3(Iterable<Iterable<int>> a) {};
+      }
+      class F4 {
+        F4({Iterable<Iterable<int>> a}) {};
+      }
+      void main() {
+        new F0(/*$info*/[]);
+        new F0(/*$info*/[3]);
+        new F0(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+        new F0(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello",
+                                            3]);
+
+        new F1(a: /*$info*/[]);
+        new F1(a: /*$info*/[3]);
+        new F1(a: /*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+        new F1(a: /*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
+
+        new F2(/*$info*/[]);
+        new F2(/*$info*/[3]);
+        new F2(/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+        new F2(/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
+
+        new F3(/*$info*/[]);
+        new F3(/*$info*/[/*$info*/[3]]);
+        new F3(/*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
+        new F3(/*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"],
+                         /*$info*/[3]]);
+
+        new F4(a: /*$info*/[]);
+        new F4(a: /*$info*/[/*$info*/[3]]);
+        new F4(a: /*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
+        new F4(a: /*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"],
+                            /*$info*/[3]]);
+      }
+      ''';
+    testChecker('infer downwards', {'/main.dart': code});
+  });
+
+  group('downwards inference on generic constructor arguments', () {
+    String info = "info:INFERRED_TYPE_LITERAL";
+    String code = '''
+      class F0<T> {
+        F0(List<T> a) {};
+      }
+      class F1<T> {
+        F1({List<T> a}) {};
+      }
+      class F2<T> {
+        F2(Iterable<T> a) {};
+      }
+      class F3<T> {
+        F3(Iterable<Iterable<T>> a) {};
+      }
+      class F4<T> {
+        F4({Iterable<Iterable<T>> a}) {};
+      }
+      void main() {
+        new F0<int>(/*$info*/[]);
+        new F0<int>(/*$info*/[3]);
+        new F0<int>(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+        new F0<int>(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello",
+                                            3]);
+
+        new F1<int>(a: /*$info*/[]);
+        new F1<int>(a: /*$info*/[3]);
+        new F1<int>(a: /*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+        new F1<int>(a: /*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
+
+        new F2<int>(/*$info*/[]);
+        new F2<int>(/*$info*/[3]);
+        new F2<int>(/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+        new F2<int>(/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
+
+        new F3<int>(/*$info*/[]);
+        new F3<int>(/*$info*/[/*$info*/[3]]);
+        new F3<int>(/*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
+        new F3<int>(/*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"],
+                         /*$info*/[3]]);
+
+        new F4<int>(a: /*$info*/[]);
+        new F4<int>(a: /*$info*/[/*$info*/[3]]);
+        new F4<int>(a: /*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
+        new F4<int>(a: /*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"],
+                            /*$info*/[3]]);
+
+        new F3(/*$info*/[]);
+        new F3(/*$info*/[[3]]);
+        new F3(/*$info*/[["hello"]]);
+        new F3(/*$info*/[["hello"], [3]]);
+
+        new F4(a: /*$info*/[]);
+        new F4(a: /*$info*/[[3]]);
+        new F4(a: /*$info*/[["hello"]]);
+        new F4(a: /*$info*/[["hello"], [3]]);
       }
       ''';
     testChecker('infer downwards', {'/main.dart': code});
   });
 
   group('downwards inference on map literals', () {
-    String info = "info:InferredTypeLiteral";
+    String info = "info:INFERRED_TYPE_LITERAL";
     String code = '''
       void foo([Map<int, String> m1 = /*$info*/const {1: "hello"},
-                Map<int, String> m1 = /*severe:StaticTypeError*/const {"hello": "world"}]) {
+        Map<int, String> m1 = /*$info*/const {(/*severe:STATIC_TYPE_ERROR*/"hello"): "world"}]) {
       }
       void main() {
         {
           Map<int, String> l0 = /*$info*/{};
           Map<int, String> l1 = /*$info*/{3: "hello"};
-          Map<int, String> l2 = /*severe:StaticTypeError*/{"hello": "hello"};
-          Map<int, String> l3 = /*severe:StaticTypeError*/{3: 3};
-          Map<int, String> l4 = /*severe:StaticTypeError*/{3:"hello", "hello": 3};
+          Map<int, String> l2 = /*$info*/{(/*severe:STATIC_TYPE_ERROR*/"hello"): "hello"};
+          Map<int, String> l3 = /*$info*/{3: /*severe:STATIC_TYPE_ERROR*/3};
+          Map<int, String> l4 = /*$info*/{3:"hello", (/*severe:STATIC_TYPE_ERROR*/"hello"): /*severe:STATIC_TYPE_ERROR*/3};
         }
         {
           Map<dynamic, dynamic> l0 = {};
@@ -1185,27 +1297,27 @@
           Map<dynamic, String> l0 = /*$info*/{};
           Map<dynamic, String> l1 = /*$info*/{3: "hello"};
           Map<dynamic, String> l2 = /*$info*/{"hello": "hello"};
-          Map<dynamic, String> l3 = /*severe:StaticTypeError*/{3: 3};
-          Map<dynamic, String> l4 = /*severe:StaticTypeError*/{3:"hello", "hello": 3};
+          Map<dynamic, String> l3 = /*$info*/{3: /*severe:STATIC_TYPE_ERROR*/3};
+          Map<dynamic, String> l4 = /*$info*/{3:"hello", "hello": /*severe:STATIC_TYPE_ERROR*/3};
         }
         {
           Map<int, dynamic> l0 = /*$info*/{};
           Map<int, dynamic> l1 = /*$info*/{3: "hello"};
-          Map<int, dynamic> l2 = /*severe:StaticTypeError*/{"hello": "hello"};
+          Map<int, dynamic> l2 = /*$info*/{(/*severe:STATIC_TYPE_ERROR*/"hello"): "hello"};
           Map<int, dynamic> l3 = /*$info*/{3: 3};
-          Map<int, dynamic> l3 = /*severe:StaticTypeError*/{3:"hello", "hello": 3};
+          Map<int, dynamic> l4 = /*$info*/{3:"hello", (/*severe:STATIC_TYPE_ERROR*/"hello"): 3};
         }
         {
-          Map<int, String> l0 = /*severe:StaticTypeError*/<num, dynamic>{};
-          Map<int, String> l1 = /*severe:StaticTypeError*/<num, dynamic>{3: "hello"};
-          Map<int, String> l3 = /*severe:StaticTypeError*/<num, dynamic>{3: 3};
+          Map<int, String> l0 = /*severe:STATIC_TYPE_ERROR*/<num, dynamic>{};
+          Map<int, String> l1 = /*severe:STATIC_TYPE_ERROR*/<num, dynamic>{3: "hello"};
+          Map<int, String> l3 = /*severe:STATIC_TYPE_ERROR*/<num, dynamic>{3: 3};
         }
         {
           const Map<int, String> l0 = /*$info*/const {};
           const Map<int, String> l1 = /*$info*/const {3: "hello"};
-          const Map<int, String> l2 = /*severe:StaticTypeError*/const {"hello": "hello"};
-          const Map<int, String> l3 = /*severe:StaticTypeError*/const {3: 3};
-          const Map<int, String> l4 = /*severe:StaticTypeError*/const {3:"hello", "hello": 3};
+          const Map<int, String> l2 = /*$info*/const {(/*severe:STATIC_TYPE_ERROR*/"hello"): "hello"};
+          const Map<int, String> l3 = /*$info*/const {3: /*severe:STATIC_TYPE_ERROR*/3};
+          const Map<int, String> l4 = /*$info*/const {3:"hello", (/*severe:STATIC_TYPE_ERROR*/"hello"): /*severe:STATIC_TYPE_ERROR*/3};
         }
       }
       ''';
@@ -1218,41 +1330,119 @@
 
       void main () {
         {
-          Function2<int, String> l0 = (int x) => null;
+          Function2<int, String> l0 = /*info:INFERRED_TYPE_CLOSURE*/(int x) => null;
           Function2<int, String> l1 = (int x) => "hello";
-          Function2<int, String> l2 = /*severe:StaticTypeError*/(String x) => "hello";
-          Function2<int, String> l3 = /*severe:StaticTypeError*/(int x) => 3;
-          Function2<int, String> l4 = /*warning:UninferredClosure should be severe:StaticTypeError*/(int x) {return 3};
+          Function2<int, String> l2 = /*severe:STATIC_TYPE_ERROR*/(String x) => "hello";
+          Function2<int, String> l3 = /*severe:STATIC_TYPE_ERROR*/(int x) => 3;
+          Function2<int, String> l4 = /*info:INFERRED_TYPE_CLOSURE*/(int x) {return /*severe:STATIC_TYPE_ERROR*/3;};
         }
         {
-          Function2<int, String> l0 = /*info:InferredTypeClosure*/(x) => null;
-          Function2<int, String> l1 = /*info:InferredTypeClosure*/(x) => "hello";
-          Function2<int, String> l2 = /*severe:StaticTypeError*/(x) => 3;
-          Function2<int, String> l3 = /*warning:UninferredClosure should be severe:StaticTypeError*/(x) {return 3};
+          Function2<int, String> l0 = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*/(x) => null;
+          Function2<int, String> l1 = /*info:INFERRED_TYPE_CLOSURE*/(x) => "hello";
+          Function2<int, String> l2 = /*info:INFERRED_TYPE_CLOSURE, severe:STATIC_TYPE_ERROR*/(x) => 3;
+          Function2<int, String> l3 = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*/(x) {return /*severe:STATIC_TYPE_ERROR*/3;};
+          Function2<int, String> l4 = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*/(x) {return /*severe:STATIC_TYPE_ERROR*/x;};
         }
         {
-          Function2<int, List<String>> l0 = (int x) => null;
-          Function2<int, List<String>> l1 = /*info:InferredTypeClosure*/(int x) => ["hello"];
-          Function2<int, List<String>> l2 = /*severe:StaticTypeError*/(String x) => ["hello"];
-          Function2<int, List<String>> l3 = /*warning:UninferredClosure should be severe:StaticTypeError*/(int x) => [3];
-          Function2<int, List<String>> l4 = /*warning:UninferredClosure should be severe:StaticTypeError*/(int x) {return [3]};
+          Function2<int, List<String>> l0 = /*info:INFERRED_TYPE_CLOSURE*/(int x) => null;
+          Function2<int, List<String>> l1 = (int x) => /*info:INFERRED_TYPE_LITERAL*/["hello"];
+          Function2<int, List<String>> l2 = /*severe:STATIC_TYPE_ERROR*/(String x) => /*info:INFERRED_TYPE_LITERAL*/["hello"];
+          Function2<int, List<String>> l3 = (int x) => /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/3];
+          Function2<int, List<String>> l4 = /*info:INFERRED_TYPE_CLOSURE*/(int x) {return /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/3];};
         }
         {
-          Function2<int, int> l0 = /*info:InferredTypeClosure*/(x) => x;
-          Function2<int, int> l1 = /*info:InferredTypeClosure*/(x) => /*info:DynamicInvoke should be pass*/x+1;
-          Function2<int, String> l2 = /*info:InferredTypeClosure should be severe:StaticTypeError*/(x) => x;
-          Function2<int, String> l3 = /*info:InferredTypeClosure should be severe:StaticTypeError*/(x) => /*info:DynamicInvoke should be pass*/x.substring(3);
-          Function2<String, String> l4 = /*info:InferredTypeClosure*/(x) => /*info:DynamicInvoke should be pass*/x.substring(3);
+          Function2<int, int> l0 = /*info:INFERRED_TYPE_CLOSURE*/(x) => x;
+          Function2<int, int> l1 = /*info:INFERRED_TYPE_CLOSURE*/(x) => x+1;
+          Function2<int, String> l2 = /*info:INFERRED_TYPE_CLOSURE, severe:STATIC_TYPE_ERROR*/(x) => x;
+          Function2<int, String> l3 = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*/(x) => /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/x.substring(3);
+          Function2<String, String> l4 = /*info:INFERRED_TYPE_CLOSURE*/(x) => x.substring(3);
         }
       }
       '''
   });
 
+  testChecker('downwards inference initializing formal, default formal', {
+    '/main.dart': '''
+      typedef T Function2<S, T>([S x]);
+      class Foo {
+        List<int> x;
+        Foo([this.x = /*info:INFERRED_TYPE_LITERAL*/const [1]]);
+        Foo.named([List<int> x = /*info:INFERRED_TYPE_LITERAL*/const [1]]);
+      }
+      void f([List<int> l = /*info:INFERRED_TYPE_LITERAL*/const [1]]) {}
+// We do this inference in an early task but don't preserve the infos.
+      Function2<List<int>, String> g = /*pass should be info:INFERRED_TYPE_CLOSURE*/([llll = /*info:INFERRED_TYPE_LITERAL*/const [1]]) => "hello";
+'''
+  });
+
+  testChecker('downwards inference async/await', {
+    '/main.dart': '''
+      import 'dart:async';
+      Future<int> test() async {
+        List<int> l0 = /*warning:DOWN_CAST_COMPOSITE should be pass*/await /*pass should be info:INFERRED_TYPE_LITERAL*/[3];
+        List<int> l1 = await /*info:INFERRED_TYPE_ALLOCATION*/new Future.value(/*info:INFERRED_TYPE_LITERAL*/[3]);
+        '''
+  });
+
+  testChecker('downwards inference foreach', {
+    '/main.dart': '''
+      import 'dart:async';
+      void main() {
+        for(int x in /*info:INFERRED_TYPE_LITERAL*/[1, 2, 3]) {
+        }
+        await for(int x in /*info:INFERRED_TYPE_ALLOCATION*/new Stream()) {
+        }
+      }
+        '''
+  });
+
+  testChecker('downwards inference yield/yield*', {
+    '/main.dart': '''
+      import 'dart:async';
+        Stream<List<int>> foo() async* {
+          yield /*info:INFERRED_TYPE_LITERAL*/[];
+          yield /*severe:STATIC_TYPE_ERROR*/new Stream();
+          yield* /*severe:STATIC_TYPE_ERROR*/[];
+          yield* /*info:INFERRED_TYPE_ALLOCATION*/new Stream();
+        }
+
+        Iterable<Map<int, int>> bar() sync* {
+          yield /*info:INFERRED_TYPE_LITERAL*/{};
+          yield /*severe:STATIC_TYPE_ERROR*/new List();
+          yield* /*severe:STATIC_TYPE_ERROR*/{};
+          yield* /*info:INFERRED_TYPE_ALLOCATION*/new List();
+        }
+        '''
+  });
+
+  testChecker('downwards inference, annotations', {
+    '/main.dart': '''
+        class Foo {
+          const Foo(List<String> l);
+          const Foo.named(List<String> l);
+        }
+        @Foo(/*info:INFERRED_TYPE_LITERAL*/const [])
+        class Bar {}
+        @Foo.named(/*info:INFERRED_TYPE_LITERAL*/const [])
+        class Baz {}
+        '''
+  });
+
+  testChecker('downwards inference, assignment statements', {
+    '/main.dart': '''
+    void main() {
+      List<int> l;
+      l = /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"];
+      l = (l = /*info:INFERRED_TYPE_LITERAL*/[1]);
+    }
+'''
+  });
+
   testChecker('inferred initializing formal checks default value', {
     '/main.dart': '''
       class Foo {
         var x = 1;
-        Foo([this.x = /*severe:StaticTypeError*/"1"]);
+        Foo([this.x = /*severe:STATIC_TYPE_ERROR*/"1"]);
       }'''
   });
 
@@ -1274,20 +1464,20 @@
           printDouble(min(1.0, 2.0));
 
           // No help for user-defined functions from num->num->num.
-          printInt(/*info:DownCastImplicit*/myMax(1, 2));
+          printInt(/*info:DOWN_CAST_IMPLICIT*/myMax(1, 2));
           printInt(myMax(1, 2) as int);
 
           // Mixing int and double means return type is num.
-          printInt(/*info:DownCastImplicit*/max(1, 2.0));
-          printInt(/*info:DownCastImplicit*/min(1, 2.0));
-          printDouble(/*info:DownCastImplicit*/max(1, 2.0));
-          printDouble(/*info:DownCastImplicit*/min(1, 2.0));
+          printInt(/*info:DOWN_CAST_IMPLICIT*/max(1, 2.0));
+          printInt(/*info:DOWN_CAST_IMPLICIT*/min(1, 2.0));
+          printDouble(/*info:DOWN_CAST_IMPLICIT*/max(1, 2.0));
+          printDouble(/*info:DOWN_CAST_IMPLICIT*/min(1, 2.0));
 
           // Types other than int and double are not accepted.
           printInt(
-              /*info:DownCastImplicit*/min(
-                  /*severe:StaticTypeError*/"hi",
-                  /*severe:StaticTypeError*/"there"));
+              /*info:DOWN_CAST_IMPLICIT*/min(
+                  /*severe:STATIC_TYPE_ERROR*/"hi",
+                  /*severe:STATIC_TYPE_ERROR*/"there"));
         }
     '''
     });
@@ -1296,7 +1486,7 @@
       '/main.dart': '''
         import 'dart:async';
 
-        Future<int> make(int x) => (/*info:InferredTypeAllocation*/new Future(() => x));
+        Future<int> make(int x) => (/*info:INFERRED_TYPE_ALLOCATION*/new Future(() => x));
 
         main() {
           Iterable<Future<int>> list = <int>[1, 2, 3].map(make);
diff --git a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
index 330801f..360f6c1 100644
--- a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
+++ b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
@@ -63,6 +63,7 @@
     AnalysisEngine.instance.useTaskModel = true;
     var context = AnalysisEngine.instance.createAnalysisContext();
     context.analysisOptions.strongMode = true;
+    context.analysisOptions.strongModeHints = true;
 
     context.sourceFactory = new SourceFactory([
       new MockDartSdk(mockSdkSources, reportMissing: true).resolver,
@@ -92,6 +93,13 @@
 
         var librarySource = context.getLibrariesContaining(source).single;
         var resolved = context.resolveCompilationUnit2(source, librarySource);
+        var analyzerErrors = context
+            .getErrors(source)
+            .errors
+            .where((error) =>
+                error.errorCode.name.startsWith('STRONG_MODE_INFERRED_TYPE'))
+            .toList();
+        errors.addAll(analyzerErrors);
         checker.visitCompilationUnit(resolved);
 
         new _ExpectedErrorVisitor(errors).validate(resolved);
@@ -370,6 +378,7 @@
       throw new UnsupportedError('not expecting relative urls in dart: mocks');
 }
 
+// TODO(jmesserly): can we reuse the same mock SDK as Analyzer tests?
 /// Sample mock SDK sources.
 final Map<String, String> mockSdkSources = {
   // The list of types below is derived from:
@@ -395,6 +404,7 @@
 
         class String {
           String operator +(String other) {}
+          String substring(int len) {}
         }
         class bool {}
         class num {
@@ -419,8 +429,10 @@
         const Object proxy = const _Proxy();
 
         class Iterable<E> {
-          fold(initialValue, combine(previousValue, E element)) {}
-          Iterable map(f(E element)) {}
+          Iterable/*<R>*/ map/*<R>*/(/*=R*/ f(E e));
+
+          /*=R*/ fold/*<R>*/(/*=R*/ initialValue,
+              /*=R*/ combine(/*=R*/ previousValue, E element));
         }
         class List<E> implements Iterable<E> {
           List([int length]);
@@ -434,8 +446,9 @@
         class Future<T> {
           Future(computation()) {}
           Future.value(T t) {}
-          Future then(onValue(T value)) {}
-          static Future<List> wait(Iterable<Future> futures) {}
+          static Future<List/*<T>*/> wait/*<T>*/(
+              Iterable<Future/*<T>*/> futures) => null;
+          Future/*<R>*/ then/*<R>*/(/*=R*/ onValue(T value)) => null;
         }
         class Stream<T> {}
   ''',
@@ -448,8 +461,8 @@
         class Random {
           bool nextBool() {}
         }
-        num min(num x, num y) {}
-        num max(num x, num y) {}
+        num/*=T*/ min/*<T extends num>*/(num/*=T*/ a, num/*=T*/ b) => null;
+        num/*=T*/ max/*<T extends num>*/(num/*=T*/ a, num/*=T*/ b) => null;
         ''',
 };
 
@@ -470,7 +483,7 @@
 
 String errorCodeName(ErrorCode errorCode) {
   var name = errorCode.name;
-  final prefix = 'dev_compiler.';
+  final prefix = 'STRONG_MODE_';
   if (name.startsWith(prefix)) {
     return name.substring(prefix.length);
   } else {
diff --git a/pkg/analyzer/test/utils.dart b/pkg/analyzer/test/utils.dart
index 7c9fbe0..d5d2879 100644
--- a/pkg/analyzer/test/utils.dart
+++ b/pkg/analyzer/test/utils.dart
@@ -4,7 +4,10 @@
 
 library analyzer.test.utils;
 
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
 import 'package:analyzer/src/generated/java_io.dart';
+import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
 import 'package:path/path.dart' as path;
 import 'package:unittest/unittest.dart';
 
@@ -12,3 +15,289 @@
   groupSep = ' | ';
   JavaFile.pathContext = path.posix;
 }
+
+/**
+ * The type of an assertion which asserts properties of [T]s.
+ */
+typedef void Asserter<T>(T type);
+
+/**
+ * The type of a function which given an [S], builds an assertion over [T]s.
+ */
+typedef Asserter<T> AsserterBuilder<S, T>(S arg);
+
+/**
+ * The type of a function which given an [S0] and an S1, builds an assertion
+ * over [T]s.
+ */
+typedef Asserter<T> AsserterBuilder2<S0, S1, T>(S0 arg0, S1 arg1);
+
+/**
+ * The type of a function which given an [R] returns an [AsserterBuilder] over
+ * [S]s and [T]s.  That is, it returns a function which given an [S], returns
+ * a function over [T]s.
+ */
+typedef AsserterBuilder<S, T> AsserterBuilderBuilder<R, S, T>(R arg);
+
+class AstFinder {
+  /**
+   * Return the declaration of the class with the given [className] in the given
+   * compilation [unit].
+   */
+  static ClassDeclaration getClass(CompilationUnit unit, String className) {
+    NodeList<CompilationUnitMember> unitMembers = unit.declarations;
+    for (CompilationUnitMember unitMember in unitMembers) {
+      if (unitMember is ClassDeclaration && unitMember.name.name == className) {
+        return unitMember;
+      }
+    }
+    fail('No class named $className in ${unit.element.source}');
+    return null;
+  }
+
+  /**
+   * Return the declaration of the constructor with the given [constructorName] in
+   * the class with the given [className] in the given compilation [unit].  If
+   * constructorName is null, return the default constructor;
+   */
+  static ConstructorDeclaration getConstructorInClass(
+      CompilationUnit unit, String className, String constructorName) {
+    ClassDeclaration unitMember = getClass(unit, className);
+    NodeList<ClassMember> classMembers = unitMember.members;
+    for (ClassMember classMember in classMembers) {
+      if (classMember is ConstructorDeclaration) {
+        if (classMember.name?.name == constructorName) {
+          return classMember;
+        }
+      }
+    }
+    fail('No constructor named $constructorName in $className');
+    return null;
+  }
+
+  /**
+   * Return the declaration of the field with the given [fieldName] in the class
+   * with the given [className] in the given compilation [unit].
+   */
+  static VariableDeclaration getFieldInClass(
+      CompilationUnit unit, String className, String fieldName) {
+    ClassDeclaration unitMember = getClass(unit, className);
+    NodeList<ClassMember> classMembers = unitMember.members;
+    for (ClassMember classMember in classMembers) {
+      if (classMember is FieldDeclaration) {
+        NodeList<VariableDeclaration> fields = classMember.fields.variables;
+        for (VariableDeclaration field in fields) {
+          if (field.name.name == fieldName) {
+            return field;
+          }
+        }
+      }
+    }
+    fail('No field named $fieldName in $className');
+    return null;
+  }
+
+  /**
+   * Return the element of the field with the given [fieldName] in the class
+   * with the given [className] in the given compilation [unit].
+   */
+  static FieldElement getFieldInClassElement(
+      CompilationUnit unit, String className, String fieldName) {
+    return getFieldInClass(unit, className, fieldName)?.name?.staticElement;
+  }
+
+  /**
+   * Return the declaration of the method with the given [methodName] in the
+   * class with the given [className] in the given compilation [unit].
+   */
+  static MethodDeclaration getMethodInClass(
+      CompilationUnit unit, String className, String methodName) {
+    ClassDeclaration unitMember = getClass(unit, className);
+    NodeList<ClassMember> classMembers = unitMember.members;
+    for (ClassMember classMember in classMembers) {
+      if (classMember is MethodDeclaration) {
+        if (classMember.name.name == methodName) {
+          return classMember;
+        }
+      }
+    }
+    fail('No method named $methodName in $className');
+    return null;
+  }
+
+  /**
+   * Return the statements in the body of a the method with the given
+   * [methodName] in the class with the given [className] in the given
+   * compilation [unit].
+   */
+  static List<Statement> getStatementsInMethod(
+      CompilationUnit unit, String className, String methodName) {
+    MethodDeclaration method = getMethodInClass(unit, className, methodName);
+    BlockFunctionBody body = method.body;
+    return body.block.statements;
+  }
+
+  /**
+   * Return the statements in the body of the top-level function with the given
+   * [functionName] in the given compilation [unit].
+   */
+  static List<Statement> getStatementsInTopLevelFunction(
+      CompilationUnit unit, String functionName) {
+    FunctionDeclaration function = getTopLevelFunction(unit, functionName);
+    BlockFunctionBody body = function.functionExpression.body;
+    return body.block.statements;
+  }
+
+  /**
+   * Return the declaration of the top-level function with the given
+   * [functionName] in the given compilation [unit].
+   */
+  static FunctionDeclaration getTopLevelFunction(
+      CompilationUnit unit, String functionName) {
+    NodeList<CompilationUnitMember> unitMembers = unit.declarations;
+    for (CompilationUnitMember unitMember in unitMembers) {
+      if (unitMember is FunctionDeclaration) {
+        if (unitMember.name.name == functionName) {
+          return unitMember;
+        }
+      }
+    }
+    fail('No toplevel function named $functionName found');
+    return null;
+  }
+
+  /**
+   * Return the declaration of the top-level variable with the given
+   * [variableName] in the given compilation [unit].
+   */
+  static VariableDeclaration getTopLevelVariable(
+      CompilationUnit unit, String variableName) {
+    NodeList<CompilationUnitMember> unitMembers = unit.declarations;
+    for (CompilationUnitMember unitMember in unitMembers) {
+      if (unitMember is TopLevelVariableDeclaration) {
+        NodeList<VariableDeclaration> variables =
+            unitMember.variables.variables;
+        for (VariableDeclaration variable in variables) {
+          if (variable.name.name == variableName) {
+            return variable;
+          }
+        }
+      }
+    }
+    fail('No toplevel variable named $variableName found');
+    return null;
+  }
+
+  /**
+   * Return the top-level variable element with the given [name].
+   */
+  static TopLevelVariableElement getTopLevelVariableElement(
+      CompilationUnit unit, String name) {
+    return getTopLevelVariable(unit, name)?.name?.staticElement;
+  }
+}
+
+/**
+ * Class for compositionally building up assertions on types
+ */
+class TypeAssertions {
+  // TODO(leafp): Make these matchers.
+  // https://www.dartdocs.org/documentation/matcher/0.12.0%2B1/matcher/Matcher-class.html
+
+  /* Provides primitive types for basic type assertions */
+  final TypeProvider _typeProvider;
+
+  TypeAssertions(this._typeProvider);
+
+  /**
+   * Primitive assertion for the dynamic type
+   */
+  Asserter<DartType> get isDynamic => isType(_typeProvider.dynamicType);
+
+  /**
+   * Primitive assertion for the int type
+   */
+  Asserter<DartType> get isInt => isType(_typeProvider.intType);
+
+  /**
+   * Primitive assertion for the list type
+   */
+  Asserter<DartType> get isList => sameElement(_typeProvider.listType);
+
+  /**
+   * Primitive assertion for the map type
+   */
+  Asserter<DartType> get isMap => sameElement(_typeProvider.mapType);
+
+  /**
+   * Primitive assertion for the num type
+   */
+  Asserter<DartType> get isNum => isType(_typeProvider.numType);
+
+  /**
+   * Primitive assertion for the string type
+   */
+  Asserter<DartType> get isString => isType(_typeProvider.stringType);
+
+  /**
+   * Given a type, produce an assertion that a type has the same element.
+   */
+  Asserter<DartType> hasElement(Element element) =>
+      (DartType type) => expect(element, same(type.element));
+
+  /**
+   * Given assertions for the argument and return types, produce an
+   *  assertion over unary function types.
+   */
+  Asserter<DartType> isFunction2Of(
+          Asserter<DartType> argType, Asserter<DartType> returnType) =>
+      (DartType type) {
+        FunctionType fType = (type as FunctionType);
+        argType(fType.normalParameterTypes[0]);
+        returnType(fType.returnType);
+      };
+
+  /**
+   * Given an assertion for the base type and assertions over the type
+   * parameters, produce an assertion over instantations.
+   */
+  AsserterBuilder<List<Asserter<DartType>>, DartType> isInstantiationOf(
+          Asserter<DartType> baseAssert) =>
+      (List<Asserter<DartType>> argAsserts) => (DartType type) {
+            InterfaceType t = (type as InterfaceType);
+            baseAssert(t);
+            List<DartType> typeArguments = t.typeArguments;
+            expect(typeArguments, hasLength(argAsserts.length));
+            for (int i = 0; i < typeArguments.length; i++) {
+              argAsserts[i](typeArguments[i]);
+            }
+          };
+
+  /**
+   * Assert that a type is the List type, and that the given assertion holds
+   * over the type parameter.
+   */
+  Asserter<InterfaceType> isListOf(Asserter<DartType> argAssert) =>
+      isInstantiationOf(isList)([argAssert]);
+
+  /**
+   * Assert that a type is the Map type, and that the given assertions hold
+   * over the type parameters.
+   */
+  Asserter<InterfaceType> isMapOf(
+          Asserter<DartType> argAssert0, Asserter<DartType> argAssert1) =>
+      isInstantiationOf(isMap)([argAssert0, argAssert1]);
+
+  /**
+   * Assert that one type is the same as another
+   */
+  Asserter<DartType> isType(DartType argument) => (DartType t) {
+        expect(t, same(argument));
+      };
+
+  /**
+   * Given a type, produce an assertion that a type has the same element.
+   */
+  Asserter<DartType> sameElement(DartType elementType) =>
+      hasElement(elementType.element);
+}
diff --git a/pkg/analyzer/tool/summary/idl.dart b/pkg/analyzer/tool/summary/idl.dart
index 545dbfc..fa71eec 100644
--- a/pkg/analyzer/tool/summary/idl.dart
+++ b/pkg/analyzer/tool/summary/idl.dart
@@ -125,6 +125,14 @@
    * the kind if [PrelinkedReferenceKind.classOrEnum].
    */
   PrelinkedReferenceKind kind;
+
+  /**
+   * Integer index indicating which unit in the imported library contains the
+   * definition of the entity.  As with indices into [UnlinkedLibrary.units],
+   * zero represents the defining compilation unit, and nonzero values
+   * represent parts in the order of the corresponding `part` declarations.
+   */
+  int unit;
 }
 
 /**
@@ -434,7 +442,8 @@
 
   /**
    * Information about the units constituting this library.  The first unit
-   * listed is always the defining compilation unit.
+   * listed is always the defining compilation unit.  The remaining units are
+   * listed in the order of their corresponding `part` declarations.
    */
   List<UnlinkedUnit> units;
 
diff --git a/pkg/analyzer/tool/task_dependency_graph/tasks.dot b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
index 4e915c8..7afcf76 100644
--- a/pkg/analyzer/tool/task_dependency_graph/tasks.dot
+++ b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
@@ -44,6 +44,7 @@
   ComputeLibraryCycleTask -> LIBRARY_CYCLE
   ComputeLibraryCycleTask -> LIBRARY_CYCLE_DEPENDENCIES
   ComputeLibraryCycleTask -> LIBRARY_CYCLE_UNITS
+  ComputePropagableVariableDependenciesTask -> PROPAGABLE_VARIABLE_DEPENDENCIES
   ContainingLibrariesTask -> CONTAINING_LIBRARIES
   DART_ERRORS -> LibraryErrorsReadyTask
   DART_ERRORS [shape=box]
@@ -54,13 +55,14 @@
   EXPORTED_LIBRARIES -> BuildDirectiveElementsTask
   EXPORTED_LIBRARIES -> ReadyLibraryElement2Task
   EXPORTED_LIBRARIES -> ReadyLibraryElement5Task
+  EXPORTED_LIBRARIES -> ReadyLibraryElement6Task
   EXPORTED_LIBRARIES -> ReadyResolvedUnit10Task
-  EXPORTED_LIBRARIES -> ReadyResolvedUnit9Task
+  EXPORTED_LIBRARIES -> ReadyResolvedUnit11Task
   EXPORTED_LIBRARIES -> ReadyResolvedUnitTask
   EXPORTED_LIBRARIES [shape=box]
   EXPORT_SOURCE_CLOSURE -> BuildExportNamespaceTask
   EXPORT_SOURCE_CLOSURE [shape=box]
-  EvaluateUnitConstantsTask -> RESOLVED_UNIT10
+  EvaluateUnitConstantsTask -> RESOLVED_UNIT11
   GatherUsedImportedElementsTask -> USED_IMPORTED_ELEMENTS
   GatherUsedLocalElementsTask -> USED_LOCAL_ELEMENTS
   GenerateHintsTask -> HINTS
@@ -70,8 +72,9 @@
   IMPORTED_LIBRARIES -> BuildDirectiveElementsTask
   IMPORTED_LIBRARIES -> ReadyLibraryElement2Task
   IMPORTED_LIBRARIES -> ReadyLibraryElement5Task
+  IMPORTED_LIBRARIES -> ReadyLibraryElement6Task
   IMPORTED_LIBRARIES -> ReadyResolvedUnit10Task
-  IMPORTED_LIBRARIES -> ReadyResolvedUnit9Task
+  IMPORTED_LIBRARIES -> ReadyResolvedUnit11Task
   IMPORTED_LIBRARIES -> ReadyResolvedUnitTask
   IMPORTED_LIBRARIES -> ResolveUnitTypeNamesTask
   IMPORTED_LIBRARIES [shape=box]
@@ -85,9 +88,9 @@
   INFERRED_STATIC_VARIABLE -> InferStaticVariableTypesInUnitTask
   INFERRED_STATIC_VARIABLE [shape=box]
   IS_LAUNCHABLE [shape=box]
-  InferInstanceMembersInUnitTask -> RESOLVED_UNIT8
+  InferInstanceMembersInUnitTask -> RESOLVED_UNIT9
   InferStaticVariableTypeTask -> INFERRED_STATIC_VARIABLE
-  InferStaticVariableTypesInUnitTask -> RESOLVED_UNIT6
+  InferStaticVariableTypesInUnitTask -> RESOLVED_UNIT7
   LIBRARY_CYCLE [shape=box]
   LIBRARY_CYCLE_DEPENDENCIES -> InferInstanceMembersInUnitTask
   LIBRARY_CYCLE_DEPENDENCIES -> InferStaticVariableTypeTask
@@ -115,15 +118,21 @@
   LIBRARY_ELEMENT4 -> ResolveUnitTypeNamesTask
   LIBRARY_ELEMENT4 [shape=box]
   LIBRARY_ELEMENT5 -> PartiallyResolveUnitReferencesTask
+  LIBRARY_ELEMENT5 -> PropagateVariableTypesInLibraryTask
   LIBRARY_ELEMENT5 -> ReadyLibraryElement5Task
   LIBRARY_ELEMENT5 -> ResolveInstanceFieldsInUnitTask
   LIBRARY_ELEMENT5 -> ResolveLibraryReferencesTask
-  LIBRARY_ELEMENT5 -> ResolveUnitTask
   LIBRARY_ELEMENT5 [shape=box]
+  LIBRARY_ELEMENT6 -> PropagateVariableTypesInLibraryClosureTask
+  LIBRARY_ELEMENT6 -> ReadyLibraryElement6Task
+  LIBRARY_ELEMENT6 [shape=box]
+  LIBRARY_ELEMENT7 -> ResolveUnitTask
+  LIBRARY_ELEMENT7 [shape=box]
   LIBRARY_ERRORS_READY [shape=box]
   LIBRARY_SPECIFIC_UNITS -> GenerateHintsTask
+  LIBRARY_SPECIFIC_UNITS -> PropagateVariableTypesInLibraryTask
   LIBRARY_SPECIFIC_UNITS -> ReadyResolvedUnit10Task
-  LIBRARY_SPECIFIC_UNITS -> ReadyResolvedUnit9Task
+  LIBRARY_SPECIFIC_UNITS -> ReadyResolvedUnit11Task
   LIBRARY_SPECIFIC_UNITS -> ReadyResolvedUnitTask
   LIBRARY_SPECIFIC_UNITS -> ResolveLibraryReferencesTask
   LIBRARY_SPECIFIC_UNITS -> ResolveLibraryTypeNamesTask
@@ -142,6 +151,13 @@
   PARSED_UNIT [shape=box]
   PARSE_ERRORS -> dartErrorsForSource
   PARSE_ERRORS [shape=box]
+  PROPAGABLE_VARIABLES_IN_UNIT -> PropagateVariableTypesInUnitTask
+  PROPAGABLE_VARIABLES_IN_UNIT [shape=box]
+  PROPAGABLE_VARIABLE_DEPENDENCIES -> PropagateVariableTypeTask
+  PROPAGABLE_VARIABLE_DEPENDENCIES [shape=box]
+  PROPAGATED_VARIABLE -> PropagateVariableTypeTask
+  PROPAGATED_VARIABLE -> PropagateVariableTypesInUnitTask
+  PROPAGATED_VARIABLE [shape=box]
   ParseDartTask -> EXPLICITLY_IMPORTED_LIBRARIES
   ParseDartTask -> EXPORTED_LIBRARIES
   ParseDartTask -> IMPORTED_LIBRARIES
@@ -152,22 +168,30 @@
   ParseDartTask -> SOURCE_KIND
   ParseDartTask -> UNITS
   PartiallyResolveUnitReferencesTask -> INFERABLE_STATIC_VARIABLES_IN_UNIT
+  PartiallyResolveUnitReferencesTask -> PROPAGABLE_VARIABLES_IN_UNIT
   PartiallyResolveUnitReferencesTask -> RESOLVED_UNIT5
+  PropagateVariableTypeTask -> PROPAGATED_VARIABLE
+  PropagateVariableTypesInLibraryClosureTask -> LIBRARY_ELEMENT7
+  PropagateVariableTypesInLibraryTask -> LIBRARY_ELEMENT6
+  PropagateVariableTypesInUnitTask -> RESOLVED_UNIT6
   READY_LIBRARY_ELEMENT2 -> ComputeLibraryCycleTask
   READY_LIBRARY_ELEMENT2 -> ReadyLibraryElement2Task
   READY_LIBRARY_ELEMENT2 [shape=box]
   READY_LIBRARY_ELEMENT5 -> PartiallyResolveUnitReferencesTask
   READY_LIBRARY_ELEMENT5 -> ReadyLibraryElement5Task
   READY_LIBRARY_ELEMENT5 [shape=box]
+  READY_LIBRARY_ELEMENT6 -> PropagateVariableTypesInLibraryClosureTask
+  READY_LIBRARY_ELEMENT6 -> ReadyLibraryElement6Task
+  READY_LIBRARY_ELEMENT6 [shape=box]
   READY_RESOLVED_UNIT -> ReadyResolvedUnitTask
   READY_RESOLVED_UNIT -> VerifyUnitTask
   READY_RESOLVED_UNIT [shape=box]
   READY_RESOLVED_UNIT10 -> ReadyResolvedUnit10Task
-  READY_RESOLVED_UNIT10 -> StrongModeVerifyUnitTask
+  READY_RESOLVED_UNIT10 -> ResolveLibraryReferencesTask
   READY_RESOLVED_UNIT10 [shape=box]
-  READY_RESOLVED_UNIT9 -> ReadyResolvedUnit9Task
-  READY_RESOLVED_UNIT9 -> ResolveLibraryReferencesTask
-  READY_RESOLVED_UNIT9 [shape=box]
+  READY_RESOLVED_UNIT11 -> ReadyResolvedUnit11Task
+  READY_RESOLVED_UNIT11 -> StrongModeVerifyUnitTask
+  READY_RESOLVED_UNIT11 [shape=box]
   REFERENCED_NAMES [shape=box]
   RESOLVED_UNIT -> GenerateHintsTask
   RESOLVED_UNIT -> GenerateLintsTask
@@ -178,9 +202,16 @@
   RESOLVED_UNIT1 -> BuildEnumMemberElementsTask
   RESOLVED_UNIT1 -> BuildLibraryElementTask
   RESOLVED_UNIT1 [shape=box]
+  RESOLVED_UNIT10 -> ComputeConstantDependenciesTask
+  RESOLVED_UNIT10 -> EvaluateUnitConstantsTask
+  RESOLVED_UNIT10 -> GatherUsedImportedElementsTask
+  RESOLVED_UNIT10 -> GatherUsedLocalElementsTask
   RESOLVED_UNIT10 -> ReadyResolvedUnit10Task
-  RESOLVED_UNIT10 -> StrongModeVerifyUnitTask
+  RESOLVED_UNIT10 -> ResolveLibraryReferencesTask
   RESOLVED_UNIT10 [shape=box]
+  RESOLVED_UNIT11 -> ReadyResolvedUnit11Task
+  RESOLVED_UNIT11 -> StrongModeVerifyUnitTask
+  RESOLVED_UNIT11 [shape=box]
   RESOLVED_UNIT2 -> ResolveUnitTypeNamesTask
   RESOLVED_UNIT2 [shape=box]
   RESOLVED_UNIT3 -> ResolveLibraryTypeNamesTask
@@ -189,25 +220,23 @@
   RESOLVED_UNIT4 -> PartiallyResolveUnitReferencesTask
   RESOLVED_UNIT4 [shape=box]
   RESOLVED_UNIT5 -> ComputeInferableStaticVariableDependenciesTask
-  RESOLVED_UNIT5 -> InferStaticVariableTypeTask
-  RESOLVED_UNIT5 -> InferStaticVariableTypesInUnitTask
+  RESOLVED_UNIT5 -> ComputePropagableVariableDependenciesTask
+  RESOLVED_UNIT5 -> PropagateVariableTypeTask
+  RESOLVED_UNIT5 -> PropagateVariableTypesInUnitTask
   RESOLVED_UNIT5 [shape=box]
-  RESOLVED_UNIT6 -> ResolveInstanceFieldsInUnitTask
+  RESOLVED_UNIT6 -> InferStaticVariableTypeTask
+  RESOLVED_UNIT6 -> InferStaticVariableTypesInUnitTask
+  RESOLVED_UNIT6 -> PropagateVariableTypesInLibraryTask
   RESOLVED_UNIT6 [shape=box]
-  RESOLVED_UNIT7 -> InferInstanceMembersInUnitTask
+  RESOLVED_UNIT7 -> ResolveInstanceFieldsInUnitTask
   RESOLVED_UNIT7 [shape=box]
   RESOLVED_UNIT8 -> InferInstanceMembersInUnitTask
-  RESOLVED_UNIT8 -> InferStaticVariableTypeTask
-  RESOLVED_UNIT8 -> PartiallyResolveUnitReferencesTask
-  RESOLVED_UNIT8 -> ResolveInstanceFieldsInUnitTask
-  RESOLVED_UNIT8 -> ResolveUnitTask
   RESOLVED_UNIT8 [shape=box]
-  RESOLVED_UNIT9 -> ComputeConstantDependenciesTask
-  RESOLVED_UNIT9 -> EvaluateUnitConstantsTask
-  RESOLVED_UNIT9 -> GatherUsedImportedElementsTask
-  RESOLVED_UNIT9 -> GatherUsedLocalElementsTask
-  RESOLVED_UNIT9 -> ReadyResolvedUnit9Task
-  RESOLVED_UNIT9 -> ResolveLibraryReferencesTask
+  RESOLVED_UNIT9 -> InferInstanceMembersInUnitTask
+  RESOLVED_UNIT9 -> InferStaticVariableTypeTask
+  RESOLVED_UNIT9 -> PartiallyResolveUnitReferencesTask
+  RESOLVED_UNIT9 -> ResolveInstanceFieldsInUnitTask
+  RESOLVED_UNIT9 -> ResolveUnitTask
   RESOLVED_UNIT9 [shape=box]
   RESOLVE_TYPE_NAMES_ERRORS -> LibraryUnitErrorsTask
   RESOLVE_TYPE_NAMES_ERRORS [shape=box]
@@ -215,14 +244,15 @@
   RESOLVE_UNIT_ERRORS [shape=box]
   ReadyLibraryElement2Task -> READY_LIBRARY_ELEMENT2
   ReadyLibraryElement5Task -> READY_LIBRARY_ELEMENT5
+  ReadyLibraryElement6Task -> READY_LIBRARY_ELEMENT6
   ReadyResolvedUnit10Task -> READY_RESOLVED_UNIT10
-  ReadyResolvedUnit9Task -> READY_RESOLVED_UNIT9
+  ReadyResolvedUnit11Task -> READY_RESOLVED_UNIT11
   ReadyResolvedUnitTask -> READY_RESOLVED_UNIT
-  ResolveInstanceFieldsInUnitTask -> RESOLVED_UNIT7
+  ResolveInstanceFieldsInUnitTask -> RESOLVED_UNIT8
   ResolveLibraryReferencesTask -> LIBRARY_ELEMENT
   ResolveLibraryReferencesTask -> REFERENCED_NAMES
   ResolveLibraryTypeNamesTask -> LIBRARY_ELEMENT5
-  ResolveUnitTask -> RESOLVED_UNIT9
+  ResolveUnitTask -> RESOLVED_UNIT10
   ResolveUnitTask -> RESOLVE_UNIT_ERRORS
   ResolveUnitTypeNamesTask -> RESOLVED_UNIT3
   ResolveUnitTypeNamesTask -> RESOLVE_TYPE_NAMES_ERRORS
@@ -248,6 +278,7 @@
   TYPE_PROVIDER -> InferInstanceMembersInUnitTask
   TYPE_PROVIDER -> InferStaticVariableTypeTask
   TYPE_PROVIDER -> PartiallyResolveUnitReferencesTask
+  TYPE_PROVIDER -> PropagateVariableTypeTask
   TYPE_PROVIDER -> ResolveInstanceFieldsInUnitTask
   TYPE_PROVIDER -> ResolveLibraryTypeNamesTask
   TYPE_PROVIDER -> ResolveUnitTask
diff --git a/pkg/analyzer_cli/.gitignore b/pkg/analyzer_cli/.gitignore
new file mode 100644
index 0000000..3a4106f
--- /dev/null
+++ b/pkg/analyzer_cli/.gitignore
@@ -0,0 +1,11 @@
+.buildlog
+.DS_Store
+.idea
+/.packages
+.project
+.pub/
+.settings/
+analyzer_cli.iml
+build/
+packages
+pubspec.lock
diff --git a/pkg/analyzer_cli/CHANGELOG.md b/pkg/analyzer_cli/CHANGELOG.md
new file mode 100644
index 0000000..c4298d7
--- /dev/null
+++ b/pkg/analyzer_cli/CHANGELOG.md
@@ -0,0 +1,16 @@
+# Changelog
+
+## 1.1.1
+
+- Removed outmoded `--url-mapping` command line option.
+
+## 1.1.0
+
+- New `--lints` command line option.
+
+## 0.0.
+
+
+## 0.0.1
+
+- Initial version
diff --git a/pkg/analyzer_cli/README.md b/pkg/analyzer_cli/README.md
new file mode 100644
index 0000000..1652184
--- /dev/null
+++ b/pkg/analyzer_cli/README.md
@@ -0,0 +1,87 @@
+# dartanalyzer
+
+Use _dartanalyzer_ to statically analyze your code at the command line,
+checking for errors and warnings that are specified in the
+[Dart Language Specification](https://www.dartlang.org/docs/spec/).
+DartPad, code editors, and IDEs such as WebStorm use the same
+analysis engine that dartanalyzer uses.
+
+If you want to _contribute_ to the dartanalyzer project, see the
+[contributor docs](https://github.com/dart-lang/analyzer_cli/blob/master/CONTRIBUTOR.md).
+This page contains information about _using_ the dartanalyzer command-line tool.
+
+## Basic usage
+
+Run the analyzer from the top directory of the package.
+Here's an example of testing a Dart file.
+
+```
+dartanalyzer bin/test.dart
+```
+
+## Options
+
+The following are the most commonly used options for dartanalyzer:
+
+* `--packages=`<br>
+ Specify the path to the package resolution configuration file.
+ For more information see
+ [Package Resolution Configuration File](https://github.com/lrhn/dep-pkgspec/blob/master/DEP-pkgspec.md).
+This option cannot be used with `--package-root`.
+
+* `--package-warnings`<br>
+  Show warnings not only for code in the specified .dart file and
+  others in its library, but also for libraries imported with `package:`.
+
+* `--options=`<br>
+  Specify the path to an analysis options file.
+
+* `--lints`<br>
+  Show the results from the linter.
+
+* `--no-hints`<br>
+  Don't show hints for improving the code.
+
+* `--ignore-unrecognized-flags`<br>
+  Rather than printing the help message,
+  ignore any unrecognized command-line flags.
+
+* `--version`<br>
+  Show the analyzer version.
+
+* `-h` _or_ `--help`<br>
+  Show all the command-line options.
+
+The following are advanced options to use with dartanalyzer:
+
+* `-b` _or_ `--batch`<br>
+  Run in batch mode.
+
+* `--dart-sdk=`<br>
+  Specify the directory that contains the Dart SDK.
+
+* `--fatal-warnings`<br>
+  Except for type warnings, treat warnings as fatal.
+
+* `--format=machine`<br>
+  Produce output in a format suitable for parsing.
+
+* `--url-mapping=libraryUri,/path/to/library.dart`<br>
+  Tells the analyzer to use the specified library as the source
+  for that particular import.
+
+The following options are deprecated:
+
+* `-p` _or_ `--package-root=`<br>
+  **Deprecated.** Specify the directory to search for any libraries that are
+  imported using `package:`. _This option is replaced as of Dart 1.12 with
+  `--packages`._
+
+* `--machine`<br>
+  **Deprecated.** Replaced by `--format`.
+
+* `--show-package-warnings`<br>
+  **Deprecated.** Replaced by `--package-warnings`.
+
+* `--show-sdk-warnings`<br>
+  **Deprecated.** Replaced by `--warnings`.
diff --git a/pkg/analyzer_cli/bin/analyzer.dart b/pkg/analyzer_cli/bin/analyzer.dart
new file mode 100644
index 0000000..b0a32fe
--- /dev/null
+++ b/pkg/analyzer_cli/bin/analyzer.dart
@@ -0,0 +1,16 @@
+#!/usr/bin/env dart
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_cli/src/driver.dart';
+
+
+
+
+/// The entry point for the analyzer.
+void main(List<String> args) {
+  var starter = new Driver();
+  starter.start(args);
+  
+}
diff --git a/pkg/analyzer_cli/lib/src/analyzer_impl.dart b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
new file mode 100644
index 0000000..32d5f37
--- /dev/null
+++ b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
@@ -0,0 +1,303 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.src.analyzer_impl;
+
+import 'dart:collection';
+import 'dart:io';
+
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/java_io.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';
+import 'package:analyzer_cli/src/driver.dart';
+import 'package:analyzer_cli/src/error_formatter.dart';
+import 'package:analyzer_cli/src/options.dart';
+
+DirectoryBasedDartSdk sdk;
+
+/// The maximum number of sources for which AST structures should be kept in the cache.
+const int _maxCacheSize = 512;
+
+int currentTimeMillis() => new DateTime.now().millisecondsSinceEpoch;
+
+/// Analyzes single library [File].
+class AnalyzerImpl {
+  final CommandLineOptions options;
+  final int startTime;
+
+  final AnalysisContext context;
+  final Source librarySource;
+
+  /// All [Source]s references by the analyzed library.
+  final Set<Source> sources = new Set<Source>();
+
+  /// All [AnalysisErrorInfo]s in the analyzed library.
+  final List<AnalysisErrorInfo> errorInfos = new List<AnalysisErrorInfo>();
+
+  /// [HashMap] between sources and analysis error infos.
+  final HashMap<Source, AnalysisErrorInfo> sourceErrorsMap =
+      new HashMap<Source, AnalysisErrorInfo>();
+
+  /// If the file specified on the command line is part of a package, the name
+  /// of that package.  Otherwise `null`.  This allows us to analyze the file
+  /// specified on the command line as though it is reached via a "package:"
+  /// URI, but avoid suppressing its output in the event that the user has not
+  /// specified the "--package-warnings" option.
+  String _selfPackageName;
+
+  AnalyzerImpl(this.context, this.librarySource, this.options, this.startTime);
+
+  /// Returns the maximal [ErrorSeverity] of the recorded errors.
+  ErrorSeverity get maxErrorSeverity {
+    var status = ErrorSeverity.NONE;
+    for (AnalysisErrorInfo errorInfo in errorInfos) {
+      for (AnalysisError error in errorInfo.errors) {
+        if (!_isDesiredError(error)) {
+          continue;
+        }
+        var severity = computeSeverity(error, options);
+        status = status.max(severity);
+      }
+    }
+    return status;
+  }
+
+  void addCompilationUnitSource(CompilationUnitElement unit,
+      Set<LibraryElement> libraries, Set<CompilationUnitElement> units) {
+    if (unit == null || units.contains(unit)) {
+      return;
+    }
+    units.add(unit);
+    sources.add(unit.source);
+  }
+
+  void addLibrarySources(LibraryElement library, Set<LibraryElement> libraries,
+      Set<CompilationUnitElement> units) {
+    if (library == null || !libraries.add(library)) {
+      return;
+    }
+    // Maybe skip library.
+    {
+      UriKind uriKind = library.source.uriKind;
+      // Optionally skip package: libraries.
+      if (!options.showPackageWarnings && _isOtherPackage(library.source.uri)) {
+        return;
+      }
+      // Optionally skip SDK libraries.
+      if (!options.showSdkWarnings && uriKind == UriKind.DART_URI) {
+        return;
+      }
+    }
+    // Add compilation units.
+    addCompilationUnitSource(library.definingCompilationUnit, libraries, units);
+    for (CompilationUnitElement child in library.parts) {
+      addCompilationUnitSource(child, libraries, units);
+    }
+    // Add referenced libraries.
+    for (LibraryElement child in library.importedLibraries) {
+      addLibrarySources(child, libraries, units);
+    }
+    for (LibraryElement child in library.exportedLibraries) {
+      addLibrarySources(child, libraries, units);
+    }
+  }
+
+  /// Treats the [sourcePath] as the top level library and analyzes it using a
+  /// synchronous algorithm over the analysis engine. If [printMode] is `0`,
+  /// then no error or performance information is printed. If [printMode] is `1`,
+  /// then both will be printed. If [printMode] is `2`, then only performance
+  /// information will be printed, and it will be marked as being for a cold VM.
+  ErrorSeverity analyzeSync({int printMode: 1}) {
+    setupForAnalysis();
+    return _analyzeSync(printMode);
+  }
+
+  /// Fills [errorInfos] using [sources].
+  void prepareErrors() {
+    for (Source source in sources) {
+      context.computeErrors(source);
+
+      errorInfos.add(context.getErrors(source));
+    }
+  }
+
+  /// Fills [sources].
+  void prepareSources(LibraryElement library) {
+    var units = new Set<CompilationUnitElement>();
+    var libraries = new Set<LibraryElement>();
+    addLibrarySources(library, libraries, units);
+  }
+
+  /// Setup local fields such as the analysis context for analysis.
+  void setupForAnalysis() {
+    sources.clear();
+    errorInfos.clear();
+    Uri libraryUri = librarySource.uri;
+    if (libraryUri.scheme == 'package' && libraryUri.pathSegments.length > 0) {
+      _selfPackageName = libraryUri.pathSegments[0];
+    }
+  }
+
+  /// The sync version of analysis.
+  ErrorSeverity _analyzeSync(int printMode) {
+    // Don't try to analyze parts.
+    if (context.computeKindOf(librarySource) == SourceKind.PART) {
+      stderr.writeln("Only libraries can be analyzed.");
+      stderr.writeln(
+          "${librarySource.fullName} is a part and can not be analyzed.");
+      return ErrorSeverity.ERROR;
+    }
+    // Resolve library.
+    var libraryElement = context.computeLibraryElement(librarySource);
+    // Prepare source and errors.
+    prepareSources(libraryElement);
+    prepareErrors();
+
+    // Print errors and performance numbers.
+    if (printMode == 1) {
+      _printErrorsAndPerf();
+    } else if (printMode == 2) {
+      _printColdPerf();
+    }
+
+    // Compute max severity and set exitCode.
+    ErrorSeverity status = maxErrorSeverity;
+    if (status == ErrorSeverity.WARNING && options.warningsAreFatal) {
+      status = ErrorSeverity.ERROR;
+    }
+    return status;
+  }
+
+  bool _isDesiredError(AnalysisError error) {
+    if (error.errorCode.type == ErrorType.TODO) {
+      return false;
+    }
+    if (computeSeverity(error, options) == ErrorSeverity.INFO &&
+        options.disableHints) {
+      return false;
+    }
+    return true;
+  }
+
+  /// Determine whether the given URI refers to a package other than the package
+  /// being analyzed.
+  bool _isOtherPackage(Uri uri) {
+    if (uri.scheme != 'package') {
+      return false;
+    }
+    if (_selfPackageName != null &&
+        uri.pathSegments.length > 0 &&
+        uri.pathSegments[0] == _selfPackageName) {
+      return false;
+    }
+    return true;
+  }
+
+  _printColdPerf() {
+    // Print cold VM performance numbers.
+    int totalTime = currentTimeMillis() - startTime;
+    int otherTime = totalTime;
+    for (PerformanceTag tag in PerformanceTag.all) {
+      if (tag != PerformanceTag.UNKNOWN) {
+        int tagTime = tag.elapsedMs;
+        outSink.writeln('${tag.label}-cold:$tagTime');
+        otherTime -= tagTime;
+      }
+    }
+    outSink.writeln('other-cold:$otherTime');
+    outSink.writeln("total-cold:$totalTime");
+  }
+
+  _printErrorsAndPerf() {
+    // The following is a hack. We currently print out to stderr to ensure that
+    // when in batch mode we print to stderr, this is because the prints from
+    // batch are made to stderr. The reason that options.shouldBatch isn't used
+    // is because when the argument flags are constructed in BatchRunner and
+    // passed in from batch mode which removes the batch flag to prevent the
+    // "cannot have the batch flag and source file" error message.
+    StringSink sink = options.machineFormat ? errorSink : outSink;
+
+    // Print errors.
+    ErrorFormatter formatter =
+        new ErrorFormatter(sink, options, _isDesiredError);
+    formatter.formatErrors(errorInfos);
+  }
+
+  /// Compute the severity of the error; however:
+  ///   * if [options.enableTypeChecks] is false, then de-escalate checked-mode
+  ///   compile time errors to a severity of [ErrorSeverity.INFO].
+  ///   * if [options.hintsAreFatal] is true, escalate hints to errors.
+  static ErrorSeverity computeSeverity(
+      AnalysisError error, CommandLineOptions options) {
+    if (!options.enableTypeChecks &&
+        error.errorCode.type == ErrorType.CHECKED_MODE_COMPILE_TIME_ERROR) {
+      return ErrorSeverity.INFO;
+    }
+    if (options.hintsAreFatal && error.errorCode is HintCode) {
+      return ErrorSeverity.ERROR;
+    }
+    return error.errorCode.errorSeverity;
+  }
+
+  /// Return the corresponding package directory or `null` if none is found.
+  static JavaFile getPackageDirectoryFor(JavaFile sourceFile) {
+    // We are going to ask parent file, so get absolute path.
+    sourceFile = sourceFile.getAbsoluteFile();
+    // Look in the containing directories.
+    JavaFile dir = sourceFile.getParentFile();
+    while (dir != null) {
+      JavaFile packagesDir = new JavaFile.relative(dir, "packages");
+      if (packagesDir.exists()) {
+        return packagesDir;
+      }
+      dir = dir.getParentFile();
+    }
+    // Not found.
+    return null;
+  }
+}
+
+/// This [Logger] prints out information comments to [outSink] and error messages
+/// to [errorSink].
+class StdLogger extends Logger {
+  StdLogger();
+
+  @override
+  void logError(String message, [CaughtException exception]) {
+    errorSink.writeln(message);
+    if (exception != null) {
+      errorSink.writeln(exception);
+    }
+  }
+
+  @override
+  void logError2(String message, Object exception) {
+    errorSink.writeln(message);
+    if (exception != null) {
+      errorSink.writeln(exception.toString());
+    }
+  }
+
+  @override
+  void logInformation(String message, [CaughtException exception]) {
+    outSink.writeln(message);
+    if (exception != null) {
+      outSink.writeln(exception);
+    }
+  }
+
+  @override
+  void logInformation2(String message, Object exception) {
+    outSink.writeln(message);
+    if (exception != null) {
+      outSink.writeln(exception.toString());
+    }
+  }
+}
diff --git a/pkg/analyzer_cli/lib/src/bootloader.dart b/pkg/analyzer_cli/lib/src/bootloader.dart
new file mode 100644
index 0000000..726004cb3
--- /dev/null
+++ b/pkg/analyzer_cli/lib/src/bootloader.dart
@@ -0,0 +1,196 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.src.bootloader;
+
+import 'dart:async';
+import 'dart:isolate';
+
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/source/analysis_options_provider.dart';
+import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/generated/engine.dart' as engine;
+import 'package:analyzer/src/plugin/plugin_configuration.dart';
+import 'package:analyzer_cli/src/driver.dart';
+import 'package:analyzer_cli/src/options.dart';
+import 'package:source_span/source_span.dart';
+import 'package:yaml/src/yaml_node.dart';
+
+const _analyzerPackageName = 'analyzer';
+
+/// Return non-null if there is a validation issue with this plugin.
+String validate(PluginInfo plugin) {
+  var missing = <String>[];
+  if (plugin.className == null) {
+    missing.add('class name');
+  }
+  if (plugin.libraryUri == null) {
+    missing.add('library uri');
+  }
+  if (missing.isEmpty) {
+    // All good.
+    return null;
+  }
+  return 'Plugin ${plugin.name} skipped, config missing: ${missing.join(", ")}';
+}
+
+List<PluginInfo> _validate(Iterable<PluginInfo> plugins) {
+  List<PluginInfo> validated = <PluginInfo>[];
+  plugins.forEach((PluginInfo plugin) {
+    String validation = validate(plugin);
+    if (validation != null) {
+      errorSink.writeln(validation);
+    } else {
+      validated.add(plugin);
+    }
+  });
+  return validated;
+}
+
+/// Source code assembler.
+class Assembler {
+  /// Plugins to configure.
+  final Iterable<PluginInfo> plugins;
+
+  /// Create an assembler for the given plugin [config].
+  Assembler(this.plugins);
+
+  /// A string enumerating required package `import`s.
+  String get enumerateImports =>
+      plugins.map((PluginInfo p) => "import '${p.libraryUri}';").join('\n');
+
+  /// A string listing initialized plugin instances.
+  String get pluginList =>
+      plugins.map((PluginInfo p) => 'new ${p.className}()').join(', ');
+
+  /// Create a file containing a `main()` suitable for loading in spawned
+  /// isolate.
+  String createMain() => _generateMain();
+
+  String _generateMain() => """
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+import 'package:analyzer_cli/src/driver.dart';
+
+$enumerateImports
+
+void main(List<String> args) {
+  var starter = new Driver();
+  starter.userDefinedPlugins = [$pluginList];
+  starter.start(args);
+}
+""";
+}
+
+/// Given environment information extracted from command-line `args`, creates a
+/// a loadable analyzer "image".
+class BootLoader {
+  /// Emits an error message to [errorSink] if plugin config can't be read.
+  static final ErrorHandler _pluginConfigErrorHandler = (Exception e) {
+    String details;
+    if (e is PluginConfigFormatException) {
+      details = e.message;
+      var node = e.yamlNode;
+      if (node is YamlNode) {
+        SourceLocation location = node.span.start;
+        details += ' (line ${location.line}, column ${location.column})';
+      }
+    } else {
+      details = e.toString();
+    }
+
+    errorSink.writeln('Plugin configuration skipped: $details');
+  };
+
+  /// Reads plugin config info from `.analysis_options`.
+  PluginConfigOptionsProcessor _pluginOptionsProcessor =
+      new PluginConfigOptionsProcessor(_pluginConfigErrorHandler);
+
+  /// Create a loadable analyzer image configured with plugins derived from
+  /// the given analyzer command-line `args`.
+  Image createImage(List<String> args) {
+    // Parse commandline options.
+    CommandLineOptions options = CommandLineOptions.parse(args);
+
+    // Process analysis options file (and notify all interested parties).
+    _processAnalysisOptions(options);
+
+    // TODO(pquitslund): Pass in .packages info
+    return new Image(_pluginOptionsProcessor.config,
+        args: args, packageRootPath: options.packageRootPath);
+  }
+
+  void _processAnalysisOptions(CommandLineOptions options) {
+    // Determine options file path.
+    var filePath = options.analysisOptionsFile ??
+        engine.AnalysisEngine.ANALYSIS_OPTIONS_FILE;
+    try {
+      var file = PhysicalResourceProvider.INSTANCE.getFile(filePath);
+      AnalysisOptionsProvider analysisOptionsProvider =
+          new AnalysisOptionsProvider();
+      Map<String, YamlNode> options =
+          analysisOptionsProvider.getOptionsFromFile(file);
+      //TODO(pq): thread in proper context.
+      var temporaryContext = new AnalysisContextImpl();
+      _pluginOptionsProcessor.optionsProcessed(temporaryContext, options);
+    } on Exception catch (e) {
+      _pluginOptionsProcessor.onError(e);
+    }
+  }
+}
+
+/// A loadable "image" of a a configured analyzer instance.
+class Image {
+  /// (Optional) package root path.
+  final String packageRootPath;
+
+  /// (Optional) package map.
+  final Map<String, Uri> packages;
+
+  /// (Optional) args to be passed on to the loaded main.
+  final List<String> args;
+
+  /// Plugin configuration.
+  final PluginConfig config;
+
+  /// Create an image with the given [config] and optionally [packages],
+  /// [packageRootPath], and command line [args].
+  Image(this.config, {this.packages, this.packageRootPath, this.args});
+
+  /// Load this image.
+  ///
+  /// Loading an image consists in assembling an analyzer `main()`, configured
+  /// to include the appropriate analyzer plugins as specified in
+  /// `.analyzer_options` which is then run in a spawned isolate.
+  Future load() {
+    List<PluginInfo> plugins = _validate(config.plugins);
+    String mainSource = new Assembler(plugins).createMain();
+
+    Completer completer = new Completer();
+    ReceivePort exitListener = new ReceivePort();
+    exitListener.listen((data) {
+      completer.complete();
+      exitListener.close();
+    });
+
+    Uri uri =
+        Uri.parse('data:application/dart;charset=utf-8,${Uri.encodeComponent(
+        mainSource)}');
+
+    // TODO(pquitslund): update once .packages are supported.
+    String packageRoot =
+        packageRootPath != null ? packageRootPath : './packages';
+    Uri packageUri = new Uri.file(packageRoot);
+
+    Isolate.spawnUri(uri, args, null /* msg */,
+        packageRoot: packageUri, onExit: exitListener.sendPort);
+
+    return completer.future;
+  }
+}
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
new file mode 100644
index 0000000..752cb1e
--- /dev/null
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -0,0 +1,641 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.src.driver;
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:analyzer/file_system/file_system.dart' as fileSystem;
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/plugin/options.dart';
+import 'package:analyzer/source/analysis_options_provider.dart';
+import 'package:analyzer/source/package_map_provider.dart';
+import 'package:analyzer/source/package_map_resolver.dart';
+import 'package:analyzer/source/pub_package_map_provider.dart';
+import 'package:analyzer/source/sdk_ext.dart';
+import 'package:analyzer/src/generated/constant.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
+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_io.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/services/lint.dart';
+import 'package:analyzer/src/task/options.dart';
+import 'package:analyzer_cli/src/analyzer_impl.dart';
+import 'package:analyzer_cli/src/options.dart';
+import 'package:linter/src/plugin/linter_plugin.dart';
+import 'package:package_config/discovery.dart' as pkgDiscovery;
+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;
+import 'package:path/path.dart' as path;
+import 'package:plugin/plugin.dart';
+import 'package:yaml/yaml.dart';
+
+/// The maximum number of sources for which AST structures should be kept in the
+/// cache.
+const int _maxCacheSize = 512;
+
+/// Shared IO sink for standard error reporting.
+///
+/// *Visible for testing.*
+StringSink errorSink = stderr;
+
+/// Shared IO sink for standard out reporting.
+///
+/// *Visible for testing.*
+StringSink outSink = stdout;
+
+/// Test this option map to see if it specifies lint rules.
+bool containsLintRuleEntry(Map<String, YamlNode> options) {
+  var linterNode = options['linter'];
+  return linterNode is YamlMap && linterNode.containsKey('rules');
+}
+
+typedef ErrorSeverity _BatchRunnerHandler(List<String> args);
+
+class Driver {
+  /// The plugins that are defined outside the `analyzer_cli` package.
+  List<Plugin> _userDefinedPlugins = <Plugin>[];
+
+  /// Indicates whether the analyzer is running in batch mode.
+  bool _isBatch;
+
+  /// The context that was most recently created by a call to [_analyzeAll], or
+  /// `null` if [_analyzeAll] hasn't been called yet.
+  AnalysisContext _context;
+
+  /// If [_context] is not `null`, the [CommandLineOptions] that guided its
+  /// creation.
+  CommandLineOptions _previousOptions;
+
+  /// This Driver's current analysis context.
+  ///
+  /// *Visible for testing.*
+  AnalysisContext get context => _context;
+
+  /// Set the [plugins] that are defined outside the `analyzer_cli` package.
+  void set userDefinedPlugins(List<Plugin> plugins) {
+    _userDefinedPlugins = plugins == null ? <Plugin>[] : plugins;
+  }
+
+  /// Use the given command-line [args] to start this analysis driver.
+  void start(List<String> args) {
+    StringUtilities.INTERNER = new MappedInterner();
+
+    _processPlugins();
+
+    // Parse commandline options.
+    CommandLineOptions options = CommandLineOptions.parse(args);
+
+    // Cache options of interest to inform analysis.
+    _setupEnv(options);
+
+    // Do analysis.
+    if (_isBatch) {
+      _BatchRunner.runAsBatch(args, (List<String> args) {
+        CommandLineOptions options = CommandLineOptions.parse(args);
+        return _analyzeAll(options);
+      });
+    } else {
+      ErrorSeverity severity = _analyzeAll(options);
+      // In case of error propagate exit code.
+      if (severity == ErrorSeverity.ERROR) {
+        exitCode = severity.ordinal;
+      }
+    }
+  }
+
+  /// Perform analysis according to the given [options].
+  ErrorSeverity _analyzeAll(CommandLineOptions options) {
+    if (!options.machineFormat) {
+      outSink.writeln("Analyzing ${options.sourceFiles}...");
+    }
+
+    // Create a context, or re-use the previous one.
+    try {
+      _createAnalysisContext(options);
+    } on _DriverError catch (error) {
+      outSink.writeln(error.msg);
+      return ErrorSeverity.ERROR;
+    }
+
+    // Add all the files to be analyzed en masse to the context.  Skip any
+    // files that were added earlier (whether explicitly or implicitly) to
+    // avoid causing those files to be unnecessarily re-read.
+    Set<Source> knownSources = _context.sources.toSet();
+    List<Source> sourcesToAnalyze = <Source>[];
+    ChangeSet changeSet = new ChangeSet();
+    for (String sourcePath in options.sourceFiles) {
+      sourcePath = sourcePath.trim();
+      // Check that file exists.
+      if (!new File(sourcePath).existsSync()) {
+        errorSink.writeln('File not found: $sourcePath');
+        exitCode = ErrorSeverity.ERROR.ordinal;
+        //Fail fast; don't analyze more files
+        return ErrorSeverity.ERROR;
+      }
+      // Check that file is Dart file.
+      if (!AnalysisEngine.isDartFileName(sourcePath)) {
+        errorSink.writeln('$sourcePath is not a Dart file');
+        exitCode = ErrorSeverity.ERROR.ordinal;
+        // Fail fast; don't analyze more files.
+        return ErrorSeverity.ERROR;
+      }
+      Source source = _computeLibrarySource(sourcePath);
+      if (!knownSources.contains(source)) {
+        changeSet.addedSource(source);
+      }
+      sourcesToAnalyze.add(source);
+    }
+    _context.applyChanges(changeSet);
+
+    // Analyze the libraries.
+    ErrorSeverity allResult = ErrorSeverity.NONE;
+    var libUris = <Uri>[];
+    var parts = <Source>[];
+    for (Source source in sourcesToAnalyze) {
+      if (context.computeKindOf(source) == SourceKind.PART) {
+        parts.add(source);
+        continue;
+      }
+      ErrorSeverity status = _runAnalyzer(source, options);
+      allResult = allResult.max(status);
+      libUris.add(source.uri);
+    }
+
+    // Check that each part has a corresponding source in the input list.
+    for (Source part in parts) {
+      bool found = false;
+      for (var lib in context.getLibrariesContaining(part)) {
+        if (libUris.contains(lib.uri)) {
+          found = true;
+        }
+      }
+      if (!found) {
+        errorSink.writeln("${part.fullName} is a part and cannot be analyzed.");
+        errorSink.writeln("Please pass in a library that contains this part.");
+        exitCode = ErrorSeverity.ERROR.ordinal;
+        allResult = allResult.max(ErrorSeverity.ERROR);
+      }
+    }
+
+    return allResult;
+  }
+
+  /// Determine whether the context created during a previous call to
+  /// [_analyzeAll] can be re-used in order to analyze using [options].
+  bool _canContextBeReused(CommandLineOptions options) {
+    // TODO(paulberry): add a command-line option that disables context re-use.
+    if (_context == null) {
+      return false;
+    }
+    if (options.packageRootPath != _previousOptions.packageRootPath) {
+      return false;
+    }
+    if (options.packageConfigPath != _previousOptions.packageConfigPath) {
+      return false;
+    }
+    if (!_equalMaps(
+        options.definedVariables, _previousOptions.definedVariables)) {
+      return false;
+    }
+    if (options.log != _previousOptions.log) {
+      return false;
+    }
+    if (options.disableHints != _previousOptions.disableHints) {
+      return false;
+    }
+    if (options.enableStrictCallChecks !=
+        _previousOptions.enableStrictCallChecks) {
+      return false;
+    }
+    if (options.showPackageWarnings != _previousOptions.showPackageWarnings) {
+      return false;
+    }
+    if (options.showSdkWarnings != _previousOptions.showSdkWarnings) {
+      return false;
+    }
+    if (options.lints != _previousOptions.lints) {
+      return false;
+    }
+    if (options.strongMode != _previousOptions.strongMode) {
+      return false;
+    }
+    if (options.enableSuperMixins != _previousOptions.enableSuperMixins) {
+      return false;
+    }
+    return true;
+  }
+
+  /// Decide on the appropriate policy for which files need to be fully parsed
+  /// and which files need to be diet parsed, based on [options], and return an
+  /// [AnalyzeFunctionBodiesPredicate] that implements this policy.
+  AnalyzeFunctionBodiesPredicate _chooseDietParsingPolicy(
+      CommandLineOptions options) {
+    if (_isBatch) {
+      // As analyzer is currently implemented, once a file has been diet
+      // parsed, it can't easily be un-diet parsed without creating a brand new
+      // context and losing caching.  In batch mode, we can't predict which
+      // files we'll need to generate errors and warnings for in the future, so
+      // we can't safely diet parse anything.
+      return (Source source) => true;
+    }
+
+    // Determine the set of packages requiring a full parse.  Use null to
+    // represent the case where all packages require a full parse.
+    Set<String> packagesRequiringFullParse;
+    if (options.showPackageWarnings) {
+      // We are showing warnings from all packages so all packages require a
+      // full parse.
+      packagesRequiringFullParse = null;
+    } else {
+      // We aren't showing warnings for dependent packages, but we may still
+      // need to show warnings for "self" packages, so we need to do a full
+      // parse in any package containing files mentioned on the command line.
+      // TODO(paulberry): implement this.  As a temporary workaround, we're
+      // fully parsing all packages.
+      packagesRequiringFullParse = null;
+    }
+    return (Source source) {
+      if (source.uri.scheme == 'dart') {
+        return options.showSdkWarnings;
+      } else if (source.uri.scheme == 'package') {
+        if (packagesRequiringFullParse == null) {
+          return true;
+        } else if (source.uri.pathSegments.length == 0) {
+          // We should never see a URI like this, but fully parse it to be
+          // safe.
+          return true;
+        } else {
+          return packagesRequiringFullParse
+              .contains(source.uri.pathSegments[0]);
+        }
+      } else {
+        return true;
+      }
+    };
+  }
+
+  /// 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) {
+    Packages packages;
+    Map<String, List<fileSystem.Folder>> packageMap;
+    UriResolver packageUriResolver;
+
+    // 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);
+
+      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 {
+        // Fall back to pub list-package-dirs.
+
+        PubPackageMapProvider pubPackageMapProvider =
+            new PubPackageMapProvider(PhysicalResourceProvider.INSTANCE, sdk);
+        PackageMapInfo packageMapInfo =
+            pubPackageMapProvider.computePackageMap(cwd);
+        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
+        // to resolve packages.
+        if (packageMapInfo.packageMap != null) {
+          packageUriResolver = new PackageMapUriResolver(
+              PhysicalResourceProvider.INSTANCE, packageMap);
+        }
+      }
+    }
+
+    // Now, build our resolver list.
+
+    // 'dart:' URIs come first.
+    List<UriResolver> resolvers = [new DartUriResolver(sdk)];
+
+    // Next SdkExts.
+    if (packageMap != null) {
+      resolvers.add(new SdkExtUriResolver(packageMap));
+    }
+
+    // Then package URIs.
+    if (packageUriResolver != null) {
+      resolvers.add(packageUriResolver);
+    }
+
+    // Finally files.
+    resolvers.add(new FileUriResolver());
+
+    return new SourceFactory(resolvers, packages);
+  }
+
+  /// Convert the given [sourcePath] (which may be relative to the current
+  /// working directory) to a [Source] object that can be fed to the analysis
+  /// context.
+  Source _computeLibrarySource(String sourcePath) {
+    sourcePath = _normalizeSourcePath(sourcePath);
+    JavaFile sourceFile = new JavaFile(sourcePath);
+    Source source = sdk.fromFileUri(sourceFile.toURI());
+    if (source != null) {
+      return source;
+    }
+    source = new FileBasedSource(sourceFile, sourceFile.toURI());
+    Uri uri = _context.sourceFactory.restoreUri(source);
+    if (uri == null) {
+      return source;
+    }
+    return new FileBasedSource(sourceFile, uri);
+  }
+
+  /// Create an analysis context that is prepared to analyze sources according
+  /// to the given [options], and store it in [_context].
+  void _createAnalysisContext(CommandLineOptions options) {
+    if (_canContextBeReused(options)) {
+      return;
+    }
+    _previousOptions = options;
+    // Choose a package resolution policy and a diet parsing policy based on
+    // the command-line options.
+    SourceFactory sourceFactory = _chooseUriResolutionPolicy(options);
+    AnalyzeFunctionBodiesPredicate dietParsingPolicy =
+        _chooseDietParsingPolicy(options);
+    // Create a context using these policies.
+    AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
+
+    context.sourceFactory = sourceFactory;
+
+    Map<String, String> definedVariables = options.definedVariables;
+    if (!definedVariables.isEmpty) {
+      DeclaredVariables declaredVariables = context.declaredVariables;
+      definedVariables.forEach((String variableName, String value) {
+        declaredVariables.define(variableName, value);
+      });
+    }
+
+    if (options.log) {
+      AnalysisEngine.instance.logger = new StdLogger();
+    }
+
+    // Set context options.
+    AnalysisOptionsImpl contextOptions = new AnalysisOptionsImpl();
+    contextOptions.cacheSize = _maxCacheSize;
+    contextOptions.hint = !options.disableHints;
+    contextOptions.enableStrictCallChecks = options.enableStrictCallChecks;
+    contextOptions.enableSuperMixins = options.enableSuperMixins;
+    contextOptions.analyzeFunctionBodiesPredicate = dietParsingPolicy;
+    contextOptions.generateImplicitErrors = options.showPackageWarnings;
+    contextOptions.generateSdkErrors = options.showSdkWarnings;
+    contextOptions.lint = options.lints;
+    contextOptions.strongMode = options.strongMode;
+    context.analysisOptions = contextOptions;
+    _context = context;
+
+    // Process analysis options file (and notify all interested parties).
+    _processAnalysisOptions(options, context);
+  }
+
+  /// Return discovered packagespec, or `null` if none is found.
+  Packages _discoverPackagespec(Uri root) {
+    try {
+      Packages packages = pkgDiscovery.findPackagesFromFile(root);
+      if (packages != Packages.noPackages) {
+        return packages;
+      }
+    } catch (_) {
+      // Ignore and fall through to null.
+    }
+
+    return null;
+  }
+
+  fileSystem.File _getOptionsFile(CommandLineOptions options) {
+    fileSystem.File file;
+    String filePath = options.analysisOptionsFile;
+    if (filePath != null) {
+      file = PhysicalResourceProvider.INSTANCE.getFile(filePath);
+      if (!file.exists) {
+        printAndFail('Options file not found: $filePath',
+            exitCode: ErrorSeverity.ERROR.ordinal);
+      }
+    } else {
+      filePath = AnalysisEngine.ANALYSIS_OPTIONS_FILE;
+      file = PhysicalResourceProvider.INSTANCE.getFile(filePath);
+    }
+    return file;
+  }
+
+  Map<String, List<fileSystem.Folder>> _getPackageMap(Packages packages) {
+    if (packages == null) {
+      return null;
+    }
+
+    Map<String, List<fileSystem.Folder>> folderMap =
+        new Map<String, List<fileSystem.Folder>>();
+    packages.asMap().forEach((String packagePath, Uri uri) {
+      folderMap[packagePath] = [
+        PhysicalResourceProvider.INSTANCE.getFolder(path.fromUri(uri))
+      ];
+    });
+    return folderMap;
+  }
+
+  void _processAnalysisOptions(
+      CommandLineOptions options, AnalysisContext context) {
+    fileSystem.File file = _getOptionsFile(options);
+    List<OptionsProcessor> optionsProcessors =
+        AnalysisEngine.instance.optionsPlugin.optionsProcessors;
+    try {
+      AnalysisOptionsProvider analysisOptionsProvider =
+          new AnalysisOptionsProvider();
+      Map<String, YamlNode> optionMap =
+          analysisOptionsProvider.getOptionsFromFile(file);
+      optionsProcessors.forEach(
+          (OptionsProcessor p) => p.optionsProcessed(context, optionMap));
+
+      // Fill in lint rule defaults in case lints are enabled and rules are
+      // not specified in an options file.
+      if (options.lints && !containsLintRuleEntry(optionMap)) {
+        setLints(context, linterPlugin.contributedRules);
+      }
+
+      // Ask engine to further process options.
+      if (optionMap != null) {
+        configureContextOptions(context, optionMap);
+      }
+    } on Exception catch (e) {
+      optionsProcessors.forEach((OptionsProcessor p) => p.onError(e));
+    }
+  }
+
+  void _processPlugins() {
+    List<Plugin> plugins = <Plugin>[];
+    plugins.add(linterPlugin);
+    plugins.addAll(_userDefinedPlugins);
+    AnalysisEngine.instance.userDefinedPlugins = plugins;
+
+    // This ensures that AE extension manager processes plugins.
+    AnalysisEngine.instance.taskManager;
+  }
+
+  /// Analyze a single source.
+  ErrorSeverity _runAnalyzer(Source source, CommandLineOptions options) {
+    int startTime = currentTimeMillis();
+    AnalyzerImpl analyzer =
+        new AnalyzerImpl(_context, source, options, startTime);
+    var errorSeverity = analyzer.analyzeSync();
+    if (errorSeverity == ErrorSeverity.ERROR) {
+      exitCode = errorSeverity.ordinal;
+    }
+    if (options.warningsAreFatal && errorSeverity == ErrorSeverity.WARNING) {
+      exitCode = errorSeverity.ordinal;
+    }
+    return errorSeverity;
+  }
+
+  void _setupEnv(CommandLineOptions options) {
+    // In batch mode, SDK is specified on the main command line rather than in
+    // the command lines sent to stdin.  So process it before deciding whether
+    // to activate batch mode.
+    if (sdk == null) {
+      sdk = new DirectoryBasedDartSdk(new JavaFile(options.dartSdkPath));
+    }
+    _isBatch = options.shouldBatch;
+  }
+
+  /// Perform a deep comparison of two string maps.
+  static bool _equalMaps(Map<String, String> m1, Map<String, String> m2) {
+    if (m1.length != m2.length) {
+      return false;
+    }
+    for (String key in m1.keys) {
+      if (!m2.containsKey(key) || m1[key] != m2[key]) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /// Convert [sourcePath] into an absolute path.
+  static String _normalizeSourcePath(String sourcePath) =>
+      path.normalize(new File(sourcePath).absolute.path);
+}
+
+/// Provides a framework to read command line options from stdin and feed them
+/// to a callback.
+class _BatchRunner {
+  /// Run the tool in 'batch' mode, receiving command lines through stdin and
+  /// returning pass/fail status through stdout. This feature is intended for
+  /// use in unit testing.
+  static void runAsBatch(List<String> sharedArgs, _BatchRunnerHandler handler) {
+    outSink.writeln('>>> BATCH START');
+    Stopwatch stopwatch = new Stopwatch();
+    stopwatch.start();
+    int testsFailed = 0;
+    int totalTests = 0;
+    ErrorSeverity batchResult = ErrorSeverity.NONE;
+    // Read line from stdin.
+    Stream cmdLine =
+        stdin.transform(UTF8.decoder).transform(new LineSplitter());
+    cmdLine.listen((String line) {
+      // Maybe finish.
+      if (line.isEmpty) {
+        var time = stopwatch.elapsedMilliseconds;
+        outSink.writeln(
+            '>>> BATCH END (${totalTests - testsFailed}/$totalTests) ${time}ms');
+        exitCode = batchResult.ordinal;
+      }
+      // Prepare aruments.
+      var args;
+      {
+        var lineArgs = line.split(new RegExp('\\s+'));
+        args = new List<String>();
+        args.addAll(sharedArgs);
+        args.addAll(lineArgs);
+        args.remove('-b');
+        args.remove('--batch');
+      }
+      // Analyze single set of arguments.
+      try {
+        totalTests++;
+        ErrorSeverity result = handler(args);
+        bool resultPass = result != ErrorSeverity.ERROR;
+        if (!resultPass) {
+          testsFailed++;
+        }
+        batchResult = batchResult.max(result);
+        // Write stderr end token and flush.
+        errorSink.writeln('>>> EOF STDERR');
+        String resultPassString = resultPass ? 'PASS' : 'FAIL';
+        outSink.writeln(
+            '>>> TEST $resultPassString ${stopwatch.elapsedMilliseconds}ms');
+      } catch (e, stackTrace) {
+        errorSink.writeln(e);
+        errorSink.writeln(stackTrace);
+        errorSink.writeln('>>> EOF STDERR');
+        outSink.writeln('>>> TEST CRASH');
+      }
+    });
+  }
+}
+
+class _DriverError implements Exception {
+  String msg;
+  _DriverError(this.msg);
+}
+
+/// [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(
+      String packageRootPath) {
+    var packageRoot = new Directory(packageRootPath);
+    if (!packageRoot.existsSync()) {
+      throw new _DriverError(
+          'Package root directory ($packageRootPath) does not exist.');
+    }
+    var packages = packageRoot.listSync(followLinks: false);
+    var result = new Map<String, List<fileSystem.Folder>>();
+    for (var package in packages) {
+      var packageName = path.basename(package.path);
+      var realPath = package.resolveSymbolicLinksSync();
+      result[packageName] = [
+        PhysicalResourceProvider.INSTANCE.getFolder(realPath)
+      ];
+    }
+    return result;
+  }
+}
diff --git a/pkg/analyzer_cli/lib/src/error_formatter.dart b/pkg/analyzer_cli/lib/src/error_formatter.dart
new file mode 100644
index 0000000..fe0f00f
--- /dev/null
+++ b/pkg/analyzer_cli/lib/src/error_formatter.dart
@@ -0,0 +1,196 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.src.error_formatter;
+
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer_cli/src/analyzer_impl.dart';
+import 'package:analyzer_cli/src/options.dart';
+
+/// Allows any [AnalysisError].
+bool _anyError(AnalysisError error) => true;
+
+/// Returns `true` if [AnalysisError] should be printed.
+typedef bool _ErrorFilter(AnalysisError error);
+
+/// Helper for formatting [AnalysisError]s.
+/// The two format options are a user consumable format and a machine consumable format.
+class ErrorFormatter {
+  final StringSink out;
+  final CommandLineOptions options;
+  final _ErrorFilter errorFilter;
+
+  ErrorFormatter(this.out, this.options, [this.errorFilter = _anyError]);
+
+  void formatError(
+      Map<AnalysisError, LineInfo> errorToLine, AnalysisError error) {
+    Source source = error.source;
+    LineInfo_Location location = errorToLine[error].getLocation(error.offset);
+    int length = error.length;
+    ErrorSeverity severity =
+        AnalyzerImpl.computeSeverity(error, options);
+    if (options.machineFormat) {
+      if (severity == ErrorSeverity.WARNING && options.warningsAreFatal) {
+        severity = ErrorSeverity.ERROR;
+      }
+      out.write(severity);
+      out.write('|');
+      out.write(error.errorCode.type);
+      out.write('|');
+      out.write(error.errorCode.name);
+      out.write('|');
+      out.write(escapePipe(source.fullName));
+      out.write('|');
+      out.write(location.lineNumber);
+      out.write('|');
+      out.write(location.columnNumber);
+      out.write('|');
+      out.write(length);
+      out.write('|');
+      out.write(escapePipe(error.message));
+    } else {
+      String errorType = severity.displayName;
+      if (error.errorCode.type == ErrorType.HINT ||
+          error.errorCode.type == ErrorType.LINT) {
+        errorType = error.errorCode.type.displayName;
+      }
+      // [warning] 'foo' is not a... (/Users/.../tmp/foo.dart, line 1, col 2)
+      out.write('[$errorType] ${error.message} ');
+      out.write('(${source.fullName}');
+      out.write(', line ${location.lineNumber}, col ${location.columnNumber})');
+    }
+    out.writeln();
+  }
+
+  void formatErrors(List<AnalysisErrorInfo> errorInfos) {
+    var errors = new List<AnalysisError>();
+    var errorToLine = new Map<AnalysisError, LineInfo>();
+    for (AnalysisErrorInfo errorInfo in errorInfos) {
+      for (AnalysisError error in errorInfo.errors) {
+        if (errorFilter(error)) {
+          errors.add(error);
+          errorToLine[error] = errorInfo.lineInfo;
+        }
+      }
+    }
+    // Sort errors.
+    errors.sort((AnalysisError error1, AnalysisError error2) {
+      // Severity.
+      ErrorSeverity severity1 =
+          AnalyzerImpl.computeSeverity(error1, options);
+      ErrorSeverity severity2 =
+          AnalyzerImpl.computeSeverity(error2, options);
+      int compare = severity2.compareTo(severity1);
+      if (compare != 0) {
+        return compare;
+      }
+      // Path.
+      compare = Comparable.compare(error1.source.fullName.toLowerCase(),
+          error2.source.fullName.toLowerCase());
+      if (compare != 0) {
+        return compare;
+      }
+      // Offset.
+      return error1.offset - error2.offset;
+    });
+    // Format errors.
+    int errorCount = 0;
+    int warnCount = 0;
+    int hintCount = 0;
+    int lintCount = 0;
+    for (AnalysisError error in errors) {
+      ErrorSeverity severity =
+          AnalyzerImpl.computeSeverity(error, options);
+      if (severity == ErrorSeverity.ERROR) {
+        errorCount++;
+      } else if (severity == ErrorSeverity.WARNING) {
+        if (options.warningsAreFatal) {
+          errorCount++;
+        } else {
+          warnCount++;
+        }
+      } else if (error.errorCode.type == ErrorType.HINT) {
+        hintCount++;
+      } else if (error.errorCode.type == ErrorType.LINT) {
+        lintCount++;
+      }
+      formatError(errorToLine, error);
+    }
+    // Print statistics.
+    if (!options.machineFormat) {
+      var hasErrors = errorCount != 0;
+      var hasWarns = warnCount != 0;
+      var hasHints = hintCount != 0;
+      var hasLints = lintCount != 0;
+      bool hasContent = false;
+      if (hasErrors) {
+        out.write(errorCount);
+        out.write(' ');
+        out.write(pluralize("error", errorCount));
+        hasContent = true;
+      }
+      if (hasWarns) {
+        if (hasContent) {
+          if (!hasHints && !hasLints) {
+            out.write(' and ');
+          } else {
+            out.write(", ");
+          }
+        }
+        out.write(warnCount);
+        out.write(' ');
+        out.write(pluralize("warning", warnCount));
+        hasContent = true;
+      }
+      if (hasHints) {
+        if (hasContent) {
+          if (!hasLints) {
+            out.write(' and ');
+          } else {
+            out.write(", ");
+          }
+        }
+        out.write(hintCount);
+        out.write(' ');
+        out.write(pluralize("hint", hintCount));
+        hasContent = true;
+      }
+      if (hasLints) {
+        if (hasContent) {
+          out.write(" and ");
+        }
+        out.write(lintCount);
+        out.write(' ');
+        out.write(pluralize("lint", lintCount));
+        hasContent = true;
+      }
+      if (hasContent) {
+        out.writeln(" found.");
+      } else {
+        out.writeln("No issues found");
+      }
+    }
+  }
+
+  static String escapePipe(String input) {
+    var result = new StringBuffer();
+    for (var c in input.codeUnits) {
+      if (c == '\\' || c == '|') {
+        result.write('\\');
+      }
+      result.writeCharCode(c);
+    }
+    return result.toString();
+  }
+
+  static String pluralize(String word, int count) {
+    if (count == 1) {
+      return word;
+    } else {
+      return word + "s";
+    }
+  }
+}
diff --git a/pkg/analyzer_cli/lib/src/options.dart b/pkg/analyzer_cli/lib/src/options.dart
new file mode 100644
index 0000000..ee683e2
--- /dev/null
+++ b/pkg/analyzer_cli/lib/src/options.dart
@@ -0,0 +1,485 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.src.options;
+
+import 'dart:io';
+
+import 'package:analyzer_cli/src/driver.dart';
+import 'package:args/args.dart';
+import 'package:cli_util/cli_util.dart' show getSdkDir;
+
+const _binaryName = 'dartanalyzer';
+
+/// Shared exit handler.
+///
+/// *Visible for testing.*
+ExitHandler exitHandler = exit;
+
+/// Print the given message to stderr and exit with the given [exitCode]
+void printAndFail(String message, {int exitCode: 15}) {
+  errorSink.writeln(message);
+  exitHandler(exitCode);
+}
+
+/// Exit handler.
+///
+/// *Visible for testing.*
+typedef void ExitHandler(int code);
+
+/// Analyzer commandline configuration options.
+class CommandLineOptions {
+  /// The path to an analysis options file
+  final String analysisOptionsFile;
+
+  /// The path to the dart SDK
+  String dartSdkPath;
+
+  /// A table mapping the names of defined variables to their values.
+  final Map<String, String> definedVariables;
+
+  /// Whether to report hints
+  final bool disableHints;
+
+  /// Whether to display version information
+  final bool displayVersion;
+
+  /// Whether to enable null-aware operators (DEP 9).
+  final bool enableNullAwareOperators;
+
+  /// Whether to strictly follow the specification when generating warnings on
+  /// "call" methods (fixes dartbug.com/21938).
+  final bool enableStrictCallChecks;
+
+  /// Whether to relax restrictions on mixins (DEP 34).
+  final bool enableSuperMixins;
+
+  /// Whether to treat type mismatches found during constant evaluation as
+  /// errors.
+  final bool enableTypeChecks;
+
+  /// Whether to treat hints as fatal
+  final bool hintsAreFatal;
+
+  /// Whether to ignore unrecognized flags
+  final bool ignoreUnrecognizedFlags;
+
+  /// Whether to report lints
+  final bool lints;
+
+  /// Whether to log additional analysis messages and exceptions
+  final bool log;
+
+  /// Whether to use machine format for error display
+  final bool machineFormat;
+
+  /// The path to the package root
+  final String packageRootPath;
+
+  /// The path to a `.packages` configuration file
+  final String packageConfigPath;
+
+  /// Batch mode (for unit testing)
+  final bool shouldBatch;
+
+  /// Whether to show package: warnings
+  final bool showPackageWarnings;
+
+  /// Whether to show SDK warnings
+  final bool showSdkWarnings;
+
+  /// The source files to analyze
+  final List<String> sourceFiles;
+
+  /// Whether to treat warnings as fatal
+  final bool warningsAreFatal;
+
+  /// Whether to use strong static checking.
+  final bool strongMode;
+
+  /// Initialize options from the given parsed [args].
+  CommandLineOptions._fromArgs(
+      ArgResults args, Map<String, String> definedVariables)
+      : dartSdkPath = args['dart-sdk'],
+        this.definedVariables = definedVariables,
+        analysisOptionsFile = args['options'],
+        disableHints = args['no-hints'],
+        displayVersion = args['version'],
+        enableNullAwareOperators = args['enable-null-aware-operators'],
+        enableStrictCallChecks = args['enable-strict-call-checks'],
+        enableSuperMixins = args['supermixin'],
+        enableTypeChecks = args['enable_type_checks'],
+        hintsAreFatal = args['fatal-hints'],
+        ignoreUnrecognizedFlags = args['ignore-unrecognized-flags'],
+        lints = args['lints'],
+        log = args['log'],
+        machineFormat = args['machine'] || args['format'] == 'machine',
+        packageConfigPath = args['packages'],
+        packageRootPath = args['package-root'],
+        shouldBatch = args['batch'],
+        showPackageWarnings =
+            args['show-package-warnings'] || args['package-warnings'],
+        showSdkWarnings = args['show-sdk-warnings'] || args['warnings'],
+        sourceFiles = args.rest,
+        warningsAreFatal = args['fatal-warnings'],
+        strongMode = args['strong'];
+
+  /// Parse [args] into [CommandLineOptions] describing the specified
+  /// analyzer options. In case of a format error, calls [printAndFail], which
+  /// by default prints an error message to stderr and exits.
+  static CommandLineOptions parse(List<String> args,
+      [printAndFail = printAndFail]) {
+    CommandLineOptions options = _parse(args);
+    // Check SDK.
+    {
+      // Infer if unspecified.
+      if (options.dartSdkPath == null) {
+        Directory sdkDir = getSdkDir(args);
+        if (sdkDir != null) {
+          options.dartSdkPath = sdkDir.path;
+        }
+      }
+
+      var sdkPath = options.dartSdkPath;
+
+      // Check that SDK is specified.
+      if (sdkPath == null) {
+        printAndFail('No Dart SDK found.');
+      }
+      // Check that SDK is existing directory.
+      if (!(new Directory(sdkPath)).existsSync()) {
+        printAndFail('Invalid Dart SDK path: $sdkPath');
+      }
+    }
+
+    // Check package config.
+    {
+      if (options.packageRootPath != null &&
+          options.packageConfigPath != null) {
+        printAndFail("Cannot specify both '--package-root' and '--packages.");
+      }
+    }
+
+    // OK.  Report deprecated options.
+    if (options.enableNullAwareOperators) {
+      stderr.writeln(
+          "Info: Option '--enable-null-aware-operators' is no longer needed. Null aware operators are supported by default.");
+    }
+
+    return options;
+  }
+
+  static String _getVersion() {
+    try {
+      // This is relative to bin/snapshot, so ../..
+      String versionPath =
+          Platform.script.resolve('../../version').toFilePath();
+      File versionFile = new File(versionPath);
+      return versionFile.readAsStringSync().trim();
+    } catch (_) {
+      // This happens when the script is not running in the context of an SDK.
+      return "<unknown>";
+    }
+  }
+
+  static CommandLineOptions _parse(List<String> args) {
+    args = args.expand((String arg) => arg.split('=')).toList();
+    var parser = new CommandLineParser()
+      ..addFlag('batch',
+          abbr: 'b',
+          help: 'Read commands from standard input (for testing).',
+          defaultsTo: false,
+          negatable: false)
+      ..addOption('dart-sdk', help: 'The path to the Dart SDK.')
+      ..addOption('packages',
+          help:
+              'Path to the package resolution configuration file, which supplies a mapping of package names to paths.  This option cannot be used with --package-root.')
+      ..addOption('package-root',
+          abbr: 'p',
+          help:
+              'Path to a package root directory (deprecated). This option cannot be used with --packages.')
+      ..addOption('options', help: 'Path to an analysis options file.')
+      ..addOption('format',
+          help: 'Specifies the format in which errors are displayed.')
+      ..addFlag('machine',
+          help: 'Print errors in a format suitable for parsing (deprecated).',
+          defaultsTo: false,
+          negatable: false)
+      ..addFlag('version',
+          help: 'Print the analyzer version.',
+          defaultsTo: false,
+          negatable: false)
+      ..addFlag('lints',
+          help: 'Show lint results.', defaultsTo: false, negatable: false)
+      ..addFlag('no-hints',
+          help: 'Do not show hint results.',
+          defaultsTo: false,
+          negatable: false)
+      ..addFlag('ignore-unrecognized-flags',
+          help: 'Ignore unrecognized command line flags.',
+          defaultsTo: false,
+          negatable: false)
+      ..addFlag('fatal-hints',
+          help: 'Treat hints as fatal.', defaultsTo: false, negatable: false)
+      ..addFlag('fatal-warnings',
+          help: 'Treat non-type warnings as fatal.',
+          defaultsTo: false,
+          negatable: false)
+      ..addFlag('package-warnings',
+          help: 'Show warnings from package: imports.',
+          defaultsTo: false,
+          negatable: false)
+      ..addFlag('show-package-warnings',
+          help: 'Show warnings from package: imports (deprecated).',
+          defaultsTo: false,
+          negatable: false)
+      ..addFlag('warnings',
+          help: 'Show warnings from SDK imports.',
+          defaultsTo: false,
+          negatable: false)
+      ..addFlag('show-sdk-warnings',
+          help: 'Show warnings from SDK imports (deprecated).',
+          defaultsTo: false,
+          negatable: false)
+      ..addFlag('help',
+          abbr: 'h',
+          help: 'Display this help message.',
+          defaultsTo: false,
+          negatable: false)
+      ..addOption('url-mapping',
+          help: '--url-mapping=libraryUri,/path/to/library.dart directs the '
+              'analyzer to use "library.dart" as the source for an import '
+              'of "libraryUri".',
+          allowMultiple: true,
+          splitCommas: false)
+      //
+      // Hidden flags.
+      //
+      ..addFlag('enable-async',
+          help: 'Enable support for the proposed async feature.',
+          defaultsTo: false,
+          negatable: false,
+          hide: true)
+      ..addFlag('enable-enum',
+          help: 'Enable support for the proposed enum feature.',
+          defaultsTo: false,
+          negatable: false,
+          hide: true)
+      ..addFlag('enable-null-aware-operators',
+          help: 'Enable support for null-aware operators (DEP 9).',
+          defaultsTo: false,
+          negatable: false,
+          hide: true)
+      ..addFlag('enable-strict-call-checks',
+          help: 'Fix issue 21938.',
+          defaultsTo: false,
+          negatable: false,
+          hide: true)
+      ..addFlag('enable-new-task-model',
+          help: 'Ennable new task model.',
+          defaultsTo: false,
+          negatable: false,
+          hide: true)
+      ..addFlag('supermixin',
+          help: 'Relax restrictions on mixins (DEP 34).',
+          defaultsTo: false,
+          negatable: false,
+          hide: true)
+      ..addFlag('log',
+          help: 'Log additional messages and exceptions.',
+          defaultsTo: false,
+          negatable: false,
+          hide: true)
+      ..addFlag('enable_type_checks',
+          help: 'Check types in constant evaluation.',
+          defaultsTo: false,
+          negatable: false,
+          hide: true)
+      ..addFlag('strong',
+          help: 'Enable strong static checks (https://goo.gl/DqcBsw)');
+
+    try {
+      // TODO(scheglov) https://code.google.com/p/dart/issues/detail?id=11061
+      args =
+          args.map((String arg) => arg == '-batch' ? '--batch' : arg).toList();
+      Map<String, String> definedVariables = <String, String>{};
+      var results = parser.parse(args, definedVariables);
+      // Help requests.
+      if (results['help']) {
+        _showUsage(parser);
+        exit(0);
+      }
+      // Batch mode and input files.
+      if (results['batch']) {
+        if (results.rest.isNotEmpty) {
+          stderr.writeln('No source files expected in the batch mode.');
+          _showUsage(parser);
+          exit(15);
+        }
+      } else if (results['version']) {
+        print('$_binaryName version ${_getVersion()}');
+        exit(0);
+      } else {
+        if (results.rest.isEmpty) {
+          _showUsage(parser);
+          exit(15);
+        }
+      }
+      return new CommandLineOptions._fromArgs(results, definedVariables);
+    } on FormatException catch (e) {
+      stderr.writeln(e.message);
+      _showUsage(parser);
+      exit(15);
+    }
+  }
+
+  static _showUsage(parser) {
+    stderr
+        .writeln('Usage: $_binaryName [options...] <libraries to analyze...>');
+    stderr.writeln(parser.getUsage());
+    stderr.writeln('');
+    stderr.writeln(
+        'For more information, see http://www.dartlang.org/tools/analyzer.');
+  }
+}
+
+/// Commandline argument parser.
+///
+/// TODO(pquitslund): when the args package supports ignoring unrecognized
+/// options/flags, this class can be replaced with a simple [ArgParser]
+/// instance.
+class CommandLineParser {
+  final List<String> _knownFlags;
+  final bool _alwaysIgnoreUnrecognized;
+  final ArgParser _parser;
+
+  /// Creates a new command line parser.
+  CommandLineParser({bool alwaysIgnoreUnrecognized: false})
+      : _knownFlags = <String>[],
+        _alwaysIgnoreUnrecognized = alwaysIgnoreUnrecognized,
+        _parser = new ArgParser(allowTrailingOptions: true);
+
+  ArgParser get parser => _parser;
+
+  /// Defines a flag.
+  /// See [ArgParser.addFlag()].
+  void addFlag(String name,
+      {String abbr,
+      String help,
+      bool defaultsTo: false,
+      bool negatable: true,
+      void callback(bool value),
+      bool hide: false}) {
+    _knownFlags.add(name);
+    _parser.addFlag(name,
+        abbr: abbr,
+        help: help,
+        defaultsTo: defaultsTo,
+        negatable: negatable,
+        callback: callback,
+        hide: hide);
+  }
+
+  /// Defines a value-taking option.
+  /// See [ArgParser.addOption()].
+  void addOption(String name,
+      {String abbr,
+      String help,
+      List<String> allowed,
+      Map<String, String> allowedHelp,
+      String defaultsTo,
+      void callback(value),
+      bool allowMultiple: false,
+      bool splitCommas}) {
+    _knownFlags.add(name);
+    _parser.addOption(name,
+        abbr: abbr,
+        help: help,
+        allowed: allowed,
+        allowedHelp: allowedHelp,
+        defaultsTo: defaultsTo,
+        callback: callback,
+        allowMultiple: allowMultiple,
+        splitCommas: splitCommas);
+  }
+
+  /// Generates a string displaying usage information for the defined options.
+  /// See [ArgParser.usage].
+  String getUsage() => _parser.usage;
+
+  /// Parses [args], a list of command-line arguments, matches them against the
+  /// flags and options defined by this parser, and returns the result. The
+  /// values of any defined variables are captured in the given map.
+  /// See [ArgParser].
+  ArgResults parse(List<String> args, Map<String, String> definedVariables) =>
+      _parser.parse(
+          _filterUnknowns(parseDefinedVariables(args, definedVariables)));
+
+  List<String> parseDefinedVariables(
+      List<String> args, Map<String, String> definedVariables) {
+    int count = args.length;
+    List<String> remainingArgs = <String>[];
+    for (int i = 0; i < count; i++) {
+      String arg = args[i];
+      if (arg == '--') {
+        while (i < count) {
+          remainingArgs.add(args[i++]);
+        }
+      } else if (arg.startsWith("-D")) {
+        definedVariables[arg.substring(2)] = args[++i];
+      } else {
+        remainingArgs.add(arg);
+      }
+    }
+    return remainingArgs;
+  }
+
+  List<String> _filterUnknowns(List<String> args) {
+    // Only filter args if the ignore flag is specified, or if
+    // _alwaysIgnoreUnrecognized was set to true.
+    if (_alwaysIgnoreUnrecognized ||
+        args.contains('--ignore-unrecognized-flags')) {
+      //TODO(pquitslund): replace w/ the following once library skew issues are
+      // sorted out
+      //return args.where((arg) => !arg.startsWith('--') ||
+      //  _knownFlags.contains(arg.substring(2)));
+
+      // Filter all unrecognized flags and options.
+      List<String> filtered = <String>[];
+      for (int i = 0; i < args.length; ++i) {
+        String arg = args[i];
+        if (arg.startsWith('--') && arg.length > 2) {
+          String option = arg.substring(2);
+          // strip the last '=value'
+          int equalsOffset = option.lastIndexOf('=');
+          if (equalsOffset != -1) {
+            option = option.substring(0, equalsOffset);
+          }
+          // Check the option
+          if (!_knownFlags.contains(option)) {
+            //"eat" params by advancing to the next flag/option
+            i = _getNextFlagIndex(args, i);
+          } else {
+            filtered.add(arg);
+          }
+        } else {
+          filtered.add(arg);
+        }
+      }
+
+      return filtered;
+    } else {
+      return args;
+    }
+  }
+
+  int _getNextFlagIndex(args, i) {
+    for (; i < args.length; ++i) {
+      if (args[i].startsWith('--')) {
+        return i;
+      }
+    }
+    return i;
+  }
+}
diff --git a/pkg/analyzer_cli/lib/src/plugin/plugin_manager.dart b/pkg/analyzer_cli/lib/src/plugin/plugin_manager.dart
new file mode 100644
index 0000000..13a8202
--- /dev/null
+++ b/pkg/analyzer_cli/lib/src/plugin/plugin_manager.dart
@@ -0,0 +1,110 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.src.plugin.plugin_manager;
+
+import 'dart:io';
+
+import 'package:analyzer/src/plugin/plugin_configuration.dart';
+import 'package:path/path.dart' as path;
+
+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.
+PluginInfo combine(PluginInfo localConfig, PluginInfo manifestInfo) {
+  return new PluginInfo(
+      name: localConfig.name,
+      version: manifestInfo.version,
+      className: manifestInfo.className,
+      libraryUri: manifestInfo.libraryUri);
+}
+
+/// Call-back to allow for the injection of manifest readers that do not need
+/// to go to disk (for testing purposes).
+typedef String ManifestReader(Uri uri);
+
+/// Wraps a [plugin] info object elaborated with any configuration information
+/// extracted from an associated manifest and [status].
+class PluginDetails {
+  /// Plugin status.
+  final PluginStatus status;
+
+  /// Plugin info.
+  final PluginInfo plugin;
+
+  /// Wrap a [plugin] with [status] info.
+  PluginDetails(this.plugin) : status = PluginStatus.Applicable;
+  PluginDetails.notApplicable(this.plugin)
+      : status = PluginStatus.NotApplicable;
+  PluginDetails.notFound(this.plugin) : status = PluginStatus.NotFound;
+}
+
+/// Manages plugin information derived from plugin manifests.
+class PluginManager {
+  /// Mapping from package name to package location.
+  final Map<String, Uri> _packageMap;
+
+  /// The package naming the app to host plugins.
+  final String hostPackage;
+
+  /// Function to perform the reading of manifest URIs. (For testing.)
+  ManifestReader _manifestReader;
+
+  /// Create a plugin manager with backing package map information.
+  PluginManager(this._packageMap, this.hostPackage,
+      [ManifestReader manifestReader]) {
+    _manifestReader =
+        manifestReader != null ? manifestReader : _findAndReadManifestAtUri;
+  }
+
+  /// Find a plugin manifest describing the given [pluginPackage].
+  PluginManifest findManifest(String pluginPackage) {
+    Uri uri = _packageMap[pluginPackage];
+    String contents = _manifestReader(uri);
+    if (contents == null) {
+      return null;
+    }
+    return parsePluginManifestString(contents);
+  }
+
+  /// Return [PluginDetails] derived from associated plugin manifests
+  /// corresponding to plugins specified in the given [config].
+  Iterable<PluginDetails> getPluginDetails(PluginConfig config) =>
+      config.plugins.map((PluginInfo localConfig) {
+        PluginManifest manifest = findManifest(localConfig.name);
+        return _getDetails(localConfig, manifest);
+      });
+
+  String _findAndReadManifestAtUri(Uri uri) {
+    File manifestFile = _findManifest(uri);
+    return manifestFile?.readAsStringSync();
+  }
+
+  File _findManifest(Uri uri) {
+    if (uri == null) {
+      return null;
+    }
+
+    Directory directory = new Directory.fromUri(uri);
+    File file = new File(path.join(directory.path, _manifestFileName));
+
+    return file.existsSync() ? file : null;
+  }
+
+  PluginDetails _getDetails(PluginInfo localConfig, PluginManifest manifest) {
+    if (manifest == null) {
+      return new PluginDetails.notFound(localConfig);
+    }
+    if (!manifest.contributesTo.contains(hostPackage)) {
+      return new PluginDetails.notApplicable(localConfig);
+    }
+
+    return new PluginDetails(combine(localConfig, manifest.plugin));
+  }
+}
+
+/// Describes plugin status.
+enum PluginStatus { Applicable, NotApplicable, NotFound }
diff --git a/pkg/analyzer_cli/pubspec.yaml b/pkg/analyzer_cli/pubspec.yaml
new file mode 100644
index 0000000..bc255ee
--- /dev/null
+++ b/pkg/analyzer_cli/pubspec.yaml
@@ -0,0 +1,18 @@
+name: analyzer_cli
+version: 1.1.2
+author: Dart Team <misc@dartlang.org>
+description: Command line interface for the Dart Analyzer.
+homepage: https://github.com/dart-lang/analyzer_cli
+environment:
+  sdk: '>=1.12.0 <2.0.0'
+dependencies:
+  analyzer: ^0.26.1+17
+  args: ^0.13.0
+  cli_util: ^0.0.1
+  linter: ^0.1.3+4
+  package_config: ^0.1.1
+  plugin: ^0.1.0
+  yaml: ^2.1.2
+dev_dependencies:
+  typed_mock: '>=0.0.4 <1.0.0'
+  unittest: '>=0.9.0 <0.12.0'
diff --git a/pkg/analyzer_cli/test/all.dart b/pkg/analyzer_cli/test/all.dart
new file mode 100644
index 0000000..5b08f58
--- /dev/null
+++ b/pkg/analyzer_cli/test/all.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'driver_test.dart' as driver;
+import 'error_test.dart' as error;
+import 'options_test.dart' as options;
+import 'plugin_manager_test.dart' as plugin_manager;
+import 'reporter_test.dart' as reporter;
+import 'sdk_ext_test.dart' as sdk_ext;
+import 'strong_mode_test.dart' as strong_mode;
+import 'super_mixin_test.dart' as super_mixin;
+
+main() {
+  // TODO(pq): fix tests to run safely on the bots
+  // https://github.com/dart-lang/sdk/issues/25001
+  //driver.main();
+  //sdk_ext.main();
+  //strong_mode.main();
+  error.main();
+  options.main();
+  plugin_manager.main();
+  reporter.main();
+  super_mixin.main();
+}
diff --git a/pkg/analyzer_cli/test/data/angular_options.yaml b/pkg/analyzer_cli/test/data/angular_options.yaml
new file mode 100644
index 0000000..e17c22a
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/angular_options.yaml
@@ -0,0 +1,7 @@
+analyzer:
+  plugins:
+    angular2_analyzer_plugin:
+      path: /Users/pquitslund/src/git/clones/angular2-dart-analyzer/analyzer_plugin/
+      class_name: AngularAnalyzerPlugin
+      library_uri: package:angular2_analyzer_plugin/plugin.dart
+    
\ No newline at end of file
diff --git a/pkg/analyzer_cli/test/data/bad_plugin_options.yaml b/pkg/analyzer_cli/test/data/bad_plugin_options.yaml
new file mode 100644
index 0000000..9a389b0
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/bad_plugin_options.yaml
@@ -0,0 +1,6 @@
+analyzer:
+  plugins:
+    - lists
+    - are
+    - not
+    - supported
diff --git a/pkg/analyzer_cli/test/data/empty_options.yaml b/pkg/analyzer_cli/test/data/empty_options.yaml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/empty_options.yaml
diff --git a/pkg/analyzer_cli/test/data/file_with_error.dart b/pkg/analyzer_cli/test/data/file_with_error.dart
new file mode 100644
index 0000000..6b4f997
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/file_with_error.dart
@@ -0,0 +1,3 @@
+
+error
+
diff --git a/pkg/analyzer_cli/test/data/file_with_hint.dart b/pkg/analyzer_cli/test/data/file_with_hint.dart
new file mode 100644
index 0000000..7c46754
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/file_with_hint.dart
@@ -0,0 +1,3 @@
+main() {
+  int unused;
+}
diff --git a/pkg/analyzer_cli/test/data/file_with_warning.dart b/pkg/analyzer_cli/test/data/file_with_warning.dart
new file mode 100644
index 0000000..6f21a74
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/file_with_warning.dart
@@ -0,0 +1,3 @@
+main() {
+  undefined();
+}
diff --git a/pkg/analyzer_cli/test/data/library_and_parts/lib.dart b/pkg/analyzer_cli/test/data/library_and_parts/lib.dart
new file mode 100644
index 0000000..a1ff776
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/library_and_parts/lib.dart
@@ -0,0 +1,3 @@
+library example;
+
+part 'part1.dart';
diff --git a/pkg/analyzer_cli/test/data/library_and_parts/part1.dart b/pkg/analyzer_cli/test/data/library_and_parts/part1.dart
new file mode 100644
index 0000000..f2fe166
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/library_and_parts/part1.dart
@@ -0,0 +1 @@
+part of example;
diff --git a/pkg/analyzer_cli/test/data/library_and_parts/part2.dart b/pkg/analyzer_cli/test/data/library_and_parts/part2.dart
new file mode 100644
index 0000000..47f4917
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/library_and_parts/part2.dart
@@ -0,0 +1 @@
+part of nothing;
diff --git a/pkg/analyzer_cli/test/data/linter_project/.analysis_options b/pkg/analyzer_cli/test/data/linter_project/.analysis_options
new file mode 100644
index 0000000..6af57a5
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/linter_project/.analysis_options
@@ -0,0 +1,3 @@
+linter:
+  rules:
+    - camel_case_types
diff --git a/pkg/analyzer_cli/test/data/linter_project/test_file.dart b/pkg/analyzer_cli/test/data/linter_project/test_file.dart
new file mode 100644
index 0000000..c1726a8
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/linter_project/test_file.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.data.linter_project.test_file;
+
+class a {}
diff --git a/pkg/analyzer_cli/test/data/no_lints_project/.analysis_options b/pkg/analyzer_cli/test/data/no_lints_project/.analysis_options
new file mode 100644
index 0000000..1bb8bf6
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/no_lints_project/.analysis_options
@@ -0,0 +1 @@
+# empty
diff --git a/pkg/analyzer_cli/test/data/no_lints_project/test_file.dart b/pkg/analyzer_cli/test/data/no_lints_project/test_file.dart
new file mode 100644
index 0000000..93088d6
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/no_lints_project/test_file.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.data.no_lints_project.test_file;
+
+class a {}
diff --git a/pkg/analyzer_cli/test/data/no_packages_file/sdk_ext_user.dart b/pkg/analyzer_cli/test/data/no_packages_file/sdk_ext_user.dart
new file mode 100644
index 0000000..b346f7f
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/no_packages_file/sdk_ext_user.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:foo';
+
+main() {
+  // import of 'dart:foo' should resolve to a file which defines bar().
+  bar();
+}
diff --git a/pkg/analyzer_cli/test/data/options_tests_project/.analysis_options b/pkg/analyzer_cli/test/data/options_tests_project/.analysis_options
new file mode 100644
index 0000000..ebd4e64
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/options_tests_project/.analysis_options
@@ -0,0 +1,5 @@
+analyzer:
+  errors:
+    unused_local_variable: ignore
+  language:
+    enableSuperMixins: true
diff --git a/pkg/analyzer_cli/test/data/options_tests_project/test_file.dart b/pkg/analyzer_cli/test/data/options_tests_project/test_file.dart
new file mode 100644
index 0000000..e8f168b
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/options_tests_project/test_file.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.data.options_test_project.test_file;
+
+class a {}
diff --git a/pkg/analyzer_cli/test/data/package_with_sdk_extension/lib/_sdkext b/pkg/analyzer_cli/test/data/package_with_sdk_extension/lib/_sdkext
new file mode 100644
index 0000000..71160ea
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/package_with_sdk_extension/lib/_sdkext
@@ -0,0 +1,3 @@
+{
+  "dart:foo": "foo.dart"
+}
diff --git a/pkg/analyzer_cli/test/data/package_with_sdk_extension/lib/foo.dart b/pkg/analyzer_cli/test/data/package_with_sdk_extension/lib/foo.dart
new file mode 100644
index 0000000..c56eef9
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/package_with_sdk_extension/lib/foo.dart
@@ -0,0 +1,5 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+void bar() {}
diff --git a/pkg/analyzer_cli/test/data/packages_file/sdk_ext_user.dart b/pkg/analyzer_cli/test/data/packages_file/sdk_ext_user.dart
new file mode 100644
index 0000000..b346f7f
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/packages_file/sdk_ext_user.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:foo';
+
+main() {
+  // import of 'dart:foo' should resolve to a file which defines bar().
+  bar();
+}
diff --git a/pkg/analyzer_cli/test/data/plugin_options.yaml b/pkg/analyzer_cli/test/data/plugin_options.yaml
new file mode 100644
index 0000000..483e76f
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/plugin_options.yaml
@@ -0,0 +1,7 @@
+analyzer:
+  plugins:
+    my_plugin1:
+      version: any
+      library_uri: 'package:my_plugin/my_plugin.dart'
+      class_name: MyPlugin
+    
\ No newline at end of file
diff --git a/pkg/analyzer_cli/test/data/strong_example.dart b/pkg/analyzer_cli/test/data/strong_example.dart
new file mode 100644
index 0000000..2f332cd
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/strong_example.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This produces an error with --strong enabled, but not otherwise.
+class MyIterable extends Iterable<String> {
+  // Error: invalid override
+  Iterator<Object> get iterator => [1, 2, 3].iterator;
+}
+
+main() {
+  var i = new MyIterable().iterator..moveNext();
+  print(i.current);
+
+  // Error: type check failed
+  List<String> list = <dynamic>[1, 2, 3];
+  print(list);
+}
diff --git a/pkg/analyzer_cli/test/data/super_mixin_example.dart b/pkg/analyzer_cli/test/data/super_mixin_example.dart
new file mode 100644
index 0000000..ea90486
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/super_mixin_example.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This produces errors normally, but --supermixin disables them.
+class Test extends Object with C {
+  void foo() {}
+}
+
+abstract class B {
+  void foo();
+}
+
+abstract class C extends B {
+  void bar() {
+    super.foo();
+  }
+}
diff --git a/pkg/analyzer_cli/test/data/test_file.dart b/pkg/analyzer_cli/test/data/test_file.dart
new file mode 100644
index 0000000..1ac3540
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/test_file.dart
@@ -0,0 +1,5 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.data.test_file;
diff --git a/pkg/analyzer_cli/test/data/test_options.yaml b/pkg/analyzer_cli/test/data/test_options.yaml
new file mode 100644
index 0000000..ae890ee
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/test_options.yaml
@@ -0,0 +1,2 @@
+test_plugin: 
+  foo: bar
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart
new file mode 100644
index 0000000..f313355
--- /dev/null
+++ b/pkg/analyzer_cli/test/driver_test.dart
@@ -0,0 +1,486 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.driver;
+
+import 'dart:io';
+
+import 'package:analyzer/plugin/options.dart';
+import 'package:analyzer/source/analysis_options_provider.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/plugin/plugin_configuration.dart';
+import 'package:analyzer/src/services/lint.dart';
+import 'package:analyzer_cli/src/bootloader.dart';
+import 'package:analyzer_cli/src/driver.dart';
+import 'package:analyzer_cli/src/options.dart';
+import 'package:path/path.dart' as path;
+import 'package:plugin/plugin.dart';
+import 'package:unittest/unittest.dart';
+import 'package:yaml/src/yaml_node.dart';
+
+// TODO(pq): fix tests to run safely on the bots
+// https://github.com/dart-lang/sdk/issues/25001
+main() {}
+_main() {
+  group('Driver', () {
+    StringSink savedOutSink, savedErrorSink;
+    int savedExitCode;
+    setUp(() {
+      savedOutSink = outSink;
+      savedErrorSink = errorSink;
+      savedExitCode = exitCode;
+      outSink = new StringBuffer();
+      errorSink = new StringBuffer();
+    });
+    tearDown(() {
+      outSink = savedOutSink;
+      errorSink = savedErrorSink;
+      exitCode = savedExitCode;
+    });
+
+    group('options', () {
+      test('custom processor', () {
+        Driver driver = new Driver();
+        TestProcessor processor = new TestProcessor();
+        driver.userDefinedPlugins = [new TestPlugin(processor)];
+        driver.start([
+          '--options',
+          'test/data/test_options.yaml',
+          'test/data/test_file.dart'
+        ]);
+        expect(processor.options['test_plugin'], isNotNull);
+        expect(processor.exception, isNull);
+      });
+    });
+
+    group('exit codes', () {
+      StringSink savedOutSink, savedErrorSink;
+      int savedExitCode;
+      ExitHandler savedExitHandler;
+      setUp(() {
+        savedOutSink = outSink;
+        savedErrorSink = errorSink;
+        savedExitCode = exitCode;
+        savedExitHandler = exitHandler;
+        exitHandler = (code) => exitCode = code;
+        outSink = new StringBuffer();
+        errorSink = new StringBuffer();
+      });
+      tearDown(() {
+        outSink = savedOutSink;
+        errorSink = savedErrorSink;
+        exitCode = savedExitCode;
+        exitHandler = savedExitHandler;
+      });
+
+      test('fatal hints', () {
+        drive('test/data/file_with_hint.dart', args: ['--fatal-hints']);
+        expect(exitCode, 3);
+      });
+
+      test('not fatal hints', () {
+        drive('test/data/file_with_hint.dart');
+        expect(exitCode, 0);
+      });
+
+      test('fatal errors', () {
+        drive('test/data/file_with_error.dart');
+        expect(exitCode, 3);
+      });
+
+      test('not fatal warnings', () {
+        drive('test/data/file_with_warning.dart');
+        expect(exitCode, 0);
+      });
+
+      test('fatal warnings', () {
+        drive('test/data/file_with_warning.dart', args: ['--fatal-warnings']);
+        expect(exitCode, 3);
+      });
+
+      test('missing options file', () {
+        drive('test/data/test_file.dart', options: 'test/data/NO_OPTIONS_HERE');
+        expect(exitCode, 3);
+      });
+
+      test('missing dart file', () {
+        drive('test/data/NO_DART_FILE_HERE.dart');
+        expect(exitCode, 3);
+      });
+
+      test('part file', () {
+        drive('test/data/library_and_parts/part2.dart');
+        expect(exitCode, 3);
+      });
+
+      test('non-dangling part file', () {
+        Driver driver = new Driver();
+        driver.start([
+          'test/data/library_and_parts/lib.dart',
+          'test/data/library_and_parts/part1.dart',
+        ]);
+        expect(exitCode, 0);
+      });
+
+      test('extra part file', () {
+        Driver driver = new Driver();
+        driver.start([
+          'test/data/library_and_parts/lib.dart',
+          'test/data/library_and_parts/part1.dart',
+          'test/data/library_and_parts/part2.dart',
+        ]);
+        expect(exitCode, 3);
+      });
+    });
+
+    group('linter', () {
+      group('lints in options', () {
+        StringSink savedOutSink;
+        Driver driver;
+
+        setUp(() {
+          savedOutSink = outSink;
+          outSink = new StringBuffer();
+
+          driver = new Driver();
+          driver.start([
+            '--options',
+            'test/data/linter_project/.analysis_options',
+            '--lints',
+            'test/data/linter_project/test_file.dart'
+          ]);
+        });
+        tearDown(() {
+          outSink = savedOutSink;
+        });
+
+        test('gets analysis options', () {
+          /// 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']));
+        });
+
+        test('generates lints', () {
+          expect(outSink.toString(),
+              contains('[lint] Name types using UpperCamelCase.'));
+        });
+      });
+
+      group('default lints', () {
+        StringSink savedOutSink;
+        Driver driver;
+
+        setUp(() {
+          savedOutSink = outSink;
+          outSink = new StringBuffer();
+
+          driver = new Driver();
+          driver.start([
+            '--lints',
+            'test/data/linter_project/test_file.dart',
+            '--options',
+            'test/data/linter_project/.analysis_options'
+          ]);
+        });
+        tearDown(() {
+          outSink = savedOutSink;
+        });
+
+        test('gets default lints', () {
+          /// 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'));
+        });
+
+        test('generates lints', () {
+          expect(outSink.toString(),
+              contains('[lint] Name types using UpperCamelCase.'));
+        });
+      });
+
+      group('no `--lints` flag (none in options)', () {
+        StringSink savedOutSink;
+        Driver driver;
+
+        setUp(() {
+          savedOutSink = outSink;
+          outSink = new StringBuffer();
+
+          driver = new Driver();
+          driver.start([
+            'test/data/no_lints_project/test_file.dart',
+            '--options',
+            'test/data/no_lints_project/.analysis_options'
+          ]);
+        });
+        tearDown(() {
+          outSink = savedOutSink;
+        });
+
+        test('lints disabled', () {
+          expect(driver.context.analysisOptions.lint, isFalse);
+        });
+
+        test('no registered lints', () {
+          expect(getLints(driver.context), isEmpty);
+        });
+
+        test('no generated warnings', () {
+          expect(outSink.toString(), contains('No issues found'));
+        });
+      });
+    });
+
+    test('containsLintRuleEntry', () {
+      Map<String, YamlNode> options;
+      options = parseOptions('''
+linter:
+  rules:
+    - foo
+        ''');
+      expect(containsLintRuleEntry(options), true);
+      options = parseOptions('''
+        ''');
+      expect(containsLintRuleEntry(options), false);
+      options = parseOptions('''
+linter:
+  rules:
+    # - foo
+        ''');
+      expect(containsLintRuleEntry(options), true);
+      options = parseOptions('''
+linter:
+ # rules:
+    # - foo
+        ''');
+      expect(containsLintRuleEntry(options), false);
+    });
+
+    group('options processing', () {
+      group('error filters', () {
+        StringSink savedOutSink;
+        Driver driver;
+
+        setUp(() {
+          savedOutSink = outSink;
+          outSink = new StringBuffer();
+
+          driver = new Driver();
+          driver.start([
+            'test/data/options_tests_project/test_file.dart',
+            '--options',
+            'test/data/options_tests_project/.analysis_options'
+          ]);
+        });
+        tearDown(() {
+          outSink = savedOutSink;
+        });
+
+        test('filters', () {
+          var filters =
+              driver.context.getConfigurationData(CONFIGURED_ERROR_FILTERS);
+          expect(filters, hasLength(1));
+
+          var unused_error = new AnalysisError(
+              new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [
+            ['x']
+          ]);
+          expect(filters.any((filter) => filter(unused_error)), isTrue);
+        });
+
+        test('language config', () {
+          expect(driver.context.analysisOptions.enableSuperMixins, isTrue);
+        });
+      });
+    });
+
+    group('in temp directory', () {
+      StringSink savedOutSink, savedErrorSink;
+      int savedExitCode;
+      Directory savedCurrentDirectory;
+      Directory tempDir;
+      setUp(() {
+        savedOutSink = outSink;
+        savedErrorSink = errorSink;
+        savedExitCode = exitCode;
+        outSink = new StringBuffer();
+        errorSink = new StringBuffer();
+        savedCurrentDirectory = Directory.current;
+        tempDir = Directory.systemTemp.createTempSync('analyzer_');
+      });
+      tearDown(() {
+        outSink = savedOutSink;
+        errorSink = savedErrorSink;
+        exitCode = savedExitCode;
+        Directory.current = savedCurrentDirectory;
+        tempDir.deleteSync(recursive: true);
+      });
+
+      test('packages folder', () {
+        Directory.current = tempDir;
+        new File(path.join(tempDir.path, 'test.dart')).writeAsStringSync('''
+import 'package:foo/bar.dart';
+main() {
+  baz();
+}
+        ''');
+        Directory packagesDir =
+            new Directory(path.join(tempDir.path, 'packages'));
+        packagesDir.createSync();
+        Directory fooDir = new Directory(path.join(packagesDir.path, 'foo'));
+        fooDir.createSync();
+        new File(path.join(fooDir.path, 'bar.dart')).writeAsStringSync('''
+void baz() {}
+        ''');
+        new Driver().start(['test.dart']);
+        expect(exitCode, 0);
+      });
+
+      test('no package resolution', () {
+        Directory.current = tempDir;
+        new File(path.join(tempDir.path, 'test.dart')).writeAsStringSync('''
+import 'package:path/path.dart';
+main() {}
+        ''');
+        new Driver().start(['test.dart']);
+        expect(exitCode, 3);
+        String stdout = outSink.toString();
+        expect(stdout, contains('[error] Target of URI does not exist'));
+        expect(stdout, contains('1 error found.'));
+        expect(errorSink.toString(), '');
+      });
+
+      test('bad package root', () {
+        new Driver().start(['--package-root', 'does/not/exist', 'test.dart']);
+        String stdout = outSink.toString();
+        expect(exitCode, 3);
+        expect(
+            stdout,
+            contains(
+                'Package root directory (does/not/exist) does not exist.'));
+      });
+    });
+  });
+  group('Bootloader', () {
+    group('plugin processing', () {
+      StringSink savedErrorSink;
+      setUp(() {
+        savedErrorSink = errorSink;
+        errorSink = new StringBuffer();
+      });
+      tearDown(() {
+        errorSink = savedErrorSink;
+      });
+      test('bad format', () {
+        BootLoader loader = new BootLoader();
+        loader.createImage([
+          '--options',
+          'test/data/bad_plugin_options.yaml',
+          'test/data/test_file.dart'
+        ]);
+        expect(
+            errorSink.toString(),
+            equals('Plugin configuration skipped: Unrecognized plugin config '
+                'format, expected `YamlMap`, got `YamlList` '
+                '(line 2, column 4)\n'));
+      });
+      test('plugin config', () {
+        BootLoader loader = new BootLoader();
+        Image image = loader.createImage([
+          '--options',
+          'test/data/plugin_options.yaml',
+          'test/data/test_file.dart'
+        ]);
+        var plugins = image.config.plugins;
+        expect(plugins, hasLength(1));
+        expect(plugins.first.name, equals('my_plugin1'));
+      });
+      group('plugin validation', () {
+        test('requires class name', () {
+          expect(
+              validate(new PluginInfo(
+                  name: 'test_plugin', libraryUri: 'my_package/foo.dart')),
+              isNotNull);
+        });
+        test('requires library URI', () {
+          expect(
+              validate(
+                  new PluginInfo(name: 'test_plugin', className: 'MyPlugin')),
+              isNotNull);
+        });
+        test('check', () {
+          expect(
+              validate(new PluginInfo(
+                  name: 'test_plugin',
+                  className: 'MyPlugin',
+                  libraryUri: 'my_package/foo.dart')),
+              isNull);
+        });
+      });
+    });
+  });
+}
+
+const emptyOptionsFile = 'test/data/empty_options.yaml';
+
+/// Start a driver for the given [source], optionally providing additional
+/// [args] and an [options] file path.  The value of [options] defaults to
+/// an empty options file to avoid unwanted configuration from an otherwise
+/// discovered options file.
+void drive(String source,
+        {String options: emptyOptionsFile,
+        List<String> args: const <String>[]}) =>
+    new Driver().start(['--options', options, source]..addAll(args));
+
+Map<String, YamlNode> parseOptions(String src) =>
+    new AnalysisOptionsProvider().getOptionsFromString(src);
+
+class TestPlugin extends Plugin {
+  TestProcessor processor;
+  TestPlugin(this.processor);
+
+  @override
+  String get uniqueIdentifier => 'test_plugin.core';
+
+  @override
+  void registerExtensionPoints(RegisterExtensionPoint register) {
+    // None
+  }
+
+  @override
+  void registerExtensions(RegisterExtension register) {
+    register(OPTIONS_PROCESSOR_EXTENSION_POINT_ID, processor);
+  }
+}
+
+class TestProcessor extends OptionsProcessor {
+  Map<String, YamlNode> options;
+  Exception exception;
+
+  @override
+  void onError(Exception exception) {
+    this.exception = exception;
+  }
+
+  @override
+  void optionsProcessed(
+      AnalysisContext context, Map<String, YamlNode> options) {
+    this.options = options;
+  }
+}
+
+class TestSource implements Source {
+  TestSource();
+
+  @override
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
diff --git a/pkg/analyzer_cli/test/error_test.dart b/pkg/analyzer_cli/test/error_test.dart
new file mode 100644
index 0000000..ad80133
--- /dev/null
+++ b/pkg/analyzer_cli/test/error_test.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+library analyzer_cli.test.error;
+
+import 'package:unittest/unittest.dart';
+
+import 'utils.dart';
+
+void main() {
+  group('error', () {
+    test("a valid Dart file doesn't throw any errors", () {
+      expect(errorsForFile('void main() => print("Hello, world!");'), isNull);
+    });
+
+    test("an empty Dart file doesn't throw any errors", () {
+      expect(errorsForFile(''), isNull);
+    });
+
+    test("an error on the first line", () {
+      expect(errorsForFile('void foo;\n'), equals(
+          "Error in test.dart: Variables cannot have a type of 'void'\n"));
+    });
+
+    test("an error on the last line", () {
+      expect(errorsForFile('\nvoid foo;'), equals(
+          "Error in test.dart: Variables cannot have a type of 'void'\n"));
+    });
+
+    test("an error in the middle", () {
+      expect(errorsForFile('\nvoid foo;\n'), equals(
+          "Error in test.dart: Variables cannot have a type of 'void'\n"));
+    });
+
+    var veryLongString = new List.filled(107, ' ').join('');
+
+    test("an error at the end of a very long line", () {
+      expect(errorsForFile('$veryLongString     void foo;'), equals(
+          "Error in test.dart: Variables cannot have a type of 'void'\n"));
+    });
+
+    test("an error at the beginning of a very long line", () {
+      expect(errorsForFile('void foo;     $veryLongString'), equals(
+          "Error in test.dart: Variables cannot have a type of 'void'\n"));
+    });
+
+    test("an error in the middle of a very long line", () {
+      expect(errorsForFile('$veryLongString void foo;$veryLongString'), equals(
+          "Error in test.dart: Variables cannot have a type of 'void'\n"));
+    });
+  });
+}
diff --git a/pkg/analyzer_cli/test/mocks.dart b/pkg/analyzer_cli/test/mocks.dart
new file mode 100644
index 0000000..794521c
--- /dev/null
+++ b/pkg/analyzer_cli/test/mocks.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.mocks;
+
+import 'package:analyzer/analyzer.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer_cli/src/options.dart';
+import 'package:typed_mock/typed_mock.dart';
+
+class MockAnalysisError extends TypedMock implements AnalysisError {
+  @override
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockAnalysisErrorInfo extends TypedMock implements AnalysisErrorInfo {
+  @override
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockCommandLineOptions extends TypedMock implements CommandLineOptions {
+  @override
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockErrorCode extends TypedMock implements ErrorCode {
+  @override
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockErrorType extends TypedMock implements ErrorType {
+  @override
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockLineInfo extends TypedMock implements LineInfo {
+  @override
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockLineInfo_Location extends TypedMock implements LineInfo_Location {
+  @override
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockSource extends TypedMock implements Source {
+  @override
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
diff --git a/pkg/analyzer_cli/test/options_test.dart b/pkg/analyzer_cli/test/options_test.dart
new file mode 100644
index 0000000..900747b
--- /dev/null
+++ b/pkg/analyzer_cli/test/options_test.dart
@@ -0,0 +1,190 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.options;
+
+import 'package:analyzer_cli/src/options.dart';
+import 'package:args/args.dart';
+import 'package:unittest/unittest.dart';
+
+main() {
+  group('CommandLineOptions', () {
+    group('parse', () {
+      test('defaults', () {
+        CommandLineOptions options =
+            CommandLineOptions.parse(['--dart-sdk', '.', 'foo.dart']);
+        expect(options, isNotNull);
+        expect(options.dartSdkPath, isNotNull);
+        expect(options.disableHints, isFalse);
+        expect(options.lints, isFalse);
+        expect(options.displayVersion, isFalse);
+        expect(options.enableStrictCallChecks, isFalse);
+        expect(options.enableSuperMixins, isFalse);
+        expect(options.enableTypeChecks, isFalse);
+        expect(options.hintsAreFatal, isFalse);
+        expect(options.ignoreUnrecognizedFlags, isFalse);
+        expect(options.log, isFalse);
+        expect(options.machineFormat, isFalse);
+        expect(options.packageRootPath, isNull);
+        expect(options.shouldBatch, isFalse);
+        expect(options.showPackageWarnings, isFalse);
+        expect(options.showSdkWarnings, isFalse);
+        expect(options.sourceFiles, equals(['foo.dart']));
+        expect(options.warningsAreFatal, isFalse);
+        expect(options.strongMode, isFalse);
+      });
+
+      test('batch', () {
+        CommandLineOptions options =
+            CommandLineOptions.parse(['--dart-sdk', '.', '--batch']);
+        expect(options.shouldBatch, isTrue);
+      });
+
+      test('defined variables', () {
+        CommandLineOptions options = CommandLineOptions
+            .parse(['--dart-sdk', '.', '-Dfoo=bar', 'foo.dart']);
+        expect(options.definedVariables['foo'], equals('bar'));
+        expect(options.definedVariables['bar'], isNull);
+      });
+
+      test('enable strict call checks', () {
+        CommandLineOptions options = CommandLineOptions.parse(
+            ['--dart-sdk', '.', '--enable-strict-call-checks', 'foo.dart']);
+        expect(options.enableStrictCallChecks, isTrue);
+      });
+
+      test('enable super mixins', () {
+        CommandLineOptions options = CommandLineOptions
+            .parse(['--dart-sdk', '.', '--supermixin', 'foo.dart']);
+        expect(options.enableSuperMixins, isTrue);
+      });
+
+      test('enable type checks', () {
+        CommandLineOptions options = CommandLineOptions
+            .parse(['--dart-sdk', '.', '--enable_type_checks', 'foo.dart']);
+        expect(options.enableTypeChecks, isTrue);
+      });
+
+      test('hintsAreFatal', () {
+        CommandLineOptions options = CommandLineOptions
+            .parse(['--dart-sdk', '.', '--fatal-hints', 'foo.dart']);
+        expect(options.hintsAreFatal, isTrue);
+      });
+
+      test('log', () {
+        CommandLineOptions options =
+            CommandLineOptions.parse(['--dart-sdk', '.', '--log', 'foo.dart']);
+        expect(options.log, isTrue);
+      });
+
+      test('machine format', () {
+        CommandLineOptions options = CommandLineOptions
+            .parse(['--dart-sdk', '.', '--format=machine', 'foo.dart']);
+        expect(options.machineFormat, isTrue);
+      });
+
+      test('no-hints', () {
+        CommandLineOptions options = CommandLineOptions
+            .parse(['--dart-sdk', '.', '--no-hints', 'foo.dart']);
+        expect(options.disableHints, isTrue);
+      });
+
+      test('options', () {
+        CommandLineOptions options = CommandLineOptions.parse(
+            ['--dart-sdk', '.', '--options', 'options.yaml', 'foo.dart']);
+        expect(options.analysisOptionsFile, equals('options.yaml'));
+      });
+
+      test('lints', () {
+        CommandLineOptions options = CommandLineOptions
+            .parse(['--dart-sdk', '.', '--lints', 'foo.dart']);
+        expect(options.lints, isTrue);
+      });
+
+      test('package root', () {
+        CommandLineOptions options = CommandLineOptions
+            .parse(['--dart-sdk', '.', '-p', 'bar', 'foo.dart']);
+        expect(options.packageRootPath, equals('bar'));
+      });
+
+      test('package warnings', () {
+        CommandLineOptions options = CommandLineOptions
+            .parse(['--dart-sdk', '.', '--package-warnings', 'foo.dart']);
+        expect(options.showPackageWarnings, isTrue);
+      });
+
+      test('sdk warnings', () {
+        CommandLineOptions options = CommandLineOptions
+            .parse(['--dart-sdk', '.', '--warnings', 'foo.dart']);
+        expect(options.showSdkWarnings, isTrue);
+      });
+
+      test('sourceFiles', () {
+        CommandLineOptions options = CommandLineOptions.parse(
+            ['--dart-sdk', '.', '--log', 'foo.dart', 'foo2.dart', 'foo3.dart']);
+        expect(options.sourceFiles,
+            equals(['foo.dart', 'foo2.dart', 'foo3.dart']));
+      });
+
+      test('warningsAreFatal', () {
+        CommandLineOptions options = CommandLineOptions
+            .parse(['--dart-sdk', '.', '--fatal-warnings', 'foo.dart']);
+        expect(options.warningsAreFatal, isTrue);
+      });
+
+      test('notice unrecognized flags', () {
+        expect(
+            () => new CommandLineParser()
+                .parse(['--bar', '--baz', 'foo.dart'], {}),
+            throwsA(new isInstanceOf<FormatException>()));
+      });
+
+      test('ignore unrecognized flags', () {
+        CommandLineOptions options = CommandLineOptions.parse([
+          '--ignore-unrecognized-flags',
+          '--bar',
+          '--baz',
+          '--dart-sdk',
+          '.',
+          'foo.dart'
+        ]);
+        expect(options, isNotNull);
+        expect(options.sourceFiles, equals(['foo.dart']));
+      });
+
+      test('ignore unrecognized options', () {
+        CommandLineParser parser =
+            new CommandLineParser(alwaysIgnoreUnrecognized: true);
+        parser.addOption('optionA');
+        parser.addFlag('flagA');
+        ArgResults argResults =
+            parser.parse(['--optionA=1', '--optionB=2', '--flagA'], {});
+        expect(argResults['optionA'], '1');
+        expect(argResults['flagA'], isTrue);
+      });
+
+      test('strong mode', () {
+        CommandLineOptions options = CommandLineOptions
+            .parse(['--strong', 'foo.dart']);
+        expect(options.strongMode, isTrue);
+      });
+
+      test("can't specify package and package-root", () {
+        var failureMessage;
+        CommandLineOptions.parse(
+            ['--package-root', '.', '--packages', '.', 'foo.dart'],
+            (msg) => failureMessage = msg);
+        expect(failureMessage,
+            equals("Cannot specify both '--package-root' and '--packages."));
+      });
+
+      test("bad SDK dir", () {
+        var failureMessage;
+        CommandLineOptions.parse(
+            ['--dart-sdk', '&&&&&', 'foo.dart'], (msg) => failureMessage = msg);
+        expect(failureMessage, equals('Invalid Dart SDK path: &&&&&'));
+      });
+    });
+  });
+}
diff --git a/pkg/analyzer_cli/test/plugin_manager_test.dart b/pkg/analyzer_cli/test/plugin_manager_test.dart
new file mode 100644
index 0000000..16280b2
--- /dev/null
+++ b/pkg/analyzer_cli/test/plugin_manager_test.dart
@@ -0,0 +1,93 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.plugin_manager_test;
+
+import 'package:analyzer/src/plugin/plugin_configuration.dart';
+import 'package:analyzer_cli/src/plugin/plugin_manager.dart';
+import 'package:unittest/unittest.dart';
+
+main() {
+  group('plugin manager tests', () {
+    test('combine plugin info', () {
+      PluginInfo localInfo = new PluginInfo(name: 'my_plugin');
+      PluginInfo manifestInfo = new PluginInfo(
+          className: 'MyPlugin', libraryUri: 'my_plugin/my_plugin.dart');
+
+      PluginInfo merged = combine(localInfo, manifestInfo);
+      expect(merged.name, equals('my_plugin'));
+      expect(merged.className, equals('MyPlugin'));
+      expect(merged.libraryUri, equals('my_plugin/my_plugin.dart'));
+    });
+
+    test('find manifest', () {
+      const manifestSrc = '''
+library_uri: 'my_plugin/my_plugin.dart'
+''';
+      var packageMap = {'my_plugin': new Uri.file('my_plugin')};
+
+      PluginManager pm =
+          new PluginManager(packageMap, 'analyzer', (Uri uri) => manifestSrc);
+
+      PluginManifest manifest = pm.findManifest('my_plugin');
+      expect(manifest, isNotNull);
+      expect(manifest.plugin.libraryUri, equals('my_plugin/my_plugin.dart'));
+    });
+
+    final plugin1Uri = new Uri.file('my_plugin1');
+    final plugin2Uri = new Uri.file('my_plugin2');
+    final plugin3Uri = new Uri.file('my_plugin3');
+
+    const serverPluginManifest = '''
+library_uri: 'my_plugin2/my_plugin2.dart'
+contributes_to: analysis_server
+''';
+    const analyzerPluginManifest = '''
+library_uri: 'my_plugin3/my_plugin3.dart'
+contributes_to: analyzer
+''';
+
+    var packageMap = {
+      'my_plugin': plugin1Uri,
+      'my_plugin2': plugin2Uri,
+      'my_plugin3': plugin3Uri
+    };
+
+    var manifestReader = (Uri uri) {
+      if (uri == plugin2Uri) return serverPluginManifest;
+      if (uri == plugin3Uri) return analyzerPluginManifest;
+      return null;
+    };
+
+    test('get plugin details', () {
+      PluginManager pm =
+          new PluginManager(packageMap, 'analysis_server', manifestReader);
+
+      PluginInfo notFound = new PluginInfo(name: 'my_plugin1');
+      PluginInfo applicable = new PluginInfo(name: 'my_plugin2');
+      PluginInfo notApplicable = new PluginInfo(name: 'my_plugin3');
+
+      PluginConfig localConfig =
+          new PluginConfig([notFound, applicable, notApplicable]);
+
+      Iterable<PluginDetails> details = pm.getPluginDetails(localConfig);
+      expect(details, hasLength(3));
+
+      List<PluginDetails> plugins = sortByName(details);
+
+      expect(plugins[0].plugin.name, equals('my_plugin1'));
+      expect(plugins[0].status, equals(PluginStatus.NotFound));
+      expect(plugins[1].plugin.name, equals('my_plugin2'));
+      expect(
+          plugins[1].plugin.libraryUri, equals('my_plugin2/my_plugin2.dart'));
+      expect(plugins[1].status, equals(PluginStatus.Applicable));
+      expect(plugins[2].plugin.name, equals('my_plugin3'));
+      expect(plugins[2].status, equals(PluginStatus.NotApplicable));
+    });
+  });
+}
+
+List<PluginDetails> sortByName(Iterable<PluginDetails> details) =>
+    details.toList()
+      ..sort((p1, p2) => p1.plugin.name.compareTo(p2.plugin.name));
diff --git a/pkg/analyzer_cli/test/reporter_test.dart b/pkg/analyzer_cli/test/reporter_test.dart
new file mode 100644
index 0000000..94b0896
--- /dev/null
+++ b/pkg/analyzer_cli/test/reporter_test.dart
@@ -0,0 +1,76 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.formatter;
+
+import 'package:analyzer/analyzer.dart';
+import 'package:analyzer_cli/src/error_formatter.dart';
+import 'package:typed_mock/typed_mock.dart';
+import 'package:unittest/unittest.dart' hide ErrorFormatter;
+
+import 'mocks.dart';
+
+main() {
+  group('reporter', () {
+    var out = new StringBuffer();
+
+    tearDown(() => out.clear());
+
+    // Options
+    var options = new MockCommandLineOptions();
+    when(options.enableTypeChecks).thenReturn(false);
+    when(options.hintsAreFatal).thenReturn(false);
+    when(options.machineFormat).thenReturn(false);
+
+    var reporter = new ErrorFormatter(out, options);
+
+    test('error', () {
+      var error = mockError(ErrorType.SYNTACTIC_ERROR, ErrorSeverity.ERROR);
+      reporter.formatErrors([error]);
+
+      expect(
+          out.toString(),
+          '''[error] MSG (/foo/bar/baz.dart, line 3, col 3)
+1 error found.
+''');
+    });
+
+    test('hint', () {
+      var error = mockError(ErrorType.HINT, ErrorSeverity.INFO);
+      reporter.formatErrors([error]);
+
+      expect(
+          out.toString(),
+          '''[hint] MSG (/foo/bar/baz.dart, line 3, col 3)
+1 hint found.
+''');
+    });
+  });
+}
+
+MockAnalysisErrorInfo mockError(ErrorType type, ErrorSeverity severity) {
+  // ErrorInfo
+  var info = new MockAnalysisErrorInfo();
+  var error = new MockAnalysisError();
+  var lineInfo = new MockLineInfo();
+  var location = new MockLineInfo_Location();
+  when(location.columnNumber).thenReturn(3);
+  when(location.lineNumber).thenReturn(3);
+  when(lineInfo.getLocation(anyObject)).thenReturn(location);
+  when(info.lineInfo).thenReturn(lineInfo);
+
+  // Details
+  var code = new MockErrorCode();
+  when(code.type).thenReturn(type);
+  when(code.errorSeverity).thenReturn(severity);
+  when(code.name).thenReturn('mock_code');
+  when(error.errorCode).thenReturn(code);
+  when(error.message).thenReturn('MSG');
+  var source = new MockSource();
+  when(source.fullName).thenReturn('/foo/bar/baz.dart');
+  when(error.source).thenReturn(source);
+  when(info.errors).thenReturn([error]);
+
+  return info;
+}
diff --git a/pkg/analyzer_cli/test/sdk_ext_test.dart b/pkg/analyzer_cli/test/sdk_ext_test.dart
new file mode 100644
index 0000000..6aa793d
--- /dev/null
+++ b/pkg/analyzer_cli/test/sdk_ext_test.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+/// Test that sdk extensions are properly detected in various scenarios.
+library analyzer_cli.test.sdk_ext;
+
+import 'dart:io';
+
+import 'package:analyzer_cli/src/driver.dart' show Driver, errorSink, outSink;
+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() {}
+_main() {
+  group('Sdk extensions', () {
+    StringSink savedOutSink, savedErrorSink;
+    int savedExitCode;
+    Directory savedCurrentDirectory;
+    setUp(() {
+      savedOutSink = outSink;
+      savedErrorSink = errorSink;
+      savedExitCode = exitCode;
+      outSink = new StringBuffer();
+      errorSink = new StringBuffer();
+      savedCurrentDirectory = Directory.current;
+    });
+    tearDown(() {
+      outSink = savedOutSink;
+      errorSink = savedErrorSink;
+      exitCode = savedExitCode;
+      Directory.current = savedCurrentDirectory;
+    });
+
+    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']);
+
+      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']);
+
+      expect(exitCode, 0);
+    });
+  });
+}
diff --git a/pkg/analyzer_cli/test/strong_mode_test.dart b/pkg/analyzer_cli/test/strong_mode_test.dart
new file mode 100644
index 0000000..763205a
--- /dev/null
+++ b/pkg/analyzer_cli/test/strong_mode_test.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.strong_mode;
+
+import 'dart:io';
+
+import 'package:analyzer_cli/src/driver.dart' show Driver, errorSink, outSink;
+import 'package:path/path.dart' as path;
+import 'package:unittest/unittest.dart';
+
+import 'driver_test.dart';
+import 'utils.dart';
+
+/// End-to-end test for --strong checking.
+///
+/// Most strong mode tests are in Analyzer, but this verifies the option is
+/// working and producing extra errors as expected.
+///
+/// Generally we don't want a lot of cases here as it requires spinning up a
+/// full analysis context.
+///
+// TODO(pq): fix tests to run safely on the bots
+// https://github.com/dart-lang/sdk/issues/25001
+main () {}
+_main() {
+  group('--strong', () {
+    StringSink savedOutSink, savedErrorSink;
+    int savedExitCode;
+    setUp(() {
+      savedOutSink = outSink;
+      savedErrorSink = errorSink;
+      savedExitCode = exitCode;
+      outSink = new StringBuffer();
+      errorSink = new StringBuffer();
+    });
+    tearDown(() {
+      outSink = savedOutSink;
+      errorSink = savedErrorSink;
+      exitCode = savedExitCode;
+    });
+
+    test('produces stricter errors', () async {
+      var testPath = path.join(testDirectory, 'data/strong_example.dart');
+      new Driver().start(['--options', emptyOptionsFile, '--strong', testPath]);
+
+      expect(exitCode, 3);
+      var stdout = outSink.toString();
+      expect(stdout, contains('[error] Invalid override'));
+      expect(stdout, contains('[error] Type check failed'));
+      expect(stdout, contains('2 errors found.'));
+      expect(errorSink.toString(), '');
+    });
+  });
+}
diff --git a/pkg/analyzer_cli/test/super_mixin_test.dart b/pkg/analyzer_cli/test/super_mixin_test.dart
new file mode 100644
index 0000000..d2b7afe
--- /dev/null
+++ b/pkg/analyzer_cli/test/super_mixin_test.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.super_mixin;
+
+import 'dart:io';
+
+import 'package:analyzer_cli/src/driver.dart' show Driver, errorSink, outSink;
+import 'package:path/path.dart' as path;
+import 'package:unittest/unittest.dart';
+
+import 'utils.dart';
+
+/// End-to-end test for --supermixins.
+///
+/// Most super mixin tests are in Analyzer, but this verifies the option is
+/// working and producing extra errors as expected.
+///
+/// Generally we don't want a lot of cases here as it requires spinning up a
+/// full analysis context.
+void main() {
+  group('--supermixins', () {
+    StringSink savedOutSink, savedErrorSink;
+    int savedExitCode;
+    setUp(() {
+      savedOutSink = outSink;
+      savedErrorSink = errorSink;
+      savedExitCode = exitCode;
+      outSink = new StringBuffer();
+      errorSink = new StringBuffer();
+    });
+    tearDown(() {
+      outSink = savedOutSink;
+      errorSink = savedErrorSink;
+      exitCode = savedExitCode;
+    });
+
+    test('produces errors when option absent', () async {
+      var testPath = path.join(testDirectory, 'data/super_mixin_example.dart');
+      new Driver().start([testPath]);
+
+      expect(exitCode, 3);
+      var stdout = outSink.toString();
+      expect(
+          stdout,
+          contains(
+              "[error] The class 'C' cannot be used as a mixin because it extends a class other than Object"));
+      expect(
+          stdout,
+          contains(
+              "[error] The class 'C' cannot be used as a mixin because it references 'super'"));
+      expect(stdout, contains('2 errors found.'));
+      expect(errorSink.toString(), '');
+    });
+
+    test('produces no errors when option present', () async {
+      var testPath = path.join(testDirectory, 'data/super_mixin_example.dart');
+      new Driver().start(['--supermixin', testPath]);
+
+      expect(exitCode, 0);
+      var stdout = outSink.toString();
+      expect(stdout, contains('No issues found'));
+    });
+  });
+}
diff --git a/pkg/analyzer_cli/test/utils.dart b/pkg/analyzer_cli/test/utils.dart
new file mode 100644
index 0000000..25779ab
--- /dev/null
+++ b/pkg/analyzer_cli/test/utils.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.utils;
+
+import 'dart:io';
+import 'dart:mirrors';
+
+import 'package:analyzer/analyzer.dart';
+import 'package:path/path.dart' as pathos;
+
+/// Returns the string representation of the [AnalyzerErrorGroup] thrown when
+/// parsing [contents] as a Dart file. If [contents] doesn't throw any errors,
+/// this will return null.
+///
+/// This replaces the filename in the error string with its basename, since the
+/// full path will vary from machine to machine. It also replaces the exception
+/// message with "..." to decouple these tests from the specific exception
+/// messages.
+String errorsForFile(String contents) {
+  return withTempDir((temp) {
+    var path = pathos.join(temp, 'test.dart');
+    new File(path).writeAsStringSync(contents);
+    try {
+      parseDartFile(path);
+    } on AnalyzerErrorGroup catch (e) {
+      return e.toString().replaceAllMapped(
+          new RegExp(r"^(Error on line \d+ of )((?:[A-Z]+:)?[^:]+): .*$",
+              multiLine: true),
+          (match) => match[1] + pathos.basename(match[2]) + ': ...');
+    }
+    return null;
+  });
+}
+
+/// Creates a temporary directory and passes its path to [fn]. Once [fn]
+/// completes, the temporary directory and all its contents will be deleted.
+///
+/// Returns the return value of [fn].
+dynamic withTempDir(fn(String path)) {
+  var tempDir = Directory.systemTemp.createTempSync('analyzer_').path;
+  try {
+    return fn(tempDir);
+  } finally {
+    new Directory(tempDir).deleteSync(recursive: true);
+  }
+}
+
+/// Gets the test directory in a way that works with
+/// package:test and package:unittest.
+/// See <https://github.com/dart-lang/test/issues/110> for more info.
+final String testDirectory = pathos.dirname(
+    pathos.fromUri((reflectClass(_TestUtils).owner as LibraryMirror).uri));
+
+class _TestUtils {}
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index 3bd085f..556006a 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -83,6 +83,8 @@
                 hasOption(options, Flags.trustTypeAnnotations),
             trustPrimitives:
                 hasOption(options, Flags.trustPrimitives),
+            trustJSInteropTypeAnnotations:
+                hasOption(options, Flags.trustJSInteropTypeAnnotations),
             enableMinification: hasOption(options, Flags.minify),
             useFrequencyNamer:
                 !hasOption(options, Flags.noFrequencyBasedMinification),
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 668cb28..03f274e 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -40,6 +40,8 @@
   static const String testMode = '--test-mode';
   static const String trustPrimitives = '--trust-primitives';
   static const String trustTypeAnnotations = '--trust-type-annotations';
+  static const String trustJSInteropTypeAnnotations =
+      '--experimental-trust-js-interop-type-annotations';
   static const String useContentSecurityPolicy = '--csp';
   static const String useCpsIr = '--use-cps-ir';
   static const String verbose = '--verbose';
diff --git a/pkg/compiler/lib/src/common/backend_api.dart b/pkg/compiler/lib/src/common/backend_api.dart
index ff49bcc..d2fa5ec 100644
--- a/pkg/compiler/lib/src/common/backend_api.dart
+++ b/pkg/compiler/lib/src/common/backend_api.dart
@@ -60,6 +60,7 @@
 import '../universe/call_structure.dart' show
     CallStructure;
 import '../universe/world_impact.dart' show
+    ImpactStrategy,
     WorldImpact;
 
 import 'codegen.dart' show
@@ -424,6 +425,13 @@
   ///
   /// Returns null if there is none.
   Uri resolvePatchUri(String libraryName, Uri plaformConfigUri);
+
+  /// Creates an impact strategy to use for compilation.
+  ImpactStrategy createImpactStrategy(
+      {bool supportDeferredLoad: true,
+       bool supportDumpInfo: true}) {
+    return const ImpactStrategy();
+  }
 }
 
 /// Interface for resolving calls to foreign functions.
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index 37c9855..7e9b40f 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -28,7 +28,8 @@
     TypeUse;
 import '../universe/world_impact.dart' show
     WorldImpact,
-    WorldImpactBuilder;
+    WorldImpactBuilder,
+    WorldImpactVisitor;
 import '../util/util.dart' show
     Pair,
     Setlet;
@@ -78,6 +79,12 @@
 
   _CodegenImpact(this.registry);
 
+  void apply(WorldImpactVisitor visitor) {
+    staticUses.forEach(visitor.visitStaticUse);
+    dynamicUses.forEach(visitor.visitDynamicUse);
+    typeUses.forEach(visitor.visitTypeUse);
+  }
+
   void registerCompileTimeConstant(ConstantValue constant) {
     if (_compileTimeConstants == null) {
       _compileTimeConstants = new Setlet<ConstantValue>();
@@ -262,8 +269,6 @@
     if (world.isProcessed(element)) return const WorldImpact();
 
     registry = new CodegenRegistry(compiler, element);
-    var impact = compiler.codegen(this, world);
-    compiler.dumpInfoTask.registerImpact(element, impact);
-    return impact;
+    return compiler.codegen(this, world);
   }
 }
diff --git a/pkg/compiler/lib/src/common/names.dart b/pkg/compiler/lib/src/common/names.dart
index 657cc6f..79389f5 100644
--- a/pkg/compiler/lib/src/common/names.dart
+++ b/pkg/compiler/lib/src/common/names.dart
@@ -109,13 +109,16 @@
 
   static final Selector length = new Selector.getter(Names.length);
 
+  static final Selector codeUnitAt =
+      new Selector.call(const PublicName('codeUnitAt'), CallStructure.ONE_ARG);
+
   /// List of all the selectors held in static fields.
   ///
   /// These objects are shared between different runs in batch-mode and must
   /// thus remain in the [Selector.canonicalizedValues] map.
   static final List<Selector> ALL = <Selector>[
       cancel, current, iterator, moveNext, noSuchMethod_, toString_,
-      hashCode_, compareTo, equals, length];
+      hashCode_, compareTo, equals, length, codeUnitAt];
 }
 
 /// [Uri]s commonly used.
diff --git a/pkg/compiler/lib/src/common/resolution.dart b/pkg/compiler/lib/src/common/resolution.dart
index 727f3aa..e422ef8 100644
--- a/pkg/compiler/lib/src/common/resolution.dart
+++ b/pkg/compiler/lib/src/common/resolution.dart
@@ -186,8 +186,21 @@
   DartType resolveTypeAnnotation(Element element, TypeAnnotation node);
 
   bool hasBeenResolved(Element element);
+
+  /// Returns the precomputed [WorldImpact] for [element].
   WorldImpact getWorldImpact(Element element);
+
+  /// Computes the [WorldImpact] for [element].
   WorldImpact computeWorldImpact(Element element);
+
+  /// Removes the [WorldImpact] for [element] from the resolution cache. Later
+  /// calls to [getWorldImpact] or [computeWorldImpact] returns an empty impact.
+  void uncacheWorldImpact(Element element);
+
+  /// Removes the [WorldImpact]s for all [Element]s in the resolution cache. ,
+  /// Later calls to [getWorldImpact] or [computeWorldImpact] returns an empty
+  /// impact.
+  void emptyCache();
 }
 
 // TODO(johnniwinther): Rename to `Parser` or `ParsingContext`.
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 392b202..fa655c5 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -137,6 +137,7 @@
 import 'universe/use.dart' show
     StaticUse;
 import 'universe/world_impact.dart' show
+    ImpactStrategy,
     WorldImpact;
 import 'util/util.dart' show
     Link,
@@ -157,6 +158,8 @@
 
   final CacheStrategy cacheStrategy;
 
+  ImpactStrategy impactStrategy = const ImpactStrategy();
+
   /**
    * Map from token to the first preceding comment token.
    */
@@ -192,6 +195,7 @@
   final bool enableUserAssertions;
   final bool trustTypeAnnotations;
   final bool trustPrimitives;
+  final bool trustJSInteropTypeAnnotations;
   final bool disableTypeInferenceFlag;
   final Uri deferredMapUri;
   final bool dumpInfo;
@@ -322,6 +326,7 @@
   ClassElement symbolImplementationClass;
 
   // Initialized when symbolImplementationClass has been resolved.
+  // TODO(johnniwinther): Move this to [BackendHelpers].
   FunctionElement symbolValidatedConstructor;
 
   // Initialized when mirrorsUsedClass has been resolved.
@@ -426,6 +431,7 @@
             this.enableUserAssertions: false,
             this.trustTypeAnnotations: false,
             this.trustPrimitives: false,
+            this.trustJSInteropTypeAnnotations: false,
             bool disableTypeInferenceFlag: false,
             this.maxConcreteTypeSize: 5,
             this.enableMinification: false,
@@ -975,6 +981,9 @@
     // something to the resolution queue.  So we cannot wait with
     // this until after the resolution queue is processed.
     deferredLoadTask.beforeResolution(this);
+    impactStrategy = backend.createImpactStrategy(
+        supportDeferredLoad: deferredLoadTask.isProgramSplit,
+        supportDumpInfo: dumpInfo);
 
     phase = PHASE_RESOLVING;
     if (analyzeAll) {
@@ -1130,6 +1139,9 @@
     }
     emptyQueue(world);
     world.queueIsClosed = true;
+    // Notify the impact strategy impacts are no longer needed for this
+    // enqueuer.
+    impactStrategy.onImpactUsed(world.impactUse);
     backend.onQueueClosed();
     assert(compilationFailed || world.checkNoEnqueuedInvokedInstanceMethods());
   }
@@ -2019,6 +2031,20 @@
   }
 
   @override
+  void uncacheWorldImpact(Element element) {
+    assert(invariant(element, _worldImpactCache[element] != null,
+        message: "WorldImpact not computed for $element."));
+    _worldImpactCache[element] = const WorldImpact();
+  }
+
+  @override
+  void emptyCache() {
+    for (Element element in _worldImpactCache.keys) {
+      _worldImpactCache[element] = const WorldImpact();
+    }
+  }
+
+  @override
   bool hasBeenResolved(Element element) {
     return _worldImpactCache.containsKey(element);
   }
diff --git a/pkg/compiler/lib/src/constants/values.dart b/pkg/compiler/lib/src/constants/values.dart
index 24b6370..2a7c5c4 100644
--- a/pkg/compiler/lib/src/constants/values.dart
+++ b/pkg/compiler/lib/src/constants/values.dart
@@ -375,6 +375,9 @@
       : this.primitiveValue = value,
         this.hashCode = value.slowToString().hashCode;
 
+  StringConstantValue.fromString(String value)
+      : this(new DartString.literal(value));
+
   bool get isString => true;
 
   DartType getType(CoreTypes types) => types.stringType;
@@ -748,4 +751,4 @@
 
   @override
   String unparse() => '>>non-constant<<';
-}
\ No newline at end of file
+}
diff --git a/pkg/compiler/lib/src/cps_ir/bounds_checker.dart b/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
index 28dbd62..a227794 100644
--- a/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
+++ b/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
@@ -168,6 +168,16 @@
     applyConstraint(v2, v1.negated, -1);
   }
 
+  void makeLessThanOrEqualToConstant(SignedVariable v1, int k) {
+    // v1 + v1 <= 2k
+    applyConstraint(v1, v1, 2 * k);
+  }
+
+  void makeGreaterThanOrEqualToConstant(SignedVariable v1, int k) {
+    // -v1 - v1 <= -2k
+    applyConstraint(v1.negated, v1.negated, -2 * k);
+  }
+
   void makeConstant(SignedVariable v1, int k) {
     // We model this using the constraints:
     //    v1 + v1 <=  2k
@@ -329,56 +339,130 @@
 
   @override
   void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
-    if (node.operator != BuiltinOperator.NumAdd &&
-        node.operator != BuiltinOperator.NumSubtract) {
-      return;
+    if (!isInt(node)) return;
+    if (node.arguments.length == 1) {
+      applyUnaryOperator(node);
+    } else if (node.arguments.length == 2) {
+      applyBinaryOperator(node);
     }
-    if (!isInt(node.arguments[0].definition) ||
-        !isInt(node.arguments[1].definition)) {
-      return;
-    }
-    if (!isInt(node)) {
-      // TODO(asgerf): The result of this operation should always be an integer,
-      // but currently type propagation does not always prove this.
-      return;
-    }
-    // We have `v1 = v2 +/- v3`, but the octagon cannot represent constraints
-    // involving more than two variables. Check if one operand is a constant.
-    int getConstantArgument(int n) {
-      Primitive prim = node.arguments[n].definition;
-      if (prim is Constant && prim.value.isInt) {
-        IntConstantValue constant = prim.value;
-        return constant.primitiveValue;
-      }
-      return null;
-    }
-    int constant = getConstantArgument(0);
-    int operandIndex = 1;
-    if (constant == null) {
-      constant = getConstantArgument(1);
-      operandIndex = 0;
-    }
-    if (constant == null) {
-      // Neither argument was a constant.
-      // Classical octagon-based analyzers would compute upper and lower bounds
-      // for the two operands and add constraints for the result based on
-      // those.  For performance reasons we omit that.
-      // TODO(asgerf): It seems expensive, but we should evaluate it.
-      return;
-    }
-    SignedVariable v1 = getValue(node);
-    SignedVariable v2 = getValue(node.arguments[operandIndex].definition);
+  }
 
-    if (node.operator == BuiltinOperator.NumAdd) {
-      // v1 = v2 + const
-      makeFloatingPointSum(v1, v2, constant);
-    } else if (operandIndex == 0) {
-      // v1 = v2 - const
-      makeFloatingPointSum(v1, v2, -constant);
-    } else {
-      // v1 = const - v2   <==>   v1 = (-v2) + const
-      makeFloatingPointSum(v1, v2.negated, constant);
+  void applyBinaryOperator(ApplyBuiltinOperator node) {
+    Primitive left = node.arguments[0].definition;
+    Primitive right = node.arguments[1].definition;
+    if (!isInt(left) || !isInt(right)) {
+      return;
     }
+    SignedVariable leftVar = getValue(left);
+    SignedVariable rightVar = getValue(right);
+    SignedVariable result = getValue(node);
+    switch (node.operator) {
+      case BuiltinOperator.NumAdd:
+        int leftConst = getIntConstant(left);
+        if (leftConst != null) {
+          makeFloatingPointSum(result, rightVar, leftConst);
+        }
+        int rightConst = getIntConstant(right);
+        if (rightConst != null) {
+          makeFloatingPointSum(result, leftVar, rightConst);
+        }
+        // Attempt to compute the sign of the result.
+        // TODO(asgerf): Compute upper/lower bounds instead of using 0.
+        if (testConstraint(leftVar, rightVar, 0)) {
+          makeLessThanOrEqualToConstant(result, 0);
+        }
+        if (testConstraint(leftVar.negated, rightVar.negated, 0)) {
+          makeGreaterThanOrEqualToConstant(result, 0);
+        }
+        // Classical octagon-based analyzers would compute upper and lower
+        // bounds for the two operands and add constraints for the result based
+        // on those.  For performance reasons we only compute the sign
+        // TODO(asgerf): It seems expensive, but we should evaluate it.
+        break;
+
+      case BuiltinOperator.NumSubtract:
+        int leftConst = getIntConstant(left);
+        if (leftConst != null) {
+          // result = leftConst - right = (-right) + leftConst
+          makeFloatingPointSum(result, rightVar.negated, leftConst);
+        }
+        int rightConst = getIntConstant(right);
+        if (rightConst != null) {
+          // result = left - rightConst = left + (-rightConst)
+          makeFloatingPointSum(result, leftVar, -rightConst);
+        }
+        // Attempt to compute the sign of the result.
+        if (isDefinitelyGreaterThanOrEqualTo(leftVar, rightVar)) {
+          makeGreaterThanOrEqualToConstant(result, 0);
+        }
+        if (isDefinitelyLessThanOrEqualTo(leftVar, rightVar)) {
+          makeLessThanOrEqualToConstant(result, 0);
+        }
+        break;
+
+      case BuiltinOperator.NumTruncatingDivideToSigned32:
+        if (isDefinitelyGreaterThanOrEqualToConstant(leftVar, 0)) {
+          // If we divide by a positive number, the result is closer to zero.
+          // If we divide by a negative number, the result is negative, and
+          // thus less than the original (non-negative) number.
+          // TODO(asgerf): The divisor is currently always positive, because
+          // type propagation checks that, but we could do better.
+          makeLessThanOrEqual(result, leftVar);
+        }
+        break;
+
+      case BuiltinOperator.NumShr:
+        if (isDefinitelyGreaterThanOrEqualToConstant(leftVar, 0)) {
+          makeLessThanOrEqual(result, leftVar);
+        }
+        int shiftAmount = getIntConstant(right);
+        if (shiftAmount != null) {
+          // TODO(asgerf): Compute upper bound on [leftVar] and use that
+          // instead of MAX_UINT32.
+          makeLessThanOrEqualToConstant(result, MAX_UINT32 >> shiftAmount);
+        }
+        break;
+
+      case BuiltinOperator.NumRemainder:
+        // TODO(asgerf): This check overlaps with checks performed in a type
+        //   propagation transformation, and we can do it more precisely here.
+        //   Should we do the rewrite here?
+        if (isDefinitelyGreaterThanOrEqualToConstant(leftVar, 0) &&
+            isDefinitelyGreaterThanOrEqualToConstant(rightVar, 1)) {
+          makeLessThanOrEqual(result, leftVar);
+          makeLessThan(result, rightVar);
+        }
+        break;
+
+      case BuiltinOperator.NumAnd:
+        // We use the faster UInt32 check instead of constraint based checks
+        // here, because the common case is that one operand is a constant.
+        if (isUInt32(left)) {
+          makeLessThanOrEqual(result, leftVar);
+        }
+        if (isUInt32(right)) {
+          makeLessThanOrEqual(result, rightVar);
+        }
+        break;
+
+      default:
+    }
+  }
+
+  void applyUnaryOperator(ApplyBuiltinOperator node) {
+    Primitive argument = node.arguments[0].definition;
+    if (!isInt(argument)) return;
+    if (node.operator == BuiltinOperator.NumNegate) {
+      valueOf[node] = getValue(argument).negated;
+    }
+  }
+
+  int getIntConstant(Primitive prim) {
+    if (prim is Constant && prim.value.isInt) {
+      IntConstantValue constant = prim.value;
+      return constant.primitiveValue;
+    }
+    return null;
   }
 
   @override
@@ -398,7 +482,7 @@
         Monotonicity mono = monotonicity[param];
         if (mono == null) {
           // Value never changes. This is extremely uncommon.
-          initialValue.substituteFor(param);
+          param.replaceUsesWith(initialValue);
         } else if (mono == Monotonicity.Increasing) {
           makeGreaterThanOrEqual(getValue(param), initialVariable);
         } else if (mono == Monotonicity.Decreasing) {
@@ -468,7 +552,7 @@
     }
   }
 
-  // ---------------- CALL EXPRESSIONS --------------------
+  // ---------------- PRIMITIVES --------------------
 
   @override
   void visitInvokeMethod(InvokeMethod node) {
@@ -478,7 +562,6 @@
         .changesIndex()) {
       currentEffectNumber = makeNewEffect();
     }
-    push(node.continuation.definition);
   }
 
   @override
@@ -486,7 +569,6 @@
     if (world.getSideEffectsOfElement(node.target).changesIndex()) {
       currentEffectNumber = makeNewEffect();
     }
-    push(node.continuation.definition);
   }
 
   @override
@@ -499,7 +581,6 @@
     if (world.getSideEffectsOfElement(target).changesIndex()) {
       currentEffectNumber = makeNewEffect();
     }
-    push(node.continuation.definition);
   }
 
   @override
@@ -507,19 +588,16 @@
     if (world.getSideEffectsOfElement(node.target).changesIndex()) {
       currentEffectNumber = makeNewEffect();
     }
-    push(node.continuation.definition);
   }
 
   @override
   void visitTypeCast(TypeCast node) {
-    push(node.continuation.definition);
   }
 
   @override
   void visitGetLazyStatic(GetLazyStatic node) {
     // TODO(asgerf): How do we get the side effects of a lazy field initializer?
     currentEffectNumber = makeNewEffect();
-    push(node.continuation.definition);
   }
 
   @override
@@ -527,23 +605,18 @@
     if (node.nativeBehavior.sideEffects.changesIndex()) {
       currentEffectNumber = makeNewEffect();
     }
-    push(node.continuation.definition);
   }
 
   @override
   void visitAwait(Await node) {
     currentEffectNumber = makeNewEffect();
-    push(node.continuation.definition);
   }
 
   @override
   void visitYield(Yield node) {
     currentEffectNumber = makeNewEffect();
-    push(node.continuation.definition);
   }
 
-  // ---------------- PRIMITIVES --------------------
-
   @override
   void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
     Primitive receiver = node.receiver.definition;
diff --git a/pkg/compiler/lib/src/cps_ir/builtin_operator.dart b/pkg/compiler/lib/src/cps_ir/builtin_operator.dart
index 9c1d83e..699e755 100644
--- a/pkg/compiler/lib/src/cps_ir/builtin_operator.dart
+++ b/pkg/compiler/lib/src/cps_ir/builtin_operator.dart
@@ -70,6 +70,12 @@
   /// Returns the empty string if no arguments are given.
   StringConcatenate,
 
+  /// Corresponds to `a.charCodeAt(b)`. `a' must be a String. The index `b` must
+  /// be in range `0 <= b < a.length`.
+  /// TODO(sra): Consider replacing with a Primitive to allow lowering when 'a'
+  /// is nullable (i.e. throws).
+  CharCodeAt,
+
   /// Returns true if the two arguments are the same value, and that value is
   /// not NaN, or if one argument is +0 and the other is -0.
   ///
diff --git a/pkg/compiler/lib/src/cps_ir/cps_fragment.dart b/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
index 7fc2ae3..ada5d1a 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
@@ -123,35 +123,19 @@
     return letPrim(apply);
   }
 
-  /// Inserts an invocation. binds its continuation, and returns the
-  /// continuation parameter (i.e. the return value of the invocation).
-  ///
-  /// The continuation body becomes the new hole.
-  Parameter invokeMethod(Primitive receiver,
+  /// Inserts an invocation and returns a primitive holding the returned value.
+  Primitive invokeMethod(Primitive receiver,
                          Selector selector,
                          TypeMask mask,
                          List<Primitive> arguments) {
-    Continuation cont = new Continuation(<Parameter>[new Parameter(null)]);
-    InvokeMethod invoke =
-      new InvokeMethod(receiver, selector, mask, arguments, cont,
-                       sourceInformation);
-    put(new LetCont(cont, invoke));
-    context = cont;
-    return cont.parameters.single;
+    return letPrim(new InvokeMethod(receiver, selector, mask, arguments,
+        sourceInformation));
   }
 
-  /// Inserts an invocation. binds its continuation, and returns the
-  /// continuation parameter (i.e. the return value of the invocation).
-  ///
-  /// The continuation body becomes the new hole.
-  Parameter invokeStatic(FunctionElement target, List<Primitive> arguments) {
-    Continuation cont = new Continuation(<Parameter>[new Parameter(null)]);
-    InvokeStatic invoke =
-      new InvokeStatic(target, new Selector.fromElement(target), arguments,
-                       cont, sourceInformation);
-    put(new LetCont(cont, invoke));
-    context = cont;
-    return cont.parameters.single;
+  /// Inserts an invocation and returns a primitive holding the returned value.
+  Primitive invokeStatic(FunctionElement target, List<Primitive> arguments) {
+    return letPrim(new InvokeStatic(target, new Selector.fromElement(target),
+        arguments, sourceInformation));
   }
 
   /// Inserts an invocation to a static function that throws an error.
@@ -253,10 +237,45 @@
   Continuation letCont([List<Parameter> parameters]) {
     if (parameters == null) parameters = <Parameter>[];
     Continuation cont = new Continuation(parameters);
+    bindContinuation(cont);
+    return cont;
+  }
+
+  /// Binds an existing continuation at this position.
+  ///
+  /// The LetCont body becomes the new hole.
+  void bindContinuation(Continuation cont) {
     LetCont let = new LetCont(cont, null);
     put(let);
     context = let;
-    return cont;
+  }
+
+  /// Inlines [target] at the current position, substituting the provided
+  /// arguments.
+  ///
+  /// Returns a primitive containing the function's return value.
+  ///
+  /// The new hole is the 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.
+  Primitive inlineFunction(FunctionDefinition target,
+                           Primitive thisArgument,
+                           List<Primitive> arguments,
+                           {Entity hint}) {
+    if (thisArgument != null) {
+      target.thisParameter.replaceUsesWith(thisArgument);
+    }
+    for (int i = 0; i < arguments.length; ++i) {
+      target.parameters[i].replaceUsesWith(arguments[i]);
+    }
+    Continuation returnCont = target.returnContinuation;
+    bindContinuation(returnCont);
+    put(target.body);
+    Parameter returnValue = returnCont.parameters.single;
+    returnValue.hint = hint;
+    context = returnCont;
+    return returnValue;
   }
 
   /// Returns a fragment whose context is the body of the given continuation.
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
index b9f26d2..b75af81 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
@@ -668,9 +668,8 @@
     assert(!element.isLocal);
     assert(!element.isInstanceMember);
     assert(isOpen);
-    return _continueWithExpression(
-        (k) => new ir.InvokeStatic(element, selector, arguments, k,
-                                   sourceInformation));
+    return addPrimitive(
+        new ir.InvokeStatic(element, selector, arguments, sourceInformation));
   }
 
   ir.Primitive _buildInvokeSuper(Element target,
@@ -679,9 +678,8 @@
                                  SourceInformation sourceInformation) {
     assert(target.isInstanceMember);
     assert(isOpen);
-    return _continueWithExpression(
-        (k) => new ir.InvokeMethodDirectly(
-            buildThis(), target, selector, arguments, k, sourceInformation));
+    return addPrimitive(new ir.InvokeMethodDirectly(
+        buildThis(), target, selector, arguments, sourceInformation));
   }
 
   ir.Primitive _buildInvokeDynamic(ir.Primitive receiver,
@@ -690,9 +688,8 @@
                                    List<ir.Primitive> arguments,
                                    SourceInformation sourceInformation) {
     assert(isOpen);
-    return _continueWithExpression(
-        (k) => new ir.InvokeMethod(receiver, selector, mask, arguments, k,
-                                   sourceInformation));
+    return addPrimitive(new ir.InvokeMethod(
+        receiver, selector, mask, arguments, sourceInformation));
   }
 
   ir.Primitive _buildInvokeCall(ir.Primitive target,
@@ -1047,8 +1044,7 @@
   /// initialized yet.
   ir.Primitive buildStaticFieldLazyGet(FieldElement field,
                                        SourceInformation sourceInformation) {
-    return _continueWithExpression(
-        (k) => new ir.GetLazyStatic(field, k, sourceInformation));
+    return addPrimitive(new ir.GetLazyStatic(field, sourceInformation));
   }
 
   /// Create a getter invocation of the static [getter].
@@ -1393,14 +1389,11 @@
     // in expressionReceiver.iterator () iteratorInvoked
     ir.Primitive expressionReceiver = buildExpression(this);
     List<ir.Primitive> emptyArguments = <ir.Primitive>[];
-    ir.Parameter iterator = new ir.Parameter(null);
-    ir.Continuation iteratorInvoked = new ir.Continuation([iterator]);
-    add(new ir.LetCont(iteratorInvoked,
+    ir.Primitive iterator = addPrimitive(
         new ir.InvokeMethod(expressionReceiver,
             Selectors.iterator,
             iteratorMask,
-            emptyArguments,
-            iteratorInvoked)));
+            emptyArguments));
 
     // Fill with:
     // let cont loop(x, ...) =
@@ -1410,14 +1403,11 @@
     // in loop(v, ...)
     JumpCollector loop = new BackwardJumpCollector(environment, target: target);
     addRecursiveContinuation(loop);
-    ir.Parameter condition = new ir.Parameter(null);
-    ir.Continuation moveNextInvoked = new ir.Continuation([condition]);
-    add(new ir.LetCont(moveNextInvoked,
+    ir.Primitive condition = addPrimitive(
         new ir.InvokeMethod(iterator,
             Selectors.moveNext,
             moveNextMask,
-            emptyArguments,
-            moveNextInvoked)));
+            emptyArguments));
 
     // As a delimited term, build:
     // <<BODY>> =
@@ -1432,14 +1422,12 @@
     if (buildVariableDeclaration != null) {
       buildVariableDeclaration(bodyBuilder);
     }
-    ir.Parameter currentValue = new ir.Parameter(null);
-    ir.Continuation currentInvoked = new ir.Continuation([currentValue]);
-    bodyBuilder.add(new ir.LetCont(currentInvoked,
+    ir.Primitive currentValue = bodyBuilder.addPrimitive(
         new ir.InvokeMethod(
             iterator,
             Selectors.current,
             currentMask,
-            emptyArguments, currentInvoked)));
+            emptyArguments));
     // TODO(sra): Does this cover all cases? The general setter case include
     // super.
     // TODO(johnniwinther): Extract this as a provided strategy.
@@ -2607,9 +2595,8 @@
     assert(isOpen);
     Selector selector =
         new Selector.call(target.memberName, new CallStructure(arguments.length));
-    return _continueWithExpression(
-        (k) => new ir.InvokeMethodDirectly(
-            receiver, target, selector, arguments, k, sourceInformation));
+    return addPrimitive(new ir.InvokeMethodDirectly(
+        receiver, target, selector, arguments, sourceInformation));
   }
 
   /// Loads parameters to a constructor body into the environment.
@@ -2654,10 +2641,9 @@
       arguments = new List<ir.Primitive>.from(arguments)
           ..addAll(typeArguments);
     }
-    return _continueWithExpression(
-        (k) => new ir.InvokeConstructor(
-            type, element, selector, arguments, k, sourceInformation,
-            allocationSiteType: allocationSiteType));
+    return addPrimitive(new ir.InvokeConstructor(
+        type, element, selector, arguments, sourceInformation,
+        allocationSiteType: allocationSiteType));
   }
 
   ir.Primitive buildTypeExpression(DartType type) {
@@ -2730,12 +2716,11 @@
                                 {Element dependency}) {
     assert(behavior != null);
     TypeMask type = program.getTypeMaskForForeign(behavior);
-    ir.Primitive result = _continueWithExpression((k) => new ir.ForeignCode(
+    ir.Primitive result = addPrimitive(new ir.ForeignCode(
         codeTemplate,
         type,
         arguments,
         behavior,
-        k,
         dependency: dependency));
     if (!codeTemplate.isExpression) {
       // Close the term if this is a "throw" expression or native body.
@@ -2792,8 +2777,7 @@
         // `x as Object` and `x as dynamic` are the same as `x`.
         return value;
       }
-      return _continueWithExpression(
-              (k) => new ir.TypeCast(value, type, typeArguments, k));
+      return addPrimitive(new ir.TypeCast(value, type, typeArguments));
     }
   }
 
@@ -2836,14 +2820,12 @@
         <ir.Primitive>[value]);
   }
 
-  ir.Node buildAwait(ir.Primitive value) {
-    return _continueWithExpression((k) => new ir.Await(value, k));
+  ir.Primitive buildAwait(ir.Primitive value) {
+    return addPrimitive(new ir.Await(value));
   }
 
   void buildYield(ir.Primitive value, bool hasStar) {
-    _continueWithExpression((k) {
-      return new ir.Yield(value, hasStar, k);
-    });
+    addPrimitive(new ir.Yield(value, hasStar));
   }
 
   ir.Primitive buildRefinement(ir.Primitive value, TypeMask type) {
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 c960bcb..829f942 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
@@ -3353,6 +3353,7 @@
   ir.Primitive buildStaticFieldGet(FieldElement field, SourceInformation src) {
     ConstantValue constant = getConstantForVariable(field);
     if (constant != null && !field.isAssignable) {
+      typeMaskSystem.associateConstantValueWithElement(constant, field);
       return irBuilder.buildConstant(constant, sourceInformation: src);
     } else if (backend.constants.lazyStatics.contains(field)) {
       return irBuilder.buildStaticFieldLazyGet(field, src);
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
index dedfbad..a295902 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
@@ -154,6 +154,9 @@
     if (inScope[def] == ScopeType.NotInScope) {
       error('Referenced out of scope: $def', ref);
     }
+    if (ref.previous == ref) {
+      error('Shared Reference object to $def', ref);
+    }
     if (ref.previous == null && def.firstRef != ref ||
         ref.previous != null && ref.previous.next != ref) {
       error('Broken .previous link in reference to $def', def);
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
index 50e84bd..53a1a98 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
@@ -123,12 +123,6 @@
   }
 }
 
-/// An expression that passes a continuation to a call.
-abstract class CallExpression extends Expression {
-  Reference<Continuation> get continuation;
-  Expression get next => continuation.definition.body;
-}
-
 /// An expression without a continuation or a subexpression body.
 ///
 /// These break straight-line control flow and can be thought of as ending a
@@ -149,19 +143,21 @@
   bool get hasAtLeastOneUse => firstRef != null;
   bool get hasMultipleUses  => !hasAtMostOneUse;
 
-  void substituteFor(Definition<T> other) {
-    if (other == this) return;
-    if (other.hasNoUses) return;
-    Reference<T> previous, current = other.firstRef;
+  void replaceUsesWith(Definition<T> newDefinition) {
+    if (newDefinition == this) return;
+    if (hasNoUses) return;
+    Reference<T> previous, current = firstRef;
     do {
-      current.definition = this;
+      current.definition = newDefinition;
       previous = current;
       current = current.next;
     } while (current != null);
-    previous.next = firstRef;
-    if (firstRef != null) firstRef.previous = previous;
-    firstRef = other.firstRef;
-    other.firstRef = null;
+    previous.next = newDefinition.firstRef;
+    if (newDefinition.firstRef != null) {
+      newDefinition.firstRef.previous = previous;
+    }
+    newDefinition.firstRef = firstRef;
+    firstRef = null;
   }
 }
 
@@ -220,6 +216,9 @@
     }
   }
 
+  /// True if this primitive has a value that can be used by other expressions.
+  bool get hasValue;
+
   /// True if the primitive can be removed, assuming it has no uses
   /// (this getter does not check if there are any uses).
   ///
@@ -268,6 +267,37 @@
     assert(hasNoUses);
     RemovalVisitor.remove(this);
   }
+
+  /// Replaces this definition, both at the binding site and at all uses sites.
+  ///
+  /// This can be thought of as changing the definition of a `let` while
+  /// preserving the variable name:
+  ///
+  ///     let x = OLD in BODY
+  ///       ==>
+  ///     let x = NEW in BODY
+  ///
+  void replaceWith(Primitive newDefinition) {
+    assert(this is! Parameter);
+    assert(newDefinition is! Parameter);
+    assert(newDefinition.parent == null);
+    replaceUsesWith(newDefinition);
+    destroy();
+    LetPrim let = parent;
+    let.primitive = newDefinition;
+    newDefinition.parent = let;
+    newDefinition.useElementAsHint(hint);
+  }
+}
+
+/// A primitive that is generally not safe for elimination, but may be marked
+/// as safe by type propagation
+//
+// TODO(asgerf): Store the flag in a bitmask in [Primitive] and get rid of this
+//               class.
+abstract class UnsafePrimitive extends Primitive {
+  bool isSafeForElimination = false;
+  bool isSafeForReordering = false;
 }
 
 /// Operands to invocations and primitives are always variables.  They point to
@@ -435,35 +465,49 @@
 /// Discussion:
 /// All information in the [selector] is technically redundant; it will likely
 /// be removed.
-class InvokeStatic extends CallExpression {
+class InvokeStatic extends UnsafePrimitive {
   final FunctionElement target;
   final Selector selector;
   final List<Reference<Primitive>> arguments;
-  final Reference<Continuation> continuation;
   final SourceInformation sourceInformation;
 
   InvokeStatic(this.target,
                this.selector,
                List<Primitive> args,
-               Continuation cont,
                [this.sourceInformation])
-      : arguments = _referenceList(args),
-        continuation = new Reference<Continuation>(cont);
+      : arguments = _referenceList(args);
 
   InvokeStatic.byReference(this.target,
                            this.selector,
                            this.arguments,
-                           this.continuation,
                            [this.sourceInformation]);
 
   accept(Visitor visitor) => visitor.visitInvokeStatic(this);
 
+  bool get hasValue => true;
+
   void setParentPointers() {
     _setParentsOnList(arguments, this);
-    continuation.parent = this;
   }
 }
 
+enum CallingConvention {
+  /// JS receiver is the Dart receiver, there are no extra arguments.
+  ///
+  /// For example: `foo.bar$1(x)`
+  Normal,
+
+  /// JS receiver is an interceptor, the first argument is the Dart receiver.
+  ///
+  /// For example: `getInterceptor(foo).bar$1(foo, x)`
+  Intercepted,
+
+  /// JS receiver is the Dart receiver, the first argument is a dummy value.
+  ///
+  /// For example: `foo.bar$1(0, x)`
+  DummyIntercepted,
+}
+
 /// Invoke a method on an object.
 ///
 /// This includes getters, setters, operators, and index getter/setters.
@@ -473,24 +517,30 @@
 ///
 /// The [selector] records the names of named arguments. The value of named
 /// arguments occur at the end of the [arguments] list, in normalized order.
-class InvokeMethod extends CallExpression {
+class InvokeMethod extends UnsafePrimitive {
   Reference<Primitive> receiver;
   Selector selector;
   TypeMask mask;
   final List<Reference<Primitive>> arguments;
-  final Reference<Continuation> continuation;
   final SourceInformation sourceInformation;
 
-  /// If true, the [receiver] is intercepted and the actual receiver is in
-  /// the first argument. Otherwise, the [receiver] is the actual receiver.
-  ///
-  /// This flag is always false for non-intercepted selectors, but it may also
-  /// be false for intercepted selectors after dummy receiver optimization
-  /// (in this case the first argument is a dummy value).
-  ///
-  /// It is always false before the unsugaring pass, where interceptors have
-  /// not yet been introduced.
-  bool receiverIsIntercepted = false;
+  CallingConvention callingConvention = CallingConvention.Normal;
+
+  Reference<Primitive> get dartReceiverReference {
+    return callingConvention == CallingConvention.Intercepted
+        ? arguments[0]
+        : receiver;
+  }
+
+  Primitive get dartReceiver => dartReceiverReference.definition;
+
+  Reference<Primitive> dartArgumentReference(int n) {
+    return callingConvention == CallingConvention.Normal
+        ? arguments[n]
+        : arguments[n + 1];
+  }
+
+  Primitive dartArgument(int n) => dartArgumentReference(n).definition;
 
   /// If true, it is known that the receiver cannot be `null`.
   bool receiverIsNotNull = false;
@@ -499,25 +549,23 @@
                this.selector,
                this.mask,
                List<Primitive> arguments,
-               Continuation continuation,
                [this.sourceInformation])
       : this.receiver = new Reference<Primitive>(receiver),
-        this.arguments = _referenceList(arguments),
-        this.continuation = new Reference<Continuation>(continuation);
+        this.arguments = _referenceList(arguments);
 
   InvokeMethod.byReference(this.receiver,
                            this.selector,
                            this.mask,
                            this.arguments,
-                           this.continuation,
                            this.sourceInformation);
 
   accept(Visitor visitor) => visitor.visitInvokeMethod(this);
 
+  bool get hasValue => true;
+
   void setParentPointers() {
     receiver.parent = this;
     _setParentsOnList(arguments, this);
-    continuation.parent = this;
   }
 }
 
@@ -540,30 +588,46 @@
 ///
 /// All optional arguments declared by [target] are passed in explicitly, and
 /// occur at the end of [arguments] list, in normalized order.
-class InvokeMethodDirectly extends CallExpression {
+class InvokeMethodDirectly extends UnsafePrimitive {
   Reference<Primitive> receiver;
   final FunctionElement target;
   final Selector selector;
   final List<Reference<Primitive>> arguments;
-  final Reference<Continuation> continuation;
   final SourceInformation sourceInformation;
 
+  CallingConvention callingConvention = CallingConvention.Normal;
+
+  Reference<Primitive> get dartReceiverReference {
+    return callingConvention == CallingConvention.Intercepted
+        ? arguments[0]
+        : receiver;
+  }
+
+  Primitive get dartReceiver => dartReceiverReference.definition;
+
+  Reference<Primitive> dartArgumentReference(int n) {
+    return callingConvention == CallingConvention.Normal
+        ? arguments[n]
+        : arguments[n + 1];
+  }
+
+  Primitive dartArgument(int n) => dartArgumentReference(n).definition;
+
   InvokeMethodDirectly(Primitive receiver,
                        this.target,
                        this.selector,
                        List<Primitive> arguments,
-                       Continuation continuation,
                        this.sourceInformation)
       : this.receiver = new Reference<Primitive>(receiver),
-        this.arguments = _referenceList(arguments),
-        this.continuation = new Reference<Continuation>(continuation);
+        this.arguments = _referenceList(arguments);
 
   accept(Visitor visitor) => visitor.visitInvokeMethodDirectly(this);
 
+  bool get hasValue => true;
+
   void setParentPointers() {
     receiver.parent = this;
     _setParentsOnList(arguments, this);
-    continuation.parent = this;
   }
 }
 
@@ -582,11 +646,10 @@
 ///
 /// Note that [InvokeConstructor] does it itself allocate an object.
 /// The invoked constructor will do that using [CreateInstance].
-class InvokeConstructor extends CallExpression {
+class InvokeConstructor extends UnsafePrimitive {
   final DartType dartType;
   final ConstructorElement target;
   final List<Reference<Primitive>> arguments;
-  final Reference<Continuation> continuation;
   final Selector selector;
   final SourceInformation sourceInformation;
 
@@ -601,17 +664,16 @@
                     this.target,
                     this.selector,
                     List<Primitive> args,
-                    Continuation cont,
                     this.sourceInformation,
                     {this.allocationSiteType})
-      : arguments = _referenceList(args),
-        continuation = new Reference<Continuation>(cont);
+      : arguments = _referenceList(args);
 
   accept(Visitor visitor) => visitor.visitInvokeConstructor(this);
 
+  bool get hasValue => true;
+
   void setParentPointers() {
     _setParentsOnList(arguments, this);
-    continuation.parent = this;
   }
 }
 
@@ -629,6 +691,7 @@
   Refinement(Primitive value, this.refineType)
     : value = new Reference<Primitive>(value);
 
+  bool get hasValue => true;
   bool get isSafeForElimination => true;
   bool get isSafeForReordering => false;
 
@@ -665,12 +728,6 @@
   /// Otherwise the list is empty.
   final List<Reference<Primitive>> typeArguments;
 
-  /// The Interceptor for [value].  May be `null` if the test can be done
-  /// without an interceptor.  May be the same as [value] after self-interceptor
-  /// optimization.
-  // TODO(24523): Remove this field.
-  Reference<Primitive> interceptor;
-
   TypeTest(Primitive value,
            this.dartType,
            List<Primitive> typeArguments)
@@ -679,13 +736,13 @@
 
   accept(Visitor visitor) => visitor.visitTypeTest(this);
 
+  bool get hasValue => true;
   bool get isSafeForElimination => true;
   bool get isSafeForReordering => true;
 
   void setParentPointers() {
     value.parent = this;
     _setParentsOnList(typeArguments, this);
-    if (interceptor != null) interceptor.parent = this;
   }
 }
 
@@ -701,6 +758,7 @@
 
   accept(Visitor visitor) => visitor.visitTypeTestViaFlag(this);
 
+  bool get hasValue => true;
   bool get isSafeForElimination => true;
   bool get isSafeForReordering => true;
 
@@ -719,26 +777,26 @@
 /// [value], which is typically in scope in the continuation. However, it might
 /// simplify type propagation, since a better type can be computed for the
 /// continuation parameter without needing flow-sensitive analysis.
-class TypeCast extends CallExpression {
+class TypeCast extends UnsafePrimitive {
   Reference<Primitive> value;
   final DartType dartType;
 
   /// See the corresponding field on [TypeTest].
   final List<Reference<Primitive>> typeArguments;
-  final Reference<Continuation> continuation;
 
   TypeCast(Primitive value,
            this.dartType,
-           List<Primitive> typeArguments,
-           Continuation cont)
+           List<Primitive> typeArguments)
       : this.value = new Reference<Primitive>(value),
-        this.typeArguments = _referenceList(typeArguments),
-        this.continuation = new Reference<Continuation>(cont);
+        this.typeArguments = _referenceList(typeArguments);
 
   accept(Visitor visitor) => visitor.visitTypeCast(this);
 
+  bool get hasValue => true;
+
   void setParentPointers() {
     value.parent = this;
+    _setParentsOnList(typeArguments, this);
   }
 }
 
@@ -757,6 +815,7 @@
 
   accept(Visitor visitor) => visitor.visitApplyBuiltinOperator(this);
 
+  bool get hasValue => true;
   bool get isSafeForElimination => true;
   bool get isSafeForReordering => true;
 
@@ -786,6 +845,7 @@
 
   accept(Visitor visitor) => visitor.visitApplyBuiltinMethod(this);
 
+  bool get hasValue => true;
   bool get isSafeForElimination => false;
   bool get isSafeForReordering => false;
 
@@ -845,6 +905,7 @@
 
   accept(Visitor visitor) => visitor.visitGetMutable(this);
 
+  bool get hasValue => true;
   bool get isSafeForElimination => true;
   bool get isSafeForReordering => false;
 
@@ -869,6 +930,7 @@
 
   accept(Visitor visitor) => visitor.visitSetMutable(this);
 
+  bool get hasValue => false;
   bool get isSafeForElimination => false;
   bool get isSafeForReordering => false;
 
@@ -973,6 +1035,7 @@
 
   accept(Visitor visitor) => visitor.visitSetField(this);
 
+  bool get hasValue => false;
   bool get isSafeForElimination => false;
   bool get isSafeForReordering => false;
 
@@ -999,6 +1062,7 @@
 
   accept(Visitor visitor) => visitor.visitGetField(this);
 
+  bool get hasValue => true;
   bool get isSafeForElimination => objectIsNotNull;
   bool get isSafeForReordering => false;
 
@@ -1018,6 +1082,7 @@
 
   GetLength(Primitive object) : this.object = new Reference<Primitive>(object);
 
+  bool get hasValue => true;
   bool get isSafeForElimination => objectIsNotNull;
   bool get isSafeForReordering => false;
 
@@ -1043,6 +1108,7 @@
       : this.object = new Reference<Primitive>(object),
         this.index = new Reference<Primitive>(index);
 
+  bool get hasValue => true;
   bool get isSafeForElimination => objectIsNotNull;
   bool get isSafeForReordering => false;
 
@@ -1069,6 +1135,7 @@
         this.index = new Reference<Primitive>(index),
         this.value = new Reference<Primitive>(value);
 
+  bool get hasValue => false;
   bool get isSafeForElimination => false;
   bool get isSafeForReordering => false;
 
@@ -1093,9 +1160,8 @@
 
   accept(Visitor visitor) => visitor.visitGetStatic(this);
 
-  bool get isSafeForElimination {
-    return true;
-  }
+  bool get hasValue => true;
+  bool get isSafeForElimination => true;
   bool get isSafeForReordering {
     return element is FunctionElement || element.isFinal;
   }
@@ -1114,6 +1180,7 @@
 
   accept(Visitor visitor) => visitor.visitSetStatic(this);
 
+  bool get hasValue => false;
   bool get isSafeForElimination => false;
   bool get isSafeForReordering => false;
 
@@ -1126,29 +1193,24 @@
 ///
 /// If the field has not yet been initialized, its initializer is evaluated
 /// and assigned to the field.
-///
-/// [continuation] is then invoked with the value of the field as argument.
-class GetLazyStatic extends CallExpression {
+class GetLazyStatic extends UnsafePrimitive {
   final FieldElement element;
-  final Reference<Continuation> continuation;
   final SourceInformation sourceInformation;
 
-  GetLazyStatic(this.element,
-                Continuation continuation,
-                [this.sourceInformation])
-      : continuation = new Reference<Continuation>(continuation);
+  GetLazyStatic(this.element, [this.sourceInformation]);
 
   accept(Visitor visitor) => visitor.visitGetLazyStatic(this);
 
-  void setParentPointers() {
-    continuation.parent = this;
-  }
+  bool get hasValue => true;
+
+  void setParentPointers() {}
 }
 
 /// Creates an object for holding boxed variables captured by a closure.
 class CreateBox extends Primitive {
   accept(Visitor visitor) => visitor.visitCreateBox(this);
 
+  bool get hasValue => true;
   bool get isSafeForElimination => true;
   bool get isSafeForReordering => true;
 
@@ -1181,6 +1243,7 @@
 
   accept(Visitor visitor) => visitor.visitCreateInstance(this);
 
+  bool get hasValue => true;
   bool get isSafeForElimination => true;
   bool get isSafeForReordering => true;
 
@@ -1277,6 +1340,7 @@
 
   accept(Visitor visitor) => visitor.visitInterceptor(this);
 
+  bool get hasValue => true;
   bool get isSafeForElimination => true;
   bool get isSafeForReordering => true;
 
@@ -1295,6 +1359,7 @@
 
   accept(Visitor visitor) => visitor.visitCreateInvocationMirror(this);
 
+  bool get hasValue => true;
   bool get isSafeForElimination => true;
   bool get isSafeForReordering => true;
 
@@ -1303,24 +1368,23 @@
   }
 }
 
-class ForeignCode extends CallExpression {
+class ForeignCode extends UnsafePrimitive {
   final js.Template codeTemplate;
   final TypeMask type;
   final List<Reference<Primitive>> arguments;
   final native.NativeBehavior nativeBehavior;
   final FunctionElement dependency;
-  final Reference<Continuation> continuation;
 
   ForeignCode(this.codeTemplate, this.type, List<Primitive> arguments,
-      this.nativeBehavior, Continuation continuation, {this.dependency})
-      : this.arguments = _referenceList(arguments),
-        this.continuation = new Reference<Continuation>(continuation);
+      this.nativeBehavior, {this.dependency})
+      : this.arguments = _referenceList(arguments);
 
   accept(Visitor visitor) => visitor.visitForeignCode(this);
 
+  bool get hasValue => true;
+
   void setParentPointers() {
     _setParentsOnList(arguments, this);
-    continuation.parent = this;
   }
 }
 
@@ -1334,6 +1398,7 @@
 
   accept(Visitor visitor) => visitor.visitConstant(this);
 
+  bool get hasValue => true;
   bool get isSafeForElimination => true;
   bool get isSafeForReordering => true;
 
@@ -1354,6 +1419,7 @@
 
   accept(Visitor visitor) => visitor.visitLiteralList(this);
 
+  bool get hasValue => true;
   bool get isSafeForElimination => true;
   bool get isSafeForReordering => true;
 
@@ -1379,6 +1445,7 @@
 
   accept(Visitor visitor) => visitor.visitLiteralMap(this);
 
+  bool get hasValue => true;
   bool get isSafeForElimination => true;
   bool get isSafeForReordering => true;
 
@@ -1390,29 +1457,6 @@
   }
 }
 
-/// Currently unused.
-///
-/// Nested functions (from Dart code) are translated to classes by closure
-/// conversion, hence they are instantiated with [CreateInstance].
-///
-/// We keep this around for now because it might come in handy when we
-/// handle async/await in the CPS IR.
-///
-/// Instantiates a nested function. [MutableVariable]s are in scope in the
-/// inner function, but primitives are not shared across function boundaries.
-class CreateFunction extends Primitive {
-  final FunctionDefinition definition;
-
-  CreateFunction(this.definition);
-
-  accept(Visitor visitor) => visitor.visitCreateFunction(this);
-
-  bool get isSafeForElimination => true;
-  bool get isSafeForReordering => true;
-
-  void setParentPointers() {}
-}
-
 class Parameter extends Primitive {
   Parameter(Entity hint) {
     super.hint = hint;
@@ -1422,6 +1466,7 @@
 
   String toString() => 'Parameter(${hint == null ? null : hint.name})';
 
+  bool get hasValue => true;
   bool get isSafeForElimination => true;
   bool get isSafeForReordering => true;
 
@@ -1515,6 +1560,7 @@
   @override
   accept(Visitor visitor) => visitor.visitReifyRuntimeType(this);
 
+  bool get hasValue => true;
   bool get isSafeForElimination => true;
   bool get isSafeForReordering => true;
 
@@ -1539,6 +1585,7 @@
   @override
   accept(Visitor visitor) => visitor.visitReadTypeVariable(this);
 
+  bool get hasValue => true;
   bool get isSafeForElimination => true;
   bool get isSafeForReordering => true;
 
@@ -1568,6 +1615,7 @@
     return visitor.visitTypeExpression(this);
   }
 
+  bool get hasValue => true;
   bool get isSafeForElimination => true;
   bool get isSafeForReordering => true;
 
@@ -1576,42 +1624,40 @@
   }
 }
 
-class Await extends CallExpression {
+class Await extends UnsafePrimitive {
   final Reference<Primitive> input;
-  final Reference<Continuation> continuation;
 
-  Await(Primitive input, Continuation continuation)
-    : this.input = new Reference<Primitive>(input),
-      this.continuation = new Reference<Continuation>(continuation);
+  Await(Primitive input)
+    : this.input = new Reference<Primitive>(input);
 
   @override
   accept(Visitor visitor) {
     return visitor.visitAwait(this);
   }
 
+  bool get hasValue => true;
+
   void setParentPointers() {
     input.parent = this;
-    continuation.parent = this;
   }
 }
 
-class Yield extends CallExpression {
+class Yield extends UnsafePrimitive {
   final Reference<Primitive> input;
-  final Reference<Continuation> continuation;
   final bool hasStar;
 
-  Yield(Primitive input, this.hasStar, Continuation continuation)
-    : this.input = new Reference<Primitive>(input),
-      this.continuation = new Reference<Continuation>(continuation);
+  Yield(Primitive input, this.hasStar)
+    : this.input = new Reference<Primitive>(input);
 
   @override
   accept(Visitor visitor) {
     return visitor.visitYield(this);
   }
 
+  bool get hasValue => true;
+
   void setParentPointers() {
     input.parent = this;
-    continuation.parent = this;
   }
 }
 
@@ -1665,7 +1711,6 @@
   T visitLiteralList(LiteralList node);
   T visitLiteralMap(LiteralMap node);
   T visitConstant(Constant node);
-  T visitCreateFunction(CreateFunction node);
   T visitGetMutable(GetMutable node);
   T visitParameter(Parameter node);
   T visitContinuation(Continuation node);
@@ -1760,7 +1805,6 @@
   processInvokeStatic(InvokeStatic node) {}
   visitInvokeStatic(InvokeStatic node) {
     processInvokeStatic(node);
-    processReference(node.continuation);
     node.arguments.forEach(processReference);
   }
 
@@ -1775,7 +1819,6 @@
   visitInvokeMethod(InvokeMethod node) {
     processInvokeMethod(node);
     processReference(node.receiver);
-    processReference(node.continuation);
     node.arguments.forEach(processReference);
   }
 
@@ -1783,14 +1826,12 @@
   visitInvokeMethodDirectly(InvokeMethodDirectly node) {
     processInvokeMethodDirectly(node);
     processReference(node.receiver);
-    processReference(node.continuation);
     node.arguments.forEach(processReference);
   }
 
   processInvokeConstructor(InvokeConstructor node) {}
   visitInvokeConstructor(InvokeConstructor node) {
     processInvokeConstructor(node);
-    processReference(node.continuation);
     node.arguments.forEach(processReference);
   }
 
@@ -1816,7 +1857,6 @@
   processTypeCast(TypeCast node) {}
   visitTypeCast(TypeCast node) {
     processTypeCast(node);
-    processReference(node.continuation);
     processReference(node.value);
     node.typeArguments.forEach(processReference);
   }
@@ -1825,7 +1865,6 @@
   visitTypeTest(TypeTest node) {
     processTypeTest(node);
     processReference(node.value);
-    if (node.interceptor != null) processReference(node.interceptor);
     node.typeArguments.forEach(processReference);
   }
 
@@ -1845,7 +1884,6 @@
   processGetLazyStatic(GetLazyStatic node) {}
   visitGetLazyStatic(GetLazyStatic node) {
     processGetLazyStatic(node);
-    processReference(node.continuation);
   }
 
   processLiteralList(LiteralList node) {}
@@ -1868,12 +1906,6 @@
     processConstant(node);
   }
 
-  processCreateFunction(CreateFunction node) {}
-  visitCreateFunction(CreateFunction node) {
-    processCreateFunction(node);
-    visit(node.definition);
-  }
-
   processMutableVariable(node) {}
   visitMutableVariable(MutableVariable node) {
     processMutableVariable(node);
@@ -1972,9 +2004,6 @@
   processForeignCode(ForeignCode node) {}
   visitForeignCode(ForeignCode node) {
     processForeignCode(node);
-    if (node.continuation != null) {
-      processReference(node.continuation);
-    }
     node.arguments.forEach(processReference);
   }
 
@@ -1987,14 +2016,12 @@
   visitAwait(Await node) {
     processAwait(node);
     processReference(node.input);
-    processReference(node.continuation);
   }
 
   processYield(Yield node) {}
   visitYield(Yield node) {
     processYield(node);
     processReference(node.input);
-    processReference(node.continuation);
   }
 
   processGetLength(GetLength node) {}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
index 79164b5..78b976f 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
@@ -108,10 +108,12 @@
   }
 
   String formatArguments(CallStructure call,
-                         List<Reference<Primitive>> arguments,
-                         {bool isIntercepted: false}) {
+        List<Reference<Primitive>> arguments,
+        [CallingConvention callingConvention = CallingConvention.Normal]) {
     int positionalArgumentCount = call.positionalArgumentCount;
-    if (isIntercepted) ++positionalArgumentCount;
+    if (callingConvention == CallingConvention.Intercepted) {
+      ++positionalArgumentCount;
+    }
     List<String> args =
         arguments.getRange(0, positionalArgumentCount).map(access).toList();
     List<String> argumentNames = call.getOrderedNamedArguments();
@@ -125,26 +127,24 @@
 
   String visitInvokeStatic(InvokeStatic node) {
     String name = node.target.name;
-    String cont = access(node.continuation);
     String args = formatArguments(node.selector.callStructure, node.arguments);
-    return '$indentation(InvokeStatic $name $args $cont)';
+    return '(InvokeStatic $name $args)';
   }
 
   String visitInvokeMethod(InvokeMethod node) {
     String name = node.selector.name;
     String rcv = access(node.receiver);
-    String cont = access(node.continuation);
     String args = formatArguments(node.selector.callStructure, node.arguments,
-        isIntercepted: node.receiverIsIntercepted);
-    return '$indentation(InvokeMethod $rcv $name $args $cont)';
+        node.callingConvention);
+    return '(InvokeMethod $rcv $name $args)';
   }
 
   String visitInvokeMethodDirectly(InvokeMethodDirectly node) {
     String receiver = access(node.receiver);
     String name = node.selector.name;
-    String cont = access(node.continuation);
-    String args = formatArguments(node.selector.callStructure, node.arguments);
-    return '$indentation(InvokeMethodDirectly $receiver $name $args $cont)';
+    String args = formatArguments(node.selector.callStructure, node.arguments,
+        node.callingConvention);
+    return '(InvokeMethodDirectly $receiver $name $args)';
   }
 
   String visitInvokeConstructor(InvokeConstructor node) {
@@ -164,9 +164,8 @@
     } else {
       callName = '${className}.${node.target.name}';
     }
-    String cont = access(node.continuation);
     String args = formatArguments(node.selector.callStructure, node.arguments);
-    return '$indentation(InvokeConstructor $callName $args $cont)';
+    return '(InvokeConstructor $callName $args)';
   }
 
   String visitInvokeContinuation(InvokeContinuation node) {
@@ -202,12 +201,6 @@
     return '(Constant $value)';
   }
 
-  String visitCreateFunction(CreateFunction node) {
-    String function =
-        indentBlock(() => indentBlock(() => visit(node.definition)));
-    return '(CreateFunction\n$function)';
-  }
-
   String visitContinuation(Continuation node) {
     String name = newContinuationName(node);
     if (node.isRecursive) name = 'rec $name';
@@ -232,19 +225,14 @@
 
   String visitTypeCast(TypeCast node) {
     String value = access(node.value);
-    String cont = access(node.continuation);
     String typeArguments = node.typeArguments.map(access).join(' ');
-    return '$indentation(TypeCast $value ${node.dartType}'
-                         ' ($typeArguments) $cont)';
+    return '(TypeCast $value ${node.dartType} ($typeArguments))';
   }
 
   String visitTypeTest(TypeTest node) {
     String value = access(node.value);
     String typeArguments = node.typeArguments.map(access).join(' ');
-    String interceptor = node.interceptor == null
-        ? ''
-        : access(node.interceptor);
-    return '(TypeTest $value ${node.dartType} ($typeArguments) ($interceptor))';
+    return '(TypeTest $value ${node.dartType} ($typeArguments))';
   }
 
   String visitTypeTestViaFlag(TypeTestViaFlag node) {
@@ -289,8 +277,7 @@
 
   String visitGetLazyStatic(GetLazyStatic node) {
     String element = node.element.name;
-    String cont = access(node.continuation);
-    return '$indentation(GetLazyStatic $element $cont)';
+    return '(GetLazyStatic $element)';
   }
 
   String visitCreateBox(CreateBox node) {
@@ -342,10 +329,7 @@
 
   String visitForeignCode(ForeignCode node) {
     String arguments = node.arguments.map(access).join(' ');
-    String continuation = node.continuation == null ? ''
-        : ' ${access(node.continuation)}';
-    return '$indentation(JS "${node.codeTemplate.source}"'
-        ' ($arguments)$continuation)';
+    return '(JS "${node.codeTemplate.source}" ($arguments))';
   }
 
   String visitGetLength(GetLength node) {
@@ -369,15 +353,13 @@
   @override
   String visitAwait(Await node) {
     String value = access(node.input);
-    String continuation = access(node.continuation);
-    return '(Await $value $continuation)';
+    return '(Await $value)';
   }
 
   @override
   String visitYield(Yield node) {
     String value = access(node.input);
-    String continuation = access(node.continuation);
-    return '(Yield $value $continuation)';
+    return '(Yield $value)';
   }
 
   String visitRefinement(Refinement node) {
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
index 12a6a31..6c7469e 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
@@ -140,35 +140,26 @@
   }
 
   visitInvokeStatic(cps_ir.InvokeStatic node) {
-    String dummy = names.name(node);
     String callName = node.selector.name;
     String args = node.arguments.map(formatReference).join(', ');
-    String kont = formatReference(node.continuation);
-    printStmt(dummy, "InvokeStatic $callName ($args) $kont");
+    return "InvokeStatic $callName ($args)";
   }
 
   visitInvokeMethod(cps_ir.InvokeMethod node) {
-    String dummy = names.name(node);
     String receiver = formatReference(node.receiver);
     String callName = node.selector.name;
     String args = node.arguments.map(formatReference).join(', ');
-    String kont = formatReference(node.continuation);
-    printStmt(dummy,
-        "InvokeMethod $receiver $callName ($args) $kont");
+    return "InvokeMethod $receiver $callName ($args)";
   }
 
   visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
-    String dummy = names.name(node);
     String receiver = formatReference(node.receiver);
     String callName = node.selector.name;
     String args = node.arguments.map(formatReference).join(', ');
-    String kont = formatReference(node.continuation);
-    printStmt(dummy,
-        "InvokeMethodDirectly $receiver $callName ($args) $kont");
+    return "InvokeMethodDirectly $receiver $callName ($args)";
   }
 
   visitInvokeConstructor(cps_ir.InvokeConstructor node) {
-    String dummy = names.name(node);
     String className = node.target.enclosingClass.name;
     String callName;
     if (node.target.name.isEmpty) {
@@ -177,8 +168,7 @@
       callName = '${className}.${node.target.name}';
     }
     String args = node.arguments.map(formatReference).join(', ');
-    String kont = formatReference(node.continuation);
-    printStmt(dummy, "InvokeConstructor $callName ($args) $kont");
+    return "InvokeConstructor $callName ($args)";
   }
 
   visitThrow(cps_ir.Throw node) {
@@ -213,11 +203,9 @@
   }
 
   visitTypeCast(cps_ir.TypeCast node) {
-    String dummy = names.name(node);
     String value = formatReference(node.value);
     String args = node.typeArguments.map(formatReference).join(', ');
-    String kont = formatReference(node.continuation);
-    printStmt(dummy, "TypeCast ($value ${node.dartType} ($args)) $kont");
+    return "TypeCast ($value ${node.dartType} ($args))";
   }
 
   visitInvokeContinuation(cps_ir.InvokeContinuation node) {
@@ -237,18 +225,14 @@
   }
 
   visitAwait(cps_ir.Await node) {
-    String dummy = names.name(node);
     String value = formatReference(node.input);
-    String continuation = formatReference(node.continuation);
-    printStmt(dummy, 'Await $value $continuation');
+    return 'Await $value';
   }
 
   visitYield(cps_ir.Yield node) {
-    String dummy = names.name(node);
     String name = node.hasStar ? 'YieldStar' : 'Yield';
     String value = formatReference(node.input);
-    String continuation = formatReference(node.continuation);
-    printStmt(dummy, '$name $value $continuation');
+    return '$name $value';
   }
 
   visitSetMutable(cps_ir.SetMutable node) {
@@ -307,9 +291,8 @@
   }
 
   visitGetLazyStatic(cps_ir.GetLazyStatic node) {
-    String dummy = names.name(node);
-    String kont = formatReference(node.continuation);
-    printStmt(dummy, "GetLazyStatic $kont");
+    String element = node.element.name;
+    return "GetLazyStatic $element";
   }
 
   visitCreateBox(cps_ir.CreateBox node) {
@@ -329,10 +312,6 @@
            '${node.interceptedClasses})';
   }
 
-  visitCreateFunction(cps_ir.CreateFunction node) {
-    return "CreateFunction ${node.definition.element.name}";
-  }
-
   visitGetMutable(cps_ir.GetMutable node) {
     String variable = names.name(node.variable.definition);
     return 'GetMutable $variable';
@@ -360,10 +339,7 @@
   visitTypeTest(cps_ir.TypeTest node) {
     String value = formatReference(node.value);
     String args = node.typeArguments.map(formatReference).join(', ');
-    String interceptor = node.interceptor == null
-        ? ''
-        : ' ${formatReference(node.interceptor)}';
-    return "TypeTest ($value ${node.dartType} ($args)$interceptor)";
+    return "TypeTest ($value ${node.dartType} ($args))";
   }
 
   visitTypeTestViaFlag(cps_ir.TypeTestViaFlag node) {
@@ -384,13 +360,11 @@
     return 'ApplyBuiltinMethod $method $receiver ($args)';
   }
 
-  @override
   visitForeignCode(cps_ir.ForeignCode node) {
     String id = names.name(node);
     String arguments = node.arguments.map(formatReference).join(', ');
-    String continuation = formatReference(node.continuation);
-    printStmt(id, "ForeignCode ${node.type} ${node.codeTemplate.source} "
-        "$arguments $continuation");
+    printStmt(id,
+        "ForeignCode ${node.type} ${node.codeTemplate.source} $arguments");
   }
 
   visitGetLength(cps_ir.GetLength node) {
@@ -411,7 +385,6 @@
     return 'SetIndex $object $index $value';
   }
 
-  @override
   visitRefinement(cps_ir.Refinement node) {
     String value = formatReference(node.value);
     return 'Refinement $value ${node.refineType}';
@@ -526,20 +499,20 @@
     addEdgeToContinuation(exp.continuation);
   }
 
-  visitInvokeStatic(cps_ir.InvokeStatic exp) {
-    addEdgeToContinuation(exp.continuation);
+  visitInvokeStatic(cps_ir.InvokeStatic node) {
+    unexpectedNode(node);
   }
 
-  visitInvokeMethod(cps_ir.InvokeMethod exp) {
-    addEdgeToContinuation(exp.continuation);
+  visitInvokeMethod(cps_ir.InvokeMethod node) {
+    unexpectedNode(node);
   }
 
-  visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly exp) {
-    addEdgeToContinuation(exp.continuation);
+  visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
+    unexpectedNode(node);
   }
 
-  visitInvokeConstructor(cps_ir.InvokeConstructor exp) {
-    addEdgeToContinuation(exp.continuation);
+  visitInvokeConstructor(cps_ir.InvokeConstructor node) {
+    unexpectedNode(node);
   }
 
   visitThrow(cps_ir.Throw exp) {
@@ -551,8 +524,8 @@
   visitUnreachable(cps_ir.Unreachable node) {
   }
 
-  visitGetLazyStatic(cps_ir.GetLazyStatic exp) {
-    addEdgeToContinuation(exp.continuation);
+  visitGetLazyStatic(cps_ir.GetLazyStatic node) {
+    unexpectedNode(node);
   }
 
   visitBranch(cps_ir.Branch exp) {
@@ -566,8 +539,8 @@
     }
   }
 
-  visitTypeCast(cps_ir.TypeCast exp) {
-    addEdgeToContinuation(exp.continuation);
+  visitTypeCast(cps_ir.TypeCast node) {
+    unexpectedNode(node);
   }
 
   visitContinuation(cps_ir.Continuation c) {
@@ -595,10 +568,6 @@
     unexpectedNode(node);
   }
 
-  visitCreateFunction(cps_ir.CreateFunction node) {
-    unexpectedNode(node);
-  }
-
   visitGetMutable(cps_ir.GetMutable node) {
     unexpectedNode(node);
   }
@@ -687,22 +656,18 @@
     unexpectedNode(node);
   }
 
-  @override
   visitForeignCode(cps_ir.ForeignCode node) {
-    addEdgeToContinuation(node.continuation);
+    unexpectedNode(node);
   }
 
-  @override
   visitAwait(cps_ir.Await node) {
-    addEdgeToContinuation(node.continuation);
+    unexpectedNode(node);
   }
 
-  @override
   visitYield(cps_ir.Yield node) {
-    addEdgeToContinuation(node.continuation);
+    unexpectedNode(node);
   }
 
-  @override
   visitRefinement(cps_ir.Refinement node) {
     unexpectedNode(node);
   }
diff --git a/pkg/compiler/lib/src/cps_ir/gvn.dart b/pkg/compiler/lib/src/cps_ir/gvn.dart
new file mode 100644
index 0000000..02379d8
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/gvn.dart
@@ -0,0 +1,706 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.cps_ir.gvn;
+
+import 'cps_ir_nodes.dart';
+import '../universe/side_effects.dart';
+import '../elements/elements.dart';
+import 'optimizers.dart' show Pass;
+import 'loop_hierarchy.dart';
+import 'loop_effects.dart';
+import '../world.dart';
+import '../compiler.dart' show Compiler;
+import '../js_backend/js_backend.dart' show JavaScriptBackend;
+import '../constants/values.dart';
+
+/// Eliminates redundant primitives by reusing the value of another primitive
+/// that is known to have the same result.  Primitives are also hoisted out of
+/// loops when possible.
+///
+/// Reusing values can introduce new temporaries, which in some cases is more
+/// expensive than recomputing the value on-demand. For example, pulling an
+/// expression such as "n+1" out of a loop is generally not worth it.
+/// Such primitives are said to be "trivial".
+///
+/// Trivial primitives are shared on-demand, i.e. they are only shared if
+/// this enables a non-trivial primitive to be hoisted out of a loop.
+//
+//  TODO(asgerf): Enable hoisting across refinement guards when this is safe:
+//    - Determine the type required for a given primitive to be "safe"
+//    - Recompute the type of a primitive after hoisting.
+//        E.g. GetIndex on a String can become a GetIndex on an arbitrary
+//             indexable, which is still safe but the type may change
+//    - Since the new type may be worse, insert a refinement at the old
+//      definition site, so we do not degrade existing type information.
+//
+//  TODO(asgerf): Put this pass at a better place in the pipeline.  We currently
+//    cannot put it anywhere we want, because this pass relies on refinement
+//    nodes being present (for safety), whereas other passes rely on refinement
+//    nodes being absent (for simplicity & precision).
+//
+class GVN extends TrampolineRecursiveVisitor implements Pass {
+  String get passName => 'GVN';
+
+  final Compiler compiler;
+  JavaScriptBackend get backend => compiler.backend;
+  World get world => compiler.world;
+
+  final GvnTable gvnTable = new GvnTable();
+  GvnVectorBuilder gvnVectorBuilder;
+  LoopHierarchy loopHierarchy;
+  LoopSideEffects loopEffects;
+
+  /// Effect numbers at the given join point.
+  Map<Continuation, EffectNumbers> effectsAt = <Continuation, EffectNumbers>{};
+
+  /// The effect numbers at the current position (during traversal).
+  EffectNumbers effectNumbers = new EffectNumbers();
+
+  /// The loop currently enclosing the binding of a given primitive.
+  final Map<Primitive, Continuation> loopHeaderFor =
+      <Primitive, Continuation>{};
+
+  /// The loop to which a given trivial primitive can be hoisted.
+  final Map<Primitive, Continuation> potentialLoopHeaderFor =
+      <Primitive, Continuation>{};
+
+  /// The GVNs for primitives that have been hoisted outside the given loop.
+  ///
+  /// These should be removed from the environment when exiting the loop.
+  final Map<Continuation, List<int>> loopHoistedBindings =
+      <Continuation, List<int>>{};
+
+  /// Maps GVNs to a currently-in-scope binding for that value.
+  final Map<int, Primitive> environment = <int, Primitive>{};
+
+  /// Maps GVN'able primitives to their global value number.
+  final Map<Primitive, int> gvnFor = <Primitive, int>{};
+
+  Continuation currentLoopHeader;
+
+  GVN(this.compiler);
+
+  int _usedEffectNumbers = 0;
+  int makeNewEffect() => ++_usedEffectNumbers;
+
+  void rewrite(FunctionDefinition node) {
+    gvnVectorBuilder = new GvnVectorBuilder(gvnFor, backend);
+    loopHierarchy = new LoopHierarchy(node);
+    loopEffects =
+        new LoopSideEffects(node, world, loopHierarchy: loopHierarchy);
+    visit(node);
+  }
+
+  // ------------------ GLOBAL VALUE NUMBERING ---------------------
+
+  @override
+  Expression traverseLetPrim(LetPrim node) {
+    Expression next = node.body;
+    Primitive prim = node.primitive;
+
+    loopHeaderFor[prim] = currentLoopHeader;
+
+    if (prim is Refinement) {
+      // Do not share refinements (they have no runtime or code size cost), and
+      // do not put them in the GVN table because GvnVectorBuilder unfolds
+      // refinements by itself.
+      return next;
+    }
+
+    // Compute the GVN vector for this computation.
+    List vector = gvnVectorBuilder.make(prim, effectNumbers);
+
+    // Update effect numbers due to side effects.
+    // Do this after computing the GVN vector so the primitive's GVN is not
+    // influenced by its own side effects.
+    visit(prim);
+
+    if (vector == null) {
+      // The primitive is not GVN'able. Move on.
+      return next;
+    }
+
+    // Compute the GVN for this primitive.
+    int gvn = gvnTable.insert(vector);
+    gvnFor[prim] = gvn;
+
+    // Try to reuse a previously computed value with the same GVN.
+    Primitive existing = environment[gvn];
+    if (existing != null &&
+        (prim.isSafeForElimination || prim is GetLazyStatic) &&
+        !isTrivialPrimitive(prim)) {
+      if (prim is Interceptor) {
+        Interceptor interceptor = existing;
+        interceptor.interceptedClasses.addAll(prim.interceptedClasses);
+        interceptor.flags |= prim.flags;
+      }
+      prim..replaceUsesWith(existing)..destroy();
+      node.remove();
+      return next;
+    }
+
+    if (tryToHoistOutOfLoop(prim, gvn)) {
+      return next;
+    }
+
+    // The primitive could not be hoisted.  Put the primitive in the
+    // environment while processing the body of the LetPrim.
+    environment[gvn] = prim;
+    pushAction(() {
+      assert(environment[gvn] == prim);
+      environment[gvn] = existing;
+    });
+
+    return next;
+  }
+
+  /// Try to hoist the binding of [prim] out of loops. Returns `true` if it was
+  /// hoisted or marked as a trivial hoist-on-demand primitive.
+  bool tryToHoistOutOfLoop(Primitive prim, int gvn) {
+    // Do not hoist primitives with side effects.
+    if (!prim.isSafeForElimination) return false;
+
+    // Bail out fast if the primitive is not inside a loop.
+    if (currentLoopHeader == null) return false;
+
+    LetPrim letPrim = prim.parent;
+
+    // Find the depth of the outermost scope where we can bind the primitive
+    // without bringing a reference out of scope. 0 is the depth of the
+    // top-level scope.
+    int hoistDepth = 0;
+    List<Primitive> inputsHoistedOnDemand = <Primitive>[];
+    InputVisitor.forEach(prim, (Reference ref) {
+      Primitive input = ref.definition;
+      if (canIgnoreRefinementGuards(prim)) {
+        input = input.effectiveDefinition;
+      }
+      Continuation loopHeader;
+      if (potentialLoopHeaderFor.containsKey(input)) {
+        // This is a reference to a value that can be hoisted further out than
+        // it currently is.  If we decide to hoist [prim], we must also hoist
+        // such dependent values.
+        loopHeader = potentialLoopHeaderFor[input];
+        inputsHoistedOnDemand.add(input);
+      } else {
+        loopHeader = loopHeaderFor[input];
+      }
+      Continuation referencedLoop =
+          loopHierarchy.lowestCommonAncestor(loopHeader, currentLoopHeader);
+      int depth = loopHierarchy.getDepth(referencedLoop);
+      if (depth > hoistDepth) {
+        hoistDepth = depth;
+      }
+    });
+
+    // Bail out if it can not be hoisted further out than it is now.
+    if (hoistDepth == loopHierarchy.getDepth(currentLoopHeader)) return false;
+
+    // Walk up the loop hierarchy and check at every step that any heap
+    // dependencies can safely be hoisted out of the loop.
+    Continuation enclosingLoop = currentLoopHeader;
+    Continuation hoistTarget = null;
+    while (loopHierarchy.getDepth(enclosingLoop) > hoistDepth &&
+           canHoistHeapDependencyOutOfLoop(prim, enclosingLoop)) {
+      hoistTarget = enclosingLoop;
+      enclosingLoop = loopHierarchy.getEnclosingLoop(enclosingLoop);
+    }
+
+    // Bail out if heap dependencies prohibit any hoisting at all.
+    if (hoistTarget == null) return false;
+
+    if (isTrivialPrimitive(prim)) {
+      // The overhead from introducting a temporary might be greater than
+      // the overhead of evaluating this primitive at every iteration.
+      // Only hoist if this enables hoisting of a non-trivial primitive.
+      potentialLoopHeaderFor[prim] = enclosingLoop;
+      return true;
+    }
+
+    LetCont loopBinding = hoistTarget.parent;
+
+    // The primitive may depend on values that have not yet been
+    // hoisted as far as they can.  Hoist those now.
+    for (Primitive input in inputsHoistedOnDemand) {
+      hoistTrivialPrimitive(input, loopBinding, enclosingLoop);
+    }
+
+    // Hoist the primitive.
+    letPrim.remove();
+    letPrim.insertAbove(loopBinding);
+    loopHeaderFor[prim] = enclosingLoop;
+
+    // If a refinement guard was bypassed, use the best refinement
+    // currently in scope.
+    if (canIgnoreRefinementGuards(prim)) {
+      int target = loopHierarchy.getDepth(enclosingLoop);
+      InputVisitor.forEach(prim, (Reference ref) {
+        Primitive input = ref.definition;
+        while (input is Refinement) {
+          Continuation loop = loopHeaderFor[input];
+          loop = loopHierarchy.lowestCommonAncestor(loop, currentLoopHeader);
+          if (loopHierarchy.getDepth(loop) <= target) break;
+          Refinement refinement = input;
+          input = refinement.value.definition;
+        }
+        ref.changeTo(input);
+      });
+    }
+
+    // Put the primitive in the environment while processing the loop.
+    environment[gvn] = prim;
+    loopHoistedBindings
+        .putIfAbsent(hoistTarget, () => <int>[])
+        .add(gvn);
+    return true;
+  }
+
+  /// If the given primitive is a trivial primitive that should be hoisted
+  /// on-demand, hoist it and its dependent values above [loopBinding].
+  void hoistTrivialPrimitive(Primitive prim,
+                             LetCont loopBinding,
+                             Continuation enclosingLoop) {
+    if (!potentialLoopHeaderFor.containsKey(prim)) return;
+    assert(isTrivialPrimitive(prim));
+
+    // The primitive might already be bound in an outer scope.  Do not relocate
+    // the primitive unless we are lifting it. For example;
+    //    t1 = a + b
+    //    t2 = t1 + c
+    //    t3 = t1 * t2
+    // If it was decided that `t3` should be hoisted, `t1` will be seen twice by
+    // this method: by the direct reference and by reference through `t2`.
+    // The second time it is seen, it will already have been moved.
+    Continuation currentLoop = loopHeaderFor[prim];
+    int currentDepth = loopHierarchy.getDepth(currentLoop);
+    int targetDepth = loopHierarchy.getDepth(enclosingLoop);
+    if (currentDepth <= targetDepth) return;
+
+    // Hoist the trivial primitives being depended on so they remain in scope.
+    InputVisitor.forEach(prim, (Reference ref) {
+      hoistTrivialPrimitive(ref.definition, loopBinding, enclosingLoop);
+    });
+
+    // Move the primitive.
+    LetPrim binding = prim.parent;
+    binding.remove();
+    binding.insertAbove(loopBinding);
+    loopHeaderFor[prim] = enclosingLoop;
+
+    if (potentialLoopHeaderFor[prim] == enclosingLoop) {
+      potentialLoopHeaderFor.remove(prim);
+    }
+  }
+
+  bool canIgnoreRefinementGuards(Primitive primitive) {
+    return primitive is Interceptor;
+  }
+
+  /// Returns true if the given primitive is so cheap at runtime that it is
+  /// better to (redundantly) recompute it rather than introduce a temporary.
+  bool isTrivialPrimitive(Primitive primitive) {
+    return primitive is ApplyBuiltinOperator ||
+           primitive is Constant && isTrivialConstant(primitive.value);
+  }
+
+  /// Returns true if the given constant has almost no runtime cost.
+  bool isTrivialConstant(ConstantValue value) {
+    return value.isPrimitive || value.isDummy;
+  }
+
+  /// True if [element] is a final or constant field or a function.
+  bool isImmutable(Element element) {
+    if (element.isField && backend.isNative(element)) return false;
+    return element.isField && (element.isFinal || element.isConst) ||
+           element.isFunction;
+  }
+
+  /// Assuming [prim] has no side effects, returns true if it can safely
+  /// be hoisted out of [loop] without changing its value.
+  bool canHoistHeapDependencyOutOfLoop(Primitive prim, Continuation loop) {
+    assert(prim.isSafeForElimination);
+    if (prim is GetLength) {
+      return !loopEffects.loopChangesLength(loop);
+    } else if (prim is GetField && !isImmutable(prim.field)) {
+      return !loopEffects.getSideEffectsInLoop(loop).changesInstanceProperty();
+    } else if (prim is GetStatic && !isImmutable(prim.element)) {
+      return !loopEffects.getSideEffectsInLoop(loop).changesStaticProperty();
+    } else if (prim is GetIndex) {
+      return !loopEffects.getSideEffectsInLoop(loop).changesIndex();
+    } else {
+      return true;
+    }
+  }
+
+
+  // ------------------ TRAVERSAL AND EFFECT NUMBERING ---------------------
+  //
+  // These methods traverse the IR while updating the current effect numbers.
+  // They are not specific to GVN.
+  //
+  // TODO(asgerf): Avoid duplicated code for side effect analysis.
+  // Should be easier to fix once primitives and call expressions are the same.
+
+  void addSideEffects(SideEffects fx, {bool length: true}) {
+    if (fx.changesInstanceProperty()) {
+      effectNumbers.instanceField = makeNewEffect();
+    }
+    if (fx.changesStaticProperty()) {
+      effectNumbers.staticField = makeNewEffect();
+    }
+    if (fx.changesIndex()) {
+      effectNumbers.indexableContent = makeNewEffect();
+    }
+    if (length && fx.changesIndex()) {
+      effectNumbers.indexableLength = makeNewEffect();
+    }
+  }
+
+  void addAllSideEffects() {
+    effectNumbers.instanceField = makeNewEffect();
+    effectNumbers.staticField = makeNewEffect();
+    effectNumbers.indexableContent = makeNewEffect();
+    effectNumbers.indexableLength = makeNewEffect();
+  }
+
+  Expression traverseLetHandler(LetHandler node) {
+    // Assume any kind of side effects may occur in the try block.
+    effectsAt[node.handler] = new EffectNumbers()
+      ..instanceField = makeNewEffect()
+      ..staticField = makeNewEffect()
+      ..indexableContent = makeNewEffect()
+      ..indexableLength = makeNewEffect();
+    push(node.handler);
+    return node.body;
+  }
+
+  Expression traverseContinuation(Continuation cont) {
+    Continuation oldLoopHeader = currentLoopHeader;
+    currentLoopHeader = loopHierarchy.getLoopHeader(cont);
+    pushAction(() {
+      currentLoopHeader = oldLoopHeader;
+    });
+    for (Parameter param in cont.parameters) {
+      loopHeaderFor[param] = currentLoopHeader;
+    }
+    if (cont.isRecursive) {
+      addSideEffects(loopEffects.getSideEffectsInLoop(cont), length: false);
+      if (loopEffects.loopChangesLength(cont)) {
+        effectNumbers.indexableLength = makeNewEffect();
+      }
+      pushAction(() {
+        List<int> hoistedBindings = loopHoistedBindings[cont];
+        if (hoistedBindings != null) {
+          hoistedBindings.forEach(environment.remove);
+        }
+      });
+    } else {
+      EffectNumbers join = effectsAt[cont];
+      if (join != null) {
+        effectNumbers = join;
+      } else {
+        // This is a call continuation seen immediately after its use.
+        // Reuse the current effect numbers.
+      }
+    }
+
+    return cont.body;
+  }
+
+  void visitInvokeContinuation(InvokeContinuation node) {
+    Continuation cont = node.continuation.definition;
+    if (cont.isRecursive) return;
+    EffectNumbers join = effectsAt[cont];
+    if (join == null) {
+      effectsAt[cont] = effectNumbers.copy();
+    } else {
+      if (effectNumbers.instanceField != join.instanceField) {
+        join.instanceField = makeNewEffect();
+      }
+      if (effectNumbers.staticField != join.staticField) {
+        join.staticField = makeNewEffect();
+      }
+      if (effectNumbers.indexableContent != join.indexableContent) {
+        join.indexableContent = makeNewEffect();
+      }
+      if (effectNumbers.indexableLength != join.indexableLength) {
+        join.indexableLength = makeNewEffect();
+      }
+    }
+  }
+
+  void visitBranch(Branch node) {
+    Continuation trueCont = node.trueContinuation.definition;
+    Continuation falseCont = node.falseContinuation.definition;
+    // Copy the effect number vector once, so the analysis of one branch does
+    // not influence the other.
+    effectsAt[trueCont] = effectNumbers;
+    effectsAt[falseCont] = effectNumbers.copy();
+  }
+
+  void visitInvokeMethod(InvokeMethod node) {
+    addSideEffects(world.getSideEffectsOfSelector(node.selector, node.mask));
+  }
+
+  void visitInvokeStatic(InvokeStatic node) {
+    addSideEffects(world.getSideEffectsOfElement(node.target));
+  }
+
+  void visitInvokeMethodDirectly(InvokeMethodDirectly node) {
+    FunctionElement target = node.target;
+    if (target is ConstructorBodyElement) {
+      ConstructorBodyElement body = target;
+      target = body.constructor;
+    }
+    addSideEffects(world.getSideEffectsOfElement(target));
+  }
+
+  void visitInvokeConstructor(InvokeConstructor node) {
+    addSideEffects(world.getSideEffectsOfElement(node.target));
+  }
+
+  void visitSetStatic(SetStatic node) {
+    effectNumbers.staticField = makeNewEffect();
+  }
+
+  void visitSetField(SetField node) {
+    effectNumbers.instanceField = makeNewEffect();
+  }
+
+  void visitSetIndex(SetIndex node) {
+    effectNumbers.indexableContent = makeNewEffect();
+  }
+
+  void visitForeignCode(ForeignCode node) {
+    addSideEffects(node.nativeBehavior.sideEffects);
+  }
+
+  void visitGetLazyStatic(GetLazyStatic node) {
+    // TODO(asgerf): How do we get the side effects of a lazy field initializer?
+    addAllSideEffects();
+  }
+
+  void visitAwait(Await node) {
+    addAllSideEffects();
+  }
+
+  void visitYield(Yield node) {
+    addAllSideEffects();
+  }
+
+  void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
+    // Push and pop.
+    effectNumbers.indexableContent = makeNewEffect();
+    effectNumbers.indexableLength = makeNewEffect();
+  }
+}
+
+/// For each of the four categories of heap locations, the IR is divided into
+/// regions wherein the given heap locations are known not to be modified.
+///
+/// Each region is identified by its "effect number".  Effect numbers from
+/// different categories have no relationship to each other.
+class EffectNumbers {
+  int indexableLength = 0;
+  int indexableContent = 0;
+  int staticField = 0;
+  int instanceField = 0;
+
+  EffectNumbers copy() {
+    return new EffectNumbers()
+      ..indexableLength = indexableLength
+      ..indexableContent = indexableContent
+      ..staticField = staticField
+      ..instanceField = instanceField;
+  }
+}
+
+/// Maps vectors to numbers, such that two vectors with the same contents
+/// map to the same number.
+class GvnTable {
+  Map<GvnEntry, int> _table = <GvnEntry, int>{};
+  int _usedGvns = 0;
+  int _makeNewGvn() => ++_usedGvns;
+
+  int insert(List vector) {
+    return _table.putIfAbsent(new GvnEntry(vector), _makeNewGvn);
+  }
+}
+
+/// Wrapper around a [List] that compares for equality based on contents
+/// instead of object identity.
+class GvnEntry {
+  final List vector;
+  final int hashCode;
+
+  GvnEntry(List vector) : vector = vector, hashCode = computeHashCode(vector);
+
+  bool operator==(other) {
+    if (other is! GvnEntry) return false;
+    GvnEntry entry = other;
+    List otherVector = entry.vector;
+    if (vector.length != otherVector.length) return false;
+    for (int i = 0; i < vector.length; ++i) {
+      if (vector[i] != otherVector[i]) return false;
+    }
+    return true;
+  }
+
+  /// Combines the hash codes of [vector] using Jenkin's hash function, with
+  /// intermediate results truncated to SMI range.
+  static int computeHashCode(List vector) {
+    int hash = 0;
+    for (int i = 0; i < vector.length; ++i) {
+      hash = 0x1fffffff & (hash + vector[i].hashCode);
+      hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+      hash = hash ^ (hash >> 6);
+    }
+    hash = 0x1fffffff & (hash + ((0x03ffffff & hash) <<  3));
+    hash = hash ^ (hash >> 11);
+    return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+  }
+}
+
+/// Converts GVN'able primitives to a vector containing all the values
+/// to be considered when computing a GVN for it.
+///
+/// This includes the instruction type, inputs, effect numbers for any part
+/// of the heap being depended on, as well as any instruction-specific payload
+/// such as any DartTypes, Elements, and operator kinds.
+///
+/// Each `visit` or `process` method for a primitive must initialize [vector]
+/// if the primitive is GVN'able and fill in any components except the inputs.
+/// The inputs will be filled in by [processReference].
+class GvnVectorBuilder extends DeepRecursiveVisitor {
+  List vector;
+  final Map<Primitive, int> gvnFor;
+  final JavaScriptBackend backend;
+  EffectNumbers effectNumbers;
+
+  GvnVectorBuilder(this.gvnFor, this.backend);
+
+  List make(Primitive prim, EffectNumbers effectNumbers) {
+    this.effectNumbers = effectNumbers;
+    vector = null;
+    visit(prim);
+    return vector;
+  }
+
+  /// The `process` methods below do not insert the referenced arguments into
+  /// the vector, but instead rely on them being inserted here.
+  processReference(Reference ref) {
+    if (vector == null) return;
+    Primitive prim = ref.definition.effectiveDefinition;
+    vector.add(gvnFor[prim] ?? prim);
+  }
+
+  processTypeTest(TypeTest node) {
+    vector = [GvnCode.TYPE_TEST, node.dartType];
+  }
+
+  processTypeTestViaFlag(TypeTestViaFlag node) {
+    vector = [GvnCode.TYPE_TEST_VIA_FLAG, node.dartType];
+  }
+
+  processApplyBuiltinOperator(ApplyBuiltinOperator node) {
+    vector = [GvnCode.BUILTIN_OPERATOR, node.operator.index];
+  }
+
+  processGetLength(GetLength node) {
+    // TODO(asgerf): Take fixed lengths into account?
+    vector = [GvnCode.GET_LENGTH, effectNumbers.indexableLength];
+  }
+
+  bool isImmutable(Element element) {
+    return element.isFunction ||
+           element.isField && (element.isFinal || element.isConst);
+  }
+
+  bool isNativeField(FieldElement field) {
+    // TODO(asgerf): We should add a GetNativeField instruction.
+    return backend.isNative(field);
+  }
+
+  processGetField(GetField node) {
+    if (isNativeField(node.field)) {
+      vector = null; // Native field access cannot be GVN'ed.
+    } else if (isImmutable(node.field)) {
+      vector = [GvnCode.GET_FIELD, node.field];
+    } else {
+      vector = [GvnCode.GET_FIELD, node.field, effectNumbers.instanceField];
+    }
+  }
+
+  processGetIndex(GetIndex node) {
+    vector = [GvnCode.GET_INDEX, effectNumbers.indexableContent];
+  }
+
+  processGetStatic(GetStatic node) {
+    if (isImmutable(node.element)) {
+      vector = [GvnCode.GET_STATIC, node.element];
+    } else {
+      vector = [GvnCode.GET_STATIC, node.element, effectNumbers.staticField];
+    }
+  }
+
+  processGetLazyStatic(GetLazyStatic node) {
+    if (isImmutable(node.element)) {
+      vector = [GvnCode.GET_STATIC, node.element];
+    } else {
+      vector = [GvnCode.GET_STATIC, node.element, effectNumbers.staticField];
+    }
+  }
+
+  processConstant(Constant node) {
+    vector = [GvnCode.CONSTANT, node.value];
+  }
+
+  processReifyRuntimeType(ReifyRuntimeType node) {
+    vector = [GvnCode.REIFY_RUNTIME_TYPE];
+  }
+
+  processReadTypeVariable(ReadTypeVariable node) {
+    vector = [GvnCode.READ_TYPE_VARIABLE, node.variable];
+  }
+
+  processTypeExpression(TypeExpression node) {
+    vector = [GvnCode.TYPE_EXPRESSION, node.dartType];
+  }
+
+  processInterceptor(Interceptor node) {
+    vector = [GvnCode.INTERCEPTOR];
+  }
+}
+
+class GvnCode {
+  static const int TYPE_TEST = 1;
+  static const int TYPE_TEST_VIA_FLAG = 2;
+  static const int BUILTIN_OPERATOR = 3;
+  static const int GET_LENGTH = 4;
+  static const int GET_FIELD = 5;
+  static const int GET_INDEX = 6;
+  static const int GET_STATIC = 7;
+  static const int CONSTANT = 8;
+  static const int REIFY_RUNTIME_TYPE = 9;
+  static const int READ_TYPE_VARIABLE = 10;
+  static const int TYPE_EXPRESSION = 11;
+  static const int INTERCEPTOR = 12;
+}
+
+typedef ReferenceCallback(Reference ref);
+class InputVisitor extends DeepRecursiveVisitor {
+  ReferenceCallback callback;
+
+  InputVisitor(this.callback);
+
+  @override
+  processReference(Reference ref) {
+    callback(ref);
+  }
+
+  static void forEach(Primitive node, ReferenceCallback callback) {
+    new InputVisitor(callback).visit(node);
+  }
+}
diff --git a/pkg/compiler/lib/src/cps_ir/insert_refinements.dart b/pkg/compiler/lib/src/cps_ir/insert_refinements.dart
index 6c5ec70..66fe170 100644
--- a/pkg/compiler/lib/src/cps_ir/insert_refinements.dart
+++ b/pkg/compiler/lib/src/cps_ir/insert_refinements.dart
@@ -75,11 +75,15 @@
     return prim is Interceptor ? prim.input.definition : prim;
   }
 
-  /// Enqueues [cont] for processing in a context where [refined] is the
-  /// current refinement for its value.
-  void pushRefinement(Continuation cont, Refinement refined) {
+  /// Sets [refined] to be the current refinement for its value, and pushes an
+  /// action that will restore the original scope again.
+  ///
+  /// The refinement is inserted as the child of [insertionParent] if it has
+  /// at least one use after its scope has been processed.
+  void applyRefinement(InteriorNode insertionParent, Refinement refined) {
     Primitive value = refined.effectiveDefinition;
     Primitive currentRefinement = refinementFor[value];
+    refinementFor[value] = refined;
     pushAction(() {
       refinementFor[value] = currentRefinement;
       if (refined.hasNoUses) {
@@ -87,18 +91,21 @@
         refined.destroy();
       } else {
         LetPrim let = new LetPrim(refined);
-        let.insertBelow(cont);
+        let.insertBelow(insertionParent);
       }
     });
-    push(cont);
+  }
+
+  /// Enqueues [cont] for processing in a context where [refined] is the
+  /// current refinement for its value.
+  void pushRefinement(Continuation cont, Refinement refined) {
     pushAction(() {
-      refinementFor[value] = refined;
+      applyRefinement(cont, refined);
+      push(cont);
     });
   }
 
   void visitInvokeMethod(InvokeMethod node) {
-    Continuation cont = node.continuation.definition;
-
     // Update references to their current refined values.
     processReference(node.receiver);
     node.arguments.forEach(processReference);
@@ -107,34 +114,28 @@
     // not the interceptor.
     Primitive receiver = unfoldInterceptor(node.receiver.definition);
 
-    // Sink the continuation to the call to ensure everything in scope
-    // here is also in scope inside the continuations.
-    sinkContinuationToUse(cont, node);
-
-    if (node.selector.isClosureCall) {
-      // Do not try to refine the receiver of closure calls; the class world
-      // does not know about closure classes.
-      push(cont);
-    } else {
+    // Do not try to refine the receiver of closure calls; the class world
+    // does not know about closure classes.
+    if (!node.selector.isClosureCall) {
       // Filter away receivers that throw on this selector.
       TypeMask type = types.receiverTypeFor(node.selector, node.mask);
       Refinement refinement = new Refinement(receiver, type);
-      pushRefinement(cont, refinement);
+      LetPrim letPrim = node.parent;
+      applyRefinement(letPrim, refinement);
     }
   }
 
   void visitTypeCast(TypeCast node) {
-    Continuation cont = node.continuation.definition;
     Primitive value = node.value.definition;
 
     processReference(node.value);
     node.typeArguments.forEach(processReference);
 
     // Refine the type of the input.
-    sinkContinuationToUse(cont, node);
     TypeMask type = types.subtypesOf(node.dartType).nullable();
     Refinement refinement = new Refinement(value, type);
-    pushRefinement(cont, refinement);
+    LetPrim letPrim = node.parent;
+    applyRefinement(letPrim, refinement);
   }
 
   void visitRefinement(Refinement node) {
@@ -151,16 +152,6 @@
     });
   }
 
-  CallExpression getCallWithResult(Primitive prim) {
-    if (prim is Parameter && prim.parent is Continuation) {
-      Continuation cont = prim.parent;
-      if (cont.hasExactlyOneUse && cont.firstRef.parent is CallExpression) {
-        return cont.firstRef.parent;
-      }
-    }
-    return null;
-  }
-
   bool isTrue(Primitive prim) {
     return prim is Constant && prim.value.isTrue;
   }
@@ -168,7 +159,6 @@
   void visitBranch(Branch node) {
     processReference(node.condition);
     Primitive condition = node.condition.definition;
-    CallExpression call = getCallWithResult(condition);
 
     Continuation trueCont = node.trueContinuation.definition;
     Continuation falseCont = node.falseContinuation.definition;
@@ -212,9 +202,9 @@
       }
     }
 
-    if (call is InvokeMethod && call.selector == Selectors.equals) {
-      refineEquality(call.arguments[0].definition,
-                     call.arguments[1].definition,
+    if (condition is InvokeMethod && condition.selector == Selectors.equals) {
+      refineEquality(condition.dartReceiver,
+                     condition.dartArgument(0),
                      trueCont,
                      falseCont);
       return;
@@ -236,13 +226,8 @@
   @override
   Expression traverseLetCont(LetCont node) {
     for (Continuation cont in node.continuations) {
-      if (cont.hasExactlyOneUse &&
-          (cont.firstRef.parent is InvokeMethod ||
-           cont.firstRef.parent is TypeCast ||
-           cont.firstRef.parent is Branch)) {
-        // Do not push the continuation here.
-        // visitInvokeMethod, visitBranch, and visitTypeCast will do that.
-      } else {
+      // Do not push the branch continuations here. visitBranch will do that.
+      if (!(cont.hasExactlyOneUse && cont.firstRef.parent is Branch)) {
         push(cont);
       }
     }
diff --git a/pkg/compiler/lib/src/cps_ir/loop_effects.dart b/pkg/compiler/lib/src/cps_ir/loop_effects.dart
index 9dd39ff..6679336 100644
--- a/pkg/compiler/lib/src/cps_ir/loop_effects.dart
+++ b/pkg/compiler/lib/src/cps_ir/loop_effects.dart
@@ -46,9 +46,7 @@
   Expression traverseContinuation(Continuation cont) {
     if (cont.isRecursive) {
       SideEffects oldEffects = currentLoopSideEffects;
-      Continuation oldLoopHeader = currentLoopHeader;
       bool oldChangesLength = currentLoopChangesLength;
-      currentLoopHeader = cont;
       loopSideEffects[cont] = currentLoopSideEffects = new SideEffects.empty();
       exitContinuations[cont] = <Continuation>[];
       pushAction(() {
@@ -57,11 +55,15 @@
           loopsChangingLength.add(cont);
         }
         currentLoopChangesLength = currentLoopChangesLength || oldChangesLength;
-        currentLoopHeader = oldLoopHeader;
         currentLoopSideEffects = oldEffects;
         exitContinuations[cont].forEach(push);
       });
     }
+    Continuation oldLoopHeader = currentLoopHeader;
+    currentLoopHeader = loopHierarchy.getLoopHeader(cont);
+    pushAction(() {
+      currentLoopHeader = oldLoopHeader;
+    });
     return cont.body;
   }
 
@@ -87,6 +89,13 @@
       Continuation inner = currentLoopHeader;
       Continuation outer = loopHierarchy.getEnclosingLoop(currentLoopHeader);
       while (outer != loop) {
+        if (inner == null) {
+          // The shrinking reductions pass must run before any pass that relies
+          // on computing loop side effects.
+          world.compiler.reporter.internalError(null,
+              'Unreachable continuations must be removed before computing '
+              'loop side effects.');
+        }
         inner = outer;
         outer = loopHierarchy.getEnclosingLoop(outer);
       }
@@ -171,6 +180,7 @@
   }
 
   void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
+    currentLoopSideEffects.setChangesIndex();
     currentLoopChangesLength = true; // Push and pop.
   }
 }
diff --git a/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart b/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
index 3aa5bc9..99b1105 100644
--- a/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
+++ b/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
@@ -99,29 +99,13 @@
     return loopTarget[cont];
   }
 
-  bool _isCallContinuation(Continuation cont) {
-    return cont.hasExactlyOneUse && cont.firstRef.parent is CallExpression;
-  }
-
   /// Analyzes a basic block and returns the innermost loop that
   /// can be invoked recursively from that block.
   Continuation _processBlock(Expression node, Continuation catchLoop) {
-    List<Continuation> callContinuations = <Continuation>[];
     for (; node is! TailExpression; node = node.next) {
       if (node is LetCont) {
         for (Continuation cont in node.continuations) {
-          if (!_isCallContinuation(cont)) {
-            // Process non-call continuations at the binding site, so they
-            // their loop target is known at all use sites.
-            _processContinuation(cont, catchLoop);
-          } else {
-            // To avoid deep recursion, do not analyze call continuations
-            // recursively. This basic block traversal steps into the
-            // call contiunation after visiting its use site. We store the
-            // continuations in a list so we can set the loop target once
-            // it is known.
-            callContinuations.add(cont);
-          }
+          _processContinuation(cont, catchLoop);
         }
       } else if (node is LetHandler) {
         catchLoop = _processContinuation(node.handler, catchLoop);
@@ -141,13 +125,28 @@
     } else {
       assert(node is Unreachable || node is Throw);
     }
-    target = _markInnerLoop(target, catchLoop);
-    for (Continuation cont in callContinuations) {
-      // Store the loop target on each call continuation in the basic block.
-      // Because we walk over call continuations as part of the basic block
-      // traversal, these do not get their loop target set otherwise.
-      loopTarget[cont] = target;
+    return _markInnerLoop(target, catchLoop);
+  }
+
+  /// Returns the 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);
+    while (c1 != c2) {
+      if (d1 <= d2) {
+        c2 = getEnclosingLoop(c2);
+        d2 = getDepth(c2);
+      } else {
+        c1 = getEnclosingLoop(c1);
+        d1 = getDepth(c1);
+      }
     }
-    return target;
+    return c1;
+  }
+
+  /// Returns the lexical nesting depth of [loop].
+  int getDepth(Continuation loop) {
+    if (loop == null) return 0;
+    return loopDepth[loop];
   }
 }
diff --git a/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart b/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
index d4630b5..e5ea7a8 100644
--- a/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
+++ b/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
@@ -168,7 +168,7 @@
         if (shouldRewrite(variable)) {
           // Replace with the reaching definition from the environment.
           Primitive value = environment[variable];
-          value.substituteFor(getter);
+          getter.replaceUsesWith(value);
           mergeHints(variable, value);
           node.remove();
         }
diff --git a/pkg/compiler/lib/src/cps_ir/octagon.dart b/pkg/compiler/lib/src/cps_ir/octagon.dart
index 8dfd5f1..691c15d 100644
--- a/pkg/compiler/lib/src/cps_ir/octagon.dart
+++ b/pkg/compiler/lib/src/cps_ir/octagon.dart
@@ -4,6 +4,8 @@
 
 library dart2js.cps_ir.octagon;
 
+import 'dart:collection';
+
 /// For every variable in the constraint system, two [SignedVariable]s exist,
 /// representing the positive and negative uses of the variable.
 ///
@@ -20,9 +22,6 @@
   static int _hashCount = 0;
   final int hashCode = (_hashCount = _hashCount + 1) & 0x0fffffff;
 
-  /// Temporary field used by the constraint solver's graph search.
-  bool _isBeingVisited = false;
-
   SignedVariable._make() {
     _negated = new SignedVariable._makeTwin(this);
   }
@@ -87,17 +86,14 @@
   ///
   /// The constraint should be removed again using [popConstraint].
   void pushConstraint(Constraint constraint) {
-    if (_unsolvableCounter > 0) {
+    if (_unsolvableCounter > 0 ||
+        _unsolvableCounter == 0 && _checkUnsolvable(constraint)) {
       ++_unsolvableCounter;
     }
     constraint.v1._constraints.add(constraint);
     if (constraint.v1 != constraint.v2) {
       constraint.v2._constraints.add(constraint);
     }
-    // Check if this constraint has made the system unsolvable.
-    if (_unsolvableCounter == 0 && _checkUnsolvable(constraint)) {
-      _unsolvableCounter = 1;
-    }
   }
 
   /// Remove a constraint that was previously added with [pushConstraint].
@@ -115,101 +111,87 @@
     }
   }
 
-  // Temporaries using during path finding.
-  SignedVariable _goal;
-  Map<SignedVariable, int> _distanceToGoal;
-
-  /// Return true if the recently added [constraint] made the system unsolvable.
+  /// Return true if [constraint] would make the constraint system unsolvable.
   ///
-  /// This function assumes the system was solvable before adding [constraint].
+  /// Assumes the system is currently solvable.
   bool _checkUnsolvable(Constraint constraint) {
     // Constraints are transitively composed like so:
-    //    v1 - v2 <= k1
-    //    v2 - v3 <= k2
+    //    v1 + v2 <= k1
+    //   -v2 + v3 <= k2
     // implies:
-    //    v1 - v3 <= k1 + k2
+    //    v1 + v3 <= k1 + k2
     //
-    // We construct a graph such that the tightest bound on `v1 - v3` is the
-    // weight of the shortest path from `v1` to `v3`.
+    // We construct a graph such that the tightest bound on `v1 + v3` is the
+    // weight of the shortest path from `v1` to `-v3`.
     //
-    // Ever constraint `v1 - v2 <= k` gives rise to two edges:
-    //     (v1)  --k--> (v2)
-    //     (-v2) --k--> (-v2)
+    // Every constraint `v1 + v2 <= k` gives rise to two edges:
+    //     (v1) --k--> (-v2)
+    //     (v2) --k--> (-v1)
     //
     // The system is unsolvable if and only if a negative-weight cycle exists
     // in this graph (this corresponds to a variable being less than itself).
 
-    // We assume the system was solvable to begin with, so we only look for
-    // cycles that use the new edges.
-    //
-    // The new [constraint] `v1 + v2 <= k` just added the edges:
-    //     (v1)  --k--> (-v2)
-    //     (v2)  --k--> (-v1)
-    //
-    // Look for a path from (-v2) to (v1) with weight at most -k-1, as this
-    // will complete a negative-weight cycle.
-
-    // It suffices to do this once. We need not check for the converse path
-    // (-v1) to (v2) because of the symmetry in the graph.
-    //
-    // Note that the graph symmetry is not a redundancy. Some cycles include
-    // both of the new edges at once, so they must be added to the graph
-    // beforehand.
-    _goal = constraint.v2;
-    _distanceToGoal = <SignedVariable, int>{};
-    int targetWeight = -constraint.bound - 1;
-    int pathWeight = _search(constraint.v1.negated, targetWeight, 0);
-    return pathWeight != null && pathWeight <= targetWeight;
+    // Check if a negative-weight cycle would be created by adding [constraint].
+    int length = _cycleLength(constraint);
+    return length != null && length < 0;
   }
 
-  static const int MAX_DEPTH = 100;
-
-  /// Returns the shortest path from [v1] to [_goal] (or any path shorter than
-  /// [budget]), or `null` if no path exists.
-  int _search(SignedVariable v1, int budget, int depth) {
-    if (v1 == _goal && budget >= 0) return 0;
-
-    // Disregard paths that use a lot of edges.
-    // In extreme cases (e.g. hundreds of `push` calls or nested ifs) this can
-    // get slow and/or overflow the stack.  Most paths that matter are very
-    // short (1-5 edges) with some occasional 10-30 length paths in math code.
-    if (depth >= MAX_DEPTH) return null;
-
-    // We found a cycle, but not the one we're looking for. If the constraint
-    // system was solvable to being with, then this must be a positive-weight
-    // cycle, and no shortest path goes through a positive-weight cycle.
-    if (v1._isBeingVisited) return null;
-
-    // Check if we have previously searched from here.
-    if (_distanceToGoal.containsKey(v1)) {
-      // We have already searched this node, return the cached answer.
-      // Note that variables may explicitly map to null, so the double lookup
-      // is necessary.
-      return _distanceToGoal[v1];
+  /// Returns the length of the shortest simple cycle that would be created by
+  /// adding [constraint] to the graph.
+  ///
+  /// Assumes there are no existing negative-weight cycles. The new cycle
+  /// may have negative weight as [constraint] has not been added yet.
+  int _cycleLength(Constraint constraint) {
+    // Single-source shortest path using a FIFO queue.
+    Queue<SignedVariable> worklist = new Queue<SignedVariable>();
+    Map<SignedVariable, int> distance = {};
+    void updateDistance(SignedVariable v, int newDistance) {
+      int oldDistance = distance[v];
+      if (oldDistance == null || oldDistance > newDistance) {
+        distance[v] = newDistance;
+        worklist.addLast(v);
+      }
     }
-
-    v1._isBeingVisited = true;
-
-    int shortestDistance = v1 == _goal ? 0 : null;
-    for (Constraint c in v1._constraints) {
-      SignedVariable v2 = c.v1 == v1 ? c.v2 : c.v1;
-      int distance = _search(v2.negated, budget - c.bound, depth + 1);
-      if (distance != null) {
-        distance += c.bound; // Pay the cost of using the edge.
-         if (distance <= budget) {
-          // Success! We found a path that is short enough so return fast.
-          // All recursive calls will now return immediately, so there is no
-          // need to update distanceToGoal, but we need to clear the
-          // beingVisited flag for the next query.
-          v1._isBeingVisited = false;
-          return distance;
-        } else if (shortestDistance == null || distance < shortestDistance) {
-          shortestDistance = distance;
+    void iterateWorklist() {
+      while (!worklist.isEmpty) {
+        SignedVariable v1 = worklist.removeFirst();
+        int distanceToV1 = distance[v1];
+        for (Constraint c in v1._constraints) {
+          SignedVariable v2 = c.v1 == v1 ? c.v2 : c.v1;
+          updateDistance(v2.negated, distanceToV1 + c.bound);
         }
       }
     }
-    v1._isBeingVisited = false;
-    _distanceToGoal[v1] = shortestDistance;
-    return shortestDistance;
+    // Two new edges will be added by the constraint `v1 + v2 <= k`:
+    //
+    //   A. (v1) --> (-v2)
+    //   B. (v2) --> (-v1)
+    //
+    // We need to check for two kinds of cycles:
+    //
+    //   Using only A:       (-v2) --> (v1) --A--> (-v2)
+    //   Using B and then A: (-v2) --> (v2) --B--> (-v1) --> (v1) --A--> (-v2)
+    //
+    // Because of the graph symmetry, cycles using only B or using A and then B
+    // exist if and only if the corresponding cycle above exist, so there is no
+    // need to check for those.
+    //
+    // Do a single-source shortest paths reaching out from (-v2).
+    updateDistance(constraint.v2.negated, 0);
+    iterateWorklist();
+    if (constraint.v1 != constraint.v2) {
+      int distanceToV2 = distance[constraint.v2];
+      if (distanceToV2 != null) {
+        // Allow one use of the B edge.
+        // This must be done outside fixpoint iteration as an infinite loop
+        // would arise when an negative-weight cycle using only B exists.
+        updateDistance(constraint.v1.negated, distanceToV2 + constraint.bound);
+        iterateWorklist();
+      }
+    }
+    // Get the distance to (v1) and check if the A edge would complete a cycle.
+    int distanceToV1 = distance[constraint.v1];
+    if (distanceToV1 == null) return null;
+    return distanceToV1 + constraint.bound;
   }
 }
diff --git a/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart b/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart
new file mode 100644
index 0000000..599989a
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart
@@ -0,0 +1,187 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.cps_ir.optimize_interceptors;
+
+import 'optimizers.dart';
+import 'cps_ir_nodes.dart';
+import 'loop_hierarchy.dart';
+import 'cps_fragment.dart';
+import '../constants/values.dart';
+import '../elements/elements.dart';
+import '../js_backend/backend_helpers.dart' show BackendHelpers;
+import '../js_backend/js_backend.dart' show JavaScriptBackend;
+import '../types/types.dart' show TypeMask;
+import '../io/source_information.dart' show SourceInformation;
+
+/// Replaces `getInterceptor` calls with interceptor constants when possible,
+/// or with "almost constant" expressions like "x && CONST" when the input
+/// is either null or has a known interceptor.
+//
+//  TODO(asgerf): Compute intercepted classes in this pass.
+class OptimizeInterceptors extends TrampolineRecursiveVisitor implements Pass {
+  String get passName => 'Optimize interceptors';
+
+  JavaScriptBackend backend;
+  LoopHierarchy loopHierarchy;
+  Continuation currentLoopHeader;
+
+  OptimizeInterceptors(this.backend);
+
+  BackendHelpers get helpers => backend.helpers;
+
+  void rewrite(FunctionDefinition node) {
+    // TODO(asgerf): Computing the LoopHierarchy here may be overkill when all
+    //               we want is to hoist constants out of loops.
+    loopHierarchy = new LoopHierarchy(node);
+    visit(node.body);
+    new ShareConstants().visit(node);
+  }
+
+  @override
+  Expression traverseContinuation(Continuation cont) {
+    Continuation oldLoopHeader = currentLoopHeader;
+    currentLoopHeader = loopHierarchy.getLoopHeader(cont);
+    pushAction(() {
+      currentLoopHeader = oldLoopHeader;
+    });
+    return cont.body;
+  }
+
+  /// If only one method table can be returned by the given interceptor,
+  /// returns a constant for that method table.
+  InterceptorConstantValue getInterceptorConstant(Interceptor node) {
+    if (node.interceptedClasses.length == 1 &&
+        node.isInterceptedClassAlwaysExact) {
+      ClassElement interceptorClass = node.interceptedClasses.single;
+      return new InterceptorConstantValue(interceptorClass.rawType);
+    }
+    return null;
+  }
+
+  bool hasNoFalsyValues(ClassElement class_) {
+    return class_ != helpers.jsInterceptorClass &&
+       class_ != helpers.jsNullClass &&
+       class_ != helpers.jsBoolClass &&
+       class_ != helpers.jsStringClass &&
+       !class_.isSubclassOf(helpers.jsNumberClass);
+  }
+
+  Continuation getCurrentOuterLoop({Continuation scope}) {
+    Continuation inner = null, outer = currentLoopHeader;
+    while (outer != scope) {
+      inner = outer;
+      outer = loopHierarchy.getEnclosingLoop(outer);
+    }
+    return inner;
+  }
+
+  /// Binds the given constant in a primitive, in scope of the [useSite].
+  ///
+  /// The constant will be hoisted out of loops, and shared with other requests
+  /// for the same constant as long as it is in scope.
+  Primitive makeConstantFor(ConstantValue constant,
+                            {Expression useSite,
+                             TypeMask type,
+                             SourceInformation sourceInformation,
+                             Entity hint}) {
+    Constant prim =
+        new Constant(constant, sourceInformation: sourceInformation);
+    prim.hint = hint;
+    prim.type = type;
+    LetPrim letPrim = new LetPrim(prim);
+    Continuation loop = getCurrentOuterLoop();
+    if (loop != null) {
+      LetCont loopBinding = loop.parent;
+      letPrim.insertAbove(loopBinding);
+    } else {
+      letPrim.insertAbove(useSite);
+    }
+    return prim;
+  }
+
+  void constifyInterceptor(Interceptor interceptor) {
+    LetPrim let = interceptor.parent;
+    InterceptorConstantValue constant = getInterceptorConstant(interceptor);
+
+    if (constant == null) return;
+
+    if (interceptor.isAlwaysIntercepted) {
+      Primitive constantPrim = makeConstantFor(constant,
+          useSite: let,
+          type: interceptor.type,
+          sourceInformation: interceptor.sourceInformation);
+      constantPrim.useElementAsHint(interceptor.hint);
+      interceptor..replaceUsesWith(constantPrim)..destroy();
+      let.remove();
+    } else if (interceptor.isAlwaysNullOrIntercepted) {
+      Primitive input = interceptor.input.definition;
+      Primitive constantPrim = makeConstantFor(constant,
+          useSite: let,
+          type: interceptor.type.nonNullable(),
+          sourceInformation: interceptor.sourceInformation);
+      CpsFragment cps = new CpsFragment(interceptor.sourceInformation);
+      Parameter param = new Parameter(interceptor.hint);
+      Continuation cont = cps.letCont(<Parameter>[param]);
+      if (interceptor.interceptedClasses.every(hasNoFalsyValues)) {
+        // If null is the only falsy value, compile as "x && CONST".
+        cps.ifFalsy(input).invokeContinuation(cont, [input]);
+      } else {
+        // If there are other falsy values compile as "x == null ? x : CONST".
+        Primitive condition = cps.applyBuiltin(
+            BuiltinOperator.LooseEq,
+            [input, cps.makeNull()]);
+        cps.ifTruthy(condition).invokeContinuation(cont, [input]);
+      }
+      cps.invokeContinuation(cont, [constantPrim]);
+      cps.context = cont;
+      cps.insertAbove(let);
+      interceptor..replaceUsesWith(param)..destroy();
+      let.remove();
+    }
+  }
+
+  @override
+  Expression traverseLetPrim(LetPrim node) {
+    Expression next = node.body;
+    if (node.primitive is Interceptor) {
+      constifyInterceptor(node.primitive);
+    }
+    return next;
+  }
+}
+
+/// Shares interceptor constants when one is in scope of another.
+///
+/// Interceptor optimization runs after GVN, hence this clean-up step is needed.
+///
+/// TODO(asgerf): Handle in separate constant optimization pass? With some other
+///   constant-related optimizations, like cloning small constants at use-site.
+class ShareConstants extends TrampolineRecursiveVisitor {
+  Map<ConstantValue, Constant> sharedConstantFor = <ConstantValue, Constant>{};
+
+  Expression traverseLetPrim(LetPrim node) {
+    Expression next = node.body;
+    if (node.primitive is Constant && shouldShareConstant(node.primitive)) {
+      Constant prim = node.primitive;
+      Constant existing = sharedConstantFor[prim.value];
+      if (existing != null) {
+        existing.useElementAsHint(prim.hint);
+        prim..replaceUsesWith(existing)..destroy();
+        node.remove();
+        return next;
+      }
+      sharedConstantFor[prim.value] = prim;
+      pushAction(() {
+        assert(sharedConstantFor[prim.value] == prim);
+        sharedConstantFor.remove(prim.value);
+      });
+    }
+    return next;
+  }
+
+  bool shouldShareConstant(Constant constant) {
+    return constant.value.isInterceptor;
+  }
+}
diff --git a/pkg/compiler/lib/src/cps_ir/optimizers.dart b/pkg/compiler/lib/src/cps_ir/optimizers.dart
index 37e8b3c..9d5f13e 100644
--- a/pkg/compiler/lib/src/cps_ir/optimizers.dart
+++ b/pkg/compiler/lib/src/cps_ir/optimizers.dart
@@ -15,9 +15,10 @@
 export 'mutable_ssa.dart' show MutableVariableEliminator;
 export 'insert_refinements.dart' show InsertRefinements;
 export 'remove_refinements.dart' show RemoveRefinements;
-export 'share_final_fields.dart' show ShareFinalFields;
-export 'share_interceptors.dart' show ShareInterceptors;
+export 'redundant_refinement.dart' show RedundantRefinementEliminator;
+export 'optimize_interceptors.dart' show OptimizeInterceptors;
 export 'bounds_checker.dart' show BoundsChecker;
+export 'gvn.dart' show GVN;
 export 'parent_visitor.dart' show ParentVisitor;
 
 /// An optimization pass over the CPS IR.
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_phi.dart b/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
index 183f8e3..7f16af9 100644
--- a/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
+++ b/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
@@ -138,7 +138,7 @@
       // * and implicitly remove param from continuation signature and
       //   invocations by not incrementing `dst`. References of removed
       //   arguments are unlinked to keep definition usages up to date.
-      uniqueDefinition.substituteFor(oldDefinition);
+      oldDefinition.replaceUsesWith(uniqueDefinition);
       for (InvokeContinuation invoke in invokes) {
         invoke.arguments[src].unlink();
       }
@@ -191,7 +191,7 @@
 
 /// Ensures [continuation] has its own LetCont binding by creating
 /// a new LetCont below its current binding, if necessary.
-/// 
+///
 /// Returns the LetCont that now binds [continuation].
 LetCont _makeUniqueBinding(Continuation continuation) {
   LetCont letCont = continuation.parent;
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_refinement.dart b/pkg/compiler/lib/src/cps_ir/redundant_refinement.dart
new file mode 100644
index 0000000..cff47d6
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/redundant_refinement.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.cps_ir.redundant_refinement;
+
+import 'cps_ir_nodes.dart';
+import 'optimizers.dart' show Pass;
+import 'type_mask_system.dart';
+
+/// Removes [Refinement] nodes where the input value is already known to
+/// satisfy the refinement type.
+///
+/// Note: This pass improves loop-invariant code motion in the GVN pass because
+/// GVN will currently not hoist a primitive across a refinement guard.
+/// But some opportunities for hoisting are still missed.  A field access can
+/// safely be hoisted across a non-redundant refinement as long as the less
+/// refined value is still known to have the field.  For example:
+///
+///     class A { var field; }
+///     class B extends A {}
+///
+///     var x = getA();       // Return type is subclass of A.
+///     while (x is B) {      // Refinement to B is not redundant.
+///         x.field.baz++;    // x.field is safe for hoisting,
+///     }                     // but blocked by the refinement node.
+///
+/// Ideally, this pass should go away and GVN should handle refinements
+/// directly.
+class RedundantRefinementEliminator extends TrampolineRecursiveVisitor
+                                    implements Pass {
+  String get passName => 'Redundant refinement elimination';
+
+  TypeMaskSystem typeSystem;
+
+  RedundantRefinementEliminator(this.typeSystem);
+
+  void rewrite(FunctionDefinition node) {
+    visit(node);
+  }
+
+  Expression traverseLetPrim(LetPrim node) {
+    Expression next = node.body;
+    if (node.primitive is Refinement) {
+      Refinement refinement = node.primitive;
+      Primitive value = refinement.value.definition;
+      if (typeSystem.isMorePreciseOrEqual(value.type, refinement.refineType)) {
+        refinement..replaceUsesWith(value)..destroy();
+        node.remove();
+        return next;
+      }
+    }
+    return next;
+  }
+}
diff --git a/pkg/compiler/lib/src/cps_ir/remove_refinements.dart b/pkg/compiler/lib/src/cps_ir/remove_refinements.dart
index 2d49c95..eead3f0 100644
--- a/pkg/compiler/lib/src/cps_ir/remove_refinements.dart
+++ b/pkg/compiler/lib/src/cps_ir/remove_refinements.dart
@@ -27,8 +27,7 @@
       if (refinement.hint != null && value.hint == null) {
         value.hint = refinement.hint;
       }
-      value.substituteFor(refinement);
-      refinement.destroy();
+      refinement..replaceUsesWith(value)..destroy();
       node.remove();
     }
     return next;
diff --git a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
index 9d5ce4f..b220847 100644
--- a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
+++ b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
@@ -142,12 +142,12 @@
           GetMutable getter = new GetMutable(variable);
           getter.type = getField.type;
           getter.variable.parent = getter;
-          getter.substituteFor(getField);
+          getField.replaceUsesWith(getter);
           replacePrimitive(getField, getter);
           deletePrimitive(getField);
         } else {
           Primitive value = fieldInitialValues[getField.field];
-          value.substituteFor(getField);
+          getField.replaceUsesWith(value);
           deleteLetPrimOf(getField);
         }
       } else if (use is SetField && use.object == ref) {
@@ -158,7 +158,7 @@
         SetMutable setter = new SetMutable(variable, value);
         setter.variable.parent = setter;
         setter.value.parent = setter;
-        setter.substituteFor(setField);
+        setField.replaceUsesWith(setter);
         replacePrimitive(setField, setter);
         deletePrimitive(setField);
       } else {
diff --git a/pkg/compiler/lib/src/cps_ir/share_final_fields.dart b/pkg/compiler/lib/src/cps_ir/share_final_fields.dart
deleted file mode 100644
index 3308c00..0000000
--- a/pkg/compiler/lib/src/cps_ir/share_final_fields.dart
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js.cps_ir.share_final_fields;
-
-import 'optimizers.dart';
-import 'cps_ir_nodes.dart';
-import 'loop_hierarchy.dart';
-import '../elements/elements.dart';
-import '../js_backend/js_backend.dart' show JavaScriptBackend;
-import '../types/types.dart' show TypeMask;
-
-/// Removes redundant GetField operations.
-///
-/// The pass performs these optimizations for field loads:
-/// - share GetFields of final fields when one is in scope of the other.
-/// - pull GetField operations of final fields out of loops when safe (object is
-///   not null).
-///
-/// This pass only optimizes final fields and should be replaced with a full
-/// load elimination pass.
-class ShareFinalFields extends TrampolineRecursiveVisitor implements Pass {
-  String get passName => 'Share final fields';
-
-  /// The innermost loop containing a given primitive.
-  final Map<Primitive, Continuation> loopHeaderFor =
-      <Primitive, Continuation>{};
-
-  // field -> receiver -> GetField
-  Map<FieldElement, Map<Primitive, Primitive>> fieldValues =
-      <FieldElement, Map<Primitive, Primitive>>{};
-
-  /// Interceptors that have been hoisted out of a given loop.
-  final Map<Continuation, List<GetField>> loopHoistedGetters =
-      <Continuation, List<GetField>>{};
-
-  JavaScriptBackend backend;
-  LoopHierarchy loopHierarchy;
-  Continuation currentLoopHeader;
-
-  ShareFinalFields(this.backend);
-
-  void rewrite(FunctionDefinition node) {
-    loopHierarchy = new LoopHierarchy(node);
-    visit(node.body);
-  }
-
-  @override
-  Expression traverseContinuation(Continuation cont) {
-    Continuation oldLoopHeader = currentLoopHeader;
-    currentLoopHeader = loopHierarchy.getLoopHeader(cont);
-    for (Parameter parameter in cont.parameters) {
-      loopHeaderFor[parameter] = currentLoopHeader;
-    }
-    if (cont.isRecursive) {
-      pushAction(() {
-        // After the loop body has been processed, all values hoisted to this
-        // loop fall out of scope and should be removed from the environment.
-        List<GetField> hoisted = loopHoistedGetters[cont];
-        if (hoisted != null) {
-          for (GetField primitive in hoisted) {
-            Primitive refinedReceiver = primitive.object.definition;
-            Primitive receiver = refinedReceiver.effectiveDefinition;
-            var map = fieldValues[primitive.field];
-            assert(map[receiver] == primitive);
-            map.remove(receiver);
-          }
-        }
-      });
-    }
-    pushAction(() {
-      currentLoopHeader = oldLoopHeader;
-    });
-    return cont.body;
-  }
-
-  Continuation getCurrentOuterLoop({Continuation scope}) {
-    Continuation inner = null, outer = currentLoopHeader;
-    while (outer != scope) {
-      inner = outer;
-      outer = loopHierarchy.getEnclosingLoop(outer);
-    }
-    return inner;
-  }
-
-  @override
-  Expression traverseLetPrim(LetPrim node) {
-    loopHeaderFor[node.primitive] = currentLoopHeader;
-    Expression next = node.body;
-    if (node.primitive is! GetField) {
-      return next;
-    }
-    GetField primitive = node.primitive;
-    FieldElement field = primitive.field;
-
-    if (!shouldShareField(field)) {
-      return next;
-    }
-
-    Primitive refinedReceiver = primitive.object.definition;
-    Primitive receiver = refinedReceiver.effectiveDefinition;
-
-    // Try to reuse an existing load for the same input.
-    var map = fieldValues.putIfAbsent(field, () => <Primitive,Primitive>{});
-    Primitive existing = map[receiver];
-    if (existing != null) {
-      existing.substituteFor(primitive);
-      primitive.destroy();
-      node.remove();
-      return next;
-    }
-
-    map[receiver] = primitive;
-
-    if (primitive.objectIsNotNull) {
-      // Determine how far the GetField can be lifted. The outermost loop that
-      // contains the input binding should also contain the load.
-      // Don't move above a refinement guard since that might be unsafe.
-
-      // TODO(sra): We can move above a refinement guard provided the input is
-      // still in scope and safe (non-null). We will have to replace
-      // primitive.object with the most constrained refinement still in scope.
-      Continuation referencedLoop =
-          lowestCommonAncestor(loopHeaderFor[refinedReceiver],
-                               currentLoopHeader);
-      if (referencedLoop != currentLoopHeader) {
-        Continuation hoistTarget = getCurrentOuterLoop(scope: referencedLoop);
-        LetCont loopBinding = hoistTarget.parent;
-        node.remove();
-        node.insertAbove(loopBinding);
-        // Remove the hoisted operations from the environment after processing
-        // the loop.
-        loopHoistedGetters
-            .putIfAbsent(hoistTarget, () => <GetField>[])
-            .add(primitive);
-        return next;
-      }
-    }
-
-    pushAction(() {
-        var map = fieldValues[field];
-        assert(map[receiver] == primitive);
-        map.remove(receiver);
-      });
-    return next;
-  }
-
-  bool shouldShareField(FieldElement field) {
-    // TODO(24781): This query is incorrect for fields assigned only via
-    //
-    //     super.field = ...
-    //
-    // return backend.compiler.world.fieldNeverChanges(field);
-
-    // Native fields are getters with side effects (e.g. layout).
-    if (backend.isNative(field)) return false;
-    return field.isFinal || field.isConst;
-  }
-
-  /// Returns the 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);
-    while (c1 != c2) {
-      if (d1 <= d2) {
-        c2 = loopHierarchy.getEnclosingLoop(c2);
-        d2 = getDepth(c2);
-      } else {
-        c1 = loopHierarchy.getEnclosingLoop(c1);
-        d1 = getDepth(c1);
-      }
-    }
-    return c1;
-  }
-
-  int getDepth(Continuation loop) {
-    if (loop == null) return -1;
-    return loopHierarchy.loopDepth[loop];
-  }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/share_interceptors.dart b/pkg/compiler/lib/src/cps_ir/share_interceptors.dart
deleted file mode 100644
index 1fbbba3..0000000
--- a/pkg/compiler/lib/src/cps_ir/share_interceptors.dart
+++ /dev/null
@@ -1,278 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js.cps_ir.share_interceptors;
-
-import 'optimizers.dart';
-import 'cps_ir_nodes.dart';
-import 'loop_hierarchy.dart';
-import 'cps_fragment.dart';
-import '../constants/values.dart';
-import '../elements/elements.dart';
-import '../js_backend/backend_helpers.dart' show BackendHelpers;
-import '../js_backend/js_backend.dart' show JavaScriptBackend;
-import '../types/types.dart' show TypeMask;
-import '../io/source_information.dart' show SourceInformation;
-
-/// Removes redundant `getInterceptor` calls.
-///
-/// The pass performs three optimizations for interceptors:
-///- pull interceptors out of loops
-///- replace interceptors with constants
-///- share interceptors when one is in scope of the other
-class ShareInterceptors extends TrampolineRecursiveVisitor implements Pass {
-  String get passName => 'Share interceptors';
-
-  /// The innermost loop containing a given primitive.
-  final Map<Primitive, Continuation> loopHeaderFor =
-      <Primitive, Continuation>{};
-
-  /// An interceptor currently in scope for a given primitive.
-  final Map<Primitive, Interceptor> interceptorFor = <Primitive, Interceptor>{};
-
-  /// Interceptors that have been hoisted out of a given loop.
-  final Map<Continuation, List<Interceptor>> loopHoistedInterceptors =
-      <Continuation, List<Interceptor>>{};
-
-  JavaScriptBackend backend;
-  LoopHierarchy loopHierarchy;
-  Continuation currentLoopHeader;
-
-  ShareInterceptors(this.backend);
-
-  BackendHelpers get helpers => backend.helpers;
-
-  void rewrite(FunctionDefinition node) {
-    loopHierarchy = new LoopHierarchy(node);
-    visit(node.body);
-    new ShareConstants().visit(node);
-  }
-
-  @override
-  Expression traverseContinuation(Continuation cont) {
-    Continuation oldLoopHeader = currentLoopHeader;
-    currentLoopHeader = loopHierarchy.getLoopHeader(cont);
-    for (Parameter param in cont.parameters) {
-      loopHeaderFor[param] = currentLoopHeader;
-    }
-    if (cont.isRecursive) {
-      pushAction(() {
-        // After the loop body has been processed, all interceptors hoisted
-        // to this loop fall out of scope and should be removed from the
-        // environment.
-        List<Interceptor> hoisted = loopHoistedInterceptors[cont];
-        if (hoisted != null) {
-          for (Interceptor interceptor in hoisted) {
-            Primitive input = interceptor.input.definition;
-            assert(interceptorFor[input] == interceptor);
-            interceptorFor.remove(input);
-            constifyInterceptor(interceptor);
-          }
-        }
-      });
-    }
-    pushAction(() {
-      currentLoopHeader = oldLoopHeader;
-    });
-    return cont.body;
-  }
-
-  /// If only one method table can be returned by the given interceptor,
-  /// returns a constant for that method table.
-  InterceptorConstantValue getInterceptorConstant(Interceptor node) {
-    if (node.interceptedClasses.length == 1 &&
-        node.isInterceptedClassAlwaysExact) {
-      ClassElement interceptorClass = node.interceptedClasses.single;
-      return new InterceptorConstantValue(interceptorClass.rawType);
-    }
-    return null;
-  }
-
-  bool hasNoFalsyValues(ClassElement class_) {
-    return class_ != helpers.jsInterceptorClass &&
-       class_ != helpers.jsNullClass &&
-       class_ != helpers.jsBoolClass &&
-       class_ != helpers.jsStringClass &&
-       !class_.isSubclassOf(helpers.jsNumberClass);
-  }
-
-  Continuation getCurrentOuterLoop({Continuation scope}) {
-    Continuation inner = null, outer = currentLoopHeader;
-    while (outer != scope) {
-      inner = outer;
-      outer = loopHierarchy.getEnclosingLoop(outer);
-    }
-    return inner;
-  }
-
-  /// Binds the given constant in a primitive, in scope of the [useSite].
-  ///
-  /// The constant will be hoisted out of loops, and shared with other requests
-  /// for the same constant as long as it is in scope.
-  Primitive makeConstantFor(ConstantValue constant,
-                            {Expression useSite,
-                             TypeMask type,
-                             SourceInformation sourceInformation,
-                             Entity hint}) {
-    Constant prim =
-        new Constant(constant, sourceInformation: sourceInformation);
-    prim.hint = hint;
-    prim.type = type;
-    LetPrim letPrim = new LetPrim(prim);
-    Continuation loop = getCurrentOuterLoop();
-    if (loop != null) {
-      LetCont loopBinding = loop.parent;
-      letPrim.insertAbove(loopBinding);
-    } else {
-      letPrim.insertAbove(useSite);
-    }
-    return prim;
-  }
-
-  void constifyInterceptor(Interceptor interceptor) {
-    LetPrim let = interceptor.parent;
-    InterceptorConstantValue constant = getInterceptorConstant(interceptor);
-
-    if (constant == null) return;
-
-    if (interceptor.isAlwaysIntercepted) {
-      Primitive constantPrim = makeConstantFor(constant,
-          useSite: let,
-          type: interceptor.type,
-          sourceInformation: interceptor.sourceInformation);
-      constantPrim.useElementAsHint(interceptor.hint);
-      constantPrim.substituteFor(interceptor);
-      interceptor.destroy();
-      let.remove();
-    } else if (interceptor.isAlwaysNullOrIntercepted) {
-      Primitive input = interceptor.input.definition;
-      Primitive constantPrim = makeConstantFor(constant,
-          useSite: let,
-          type: interceptor.type.nonNullable(),
-          sourceInformation: interceptor.sourceInformation);
-      CpsFragment cps = new CpsFragment(interceptor.sourceInformation);
-      Parameter param = new Parameter(interceptor.hint);
-      Continuation cont = cps.letCont(<Parameter>[param]);
-      if (interceptor.interceptedClasses.every(hasNoFalsyValues)) {
-        // If null is the only falsy value, compile as "x && CONST".
-        cps.ifFalsy(input).invokeContinuation(cont, [input]);
-      } else {
-        // If there are other falsy values compile as "x == null ? x : CONST".
-        Primitive condition = cps.applyBuiltin(
-            BuiltinOperator.LooseEq,
-            [input, cps.makeNull()]);
-        cps.ifTruthy(condition).invokeContinuation(cont, [input]);
-      }
-      cps.invokeContinuation(cont, [constantPrim]);
-      cps.context = cont;
-      cps.insertAbove(let);
-      param.substituteFor(interceptor);
-      interceptor.destroy();
-      let.remove();
-    }
-  }
-
-  @override
-  Expression traverseLetPrim(LetPrim node) {
-    loopHeaderFor[node.primitive] = currentLoopHeader;
-    Expression next = node.body;
-    if (node.primitive is! Interceptor) {
-      return next;
-    }
-    Interceptor interceptor = node.primitive;
-    Primitive input = interceptor.input.definition;
-
-    // Try to reuse an existing interceptor for the same input.
-    Interceptor existing = interceptorFor[input];
-    if (existing != null) {
-      existing.interceptedClasses.addAll(interceptor.interceptedClasses);
-      existing.flags |= interceptor.flags;
-      existing.substituteFor(interceptor);
-      interceptor.destroy();
-      node.remove();
-      return next;
-    }
-
-    // Put this interceptor in the environment.
-    interceptorFor[input] = interceptor;
-
-    // Determine how far the interceptor can be lifted. The outermost loop
-    // that contains the input binding should also contain the interceptor
-    // binding.
-    Continuation referencedLoop =
-        lowestCommonAncestor(loopHeaderFor[input], currentLoopHeader);
-    if (referencedLoop != currentLoopHeader) {
-      Continuation hoistTarget = getCurrentOuterLoop(scope: referencedLoop);
-      LetCont loopBinding = hoistTarget.parent;
-      node.remove();
-      node.insertAbove(loopBinding);
-      // Remove the interceptor from the environment after processing the loop.
-      loopHoistedInterceptors
-          .putIfAbsent(hoistTarget, () => <Interceptor>[])
-          .add(interceptor);
-    } else {
-      // Remove the interceptor from the environment when it falls out of scope.
-      pushAction(() {
-        assert(interceptorFor[input] == interceptor);
-        interceptorFor.remove(input);
-
-        // Now that the final set of intercepted classes has been seen, try to
-        // replace it with a constant.
-        constifyInterceptor(interceptor);
-      });
-    }
-
-    return next;
-  }
-
-  /// Returns the 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);
-    while (c1 != c2) {
-      if (d1 <= d2) {
-        c2 = loopHierarchy.getEnclosingLoop(c2);
-        d2 = getDepth(c2);
-      } else {
-        c1 = loopHierarchy.getEnclosingLoop(c1);
-        d1 = getDepth(c1);
-      }
-    }
-    return c1;
-  }
-
-  int getDepth(Continuation loop) {
-    if (loop == null) return -1;
-    return loopHierarchy.loopDepth[loop];
-  }
-}
-
-class ShareConstants extends TrampolineRecursiveVisitor {
-  Map<ConstantValue, Constant> sharedConstantFor = <ConstantValue, Constant>{};
-
-  Expression traverseLetPrim(LetPrim node) {
-    Expression next = node.body;
-    if (node.primitive is Constant && shouldShareConstant(node.primitive)) {
-      Constant prim = node.primitive;
-      Constant existing = sharedConstantFor[prim.value];
-      if (existing != null) {
-        existing.substituteFor(prim);
-        existing.useElementAsHint(prim.hint);
-        prim.destroy();
-        node.remove();
-        return next;
-      }
-      sharedConstantFor[prim.value] = prim;
-      pushAction(() {
-        assert(sharedConstantFor[prim.value] == prim);
-        sharedConstantFor.remove(prim.value);
-      });
-    }
-    return next;
-  }
-
-  bool shouldShareConstant(Constant constant) {
-    return constant.value.isInterceptor;
-  }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
index a6017cb..422db14 100644
--- a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
+++ b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
@@ -138,8 +138,7 @@
 
     // Substitute the invocation argument for the continuation parameter.
     for (int i = 0; i < invoke.arguments.length; i++) {
-      Reference argRef = invoke.arguments[i];
-      argRef.definition.substituteFor(cont.parameters[i]);
+      cont.parameters[i].replaceUsesWith(invoke.arguments[i].definition);
     }
 
     // Perform bookkeeping on substituted body and scan for new redexes.
@@ -168,7 +167,7 @@
     Continuation wrappedCont = invoke.continuation.definition;
 
     // Replace all occurrences with the wrapped continuation.
-    wrappedCont.substituteFor(cont);
+    cont.replaceUsesWith(wrappedCont);
 
     // Perform bookkeeping on removed body and scan for new redexes.
     new _RemovalVisitor(_worklist).visit(cont);
diff --git a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
index a36f284..2329144 100644
--- a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
@@ -11,17 +11,14 @@
 import '../elements/elements.dart';
 import '../js_backend/backend_helpers.dart' show BackendHelpers;
 import '../js_backend/js_backend.dart' show JavaScriptBackend;
+import '../types/abstract_value_domain.dart';
 import '../types/types.dart';
 import '../types/constants.dart' show computeTypeMask;
 import '../universe/selector.dart' show Selector;
-import '../universe/call_structure.dart' show CallStructure;
 import '../world.dart' show World;
+import '../closure.dart' show ClosureFieldElement, BoxLocal, TypeVariableLocal;
 
-enum AbstractBool {
-  True, False, Maybe, Nothing
-}
-
-class TypeMaskSystem {
+class TypeMaskSystem implements AbstractValueDomain {
   final TypesTask inferrer;
   final World classWorld;
   final JavaScriptBackend backend;
@@ -33,27 +30,69 @@
 
   TypeMask __indexableTypeTest;
 
+  // The full type of a constant (e.g. a ContainerTypeMask) is not available on
+  // the constant. Type inference flows the type to some place where it is used,
+  // e.g. a parameter. For constant values that are the value of static const
+  // fields we need to remember the association.
+  final Map<ConstantValue, TypeMask> _constantMasks =
+      <ConstantValue, TypeMask>{};
+
+  @override
   TypeMask get dynamicType => inferrer.dynamicType;
+
+  @override
   TypeMask get typeType => inferrer.typeType;
+
+  @override
   TypeMask get functionType => inferrer.functionType;
+
+  @override
   TypeMask get boolType => inferrer.boolType;
+
+  @override
   TypeMask get intType => inferrer.intType;
+
+  @override
   TypeMask get doubleType => inferrer.doubleType;
+
+  @override
   TypeMask get numType => inferrer.numType;
+
+  @override
   TypeMask get stringType => inferrer.stringType;
+
+  @override
   TypeMask get listType => inferrer.listType;
+
+  @override
   TypeMask get mapType => inferrer.mapType;
+
+  @override
   TypeMask get nonNullType => inferrer.nonNullType;
+
+  @override
   TypeMask get nullType => inferrer.nullType;
+
+  @override
   TypeMask get extendableArrayType => backend.extendableArrayType;
+
+  @override
   TypeMask get fixedArrayType => backend.fixedArrayType;
+
+  @override
   TypeMask get arrayType =>
       new TypeMask.nonNullSubclass(helpers.jsArrayClass, classWorld);
 
+  @override
   TypeMask get uint31Type => inferrer.uint31Type;
+
+  @override
   TypeMask get uint32Type => inferrer.uint32Type;
+
+  @override
   TypeMask get uintType => inferrer.positiveIntType;
 
+  @override
   TypeMask get numStringBoolType {
     if (_numStringBoolType == null) {
       // Build the number+string+bool type. To make containment tests more
@@ -72,6 +111,7 @@
     return _numStringBoolType;
   }
 
+  @override
   TypeMask get fixedLengthType {
     if (_fixedLengthType == null) {
       List<TypeMask> fixedLengthTypes =
@@ -84,6 +124,7 @@
     return _fixedLengthType;
   }
 
+  @override
   TypeMask get interceptorType {
     if (_interceptorType == null) {
       _interceptorType =
@@ -92,6 +133,7 @@
     return _interceptorType;
   }
 
+  @override
   TypeMask get interceptedTypes { // Does not include null.
     if (_interceptedTypes == null) {
       // We redundantly include subtypes of num/string/bool as intercepted
@@ -130,6 +172,7 @@
         backend = compiler.backend {
   }
 
+  @override
   bool methodUsesReceiverArgument(FunctionElement function) {
     assert(backend.isInterceptedMethod(function));
     ClassElement clazz = function.enclosingClass.declaration;
@@ -137,18 +180,22 @@
            classWorld.isUsedAsMixin(clazz);
   }
 
+  @override
   Element locateSingleElement(TypeMask mask, Selector selector) {
     return mask.locateSingleElement(selector, mask, classWorld.compiler);
   }
 
+  @override
   ClassElement singleClass(TypeMask mask) {
     return mask.singleClass(classWorld);
   }
 
+  @override
   bool needsNoSuchMethodHandling(TypeMask mask, Selector selector) {
     return mask.needsNoSuchMethodHandling(selector, classWorld);
   }
 
+  @override
   TypeMask getReceiverType(MethodElement method) {
     assert(method.isInstanceMember);
     if (classWorld.isUsedAsMixin(method.enclosingClass.declaration)) {
@@ -161,14 +208,17 @@
     }
   }
 
+  @override
   TypeMask getParameterType(ParameterElement parameter) {
     return inferrer.getGuaranteedTypeOfElement(parameter);
   }
 
+  @override
   TypeMask getReturnType(FunctionElement function) {
     return inferrer.getGuaranteedReturnTypeOfElement(function);
   }
 
+  @override
   TypeMask getInvokeReturnType(Selector selector, TypeMask mask) {
     TypeMask result = inferrer.getGuaranteedTypeOfSelector(selector, mask);
     // Tearing off .call from a function returns the function itself.
@@ -180,26 +230,53 @@
     return result;
   }
 
+  @override
   TypeMask getFieldType(FieldElement field) {
+    if (field is ClosureFieldElement) {
+      // The type inference does not report types for all closure fields.
+      // Box fields are never null.
+      if (field.local is BoxLocal) return nonNullType;
+      // Closure fields for type variables contain the internal representation
+      // of the type (which can be null), not the Type object.
+      if (field.local is TypeVariableLocal) return dynamicType;
+    }
     return inferrer.getGuaranteedTypeOfElement(field);
   }
 
+  @override
   TypeMask join(TypeMask a, TypeMask b) {
     return a.union(b, classWorld);
   }
 
+  @override
   TypeMask intersection(TypeMask a, TypeMask b) {
     if (a == null) return b;
     if (b == null) return a;
     return a.intersection(b, classWorld);
   }
 
-  TypeMask getTypeOf(ConstantValue constant) {
-    return computeTypeMask(inferrer.compiler, constant);
+  void associateConstantValueWithElement(ConstantValue constant,
+                                         Element element) {
+    // TODO(25093): Replace this code with an approach that works for anonymous
+    // constants and non-constant literals.
+    if (constant is ListConstantValue || constant is MapConstantValue) {
+      // Inferred type is usually better (e.g. a ContainerTypeMask) but is
+      // occasionally less general.
+      TypeMask computed = computeTypeMask(inferrer.compiler, constant);
+      TypeMask inferred = inferrer.getGuaranteedTypeOfElement(element);
+      TypeMask best = intersection(inferred, computed);
+      assert(!best.isEmpty);
+      _constantMasks[constant] = best;
+    }
   }
 
-  // Returns the constant value if a TypeMask represents a single value.
-  // Returns `null` if [mask] is not a constant.
+  @override
+  TypeMask getTypeOf(ConstantValue constant) {
+    return _constantMasks[constant] ??
+           computeTypeMask(inferrer.compiler, constant);
+  }
+
+  @override
   ConstantValue getConstantOf(TypeMask mask) {
     if (!mask.isValue) return null;
     if (mask.isNullable) return null;  // e.g. 'true or null'.
@@ -209,7 +286,9 @@
     return null;
   }
 
+  @override
   TypeMask nonNullExact(ClassElement element) {
+    // TODO(johnniwinther): I don't think the follow is valid anymore.
     // The class world does not know about classes created by
     // closure conversion, so just treat those as a subtypes of Function.
     // TODO(asgerf): Maybe closure conversion should create a new ClassWorld?
@@ -217,36 +296,43 @@
     return new TypeMask.nonNullExact(element.declaration, classWorld);
   }
 
+  @override
   TypeMask nonNullSubclass(ClassElement element) {
     if (element.isClosure) return functionType;
     return new TypeMask.nonNullSubclass(element.declaration, classWorld);
   }
 
+  @override
   TypeMask nonNullSubtype(ClassElement element) {
     if (element.isClosure) return functionType;
     return new TypeMask.nonNullSubtype(element.declaration, classWorld);
   }
 
+  @override
   bool isDefinitelyBool(TypeMask t, {bool allowNull: false}) {
     if (!allowNull && t.isNullable) return false;
     return t.nonNullable().containsOnlyBool(classWorld);
   }
 
+  @override
   bool isDefinitelyNum(TypeMask t, {bool allowNull: false}) {
     if (!allowNull && t.isNullable) return false;
     return t.nonNullable().containsOnlyNum(classWorld);
   }
 
+  @override
   bool isDefinitelyString(TypeMask t, {bool allowNull: false}) {
     if (!allowNull && t.isNullable) return false;
     return t.nonNullable().containsOnlyString(classWorld);
   }
 
+  @override
   bool isDefinitelyNumStringBool(TypeMask t, {bool allowNull: false}) {
     if (!allowNull && t.isNullable) return false;
     return numStringBoolType.containsMask(t.nonNullable(), classWorld);
   }
 
+  @override
   bool isDefinitelyNotNumStringBool(TypeMask t) {
     return areDisjoint(t, numStringBoolType);
   }
@@ -255,6 +341,7 @@
   ///
   /// This does not imply that the value is an integer, since most other values
   /// such as null are also not a non-integer double.
+  @override
   bool isDefinitelyNotNonIntegerDouble(TypeMask t) {
     // Even though int is a subclass of double in the JS type system, we can
     // still check this with disjointness, because [doubleType] is the *exact*
@@ -265,69 +352,82 @@
     return areDisjoint(t, doubleType);
   }
 
+  @override
   bool isDefinitelyNonNegativeInt(TypeMask t, {bool allowNull: false}) {
     if (!allowNull && t.isNullable) return false;
     // The JSPositiveInt class includes zero, despite the name.
     return t.satisfies(helpers.jsPositiveIntClass, classWorld);
   }
 
+  @override
   bool isDefinitelyInt(TypeMask t, {bool allowNull: false}) {
     if (!allowNull && t.isNullable) return false;
     return t.nonNullable().containsOnlyInt(classWorld);
   }
 
+  @override
   bool isDefinitelyUint31(TypeMask t, {bool allowNull: false}) {
     if (!allowNull && t.isNullable) return false;
     return t.satisfies(helpers.jsUInt31Class, classWorld);
   }
 
+  @override
   bool isDefinitelyUint32(TypeMask t, {bool allowNull: false}) {
     if (!allowNull && t.isNullable) return false;
     return t.satisfies(helpers.jsUInt32Class, classWorld);
   }
 
+  @override
   bool isDefinitelyUint(TypeMask t, {bool allowNull: false}) {
     if (!allowNull && t.isNullable) return false;
     return t.satisfies(helpers.jsPositiveIntClass, classWorld);
   }
 
+  @override
   bool isDefinitelyArray(TypeMask t, {bool allowNull: false}) {
     if (!allowNull && t.isNullable) return false;
     return t.nonNullable().satisfies(helpers.jsArrayClass, classWorld);
   }
 
+  @override
   bool isDefinitelyMutableArray(TypeMask t, {bool allowNull: false}) {
     if (!allowNull && t.isNullable) return false;
     return t.nonNullable().satisfies(helpers.jsMutableArrayClass, classWorld);
   }
 
+  @override
   bool isDefinitelyFixedArray(TypeMask t, {bool allowNull: false}) {
     if (!allowNull && t.isNullable) return false;
     return t.nonNullable().satisfies(helpers.jsFixedArrayClass, classWorld);
   }
 
+  @override
   bool isDefinitelyExtendableArray(TypeMask t, {bool allowNull: false}) {
     if (!allowNull && t.isNullable) return false;
     return t.nonNullable().satisfies(helpers.jsExtendableArrayClass,
                                      classWorld);
   }
 
+  @override
   bool isDefinitelyIndexable(TypeMask t, {bool allowNull: false}) {
     if (!allowNull && t.isNullable) return false;
     return _indexableTypeTest.containsMask(t.nonNullable(), classWorld);
   }
 
+  @override
   bool isDefinitelyMutableIndexable(TypeMask t, {bool allowNull: false}) {
     if (!allowNull && t.isNullable) return false;
     return t.nonNullable().satisfies(helpers.jsMutableIndexableClass,
         classWorld);
   }
 
+  @override
   bool isDefinitelyFixedLengthIndexable(TypeMask t, {bool allowNull: false}) {
     if (!allowNull && t.isNullable) return false;
     return fixedLengthType.containsMask(t.nonNullable(), classWorld);
   }
 
+  @override
   bool isDefinitelyIntercepted(TypeMask t, {bool allowNull}) {
     assert(allowNull != null);
     if (!allowNull && t.isNullable) return false;
@@ -336,6 +436,7 @@
 
   /// Given a class from the interceptor hierarchy, returns a [TypeMask]
   /// matching all values with that interceptor (or a subtype thereof).
+  @override
   TypeMask getInterceptorSubtypes(ClassElement class_) {
     if (class_ == helpers.jsInterceptorClass) {
       return interceptorType.nullable();
@@ -346,11 +447,18 @@
     }
   }
 
+  @override
   bool areDisjoint(TypeMask leftType, TypeMask rightType) {
-    TypeMask intersection = leftType.intersection(rightType, classWorld);
-    return intersection.isEmpty && !intersection.isNullable;
+    TypeMask intersected = intersection(leftType, rightType);
+    return intersected.isEmpty && !intersected.isNullable;
   }
 
+  @override
+  bool isMorePreciseOrEqual(TypeMask t1, TypeMask t2) {
+    return t2.containsMask(t1, classWorld);
+  }
+
+  @override
   AbstractBool isSubtypeOf(TypeMask value,
                            types.DartType type,
                            {bool allowNull}) {
@@ -386,6 +494,7 @@
 
   /// Returns whether [type] is one of the falsy values: false, 0, -0, NaN,
   /// the empty string, or null.
+  @override
   AbstractBool boolify(TypeMask type) {
     if (isDefinitelyNotNumStringBool(type) && !type.isNullable) {
       return AbstractBool.True;
@@ -393,12 +502,14 @@
     return AbstractBool.Maybe;
   }
 
+  @override
   AbstractBool strictBoolify(TypeMask type) {
     if (areDisjoint(type, boolType)) return AbstractBool.False;
     return AbstractBool.Maybe;
   }
 
   /// Create a type mask containing at least all subtypes of [type].
+  @override
   TypeMask subtypesOf(types.DartType type) {
     if (type is types.InterfaceType) {
       ClassElement element = type.element;
@@ -431,12 +542,14 @@
 
   /// Returns a subset of [mask] containing at least the types
   /// that can respond to [selector] without throwing.
+  @override
   TypeMask receiverTypeFor(Selector selector, TypeMask mask) {
     return classWorld.allFunctions.receiverType(selector, mask);
   }
 
   /// The result of an index operation on something of [type], or the dynamic
   /// type if unknown.
+  @override
   TypeMask elementTypeOfIndexable(TypeMask type) {
     if (type is UnionTypeMask) {
       return new TypeMask.unionOf(
@@ -458,6 +571,7 @@
   }
 
   /// The length of something of [type], or `null` if unknown.
+  @override
   int getContainerLength(TypeMask type) {
     if (type is ContainerTypeMask) {
       return type.length;
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index 9d1a335..8a4daba 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -30,42 +30,47 @@
 import '../resolution/send_structure.dart';
 import '../tree/tree.dart' as ast;
 import '../types/types.dart';
+import '../types/abstract_value_domain.dart' show
+    AbstractBool;
 import '../universe/selector.dart' show
     Selector;
 import '../world.dart' show World;
 import 'cps_fragment.dart';
 import 'cps_ir_nodes.dart';
 import 'type_mask_system.dart';
+import '../closure.dart' show
+    ClosureFieldElement,
+    BoxLocal;
 
 class ConstantPropagationLattice {
   final TypeMaskSystem typeSystem;
   final ConstantSystem constantSystem;
   final types.DartTypes dartTypes;
-  final AbstractValue anything;
-  final AbstractValue nullValue;
+  final AbstractConstantValue anything;
+  final AbstractConstantValue nullValue;
 
   ConstantPropagationLattice(TypeMaskSystem typeSystem,
                              this.constantSystem,
                              this.dartTypes)
     : this.typeSystem = typeSystem,
-      anything = new AbstractValue.nonConstant(typeSystem.dynamicType),
-      nullValue = new AbstractValue.constantValue(
+      anything = new AbstractConstantValue.nonConstant(typeSystem.dynamicType),
+      nullValue = new AbstractConstantValue.constantValue(
           new NullConstantValue(), new TypeMask.empty());
 
-  final AbstractValue nothing = new AbstractValue.nothing();
+  final AbstractConstantValue nothing = new AbstractConstantValue.nothing();
 
-  AbstractValue constant(ConstantValue value, [TypeMask type]) {
+  AbstractConstantValue constant(ConstantValue value, [TypeMask type]) {
     if (type == null) type = typeSystem.getTypeOf(value);
-    return new AbstractValue.constantValue(value, type);
+    return new AbstractConstantValue.constantValue(value, type);
   }
 
-  AbstractValue nonConstant([TypeMask type]) {
+  AbstractConstantValue nonConstant([TypeMask type]) {
     if (type == null) type = typeSystem.dynamicType;
-    return new AbstractValue.nonConstant(type);
+    return new AbstractConstantValue.nonConstant(type);
   }
 
   /// Compute the join of two values in the lattice.
-  AbstractValue join(AbstractValue x, AbstractValue y) {
+  AbstractConstantValue join(AbstractConstantValue x, AbstractConstantValue y) {
     assert(x != null);
     assert(y != null);
 
@@ -76,36 +81,39 @@
     } else if (x.isConstant && y.isConstant && x.constant == y.constant) {
       return x;
     } else {
-      return new AbstractValue.nonConstant(typeSystem.join(x.type, y.type));
+      return new AbstractConstantValue.nonConstant(
+          typeSystem.join(x.type, y.type));
     }
   }
 
   /// True if all members of this value are booleans.
-  bool isDefinitelyBool(AbstractValue value, {bool allowNull: false}) {
+  bool isDefinitelyBool(AbstractConstantValue value, {bool allowNull: false}) {
     return value.isNothing ||
       typeSystem.isDefinitelyBool(value.type, allowNull: allowNull);
   }
 
   /// True if all members of this value are numbers.
-  bool isDefinitelyNum(AbstractValue value, {bool allowNull: false}) {
+  bool isDefinitelyNum(AbstractConstantValue value, {bool allowNull: false}) {
     return value.isNothing ||
       typeSystem.isDefinitelyNum(value.type, allowNull: allowNull);
   }
 
   /// True if all members of this value are strings.
-  bool isDefinitelyString(AbstractValue value, {bool allowNull: false}) {
+  bool isDefinitelyString(AbstractConstantValue value,
+                          {bool allowNull: false}) {
     return value.isNothing ||
       typeSystem.isDefinitelyString(value.type, allowNull: allowNull);
   }
 
   /// True if all members of this value are numbers, strings, or booleans.
-  bool isDefinitelyNumStringBool(AbstractValue value, {bool allowNull: false}) {
+  bool isDefinitelyNumStringBool(AbstractConstantValue value,
+                                 {bool allowNull: false}) {
     return value.isNothing ||
       typeSystem.isDefinitelyNumStringBool(value.type, allowNull: allowNull);
   }
 
   /// True if this value cannot be a string, number, or boolean.
-  bool isDefinitelyNotNumStringBool(AbstractValue value) {
+  bool isDefinitelyNotNumStringBool(AbstractConstantValue value) {
     return value.isNothing ||
       typeSystem.isDefinitelyNotNumStringBool(value.type);
   }
@@ -114,71 +122,72 @@
   ///
   /// In other words, if true is returned, and the value is a number, then
   /// it is a whole number and is not NaN, Infinity, or minus Infinity.
-  bool isDefinitelyNotNonIntegerDouble(AbstractValue value) {
+  bool isDefinitelyNotNonIntegerDouble(AbstractConstantValue value) {
     return value.isNothing ||
       value.isConstant && !value.constant.isDouble ||
       typeSystem.isDefinitelyNotNonIntegerDouble(value.type);
   }
 
-  bool isDefinitelyInt(AbstractValue value,
+  bool isDefinitelyInt(AbstractConstantValue value,
                        {bool allowNull: false}) {
     return value.isNothing ||
         typeSystem.isDefinitelyInt(value.type, allowNull: allowNull);
   }
 
-  bool isDefinitelyUint31(AbstractValue value,
-                       {bool allowNull: false}) {
+  bool isDefinitelyUint31(AbstractConstantValue value,
+                          {bool allowNull: false}) {
     return value.isNothing ||
         typeSystem.isDefinitelyUint31(value.type, allowNull: allowNull);
   }
 
-  bool isDefinitelyUint32(AbstractValue value,
-                       {bool allowNull: false}) {
+  bool isDefinitelyUint32(AbstractConstantValue value,
+                          {bool allowNull: false}) {
     return value.isNothing ||
         typeSystem.isDefinitelyUint32(value.type, allowNull: allowNull);
   }
 
-  bool isDefinitelyUint(AbstractValue value,
+  bool isDefinitelyUint(AbstractConstantValue value,
                        {bool allowNull: false}) {
     return value.isNothing ||
         typeSystem.isDefinitelyUint(value.type, allowNull: allowNull);
   }
 
-  bool isDefinitelyArray(AbstractValue value,
+  bool isDefinitelyArray(AbstractConstantValue value,
                               {bool allowNull: false}) {
     return value.isNothing ||
         typeSystem.isDefinitelyArray(value.type, allowNull: allowNull);
   }
 
-  bool isDefinitelyMutableArray(AbstractValue value,
+  bool isDefinitelyMutableArray(AbstractConstantValue value,
                                      {bool allowNull: false}) {
     return value.isNothing ||
          typeSystem.isDefinitelyMutableArray(value.type,
                                                   allowNull: allowNull);
   }
 
-  bool isDefinitelyFixedArray(AbstractValue value,
-                                   {bool allowNull: false}) {
+  bool isDefinitelyFixedArray(AbstractConstantValue value,
+                              {bool allowNull: false}) {
     return value.isNothing ||
         typeSystem.isDefinitelyFixedArray(value.type,
+                                          allowNull: allowNull);
+  }
+
+  bool isDefinitelyExtendableArray(AbstractConstantValue value,
+                                   {bool allowNull: false}) {
+    return value.isNothing ||
+        typeSystem.isDefinitelyExtendableArray(value.type,
                                                allowNull: allowNull);
   }
 
-  bool isDefinitelyExtendableArray(AbstractValue value,
-                                        {bool allowNull: false}) {
-    return value.isNothing ||
-        typeSystem.isDefinitelyExtendableArray(value.type,
-                                                    allowNull: allowNull);
-  }
-
-  bool isDefinitelyIndexable(AbstractValue value, {bool allowNull: false}) {
+  bool isDefinitelyIndexable(AbstractConstantValue value,
+                             {bool allowNull: false}) {
     return value.isNothing ||
         typeSystem.isDefinitelyIndexable(value.type, allowNull: allowNull);
   }
 
   /// Returns `true` if [value] represents an int value that must be in the
   /// inclusive range.
-  bool isDefinitelyIntInRange(AbstractValue value, {int min, int max}) {
+  bool isDefinitelyIntInRange(AbstractConstantValue value, {int min, int max}) {
     if (value.isNothing) return true;
     if (!isDefinitelyInt(value)) return false;
     PrimitiveConstantValue constant = value.constant;
@@ -199,7 +208,7 @@
   /// If [allowNull] is true, `null` is considered an instance of anything,
   /// otherwise it is only considered an instance of [Object], [dynamic], and
   /// [Null].
-  AbstractBool isSubtypeOf(AbstractValue value,
+  AbstractBool isSubtypeOf(AbstractConstantValue value,
                            types.DartType type,
                            {bool allowNull}) {
     assert(allowNull != null);
@@ -245,7 +254,8 @@
   ///
   /// This method returns `null` if a good result could not be found. In that
   /// case, it is best to fall back on interprocedural type information.
-  AbstractValue unaryOp(UnaryOperator operator, AbstractValue value) {
+  AbstractConstantValue unaryOp(UnaryOperator operator,
+                                AbstractConstantValue value) {
     switch (operator.kind) {
       case UnaryOperatorKind.COMPLEMENT:
         return bitNotSpecial(value);
@@ -276,9 +286,9 @@
   ///
   /// This method returns `null` if a good result could not be found. In that
   /// case, it is best to fall back on interprocedural type information.
-  AbstractValue binaryOp(BinaryOperator operator,
-                         AbstractValue left,
-                         AbstractValue right) {
+  AbstractConstantValue binaryOp(BinaryOperator operator,
+                         AbstractConstantValue left,
+                         AbstractConstantValue right) {
     switch (operator.kind) {
       case BinaryOperatorKind.ADD:
         return addSpecial(left, right);
@@ -343,7 +353,8 @@
     return null; // The caller will use return type from type inference.
   }
 
-  AbstractValue foldUnary(UnaryOperation operation, AbstractValue value) {
+  AbstractConstantValue foldUnary(UnaryOperation operation,
+                                  AbstractConstantValue value) {
     if (value.isNothing) return nothing;
     if (value.isConstant) {
       ConstantValue result = operation.fold(value.constant);
@@ -352,20 +363,20 @@
     return null;
   }
 
-  AbstractValue bitNotSpecial(AbstractValue value) {
+  AbstractConstantValue bitNotSpecial(AbstractConstantValue value) {
     return foldUnary(constantSystem.bitNot, value);
   }
 
-  AbstractValue negateSpecial(AbstractValue value) {
-    AbstractValue folded = foldUnary(constantSystem.negate, value);
+  AbstractConstantValue negateSpecial(AbstractConstantValue value) {
+    AbstractConstantValue folded = foldUnary(constantSystem.negate, value);
     if (folded != null) return folded;
     if (isDefinitelyInt(value)) return nonConstant(typeSystem.intType);
     return null;
   }
 
 
-  AbstractValue foldBinary(BinaryOperation operation,
-      AbstractValue left, AbstractValue right) {
+  AbstractConstantValue foldBinary(BinaryOperation operation,
+      AbstractConstantValue left, AbstractConstantValue right) {
     if (left.isNothing || right.isNothing) return nothing;
     if (left.isConstant && right.isConstant) {
       ConstantValue result = operation.fold(left.constant, right.constant);
@@ -374,32 +385,37 @@
     return null;
   }
 
-  AbstractValue closedOnInt(AbstractValue left, AbstractValue right) {
-    if (isDefinitelyInt(left) && isDefinitelyInt(right)) {
+  AbstractConstantValue closedOnInt(AbstractConstantValue left,
+                                    AbstractConstantValue right) {
+    if (isDefinitelyInt(left) && isDefinitelyInt(right, allowNull: true)) {
       return nonConstant(typeSystem.intType);
     }
     return null;
   }
 
-  AbstractValue closedOnUint(AbstractValue left, AbstractValue right) {
-    if (isDefinitelyUint(left) && isDefinitelyUint(right)) {
+  AbstractConstantValue closedOnUint(AbstractConstantValue left,
+                                     AbstractConstantValue right) {
+    if (isDefinitelyUint(left) && isDefinitelyUint(right, allowNull: true)) {
       return nonConstant(typeSystem.uintType);
     }
     return null;
   }
 
-  AbstractValue closedOnUint31(AbstractValue left, AbstractValue right) {
-    if (isDefinitelyUint31(left) && isDefinitelyUint31(right)) {
+  AbstractConstantValue closedOnUint31(AbstractConstantValue left,
+                                       AbstractConstantValue right) {
+    if (isDefinitelyUint31(left) && isDefinitelyUint31(right, allowNull: true)) {
       return nonConstant(typeSystem.uint31Type);
     }
     return null;
   }
 
-  AbstractValue addSpecial(AbstractValue left, AbstractValue right) {
-    AbstractValue folded = foldBinary(constantSystem.add, left, right);
+  AbstractConstantValue addSpecial(AbstractConstantValue left,
+                                   AbstractConstantValue right) {
+    AbstractConstantValue folded = foldBinary(constantSystem.add, left, right);
     if (folded != null) return folded;
     if (isDefinitelyNum(left)) {
-      if (isDefinitelyUint31(left) && isDefinitelyUint31(right)) {
+      if (isDefinitelyUint31(left) &&
+          isDefinitelyUint31(right, allowNull: true)) {
         return nonConstant(typeSystem.uint32Type);
       }
       return closedOnUint(left, right) ?? closedOnInt(left, right);
@@ -407,30 +423,35 @@
     return null;
   }
 
-  AbstractValue subtractSpecial(AbstractValue left, AbstractValue right) {
-    AbstractValue folded = foldBinary(constantSystem.subtract, left, right);
+  AbstractConstantValue subtractSpecial(AbstractConstantValue left,
+                                        AbstractConstantValue right) {
+    AbstractConstantValue folded =
+        foldBinary(constantSystem.subtract, left, right);
     return folded ?? closedOnInt(left, right);
   }
 
-  AbstractValue multiplySpecial(AbstractValue left, AbstractValue right) {
-    AbstractValue folded = foldBinary(constantSystem.multiply, left, right);
+  AbstractConstantValue multiplySpecial(AbstractConstantValue left,
+                                        AbstractConstantValue right) {
+    AbstractConstantValue folded =
+        foldBinary(constantSystem.multiply, left, right);
     return folded ?? closedOnUint(left, right) ?? closedOnInt(left, right);
   }
 
-  AbstractValue divideSpecial(AbstractValue left, AbstractValue right) {
+  AbstractConstantValue divideSpecial(AbstractConstantValue left,
+                                      AbstractConstantValue right) {
     return foldBinary(constantSystem.divide, left, right);
   }
 
-  AbstractValue truncatingDivideSpecial(
-      AbstractValue left, AbstractValue right) {
-    AbstractValue folded =
+  AbstractConstantValue truncatingDivideSpecial(
+      AbstractConstantValue left, AbstractConstantValue right) {
+    AbstractConstantValue folded =
         foldBinary(constantSystem.truncatingDivide, left, right);
     if (folded != null) return folded;
     if (isDefinitelyNum(left)) {
       if (isDefinitelyUint32(left) && isDefinitelyIntInRange(right, min: 2)) {
         return nonConstant(typeSystem.uint31Type);
       }
-      if (isDefinitelyUint(right)) {
+      if (isDefinitelyUint(right, allowNull: true)) {
         // `0` will be an exception, other values will shrink the result.
         if (isDefinitelyUint31(left)) return nonConstant(typeSystem.uint31Type);
         if (isDefinitelyUint32(left)) return nonConstant(typeSystem.uint32Type);
@@ -441,19 +462,29 @@
     return null;
   }
 
-  AbstractValue moduloSpecial(AbstractValue left, AbstractValue right) {
-    AbstractValue folded = foldBinary(constantSystem.modulo, left, right);
+  AbstractConstantValue moduloSpecial(AbstractConstantValue left,
+                                      AbstractConstantValue right) {
+    AbstractConstantValue folded =
+        foldBinary(constantSystem.modulo, left, right);
     return folded ?? closedOnUint(left, right) ?? closedOnInt(left, right);
   }
 
-  AbstractValue remainderSpecial(AbstractValue left, AbstractValue right) {
+  AbstractConstantValue remainderSpecial(AbstractConstantValue left,
+                                         AbstractConstantValue right) {
     if (left.isNothing || right.isNothing) return nothing;
-    AbstractValue folded = null;  // Remainder not in constant system.
+    AbstractConstantValue folded = null;  // Remainder not in constant system.
     return folded ?? closedOnUint(left, right) ?? closedOnInt(left, right);
   }
 
-  AbstractValue equalSpecial(AbstractValue left, AbstractValue right) {
-    AbstractValue folded = foldBinary(constantSystem.equal, left, right);
+  AbstractConstantValue codeUnitAtSpecial(AbstractConstantValue left,
+                                          AbstractConstantValue right) {
+    return foldBinary(constantSystem.codeUnitAt, left, right);
+  }
+
+  AbstractConstantValue equalSpecial(AbstractConstantValue left,
+                                     AbstractConstantValue right) {
+    AbstractConstantValue folded =
+        foldBinary(constantSystem.equal, left, right);
     if (folded != null) return folded;
     bool behavesLikeIdentity =
         isDefinitelyNumStringBool(left, allowNull: true) ||
@@ -465,11 +496,14 @@
     return null;
   }
 
-  AbstractValue andSpecial(AbstractValue left, AbstractValue right) {
-    AbstractValue folded = foldBinary(constantSystem.bitAnd, left, right);
+  AbstractConstantValue andSpecial(AbstractConstantValue left,
+                                   AbstractConstantValue right) {
+    AbstractConstantValue folded =
+        foldBinary(constantSystem.bitAnd, left, right);
     if (folded != null) return folded;
     if (isDefinitelyNum(left)) {
-      if (isDefinitelyUint31(left) || isDefinitelyUint31(right)) {
+      if (isDefinitelyUint31(left) ||
+          isDefinitelyUint31(right, allowNull: true)) {
         // Either 31-bit argument will truncate the other.
         return nonConstant(typeSystem.uint31Type);
       }
@@ -477,22 +511,29 @@
     return null;
   }
 
-  AbstractValue orSpecial(AbstractValue left, AbstractValue right) {
-    AbstractValue folded = foldBinary(constantSystem.bitOr, left, right);
+  AbstractConstantValue orSpecial(AbstractConstantValue left,
+                                  AbstractConstantValue right) {
+    AbstractConstantValue folded =
+        foldBinary(constantSystem.bitOr, left, right);
     return folded ?? closedOnUint31(left, right);
   }
 
-  AbstractValue xorSpecial(AbstractValue left, AbstractValue right) {
-    AbstractValue folded = foldBinary(constantSystem.bitXor, left, right);
+  AbstractConstantValue xorSpecial(AbstractConstantValue left,
+                                   AbstractConstantValue right) {
+    AbstractConstantValue folded =
+        foldBinary(constantSystem.bitXor, left, right);
     return folded ?? closedOnUint31(left, right);
   }
 
-  AbstractValue shiftLeftSpecial(AbstractValue left, AbstractValue right) {
+  AbstractConstantValue shiftLeftSpecial(AbstractConstantValue left,
+                                         AbstractConstantValue right) {
     return foldBinary(constantSystem.shiftLeft, left, right);
   }
 
-  AbstractValue shiftRightSpecial(AbstractValue left, AbstractValue right) {
-    AbstractValue folded = foldBinary(constantSystem.shiftRight, left, right);
+  AbstractConstantValue shiftRightSpecial(AbstractConstantValue left,
+                                          AbstractConstantValue right) {
+    AbstractConstantValue folded =
+        foldBinary(constantSystem.shiftRight, left, right);
     if (folded != null) return folded;
     if (isDefinitelyUint31(left)) {
       return nonConstant(typeSystem.uint31Type);
@@ -506,27 +547,51 @@
     return null;
   }
 
-  AbstractValue lessSpecial(AbstractValue left, AbstractValue right) {
+  AbstractConstantValue lessSpecial(AbstractConstantValue left,
+                                    AbstractConstantValue right) {
     return foldBinary(constantSystem.less, left, right);
   }
 
-  AbstractValue lessEqualSpecial(AbstractValue left, AbstractValue right) {
+  AbstractConstantValue lessEqualSpecial(AbstractConstantValue left,
+                                         AbstractConstantValue right) {
     return foldBinary(constantSystem.lessEqual, left, right);
   }
 
-  AbstractValue greaterSpecial(AbstractValue left, AbstractValue right) {
+  AbstractConstantValue greaterSpecial(AbstractConstantValue left,
+                                       AbstractConstantValue right) {
     return foldBinary(constantSystem.greater, left, right);
   }
 
-  AbstractValue greaterEqualSpecial(AbstractValue left, AbstractValue right) {
+  AbstractConstantValue greaterEqualSpecial(AbstractConstantValue left,
+                                            AbstractConstantValue right) {
     return foldBinary(constantSystem.greaterEqual, left, right);
   }
 
-  AbstractValue stringConstant(String value) {
+  AbstractConstantValue intConstant(int value) {
+    return constant(new IntConstantValue(value));
+  }
+
+  AbstractConstantValue lengthSpecial(AbstractConstantValue input) {
+    if (input.isConstant) {
+      ConstantValue constant = input.constant;
+      if (constant is StringConstantValue) {
+        return intConstant(constant.length);
+      } else if (constant is ListConstantValue) {
+        return intConstant(constant.length);
+      }
+    }
+    int length = typeSystem.getContainerLength(input.type);
+    if (length != null) {
+      return intConstant(length);
+    }
+    return null;  // The caller will use return type from type inference.
+  }
+
+  AbstractConstantValue stringConstant(String value) {
     return constant(new StringConstantValue(new ast.DartString.literal(value)));
   }
 
-  AbstractValue stringify(AbstractValue value) {
+  AbstractConstantValue stringify(AbstractConstantValue value) {
     if (value.isNothing) return nothing;
     if (value.isNonConst) return nonConstant(typeSystem.stringType);
     ConstantValue constantValue = value.constant;
@@ -544,7 +609,7 @@
 
   /// Returns whether [value] is one of the falsy values: false, 0, -0, NaN,
   /// the empty string, or null.
-  AbstractBool boolify(AbstractValue value) {
+  AbstractBool boolify(AbstractConstantValue value) {
     if (value.isNothing) return AbstractBool.Nothing;
     if (value.isConstant) {
       ConstantValue constantValue = value.constant;
@@ -558,7 +623,7 @@
   }
 
   /// Returns whether [value] is the value `true`.
-  AbstractBool strictBoolify(AbstractValue value) {
+  AbstractBool strictBoolify(AbstractConstantValue value) {
     if (value.isNothing) return AbstractBool.Nothing;
     if (value.isConstant) {
       return value.constant.isTrue ? AbstractBool.True : AbstractBool.False;
@@ -569,11 +634,11 @@
   /// The possible return types of a method that may be targeted by
   /// [typedSelector]. If the given selector is not a [TypedSelector], any
   /// reachable method matching the selector may be targeted.
-  AbstractValue getInvokeReturnType(Selector selector, TypeMask mask) {
+  AbstractConstantValue getInvokeReturnType(Selector selector, TypeMask mask) {
     return fromMask(typeSystem.getInvokeReturnType(selector, mask));
   }
 
-  AbstractValue fromMask(TypeMask mask) {
+  AbstractConstantValue fromMask(TypeMask mask) {
     ConstantValue constantValue = typeSystem.getConstantOf(mask);
     if (constantValue != null) return constant(constantValue, mask);
     return nonConstant(mask);
@@ -613,14 +678,11 @@
 
   @override
   void rewrite(FunctionDefinition root) {
-    Map<Expression, ConstantValue> replacements = <Expression, ConstantValue>{};
-
     // Analyze. In this phase, the entire term is analyzed for reachability
     // and the abstract value of each expression.
     TypePropagationVisitor analyzer = new TypePropagationVisitor(
         _lattice,
         _values,
-        replacements,
         _internalError);
 
     analyzer.analyze(root);
@@ -633,7 +695,6 @@
         _functionCompiler,
         _lattice,
         analyzer,
-        replacements,
         _internalError);
     transformer.transform(root);
   }
@@ -660,7 +721,6 @@
  */
 class TransformingVisitor extends DeepRecursiveVisitor {
   final TypePropagationVisitor analyzer;
-  final Map<Expression, ConstantValue> replacements;
   final ConstantPropagationLattice lattice;
   final dart2js.Compiler compiler;
   final CpsFunctionCompiler functionCompiler;
@@ -680,10 +740,24 @@
                       this.functionCompiler,
                       this.lattice,
                       this.analyzer,
-                      this.replacements,
                       this.internalError);
 
   void transform(FunctionDefinition root) {
+    // If one of the parameters has no value, the function is unreachable.
+    // We assume all values in scope have a non-empty type (otherwise the
+    // scope is unreachable), so this optimization is required.
+    // TODO(asgerf): Can we avoid emitting the function is the first place?
+    for (Parameter param in root.parameters) {
+      if (getValue(param).isNothing) {
+        // Replace with `throw "Unreachable";`
+        CpsFragment cps = new CpsFragment(null);
+        Primitive message = cps.makeConstant(
+            new StringConstantValue.fromString("Unreachable"));
+        cps.put(new Throw(message));
+        replaceSubtree(root.body, cps.result);
+        return;
+      }
+    }
     push(root.body);
     while (stack.isNotEmpty) {
       visit(stack.removeLast());
@@ -719,39 +793,66 @@
   }
 
   void visitLetPrim(LetPrim node) {
-    AbstractValue value = getValue(node.primitive);
-    if (node.primitive is! Constant &&
-        node.primitive is! Refinement &&
-        node.primitive.isSafeForElimination &&
-        value.isConstant) {
-      // If the value is a known constant, compile it as a constant.
-      Constant newPrim = makeConstantPrimitive(value.constant);
-      newPrim.substituteFor(node.primitive);
-      RemovalVisitor.remove(node.primitive);
-      node.primitive = newPrim;
-      newPrim.parent = node;
-    } else {
-      Primitive newPrim = visit(node.primitive);
-      if (newPrim != null) {
-        newPrim.substituteFor(node.primitive);
-        RemovalVisitor.remove(node.primitive);
-        node.primitive = newPrim;
-        newPrim.parent = node;
-        reanalyze(newPrim);
-      }
-      if (node.primitive.hasNoUses && node.primitive.isSafeForElimination) {
-        // Remove unused primitives before entering the body.
-        // This would also be done by shrinking reductions, but usage analyses
-        // such as isAlwaysBoolified are more precise without the dead uses, so
-        // we prefer to remove them early.
-        RemovalVisitor.remove(node.primitive);
-        node.parent.body = node.body;
-        node.body.parent = node.parent;
+    Primitive prim = node.primitive;
+
+    // Try to remove a dead primitive.
+    if (prim.hasNoUses && prim.isSafeForElimination) {
+      push(node.body);
+      prim.destroy();
+      node.remove();
+      return;
+    }
+
+    // Try to constant-fold the primitive.
+    if (prim is! Constant && prim is! Refinement && prim.isSafeForElimination) {
+      AbstractConstantValue value = getValue(prim);
+      if (value.isConstant) {
+        prim.replaceWith(makeConstantPrimitive(value.constant));
+        push(node.body);
+        return;
       }
     }
+
+    // Try to specialize the primitive.
+    var replacement = visit(prim);
+    if (replacement is CpsFragment) {
+      reanalyzeFragment(replacement);
+      replacement.insertBelow(node);
+      push(node.body); // Get the body before removing the node.
+      prim.destroy();
+      node.remove();
+      return;
+    }
+    if (replacement is Primitive) {
+      prim.replaceWith(replacement);
+      reanalyze(replacement);
+      // Reanalyze this node. Further specialization may be possible.
+      push(node);
+      return;
+    }
+    assert(replacement == null);
+
+    // Remove dead code after a primitive that always throws.
+    if (isAlwaysThrowingOrDiverging(prim)) {
+      replaceSubtree(node.body, new Unreachable());
+      return;
+    }
+
     push(node.body);
   }
 
+  bool isAlwaysThrowingOrDiverging(Primitive prim) {
+    if (prim is SetField) {
+      return getValue(prim.object.definition).isNullConstant;
+    }
+    if (prim is SetIndex) {
+      return getValue(prim.object.definition).isNullConstant;
+    }
+    // If a primitive has a value, but can't return anything, it must throw
+    // or diverge.
+    return prim.hasValue && prim.type.isEmpty && !prim.type.isNullable;
+  }
+
   void visitContinuation(Continuation node) {
     if (node.isReturnContinuation) return;
     if (!analyzer.reachableContinuations.contains(node)) {
@@ -771,27 +872,35 @@
     analyzer.reanalyzeSubtree(node);
   }
 
+  /// Sets parent pointers and computes types for the given fragment.
+  void reanalyzeFragment(CpsFragment code) {
+    if (code.isEmpty) return;
+    if (code.isOpen) {
+      // Temporarily close the fragment while analyzing it.
+      // TODO(asgerf): Perhaps the analyzer should just cope with missing nodes.
+      InteriorNode context = code.context;
+      code.put(new Unreachable());
+      reanalyze(code.root);
+      code.context = context;
+      context.body = null;
+    } else {
+      reanalyze(code.root);
+    }
+  }
+
   /// Removes the entire subtree of [node] and inserts [replacement].
   ///
-  /// By default, all references in the [node] subtree are unlinked, and parent
-  /// pointers in [replacement] are initialized and its types recomputed.
-  ///
-  /// If the caller needs to manually unlink the node, because some references
-  /// were adopted by other nodes, it can be disabled by passing `false`
-  /// as the [unlink] parameter.
+  /// All references in the [node] subtree are unlinked all types in
+  /// [replacement] are recomputed.
   ///
   /// [replacement] must be "fresh", i.e. it must not contain significant parts
-  /// of the original IR inside of it since the [ParentVisitor] will
-  /// redundantly reprocess it.
-  void replaceSubtree(Expression node, Expression replacement,
-                      {bool unlink: true}) {
+  /// of the original IR inside of it, as this leads to redundant reprocessing.
+  void replaceSubtree(Expression node, Expression replacement) {
     InteriorNode parent = node.parent;
     parent.body = replacement;
     replacement.parent = parent;
     node.parent = null;
-    if (unlink) {
-      RemovalVisitor.remove(node);
-    }
+    RemovalVisitor.remove(node);
     reanalyze(replacement);
   }
 
@@ -818,16 +927,6 @@
     node.parent = context;
   }
 
-  /// Binds [prim] before [node].
-  void insertLetPrim(Expression node, Primitive prim) {
-    InteriorNode parent = node.parent;
-    LetPrim let = new LetPrim(prim);
-    parent.body = let;
-    let.body = node;
-    node.parent = let;
-    let.parent = parent;
-  }
-
   /// Make a constant primitive for [constant] and set its entry in [values].
   Constant makeConstantPrimitive(ConstantValue constant) {
     Constant primitive = new Constant(constant);
@@ -864,7 +963,7 @@
     Continuation trueCont = node.trueContinuation.definition;
     Continuation falseCont = node.falseContinuation.definition;
     Primitive condition = node.condition.definition;
-    AbstractValue conditionValue = getValue(condition);
+    AbstractConstantValue conditionValue = getValue(condition);
 
     // Change to non-strict check if the condition is a boolean or null.
     if (lattice.isDefinitelyBool(conditionValue, allowNull: true)) {
@@ -889,44 +988,6 @@
       push(invoke);
       return;
     }
-
-    if (condition is ApplyBuiltinOperator &&
-        (condition.operator == BuiltinOperator.LooseEq ||
-         condition.operator == BuiltinOperator.StrictEq)) {
-      Primitive leftArg = condition.arguments[0].definition;
-      Primitive rightArg = condition.arguments[1].definition;
-      AbstractValue left = getValue(leftArg);
-      AbstractValue right = getValue(rightArg);
-      if (right.isNullConstant &&
-          lattice.isDefinitelyNotNumStringBool(left)) {
-        // Rewrite:
-        //   if (x == null) S1 else S2
-        //     =>
-        //   if (x) S2 else S1   (note the swapped branches)
-        Branch branch = new Branch.loose(leftArg, falseCont, trueCont);
-        replaceSubtree(node, branch);
-        return;
-      } else if (left.isNullConstant &&
-                 lattice.isDefinitelyNotNumStringBool(right)) {
-        Branch branch = new Branch.loose(rightArg, falseCont, trueCont);
-        replaceSubtree(node, branch);
-        return;
-      } else if (right.isTrueConstant &&
-                 lattice.isDefinitelyBool(left, allowNull: true)) {
-        // Rewrite:
-        //   if (x == true) S1 else S2
-        //     =>
-        //   if (x) S1 else S2
-        Branch branch = new Branch.loose(leftArg, trueCont, falseCont);
-        replaceSubtree(node, branch);
-        return;
-      } else if (left.isTrueConstant &&
-                 lattice.isDefinitelyBool(right, allowNull: true)) {
-        Branch branch = new Branch.loose(rightArg, trueCont, falseCont);
-        replaceSubtree(node, branch);
-        return;
-      }
-    }
   }
 
   void visitInvokeContinuation(InvokeContinuation node) {
@@ -941,8 +1002,10 @@
         !cont.isRecursive &&
         !node.isEscapingTry) {
       for (int i = 0; i < node.arguments.length; ++i) {
-        node.arguments[i].definition.useElementAsHint(cont.parameters[i].hint);
-        node.arguments[i].definition.substituteFor(cont.parameters[i]);
+        Primitive argument = node.arguments[i].definition;
+        Parameter parameter = cont.parameters[i];
+        argument.useElementAsHint(parameter.hint);
+        parameter.replaceUsesWith(argument);
         node.arguments[i].unlink();
       }
       node.continuation.unlink();
@@ -967,34 +1030,70 @@
   /// Replaces [node] with a more specialized instruction, if possible.
   ///
   /// Returns `true` if the node was replaced.
-  bool specializeOperatorCall(InvokeMethod node) {
-    Continuation cont = node.continuation.definition;
-    bool replaceWithPrimitive(Primitive prim) {
-      LetPrim let = makeLetPrimInvoke(prim, cont);
-      replaceSubtree(node, let);
-      push(let);
-      return true; // So returning early is more convenient.
-    }
-    bool replaceWithBinary(BuiltinOperator operator,
-                           Primitive left,
-                           Primitive right) {
-      return replaceWithPrimitive(
-          new ApplyBuiltinOperator(
-              operator, <Primitive>[left, right], node.sourceInformation));
-    }
-    bool replaceWithUnary(BuiltinOperator operator, Primitive argument) {
-      return replaceWithPrimitive(
-          new ApplyBuiltinOperator(
-              operator, <Primitive>[argument], node.sourceInformation));
-    }
-
+  specializeOperatorCall(InvokeMethod node) {
     bool trustPrimitives = compiler.trustPrimitives;
 
+    /// Checks that the the receiver satisfied the given predicate [guard],
+    /// otherwise ensures a [NoSuchMethodError] will be thrown.
+    ///
+    /// For example, if the [guard] is `IsNumber` for a call to `<`:
+    ///
+    ///     if (typeof x !== 'number') return x.$lt();
+    ///
+    /// The [guard] must accept all possible non-null values for the receiver,
+    /// but should be as specific as possible so the VM gets more information
+    /// from the check.
+    Primitive guardReceiver(CpsFragment cps, BuiltinOperator guard) {
+      if (guard == null || getValue(node.dartReceiver).isDefinitelyNotNull) {
+        return node.dartReceiver;
+      }
+      if (!trustPrimitives) {
+        Primitive check = cps.applyBuiltin(guard, [node.dartReceiver]);
+        cps.ifFalsy(check)
+           ..invokeMethod(node.dartReceiver, node.selector,
+             typeSystem.nullType, [])
+           ..put(new Unreachable());
+      }
+      // Refine the receiver to be non-null for use in the operator.
+      // This restricts code motion and improves the type computed for the
+      // built-in operator that depends on it.
+      // This must be done even if trusting primitives.
+      Primitive refined = cps.letPrim(
+          new Refinement(node.dartReceiver, typeSystem.nonNullType));
+      return refined;
+    }
+
+    /// Replaces the call with [operator], using the receiver and first argument
+    /// as operands (in that order).
+    ///
+    /// If [guard] is given, the receiver is checked using [guardReceiver],
+    /// unless it is known kot to be null.
+    CpsFragment makeBinary(BuiltinOperator operator, {BuiltinOperator guard}) {
+      CpsFragment cps = new CpsFragment(node.sourceInformation);
+      Primitive left = guardReceiver(cps, guard);
+      Primitive right = node.dartArgument(0);
+      Primitive result = cps.applyBuiltin(operator, [left, right]);
+      result.hint = node.hint;
+      node.replaceUsesWith(result);
+      return cps;
+    }
+
+    /// Like [makeBinary] but for unary operators with the receiver as the
+    /// argument.
+    CpsFragment makeUnary(BuiltinOperator operator, {BuiltinOperator guard}) {
+      CpsFragment cps = new CpsFragment(node.sourceInformation);
+      Primitive argument = guardReceiver(cps, guard);
+      Primitive result = cps.applyBuiltin(operator, [argument]);
+      result.hint = node.hint;
+      node.replaceUsesWith(result);
+      return cps;
+    }
+
     if (node.selector.isOperator && node.arguments.length == 2) {
-      Primitive leftArg = getDartReceiver(node);
-      Primitive rightArg = getDartArgument(node, 0);
-      AbstractValue left = getValue(leftArg);
-      AbstractValue right = getValue(rightArg);
+      Primitive leftArg = node.dartReceiver;
+      Primitive rightArg = node.dartArgument(0);
+      AbstractConstantValue left = getValue(leftArg);
+      AbstractConstantValue right = getValue(rightArg);
 
       String opname = node.selector.name;
       if (opname == '==') {
@@ -1002,8 +1101,7 @@
         // fact that Dart-null corresponds to both JS-null and JS-undefined.
         // Please see documentation for IsFalsy, StrictEq, and LooseEq.
         if (left.isNullConstant || right.isNullConstant) {
-          return replaceWithBinary(BuiltinOperator.Identical,
-                                   leftArg, rightArg);
+          return makeBinary(BuiltinOperator.Identical);
         }
         // There are several implementations of == that behave like identical.
         // Specialize it if we definitely call one of those.
@@ -1018,98 +1116,113 @@
           }
         }
         if (behavesLikeIdentical) {
-          return replaceWithBinary(BuiltinOperator.Identical,
-                                   leftArg, rightArg);
+          return makeBinary(BuiltinOperator.Identical);
         }
       } else {
-        if (lattice.isDefinitelyNum(left, allowNull: trustPrimitives) &&
+        if (lattice.isDefinitelyNum(left, allowNull: true) &&
             lattice.isDefinitelyNum(right, allowNull: trustPrimitives)) {
           // Try to insert a numeric operator.
           BuiltinOperator operator = NumBinaryBuiltins[opname];
           if (operator != null) {
-            return replaceWithBinary(operator, leftArg, rightArg);
+            return makeBinary(operator, guard: BuiltinOperator.IsNumber);
           }
           // Shift operators are not in [NumBinaryBuiltins] because Dart shifts
           // behave different to JS shifts, especially in the handling of the
           // shift count.
           // Try to insert a shift-left operator.
           if (opname == '<<' &&
-              lattice.isDefinitelyInt(left, allowNull: trustPrimitives) &&
+              lattice.isDefinitelyInt(left, allowNull: true) &&
               lattice.isDefinitelyIntInRange(right, min: 0, max: 31)) {
-            return replaceWithBinary(BuiltinOperator.NumShl, leftArg, rightArg);
+            return makeBinary(BuiltinOperator.NumShl,
+                guard: BuiltinOperator.IsNumber);
           }
           // Try to insert a shift-right operator. JavaScript's right shift is
           // consistent with Dart's only for left operands in the unsigned
           // 32-bit range.
           if (opname == '>>' &&
-              lattice.isDefinitelyUint32(left, allowNull: trustPrimitives) &&
+              lattice.isDefinitelyUint32(left, allowNull: true) &&
               lattice.isDefinitelyIntInRange(right, min: 0, max: 31)) {
-            return replaceWithBinary(BuiltinOperator.NumShr, leftArg, rightArg);
+            return makeBinary(BuiltinOperator.NumShr,
+                guard: BuiltinOperator.IsNumber);
           }
           // Try to use remainder for '%'. Both operands must be non-negative
           // and the divisor must be non-zero.
           if (opname == '%' &&
-              lattice.isDefinitelyUint(left, allowNull: trustPrimitives) &&
+              lattice.isDefinitelyUint(left, allowNull: true) &&
               lattice.isDefinitelyUint(right) &&
               lattice.isDefinitelyIntInRange(right, min: 1)) {
-            return replaceWithBinary(
-                BuiltinOperator.NumRemainder, leftArg, rightArg);
+            return makeBinary(BuiltinOperator.NumRemainder,
+                guard: BuiltinOperator.IsNumber);
           }
 
           if (opname == '~/' &&
-              lattice.isDefinitelyUint32(left, allowNull: trustPrimitives) &&
+              lattice.isDefinitelyUint32(left, allowNull: true) &&
               lattice.isDefinitelyIntInRange(right, min: 2)) {
-            return replaceWithBinary(
-                BuiltinOperator.NumTruncatingDivideToSigned32,
-                leftArg, rightArg);
+            return makeBinary(BuiltinOperator.NumTruncatingDivideToSigned32,
+                guard: BuiltinOperator.IsNumber);
           }
         }
         if (lattice.isDefinitelyString(left, allowNull: trustPrimitives) &&
             lattice.isDefinitelyString(right, allowNull: trustPrimitives) &&
             opname == '+') {
-          return replaceWithBinary(BuiltinOperator.StringConcatenate,
-                                   leftArg, rightArg);
+          // TODO(asgerf): Add IsString builtin so we can use a guard here.
+          return makeBinary(BuiltinOperator.StringConcatenate);
         }
       }
     }
     if (node.selector.isOperator && node.arguments.length == 1) {
-      Primitive argument = getDartReceiver(node);
-      AbstractValue value = getValue(argument);
+      Primitive argument = node.dartReceiver;
+      AbstractConstantValue value = getValue(argument);
 
-      if (lattice.isDefinitelyNum(value, allowNull: false)) {
+      if (lattice.isDefinitelyNum(value, allowNull: true)) {
         String opname = node.selector.name;
         if (opname == '~') {
-          return replaceWithUnary(BuiltinOperator.NumBitNot, argument);
+          return makeUnary(BuiltinOperator.NumBitNot,
+              guard: BuiltinOperator.IsNumber);
         }
         if (opname == 'unary-') {
-          return replaceWithUnary(BuiltinOperator.NumNegate, argument);
+          return makeUnary(BuiltinOperator.NumNegate,
+              guard: BuiltinOperator.IsNumber);
         }
       }
     }
     if (node.selector.isCall) {
       String name = node.selector.name;
-      Primitive receiver = getDartReceiver(node);
-      AbstractValue receiverValue = getValue(receiver);
+      Primitive receiver = node.dartReceiver;
+      AbstractConstantValue receiverValue = getValue(receiver);
       if (name == 'remainder') {
         if (node.arguments.length == 2) {
-          Primitive arg = getDartArgument(node, 0);
-          AbstractValue argValue = getValue(arg);
-          if (lattice.isDefinitelyInt(receiverValue) &&
+          Primitive arg = node.dartArgument(0);
+          AbstractConstantValue argValue = getValue(arg);
+          if (lattice.isDefinitelyInt(receiverValue, allowNull: true) &&
               lattice.isDefinitelyInt(argValue) &&
               isIntNotZero(argValue)) {
-            return
-                replaceWithBinary(BuiltinOperator.NumRemainder, receiver, arg);
+            return makeBinary(BuiltinOperator.NumRemainder,
+                guard: BuiltinOperator.IsNumber);
+          }
+        }
+      } else if (name == 'codeUnitAt') {
+        if (node.arguments.length == 2) {
+          Primitive index = node.dartArgument(0);
+          if (lattice.isDefinitelyString(receiverValue) &&
+              lattice.isDefinitelyInt(getValue(index))) {
+            SourceInformation sourceInfo = node.sourceInformation;
+            CpsFragment cps = makeBoundsCheck(receiver, index, sourceInfo);
+            ApplyBuiltinOperator get =
+                cps.applyBuiltin(BuiltinOperator.CharCodeAt,
+                                 <Primitive>[receiver, index]);
+            node.replaceUsesWith(get);
+            get.hint = node.hint;
+            return cps;
           }
         }
       }
     }
-    // We should only get here if the node was not specialized.
-    assert(node.parent != null);
-    return false;
+    return null;
   }
 
   /// Returns `true` if [value] represents an int value that cannot be zero.
-  bool isIntNotZero(AbstractValue value) {
+  bool isIntNotZero(AbstractConstantValue value) {
     return lattice.isDefinitelyIntInRange(value, min: 1) ||
         lattice.isDefinitelyIntInRange(value, max: -1);
   }
@@ -1118,56 +1231,29 @@
     return backend.isInterceptedSelector(selector);
   }
 
-  Primitive getDartReceiver(InvokeMethod node) {
-    if (node.receiverIsIntercepted) {
-      return node.arguments[0].definition;
-    } else {
-      return node.receiver.definition;
-    }
-  }
-
-  Primitive getDartArgument(InvokeMethod node, int n) {
-    if (isInterceptedSelector(node.selector)) {
-      return node.arguments[n+1].definition;
-    } else {
-      return node.arguments[n].definition;
-    }
-  }
-
   /// If [node] is a getter or setter invocation, tries to replace the
   /// invocation with a direct access to a field.
   ///
   /// Returns `true` if the node was replaced.
-  bool specializeFieldAccess(InvokeMethod node) {
-    if (!node.selector.isGetter && !node.selector.isSetter) return false;
-    AbstractValue receiver = getValue(getDartReceiver(node));
+  Primitive specializeFieldAccess(InvokeMethod node) {
+    if (!node.selector.isGetter && !node.selector.isSetter) return null;
+    AbstractConstantValue receiver = getValue(node.dartReceiver);
     Element target =
         typeSystem.locateSingleElement(receiver.type, node.selector);
-    if (target is! FieldElement) return false;
+    if (target is! FieldElement) return null;
     // TODO(asgerf): Inlining native fields will make some tests pass for the
     // wrong reason, so for testing reasons avoid inlining them.
     if (backend.isNative(target) || backend.isJsInterop(target)) {
-      return false;
+      return null;
     }
-    Continuation cont = node.continuation.definition;
     if (node.selector.isGetter) {
-      GetField get = new GetField(getDartReceiver(node), target);
-      LetPrim let = makeLetPrimInvoke(get, cont);
-      replaceSubtree(node, let);
-      push(let);
-      return true;
+      return new GetField(node.dartReceiver, target);
     } else {
-      if (target.isFinal) return false;
-      assert(cont.parameters.single.hasNoUses);
-      cont.parameters.clear();
-      CpsFragment cps = new CpsFragment(node.sourceInformation);
-      cps.letPrim(new SetField(getDartReceiver(node),
-                               target,
-                               getDartArgument(node, 0)));
-      cps.invokeContinuation(cont);
-      replaceSubtree(node, cps.result);
-      push(cps.result);
-      return true;
+      if (target.isFinal) return null;
+      assert(node.hasNoUses);
+      return new SetField(node.dartReceiver,
+                          target,
+                          node.dartArgument(0));
     }
   }
 
@@ -1185,10 +1271,12 @@
       return cps;
     }
     Continuation fail = cps.letCont();
-    Primitive isTooSmall = cps.applyBuiltin(
-        BuiltinOperator.NumLt,
-        <Primitive>[index, cps.makeZero()]);
-    cps.ifTruthy(isTooSmall).invokeContinuation(fail);
+    if (!typeSystem.isDefinitelyNonNegativeInt(index.type)) {
+      Primitive isTooSmall = cps.applyBuiltin(
+          BuiltinOperator.NumLt,
+          <Primitive>[index, cps.makeZero()]);
+      cps.ifTruthy(isTooSmall).invokeContinuation(fail);
+    }
     Primitive isTooLarge = cps.applyBuiltin(
         BuiltinOperator.NumGe,
         <Primitive>[index, cps.letPrim(new GetLength(list))]);
@@ -1220,65 +1308,56 @@
   /// Tries to replace [node] with a direct `length` or index access.
   ///
   /// Returns `true` if the node was replaced.
-  bool specializeIndexableAccess(InvokeMethod node) {
-    Primitive receiver = getDartReceiver(node);
-    AbstractValue receiverValue = getValue(receiver);
+  specializeIndexableAccess(InvokeMethod node) {
+    Primitive receiver = node.dartReceiver;
+    AbstractConstantValue receiverValue = getValue(receiver);
     if (!typeSystem.isDefinitelyIndexable(receiverValue.type,
             allowNull: true)) {
-      return false;
+      return null;
     }
     SourceInformation sourceInfo = node.sourceInformation;
-    Continuation cont = node.continuation.definition;
     switch (node.selector.name) {
       case 'length':
-        if (!node.selector.isGetter) return false;
-        CpsFragment cps = new CpsFragment(sourceInfo);
-        cps.invokeContinuation(cont, [cps.letPrim(new GetLength(receiver))]);
-        replaceSubtree(node, cps.result);
-        push(cps.result);
-        return true;
+        if (!node.selector.isGetter) return null;
+        return new GetLength(receiver);
 
       case '[]':
-        Primitive index = getDartArgument(node, 0);
-        if (!lattice.isDefinitelyInt(getValue(index))) return false;
+        Primitive index = node.dartArgument(0);
+        if (!lattice.isDefinitelyInt(getValue(index))) return null;
         CpsFragment cps = makeBoundsCheck(receiver, index, sourceInfo);
         GetIndex get = cps.letPrim(new GetIndex(receiver, index));
-        cps.invokeContinuation(cont, [get]);
-        replaceSubtree(node, cps.result);
-        push(cps.result);
-        return true;
+        node.replaceUsesWith(get);
+        // TODO(asgerf): Make replaceUsesWith set the hint?
+        get.hint = node.hint;
+        return cps;
 
       case '[]=':
         if (!typeSystem.isDefinitelyMutableIndexable(receiverValue.type,
                 allowNull: true)) {
-          return false;
+          return null;
         }
-        Primitive index = getDartArgument(node, 0);
-        Primitive value = getDartArgument(node, 1);
-        if (!lattice.isDefinitelyInt(getValue(index))) return false;
+        Primitive index = node.dartArgument(0);
+        Primitive value = node.dartArgument(1);
+        if (!lattice.isDefinitelyInt(getValue(index))) return null;
         CpsFragment cps = makeBoundsCheck(receiver, index, sourceInfo);
         cps.letPrim(new SetIndex(receiver, index, value));
-        assert(cont.parameters.single.hasNoUses);
-        cont.parameters.clear();
-        cps.invokeContinuation(cont, []);
-        replaceSubtree(node, cps.result);
-        push(cps.result);
-        return true;
+        assert(node.hasNoUses);
+        return cps;
 
       default:
-        return false;
+        return null;
     }
   }
 
   /// Tries to replace [node] with one or more direct array access operations.
   ///
   /// Returns `true` if the node was replaced.
-  bool specializeArrayAccess(InvokeMethod node) {
-    Primitive list = getDartReceiver(node);
-    AbstractValue listValue = getValue(list);
+  CpsFragment specializeArrayAccess(InvokeMethod node) {
+    Primitive list = node.dartReceiver;
+    AbstractConstantValue listValue = getValue(list);
     // Ensure that the object is a native list or null.
     if (!lattice.isDefinitelyArray(listValue, allowNull: true)) {
-      return false;
+      return null;
     }
     bool isFixedLength =
         lattice.isDefinitelyFixedArray(listValue, allowNull: true);
@@ -1287,31 +1366,30 @@
     bool isExtendable =
         lattice.isDefinitelyExtendableArray(listValue, allowNull: true);
     SourceInformation sourceInfo = node.sourceInformation;
-    Continuation cont = node.continuation.definition;
     switch (node.selector.name) {
       case 'add':
         if (!node.selector.isCall ||
             node.selector.positionalArgumentCount != 1 ||
             node.selector.namedArgumentCount != 0) {
-          return false;
+          return null;
         }
-        if (!isExtendable) return false;
-        Primitive addedItem = getDartArgument(node, 0);
+        if (!isExtendable) return null;
+        Primitive addedItem = node.dartArgument(0);
         CpsFragment cps = new CpsFragment(sourceInfo);
         cps.invokeBuiltin(BuiltinMethod.Push,
             list,
             <Primitive>[addedItem]);
-        cps.invokeContinuation(cont, [cps.makeNull()]);
-        replaceSubtree(node, cps.result);
-        push(cps.result);
-        return true;
+        if (node.hasAtLeastOneUse) {
+          node.replaceUsesWith(cps.makeNull());
+        }
+        return cps;
 
       case 'removeLast':
         if (!node.selector.isCall ||
             node.selector.argumentCount != 0) {
-          return false;
+          return null;
         }
-        if (!isExtendable) return false;
+        if (!isExtendable) return null;
         CpsFragment cps = new CpsFragment(sourceInfo);
         Primitive length = cps.letPrim(new GetLength(list));
         Primitive isEmpty = cps.applyBuiltin(
@@ -1324,86 +1402,86 @@
         Primitive removedItem = cps.invokeBuiltin(BuiltinMethod.Pop,
             list,
             <Primitive>[]);
-        cps.invokeContinuation(cont, [removedItem]);
-        replaceSubtree(node, cps.result);
-        push(cps.result);
-        return true;
+        removedItem.hint = node.hint;
+        node.replaceUsesWith(removedItem);
+        return cps;
 
       case 'addAll':
         if (!node.selector.isCall ||
             node.selector.argumentCount != 1) {
-          return false;
+          return null;
         }
-        if (!isExtendable) return false;
-        Primitive addedList = getDartArgument(node, 0);
-        // Rewrite addAll([x1, ..., xN]) to push(x1, ..., xN).
+        if (!isExtendable) return null;
+        Primitive addedList = node.dartArgument(0);
+        // Rewrite addAll([x1, ..., xN]) to push(x1), ..., push(xN).
         // Ensure that the list is not mutated between creation and use.
         // We aim for the common case where this is the only use of the list,
         // which also guarantees that this list is not mutated before use.
         if (addedList is! LiteralList || !addedList.hasExactlyOneUse) {
-          return false;
+          return null;
         }
         LiteralList addedLiteral = addedList;
         CpsFragment cps = new CpsFragment(sourceInfo);
-        cps.invokeBuiltin(BuiltinMethod.Push,
-            list,
-            addedLiteral.values.map((ref) => ref.definition).toList());
-        cps.invokeContinuation(cont, [cps.makeNull()]);
-        replaceSubtree(node, cps.result);
-        push(cps.result);
-        return true;
+        for (Reference value in addedLiteral.values) {
+          cps.invokeBuiltin(BuiltinMethod.Push,
+              list,
+              <Primitive>[value.definition]);
+        }
+        if (node.hasAtLeastOneUse) {
+          node.replaceUsesWith(cps.makeNull());
+        }
+        return cps;
 
       case 'elementAt':
         if (!node.selector.isCall ||
             node.selector.positionalArgumentCount != 1 ||
             node.selector.namedArgumentCount != 0) {
-          return false;
+          return null;
         }
-        if (listValue.isNullable) return false;
-        Primitive index = getDartArgument(node, 0);
-        if (!lattice.isDefinitelyInt(getValue(index))) return false;
+        if (listValue.isNullable) return null;
+        Primitive index = node.dartArgument(0);
+        if (!lattice.isDefinitelyInt(getValue(index))) return null;
         CpsFragment cps = makeBoundsCheck(list, index, sourceInfo);
         GetIndex get = cps.letPrim(new GetIndex(list, index));
-        cps.invokeContinuation(cont, [get]);
-        replaceSubtree(node, cps.result);
-        push(cps.result);
-        return true;
+        get.hint = node.hint;
+        node.replaceUsesWith(get);
+        return cps;
 
       case 'forEach':
         Element element =
             compiler.world.locateSingleElement(node.selector, listValue.type);
         if (element == null ||
             !element.isFunction ||
-            !node.selector.isCall) return false;
+            !node.selector.isCall) return null;
         assert(node.selector.positionalArgumentCount == 1);
         assert(node.selector.namedArgumentCount == 0);
         FunctionDefinition target = functionCompiler.compileToCpsIr(element);
 
-        node.receiver.definition.substituteFor(target.thisParameter);
-        for (int i = 0; i < node.arguments.length; ++i) {
-          node.arguments[i].definition.substituteFor(target.parameters[i]);
-        }
-        node.continuation.definition.substituteFor(target.returnContinuation);
-
-        replaceSubtree(node, target.body);
-        push(target.body);
-        return true;
+        CpsFragment cps = new CpsFragment(node.sourceInformation);
+        Primitive result = cps.inlineFunction(target,
+            node.receiver.definition,
+            node.arguments.map((ref) => ref.definition).toList(),
+            hint: node.hint);
+        node.replaceUsesWith(result);
+        return cps;
 
       case 'iterator':
-        if (!node.selector.isGetter) return false;
-        Primitive iterator = cont.parameters.single;
-        Continuation iteratorCont = cont;
+        // TODO(asgerf): This should be done differently.
+        //               The types are recomputed in a very error-prone manner.
+        if (!node.selector.isGetter) return null;
+        Primitive iterator = node;
+        LetPrim iteratorBinding = node.parent;
 
         // Check that all uses of the iterator are 'moveNext' and 'current'.
         assert(!isInterceptedSelector(Selectors.moveNext));
         assert(!isInterceptedSelector(Selectors.current));
         for (Reference ref in iterator.effectiveUses) {
-          if (ref.parent is! InvokeMethod) return false;
+          if (ref.parent is! InvokeMethod) return null;
           InvokeMethod use = ref.parent;
-          if (ref != use.receiver) return false;
+          if (ref != use.receiver) return null;
           if (use.selector != Selectors.moveNext &&
               use.selector != Selectors.current) {
-            return false;
+            return null;
           }
         }
 
@@ -1416,17 +1494,14 @@
         // Rewrite all uses of the iterator.
         for (Reference ref in iterator.effectiveUses) {
           InvokeMethod use = ref.parent;
-          Continuation useCont = use.continuation.definition;
           if (use.selector == Selectors.current) {
             // Rewrite iterator.current to a use of the 'current' variable.
-            Parameter result = useCont.parameters.single;
-            if (result.hint != null) {
+            if (use.hint != null) {
               // If 'current' was originally moved into a named variable, use
               // that variable name for the mutable variable.
-              current.hint = result.hint;
+              current.hint = use.hint;
             }
-            LetPrim let = makeLetPrimInvoke(new GetMutable(current), useCont);
-            replaceSubtree(use, let);
+            use.replaceWith(new GetMutable(current));
           } else {
             assert (use.selector == Selectors.moveNext);
             // Rewrite iterator.moveNext() to:
@@ -1444,6 +1519,8 @@
 
             // [cps] contains the code we insert instead of moveNext().
             CpsFragment cps = new CpsFragment(node.sourceInformation);
+            Parameter result = new Parameter(node.hint);
+            Continuation moveNextCont = cps.letCont(<Parameter>[result]);
 
             // We must check for concurrent modification when calling moveNext.
             // When moveNext is used as a loop condition, the check prevents
@@ -1471,7 +1548,7 @@
             //
             // The check before the loop can often be eliminated because it
             // follows immediately after the 'iterator' call.
-            InteriorNode parent = getEffectiveParent(use);
+            InteriorNode parent = getEffectiveParent(use.parent);
             if (!isFixedLength) {
               if (parent is Continuation && parent.isRecursive) {
                 // Check for concurrent modification before every invocation
@@ -1482,7 +1559,7 @@
                      ref != null;
                      ref = ref.next) {
                   Expression invocationCaller = ref.parent;
-                  if (getEffectiveParent(invocationCaller) == iteratorCont) {
+                  if (getEffectiveParent(invocationCaller) == iteratorBinding) {
                     // No need to check for concurrent modification immediately
                     // after the call to 'iterator'.
                     continue;
@@ -1506,18 +1583,25 @@
             CpsFragment falseBranch = cps.ifFalsy(hasMore);
             falseBranch
               ..setMutable(current, falseBranch.makeNull())
-              ..invokeContinuation(useCont, [falseBranch.makeFalse()]);
+              ..invokeContinuation(moveNextCont, [falseBranch.makeFalse()]);
 
             // Return true if there are more element.
+            current.type = typeSystem.elementTypeOfIndexable(listValue.type);
             cps.setMutable(current,
                 cps.letPrim(new GetIndex(list, cps.getMutable(index))));
             cps.setMutable(index, cps.applyBuiltin(
                 BuiltinOperator.NumAdd,
                 [cps.getMutable(index), cps.makeOne()]));
-            cps.invokeContinuation(useCont, [cps.makeTrue()]);
+            cps.invokeContinuation(moveNextCont, [cps.makeTrue()]);
+
+            reanalyzeFragment(cps);
 
             // Replace the moveNext() call. It will be visited later.
-            replaceSubtree(use, cps.result);
+            LetPrim let = use.parent;
+            cps.context = moveNextCont;
+            cps.insertBelow(let);
+            let.remove();
+            use..replaceUsesWith(result)..destroy();
           }
         }
 
@@ -1529,38 +1613,13 @@
         cps.letMutable(index, cps.makeZero());
         cps.letMutable(current, cps.makeNull());
         cps.letPrim(originalLength);
-
-        // Insert this fragment before the continuation body and replace the
-        // iterator call with a call to the continuation without arguments.
-        // For scoping reasons, the variables must be bound inside the
-        // continuation, not at the invocation-site.
-        iteratorCont.parameters.clear();
-        insertBefore(iteratorCont.body, cps);
-        InvokeContinuation invoke = new InvokeContinuation(iteratorCont, []);
-        replaceSubtree(node, invoke);
-        push(invoke);
-        return true;
+        return cps;
 
       default:
-        return false;
+        return null;
     }
   }
 
-  /// If [prim] is the parameter to a call continuation, returns the
-  /// corresponding call.
-  CallExpression getCallWithResult(Primitive prim) {
-    if (prim is Parameter && prim.parent is Continuation) {
-      Continuation cont = prim.parent;
-      if (cont.hasExactlyOneUse) {
-        Node use = cont.firstRef.parent;
-        if (use is CallExpression) {
-          return use;
-        }
-      }
-    }
-    return null;
-  }
-
   /// Returns the first parent of [node] that is not a pure expression.
   InteriorNode getEffectiveParent(Expression node) {
     while (true) {
@@ -1582,14 +1641,14 @@
   ///       =>
   ///     obj.foo$<n>(<args>)
   ///
-  bool specializeClosureCall(InvokeMethod node) {
+  Primitive specializeClosureCall(InvokeMethod node) {
     Selector call = node.selector;
-    if (!call.isClosureCall) return false;
+    if (!call.isClosureCall) return null;
 
     assert(!isInterceptedSelector(call));
     assert(call.argumentCount == node.arguments.length);
 
-    Primitive tearOff = node.receiver.definition.effectiveDefinition;
+    Primitive tearOff = node.dartReceiver.effectiveDefinition;
     // Note: We don't know if [tearOff] is actually a tear-off.
     // We name variables based on the pattern we are trying to match.
 
@@ -1598,69 +1657,73 @@
       FunctionSignature signature = target.functionSignature;
 
       // If the selector does not apply, don't bother (will throw at runtime).
-      if (!call.signatureApplies(target)) return false;
+      if (!call.signatureApplies(target)) return null;
 
       // If some optional arguments are missing, give up.
       // TODO(asgerf): Improve optimization by inserting default arguments.
-      if (call.argumentCount != signature.parameterCount) return false;
+      if (call.argumentCount != signature.parameterCount) return null;
 
-      InvokeStatic invoke = new InvokeStatic.byReference(
-          target,
+      // Replace with InvokeStatic.
+      // The tear-off will be cleaned up by shrinking reductions.
+      return new InvokeStatic(target,
           new Selector.fromElement(target),
-          node.arguments,
-          node.continuation,
+          node.arguments.map((ref) => ref.definition).toList(),
           node.sourceInformation);
-      node.receiver.unlink();
-      replaceSubtree(node, invoke, unlink: false);
-      push(invoke);
-      return true;
     }
-    CallExpression tearOffInvoke = getCallWithResult(tearOff);
-    if (tearOffInvoke is InvokeMethod && tearOffInvoke.selector.isGetter) {
-      Selector getter = tearOffInvoke.selector;
+    if (tearOff is InvokeMethod && tearOff.selector.isGetter) {
+      Selector getter = tearOff.selector;
 
       // TODO(asgerf): Support torn-off intercepted methods.
-      if (isInterceptedSelector(getter)) return false;
+      if (isInterceptedSelector(getter)) return null;
 
-      Continuation getterCont = tearOffInvoke.continuation.definition;
+      LetPrim tearOffBinding = tearOff.parent;
 
-      Primitive object = tearOffInvoke.receiver.definition;
+      Primitive object = tearOff.receiver.definition;
 
       // Ensure that the object actually has a foo member, since we might
       // otherwise alter a noSuchMethod call.
       TypeMask type = getValue(object).type;
-      if (typeSystem.needsNoSuchMethodHandling(type, getter)) return false;
+      if (typeSystem.needsNoSuchMethodHandling(type, getter)) return null;
 
-      // Determine if the getter invocation can have side-effects.
       Element element = typeSystem.locateSingleElement(type, getter);
+
+      // If it's definitely not a tear-off, the rewrite is not worth it.
+      // If we don't know what the target is, we assume that it's better to
+      // rewrite (as long as it's safe to do so).
+      if (element != null && element.isGetter) return null;
+
+      // Either the target is a tear-off or we don't know what it is.
+      // If we don't know for sure, the getter might have side effects, which
+      // can make the rewriting unsafe, because we risk suppressing side effects
+      // in the getter.
+      // Determine if the getter invocation can have side-effects.
       bool isPure = element != null && !element.isGetter;
 
       // If there are multiple uses, we cannot eliminate the getter call and
       // therefore risk duplicating its side effects.
-      if (!isPure && tearOff.hasMultipleEffectiveUses) return false;
+      if (!isPure && tearOff.hasMultipleEffectiveUses) return null;
 
-      // If the getter call is impure, we risk reordering side effects.
-      if (!isPure && getEffectiveParent(node) != getterCont) {
-        return false;
+      // If the getter call is impure, we risk reordering side effects,
+      // unless it is immediately prior to the closure call.
+      if (!isPure && getEffectiveParent(node.parent) != tearOffBinding) {
+        return null;
       }
 
-      InvokeMethod invoke = new InvokeMethod.byReference(
-        new Reference<Primitive>(object),
+      InvokeMethod invoke = new InvokeMethod(
+        object,
         new Selector.call(getter.memberName, call.callStructure),
         type,
-        node.arguments,
-        node.continuation,
+        node.arguments.map((ref) => ref.definition).toList(),
         node.sourceInformation);
-      node.receiver.unlink();
-      replaceSubtree(node, invoke, unlink: false);
+      node.receiver.changeTo(new Parameter(null)); // Remove the tear off use.
 
       if (tearOff.hasNoEffectiveUses) {
         // Eliminate the getter call if it has no more uses.
         // This cannot be delegated to other optimizations because we need to
         // avoid duplication of side effects.
         destroyRefinementsOfDeadPrimitive(tearOff);
-        getterCont.parameters.clear();
-        replaceSubtree(tearOffInvoke, new InvokeContinuation(getterCont, []));
+        tearOff.destroy();
+        tearOffBinding.remove();
       } else {
         // There are more uses, so we cannot eliminate the getter call. This
         // means we duplicated the effects of the getter call, but we should
@@ -1668,10 +1731,9 @@
         assert(isPure);
       }
 
-      push(invoke);
-      return true;
+      return invoke;
     }
-    return false;
+    return null;
   }
 
   void destroyRefinementsOfDeadPrimitive(Primitive prim) {
@@ -1688,39 +1750,39 @@
 
   /// Inlines a single-use closure if it leaves the closure object with only
   /// field accesses.  This is optimized later by [ScalarReplacer].
-  bool specializeSingleUseClosureCall(InvokeMethod node) {
+  CpsFragment specializeSingleUseClosureCall(InvokeMethod node) {
     Selector call = node.selector;
-    if (!call.isClosureCall) return false;
+    if (!call.isClosureCall) return null;
 
     assert(!isInterceptedSelector(call));
     assert(call.argumentCount == node.arguments.length);
 
     Primitive receiver = node.receiver.definition;
-    if (receiver is !CreateInstance) return false;
+    if (receiver is !CreateInstance) return null;
     CreateInstance createInstance = receiver;
-    if (!createInstance.hasExactlyOneUse) return false;
+    if (!createInstance.hasExactlyOneUse) return null;
 
     // Inline only closures. This avoids inlining the 'call' method of a class
     // that has many allocation sites.
-    if (createInstance.classElement is !ClosureClassElement) return false;
+    if (createInstance.classElement is !ClosureClassElement) return null;
 
     ClosureClassElement closureClassElement = createInstance.classElement;
     Element element = closureClassElement.localLookup(Identifiers.call);
 
-    if (element == null || !element.isFunction) return false;
+    if (element == null || !element.isFunction) return null;
     FunctionElement functionElement = element;
-    if (functionElement.asyncMarker != AsyncMarker.SYNC) return false;
+    if (functionElement.asyncMarker != AsyncMarker.SYNC) return null;
 
-    if (!call.signatureApplies(functionElement)) return false;
+    if (!call.signatureApplies(functionElement)) return null;
     // Inline only for exact match.
     // TODO(sra): Handle call with defaulted arguments.
     Selector targetSelector = new Selector.fromElement(functionElement);
-    if (call.callStructure != targetSelector.callStructure) return false;
+    if (call.callStructure != targetSelector.callStructure) return null;
 
     // Don't inline if [target] contains try-catch or try-finally. JavaScript
     // engines typically do poor optimization of the entire function containing
     // the 'try'.
-    if (functionElement.resolvedAst.elements.containsTryStatement) return false;
+    if (functionElement.resolvedAst.elements.containsTryStatement) return null;
 
     FunctionDefinition target =
         functionCompiler.compileToCpsIr(functionElement);
@@ -1736,53 +1798,34 @@
       // Closures do not currently have writable fields, but closure conversion
       // could esily be changed to allocate some cells in a closure object.
       if (use is SetField && ref == use.object) continue;
-      return false;
+      return null;
     }
 
-    node.receiver.definition.substituteFor(target.thisParameter);
-    for (int i = 0; i < node.arguments.length; ++i) {
-      node.arguments[i].definition.substituteFor(target.parameters[i]);
-    }
-    node.continuation.definition.substituteFor(target.returnContinuation);
-
-    replaceSubtree(node, target.body);
-    push(target.body);
-    return true;
+    CpsFragment cps = new CpsFragment(node.sourceInformation);
+    Primitive returnValue = cps.inlineFunction(target,
+        node.receiver.definition,
+        node.arguments.map((ref) => ref.definition).toList(),
+        hint: node.hint);
+    node.replaceUsesWith(returnValue);
+    return cps;
   }
 
-  /// Side-effect free expressions with constant results are be replaced by:
-  ///
-  ///    (LetPrim p = constant (InvokeContinuation k p)).
-  ///
-  /// The new expression will be visited.
-  ///
-  /// Returns true if the node was replaced.
-  bool constifyExpression(CallExpression node) {
-    Continuation continuation = node.continuation.definition;
-    ConstantValue constant = replacements[node];
-    if (constant == null) return false;
-    Constant primitive = makeConstantPrimitive(constant);
-    LetPrim letPrim = makeLetPrimInvoke(primitive, continuation);
-    replaceSubtree(node, letPrim);
-    push(letPrim);
-    return true;
-  }
-
-  void visitInvokeMethod(InvokeMethod node) {
-    if (constifyExpression(node)) return;
-    if (specializeOperatorCall(node)) return;
-    if (specializeFieldAccess(node)) return;
-    if (specializeIndexableAccess(node)) return;
-    if (specializeArrayAccess(node)) return;
-    if (specializeSingleUseClosureCall(node)) return;
-    if (specializeClosureCall(node)) return;
+  visitInvokeMethod(InvokeMethod node) {
+    var specialized =
+        specializeOperatorCall(node) ??
+        specializeFieldAccess(node) ??
+        specializeIndexableAccess(node) ??
+        specializeArrayAccess(node) ??
+        specializeSingleUseClosureCall(node) ??
+        specializeClosureCall(node);
+    if (specialized != null) return specialized;
 
     node.mask =
-      typeSystem.intersection(node.mask, getValue(getDartReceiver(node)).type);
+      typeSystem.intersection(node.mask, getValue(node.dartReceiver).type);
 
-    AbstractValue receiver = getValue(node.receiver.definition);
+    AbstractConstantValue receiver = getValue(node.receiver.definition);
 
-    if (node.receiverIsIntercepted &&
+    if (node.callingConvention == CallingConvention.Intercepted &&
         node.receiver.definition.sameValue(node.arguments[0].definition)) {
       // The receiver and first argument are the same; that means we already
       // determined in visitInterceptor that we are targeting a non-interceptor.
@@ -1802,81 +1845,48 @@
         // Replace the extra receiver argument with a dummy value if the
         // target definitely does not use it.
         Constant dummy = makeConstantPrimitive(new IntConstantValue(0));
-        insertLetPrim(node, dummy);
+        new LetPrim(dummy).insertAbove(node.parent);
         node.arguments[0].changeTo(dummy);
-        node.receiverIsIntercepted = false;
+        node.callingConvention = CallingConvention.DummyIntercepted;
       }
     }
   }
 
-  void visitTypeCast(TypeCast node) {
-    Continuation cont = node.continuation.definition;
-
-    AbstractValue value = getValue(node.value.definition);
+  CpsFragment visitTypeCast(TypeCast node) {
+    AbstractConstantValue value = getValue(node.value.definition);
     switch (lattice.isSubtypeOf(value, node.dartType, allowNull: true)) {
       case AbstractBool.Maybe:
       case AbstractBool.Nothing:
-        break;
+        return null;
 
       case AbstractBool.True:
-        // Cast always succeeds, replace it with InvokeContinuation.
-        InvokeContinuation invoke =
-            new InvokeContinuation(cont, <Primitive>[node.value.definition]);
-        replaceSubtree(node, invoke);
-        push(invoke);
-        return;
+        // Return an unused primitive moved again.
+        node.replaceUsesWith(node.value.definition);
+        return new CpsFragment(); // Remove the node.
 
       case AbstractBool.False:
-        // Cast always fails, remove unreachable continuation body.
-        replaceSubtree(cont.body, new Unreachable());
-        break;
+        // Note: The surrounding LetPrim will remove the following code because
+        // it always throws. We don't need to do it here.
+        return null;
     }
   }
 
   /// Specialize calls to internal static methods.
-  ///
-  /// Returns true if the call was replaced.
-  bool specializeInternalMethodCall(InvokeStatic node) {
-    // TODO(asgerf): This is written to easily scale to more cases,
-    //               either add more cases or clean up.
-    Continuation cont = node.continuation.definition;
-    Primitive arg(int n) => node.arguments[n].definition;
-    AbstractValue argType(int n) => getValue(arg(n));
-
-    bool replaceWithBinary(BuiltinOperator operator,
-                           Primitive left,
-                           Primitive right) {
-      Primitive prim =
-          new ApplyBuiltinOperator(operator, <Primitive>[left, right],
-                                   node.sourceInformation);
-      LetPrim let = makeLetPrimInvoke(prim, cont);
-      replaceSubtree(node, let);
-      push(let);
-      return true; // So returning early is more convenient.
-    }
-
-    if (node.target.library.isInternalLibrary) {
-      switch(node.target.name) {
-        case InternalMethod.Stringify:
-          if (lattice.isDefinitelyString(argType(0))) {
-            InvokeContinuation invoke =
-                new InvokeContinuation(cont, <Primitive>[arg(0)]);
-            replaceSubtree(node, invoke);
-            push(invoke);
-            return true;
-          }
-          break;
+  specializeInternalMethodCall(InvokeStatic node) {
+    if (node.target == backend.helpers.stringInterpolationHelper) {
+      AbstractConstantValue value = getValue(node.arguments[0].definition);
+      if (lattice.isDefinitelyString(value)) {
+        node.replaceUsesWith(node.arguments[0].definition);
+        return new CpsFragment();
       }
-    } else if (node.target.library.isDartCore) {
-      switch(node.target.name) {
-        case CorelibMethod.Identical:
-          if (node.arguments.length == 2) {
-            return replaceWithBinary(BuiltinOperator.Identical, arg(0), arg(1));
-          }
-          break;
+    } else if (node.target == compiler.identicalFunction) {
+      if (node.arguments.length == 2) {
+        return new ApplyBuiltinOperator(BuiltinOperator.Identical,
+            [node.arguments[0].definition, node.arguments[1].definition],
+            node.sourceInformation);
       }
     }
-    return false;
+    return null;
   }
 
   /// Try to inline static invocations.
@@ -1886,13 +1896,13 @@
   ///
   /// * Inline functions with a single expression statement or return statement
   /// provided that the subexpression is an invocation of foreign code.
-  bool inlineInvokeStatic(InvokeStatic node) {
+  inlineInvokeStatic(InvokeStatic node) {
     // The target might not have an AST, for example if it deferred.
-    if (!node.target.hasNode) return false;
+    if (!node.target.hasNode) return null;
 
     if (node.target.asyncMarker != AsyncMarker.SYNC) {
       // Inlining of async/sync*/async* methods is currently not supported.
-      return false;
+      return null;
     }
 
     // True if an expression is non-expansive, in the sense defined by this
@@ -1952,46 +1962,48 @@
       return false;
     }
 
-    if (!shouldInline()) return false;
+    if (!shouldInline()) return null;
 
     FunctionDefinition target = functionCompiler.compileToCpsIr(node.target);
-    for (int i = 0; i < node.arguments.length; ++i) {
-      node.arguments[i].definition.substituteFor(target.parameters[i]);
-    }
-    node.continuation.definition.substituteFor(target.returnContinuation);
 
-    replaceSubtree(node, target.body);
-    push(target.body);
-    return true;
+    CpsFragment cps = new CpsFragment(node.sourceInformation);
+    Primitive result = cps.inlineFunction(target,
+        null,
+        node.arguments.map((ref) => ref.definition).toList(),
+        hint: node.hint);
+    node.replaceUsesWith(result);
+    return cps;
   }
 
-  void visitInvokeStatic(InvokeStatic node) {
-    if (constifyExpression(node)) return;
-    if (specializeInternalMethodCall(node)) return;
-    if (inlineInvokeStatic(node)) return;
+  visitInvokeStatic(InvokeStatic node) {
+    return specializeInternalMethodCall(node) ?? inlineInvokeStatic(node);
   }
 
-  AbstractValue getValue(Variable node) {
+  AbstractConstantValue getValue(Variable node) {
+    assert(node.type != null);
     ConstantValue constant = values[node];
     if (constant != null) {
-      return new AbstractValue.constantValue(constant, node.type);
+      return new AbstractConstantValue.constantValue(constant, node.type);
     }
-    if (node.type != null) {
-      return new AbstractValue.nonConstant(node.type);
-    }
-    return lattice.nothing;
+    return new AbstractConstantValue.nonConstant(node.type);
   }
 
 
   /*************************** PRIMITIVES **************************/
   //
-  // The visit method for a primitive may optionally return a new
-  // primitive. If non-null, the surrounding LetPrim will substitute it
-  // and bind the new primitive instead.
+  // The visit method for a primitive may return one of the following:
+  // - Primitive:
+  //     The visited primitive will be replaced by the returned primitive.
+  //     The type of the primitive will be recomputed.
+  // - CpsFragment:
+  //     The primitive binding will be destroyed and replaced by the given
+  //     code fragment.  All types in the fragment will be recomputed.
+  // - Null:
+  //     Nothing happens. The primitive remains as it is.
   //
 
   void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
-    ast.DartString getString(AbstractValue value) {
+    ast.DartString getString(AbstractConstantValue value) {
       StringConstantValue constant = value.constant;
       return constant.primitiveValue;
     }
@@ -2002,9 +2014,11 @@
         int i = 0;
         while (i < node.arguments.length - 1) {
           int startOfSequence = i;
-          AbstractValue firstValue = getValue(node.arguments[i++].definition);
+          AbstractConstantValue firstValue =
+              getValue(node.arguments[i++].definition);
           if (!firstValue.isConstant) continue;
-          AbstractValue secondValue = getValue(node.arguments[i++].definition);
+          AbstractConstantValue secondValue =
+              getValue(node.arguments[i++].definition);
           if (!secondValue.isConstant) continue;
 
           ast.DartString string =
@@ -2014,14 +2028,15 @@
           // We found a sequence of at least two constants.
           // Look for the end of the sequence.
           while (i < node.arguments.length) {
-            AbstractValue value = getValue(node.arguments[i].definition);
+            AbstractConstantValue value =
+                getValue(node.arguments[i].definition);
             if (!value.isConstant) break;
             string = new ast.ConsDartString(string, getString(value));
             ++i;
           }
           Constant prim =
               makeConstantPrimitive(new StringConstantValue(string));
-          insertLetPrim(node.parent, prim);
+          new LetPrim(prim).insertAbove(node.parent);
           for (int k = startOfSequence; k < i; ++k) {
             node.arguments[k].unlink();
             node.arguments[k] = null; // Remove the argument after the loop.
@@ -2040,19 +2055,19 @@
       case BuiltinOperator.Identical:
         Primitive leftArg = node.arguments[0].definition;
         Primitive rightArg = node.arguments[1].definition;
-        AbstractValue left = getValue(leftArg);
-        AbstractValue right = getValue(rightArg);
+        AbstractConstantValue left = getValue(leftArg);
+        AbstractConstantValue right = getValue(rightArg);
         if (lattice.isDefinitelyBool(left) &&
             right.isConstant &&
             right.constant.isTrue) {
           // Replace identical(x, true) by x when x is known to be a boolean.
           // Note that this is not safe if x is null, because the value might
-          // not be used as a condition. A rule for [IsTrue] handles that case.
-          leftArg.substituteFor(node);
+          // not be used as a condition.
+          node.replaceUsesWith(leftArg);
         } else if (lattice.isDefinitelyBool(right) &&
             left.isConstant &&
             left.constant.isTrue) {
-          rightArg.substituteFor(node);
+          node.replaceUsesWith(rightArg);
         } else if (left.isNullConstant || right.isNullConstant) {
           // Use `==` for comparing against null, so JS undefined and JS null
           // are considered equal.
@@ -2081,52 +2096,21 @@
   }
 
   void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
-    if (node.method == BuiltinMethod.Push) {
-      // Convert consecutive pushes into a single push.
-      InteriorNode parent = getEffectiveParent(node.parent);
-      if (parent is LetPrim && parent.primitive is ApplyBuiltinMethod) {
-        ApplyBuiltinMethod previous = parent.primitive;
-        if (previous.method == BuiltinMethod.Push &&
-            previous.receiver.definition.sameValue(node.receiver.definition)) {
-          // We found two consecutive pushes.
-          // Move all arguments from the first push onto the second one.
-          List<Reference<Primitive>> arguments = previous.arguments;
-          for (Reference ref in arguments) {
-            ref.parent = node;
-          }
-          arguments.addAll(node.arguments);
-          node.arguments = arguments;
-          // Elimnate the old push.
-          previous.receiver.unlink();
-          assert(previous.hasNoUses);
-          parent.parent.body = parent.body;
-          parent.body.parent = parent.parent;
-        }
-      }
-    }
   }
 
-  Primitive visitTypeTest(TypeTest node) {
+  visitTypeTest(TypeTest node) {
     Primitive prim = node.value.definition;
 
     Primitive unaryBuiltinOperator(BuiltinOperator operator) =>
         new ApplyBuiltinOperator(
             operator, <Primitive>[prim], node.sourceInformation);
 
-    void unlinkInterceptor() {
-      if (node.interceptor != null) {
-        node.interceptor.unlink();
-        node.interceptor = null;
-      }
-    }
-
-    AbstractValue value = getValue(prim);
+    AbstractConstantValue value = getValue(prim);
     types.DartType dartType = node.dartType;
 
     if (!(dartType.isInterfaceType && dartType.isRaw)) {
       // TODO(23685): Efficient function arity check.
       // TODO(sra): Pass interceptor to runtime subtype functions.
-      unlinkInterceptor();
       return null;
     }
 
@@ -2168,7 +2152,7 @@
       // This has lower priority than the 'typeof'-based tests because
       // 'typeof' expressions might give the VM some more useful information.
       Primitive nullConst = makeConstantPrimitive(new NullConstantValue());
-      insertLetPrim(node.parent, nullConst);
+      new LetPrim(nullConst).insertAbove(node.parent);
       return new ApplyBuiltinOperator(
           BuiltinOperator.LooseNeq,
           <Primitive>[prim, nullConst],
@@ -2198,14 +2182,19 @@
     if (dartType == dartTypes.coreTypes.stringType ||
         dartType == dartTypes.coreTypes.boolType) {
       // These types are recognized in tree_ir TypeOperator codegen.
-      unlinkInterceptor();
       return null;
     }
 
-    // TODO(sra): Propagate sourceInformation.
     // TODO(sra): If getInterceptor(x) === x or JSNull, rewrite
     //     getInterceptor(x).$isFoo ---> x != null && x.$isFoo
-    return new TypeTestViaFlag(node.interceptor.definition, dartType);
+    CpsFragment cps = new CpsFragment(node.sourceInformation);
+    Interceptor interceptor =
+        cps.letPrim(new Interceptor(prim, node.sourceInformation));
+    interceptor.interceptedClasses.addAll(backend.interceptedClasses);
+    Primitive testViaFlag =
+        cps.letPrim(new TypeTestViaFlag(interceptor, dartType));
+    node.replaceUsesWith(testViaFlag);
+    return cps;
   }
 
   Primitive visitTypeTestViaFlag(TypeTestViaFlag node) {
@@ -2213,7 +2202,7 @@
   }
 
   Primitive visitInterceptor(Interceptor node) {
-    AbstractValue value = getValue(node.input.definition);
+    AbstractConstantValue value = getValue(node.input.definition);
     TypeMask interceptedInputs = value.type.intersection(
         typeSystem.interceptorType.nullable(), classWorld);
     bool interceptNull =
@@ -2230,6 +2219,11 @@
         node.interceptedClasses..clear()..add(helpers.jsNumberClass);
         return;
       }
+
+      // TODO(asgerf): Avoid adding non-instantiated intercepted classes
+      // in the first place.  (This should also happen in later pass).
+      node.interceptedClasses.retainWhere(classWorld.isInstantiated);
+
       TypeMask interceptedClassesType = new TypeMask.unionOf(
           node.interceptedClasses.map(typeSystem.getInterceptorSubtypes),
           classWorld);
@@ -2267,8 +2261,8 @@
       //
       // We only do this optimization if the resulting interceptor call is
       // sufficiently specialized to be worth it (#classes <= 2).
-      // TODO(asgerf): Reconsider when TypeTest interceptors don't intercept
-      //               ALL interceptor classes.
+      // TODO(asgerf): Reconsider when TypeTestViaFlag interceptors don't
+      //               intercept ALL interceptor classes.
       if (node.interceptedClasses.length > 1 &&
           node.interceptedClasses.length < 4 &&
           node.interceptedClasses.contains(helpers.jsInterceptorClass)) {
@@ -2290,7 +2284,7 @@
 
     // Remove the interceptor call if it can only return its input.
     if (node.interceptedClasses.isEmpty) {
-      node.input.definition.substituteFor(node);
+      node.replaceUsesWith(node.input.definition);
       return null;
     }
 
@@ -2398,11 +2392,13 @@
 
   World get classWorld => typeSystem.classWorld;
 
-  AbstractValue get nothing => lattice.nothing;
+  AbstractConstantValue get nothing => lattice.nothing;
 
-  AbstractValue nonConstant([TypeMask type]) => lattice.nonConstant(type);
+  AbstractConstantValue nonConstant([TypeMask type]) {
+    return lattice.nonConstant(type);
+  }
 
-  AbstractValue constantValue(ConstantValue constant, [TypeMask type]) {
+  AbstractConstantValue constantValue(ConstantValue constant, [TypeMask type]) {
     return lattice.constant(constant, type);
   }
 
@@ -2410,13 +2406,8 @@
   // Access through [getValue] and [setValue].
   final Map<Variable, ConstantValue> values;
 
-  /// Expressions that invoke their call continuation with a constant value
-  /// and without any side effects. These can be replaced by the constant.
-  final Map<Expression, ConstantValue> replacements;
-
   TypePropagationVisitor(this.lattice,
                          this.values,
-                         this.replacements,
                          this.internalError);
 
   void analyze(FunctionDefinition root) {
@@ -2472,13 +2463,13 @@
   /// Returns the lattice value corresponding to [node], defaulting to nothing.
   ///
   /// Never returns null.
-  AbstractValue getValue(Variable node) {
+  AbstractConstantValue getValue(Variable node) {
     ConstantValue constant = values[node];
     if (constant != null) {
-      return new AbstractValue.constantValue(constant, node.type);
+      return new AbstractConstantValue.constantValue(constant, node.type);
     }
     if (node.type != null) {
-      return new AbstractValue.nonConstant(node.type);
+      return new AbstractConstantValue.nonConstant(node.type);
     }
     return lattice.nothing;
   }
@@ -2486,9 +2477,9 @@
   /// Joins the passed lattice [updateValue] to the current value of [node],
   /// and adds it to the definition work set if it has changed and [node] is
   /// a definition.
-  void setValue(Variable node, AbstractValue updateValue) {
-    AbstractValue oldValue = getValue(node);
-    AbstractValue newValue = lattice.join(oldValue, updateValue);
+  void setValue(Variable node, AbstractConstantValue updateValue) {
+    AbstractConstantValue oldValue = getValue(node);
+    AbstractConstantValue newValue = lattice.join(oldValue, updateValue);
     node.type = newValue.type; // Ensure type is initialized even if bottom.
     if (oldValue == newValue) {
       return;
@@ -2501,44 +2492,22 @@
     defWorklist.add(node);
   }
 
-  /// Updates the value of a [CallExpression]'s continuation parameter.
-  void setResult(CallExpression call,
-                 AbstractValue updateValue,
+  /// Sets the type of the given primitive.
+  ///
+  /// If [updateValue] is a constant and [canReplace] is true, the primitive
+  /// is also marked as safe for elimination, so it can be constant-folded.
+  void setResult(UnsafePrimitive prim,
+                 AbstractConstantValue updateValue,
                  {bool canReplace: false}) {
-    Continuation cont = call.continuation.definition;
-    setValue(cont.parameters.single, updateValue);
-    if (!updateValue.isNothing) {
-      setReachable(cont);
-
-      if (updateValue.isConstant && canReplace) {
-        replacements[call] = updateValue.constant;
-      } else {
-        // A replacement might have been set in a previous iteration.
-        replacements.remove(call);
-      }
-    }
+    // TODO(asgerf): Separate constant folding from side effect analysis.
+    setValue(prim, updateValue);
+    prim.isSafeForElimination = canReplace && updateValue.isConstant;
   }
 
   bool isInterceptedSelector(Selector selector) {
     return backend.isInterceptedSelector(selector);
   }
 
-  Primitive getDartReceiver(InvokeMethod node) {
-    if (node.receiverIsIntercepted) {
-      return node.arguments[0].definition;
-    } else {
-      return node.receiver.definition;
-    }
-  }
-
-  Primitive getDartArgument(InvokeMethod node, int n) {
-    if (isInterceptedSelector(node.selector)) {
-      return node.arguments[n+1].definition;
-    } else {
-      return node.arguments[n].definition;
-    }
-  }
-
   // -------------------------- Visitor overrides ------------------------------
   void visit(Node node) { node.accept(this); }
 
@@ -2559,14 +2528,20 @@
       setValue(node.thisParameter,
                nonConstant(typeSystem.getReceiverType(node.element)));
     }
+    bool hasParameterWithoutValue = false;
     for (Parameter param in node.parameters.skip(firstActualParameter)) {
       // TODO(karlklose): remove reference to the element model.
       TypeMask type = param.hint is ParameterElement
           ? typeSystem.getParameterType(param.hint)
           : typeSystem.dynamicType;
       setValue(param, lattice.fromMask(type));
+      if (type.isEmpty && !type.isNullable) {
+        hasParameterWithoutValue = true;
+      }
     }
-    push(node.body);
+    if (!hasParameterWithoutValue) { // Don't analyze unreachable code.
+      push(node.body);
+    }
   }
 
   void visitLetPrim(LetPrim node) {
@@ -2601,13 +2576,10 @@
   }
 
   void visitInvokeStatic(InvokeStatic node) {
-    if (node.target.library != null && node.target.library.isInternalLibrary) {
-      switch (node.target.name) {
-        case InternalMethod.Stringify:
-          AbstractValue argValue = getValue(node.arguments[0].definition);
-          setResult(node, lattice.stringify(argValue), canReplace: true);
-          return;
-      }
+    if (node.target == backend.helpers.stringInterpolationHelper) {
+      AbstractConstantValue argValue = getValue(node.arguments[0].definition);
+      setResult(node, lattice.stringify(argValue), canReplace: true);
+      return;
     }
 
     TypeMask returnType = typeSystem.getReturnType(node.target);
@@ -2622,41 +2594,59 @@
     // continuation. Note that this is effectively a phi node in SSA terms.
     for (int i = 0; i < node.arguments.length; i++) {
       Primitive def = node.arguments[i].definition;
-      AbstractValue cell = getValue(def);
+      AbstractConstantValue cell = getValue(def);
       setValue(cont.parameters[i], cell);
     }
   }
 
   void visitInvokeMethod(InvokeMethod node) {
-    AbstractValue receiver = getValue(node.receiver.definition);
+    AbstractConstantValue receiver = getValue(node.receiver.definition);
     node.receiverIsNotNull = receiver.isDefinitelyNotNull;
     if (receiver.isNothing) {
+      setResult(node, lattice.nothing);
       return;  // And come back later.
     }
 
-    // Constant fold known length of containers.
-    if (node.selector == Selectors.length) {
-      AbstractValue object = getValue(getDartReceiver(node));
-      if (typeSystem.isDefinitelyIndexable(object.type, allowNull: true)) {
-        int length = typeSystem.getContainerLength(object.type.nonNullable());
-        if (length != null) {
-          setResult(node, constantValue(new IntConstantValue(length)),
-              canReplace: !object.isNullable);
+    if (node.selector.isGetter) {
+      // Constant fold known length of containers.
+      if (node.selector == Selectors.length) {
+        AbstractConstantValue object = getValue(node.dartReceiver);
+        if (typeSystem.isDefinitelyIndexable(object.type, allowNull: true)) {
+          AbstractConstantValue length = lattice.lengthSpecial(object);
+          if (length != null) {
+            setResult(node, length, canReplace: !object.isNullable);
+          }
         }
       }
+      setResult(node, lattice.getInvokeReturnType(node.selector, node.mask));
+      return;
+    }
+
+    if (node.selector.isCall) {
+      AbstractConstantValue result;
+      if (node.selector == Selectors.codeUnitAt) {
+        AbstractConstantValue object = getValue(node.dartReceiver);
+        AbstractConstantValue right = getValue(node.dartArgument(0));
+        result = lattice.codeUnitAtSpecial(object, right);
+      }
+      if (result == null) {
+        setResult(node, lattice.getInvokeReturnType(node.selector, node.mask));
+      } else {
+        setResult(node, result, canReplace: true);
+      }
+      return;
     }
 
     if (!node.selector.isOperator) {
-      // TODO(jgruber): Handle known methods on constants such as String.length.
       setResult(node, lattice.getInvokeReturnType(node.selector, node.mask));
       return;
     }
 
     // Calculate the resulting constant if possible.
-    AbstractValue result;
+    AbstractConstantValue result;
     String opname = node.selector.name;
     if (node.arguments.length == 1) {
-      AbstractValue argument = getValue(getDartReceiver(node));
+      AbstractConstantValue argument = getValue(node.dartReceiver);
       // Unary operator.
       if (opname == "unary-") {
         opname = "-";
@@ -2665,8 +2655,8 @@
       result = lattice.unaryOp(operator, argument);
     } else if (node.arguments.length == 2) {
       // Binary operator.
-      AbstractValue left = getValue(getDartReceiver(node));
-      AbstractValue right = getValue(getDartArgument(node, 0));
+      AbstractConstantValue left = getValue(node.dartReceiver);
+      AbstractConstantValue right = getValue(node.dartArgument(0));
       BinaryOperator operator = BinaryOperator.parse(opname);
       result = lattice.binaryOp(operator, left, right);
     }
@@ -2682,32 +2672,37 @@
 
   void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
 
-    void unaryOp(AbstractValue operation(AbstractValue argument),
-                 TypeMask defaultType) {
-      AbstractValue value = getValue(node.arguments[0].definition);
+    void unaryOp(
+        AbstractConstantValue operation(AbstractConstantValue argument),
+        TypeMask defaultType) {
+      AbstractConstantValue value = getValue(node.arguments[0].definition);
       setValue(node, operation(value) ?? nonConstant(defaultType));
     }
 
     void binaryOp(
-        AbstractValue operation(AbstractValue left, AbstractValue right),
+        AbstractConstantValue operation(AbstractConstantValue left,
+                                        AbstractConstantValue right),
         TypeMask defaultType) {
-      AbstractValue left = getValue(node.arguments[0].definition);
-      AbstractValue right = getValue(node.arguments[1].definition);
+      AbstractConstantValue left = getValue(node.arguments[0].definition);
+      AbstractConstantValue right = getValue(node.arguments[1].definition);
       setValue(node, operation(left, right) ?? nonConstant(defaultType));
     }
 
     void binaryNumOp(
-        AbstractValue operation(AbstractValue left, AbstractValue right)) {
+        AbstractConstantValue operation(AbstractConstantValue left,
+                                        AbstractConstantValue right)) {
       binaryOp(operation, typeSystem.numType);
     }
 
     void binaryUint32Op(
-        AbstractValue operation(AbstractValue left, AbstractValue right)) {
+        AbstractConstantValue operation(AbstractConstantValue left,
+                                        AbstractConstantValue right)) {
       binaryOp(operation, typeSystem.uint32Type);
     }
 
     void binaryBoolOp(
-        AbstractValue operation(AbstractValue left, AbstractValue right)) {
+        AbstractConstantValue operation(AbstractConstantValue left,
+                                        AbstractConstantValue right)) {
       binaryOp(operation, typeSystem.boolType);
     }
 
@@ -2715,8 +2710,9 @@
       case BuiltinOperator.StringConcatenate:
         ast.DartString stringValue = const ast.LiteralDartString('');
         for (Reference<Primitive> arg in node.arguments) {
-          AbstractValue value = getValue(arg.definition);
+          AbstractConstantValue value = getValue(arg.definition);
           if (value.isNothing) {
+            setValue(node, lattice.nothing);
             return; // And come back later
           } else if (value.isConstant &&
                      value.constant.isString &&
@@ -2736,16 +2732,22 @@
         }
         break;
 
+      case BuiltinOperator.CharCodeAt:
+        binaryOp(lattice.codeUnitAtSpecial, typeSystem.uint31Type);
+        break;
+
       case BuiltinOperator.Identical:
       case BuiltinOperator.StrictEq:
       case BuiltinOperator.LooseEq:
-        AbstractValue leftConst = getValue(node.arguments[0].definition);
-        AbstractValue rightConst = getValue(node.arguments[1].definition);
+        AbstractConstantValue leftConst =
+            getValue(node.arguments[0].definition);
+        AbstractConstantValue rightConst =
+            getValue(node.arguments[1].definition);
         ConstantValue leftValue = leftConst.constant;
         ConstantValue rightValue = rightConst.constant;
         if (leftConst.isNothing || rightConst.isNothing) {
-          // Come back later.
-          return;
+          setValue(node, lattice.nothing);
+          return; // And come back later.
         } else if (!leftConst.isConstant || !rightConst.isConstant) {
           TypeMask leftType = leftConst.type;
           TypeMask rightType = rightConst.type;
@@ -2857,7 +2859,7 @@
   }
 
   void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
-    AbstractValue receiver = getValue(node.receiver.definition);
+    AbstractConstantValue receiver = getValue(node.receiver.definition);
     if (node.method == BuiltinMethod.Pop) {
       setValue(node, nonConstant(
           typeSystem.elementTypeOfIndexable(receiver.type)));
@@ -2889,7 +2891,7 @@
   }
 
   void visitBranch(Branch node) {
-    AbstractValue conditionCell = getValue(node.condition.definition);
+    AbstractConstantValue conditionCell = getValue(node.condition.definition);
     AbstractBool boolifiedValue = node.isStrictCheck
         ? lattice.strictBoolify(conditionCell)
         : lattice.boolify(conditionCell);
@@ -2922,7 +2924,7 @@
   }
 
   void handleTypeTest(
-      Primitive node, AbstractValue input, types.DartType dartType) {
+      Primitive node, AbstractConstantValue input, types.DartType dartType) {
     TypeMask boolType = typeSystem.boolType;
     switch(lattice.isSubtypeOf(input, dartType, allowNull: false)) {
       case AbstractBool.Nothing:
@@ -2943,27 +2945,26 @@
   }
 
   void visitTypeCast(TypeCast node) {
-    Continuation cont = node.continuation.definition;
-    AbstractValue input = getValue(node.value.definition);
+    AbstractConstantValue input = getValue(node.value.definition);
     switch (lattice.isSubtypeOf(input, node.dartType, allowNull: true)) {
       case AbstractBool.Nothing:
+        setValue(node, lattice.nothing);
         break; // And come back later.
 
       case AbstractBool.True:
-        setReachable(cont);
-        setValue(cont.parameters.single, input);
+        setValue(node, input);
         break;
 
       case AbstractBool.False:
-        break; // Cast fails. Continuation should remain unreachable.
+        setValue(node, lattice.nothing); // Cast fails.
+        break;
 
       case AbstractBool.Maybe:
-        setReachable(cont);
         // Narrow type of output to those that survive the cast.
         TypeMask type = input.type.intersection(
             typeSystem.subtypesOf(node.dartType).nullable(),
             classWorld);
-        setValue(cont.parameters.single, nonConstant(type));
+        setValue(node, nonConstant(type));
         break;
     }
   }
@@ -2996,10 +2997,6 @@
     }
   }
 
-  void visitCreateFunction(CreateFunction node) {
-    throw 'CreateFunction is not used';
-  }
-
   void visitGetMutable(GetMutable node) {
     setValue(node, getValue(node.variable.definition));
   }
@@ -3034,7 +3031,7 @@
 
   void visitInterceptor(Interceptor node) {
     push(node.input.definition);
-    AbstractValue value = getValue(node.input.definition);
+    AbstractConstantValue value = getValue(node.input.definition);
     if (value.isNothing) {
       setValue(node, nothing);
     } else if (value.isNullable &&
@@ -3050,8 +3047,13 @@
   }
 
   void visitGetField(GetField node) {
-    node.objectIsNotNull = getValue(node.object.definition).isDefinitelyNotNull;
-    setValue(node, lattice.fromMask(typeSystem.getFieldType(node.field)));
+    AbstractConstantValue object = getValue(node.object.definition);
+    if (object.isNothing || object.isNullConstant) {
+      setValue(node, nothing);
+    } else {
+      node.objectIsNotNull = object.isDefinitelyNotNull;
+      setValue(node, lattice.fromMask(typeSystem.getFieldType(node.field)));
+    }
   }
 
   void visitSetField(SetField node) {}
@@ -3061,7 +3063,8 @@
   }
 
   void visitCreateInstance(CreateInstance node) {
-    setValue(node, nonConstant(typeSystem.nonNullExact(node.classElement.declaration)));
+    setValue(node,
+        nonConstant(typeSystem.nonNullExact(node.classElement.declaration)));
   }
 
   void visitReifyRuntimeType(ReifyRuntimeType node) {
@@ -3088,20 +3091,18 @@
 
   @override
   void visitForeignCode(ForeignCode node) {
-    if (node.continuation != null) {
-      setResult(node, nonConstant(node.type));
-    }
+    setValue(node, nonConstant(node.type));
   }
 
   @override
   void visitGetLength(GetLength node) {
-    AbstractValue input = getValue(node.object.definition);
-    node.objectIsNotNull = getValue(node.object.definition).isDefinitelyNotNull;
-    int length = typeSystem.getContainerLength(input.type);
+    AbstractConstantValue input = getValue(node.object.definition);
+    node.objectIsNotNull = input.isDefinitelyNotNull;
+    AbstractConstantValue length = lattice.lengthSpecial(input);
     if (length != null) {
       // TODO(asgerf): Constant-folding the length might degrade the VM's
       // own bounds-check elimination?
-      setValue(node, constantValue(new IntConstantValue(length)));
+      setValue(node, length);
     } else {
       setValue(node, nonConstant(typeSystem.uint32Type));
     }
@@ -3109,14 +3110,17 @@
 
   @override
   void visitGetIndex(GetIndex node) {
-    AbstractValue input = getValue(node.object.definition);
-    setValue(node, nonConstant(typeSystem.elementTypeOfIndexable(input.type)));
+    AbstractConstantValue object = getValue(node.object.definition);
+    if (object.isNothing || object.isNullConstant) {
+      setValue(node, nothing);
+    } else {
+      node.objectIsNotNull = object.isDefinitelyNotNull;
+      setValue(node, nonConstant(typeSystem.elementTypeOfIndexable(object.type)));
+    }
   }
 
   @override
-  void visitSetIndex(SetIndex node) {
-    setValue(node, nonConstant());
-  }
+  void visitSetIndex(SetIndex node) {}
 
   @override
   void visitAwait(Await node) {
@@ -3125,12 +3129,12 @@
 
   @override
   visitYield(Yield node) {
-    setReachable(node.continuation.definition);
+    setValue(node, nonConstant());
   }
 
   @override
   void visitRefinement(Refinement node) {
-    AbstractValue value = getValue(node.value.definition);
+    AbstractConstantValue value = getValue(node.value.definition);
     if (value.isNothing ||
         typeSystem.areDisjoint(value.type, node.refineType)) {
       setValue(node, nothing);
@@ -3152,7 +3156,7 @@
 ///   CONSTANT: is a constant. The value is stored in the [constant] field,
 ///             and the type of the constant is in the [type] field.
 ///   NONCONST: not a constant, but [type] may hold some information.
-class AbstractValue {
+class AbstractConstantValue {
   static const int NOTHING  = 0;
   static const int CONSTANT = 1;
   static const int NONCONST = 2;
@@ -3161,25 +3165,26 @@
   final ConstantValue constant;
   final TypeMask type;
 
-  AbstractValue._internal(this.kind, this.constant, this.type) {
+  AbstractConstantValue._internal(this.kind, this.constant, this.type) {
     assert(kind != CONSTANT || constant != null);
     assert(constant is! SyntheticConstantValue);
   }
 
-  AbstractValue.nothing()
+  AbstractConstantValue.nothing()
       : this._internal(NOTHING, null, new TypeMask.nonNullEmpty());
 
-  AbstractValue.constantValue(ConstantValue constant, TypeMask type)
+  AbstractConstantValue.constantValue(ConstantValue constant, TypeMask type)
       : this._internal(CONSTANT, constant, type);
 
-  factory AbstractValue.nonConstant(TypeMask type) {
+  factory AbstractConstantValue.nonConstant(TypeMask type) {
     if (type.isEmpty) {
       if (type.isNullable)
-        return new AbstractValue.constantValue(new NullConstantValue(), type);
+        return new AbstractConstantValue.constantValue(
+            new NullConstantValue(), type);
       else
-        return new AbstractValue.nothing();
+        return new AbstractConstantValue.nothing();
     } else {
-      return new AbstractValue._internal(NONCONST, null, type);
+      return new AbstractConstantValue._internal(NONCONST, null, type);
     }
   }
 
@@ -3198,7 +3203,7 @@
     return hash & 0x3fffffff;
   }
 
-  bool operator ==(AbstractValue that) {
+  bool operator ==(AbstractConstantValue that) {
     return that.kind == this.kind &&
            that.constant == this.constant &&
            that.type == this.type;
@@ -3215,16 +3220,6 @@
   }
 }
 
-/// Enum-like class with the names of internal methods we care about.
-abstract class InternalMethod {
-  static const String Stringify = 'S';
-}
-
-/// Enum-like class with the names of dart:core methods we care about.
-abstract class CorelibMethod {
-  static const String Identical = 'identical';
-}
-
 /// Suggested name for a synthesized loop index.
 class LoopIndexEntity extends Entity {
   String get name => 'i';
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index fa7aeb7..662316b 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -119,6 +119,7 @@
   bool dumpInfo = false;
   bool allowNativeExtensions = false;
   bool trustTypeAnnotations = false;
+  bool trustJSInteropTypeAnnotations = false;
   bool checkedMode = false;
   // List of provided options that imply that output is expected.
   List<String> optionsImplyCompilation = <String>[];
@@ -227,6 +228,11 @@
     implyCompilation(argument);
   }
 
+  setTrustJSInteropTypeAnnotations(String argument) {
+    trustJSInteropTypeAnnotations = true;
+    implyCompilation(argument);
+  }
+
   setTrustPrimitives(String argument) {
     implyCompilation(argument);
   }
@@ -326,6 +332,9 @@
     new OptionHandler(Flags.trustPrimitives,
                       (_) => setTrustPrimitives(
                           Flags.trustPrimitives)),
+    new OptionHandler(Flags.trustJSInteropTypeAnnotations,
+                      (_) => setTrustJSInteropTypeAnnotations(
+                          Flags.trustJSInteropTypeAnnotations)),
     new OptionHandler(r'--help|/\?|/h', (_) => wantHelp = true),
     new OptionHandler('--packages=.+', setPackageConfig),
     new OptionHandler('--package-root=.+|-p.+', setPackageRoot),
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 78c0a37..c24ecbf 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -28,6 +28,7 @@
     FunctionElement,
     ImportElement,
     LibraryElement,
+    LocalFunctionElement,
     MetadataAnnotation,
     PrefixElement,
     ScopeContainerElement,
@@ -48,11 +49,14 @@
     NewExpression,
     Node;
 import 'universe/use.dart' show
+    DynamicUse,
     StaticUse,
     TypeUse,
     TypeUseKind;
 import 'universe/world_impact.dart' show
-    WorldImpact;
+    ImpactUseCase,
+    WorldImpact,
+    WorldImpactVisitorImpl;
 import 'util/setlet.dart' show
     Setlet;
 import 'util/uri_extras.dart' as uri_extras;
@@ -122,6 +126,8 @@
   /// Will be `true` if the program contains deferred libraries.
   bool isProgramSplit = false;
 
+  static const ImpactUseCase IMPACT_USE = const ImpactUseCase('Deferred load');
+
   /// A mapping from the name of a defer import to all the output units it
   /// depends on in a list of lists to be loaded in the order they appear.
   ///
@@ -318,30 +324,35 @@
 
         WorldImpact worldImpact =
             compiler.resolution.getWorldImpact(analyzableElement);
-        worldImpact.staticUses.forEach((StaticUse staticUse) {
-          elements.add(staticUse.element);
-        });
-        for (TypeUse typeUse in worldImpact.typeUses) {
-          DartType type = typeUse.type;
-          switch (typeUse.kind) {
-            case TypeUseKind.TYPE_LITERAL:
-              if (type.isTypedef || type.isInterfaceType) {
-                elements.add(type.element);
-              }
-              break;
-            case TypeUseKind.INSTANTIATION:
-            case TypeUseKind.IS_CHECK:
-            case TypeUseKind.AS_CAST:
-            case TypeUseKind.CATCH_TYPE:
-              collectTypeDependencies(type);
-              break;
-            case TypeUseKind.CHECKED_MODE_CHECK:
-              if (compiler.enableTypeAssertions) {
-                collectTypeDependencies(type);
-              }
-              break;
-          }
-        }
+        compiler.impactStrategy.visitImpact(
+            analyzableElement,
+            worldImpact,
+            new WorldImpactVisitorImpl(
+                visitStaticUse: (StaticUse staticUse) {
+                  elements.add(staticUse.element);
+                },
+                visitTypeUse: (TypeUse typeUse) {
+                  DartType type = typeUse.type;
+                  switch (typeUse.kind) {
+                    case TypeUseKind.TYPE_LITERAL:
+                      if (type.isTypedef || type.isInterfaceType) {
+                        elements.add(type.element);
+                      }
+                      break;
+                    case TypeUseKind.INSTANTIATION:
+                    case TypeUseKind.IS_CHECK:
+                    case TypeUseKind.AS_CAST:
+                    case TypeUseKind.CATCH_TYPE:
+                      collectTypeDependencies(type);
+                      break;
+                    case TypeUseKind.CHECKED_MODE_CHECK:
+                      if (compiler.enableTypeAssertions) {
+                        collectTypeDependencies(type);
+                      }
+                      break;
+                  }
+                }),
+             IMPACT_USE);
 
         TreeElements treeElements = analyzableElement.resolvedAst.elements;
         assert(treeElements != null);
@@ -711,6 +722,9 @@
       // Generate a unique name for each OutputUnit.
       _assignNamesToOutputUnits(allOutputUnits);
     });
+    // Notify the impact strategy impacts are no longer needed for deferred
+    // load.
+    compiler.impactStrategy.onImpactUsed(IMPACT_USE);
   }
 
   void beforeResolution(Compiler compiler) {
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 09ab8e5..207954d 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -4,25 +4,41 @@
 
 library dump_info;
 
-import 'dart:convert'
-    show HtmlEscape, JsonEncoder, StringConversionSink, ChunkedConversionSink;
+import 'dart:convert' show
+    ChunkedConversionSink,
+    HtmlEscape,
+    JsonEncoder,
+    StringConversionSink;
 
 import 'package:dart2js_info/info.dart';
 
 import 'common.dart';
-import 'common/tasks.dart' show CompilerTask;
-import 'constants/values.dart' show ConstantValue, InterceptorConstantValue;
-import 'compiler.dart' show Compiler;
+import 'common/tasks.dart' show
+    CompilerTask;
+import 'constants/values.dart' show
+    ConstantValue,
+    InterceptorConstantValue;
+import 'compiler.dart' show
+    Compiler;
+import 'deferred_load.dart' show
+    OutputUnit;
 import 'elements/elements.dart';
 import 'elements/visitor.dart';
-import 'types/types.dart' show TypeMask;
-import 'deferred_load.dart' show OutputUnit;
-import 'js_backend/js_backend.dart' show JavaScriptBackend;
-import 'js_emitter/full_emitter/emitter.dart' as full show Emitter;
+import 'info/send_info.dart' show
+    collectSendMeasurements;
+import 'js_backend/js_backend.dart' show
+    JavaScriptBackend;
+import 'js_emitter/full_emitter/emitter.dart' as full show
+    Emitter;
 import 'js/js.dart' as jsAst;
-import 'universe/universe.dart' show ReceiverConstraint;
-import 'universe/world_impact.dart' show WorldImpact;
-import 'info/send_info.dart' show collectSendMeasurements;
+import 'types/types.dart' show
+    TypeMask;
+import 'universe/universe.dart' show
+    ReceiverConstraint;
+import 'universe/world_impact.dart' show
+    ImpactUseCase,
+    WorldImpact,
+    WorldImpactVisitorImpl;
 
 class ElementInfoCollector extends BaseElementVisitor<Info, dynamic> {
   final Compiler compiler;
@@ -366,6 +382,8 @@
 }
 
 class DumpInfoTask extends CompilerTask implements InfoReporter {
+  static const ImpactUseCase IMPACT_USE = const ImpactUseCase('Dump info');
+
   DumpInfoTask(Compiler compiler) : super(compiler);
 
   String get name => "Dump Info";
@@ -418,23 +436,34 @@
     }
   }
 
+  void unregisterImpact(Element element) {
+    impacts.remove(element);
+  }
+
   /**
    * Returns an iterable of [Selection]s that are used by
    * [element].  Each [Selection] contains an element that is
    * used and the selector that selected the element.
    */
   Iterable<Selection> getRetaining(Element element) {
-    var impact = impacts[element];
+    WorldImpact impact = impacts[element];
     if (impact == null) return const <Selection>[];
 
     var selections = <Selection>[];
-    selections.addAll(impact.dynamicUses.expand((dynamicUse) {
-      return compiler.world.allFunctions
-          .filter(dynamicUse.selector, dynamicUse.mask)
-          .map((e) => new Selection(e, dynamicUse.mask));
-    }));
-    selections.addAll(impact.staticUses
-        .map((staticUse) => new Selection(staticUse.element, null)));
+    compiler.impactStrategy.visitImpact(
+        element,
+        impact,
+        new WorldImpactVisitorImpl(
+            visitDynamicUse: (dynamicUse) {
+              selections.addAll(compiler.world.allFunctions
+                        .filter(dynamicUse.selector, dynamicUse.mask)
+                        .map((e) => new Selection(e, dynamicUse.mask)));
+            },
+            visitStaticUse: (staticUse) {
+              selections.add(new Selection(staticUse.element, null));
+            }
+        ),
+        IMPACT_USE);
     return selections;
   }
 
@@ -535,6 +564,8 @@
         info.uses.add(new DependencyInfo(useInfo, '${selection.mask}'));
       }
     }
+    // Notify the impact strategy impacts are no longer needed for dump info.
+    compiler.impactStrategy.onImpactUsed(IMPACT_USE);
 
     // Track dependencies that come from inlining.
     for (Element element in inlineMap.keys) {
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index 53796dc..2c7403f 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -58,7 +58,9 @@
     TypeUse,
     TypeUseKind;
 import 'universe/world_impact.dart' show
-    WorldImpact;
+    ImpactUseCase,
+    WorldImpact,
+    WorldImpactVisitor;
 import 'util/util.dart' show
     Link,
     Setlet;
@@ -117,10 +119,14 @@
   bool hasEnqueuedReflectiveElements = false;
   bool hasEnqueuedReflectiveStaticFields = false;
 
+  WorldImpactVisitor impactVisitor;
+
   Enqueuer(this.name,
            this.compiler,
            this.itemCompilationContextCreator,
-           this.strategy);
+           this.strategy) {
+    impactVisitor = new _EnqueuerImpactVisitor(this);
+  }
 
   // TODO(johnniwinther): Move this to [ResolutionEnqueuer].
   Resolution get resolution => compiler.resolution;
@@ -142,6 +148,8 @@
 
   Iterable<ClassElement> get processedClasses => _processedClasses;
 
+  ImpactUseCase get impactUse;
+
   /**
    * Documentation wanted -- johnniwinther
    *
@@ -166,10 +174,8 @@
 
   /// Apply the [worldImpact] of processing [element] to this enqueuer.
   void applyImpact(Element element, WorldImpact worldImpact) {
-    // TODO(johnniwinther): Optimize the application of the world impact.
-    worldImpact.dynamicUses.forEach(registerDynamicUse);
-    worldImpact.staticUses.forEach(registerStaticUse);
-    worldImpact.typeUses.forEach(registerTypeUse);
+    compiler.impactStrategy.visitImpact(
+        element, worldImpact, impactVisitor, impactUse);
   }
 
   void registerInstantiatedType(InterfaceType type,
@@ -634,6 +640,7 @@
         // enqueue.
         addElement = false;
         break;
+      case StaticUseKind.SUPER_FIELD_SET:
       case StaticUseKind.SUPER_TEAR_OFF:
       case StaticUseKind.GENERAL:
         break;
@@ -741,6 +748,10 @@
    */
   final Queue<DeferredTask> deferredTaskQueue;
 
+  static const ImpactUseCase IMPACT_USE = const ImpactUseCase('ResolutionEnqueuer');
+
+  ImpactUseCase get impactUse => IMPACT_USE;
+
   ResolutionEnqueuer(Compiler compiler,
                      ItemCompilationContext itemCompilationContextCreator(),
                      EnqueuerStrategy strategy)
@@ -896,6 +907,10 @@
 
   bool enabledNoSuchMethod = false;
 
+  static const ImpactUseCase IMPACT_USE = const ImpactUseCase('CodegenEnqueuer');
+
+  ImpactUseCase get impactUse => IMPACT_USE;
+
   CodegenEnqueuer(Compiler compiler,
                   ItemCompilationContext itemCompilationContextCreator(),
                   EnqueuerStrategy strategy)
@@ -1039,3 +1054,24 @@
     enqueuer.handleUnseenSelectorInternal(dynamicUse);
   }
 }
+
+class _EnqueuerImpactVisitor implements WorldImpactVisitor {
+  final Enqueuer enqueuer;
+
+  _EnqueuerImpactVisitor(this.enqueuer);
+
+  @override
+  void visitDynamicUse(DynamicUse dynamicUse) {
+    enqueuer.registerDynamicUse(dynamicUse);
+  }
+
+  @override
+  void visitStaticUse(StaticUse staticUse) {
+    enqueuer.registerStaticUse(staticUse);
+  }
+
+  @override
+  void visitTypeUse(TypeUse typeUse) {
+    enqueuer.registerTypeUse(typeUse);
+  }
+}
diff --git a/pkg/compiler/lib/src/inferrer/closure_tracer.dart b/pkg/compiler/lib/src/inferrer/closure_tracer.dart
index aa78001..b7d1ef7 100644
--- a/pkg/compiler/lib/src/inferrer/closure_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/closure_tracer.dart
@@ -2,11 +2,20 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of type_graph_inferrer;
+library compiler.src.inferrer.closure_tracer;
+
+import '../types/types.dart' show TypeMask;
+import '../common/names.dart' show Names;
+import '../elements/elements.dart';
+import '../universe/selector.dart' show Selector;
+import 'node_tracer.dart';
+import 'type_graph_nodes.dart';
+import 'debug.dart' as debug;
+
 
 class ClosureTracerVisitor extends TracerVisitor<ApplyableTypeInformation> {
   final Iterable<FunctionElement> tracedElements;
-  final List<CallSiteTypeInformation> callsToAnalyze =
+  final List<CallSiteTypeInformation> _callsToAnalyze =
       new List<CallSiteTypeInformation>();
 
   ClosureTracerVisitor(this.tracedElements, tracedType, inferrer)
@@ -15,7 +24,7 @@
   void run() {
     analyze();
     if (!continueAnalyzing) return;
-    callsToAnalyze.forEach(analyzeCall);
+    _callsToAnalyze.forEach(_analyzeCall);
     for(FunctionElement e in tracedElements) {
       e.functionSignature.forEachParameter((Element parameter) {
         ElementTypeInformation info =
@@ -25,18 +34,18 @@
     }
   }
 
-  void tagAsFunctionApplyTarget([String reason]) {
+  void _tagAsFunctionApplyTarget([String reason]) {
     tracedType.mightBePassedToFunctionApply = true;
-    if (_VERBOSE) {
+    if (debug.VERBOSE) {
       print("Closure $tracedType might be passed to apply: $reason");
     }
   }
 
-  void registerCallForLaterAnalysis(CallSiteTypeInformation info) {
-    callsToAnalyze.add(info);
+  void _registerCallForLaterAnalysis(CallSiteTypeInformation info) {
+    _callsToAnalyze.add(info);
   }
 
-  void analyzeCall(CallSiteTypeInformation info) {
+  void _analyzeCall(CallSiteTypeInformation info) {
     Selector selector = info.selector;
     TypeMask mask = info.mask;
     tracedElements.forEach((FunctionElement functionElement) {
@@ -46,15 +55,17 @@
     });
   }
 
+  @override
   visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) {
     super.visitClosureCallSiteTypeInformation(info);
     if (info.closure == currentUser) {
-      registerCallForLaterAnalysis(info);
+      _registerCallForLaterAnalysis(info);
     } else {
       bailout('Passed to a closure');
     }
   }
 
+  @override
   visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
     super.visitStaticCallSiteTypeInformation(info);
     Element called = info.calledElement;
@@ -70,23 +81,22 @@
         && inferrer.types.getInferredTypeOf(called) == currentUser) {
       // This node can be a closure call as well. For example, `foo()`
       // where `foo` is a getter.
-      registerCallForLaterAnalysis(info);
+      _registerCallForLaterAnalysis(info);
     }
-    if (checkIfFunctionApply(called) &&
+    if (_checkIfFunctionApply(called) &&
         info.arguments != null &&
         info.arguments.contains(currentUser)) {
-      tagAsFunctionApplyTarget("static call");
+      _tagAsFunctionApplyTarget("static call");
     }
   }
 
-  bool checkIfCurrentUser(element) {
-    return inferrer.types.getInferredTypeOf(element) == currentUser;
-  }
+  bool _checkIfCurrentUser(element) =>
+      inferrer.types.getInferredTypeOf(element) == currentUser;
 
-  bool checkIfFunctionApply(element) {
-    return compiler.functionApplyMethod == element;
-  }
+  bool _checkIfFunctionApply(element) =>
+      compiler.functionApplyMethod == element;
 
+  @override
   visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) {
     super.visitDynamicCallSiteTypeInformation(info);
     if (info.selector.isCall) {
@@ -94,11 +104,11 @@
         if (!info.targets.every((element) => element.isFunction)) {
           bailout('Passed to a closure');
         }
-        if (info.targets.any(checkIfFunctionApply)) {
-          tagAsFunctionApplyTarget("dynamic call");
+        if (info.targets.any(_checkIfFunctionApply)) {
+          _tagAsFunctionApplyTarget("dynamic call");
         }
-      } else if (info.targets.any((element) => checkIfCurrentUser(element))) {
-        registerCallForLaterAnalysis(info);
+      } else if (info.targets.any((element) => _checkIfCurrentUser(element))) {
+        _registerCallForLaterAnalysis(info);
       }
     } else if (info.selector.isGetter &&
         info.selector.memberName == Names.call) {
@@ -112,6 +122,7 @@
   StaticTearOffClosureTracerVisitor(tracedElement, tracedType, inferrer)
       : super([tracedElement], tracedType, inferrer);
 
+  @override
   visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
     super.visitStaticCallSiteTypeInformation(info);
     if (info.calledElement == tracedElements.first
diff --git a/pkg/compiler/lib/src/inferrer/debug.dart b/pkg/compiler/lib/src/inferrer/debug.dart
new file mode 100644
index 0000000..502f966
--- /dev/null
+++ b/pkg/compiler/lib/src/inferrer/debug.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Values used only for debugging type inference.
+library compiler.src.inferrer.debug;
+
+bool VERBOSE = false;
+bool PRINT_SUMMARY = false;
+final ANOMALY_WARN = false;
+
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart b/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
index f9dc9eb..fbb7880 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
@@ -91,6 +91,11 @@
   T narrowType(T type, DartType annotation, {bool isNullable: true});
 
   /**
+   * Returns the non-nullable type [T].
+   */
+  T narrowNotNull(T type);
+
+  /**
    * Returns a new type that unions [firstInput] and [secondInput].
    */
   T allocateDiamondPhi(T firstInput, T secondInput);
@@ -469,9 +474,13 @@
 
       SendSet send = node != null ? node.asSendSet() : null;
       if (send != null && send.isIfNullAssignment && currentType != null) {
-        // If-null assignments may return either the new or the original value.
+        // If-null assignments may return either the new or the original value
+        // narrowed to non-null.
         type = types.addPhiInput(
-            local, types.allocatePhi(locals.block, local, currentType), type);
+            local,
+            types.allocatePhi(locals.block, local,
+                              types.narrowNotNull(currentType)),
+            type);
       }
       locals[local] = type;
       if (currentType != type) {
@@ -1124,7 +1133,7 @@
   T visitIfNull(Send node, Node left, Node right, _) {
     T firstType = visit(left);
     T secondType = visit(right);
-    return types.allocateDiamondPhi(firstType, secondType);
+    return types.allocateDiamondPhi(types.narrowNotNull(firstType), secondType);
   }
 
   @override
diff --git a/pkg/compiler/lib/src/inferrer/list_tracer.dart b/pkg/compiler/lib/src/inferrer/list_tracer.dart
index b3e8ab3..a57087f 100644
--- a/pkg/compiler/lib/src/inferrer/list_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/list_tracer.dart
@@ -2,7 +2,14 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of type_graph_inferrer;
+library compiler.src.inferrer.list_tracer;
+
+import '../elements/elements.dart';
+import '../universe/selector.dart' show Selector;
+import '../util/util.dart' show Setlet;
+
+import 'node_tracer.dart';
+import 'type_graph_nodes.dart';
 
 /**
  * A set of selector names that [List] implements, that we know do not
diff --git a/pkg/compiler/lib/src/inferrer/map_tracer.dart b/pkg/compiler/lib/src/inferrer/map_tracer.dart
index 94caa57..1ab3c24 100644
--- a/pkg/compiler/lib/src/inferrer/map_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/map_tracer.dart
@@ -2,7 +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.
 
-part of type_graph_inferrer;
+library compiler.src.inferrer.map_tracer;
+
+import '../elements/elements.dart';
+import '../universe/selector.dart' show Selector;
+
+import 'node_tracer.dart';
+import 'type_graph_nodes.dart';
 
 Set<String> okMapSelectorsSet = new Set.from(
     const <String>[
diff --git a/pkg/compiler/lib/src/inferrer/node_tracer.dart b/pkg/compiler/lib/src/inferrer/node_tracer.dart
index 371adb5..174ae56 100644
--- a/pkg/compiler/lib/src/inferrer/node_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/node_tracer.dart
@@ -2,7 +2,17 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of type_graph_inferrer;
+library compiler.src.inferrer.node_tracer;
+
+import '../common/names.dart' show Identifiers;
+import '../compiler.dart' show Compiler;
+import '../elements/elements.dart';
+import '../types/types.dart' show ContainerTypeMask, MapTypeMask;
+import '../util/util.dart' show Setlet;
+
+import 'type_graph_inferrer.dart' show TypeGraphInferrerEngine;
+import 'type_graph_nodes.dart';
+import 'debug.dart' as debug;
 
 // A set of selectors we know do not escape the elements inside the
 // list.
@@ -64,6 +74,7 @@
     'keys'
   ]);
 
+/// Common logic to trace a value through the type inference graph nodes.
 abstract class TracerVisitor<T extends TypeInformation>
     implements TypeInformationVisitor {
   final T tracedType;
@@ -136,7 +147,7 @@
   }
 
   void bailout(String reason) {
-    if (_VERBOSE) {
+    if (debug.VERBOSE) {
       print('Bailing out on $tracedType because: $reason');
     }
     continueAnalyzing = false;
@@ -202,7 +213,7 @@
         flow.users.forEach((user) {
           if (user is !DynamicCallSiteTypeInformation) return;
           if (user.receiver != flow) return;
-          if (inferrer._returnsListElementTypeSet.contains(user.selector)) {
+          if (inferrer.returnsListElementTypeSet.contains(user.selector)) {
             addNewEscapeInformation(user);
           } else if (!doesNotEscapeListSet.contains(user.selector.name)) {
             bailout('Escape from a list via [${user.selector.name}]');
diff --git a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
index 61f8595..f897876 100644
--- a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
@@ -52,151 +52,6 @@
 import 'inferrer_visitor.dart';
 
 /**
- * An implementation of [TypeSystem] for [TypeMask].
- */
-class TypeMaskSystem implements TypeSystem<TypeMask> {
-  final Compiler compiler;
-  final ClassWorld classWorld;
-  TypeMaskSystem(Compiler compiler)
-      : this.compiler = compiler,
-        this.classWorld = compiler.world;
-
-  TypeMask narrowType(TypeMask type,
-                      DartType annotation,
-                      {bool isNullable: true}) {
-    if (annotation.treatAsDynamic) return type;
-    if (annotation.isObject) return type;
-    TypeMask otherType;
-    if (annotation.isTypedef || annotation.isFunctionType) {
-      otherType = functionType;
-    } else if (annotation.isTypeVariable) {
-      // TODO(ngeoffray): Narrow to bound.
-      return type;
-    } else if (annotation.isVoid) {
-      otherType = nullType;
-    } else {
-      assert(annotation.isInterfaceType);
-      otherType = new TypeMask.nonNullSubtype(annotation.element, classWorld);
-    }
-    if (isNullable) otherType = otherType.nullable();
-    if (type == null) return otherType;
-    return type.intersection(otherType, classWorld);
-  }
-
-  TypeMask computeLUB(TypeMask firstType, TypeMask secondType) {
-    if (firstType == null) {
-      return secondType;
-    } else if (secondType == dynamicType || firstType == dynamicType) {
-      return dynamicType;
-    } else if (firstType == secondType) {
-      return firstType;
-    } else {
-      TypeMask union = firstType.union(secondType, classWorld);
-      // TODO(kasperl): If the union isn't nullable it seems wasteful
-      // to use dynamic. Fix that.
-      return union.containsAll(classWorld) ? dynamicType : union;
-    }
-  }
-
-  TypeMask allocateDiamondPhi(TypeMask firstType, TypeMask secondType) {
-    return computeLUB(firstType, secondType);
-  }
-
-  TypeMask get dynamicType => compiler.typesTask.dynamicType;
-  TypeMask get nullType => compiler.typesTask.nullType;
-  TypeMask get intType => compiler.typesTask.intType;
-  TypeMask get uint32Type => compiler.typesTask.uint32Type;
-  TypeMask get uint31Type => compiler.typesTask.uint31Type;
-  TypeMask get positiveIntType => compiler.typesTask.positiveIntType;
-  TypeMask get doubleType => compiler.typesTask.doubleType;
-  TypeMask get numType => compiler.typesTask.numType;
-  TypeMask get boolType => compiler.typesTask.boolType;
-  TypeMask get functionType => compiler.typesTask.functionType;
-  TypeMask get listType => compiler.typesTask.listType;
-  TypeMask get constListType => compiler.typesTask.constListType;
-  TypeMask get fixedListType => compiler.typesTask.fixedListType;
-  TypeMask get growableListType => compiler.typesTask.growableListType;
-  TypeMask get mapType => compiler.typesTask.mapType;
-  TypeMask get constMapType => compiler.typesTask.constMapType;
-  TypeMask get stringType => compiler.typesTask.stringType;
-  TypeMask get typeType => compiler.typesTask.typeType;
-  TypeMask get syncStarIterableType => compiler.typesTask.syncStarIterableType;
-  TypeMask get asyncFutureType => compiler.typesTask.asyncFutureType;
-  TypeMask get asyncStarStreamType => compiler.typesTask.asyncStarStreamType;
-  bool isNull(TypeMask mask) => mask.isEmpty && mask.isNullable;
-
-  TypeMask stringLiteralType(ast.DartString value) => stringType;
-  TypeMask boolLiteralType(ast.LiteralBool value) => boolType;
-
-  TypeMask nonNullSubtype(ClassElement type)
-      => new TypeMask.nonNullSubtype(type.declaration, classWorld);
-  TypeMask nonNullSubclass(ClassElement type)
-      => new TypeMask.nonNullSubclass(type.declaration, classWorld);
-  TypeMask nonNullExact(ClassElement type)
-      => new TypeMask.nonNullExact(type.declaration, classWorld);
-  TypeMask nonNullEmpty() => new TypeMask.nonNullEmpty();
-
-  TypeMask allocateList(TypeMask type,
-                        ast.Node node,
-                        Element enclosing,
-                        [TypeMask elementType, int length]) {
-    return new ContainerTypeMask(type, node, enclosing, elementType, length);
-  }
-
-  TypeMask allocateMap(TypeMask type, ast.Node node, Element element,
-                       [List<TypeMask> keys, List<TypeMask> values]) {
-    return type;
-  }
-
-  TypeMask allocateClosure(ast.Node node, Element element) {
-    return functionType;
-  }
-
-  TypeMask newTypedSelector(TypeMask receiver, TypeMask mask) {
-    return receiver;
-  }
-
-  TypeMask addPhiInput(Local variable,
-                       TypeMask phiType,
-                       TypeMask newType) {
-    return computeLUB(phiType, newType);
-  }
-
-  TypeMask allocatePhi(ast.Node node,
-                       Local variable,
-                       TypeMask inputType) {
-    return inputType;
-  }
-
-  TypeMask allocateLoopPhi(ast.Node node,
-                           Local variable,
-                           TypeMask inputType) {
-    return inputType;
-  }
-
-  TypeMask simplifyPhi(ast.Node node,
-                       Local variable,
-                       TypeMask phiType) {
-    return phiType;
-  }
-
-  bool selectorNeedsUpdate(TypeMask type, TypeMask mask) {
-    return type != mask;
-  }
-
-  TypeMask refineReceiver(Selector selector,
-                          TypeMask mask,
-                          TypeMask receiverType,
-                          bool isConditional) {
-    TypeMask newType =
-        compiler.world.allFunctions.receiverType(selector, mask);
-    return receiverType.intersection(newType, classWorld);
-  }
-
-  TypeMask getConcreteTypeFor(TypeMask mask) => mask;
-}
-
-/**
  * Common super class used by [SimpleTypeInferrerVisitor] to propagate
  * type information about visited nodes, as well as to request type
  * information of elements.
@@ -482,6 +337,15 @@
   }
 }
 
+/// [SimpleTypeInferrerVisitor] can be thought of as a type-inference graph
+/// builder for a single element.
+///
+/// Calling [run] will start the work of visiting the body of the code to
+/// construct a set of infernece-nodes that abstractly represent what the code
+/// is doing.
+///
+/// This visitor is parameterized by an [InferenceEngine], which internally
+/// decides how to represent inference nodes.
 class SimpleTypeInferrerVisitor<T>
     extends InferrerVisitor<T, InferrerEngine<T, TypeSystem<T>>> {
   T returnType;
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
index 4a03baf..a568066 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
@@ -4,9 +4,7 @@
 
 library type_graph_inferrer;
 
-import 'dart:collection' show
-    IterableBase,
-    Queue;
+import 'dart:collection' show Queue;
 
 import '../common.dart';
 import '../common/names.dart' show
@@ -15,8 +13,6 @@
 import '../compiler.dart' show
     Compiler;
 import '../constants/values.dart';
-import '../cps_ir/cps_ir_nodes.dart' as cps_ir show
-    Node;
 import '../dart_types.dart' show
     DartType,
     FunctionType,
@@ -26,7 +22,6 @@
 import '../js_backend/js_backend.dart' show
     Annotations,
     JavaScriptBackend;
-import '../native/native.dart' as native;
 import '../resolution/tree_elements.dart' show
     TreeElementMapping;
 import '../tree/tree.dart' as ast show
@@ -38,11 +33,9 @@
     TryStatement;
 import '../types/types.dart' show
     ContainerTypeMask,
-    DictionaryTypeMask,
     MapTypeMask,
     TypeMask,
-    TypesInferrer,
-    ValueTypeMask;
+    TypesInferrer;
 import '../types/constants.dart' show
     computeTypeMask;
 import '../universe/call_structure.dart' show
@@ -62,15 +55,12 @@
     TypeSystem;
 import 'simple_types_inferrer.dart';
 
-part 'closure_tracer.dart';
-part 'list_tracer.dart';
-part 'map_tracer.dart';
-part 'node_tracer.dart';
-part 'type_graph_nodes.dart';
+import 'closure_tracer.dart';
+import 'list_tracer.dart';
+import 'map_tracer.dart';
+import 'type_graph_nodes.dart';
+import 'debug.dart' as debug;
 
-bool _VERBOSE = false;
-bool _PRINT_SUMMARY = false;
-final _ANOMALY_WARN = false;
 
 class TypeInformationSystem extends TypeSystem<TypeInformation> {
   final Compiler compiler;
@@ -337,6 +327,16 @@
     }
   }
 
+  TypeInformation narrowNotNull(TypeInformation type) {
+    if (type.type.isExact && !type.type.isNullable) {
+      return type;
+    }
+    TypeInformation newType =
+        new NarrowTypeInformation(type, dynamicType.type.nonNullable());
+    allocatedTypes.add(newType);
+    return newType;
+  }
+
   ElementTypeInformation getInferredTypeOf(Element element) {
     element = element.implementation;
     return typeInformations.putIfAbsent(element, () {
@@ -612,7 +612,7 @@
    * A set of selector names that [List] implements, that we know return
    * their element type.
    */
-  final Set<Selector> _returnsListElementTypeSet = new Set<Selector>.from(
+  final Set<Selector> returnsListElementTypeSet = new Set<Selector>.from(
     <Selector>[
       new Selector.getter(const PublicName('first')),
       new Selector.getter(const PublicName('last')),
@@ -627,7 +627,7 @@
   bool returnsListElementType(Selector selector, TypeMask mask) {
     return mask != null &&
            mask.isContainer &&
-           _returnsListElementTypeSet.contains(selector);
+           returnsListElementTypeSet.contains(selector);
   }
 
   bool returnsMapValueType(Selector selector, TypeMask mask) {
@@ -723,7 +723,7 @@
         if (!tracer.continueAnalyzing) {
           elements.forEach((FunctionElement e) {
             compiler.world.registerMightBePassedToApply(e);
-            if (_VERBOSE) print("traced closure $e as ${true} (bail)");
+            if (debug.VERBOSE) print("traced closure $e as ${true} (bail)");
             e.functionSignature.forEachParameter((parameter) {
               types.getInferredTypeOf(parameter).giveUp(
                   this,
@@ -744,7 +744,7 @@
           if (tracer.tracedType.mightBePassedToFunctionApply) {
             compiler.world.registerMightBePassedToApply(e);
           };
-          if (_VERBOSE) {
+          if (debug.VERBOSE) {
             print("traced closure $e as "
                 "${compiler.world.getMightBePassedToApply(e)}");
           }
@@ -798,7 +798,7 @@
     workQueue.addAll(seenTypes);
     refine();
 
-    if (_PRINT_SUMMARY) {
+    if (debug.PRINT_SUMMARY) {
       types.allocatedLists.values.forEach((ListTypeInformation info) {
         print('${info.type} '
               'for ${info.originalType.allocationNode} '
@@ -946,7 +946,7 @@
         overallRefineCount++;
         info.refineCount++;
         if (info.refineCount > MAX_CHANGE_COUNT) {
-          if (_ANOMALY_WARN) {
+          if (debug.ANOMALY_WARN) {
             print("ANOMALY WARNING: max refinement reached for $info");
           }
           info.giveUp(this);
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index dd50651..cbc662c 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -2,7 +2,44 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of type_graph_inferrer;
+library compiler.src.inferrer.type_graph_nodes;
+
+import 'dart:collection' show IterableBase;
+
+import '../common.dart';
+import '../common/names.dart' show Identifiers;
+import '../compiler.dart' show Compiler;
+import '../constants/values.dart';
+import '../cps_ir/cps_ir_nodes.dart' as cps_ir show Node;
+import '../dart_types.dart' show
+    DartType,
+    FunctionType,
+    InterfaceType,
+    TypeKind;
+import '../elements/elements.dart';
+import '../native/native.dart' as native;
+import '../tree/tree.dart' as ast show
+    DartString,
+    Node,
+    LiteralBool,
+    Send,
+    SendSet,
+    TryStatement;
+import '../types/types.dart' show
+    ContainerTypeMask,
+    DictionaryTypeMask,
+    MapTypeMask,
+    TypeMask,
+    ValueTypeMask;
+import '../universe/selector.dart' show Selector;
+import '../util/util.dart' show ImmutableEmptySet, Setlet;
+import '../world.dart' show ClassWorld;
+
+import 'inferrer_visitor.dart' show ArgumentsTypes;
+import 'type_graph_inferrer.dart' show
+    TypeGraphInferrerEngine,
+    TypeInformationSystem;
+import 'debug.dart' as debug;
 
 /**
  * Common class for all nodes in the graph. The current nodes are:
@@ -455,14 +492,14 @@
       return mask;
     }
     if (element.isField) {
-      return new TypeMaskSystem(compiler).narrowType(mask, element.type);
+      return _narrowType(compiler, mask, element.type);
     }
     assert(element.isFunction ||
            element.isGetter ||
            element.isFactoryConstructor);
 
     FunctionType type = element.type;
-    return new TypeMaskSystem(compiler).narrowType(mask, type.returnType);
+    return _narrowType(compiler, mask, type.returnType);
   }
 
   TypeMask computeType(TypeGraphInferrerEngine inferrer) {
@@ -594,7 +631,7 @@
     // ignore type annotations to ensure that the checks are actually inserted
     // into the function body and retained until runtime.
     assert(!compiler.enableTypeAssertions);
-    return new TypeMaskSystem(compiler).narrowType(mask, element.type);
+    return _narrowType(compiler, mask, element.type);
   }
 
   TypeMask computeType(TypeGraphInferrerEngine inferrer) {
@@ -935,7 +972,7 @@
           ValueTypeMask arg = arguments.positional[0].type;
           String key = arg.value.primitiveValue.slowToString();
           if (dictionaryTypeMask.typeMap.containsKey(key)) {
-            if (_VERBOSE) {
+            if (debug.VERBOSE) {
               print("Dictionary lookup for $key yields "
                     "${dictionaryTypeMask.typeMap[key]}.");
             }
@@ -943,14 +980,14 @@
           } else {
             // The typeMap is precise, so if we do not find the key, the lookup
             // will be [null] at runtime.
-            if (_VERBOSE) {
+            if (debug.VERBOSE) {
               print("Dictionary lookup for $key yields [null].");
             }
             return inferrer.types.nullType.type;
           }
         }
         MapTypeMask mapTypeMask = typeMask;
-        if (_VERBOSE) {
+        if (debug.VERBOSE) {
           print(
               "Map lookup for $selector yields ${mapTypeMask.valueType}.");
         }
@@ -1180,7 +1217,7 @@
     TypeMask input = assignments.first.type;
     TypeMask intersection = input.intersection(typeAnnotation,
         inferrer.classWorld);
-    if (_ANOMALY_WARN) {
+    if (debug.ANOMALY_WARN) {
       if (!input.containsMask(intersection, inferrer.classWorld) ||
           !typeAnnotation.containsMask(intersection, inferrer.classWorld)) {
         print("ANOMALY WARNING: narrowed $input to $intersection via "
@@ -1611,3 +1648,24 @@
   T visitClosureTypeInformation(ClosureTypeInformation info);
   T visitAwaitTypeInformation(AwaitTypeInformation info);
 }
+
+TypeMask _narrowType(Compiler compiler, TypeMask type, DartType annotation,
+    {bool isNullable: true}) {
+  if (annotation.treatAsDynamic) return type;
+  if (annotation.isObject) return type;
+  TypeMask otherType;
+  if (annotation.isTypedef || annotation.isFunctionType) {
+    otherType = compiler.typesTask.functionType;
+  } else if (annotation.isTypeVariable) {
+    // TODO(ngeoffray): Narrow to bound.
+    return type;
+  } else if (annotation.isVoid) {
+    otherType = compiler.typesTask.nullType;
+  } else {
+    assert(annotation.isInterfaceType);
+    otherType = new TypeMask.nonNullSubtype(annotation.element, compiler.world);
+  }
+  if (isNullable) otherType = otherType.nullable();
+  if (type == null) return otherType;
+  return type.intersection(otherType, compiler.world);
+}
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 0fed323..5bd42a1 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -581,6 +581,52 @@
         new Namer(compiler);
   }
 
+  /// The backend must *always* call this method when enqueuing an
+  /// element. Calls done by the backend are not seen by global
+  /// optimizations, so they would make these optimizations unsound.
+  /// Therefore we need to collect the list of helpers the backend may
+  /// use.
+  // TODO(johnniwinther): Replace this with a more precise modelling; type
+  // inference of these elements is disabled.
+  Element registerBackendUse(Element element) {
+    if (element != null) {
+      bool registerUse = false;
+      if (element == helpers.streamIteratorConstructor ||
+          element == helpers.compiler.symbolConstructor ||
+          element == helpers.compiler.symbolValidatedConstructor ||
+          element == helpers.syncCompleterConstructor ||
+          element == coreClasses.symbolClass ||
+          element == helpers.objectNoSuchMethod) {
+        // TODO(johnniwinther): These are valid but we could be more precise.
+        registerUse = true;
+      } else if (element.implementationLibrary.isPatch ||
+                 element.library == helpers.jsHelperLibrary ||
+                 element.library == helpers.interceptorsLibrary ||
+                 element.library == helpers.isolateHelperLibrary) {
+        // TODO(johnniwinther): We should be more precise about these.
+        registerUse = true;
+      } else if (element == coreClasses.listClass ||
+                 element == helpers.mapLiteralClass ||
+                 element == coreClasses.functionClass ||
+                 element == coreClasses.stringClass) {
+        // TODO(johnniwinther): Avoid these.
+        registerUse = true;
+      }
+      if (!registerUse) {
+        assert(invariant(element, false,
+            message: "Backend use of $element is not allowed."));
+        return element;
+      }
+      helpersUsed.add(element.declaration);
+      if (element.isClass && element.isPatched) {
+        // Both declaration and implementation may declare fields, so we
+        // add both to the list of helpers.
+        helpersUsed.add(element.implementation);
+      }
+    }
+    return element;
+  }
+
   bool usedByBackend(Element element) {
     if (element.isParameter
         || element.isInitializingFormal
@@ -1479,23 +1525,6 @@
            compiler.enabledRuntimeType;
   }
 
-  /// The backend must *always* call this method when enqueuing an
-  /// element. Calls done by the backend are not seen by global
-  /// optimizations, so they would make these optimizations unsound.
-  /// Therefore we need to collect the list of helpers the backend may
-  /// use.
-  Element registerBackendUse(Element element) {
-    if (element != null) {
-      helpersUsed.add(element.declaration);
-      if (element.isClass && element.isPatched) {
-        // Both declaration and implementation may declare fields, so we
-        // add both to the list of helpers.
-        helpersUsed.add(element.implementation);
-      }
-    }
-    return element;
-  }
-
   /// Enqueue [e] in [enqueuer].
   ///
   /// This method calls [registerBackendUse].
@@ -1602,7 +1631,10 @@
     }
 
     generatedCode[element] = functionCompiler.compile(work);
-    return impactTransformer.transformCodegenImpact(work.registry.worldImpact);
+    WorldImpact worldImpact =
+        impactTransformer.transformCodegenImpact(work.registry.worldImpact);
+    compiler.dumpInfoTask.registerImpact(element, worldImpact);
+    return worldImpact;
   }
 
   native.NativeEnqueuer nativeResolutionEnqueuer(Enqueuer world) {
@@ -2611,6 +2643,17 @@
     if (patchLocation == null) return null;
     return platformConfigUri.resolve(patchLocation);
   }
+
+  @override
+  ImpactStrategy createImpactStrategy(
+      {bool supportDeferredLoad: true,
+       bool supportDumpInfo: true}) {
+    return new JavaScriptImpactStrategy(
+        resolution,
+        compiler.dumpInfoTask,
+        supportDeferredLoad: supportDeferredLoad,
+        supportDumpInfo: supportDumpInfo);
+  }
 }
 
 /// Handling of special annotations for tests.
@@ -3079,3 +3122,46 @@
 
   const Dependency(this.constant, this.annotatedElement);
 }
+
+class JavaScriptImpactStrategy extends ImpactStrategy {
+  final Resolution resolution;
+  final DumpInfoTask dumpInfoTask;
+  final bool supportDeferredLoad;
+  final bool supportDumpInfo;
+
+  JavaScriptImpactStrategy(this.resolution,
+                           this.dumpInfoTask,
+                           {this.supportDeferredLoad,
+                            this.supportDumpInfo});
+
+  @override
+  void visitImpact(Element element,
+                   WorldImpact impact,
+                   WorldImpactVisitor visitor,
+                   ImpactUseCase impactUse) {
+    // TODO(johnniwinther): Compute the application strategy once for each use.
+    if (impactUse == ResolutionEnqueuer.IMPACT_USE) {
+      if (supportDeferredLoad) {
+        impact.apply(visitor);
+      } else {
+        impact.apply(visitor);
+        resolution.uncacheWorldImpact(element);
+      }
+    } else if (impactUse == DeferredLoadTask.IMPACT_USE) {
+      impact.apply(visitor);
+      // Impacts are uncached globally in [onImpactUsed].
+    } else if (impactUse == DumpInfoTask.IMPACT_USE) {
+      impact.apply(visitor);
+      dumpInfoTask.unregisterImpact(element);
+    } else {
+      impact.apply(visitor);
+    }
+  }
+
+  @override
+  void onImpactUsed(ImpactUseCase impactUse) {
+    if (impactUse == DeferredLoadTask.IMPACT_USE) {
+      resolution.emptyCache();
+    }
+  }
+}
diff --git a/pkg/compiler/lib/src/js_backend/backend_helpers.dart b/pkg/compiler/lib/src/js_backend/backend_helpers.dart
index d0b2750..f0a92d7 100644
--- a/pkg/compiler/lib/src/js_backend/backend_helpers.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_helpers.dart
@@ -6,6 +6,7 @@
 
 import '../common.dart';
 import '../common/names.dart' show
+    Identifiers,
     Uris;
 import '../common/resolution.dart' show
     Resolution;
@@ -679,4 +680,18 @@
   Element get convertRtiToRuntimeType {
     return findHelper('convertRtiToRuntimeType');
   }
+
+  ClassElement get stackTraceClass {
+    return findHelper('_StackTrace');
+  }
+
+  MethodElement _objectNoSuchMethod;
+
+  MethodElement get objectNoSuchMethod {
+    if (_objectNoSuchMethod == null) {
+      _objectNoSuchMethod =
+          coreClasses.objectClass.lookupLocalMember(Identifiers.noSuchMethod_);
+    }
+    return _objectNoSuchMethod;
+  }
 }
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index 3320c2f..f25e13b 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -68,8 +68,8 @@
             helpers.getRuntimeTypeInfo,
             helpers.computeSignature,
             helpers.getRuntimeTypeArguments],
-          instantiatedClasses: [
-            coreClasses.listClass]);
+          otherImpacts: [
+            listValues]);
     }
     return _computeSignature;
   }
@@ -187,6 +187,74 @@
     return _throwNoSuchMethod;
   }
 
+  BackendImpact _stringValues;
+
+  BackendImpact get stringValues {
+    if (_stringValues == null) {
+      _stringValues = new BackendImpact(
+          instantiatedClasses: [
+            helpers.jsStringClass]);
+    }
+    return _stringValues;
+  }
+
+  BackendImpact _numValues;
+
+  BackendImpact get numValues {
+    if (_numValues == null) {
+      _numValues = new BackendImpact(
+          instantiatedClasses: [
+            helpers.jsIntClass,
+            helpers.jsPositiveIntClass,
+            helpers.jsUInt32Class,
+            helpers.jsUInt31Class,
+            helpers.jsNumberClass,
+            helpers.jsDoubleClass]);
+    }
+    return _numValues;
+  }
+
+  BackendImpact get intValues => numValues;
+
+  BackendImpact get doubleValues => numValues;
+
+  BackendImpact _boolValues;
+
+  BackendImpact get boolValues {
+    if (_boolValues == null) {
+      _boolValues = new BackendImpact(
+          instantiatedClasses: [
+            helpers.jsBoolClass]);
+    }
+    return _boolValues;
+  }
+
+  BackendImpact _nullValue;
+
+  BackendImpact get nullValue {
+    if (_nullValue == null) {
+      _nullValue = new BackendImpact(
+          instantiatedClasses: [
+            helpers.jsNullClass]);
+    }
+    return _nullValue;
+  }
+
+  BackendImpact _listValues;
+
+  BackendImpact get listValues {
+    if (_listValues == null) {
+      _listValues = new BackendImpact(
+          instantiatedClasses: [
+            helpers.jsArrayClass,
+            helpers.jsMutableArrayClass,
+            helpers.jsFixedArrayClass,
+            helpers.jsExtendableArrayClass,
+            helpers.jsUnmodifiableArrayClass]);
+    }
+    return _listValues;
+  }
+
   BackendImpact _throwRuntimeError;
 
   BackendImpact get throwRuntimeError {
@@ -194,9 +262,9 @@
       _throwRuntimeError = new BackendImpact(
           staticUses: [
             helpers.throwRuntimeError],
-          // Also register the types of the arguments passed to this method.
-          instantiatedClasses: [
-            coreClasses.stringClass]);
+          otherImpacts: [
+            // Also register the types of the arguments passed to this method.
+            stringValues]);
     }
     return _throwRuntimeError;
   }
@@ -208,8 +276,7 @@
       _superNoSuchMethod = new BackendImpact(
           staticUses: [
             helpers.createInvocationMirror,
-            coreClasses.objectClass.lookupLocalMember(
-                Identifiers.noSuchMethod_)],
+            helpers.objectNoSuchMethod],
           otherImpacts: [
             _needsInt(
                 'Needed to encode the invocation kind of super.noSuchMethod.'),
@@ -277,23 +344,19 @@
   /// Helper for registering that `int` is needed.
   BackendImpact _needsInt(String reason) {
     // TODO(johnniwinther): Register [reason] for use in dump-info.
-    return new BackendImpact(
-        instantiatedClasses: [coreClasses.intClass]);
+    return intValues;
   }
 
   /// Helper for registering that `List` is needed.
   BackendImpact _needsList(String reason) {
     // TODO(johnniwinther): Register [reason] for use in dump-info.
-    return new BackendImpact(
-        instantiatedClasses: [coreClasses.listClass]);
+    return listValues;
   }
 
   /// Helper for registering that `String` is needed.
   BackendImpact _needsString(String reason) {
     // TODO(johnniwinther): Register [reason] for use in dump-info.
-    return new BackendImpact(
-        instantiatedClasses: [
-          coreClasses.stringClass]);
+    return stringValues;
   }
 
   BackendImpact _assertWithoutMessage;
@@ -352,62 +415,15 @@
     return _stringJuxtaposition;
   }
 
-  // TODO(johnniwinther): Point to to the JavaScript classes instead of the Dart
-  // classes in these impacts.
-  BackendImpact _nullLiteral;
+  BackendImpact get nullLiteral => nullValue;
 
-  BackendImpact get nullLiteral {
-    if (_nullLiteral == null) {
-      _nullLiteral = new BackendImpact(
-          instantiatedClasses: [
-            coreClasses.nullClass]);
-    }
-    return _nullLiteral;
-  }
+  BackendImpact get boolLiteral => boolValues;
 
-  BackendImpact _boolLiteral;
+  BackendImpact get intLiteral => intValues;
 
-  BackendImpact get boolLiteral {
-    if (_boolLiteral == null) {
-      _boolLiteral = new BackendImpact(
-          instantiatedClasses: [
-            coreClasses.boolClass]);
-    }
-    return _boolLiteral;
-  }
+  BackendImpact get doubleLiteral => doubleValues;
 
-  BackendImpact _intLiteral;
-
-  BackendImpact get intLiteral {
-    if (_intLiteral == null) {
-      _intLiteral = new BackendImpact(
-          instantiatedClasses: [
-            coreClasses.intClass]);
-    }
-    return _intLiteral;
-  }
-
-  BackendImpact _doubleLiteral;
-
-  BackendImpact get doubleLiteral {
-    if (_doubleLiteral == null) {
-      _doubleLiteral = new BackendImpact(
-          instantiatedClasses: [
-            coreClasses.doubleClass]);
-    }
-    return _doubleLiteral;
-  }
-
-  BackendImpact _stringLiteral;
-
-  BackendImpact get stringLiteral {
-    if (_stringLiteral == null) {
-      _stringLiteral = new BackendImpact(
-          instantiatedClasses: [
-            coreClasses.stringClass]);
-    }
-    return _stringLiteral;
-  }
+  BackendImpact get stringLiteral => stringValues;
 
   BackendImpact _catchStatement;
 
@@ -468,7 +484,7 @@
     if (_stackTraceInCatch == null) {
       _stackTraceInCatch = new BackendImpact(
           instantiatedClasses: [
-            coreClasses.stackTraceClass],
+            helpers.stackTraceClass],
           staticUses: [
             helpers.traceFromException]);
     }
@@ -498,9 +514,8 @@
             helpers.getRuntimeTypeInfo,
             helpers.runtimeTypeToString,
             helpers.createRuntimeType],
-          instantiatedClasses: [
-            coreClasses.listClass],
           otherImpacts: [
+            listValues,
             getRuntimeTypeArgument,
             _needsInt('Needed for accessing a type variable literal on this.')
           ]);
@@ -513,8 +528,8 @@
   BackendImpact get typeCheck {
     if (_typeCheck == null) {
       _typeCheck = new BackendImpact(
-          instantiatedClasses: [
-            coreClasses.boolClass]);
+          otherImpacts: [
+            boolValues]);
     }
     return _typeCheck;
   }
@@ -551,9 +566,8 @@
             // TODO(johnniwinther): Investigate why this is needed.
             helpers.setRuntimeTypeInfo,
             helpers.getRuntimeTypeInfo],
-          instantiatedClasses: [
-            coreClasses.listClass],
           otherImpacts: [
+            listValues,
             getRuntimeTypeArgument]);
     }
     return _genericTypeCheck;
@@ -564,8 +578,8 @@
   BackendImpact get genericIsCheck {
     if (_genericIsCheck == null) {
       _genericIsCheck = new BackendImpact(
-          instantiatedClasses: [
-            coreClasses.listClass]);
+          otherImpacts: [
+            intValues]);
     }
     return _genericIsCheck;
   }
diff --git a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
index bcf0968..8bb26fd 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
@@ -68,6 +68,18 @@
   final tree_ir.FallthroughStack shortContinue =
       new tree_ir.FallthroughStack();
 
+  /// When the top element is true, [Unreachable] statements will be emitted
+  /// as [Return]s, otherwise they are emitted as empty because they are
+  /// followed by the end of the method.
+  ///
+  /// Note on why the [fallthrough] stack should not be used for this:
+  /// Ordinary statements may choose whether to use the [fallthrough] target,
+  /// and the choice to do so may disable an optimization in [visitIf].
+  /// But omitting an unreachable 'return' should have lower priority than
+  /// the optimizations in [visitIf], so [visitIf] will instead tell the
+  /// [Unreachable] statements whether they may use fallthrough or not.
+  List<bool> emitUnreachableAsReturn = <bool>[false];
+
   Set<tree_ir.Label> usedLabels = new Set<tree_ir.Label>();
 
   List<js.Statement> accumulator = new List<js.Statement>();
@@ -272,6 +284,7 @@
   void registerMethodInvoke(tree_ir.InvokeMethod node) {
     Selector selector = node.selector;
     TypeMask mask = node.mask;
+    mask = glue.extendMaskIfReachesAll(selector, mask);
     if (selector.isGetter) {
       registry.registerDynamicUse(new DynamicUse(selector, mask));
     } else if (selector.isSetter) {
@@ -533,16 +546,34 @@
 
   @override
   void visitExpressionStatement(tree_ir.ExpressionStatement node) {
-    accumulator.add(new js.ExpressionStatement(
-        visitExpression(node.expression)));
-    visitStatement(node.next);
+    js.Expression exp = visitExpression(node.expression);
+    if (node.next is tree_ir.Unreachable && emitUnreachableAsReturn.last) {
+      // Emit as 'return exp' to assist local analysis in the VM.
+      accumulator.add(new js.Return(exp));
+    } else {
+      accumulator.add(new js.ExpressionStatement(exp));
+      visitStatement(node.next);
+    }
+  }
+
+  bool isNullReturn(tree_ir.Statement node) {
+    return node is tree_ir.Return && isNull(node.value);
+  }
+
+  bool isEndOfMethod(tree_ir.Statement node) {
+    return isNullReturn(node) ||
+           node is tree_ir.Break && isNullReturn(node.target.binding.next);
   }
 
   @override
   void visitIf(tree_ir.If node) {
     js.Expression condition = visitExpression(node.condition);
     int usesBefore = fallthrough.useCount;
+    // Unless the 'else' part ends the method. make sure to terminate any
+    // uncompletable code paths in the 'then' part.
+    emitUnreachableAsReturn.add(!isEndOfMethod(node.elseStatement));
     js.Statement thenBody = buildBodyStatement(node.thenStatement);
+    emitUnreachableAsReturn.removeLast();
     bool thenHasFallthrough = (fallthrough.useCount > usesBefore);
     if (thenHasFallthrough) {
       js.Statement elseBody = buildBodyStatement(node.elseStatement);
@@ -613,7 +644,9 @@
     shortBreak.push(node.next);
     shortContinue.push(node);
     fallthrough.push(node);
+    emitUnreachableAsReturn.add(true);
     js.Statement body = buildBodyStatement(node.body);
+    emitUnreachableAsReturn.removeLast();
     fallthrough.pop();
     shortContinue.pop();
     shortBreak.pop();
@@ -643,7 +676,9 @@
     shortBreak.push(fallthrough.target);
     shortContinue.push(node);
     fallthrough.push(node);
+    emitUnreachableAsReturn.add(true);
     js.Statement jsBody = buildBodyStatement(node.body);
+    emitUnreachableAsReturn.removeLast();
     fallthrough.pop();
     shortContinue.pop();
     if (shortBreak.useCount > 0) {
@@ -682,8 +717,10 @@
 
   @override
   void visitUnreachable(tree_ir.Unreachable node) {
-    // Output nothing.
-    // TODO(asgerf): Emit a throw/return to assist local analysis in the VM?
+    if (emitUnreachableAsReturn.last) {
+      // Emit a return to assist local analysis in the VM.
+      accumulator.add(new js.Return());
+    }
   }
 
   @override
@@ -949,6 +986,8 @@
       case BuiltinOperator.StringConcatenate:
         if (args.isEmpty) return js.string('');
         return args.reduce((e1,e2) => new js.Binary('+', e1, e2));
+      case BuiltinOperator.CharCodeAt:
+        return js.js('#.charCodeAt(#)', args);
       case BuiltinOperator.Identical:
         registry.registerStaticUse(new StaticUse.staticInvoke(
             glue.identicalFunction, new CallStructure.unnamed(args.length)));
@@ -1072,12 +1111,6 @@
     return new js.Await(visitExpression(node.input));
   }
 
-  visitFunctionExpression(tree_ir.FunctionExpression node) {
-    // FunctionExpressions are currently unused.
-    // We might need them if we want to emit raw JS nested functions.
-    throw 'FunctionExpressions should not be used';
-  }
-
   /// Ensures that parameter defaults will be emitted.
   ///
   /// Ideally, this should be done when generating the relevant stub methods,
diff --git a/pkg/compiler/lib/src/js_backend/codegen/glue.dart b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
index b441960..463d6da 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/glue.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
@@ -30,7 +30,7 @@
     Selector;
 import '../../world.dart' show
     ClassWorld;
-
+import '../../types/types.dart';
 
 /// Encapsulates the dependencies of the function-compiler to the compiler,
 /// backend and emitter.
@@ -287,5 +287,9 @@
     return _backend.constants.getConstantValueForVariable(elem);
   }
 
+  TypeMask extendMaskIfReachesAll(Selector selector, TypeMask mask) {
+    return _compiler.world.extendMaskIfReachesAll(selector, mask);
+  }
+
   FunctionElement get closureFromTearOff => _backend.helpers.closureFromTearOff;
 }
diff --git a/pkg/compiler/lib/src/js_backend/codegen/task.dart b/pkg/compiler/lib/src/js_backend/codegen/task.dart
index d9881b2..cad67af 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/task.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/task.dart
@@ -201,13 +201,14 @@
 
   cps.FunctionDefinition optimizeCpsIr(cps.FunctionDefinition cpsFunction) {
     cpsOptimizationTask.measure(() {
-      TypeMaskSystem typeSystem = new TypeMaskSystem(compiler);
-
       applyCpsPass(new RedundantJoinEliminator(), cpsFunction);
       applyCpsPass(new RedundantPhiEliminator(), cpsFunction);
       applyCpsPass(new InsertRefinements(typeSystem), cpsFunction);
       applyCpsPass(new TypePropagator(compiler, typeSystem, this), cpsFunction);
-      applyCpsPass(new ShareFinalFields(backend), cpsFunction);
+      applyCpsPass(new RedundantJoinEliminator(), cpsFunction);
+      applyCpsPass(new ShrinkingReducer(), cpsFunction);
+      applyCpsPass(new RedundantRefinementEliminator(typeSystem), cpsFunction);
+      applyCpsPass(new GVN(compiler), cpsFunction);
       applyCpsPass(new RemoveRefinements(), cpsFunction);
       applyCpsPass(new ShrinkingReducer(), cpsFunction);
       applyCpsPass(new ScalarReplacer(compiler), cpsFunction);
@@ -216,7 +217,7 @@
       applyCpsPass(new RedundantPhiEliminator(), cpsFunction);
       applyCpsPass(new BoundsChecker(typeSystem, compiler.world), cpsFunction);
       applyCpsPass(new ShrinkingReducer(), cpsFunction);
-      applyCpsPass(new ShareInterceptors(backend), cpsFunction);
+      applyCpsPass(new OptimizeInterceptors(backend), cpsFunction);
       applyCpsPass(new ShrinkingReducer(), cpsFunction);
     });
     return cpsFunction;
diff --git a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart b/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
index 3fa6f18..f1f5dd0 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
@@ -9,6 +9,7 @@
 import '../../universe/selector.dart' show Selector;
 import '../../cps_ir/cps_ir_builder.dart' show ThisParameterLocal;
 import '../../cps_ir/cps_fragment.dart';
+import '../../common/names.dart';
 
 class ExplicitReceiverParameterEntity implements Local {
   String get name => 'receiver';
@@ -77,7 +78,7 @@
     }
 
     if (inInterceptedMethod && methodUsesReceiverArgument(function.element)) {
-      explicitReceiverParameter.substituteFor(thisParameter);
+      thisParameter.replaceUsesWith(explicitReceiverParameter);
     }
 
     visit(function);
@@ -95,11 +96,6 @@
     return new Constant(new NullConstantValue());
   }
 
-  void insertLetPrim(Primitive primitive, Expression node) {
-    LetPrim let = new LetPrim(primitive);
-    let.insertAbove(node);
-  }
-
   void insertEqNullCheck(FunctionDefinition function) {
     // Replace
     //
@@ -122,30 +118,15 @@
     cps.insertAbove(function.body);
   }
 
-  /// Insert a static call to [function] at the point of [node] with result
-  /// [result].
-  ///
-  /// Rewrite [node] to
-  ///
-  /// let cont continuation(result) = node
-  /// in invoke function arguments continuation
-  void insertStaticCall(FunctionElement function, List<Primitive> arguments,
-      Parameter result, Expression node) {
-    InteriorNode parent = node.parent;
-    Continuation continuation = new Continuation([result]);
-
-    Selector selector = new Selector.fromElement(function);
+  /// Insert a static call to [function] immediately above [node].
+  Primitive insertStaticCallAbove(FunctionElement function,
+      List<Primitive> arguments, Expression node) {
     // TODO(johnniwinther): Come up with an implementation of SourceInformation
     // for calls such as this one that don't appear in the original source.
     InvokeStatic invoke = new InvokeStatic(
-        function, selector, arguments, continuation, null);
-
-    LetCont letCont = new LetCont(continuation, invoke);
-
-    parent.body = letCont;
-    letCont.parent = parent;
-    continuation.body = node;
-    node.parent = continuation;
+        function, new Selector.fromElement(function), arguments, null);
+    new LetPrim(invoke).insertAbove(node);
+    return invoke;
   }
 
   @override
@@ -161,16 +142,22 @@
     Expression body = node.handler.body;
     if (_exceptionParameter.hasAtLeastOneUse ||
         stackTraceParameter.hasAtLeastOneUse) {
-      Parameter exceptionValue = new Parameter(null);
-      exceptionValue.substituteFor(_exceptionParameter);
-      insertStaticCall(_glue.getExceptionUnwrapper(), [_exceptionParameter],
-          exceptionValue, body);
+      InvokeStatic unwrapped = insertStaticCallAbove(
+          _glue.getExceptionUnwrapper(),
+          [new Parameter(null)], // Dummy argument, see below.
+          body);
+      _exceptionParameter.replaceUsesWith(unwrapped);
+
+      // Replace the dummy with the exception parameter.  It must be set after
+      // replacing all uses of [_exceptionParameter].
+      unwrapped.arguments[0].changeTo(_exceptionParameter);
 
       if (stackTraceParameter.hasAtLeastOneUse) {
-        Parameter stackTraceValue = new Parameter(null);
-        stackTraceValue.substituteFor(stackTraceParameter);
-        insertStaticCall(_glue.getTraceFromException(), [_exceptionParameter],
-            stackTraceValue, body);
+        InvokeStatic stackTraceValue = insertStaticCallAbove(
+            _glue.getTraceFromException(),
+            [_exceptionParameter],
+            body);
+        stackTraceParameter.replaceUsesWith(stackTraceValue);
       }
     }
 
@@ -185,9 +172,10 @@
 
   processThrow(Throw node) {
     // The subexpression of throw is wrapped in the JavaScript output.
-    Parameter wrappedException = new Parameter(null);
-    insertStaticCall(_glue.getWrapExceptionHelper(), [node.value.definition],
-        wrappedException, node);
+    Primitive wrappedException = insertStaticCallAbove(
+        _glue.getWrapExceptionHelper(),
+        [node.value.definition],
+        node);
     node.value.changeTo(wrappedException);
   }
 
@@ -202,22 +190,26 @@
     // worry about unlinking.
   }
 
-  // TODO(24523): Insert interceptor on demand when we discover we want to use
-  // one rather than on every check.
-  processTypeTest(TypeTest node) {
-    assert(node.interceptor == null);
-    Primitive receiver = node.value.definition;
-    Primitive interceptor = new Interceptor(receiver, node.sourceInformation)
-        ..interceptedClasses.addAll(_glue.interceptedClasses);
-    insertLetPrim(interceptor, node.parent);
-    node.interceptor = new Reference<Primitive>(interceptor);
-    node.interceptor.parent = node;
+  bool isNullConstant(Primitive prim) {
+    return prim is Constant && prim.value.isNull;
   }
 
   processInvokeMethod(InvokeMethod node) {
     Selector selector = node.selector;
     if (!_glue.isInterceptedSelector(selector)) return;
 
+    // Some platform libraries will compare non-interceptable objects against
+    // null using the Dart == operator.  These must be translated directly.
+    if (node.selector == Selectors.equals &&
+        node.arguments.length == 1 &&
+        isNullConstant(node.arguments[0].definition)) {
+      node.replaceWith(new ApplyBuiltinOperator(
+          BuiltinOperator.Identical,
+          [node.receiver.definition, node.arguments[0].definition],
+          node.sourceInformation));
+      return;
+    }
+
     Primitive receiver = node.receiver.definition;
     Primitive newReceiver;
 
@@ -227,17 +219,16 @@
       //  Change 'receiver.foo()'  to  'this.foo(receiver)'.
       newReceiver = thisParameter;
     } else {
-      LetCont contBinding = node.parent;
       newReceiver = new Interceptor(receiver, node.sourceInformation)
           ..interceptedClasses.addAll(_glue.getInterceptedClassesOn(selector));
       if (receiver.hint != null) {
         newReceiver.hint = new InterceptorEntity(receiver.hint);
       }
-      insertLetPrim(newReceiver, contBinding);
+      new LetPrim(newReceiver).insertAbove(node.parent);
     }
     node.arguments.insert(0, node.receiver);
     node.receiver = new Reference<Primitive>(newReceiver)..parent = node;
-    node.receiverIsIntercepted = true;
+    node.callingConvention = CallingConvention.Intercepted;
   }
 
   processInvokeMethodDirectly(InvokeMethodDirectly node) {
@@ -253,16 +244,16 @@
       //  Change 'receiver.foo()'  to  'this.foo(receiver)'.
       newReceiver = thisParameter;
     } else {
-      LetCont contBinding = node.parent;
       newReceiver = new Interceptor(receiver, node.sourceInformation)
         ..interceptedClasses.addAll(_glue.getInterceptedClassesOn(selector));
       if (receiver.hint != null) {
         newReceiver.hint = new InterceptorEntity(receiver.hint);
       }
-      insertLetPrim(newReceiver, contBinding);
+      new LetPrim(newReceiver).insertAbove(node.parent);
     }
     node.arguments.insert(0, node.receiver);
     node.receiver = new Reference<Primitive>(newReceiver)..parent = node;
+    node.callingConvention = CallingConvention.Intercepted;
   }
 
   processInterceptor(Interceptor node) {
diff --git a/pkg/compiler/lib/src/js_backend/js_backend.dart b/pkg/compiler/lib/src/js_backend/js_backend.dart
index 9c69c45..99d383c 100644
--- a/pkg/compiler/lib/src/js_backend/js_backend.dart
+++ b/pkg/compiler/lib/src/js_backend/js_backend.dart
@@ -47,6 +47,10 @@
     CoreClasses,
     CoreTypes;
 import '../dart_types.dart';
+import '../deferred_load.dart' show
+    DeferredLoadTask;
+import '../dump_info.dart' show
+    DumpInfoTask;
 import '../elements/elements.dart';
 import '../elements/visitor.dart' show
     BaseElementVisitor;
@@ -92,8 +96,11 @@
     TypeUse,
     TypeUseKind;
 import '../universe/world_impact.dart' show
+    ImpactStrategy,
+    ImpactUseCase,
     TransformedWorldImpact,
-    WorldImpact;
+    WorldImpact,
+    WorldImpactVisitor;
 import '../util/characters.dart';
 import '../util/util.dart';
 import '../world.dart' show
diff --git a/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart b/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
index 65a49c8..ad5c04c 100644
--- a/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
@@ -120,6 +120,10 @@
 
       ClassElement classElement = element;
 
+      // Skip classes that are completely unreachable. This should only happen
+      // when all of jsinterop types are unreachable from main.
+      if (!backend.compiler.world.isImplemented(classElement)) return;
+
       if (!classElement
           .implementsInterface(helpers.jsJavaScriptObjectClass)) {
         backend.reporter.reportErrorMessage(classElement,
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart b/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
index 3a84f11..894bd92 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
@@ -149,7 +149,7 @@
     if (field.isFinal || field.isConst) return false;
     if (backend.shouldRetainSetter(field)) return true;
     return field.isClassMember &&
-    compiler.codegenWorld.hasInvokedSetter(field, compiler.world);
+        compiler.codegenWorld.hasInvokedSetter(field, compiler.world);
   }
 
   static bool fieldAccessNeverThrows(VariableElement field) {
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index 7dbab30..438dbe6 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -140,9 +140,15 @@
   ///
   /// Two forms of the string is supported:
   ///
-  /// 1) A single type string of the form 'void', '', 'var' or 'T1|...|Tn'
-  ///    which defines the types returned and for the later form also created by
-  ///    the call to JS.
+  /// 1) A single type string of the form 'void', '', 'var' or 'T1|...|Tn' which
+  ///    defines the types returned, and, for the last form, the types also
+  ///    created by the call to JS.  'var' (and '') are like 'dynamic' or
+  ///    'Object' except that 'dynamic' would indicate that objects of any type
+  ///    are created, which defeats tree-shaking.  Think of 'var' (and '') as
+  ///    meaning 'any pre-existing type'.
+  ///
+  ///    The types Ti are non-nullable, so add class `Null` to specify a
+  ///    nullable type, e.g `'String|Null'`.
   ///
   /// 2) A sequence of <tag>:<value> pairs of the following kinds
   ///
@@ -155,7 +161,7 @@
   ///    A <type-tag> is either 'returns' or 'creates' and <type-string> is a
   ///    type string like in 1). The type string marked by 'returns' defines the
   ///    types returned and 'creates' defines the types created by the call to
-  ///    JS.
+  ///    JS. If 'creates' is missing, it defaults to 'returns'.
   ///
   ///    An <effect-tag> is either 'effects' or 'depends' and <effect-string> is
   ///    either 'all', 'none' or a comma-separated list of 'no-index',
@@ -309,23 +315,30 @@
 
     String returns = values['returns'];
     if (returns != null) {
-      resolveTypesString(returns, onVar: () {
-        typesReturned.add(objectType);
-        typesReturned.add(nullType);
-      }, onType: (type) {
-        typesReturned.add(type);
-      });
+      resolveTypesString(returns,
+        onVar: () {
+          typesReturned.add(objectType);
+          typesReturned.add(nullType);
+        },
+        onType: (type) {
+          typesReturned.add(type);
+        });
     }
 
     String creates = values['creates'];
     if (creates != null) {
-      resolveTypesString(creates, onVoid: () {
-        reportError("Invalid type string 'creates:$creates'");
-      }, onVar: () {
-        reportError("Invalid type string 'creates:$creates'");
-      }, onType: (type) {
-        typesInstantiated.add(type);
-      });
+      resolveTypesString(creates,
+        onVoid: () {
+          reportError("Invalid type string 'creates:$creates'");
+        },
+        onType: (type) {
+          typesInstantiated.add(type);
+        });
+    } else if (returns != null) {
+      resolveTypesString(returns,
+        onType: (type) {
+          typesInstantiated.add(type);
+        });
     }
 
     const throwsOption = const <String, NativeThrowBehavior>{
@@ -645,12 +658,26 @@
   static NativeBehavior ofMethod(FunctionElement method,  Compiler compiler) {
     FunctionType type = method.computeType(compiler.resolution);
     var behavior = new NativeBehavior();
-    behavior.typesReturned.add(type.returnType);
+    var returnType = type.returnType;
+    bool isInterop = compiler.backend.isJsInterop(method);
+    // Note: For dart:html and other internal libraries we maintain, we can
+    // trust the return type and use it to limit what we enqueue. We have to
+    // be more conservative about JS interop types and assume they can return
+    // anything (unless the user provides the experimental flag to trust the
+    // type of js-interop APIs). We do restrict the allocation effects and say
+    // that interop calls create only interop types (which may be unsound if
+    // an interop call returns a DOM type and declares a dynamic return type,
+    // but otherwise we would include a lot of code by default).
+    // TODO(sigmund,sra): consider doing something better for numeric types.
+    behavior.typesReturned.add(
+        !isInterop || compiler.trustJSInteropTypeAnnotations ? returnType
+        : const DynamicType());
     if (!type.returnType.isVoid) {
       // Declared types are nullable.
       behavior.typesReturned.add(compiler.coreTypes.nullType);
     }
-    behavior._capture(type, compiler.resolution);
+    behavior._capture(type, compiler.resolution,
+        isInterop: isInterop, compiler: compiler);
 
     // TODO(sra): Optional arguments are currently missing from the
     // DartType. This should be fixed so the following work-around can be
@@ -668,10 +695,15 @@
     Resolution resolution = compiler.resolution;
     DartType type = field.computeType(resolution);
     var behavior = new NativeBehavior();
-    behavior.typesReturned.add(type);
+    bool isInterop = compiler.backend.isJsInterop(field);
+    // TODO(sigmund,sra): consider doing something better for numeric types.
+    behavior.typesReturned.add(
+        !isInterop || compiler.trustJSInteropTypeAnnotations ? type
+        : const DynamicType());
     // Declared types are nullable.
     behavior.typesReturned.add(resolution.coreTypes.nullType);
-    behavior._capture(type, resolution);
+    behavior._capture(type, resolution,
+        isInterop: isInterop, compiler: compiler);
     behavior._overrideWithAnnotations(field, compiler);
     return behavior;
   }
@@ -765,17 +797,50 @@
   /// Models the behavior of Dart code receiving instances and methods of [type]
   /// from native code.  We usually start the analysis by capturing a native
   /// method that has been used.
-  void _capture(DartType type, Resolution resolution) {
+  ///
+  /// We assume that JS-interop APIs cannot instantiate Dart types or
+  /// non-JSInterop native types.
+  void _capture(DartType type, Resolution resolution,
+      {bool isInterop: false, Compiler compiler}) {
     type.computeUnaliased(resolution);
     type = type.unaliased;
     if (type is FunctionType) {
       FunctionType functionType = type;
-      _capture(functionType.returnType, resolution);
+      _capture(functionType.returnType, resolution,
+          isInterop: isInterop, compiler: compiler);
       for (DartType parameter in functionType.parameterTypes) {
         _escape(parameter, resolution);
       }
     } else {
-      typesInstantiated.add(type);
+      DartType instantiated = null;
+      JavaScriptBackend backend = compiler?.backend;
+      if (!isInterop) {
+        typesInstantiated.add(type);
+      } else {
+        if (type.element != null && backend.isNative(type.element)) {
+          // Any declared native or interop type (isNative implies isJsInterop)
+          // is assumed to be allocated.
+          typesInstantiated.add(type);
+        }
+
+        if (!compiler.trustJSInteropTypeAnnotations ||
+          type.isDynamic || type.isObject) {
+          // By saying that only JS-interop types can be created, we prevent
+          // pulling in every other native type (e.g. all of dart:html) when a
+          // JS interop API returns dynamic or when we don't trust the type
+          // annotations. This means that to some degree we still use the return
+          // type to decide whether to include native types, even if we don't
+          // trust the type annotation.
+          ClassElement cls = backend.helpers.jsJavaScriptObjectClass;
+          cls.ensureResolved(resolution);
+          typesInstantiated.add(cls.thisType);
+        } else {
+          // Otherwise, when the declared type is a Dart type, we do not
+          // register an allocation because we assume it cannot be instantiated
+          // from within the JS-interop code. It must have escaped from another
+          // API.
+        }
+      }
     }
   }
 
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 6d41d9c..c41d5a1 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -3361,13 +3361,14 @@
           registry.registerStaticUse(new StaticUse.superGet(semantics.getter));
           break;
         case AccessKind.SUPER_SETTER:
-          registry.registerStaticUse(new StaticUse.superSet(semantics.setter));
+          registry.registerStaticUse(
+              new StaticUse.superSetterSet(semantics.setter));
           break;
         case AccessKind.SUPER_FIELD:
           registry.registerStaticUse(
               new StaticUse.superGet(semantics.element));
           registry.registerStaticUse(
-              new StaticUse.superSet(semantics.element));
+              new StaticUse.superFieldSet(semantics.element));
           break;
         case AccessKind.SUPER_FINAL_FIELD:
           registry.registerStaticUse(
@@ -3376,22 +3377,27 @@
         case AccessKind.COMPOUND:
           CompoundAccessSemantics compoundSemantics = semantics;
           switch (compoundSemantics.compoundAccessKind) {
-            case CompoundAccessKind.SUPER_GETTER_SETTER:
             case CompoundAccessKind.SUPER_GETTER_FIELD:
-            case CompoundAccessKind.SUPER_FIELD_SETTER:
             case CompoundAccessKind.SUPER_FIELD_FIELD:
               registry.registerStaticUse(
                   new StaticUse.superGet(semantics.getter));
               registry.registerStaticUse(
-                  new StaticUse.superSet(semantics.setter));
+                  new StaticUse.superFieldSet(semantics.setter));
+              break;
+            case CompoundAccessKind.SUPER_FIELD_SETTER:
+            case CompoundAccessKind.SUPER_GETTER_SETTER:
+              registry.registerStaticUse(
+                  new StaticUse.superGet(semantics.getter));
+              registry.registerStaticUse(
+                  new StaticUse.superSetterSet(semantics.setter));
               break;
             case CompoundAccessKind.SUPER_METHOD_SETTER:
               registry.registerStaticUse(
-                  new StaticUse.superSet(semantics.setter));
+                  new StaticUse.superSetterSet(semantics.setter));
               break;
             case CompoundAccessKind.UNRESOLVED_SUPER_GETTER:
               registry.registerStaticUse(
-                  new StaticUse.superSet(semantics.setter));
+                  new StaticUse.superSetterSet(semantics.setter));
               break;
             case CompoundAccessKind.UNRESOLVED_SUPER_SETTER:
               registry.registerStaticUse(
@@ -3446,9 +3452,12 @@
               registry.registerFeature(Feature.SUPER_NO_SUCH_METHOD);
               break;
             case AccessKind.SUPER_FIELD:
+              registry.registerStaticUse(
+                  new StaticUse.superFieldSet(semantics.setter));
+              break;
             case AccessKind.SUPER_SETTER:
               registry.registerStaticUse(
-                  new StaticUse.superSet(semantics.setter));
+                  new StaticUse.superSetterSet(semantics.setter));
               break;
             default:
               break;
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 0945568..540ba50 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -5134,15 +5134,23 @@
       stack.add(graph.addConstantNull(compiler));
       return;
     }
+
     if (checkTypeVariableBounds(node, type)) return;
 
-    var inputs = <HInstruction>[];
-    if (constructor.isGenerativeConstructor &&
-        backend.isNativeOrExtendsNative(constructor.enclosingClass) &&
-        !backend.isJsInterop(constructor)) {
-      // Native class generative constructors take a pre-constructed object.
-      inputs.add(graph.addConstantNull(compiler));
+    // Abstract class instantiation error takes precedence over argument
+    // mismatch.
+    ClassElement cls = constructor.enclosingClass;
+    if (cls.isAbstract && constructor.isGenerativeConstructor) {
+      // However, we need to ensure that all arguments are evaluated before we
+      // throw the ACIE exception.
+      send.arguments.forEach((arg) {
+        visit(arg);
+        pop();
+      });
+      generateAbstractClassInstantiationError(send, cls.name);
+      return;
     }
+
     // TODO(5347): Try to avoid the need for calling [implementation] before
     // calling [makeStaticArgumentList].
     constructorImplementation = constructor.implementation;
@@ -5152,6 +5160,14 @@
       generateWrongArgumentCountError(send, constructor, send.arguments);
       return;
     }
+
+    var inputs = <HInstruction>[];
+    if (constructor.isGenerativeConstructor &&
+        backend.isNativeOrExtendsNative(constructor.enclosingClass) &&
+        !backend.isJsInterop(constructor)) {
+      // Native class generative constructors take a pre-constructed object.
+      inputs.add(graph.addConstantNull(compiler));
+    }
     inputs.addAll(makeStaticArgumentList(callStructure,
                                          send.arguments,
                                          constructorImplementation));
@@ -5198,13 +5214,7 @@
     } else {
       SourceInformation sourceInformation =
           sourceInformationBuilder.buildNew(send);
-      ClassElement cls = constructor.enclosingClass;
-      if (cls.isAbstract && constructor.isGenerativeConstructor) {
-        generateAbstractClassInstantiationError(send, cls.name);
-        return;
-      }
       potentiallyAddTypeArguments(inputs, cls, expectedType);
-
       addInlinedInstantiation(expectedType);
       pushInvokeStatic(node, constructor, inputs,
           typeMask: elementType,
@@ -5864,7 +5874,7 @@
         && params.optionalParametersAreNamed;
   }
 
-  HForeignCode invokeJsInteropFunction(Element element,
+  HForeignCode invokeJsInteropFunction(FunctionElement element,
                                        List<HInstruction> arguments,
                                        SourceInformation sourceInformation) {
     assert(backend.isJsInterop(element));
@@ -5898,6 +5908,9 @@
 
       var nativeBehavior = new native.NativeBehavior()
         ..codeTemplate = codeTemplate;
+      if (compiler.trustJSInteropTypeAnnotations) {
+        nativeBehavior.typesReturned.add(constructor.enclosingClass.thisType);
+      }
       return new HForeignCode(
           codeTemplate,
           backend.dynamicType, filteredArguments,
@@ -5917,34 +5930,43 @@
     arguments = arguments.where((arg) => arg != null).toList();
     var inputs = <HInstruction>[target]..addAll(arguments);
 
-    js.Template codeTemplate;
-    if (element.isGetter) {
-      codeTemplate = js.js.parseForeignJS("#");
-    } else if (element.isSetter) {
-      codeTemplate = js.js.parseForeignJS("# = #");
-    } else {
-      FunctionElement function = element;
-      FunctionSignature params = function.functionSignature;
+    var nativeBehavior = new native.NativeBehavior()
+      ..sideEffects.setAllSideEffects();
 
-      var argsStub = <String>[];
-      for (int i = 0; i < arguments.length; i++) {
-        argsStub.add('#');
-      }
+    DartType type = element.isConstructor ?
+        element.enclosingClass.thisType : element.type.returnType;
+    // Native behavior effects here are similar to native/behavior.dart.
+    // The return type is dynamic if we don't trust js-interop type
+    // declarations.
+    nativeBehavior.typesReturned.add(
+        compiler.trustJSInteropTypeAnnotations ? type : const DynamicType());
 
-      if (element.isConstructor) {
-        codeTemplate = js.js.parseForeignJS("new #(${argsStub.join(",")})");
-      } else {
-        codeTemplate = js.js.parseForeignJS("#(${argsStub.join(",")})");
-      }
+    // The allocation effects include the declared type if it is native (which
+    // includes js interop types).
+    if (type.element != null && backend.isNative(type.element)) {
+      nativeBehavior.typesInstantiated.add(type);
     }
 
-    var nativeBehavior = new native.NativeBehavior()
-      ..codeTemplate = codeTemplate
-      ..typesReturned.add(
-          helpers.jsJavaScriptObjectClass.thisType)
-      ..typesInstantiated.add(
-          helpers.jsJavaScriptObjectClass.thisType)
-      ..sideEffects.setAllSideEffects();
+    // It also includes any other JS interop type if we don't trust the
+    // annotation or if is declared too broad.
+    if (!compiler.trustJSInteropTypeAnnotations || type.isObject ||
+        type.isDynamic) {
+      nativeBehavior.typesInstantiated.add(
+          backend.helpers.jsJavaScriptObjectClass.thisType);
+    }
+
+    String code;
+    if (element.isGetter) {
+      code = "#";
+    } else if (element.isSetter) {
+      code = "# = #";
+    } else {
+      var args = new List.filled(arguments.length, '#').join(',');
+      code = element.isConstructor ? "new #($args)" : "#($args)";
+    }
+    js.Template codeTemplate = js.js.parseForeignJS(code);
+    nativeBehavior.codeTemplate = codeTemplate;
+
     return new HForeignCode(
         codeTemplate,
         backend.dynamicType, inputs,
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 69ee9c8..688030a 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -1751,7 +1751,9 @@
               .withSourceInformation(node.sourceInformation);
       if (node.isSetter) {
         registry.registerStaticUse(
-            new StaticUse.superSet(superElement));
+            superElement.isSetter
+                ? new StaticUse.superSetterSet(superElement)
+                : new StaticUse.superFieldSet(superElement));
         use(node.value);
         push(new js.Assignment(access, pop())
             .withSourceInformation(node.sourceInformation));
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart
index 4f0be4a..b4f6dd8 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart
@@ -63,11 +63,6 @@
 
   final FallthroughStack fallthrough = new FallthroughStack();
 
-  @override
-  void visitInnerFunction(FunctionDefinition node) {
-    new LogicalRewriter().rewrite(node);
-  }
-
   /// True if the given statement is equivalent to its fallthrough semantics.
   ///
   /// This means it will ultimately translate to an empty statement.
@@ -543,9 +538,9 @@
     }
   }
 
-  /// True if [e2] is known to return the same value as [e1] 
+  /// True if [e2] is known to return the same value as [e1]
   /// (with no additional side effects) if evaluated immediately after [e1].
-  /// 
+  ///
   /// Concretely, this is true if [e1] and [e2] are uses of the same variable,
   /// or if [e2] is a use of a variable assigned by [e1].
   bool isSameVariable(Expression e1, Expression e2) {
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/loop_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/loop_rewriter.dart
index 14069e8..2f5a9fd 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/loop_rewriter.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/loop_rewriter.dart
@@ -52,13 +52,13 @@
 ///
 /// Note that the pattern above needs no iteration since nested ifs have been
 /// collapsed previously in the [StatementRewriter] phase.
-/// 
+///
 ///
 /// PULL INTO UPDATE EXPRESSION:
-/// 
+///
 /// Assignment expressions before the unique continue to a [whileCondition] are
 /// pulled into the updates for the loop.
-/// 
+///
 ///   L:
 ///   for (; condition; updates) {
 ///     S [ x = E; continue L ]
@@ -69,7 +69,7 @@
 ///     S [ continue L ]
 ///   }
 ///
-/// The decision to only pull in assignments is a heuristic to balance 
+/// The decision to only pull in assignments is a heuristic to balance
 /// readability and stack trace usability versus the modest code size
 /// reduction one might get by aggressively moving expressions into the
 /// updates.
@@ -88,11 +88,6 @@
     root.body = visitStatement(root.body);
   }
 
-  @override
-  void visitInnerFunction(FunctionDefinition node) {
-    node.body = new LoopRewriter().visitStatement(node.body);
-  }
-
   Statement visitContinue(Continue node) {
     usedContinueLabels.add(node.target);
     return node;
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart b/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
index 878d8e1..18bab39 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
@@ -338,15 +338,6 @@
     return node;
   }
 
-  void visitInnerFunction(FunctionDefinition node) {
-    new PullIntoInitializers().rewrite(node);
-  }
-
-  Expression visitFunctionExpression(FunctionExpression node) {
-    visitInnerFunction(node.definition);
-    return node;
-  }
-
   Expression visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
     rewriteList(node.arguments);
     return node;
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
index 1da49af..6667ded 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
@@ -579,11 +579,6 @@
     return node;
   }
 
-  Expression visitFunctionExpression(FunctionExpression node) {
-    new StatementRewriter.nested(this).rewrite(node.definition);
-    return node;
-  }
-
   Statement visitReturn(Return node) {
     node.value = visitExpression(node.value);
     return node;
@@ -1256,8 +1251,6 @@
       wasFound = true;
     }
   }
-
-  visitInnerFunction(FunctionDefinition node) {}
 }
 
 typedef VariableUseCallback(VariableUse use);
@@ -1269,8 +1262,6 @@
 
   visitVariableUse(VariableUse use) => callback(use);
 
-  visitInnerFunction(FunctionDefinition node) {}
-
   static void visit(Expression node, VariableUseCallback callback) {
     new VariableUseVisitor(callback).visitExpression(node);
   }
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart b/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart
index 91a5aac..fb31f02 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart
@@ -20,11 +20,6 @@
     visitStatement(node.body);
   }
 
-  @override
-  void visitInnerFunction(FunctionDefinition node) {
-    rewriteFunction(node);
-  }
-
   /// Rewrites the given function.
   /// This is called for the outermost function and inner functions.
   void rewriteFunction(FunctionDefinition node) {
@@ -112,11 +107,6 @@
     visitStatement(node.body);
   }
 
-  @override
-  void visitInnerFunction(FunctionDefinition node) {
-    // Do nothing. Inner functions are traversed in VariableMerger.
-  }
-
   /// Creates a new block with the current exception handler or [catchBlock]
   /// if provided.
   Block newBlock({Block catchBlock}) {
@@ -506,11 +496,6 @@
     node.body = visitStatement(node.body);
   }
 
-  @override
-  void visitInnerFunction(FunctionDefinition node) {
-    // Do nothing. Inner functions are traversed in VariableMerger.
-  }
-
   Expression visitVariableUse(VariableUse node) {
     node.variable = replaceRead(node.variable);
     return node;
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
index c42cab8..84c5200 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
@@ -117,13 +117,8 @@
     return labels.putIfAbsent(cont, () => new Label());
   }
 
-  Variable addFunctionParameter(cps_ir.Definition variable) {
-    if (variable is cps_ir.Parameter) {
-      return getVariable(variable);
-    } else {
-      return addMutableVariable(variable as cps_ir.MutableVariable)
-              ..isCaptured = true;
-    }
+  Variable addFunctionParameter(cps_ir.Parameter parameter) {
+    return getVariable(parameter);
   }
 
   FunctionDefinition buildFunction(cps_ir.FunctionDefinition node) {
@@ -273,7 +268,7 @@
   /// Translates a CPS primitive to a tree expression.
   ///
   /// This simply calls the visit method for the primitive.
-  Expression translatePrimitive(cps_ir.Primitive prim) {
+  translatePrimitive(cps_ir.Primitive prim) {
     return prim.accept(this);
   }
 
@@ -284,15 +279,20 @@
   //    (Statement next) => <result statement>
   //
 
-  NodeCallback visitLetPrim(cps_ir.LetPrim node) => (Statement next) {
+  NodeCallback visitLetPrim(cps_ir.LetPrim node) {
     Variable variable = getVariable(node.primitive);
-    Expression value = translatePrimitive(node.primitive);
-    if (node.primitive.hasAtLeastOneUse) {
-      return Assign.makeStatement(variable, value, next);
+    var value = translatePrimitive(node.primitive);
+    if (value is Expression) {
+      if (node.primitive.hasAtLeastOneUse) {
+        return (Statement next) => Assign.makeStatement(variable, value, next);
+      } else {
+        return (Statement next) => new ExpressionStatement(value, next);
+      }
     } else {
-      return new ExpressionStatement(value, next);
+      assert(value is NodeCallback);
+      return value;
     }
-  };
+  }
 
   // Continuations are bound at the same level, but they have to be
   // translated as if nested.  This is because the body can invoke any
@@ -338,128 +338,6 @@
     return (Statement next) => Assign.makeStatement(variable, value, next);
   }
 
-
-  /************************ CALL EXPRESSIONS  ************************/
-  //
-  // Visit methods for call expressions must return a function:
-  //
-  //    (Statement next) => <result statement>
-  //
-  // The result statement must include an assignment to the continuation
-  // parameter, if the parameter is used.
-  //
-
-  NodeCallback makeCallExpression(cps_ir.CallExpression call,
-                                  Expression expression) {
-    return (Statement next) {
-      cps_ir.Parameter result = call.continuation.definition.parameters.single;
-      if (result.hasAtLeastOneUse) {
-        return Assign.makeStatement(getVariable(result), expression, next);
-      } else {
-        return new ExpressionStatement(expression, next);
-      }
-    };
-  }
-
-  NodeCallback visitInvokeStatic(cps_ir.InvokeStatic node) {
-    List<Expression> arguments = translateArguments(node.arguments);
-    Expression invoke = new InvokeStatic(node.target, node.selector, arguments,
-                                         node.sourceInformation);
-    return makeCallExpression(node, invoke);
-  }
-
-  NodeCallback visitInvokeMethod(cps_ir.InvokeMethod node) {
-    InvokeMethod invoke = new InvokeMethod(
-        getVariableUse(node.receiver),
-        node.selector,
-        node.mask,
-        translateArguments(node.arguments),
-        node.sourceInformation);
-    invoke.receiverIsNotNull = node.receiverIsNotNull;
-    return makeCallExpression(node, invoke);
-  }
-
-  NodeCallback visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
-    Expression receiver = getVariableUse(node.receiver);
-    List<Expression> arguments = translateArguments(node.arguments);
-    Expression invoke = new InvokeMethodDirectly(receiver, node.target,
-        node.selector, arguments, node.sourceInformation);
-    return makeCallExpression(node, invoke);
-  }
-
-  NodeCallback visitTypeCast(cps_ir.TypeCast node) {
-    Expression value = getVariableUse(node.value);
-    List<Expression> typeArgs = translateArguments(node.typeArguments);
-    Expression expression =
-        new TypeOperator(value, node.dartType, typeArgs, isTypeTest: false);
-    return makeCallExpression(node, expression);
-  }
-
-  NodeCallback visitInvokeConstructor(cps_ir.InvokeConstructor node) {
-    List<Expression> arguments = translateArguments(node.arguments);
-    Expression invoke = new InvokeConstructor(
-        node.dartType,
-        node.target,
-        node.selector,
-        arguments,
-        node.sourceInformation);
-    return makeCallExpression(node, invoke);
-  }
-
-  NodeCallback visitForeignCode(cps_ir.ForeignCode node) {
-    List<Expression> arguments =
-        node.arguments.map(getVariableUse).toList(growable: false);
-    if (HasCapturedArguments.check(node.codeTemplate.ast)) {
-      for (Expression arg in arguments) {
-        if (arg is VariableUse) {
-          arg.variable.isCaptured = true;
-        } else {
-          // TODO(asgerf): Avoid capture of 'this'.
-        }
-      }
-    }
-    if (node.codeTemplate.isExpression) {
-      Expression foreignCode = new ForeignExpression(
-          node.codeTemplate,
-          node.type,
-          arguments,
-          node.nativeBehavior,
-          node.dependency);
-      return makeCallExpression(node, foreignCode);
-    } else {
-      return (Statement next) {
-        assert(next is Unreachable); // We are not using the `next` statement.
-        return new ForeignStatement(
-            node.codeTemplate,
-            node.type,
-            arguments,
-            node.nativeBehavior,
-            node.dependency);
-      };
-    }
-  }
-
-  NodeCallback visitGetLazyStatic(cps_ir.GetLazyStatic node) {
-    // In the tree IR, GetStatic handles lazy fields because we do not need
-    // as fine-grained control over side effects.
-    GetStatic value = new GetStatic(node.element, node.sourceInformation);
-    return makeCallExpression(node, value);
-  }
-
-  @override
-  NodeCallback visitYield(cps_ir.Yield node) {
-    return (Statement next) {
-      return new Yield(getVariableUse(node.input), node.hasStar, next);
-    };
-  }
-
-  @override
-  NodeCallback visitAwait(cps_ir.Await node) {
-    Expression value = new Await(getVariableUse(node.input));
-    return makeCallExpression(node, value);
-  }
-
-
   /************************** TAIL EXPRESSIONS  **************************/
   //
   // Visit methods for tail expressions must return a statement directly
@@ -622,11 +500,6 @@
     return createInnerBuilder().buildFunction(function);
   }
 
-  Expression visitCreateFunction(cps_ir.CreateFunction node) {
-    FunctionDefinition def = makeSubFunction(node.definition);
-    return new FunctionExpression(def);
-  }
-
   Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) {
     return new ReifyRuntimeType(
         getVariableUse(node.value), node.sourceInformation);
@@ -698,6 +571,96 @@
                         getVariableUse(node.value));
   }
 
+  Expression visitInvokeStatic(cps_ir.InvokeStatic node) {
+    List<Expression> arguments = translateArguments(node.arguments);
+    return new InvokeStatic(node.target, node.selector, arguments,
+                                         node.sourceInformation);
+  }
+
+  Expression visitInvokeMethod(cps_ir.InvokeMethod node) {
+    InvokeMethod invoke = new InvokeMethod(
+        getVariableUse(node.receiver),
+        node.selector,
+        node.mask,
+        translateArguments(node.arguments),
+        node.sourceInformation);
+    invoke.receiverIsNotNull = node.receiverIsNotNull;
+    return invoke;
+  }
+
+  Expression visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
+    Expression receiver = getVariableUse(node.receiver);
+    List<Expression> arguments = translateArguments(node.arguments);
+    return new InvokeMethodDirectly(receiver, node.target,
+        node.selector, arguments, node.sourceInformation);
+  }
+
+  Expression visitTypeCast(cps_ir.TypeCast node) {
+    Expression value = getVariableUse(node.value);
+    List<Expression> typeArgs = translateArguments(node.typeArguments);
+    return new TypeOperator(value, node.dartType, typeArgs, isTypeTest: false);
+  }
+
+  Expression visitInvokeConstructor(cps_ir.InvokeConstructor node) {
+    List<Expression> arguments = translateArguments(node.arguments);
+    return new InvokeConstructor(
+        node.dartType,
+        node.target,
+        node.selector,
+        arguments,
+        node.sourceInformation);
+  }
+
+  visitForeignCode(cps_ir.ForeignCode node) {
+    List<Expression> arguments =
+        node.arguments.map(getVariableUse).toList(growable: false);
+    if (HasCapturedArguments.check(node.codeTemplate.ast)) {
+      for (Expression arg in arguments) {
+        if (arg is VariableUse) {
+          arg.variable.isCaptured = true;
+        } else {
+          // TODO(asgerf): Avoid capture of 'this'.
+        }
+      }
+    }
+    if (node.codeTemplate.isExpression) {
+      return new ForeignExpression(
+          node.codeTemplate,
+          node.type,
+          arguments,
+          node.nativeBehavior,
+          node.dependency);
+    } else {
+      return (Statement next) {
+        assert(next is Unreachable); // We are not using the `next` statement.
+        return new ForeignStatement(
+            node.codeTemplate,
+            node.type,
+            arguments,
+            node.nativeBehavior,
+            node.dependency);
+      };
+    }
+  }
+
+  Expression visitGetLazyStatic(cps_ir.GetLazyStatic node) {
+    // In the tree IR, GetStatic handles lazy fields because we do not need
+    // as fine-grained control over side effects.
+    return new GetStatic(node.element, node.sourceInformation);
+  }
+
+  @override
+  NodeCallback visitYield(cps_ir.Yield node) {
+    return (Statement next) {
+      return new Yield(getVariableUse(node.input), node.hasStar, next);
+    };
+  }
+
+  @override
+  Expression visitAwait(cps_ir.Await node) {
+    return new Await(getVariableUse(node.input));
+  }
+
   @override
   Expression visitRefinement(cps_ir.Refinement node) {
     throw 'Unexpected Refinement node in tree builder';
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart
index 3a1a0bc..691a330 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart
@@ -129,10 +129,6 @@
     labelUses[node.target]++;
   }
 
-  visitInnerFunction(FunctionDefinition node) {
-    checkBody(node);
-  }
-
   void checkBody(FunctionDefinition node) {
     node.parameters.forEach(declare);
     visitStatement(node.body);
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 bd4baab..80e4f28 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
@@ -114,7 +114,6 @@
 
   /// Number of places where this variable occurs as:
   /// - left-hand of an [Assign]
-  /// - left-hand of a [FunctionDeclaration]
   /// - parameter in a [FunctionDefinition]
   /// - catch parameter in a [Try]
   int writeCount = 0;
@@ -437,20 +436,6 @@
   accept1(ExpressionVisitor1 visitor, arg) => visitor.visitNot(this, arg);
 }
 
-/// Currently unused.
-///
-/// See CreateFunction in the cps_ir_nodes.dart.
-class FunctionExpression extends Expression {
-  final FunctionDefinition definition;
-
-  FunctionExpression(this.definition);
-
-  accept(ExpressionVisitor visitor) => visitor.visitFunctionExpression(this);
-  accept1(ExpressionVisitor1 visitor, arg) {
-    return visitor.visitFunctionExpression(this, arg);
-  }
-}
-
 /// A [LabeledStatement] or [WhileTrue] or [For].
 abstract class JumpTarget extends Statement {
   Label get label;
@@ -988,7 +973,6 @@
   E visitLiteralList(LiteralList node);
   E visitLiteralMap(LiteralMap node);
   E visitTypeOperator(TypeOperator node);
-  E visitFunctionExpression(FunctionExpression node);
   E visitGetField(GetField node);
   E visitSetField(SetField node);
   E visitGetStatic(GetStatic node);
@@ -1026,7 +1010,6 @@
   E visitLiteralList(LiteralList node, A arg);
   E visitLiteralMap(LiteralMap node, A arg);
   E visitTypeOperator(TypeOperator node, A arg);
-  E visitFunctionExpression(FunctionExpression node, A arg);
   E visitGetField(GetField node, A arg);
   E visitSetField(SetField node, A arg);
   E visitGetStatic(GetStatic node, A arg);
@@ -1088,8 +1071,6 @@
   visitExpression(Expression e) => e.accept(this);
   visitStatement(Statement s) => s.accept(this);
 
-  visitInnerFunction(FunctionDefinition node);
-
   visitVariable(Variable variable) {}
 
   visitVariableUse(VariableUse node) {
@@ -1154,10 +1135,6 @@
     node.typeArguments.forEach(visitExpression);
   }
 
-  visitFunctionExpression(FunctionExpression node) {
-    visitInnerFunction(node.definition);
-  }
-
   visitLabeledStatement(LabeledStatement node) {
     visitStatement(node.body);
     visitStatement(node.next);
@@ -1309,10 +1286,6 @@
 }
 
 class RecursiveTransformer extends Transformer {
-  void visitInnerFunction(FunctionDefinition node) {
-    node.body = visitStatement(node.body);
-  }
-
   void _replaceExpressions(List<Expression> list) {
     for (int i = 0; i < list.length; i++) {
       list[i] = visitExpression(list[i]);
@@ -1389,11 +1362,6 @@
     return node;
   }
 
-  visitFunctionExpression(FunctionExpression node) {
-    visitInnerFunction(node.definition);
-    return node;
-  }
-
   visitLabeledStatement(LabeledStatement node) {
     node.body = visitStatement(node.body);
     node.next = visitStatement(node.next);
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
index 130d268..3f08e95 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
@@ -464,10 +464,6 @@
     return '!$operand';
   }
 
-  String visitFunctionExpression(FunctionExpression node) {
-    return "function ${node.definition.element.name}";
-  }
-
   String visitGetField(GetField node) {
     String object = visitExpression(node.object);
     String field = node.field.name;
diff --git a/pkg/compiler/lib/src/types/abstract_value_domain.dart b/pkg/compiler/lib/src/types/abstract_value_domain.dart
new file mode 100644
index 0000000..14c9939
--- /dev/null
+++ b/pkg/compiler/lib/src/types/abstract_value_domain.dart
@@ -0,0 +1,164 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.abstract_value_domain;
+
+import '../constants/values.dart';
+import '../dart_types.dart';
+import '../elements/elements.dart';
+import '../native/native.dart' show
+    NativeBehavior;
+import '../universe/selector.dart' show
+    Selector;
+import '../universe/universe.dart' show
+    ReceiverConstraint;
+
+enum AbstractBool {
+  True, False, Maybe, Nothing
+}
+
+/// A value in an abstraction of runtime values.
+abstract class AbstractValue {}
+
+/// A system that implements an abstraction over runtime values and provides
+/// access to interprocedural analysis results.
+// TODO(johnniwinther): Consider extracting the inference result access from
+// this interface.
+abstract class AbstractValueDomain {
+  AbstractValue get dynamicType;
+  AbstractValue get typeType;
+  AbstractValue get functionType;
+  AbstractValue get boolType;
+  AbstractValue get intType;
+  AbstractValue get doubleType;
+  AbstractValue get numType;
+  AbstractValue get stringType;
+  AbstractValue get listType;
+  AbstractValue get mapType;
+  AbstractValue get nonNullType;
+  AbstractValue get nullType;
+  AbstractValue get extendableArrayType;
+  AbstractValue get fixedArrayType;
+  AbstractValue get arrayType;
+  AbstractValue get uint31Type;
+  AbstractValue get uint32Type;
+  AbstractValue get uintType;
+
+  AbstractValue get numStringBoolType;
+
+  AbstractValue get fixedLengthType;
+
+  AbstractValue get interceptorType;
+
+  AbstractValue get interceptedTypes;
+
+  bool methodUsesReceiverArgument(FunctionElement function);
+
+  Element locateSingleElement(AbstractValue mask, Selector selector);
+
+  ClassElement singleClass(AbstractValue mask);
+
+  bool needsNoSuchMethodHandling(AbstractValue mask, Selector selector);
+
+  AbstractValue getReceiverType(MethodElement method);
+
+  AbstractValue getParameterType(ParameterElement parameter);
+
+  AbstractValue getReturnType(FunctionElement function);
+
+  AbstractValue getInvokeReturnType(Selector selector, AbstractValue mask);
+
+  AbstractValue getFieldType(FieldElement field);
+
+  AbstractValue join(AbstractValue a, AbstractValue b);
+
+  AbstractValue intersection(AbstractValue a, AbstractValue b);
+
+  AbstractValue getTypeOf(ConstantValue constant);
+
+  /// Returns the constant value if the [AbstractValue] represents a single
+  /// constant value. Returns `null` if [value] is not a constant.
+  ConstantValue getConstantOf(AbstractValue value);
+
+  AbstractValue nonNullExact(ClassElement element);
+
+  AbstractValue nonNullSubclass(ClassElement element);
+
+  AbstractValue nonNullSubtype(ClassElement element);
+
+  bool isDefinitelyBool(AbstractValue t, {bool allowNull: false});
+
+  bool isDefinitelyNum(AbstractValue t, {bool allowNull: false});
+
+  bool isDefinitelyString(AbstractValue t, {bool allowNull: false});
+
+  bool isDefinitelyNumStringBool(AbstractValue t, {bool allowNull: false});
+
+  bool isDefinitelyNotNumStringBool(AbstractValue t);
+
+  /// True if all values of [t] are either integers or not numbers at all.
+  ///
+  /// This does not imply that the value is an integer, since most other values
+  /// such as null are also not a non-integer double.
+  bool isDefinitelyNotNonIntegerDouble(AbstractValue t);
+
+  bool isDefinitelyNonNegativeInt(AbstractValue t, {bool allowNull: false});
+
+  bool isDefinitelyInt(AbstractValue t, {bool allowNull: false});
+
+  bool isDefinitelyUint31(AbstractValue t, {bool allowNull: false});
+
+  bool isDefinitelyUint32(AbstractValue t, {bool allowNull: false});
+
+  bool isDefinitelyUint(AbstractValue t, {bool allowNull: false});
+
+  bool isDefinitelyArray(AbstractValue t, {bool allowNull: false});
+
+  bool isDefinitelyMutableArray(AbstractValue t, {bool allowNull: false});
+
+  bool isDefinitelyFixedArray(AbstractValue t, {bool allowNull: false});
+
+  bool isDefinitelyExtendableArray(AbstractValue t, {bool allowNull: false});
+
+  bool isDefinitelyIndexable(AbstractValue t, {bool allowNull: false});
+
+  bool isDefinitelyMutableIndexable(AbstractValue t, {bool allowNull: false});
+
+  bool isDefinitelyFixedLengthIndexable(AbstractValue t,
+                                        {bool allowNull: false});
+
+  bool isDefinitelyIntercepted(AbstractValue t, {bool allowNull});
+
+  /// Given a class from the interceptor hierarchy, returns an [AbstractValue]
+  /// matching all values with that interceptor (or a subtype thereof).
+  AbstractValue getInterceptorSubtypes(ClassElement class_);
+
+  bool areDisjoint(AbstractValue leftType, AbstractValue rightType);
+
+  bool isMorePreciseOrEqual(AbstractValue t1, AbstractValue t2);
+
+  AbstractBool isSubtypeOf(AbstractValue value,
+                           DartType type,
+                           {bool allowNull});
+
+  /// Returns whether [value] is one of the falsy values: false, 0, -0, NaN,
+  /// the empty string, or null.
+  AbstractBool boolify(AbstractValue value);
+
+  AbstractBool strictBoolify(AbstractValue type);
+
+  /// Create a type mask containing at least all subtypes of [type].
+  AbstractValue subtypesOf(DartType type);
+
+  /// Returns a subset of [receiver] containing at least the types
+  /// that can respond to [selector] without throwing.
+  AbstractValue receiverTypeFor(Selector selector, AbstractValue receiver);
+
+  /// The result of an index operation on [value], or the dynamic type if
+  /// unknown.
+  AbstractValue elementTypeOfIndexable(AbstractValue value);
+
+  /// The length property of [value], or `null` if unknown.
+  int getContainerLength(AbstractValue value);
+}
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/types/type_mask.dart b/pkg/compiler/lib/src/types/type_mask.dart
index c255b60..3339738 100644
--- a/pkg/compiler/lib/src/types/type_mask.dart
+++ b/pkg/compiler/lib/src/types/type_mask.dart
@@ -75,7 +75,7 @@
  * operations on it are not guaranteed to be precise and they may
  * yield conservative answers that contain too many classes.
  */
-abstract class TypeMask implements ReceiverConstraint {
+abstract class TypeMask implements ReceiverConstraint, AbstractValue {
   factory TypeMask(ClassElement base,
                    int kind,
                    bool isNullable,
diff --git a/pkg/compiler/lib/src/types/types.dart b/pkg/compiler/lib/src/types/types.dart
index b8591aa..b9e5969 100644
--- a/pkg/compiler/lib/src/types/types.dart
+++ b/pkg/compiler/lib/src/types/types.dart
@@ -28,6 +28,9 @@
     ClassWorld,
     World;
 
+import 'abstract_value_domain.dart' show
+    AbstractValue;
+
 part 'container_type_mask.dart';
 part 'dictionary_type_mask.dart';
 part 'flat_type_mask.dart';
diff --git a/pkg/compiler/lib/src/universe/universe.dart b/pkg/compiler/lib/src/universe/universe.dart
index 5a7ba20..8b2f53e 100644
--- a/pkg/compiler/lib/src/universe/universe.dart
+++ b/pkg/compiler/lib/src/universe/universe.dart
@@ -305,7 +305,9 @@
     Map<Selector, SelectorConstraints> selectors = selectorMap.putIfAbsent(
         name, () => new Maplet<Selector, SelectorConstraints>());
     UniverseSelectorConstraints constraints = selectors.putIfAbsent(
-        selector, () => selectorConstraintsStrategy.createSelectorConstraints(selector));
+        selector, () {
+      return selectorConstraintsStrategy.createSelectorConstraints(selector);
+    });
     return constraints.addReceiverConstraint(mask);
   }
 
@@ -364,6 +366,7 @@
       case StaticUseKind.FIELD_GET:
         fieldGetters.add(element);
         break;
+      case StaticUseKind.SUPER_FIELD_SET:
       case StaticUseKind.FIELD_SET:
         fieldSetters.add(element);
         break;
diff --git a/pkg/compiler/lib/src/universe/use.dart b/pkg/compiler/lib/src/universe/use.dart
index b619d5a..77c1084 100644
--- a/pkg/compiler/lib/src/universe/use.dart
+++ b/pkg/compiler/lib/src/universe/use.dart
@@ -70,6 +70,7 @@
   GENERAL,
   STATIC_TEAR_OFF,
   SUPER_TEAR_OFF,
+  SUPER_FIELD_SET,
   FIELD_GET,
   FIELD_SET,
   CLOSURE,
@@ -160,12 +161,21 @@
     return new StaticUse._(element, StaticUseKind.GENERAL);
   }
 
-  /// Write access of a super field or setter [element].
-  factory StaticUse.superSet(Element element) {
+  /// Write access of a super field [element].
+  factory StaticUse.superFieldSet(FieldElement element) {
     assert(invariant(element, element.isInstanceMember,
         message: "Super set element $element must be an instance method."));
-    assert(invariant(element, element.isField || element.isSetter,
-        message: "Super set element $element must be a field or a setter."));
+    assert(invariant(element, element.isField,
+        message: "Super set element $element must be a field."));
+    return new StaticUse._(element, StaticUseKind.SUPER_FIELD_SET);
+  }
+
+  /// Write access of a super setter [element].
+  factory StaticUse.superSetterSet(SetterElement element) {
+    assert(invariant(element, element.isInstanceMember,
+        message: "Super set element $element must be an instance method."));
+    assert(invariant(element, element.isSetter,
+        message: "Super set element $element must be a setter."));
     return new StaticUse._(element, StaticUseKind.GENERAL);
   }
 
diff --git a/pkg/compiler/lib/src/universe/world_impact.dart b/pkg/compiler/lib/src/universe/world_impact.dart
index fe7822d..95980a0 100644
--- a/pkg/compiler/lib/src/universe/world_impact.dart
+++ b/pkg/compiler/lib/src/universe/world_impact.dart
@@ -34,6 +34,12 @@
 
   Iterable<TypeUse> get typeUses => const <TypeUse>[];
 
+  void apply(WorldImpactVisitor visitor) {
+    staticUses.forEach(visitor.visitStaticUse);
+    dynamicUses.forEach(visitor.visitDynamicUse);
+    typeUses.forEach(visitor.visitTypeUse);
+  }
+
   String toString() => dump(this);
 
   static String dump(WorldImpact worldImpact) {
@@ -154,6 +160,12 @@
     return _staticUses != null ? _staticUses : worldImpact.staticUses;
   }
 
+  void apply(WorldImpactVisitor visitor) {
+    staticUses.forEach(visitor.visitStaticUse);
+    dynamicUses.forEach(visitor.visitDynamicUse);
+    typeUses.forEach(visitor.visitTypeUse);
+  }
+
   String toString() {
     StringBuffer sb = new StringBuffer();
     sb.write('TransformedWorldImpact($worldImpact)');
@@ -161,3 +173,78 @@
     return sb.toString();
   }
 }
+
+/// Constant used to denote a specific use of a [WorldImpact].
+class ImpactUseCase {
+  final String name;
+
+  const ImpactUseCase(this.name);
+
+  String toString() => 'ImpactUseCase($name)';
+}
+
+/// Strategy used for processing [WorldImpact] object in various use cases.
+class ImpactStrategy {
+  const ImpactStrategy();
+
+  /// Applies [impact] to [visitor] for the [impactUseCase] of [element].
+  void visitImpact(Element element,
+                   WorldImpact impact,
+                   WorldImpactVisitor visitor,
+                   ImpactUseCase impactUseCase) {
+    // Apply unconditionally.
+    impact.apply(visitor);
+  }
+
+  /// Notifies the strategy that no more impacts of [impactUseCase] will be
+  /// applied.
+  void onImpactUsed(ImpactUseCase impactUseCase) {
+    // Do nothing.
+  }
+}
+
+/// Visitor used to process the uses of a [WorldImpact].
+abstract class WorldImpactVisitor {
+  void visitStaticUse(StaticUse staticUse);
+  void visitDynamicUse(DynamicUse dynamicUse);
+  void visitTypeUse(TypeUse typeUse);
+}
+
+// TODO(johnniwinther): Remove these when we get anonymous local classes.
+typedef void VisitUse<U>(U use);
+
+class WorldImpactVisitorImpl implements WorldImpactVisitor {
+  final VisitUse<StaticUse> _visitStaticUse;
+  final VisitUse<DynamicUse> _visitDynamicUse;
+  final VisitUse<TypeUse> _visitTypeUse;
+
+  WorldImpactVisitorImpl(
+      {VisitUse<StaticUse> visitStaticUse,
+       VisitUse<DynamicUse> visitDynamicUse,
+       VisitUse<TypeUse> visitTypeUse})
+      : _visitStaticUse = visitStaticUse,
+        _visitDynamicUse = visitDynamicUse,
+        _visitTypeUse = visitTypeUse;
+
+  @override
+  void visitStaticUse(StaticUse use) {
+    if (_visitStaticUse != null) {
+      _visitStaticUse(use);
+    }
+  }
+
+  @override
+  void visitDynamicUse(DynamicUse use) {
+    if (_visitDynamicUse != null) {
+      _visitDynamicUse(use);
+    }
+  }
+
+  @override
+  void visitTypeUse(TypeUse use) {
+    if (_visitTypeUse != null) {
+      _visitTypeUse(use);
+    }
+  }
+}
+
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index b4860b8..8fd7e6c 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -675,10 +675,14 @@
       return false;
     }
 
-    return element.isFinal
-        || element.isConst
-        || (element.isInstanceMember
-            && !compiler.resolverWorld.hasInvokedSetter(element, this));
+    if (element.isFinal || element.isConst) {
+      return true;
+    }
+    if (element.isInstanceMember) {
+      return !compiler.resolverWorld.hasInvokedSetter(element, this) &&
+             !compiler.resolverWorld.fieldSetters.contains(element);
+    }
+    return false;
   }
 
   SideEffects getSideEffectsOfElement(Element element) {
diff --git a/pkg/js/README.md b/pkg/js/README.md
index 3ba66d1..e1da41e 100644
--- a/pkg/js/README.md
+++ b/pkg/js/README.md
@@ -64,7 +64,7 @@
 ```
 
 If you want to use `printOptions` from Dart, you cannot simply pass a Dart `Map`
-object – they are are "opaque" in JavaScript.
+object – they are "opaque" in JavaScript.
 
 
 Instead, create a Dart class with both the `@JS()` and
diff --git a/pkg/js_ast/lib/src/printer.dart b/pkg/js_ast/lib/src/printer.dart
index b2fd29d..d5c1d9b 100644
--- a/pkg/js_ast/lib/src/printer.dart
+++ b/pkg/js_ast/lib/src/printer.dart
@@ -920,6 +920,7 @@
     // reserved word.  We don't generate fields with reserved word names except
     // for 'super'.
     if (field == '"super"') return false;
+    if (field == '"catch"') return false;
     return true;
   }
 
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 8c76824..2160dd9 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -28,6 +28,7 @@
 analyzer/test/generated/all_the_rest_test: Fail # Issue 21772
 
 [ $compiler == dart2js ]
+analyzer_cli/test/*: SkipByDesign # Only meant to run on vm
 analysis_server/test/*: Skip # Issue 22161
 analysis_server/test/analysis_notification_highlights_test: Pass, Slow # 19756, 21628
 analysis_server/test/analysis_notification_navigation_test: Pass, Slow # Issue 19756, 21628
diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index a7f3bf7..989b980 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -626,6 +626,49 @@
       },
     },
     {
+      # dart binary for running precompiled snapshots without the compiler.
+      'target_name': 'dart_precompiled',
+      'type': 'executable',
+      'dependencies': [
+        'libdart_precompiled',
+        'libdart_builtin',
+        'libdart_io',
+        'build_observatory#host',
+        'generate_resources_cc_file#host',
+        'generate_observatory_assets_cc_file#host',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'sources': [
+        'main.cc',
+        'builtin_common.cc',
+        'builtin_natives.cc',
+        'builtin_nolib.cc',
+        'builtin.h',
+        'io_natives.h',
+        'vmservice_impl.cc',
+        'vmservice_impl.h',
+        'snapshot_empty.cc',
+        '<(resources_cc_file)',
+        '<(observatory_assets_cc_file)',
+      ],
+      'conditions': [
+        ['OS=="win"', {
+          'link_settings': {
+            'libraries': [ '-lws2_32.lib', '-lRpcrt4.lib', '-lwinmm.lib' ],
+          },
+          # Generate an import library on Windows, by exporting a function.
+          # Extensions use this import library to link to the API in dart.exe.
+          'msvs_settings': {
+            'VCLinkerTool': {
+              'AdditionalOptions': [ '/EXPORT:Dart_True' ],
+            },
+          },
+        }],
+      ],
+    },
+    {
       # dart binary built for the host. It does not use a snapshot
       # and does not include Observatory.
       'target_name': 'dart_bootstrap',
diff --git a/runtime/bin/builtin_impl_sources.gypi b/runtime/bin/builtin_impl_sources.gypi
index 8fcb007..054ec9b 100644
--- a/runtime/bin/builtin_impl_sources.gypi
+++ b/runtime/bin/builtin_impl_sources.gypi
@@ -16,17 +16,6 @@
     'builtin_common.cc',
     'dartutils.cc',
     'dartutils.h',
-    'dbg_connection.cc',
-    'dbg_connection.h',
-    'dbg_connection_android.cc',
-    'dbg_connection_linux.cc',
-    'dbg_connection_linux.h',
-    'dbg_connection_macos.cc',
-    'dbg_connection_macos.h',
-    'dbg_connection_win.cc',
-    'dbg_connection_win.h',
-    'dbg_message.h',
-    'dbg_message.cc',
     'directory.cc',
     'directory.h',
     'directory_android.cc',
diff --git a/runtime/bin/builtin_natives.cc b/runtime/bin/builtin_natives.cc
index f737132..5ba5637 100644
--- a/runtime/bin/builtin_natives.cc
+++ b/runtime/bin/builtin_natives.cc
@@ -13,6 +13,7 @@
 
 #include "bin/builtin.h"
 #include "bin/dartutils.h"
+#include "bin/embedded_dart_io.h"
 #include "bin/file.h"
 #include "bin/io_natives.h"
 #include "bin/platform.h"
@@ -90,10 +91,11 @@
   if (Dart_IsError(result)) Dart_PropagateError(result);
 
   // Uses fwrite to support printing NUL bytes.
-  fwrite(chars, 1, length, stdout);
+  intptr_t res = fwrite(chars, 1, length, stdout);
+  ASSERT(res == length);
   fputs("\n", stdout);
   fflush(stdout);
-  if (File::capture_stdout()) {
+  if (ShouldCaptureStdout()) {
     // For now we report print output on the Stdout stream.
     uint8_t newline[] = { '\n' };
     Dart_ServiceSendDataEvent("Stdout", "WriteEvent", chars, length);
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index 50ae7d0..9e2fcf7 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -34,20 +34,20 @@
 namespace bin {
 
 const char* DartUtils::original_working_directory = NULL;
-const char* DartUtils::kDartScheme = "dart:";
-const char* DartUtils::kDartExtensionScheme = "dart-ext:";
-const char* DartUtils::kAsyncLibURL = "dart:async";
-const char* DartUtils::kBuiltinLibURL = "dart:_builtin";
-const char* DartUtils::kCoreLibURL = "dart:core";
-const char* DartUtils::kInternalLibURL = "dart:_internal";
-const char* DartUtils::kIsolateLibURL = "dart:isolate";
-const char* DartUtils::kIOLibURL = "dart:io";
-const char* DartUtils::kIOLibPatchURL = "dart:io-patch";
-const char* DartUtils::kUriLibURL = "dart:uri";
-const char* DartUtils::kHttpScheme = "http:";
-const char* DartUtils::kVMServiceLibURL = "dart:vmservice";
+const char* const DartUtils::kDartScheme = "dart:";
+const char* const DartUtils::kDartExtensionScheme = "dart-ext:";
+const char* const DartUtils::kAsyncLibURL = "dart:async";
+const char* const DartUtils::kBuiltinLibURL = "dart:_builtin";
+const char* const DartUtils::kCoreLibURL = "dart:core";
+const char* const DartUtils::kInternalLibURL = "dart:_internal";
+const char* const DartUtils::kIsolateLibURL = "dart:isolate";
+const char* const DartUtils::kIOLibURL = "dart:io";
+const char* const DartUtils::kIOLibPatchURL = "dart:io-patch";
+const char* const DartUtils::kUriLibURL = "dart:uri";
+const char* const DartUtils::kHttpScheme = "http:";
+const char* const DartUtils::kVMServiceLibURL = "dart:vmservice";
 
-uint8_t DartUtils::magic_number[] = { 0xf5, 0xf5, 0xdc, 0xdc };
+const uint8_t DartUtils::magic_number[] = { 0xf5, 0xf5, 0xdc, 0xdc };
 
 static bool IsWindowsHost() {
 #if defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h
index cd3ce0e..2c497b2 100644
--- a/runtime/bin/dartutils.h
+++ b/runtime/bin/dartutils.h
@@ -216,20 +216,20 @@
   // Global state that stores the original working directory..
   static const char* original_working_directory;
 
-  static const char* kDartScheme;
-  static const char* kDartExtensionScheme;
-  static const char* kAsyncLibURL;
-  static const char* kBuiltinLibURL;
-  static const char* kCoreLibURL;
-  static const char* kInternalLibURL;
-  static const char* kIsolateLibURL;
-  static const char* kIOLibURL;
-  static const char* kIOLibPatchURL;
-  static const char* kUriLibURL;
-  static const char* kHttpScheme;
-  static const char* kVMServiceLibURL;
+  static const char* const kDartScheme;
+  static const char* const kDartExtensionScheme;
+  static const char* const kAsyncLibURL;
+  static const char* const kBuiltinLibURL;
+  static const char* const kCoreLibURL;
+  static const char* const kInternalLibURL;
+  static const char* const kIsolateLibURL;
+  static const char* const kIOLibURL;
+  static const char* const kIOLibPatchURL;
+  static const char* const kUriLibURL;
+  static const char* const kHttpScheme;
+  static const char* const kVMServiceLibURL;
 
-  static uint8_t magic_number[];
+  static const uint8_t magic_number[];
 
  private:
   DISALLOW_ALLOCATION();
diff --git a/runtime/bin/dbg_connection.cc b/runtime/bin/dbg_connection.cc
deleted file mode 100644
index 6bd0cda..0000000
--- a/runtime/bin/dbg_connection.cc
+++ /dev/null
@@ -1,526 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "bin/dbg_connection.h"
-#include "bin/dbg_message.h"
-#include "bin/dartutils.h"
-#include "bin/lockers.h"
-#include "bin/log.h"
-#include "bin/socket.h"
-#include "bin/thread.h"
-#include "bin/utils.h"
-
-#include "platform/globals.h"
-#include "platform/json.h"
-#include "platform/utils.h"
-
-#include "include/dart_api.h"
-
-
-namespace dart {
-namespace bin {
-
-bool trace_debug_protocol = false;
-
-intptr_t DebuggerConnectionHandler::listener_fd_ = -1;
-Monitor* DebuggerConnectionHandler::handler_lock_ = new Monitor();
-
-// TODO(asiva): Remove this once we have support for multiple debugger
-// connections. For now we just store the single debugger connection
-// handler in a static variable.
-static DebuggerConnectionHandler* singleton_handler = NULL;
-
-// The maximum message length to print when --trace_debug_protocol is
-// specified.
-static const int kMaxPrintMessageLen = 1024;
-
-class MessageBuffer {
- public:
-  explicit MessageBuffer(intptr_t fd);
-  ~MessageBuffer();
-  void ReadData();
-  bool IsValidMessage() const;
-  void PopMessage();
-  int MessageId() const;
-  char* buf() const { return buf_; }
-  bool Alive() const { return connection_is_alive_; }
-
- private:
-  static const int kInitialBufferSize = 256;
-  char* buf_;
-  int buf_length_;
-  intptr_t fd_;
-  int data_length_;
-  bool connection_is_alive_;
-
-  DISALLOW_COPY_AND_ASSIGN(MessageBuffer);
-};
-
-
-MessageBuffer::MessageBuffer(intptr_t fd)
-    :  buf_(NULL),
-       buf_length_(0),
-       fd_(fd),
-       data_length_(0),
-       connection_is_alive_(true) {
-  buf_ = reinterpret_cast<char*>(malloc(kInitialBufferSize));
-  if (buf_ == NULL) {
-    FATAL("Failed to allocate message buffer\n");
-  }
-  buf_length_ = kInitialBufferSize;
-  buf_[0] = '\0';
-  data_length_ = 0;
-}
-
-
-MessageBuffer::~MessageBuffer() {
-  free(buf_);
-  buf_ = NULL;
-  fd_ = -1;
-}
-
-
-bool MessageBuffer::IsValidMessage() const {
-  if (data_length_ == 0) {
-    return false;
-  }
-  dart::JSONReader msg_reader(buf_);
-  return msg_reader.EndOfObject() != NULL;
-}
-
-
-int MessageBuffer::MessageId() const {
-  dart::JSONReader r(buf_);
-  r.Seek("id");
-  if (r.Type() == dart::JSONReader::kInteger) {
-    return atoi(r.ValueChars());
-  } else {
-    return -1;
-  }
-}
-
-
-void MessageBuffer::ReadData() {
-  ASSERT(data_length_ >= 0);
-  ASSERT(data_length_ < buf_length_);
-  int max_read = buf_length_ - data_length_ - 1;
-  if (max_read == 0) {
-    // TODO(hausner):
-    // Buffer is full. What should we do if there is no valid message
-    // in the buffer? This might be possible if the client sends a message
-    // that's larger than the buffer, of if the client sends malformed
-    // messages that keep piling up.
-    ASSERT(IsValidMessage());
-    return;
-  }
-  // TODO(hausner): Handle error conditions returned by Read. We may
-  // want to close the debugger connection if we get any errors.
-  int bytes_read =
-      DebuggerConnectionImpl::Receive(fd_, buf_ + data_length_, max_read);
-  if (bytes_read == 0) {
-    connection_is_alive_ = false;
-    return;
-  }
-  ASSERT(bytes_read > 0);
-  data_length_ += bytes_read;
-  ASSERT(data_length_ < buf_length_);
-  buf_[data_length_] = '\0';
-}
-
-
-void MessageBuffer::PopMessage() {
-  dart::JSONReader msg_reader(buf_);
-  const char* end = msg_reader.EndOfObject();
-  if (end != NULL) {
-    ASSERT(*end == '}');
-    end++;
-    data_length_ = 0;
-    while (*end != '\0') {
-      buf_[data_length_] = *end++;
-      data_length_++;
-    }
-    buf_[data_length_] = '\0';
-    ASSERT(data_length_ < buf_length_);
-  }
-}
-
-
-static bool IsValidJSON(const char* msg) {
-  dart::JSONReader r(msg);
-  return r.CheckMessage();
-}
-
-
-DebuggerConnectionHandler::DebuggerConnectionHandler(intptr_t debug_fd)
-    : debug_fd_(debug_fd), msgbuf_(NULL) {
-  msgbuf_ = new MessageBuffer(debug_fd_);
-}
-
-
-DebuggerConnectionHandler::~DebuggerConnectionHandler() {
-  CloseDbgConnection();
-  DebuggerConnectionHandler::RemoveDebuggerConnection(debug_fd_);
-}
-
-
-int DebuggerConnectionHandler::MessageId() {
-  ASSERT(msgbuf_ != NULL);
-  return msgbuf_->MessageId();
-}
-
-
-void DebuggerConnectionHandler::HandleUnknownMsg() {
-  int msg_id = msgbuf_->MessageId();
-  ASSERT(msg_id >= 0);
-  SendError(debug_fd_, msg_id, "unknown debugger command");
-}
-
-
-typedef void (*CommandHandler)(DbgMessage* msg);
-
-struct JSONDebuggerCommand {
-  const char* cmd_string;
-  CommandHandler handler_function;
-};
-
-
-void DebuggerConnectionHandler::HandleMessages() {
-  static JSONDebuggerCommand generic_debugger_commands[] = {
-    { "interrupt", HandleInterruptCmd },
-    { "getIsolateIds", HandleIsolatesListCmd },
-    { NULL, NULL }
-  };
-
-  for (;;) {
-    // Read a message.
-    while (!msgbuf_->IsValidMessage() && msgbuf_->Alive()) {
-      msgbuf_->ReadData();
-    }
-    if (!msgbuf_->Alive()) {
-      if (trace_debug_protocol) {
-        Log::Print("Debugger is exiting HandleMessages loop.\n");
-      }
-      return;
-    }
-
-    if (trace_debug_protocol) {
-      dart::JSONReader r(msgbuf_->buf());
-      const char* msg_end = r.EndOfObject();
-      if (msg_end != NULL) {
-        intptr_t msg_len = msg_end - msgbuf_->buf();
-        int print_len = ((msg_len > kMaxPrintMessageLen)
-                         ? kMaxPrintMessageLen : msg_len);
-        Log::Print("[<<<] Receiving message from debug fd %" Pd ":\n%.*s%s\n",
-                   debug_fd_, print_len, msgbuf_->buf(),
-                   ((msg_len > print_len) ? "..." : ""));
-      }
-    }
-
-    // Parse out the command portion from the message.
-    dart::JSONReader r(msgbuf_->buf());
-    bool found = r.Seek("command");
-    if (r.Error()) {
-      FATAL("Illegal JSON message received");
-    }
-    if (!found) {
-      Log::Print("'command' not found in JSON message: '%s'\n",
-                      msgbuf_->buf());
-      msgbuf_->PopMessage();
-    }
-
-    // Check if this is a generic command (not isolate specific).
-    int i = 0;
-    bool is_handled = false;
-    while (generic_debugger_commands[i].cmd_string != NULL) {
-      if (r.IsStringLiteral(generic_debugger_commands[i].cmd_string)) {
-        DbgMessage* msg = new DbgMessage(i,
-                                         msgbuf_->buf(),
-                                         r.EndOfObject(),
-                                         debug_fd_);
-        (*generic_debugger_commands[i].handler_function)(msg);
-        is_handled = true;
-        msgbuf_->PopMessage();
-        delete msg;
-        break;
-      }
-      i++;
-    }
-    if (!is_handled) {
-      // Check if this is an isolate specific command.
-      int32_t cmd_idx = DbgMsgQueueList::LookupIsolateCommand(r.ValueChars(),
-                                                              r.ValueLen());
-      if (cmd_idx != DbgMsgQueueList::kInvalidCommand) {
-        const char* start = msgbuf_->buf();
-        const char* end = r.EndOfObject();
-        // Get debug message queue corresponding to isolate.
-        MessageParser msg_parser(start, (end - start));
-        Dart_IsolateId isolate_id = msg_parser.GetInt64Param("isolateId");
-        if (!DbgMsgQueueList::AddIsolateMessage(isolate_id,
-                                                cmd_idx,
-                                                msgbuf_->buf(),
-                                                r.EndOfObject(),
-                                                debug_fd_)) {
-          SendError(debug_fd_, MessageId(), "Invalid isolate specified");
-        }
-        msgbuf_->PopMessage();
-        continue;
-      }
-
-      // This is an unrecognized command, report error and move on to next.
-      Log::Print("unrecognized command received: '%s'\n", msgbuf_->buf());
-      HandleUnknownMsg();
-      msgbuf_->PopMessage();
-    }
-  }
-}
-
-
-void DebuggerConnectionHandler::SendError(intptr_t debug_fd,
-                                          int msg_id,
-                                          const char* err_msg) {
-  dart::TextBuffer msg(64);
-  msg.Printf("{\"id\": %d, \"error\": \"Error: ", msg_id);
-  msg.AddEscapedString(err_msg);
-  msg.Printf("\"}");
-  SendMsg(debug_fd, &msg);
-}
-
-
-void DebuggerConnectionHandler::CloseDbgConnection() {
-  if (debug_fd_ >= 0) {
-    Socket::Close(debug_fd_);
-  }
-  if (msgbuf_ != NULL) {
-    delete msgbuf_;
-    msgbuf_ = NULL;
-  }
-  // TODO(hausner): Need to tell the VM debugger object to remove all
-  // breakpoints.
-}
-
-
-// The vm service relies on certain debugger functionality.
-void DebuggerConnectionHandler::InitForVmService() {
-  MonitorLocker ml(handler_lock_);
-  DbgMsgQueueList::Initialize();
-}
-
-
-int DebuggerConnectionHandler::StartHandler(const char* address,
-                                            int port_number) {
-  ASSERT(handler_lock_ != NULL);
-  MonitorLocker ml(handler_lock_);
-  if (IsListening()) {
-    // The debugger connection handler was already started.
-    return Socket::GetPort(listener_fd_);
-  }
-
-  // First setup breakpoint, exception and delayed breakpoint handlers.
-  DbgMsgQueueList::Initialize();
-
-  // Initialize the socket implementation.
-  if (!Socket::Initialize()) {
-    FATAL("Failed initializing socket implementation.");
-  }
-
-  // Now setup a listener socket and start a thread which will
-  // listen, accept connections from debuggers, read and handle/dispatch
-  // debugger commands received on these connections.
-  ASSERT(listener_fd_ == -1);
-  OSError *os_error;
-  AddressList<SocketAddress>* addresses =
-      Socket::LookupAddress(address, -1, &os_error);
-  RawAddr addr = addresses->GetAt(0)->addr();
-  SocketAddress::SetAddrPort(&addr, port_number);
-  listener_fd_ = ServerSocket::CreateBindListen(addr, 1);
-  delete addresses;
-  if (listener_fd_ < 0) {
-    fprintf(stderr, "%s", "Could not initialize debug socket\n");
-    fflush(stderr);
-    exit(255);
-  }
-
-  port_number = Socket::GetPort(listener_fd_);
-  DebuggerConnectionImpl::StartHandler(port_number);
-  return port_number;
-}
-
-
-void DebuggerConnectionHandler::StopHandler() {
-  if (IsConnected()) {
-    DebuggerConnectionImpl::StopHandler(singleton_handler->debug_fd());
-  }
-}
-
-
-void DebuggerConnectionHandler::WaitForConnection() {
-  ASSERT(handler_lock_ != NULL);
-  MonitorLocker ml(handler_lock_);
-  if (!IsListening()) {
-    // If we are only running the vm service, don't wait for
-    // connections.
-    return;
-  }
-  while (!IsConnected()) {
-    Monitor::WaitResult res = ml.Wait();
-    ASSERT(res == Monitor::kNotified);
-  }
-}
-
-
-void DebuggerConnectionHandler::SendMsg(intptr_t debug_fd,
-                                        dart::TextBuffer* msg) {
-  ASSERT(handler_lock_ != NULL);
-  MonitorLocker ml(handler_lock_);
-  SendMsgHelper(debug_fd, msg);
-}
-
-
-void DebuggerConnectionHandler::BroadcastMsg(dart::TextBuffer* msg) {
-  ASSERT(handler_lock_ != NULL);
-  MonitorLocker ml(handler_lock_);
-  if (!IsListening()) {
-    // If we are only running the vm service, don't try to broadcast
-    // to debugger clients.
-    return;
-  }
-  // TODO(asiva): Once we support connection to multiple debuggers
-  // we need to send the message to all of them.
-  ASSERT(singleton_handler != NULL);
-  SendMsgHelper(singleton_handler->debug_fd(), msg);
-}
-
-
-void DebuggerConnectionHandler::SendMsgHelper(intptr_t debug_fd,
-                                              dart::TextBuffer* msg) {
-  ASSERT(debug_fd >= 0);
-  ASSERT(IsValidJSON(msg->buf()));
-
-  if (trace_debug_protocol) {
-    int print_len = ((msg->length() > kMaxPrintMessageLen)
-                     ? kMaxPrintMessageLen : msg->length());
-    Log::Print("[>>>] Sending message to debug fd %" Pd ":\n%.*s%s\n",
-               debug_fd, print_len, msg->buf(),
-               ((msg->length() > print_len) ? "..." : ""));
-  }
-
-  // Sending messages in short pieces can be used to stress test the
-  // debugger front-end's message handling code.
-  const bool send_in_pieces = false;
-  if (send_in_pieces) {
-    intptr_t remaining = msg->length();
-    intptr_t sent = 0;
-    const intptr_t max_piece_len = 122;  // Pretty arbitrary, not a power of 2.
-    Monitor sleep;
-    while (remaining > 0) {
-      intptr_t piece_len = remaining;
-      if (piece_len > max_piece_len) {
-        piece_len = max_piece_len;
-      }
-      intptr_t written =
-          DebuggerConnectionImpl::Send(debug_fd, msg->buf() + sent, piece_len);
-      ASSERT(written == piece_len);
-      sent += written;
-      remaining -= written;
-      // Wait briefly so the OS does not coalesce message fragments.
-      {
-        MonitorLocker ml(&sleep);
-        ml.Wait(10);
-      }
-    }
-    return;
-  }
-  intptr_t bytes_written =
-      DebuggerConnectionImpl::Send(debug_fd, msg->buf(), msg->length());
-  ASSERT(msg->length() == bytes_written);
-  // TODO(hausner): Error checking. Probably just shut down the debugger
-  // session if we there is an error while writing.
-}
-
-
-void DebuggerConnectionHandler::AcceptDbgConnection(intptr_t debug_fd) {
-  Socket::SetNoDelay(debug_fd, true);
-  AddNewDebuggerConnection(debug_fd);
-  {
-    ASSERT(handler_lock_ != NULL);
-    MonitorLocker ml(handler_lock_);
-    ml.NotifyAll();
-  }
-  // TODO(asiva): Once we implement support for multiple connections
-  // we should have a different callback for wakeups on fds which
-  // are not the listener_fd_.
-  // In that callback we would lookup the handler object
-  // corresponding to that fd and invoke HandleMessages on it.
-  // For now we run that code here.
-  DebuggerConnectionHandler* handler = GetDebuggerConnectionHandler(debug_fd);
-  if (handler != NULL) {
-    handler->HandleMessages();
-    delete handler;
-  }
-}
-
-
-void DebuggerConnectionHandler::HandleInterruptCmd(DbgMessage* in_msg) {
-  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
-  int msg_id = msg_parser.MessageId();
-  Dart_IsolateId isolate_id = msg_parser.GetInt64Param("isolateId");
-  if (isolate_id == ILLEGAL_ISOLATE_ID || Dart_GetIsolate(isolate_id) == NULL) {
-    in_msg->SendErrorReply(msg_id, "Invalid isolate specified");
-    return;
-  }
-  if (!DbgMsgQueueList::InterruptIsolate(isolate_id)) {
-    in_msg->SendErrorReply(msg_id, "Invalid isolate specified");
-    return;
-  }
-  dart::TextBuffer msg(64);
-  msg.Printf("{ \"id\": %d }", msg_id);
-  in_msg->SendReply(&msg);
-}
-
-
-void DebuggerConnectionHandler::HandleIsolatesListCmd(DbgMessage* in_msg) {
-  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
-  int msg_id = msg_parser.MessageId();
-  ASSERT(msg_id >= 0);
-  dart::TextBuffer msg(64);
-  msg.Printf("{ \"id\": %d, \"result\": { \"isolateIds\": [", msg_id);
-  DbgMsgQueueList::ListIsolateIds(&msg);
-  msg.Printf("]}}");
-  in_msg->SendReply(&msg);
-}
-
-
-void DebuggerConnectionHandler::AddNewDebuggerConnection(intptr_t debug_fd) {
-  // TODO(asiva): Support multiple debugger connections, for now we just
-  // create one handler, store it in a static variable and use it.
-  ASSERT(singleton_handler == NULL);
-  singleton_handler = new DebuggerConnectionHandler(debug_fd);
-}
-
-
-void DebuggerConnectionHandler::RemoveDebuggerConnection(intptr_t debug_fd) {
-  // TODO(asiva): Support multiple debugger connections, for now we just
-  // set the static handler back to NULL.
-  ASSERT(singleton_handler != NULL);
-  singleton_handler = NULL;
-}
-
-
-DebuggerConnectionHandler*
-DebuggerConnectionHandler::GetDebuggerConnectionHandler(intptr_t debug_fd) {
-  // TODO(asiva): Support multiple debugger connections, for now we just
-  // return the one static handler that was created.
-  ASSERT(singleton_handler != NULL);
-  return singleton_handler;
-}
-
-
-bool DebuggerConnectionHandler::IsConnected() {
-  // TODO(asiva): Support multiple debugger connections.
-  // Return true if a connection has been established.
-  return singleton_handler != NULL;
-}
-
-}  // namespace bin
-}  // namespace dart
diff --git a/runtime/bin/dbg_connection.h b/runtime/bin/dbg_connection.h
deleted file mode 100644
index 577c30a..0000000
--- a/runtime/bin/dbg_connection.h
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef BIN_DBG_CONNECTION_H_
-#define BIN_DBG_CONNECTION_H_
-
-#include "bin/builtin.h"
-#include "bin/utils.h"
-
-#include "include/dart_tools_api.h"
-
-#include "platform/globals.h"
-#include "platform/json.h"
-#include "bin/thread.h"
-// Declare the OS-specific types ahead of defining the generic class.
-#if defined(TARGET_OS_ANDROID)
-#include "bin/dbg_connection_android.h"
-#elif defined(TARGET_OS_LINUX)
-#include "bin/dbg_connection_linux.h"
-#elif defined(TARGET_OS_MACOS)
-#include "bin/dbg_connection_macos.h"
-#elif defined(TARGET_OS_WINDOWS)
-#include "bin/dbg_connection_win.h"
-#else
-#error Unknown target os.
-#endif
-
-
-namespace dart {
-namespace bin {
-
-// Forward declarations.
-class DbgMessage;
-class MessageBuffer;
-
-
-class DebuggerConnectionHandler {
- public:
-  explicit DebuggerConnectionHandler(intptr_t debug_fd);
-  ~DebuggerConnectionHandler();
-
-  // Accessors.
-  intptr_t debug_fd() const { return debug_fd_; }
-
-  // Return message id of current debug command message.
-  int MessageId();
-
-  // Starts the native thread which listens for connections from
-  // debugger clients, reads and dispatches debug command messages
-  // from the client.
-  static int StartHandler(const char* address, int port_number);
-
-  // Stops the native thread.
-  static void StopHandler();
-
-  // Initializes the parts of the debugger which are needed by the vm
-  // service.  This function should only be called when StartHandler
-  // is not called.
-  static void InitForVmService();
-
-  // Called by Isolates when they need to wait for a connection
-  // from debugger clients.
-  static void WaitForConnection();
-
-  // Sends a reply or an error message to a specific debugger client.
-  static void SendMsg(intptr_t debug_fd, dart::TextBuffer* msg);
-  static void SendError(intptr_t debug_fd, int msg_id, const char* err_msg);
-
-  // Sends an event message to all debugger clients that are connected.
-  static void BroadcastMsg(dart::TextBuffer* msg);
-
- private:
-  void HandleUnknownMsg();
-  void HandleMessages();
-
-  void CloseDbgConnection();
-
-  // The socket that connects with the debugger client.
-  // The descriptor is created and closed by the debugger connection thread.
-  intptr_t debug_fd_;
-
-  // Buffer holding the messages received over the wire from the debugger
-  // front end..
-  MessageBuffer* msgbuf_;
-
-  // Accepts connection requests from debugger client and sets up a
-  // connection handler object to read and handle messages from the client.
-  static void AcceptDbgConnection(intptr_t debug_fd);
-
-  // Handlers for generic debug command messages which are not specific to
-  // an isolate.
-  static void HandleInterruptCmd(DbgMessage* msg);
-  static void HandleIsolatesListCmd(DbgMessage* msg);
-
-  // Helper methods to manage debugger client connections.
-  static void AddNewDebuggerConnection(intptr_t debug_fd);
-  static void RemoveDebuggerConnection(intptr_t debug_fd);
-  static DebuggerConnectionHandler* GetDebuggerConnectionHandler(
-                                       intptr_t debug_fd);
-  static bool IsConnected();
-
-  // Helper method for sending messages back to a debugger client.
-  static void SendMsgHelper(intptr_t debug_fd, dart::TextBuffer* msg);
-
-  // mutex/condition variable used by isolates when writing back to the
-  // debugger. This is also used to ensure that the isolate waits for
-  // a debugger to be attached when that is requested on the command line.
-  static Monitor* handler_lock_;
-
-  static bool IsListening() {
-    return listener_fd_ != -1;
-  }
-
-  // The socket that is listening for incoming debugger connections.
-  // This descriptor is created and closed by a native thread.
-  static intptr_t listener_fd_;
-
-  friend class DebuggerConnectionImpl;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(DebuggerConnectionHandler);
-};
-
-}  // namespace bin
-}  // namespace dart
-
-#endif  // BIN_DBG_CONNECTION_H_
diff --git a/runtime/bin/dbg_connection_android.cc b/runtime/bin/dbg_connection_android.cc
deleted file mode 100644
index 77c7a20..0000000
--- a/runtime/bin/dbg_connection_android.cc
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "platform/globals.h"
-#if defined(TARGET_OS_ANDROID)
-
-#include <errno.h>  // NOLINT
-#include <stdio.h>  // NOLINT
-#include <stdlib.h>  // NOLINT
-#include <sys/epoll.h>  // NOLINT
-
-#include "bin/dbg_connection.h"
-#include "bin/fdutils.h"
-#include "bin/log.h"
-#include "bin/socket.h"
-
-#include "platform/signal_blocker.h"
-
-
-namespace dart {
-namespace bin {
-
-intptr_t DebuggerConnectionImpl::epoll_fd_ = -1;
-int DebuggerConnectionImpl::wakeup_fds_[2] = {-1, -1};
-
-
-void DebuggerConnectionImpl::HandleEvent(struct epoll_event* event) {
-  if (event->data.fd == DebuggerConnectionHandler::listener_fd_) {
-    if (DebuggerConnectionHandler::IsConnected()) {
-      FATAL("Cannot connect to more than one debugger.\n");
-    }
-    intptr_t fd = ServerSocket::Accept(event->data.fd);
-    if (fd < 0) {
-      FATAL("Accepting new debugger connection failed.\n");
-    }
-    FDUtils::SetBlocking(fd);
-    DebuggerConnectionHandler::AcceptDbgConnection(fd);
-    // TODO(hausner): add the debugger wire socket fd to the event poll queue
-    // once we poll the debugger connection.
-  } else if (event->data.fd == wakeup_fds_[0]) {
-    // Sync message. Not yet implemented.
-    UNIMPLEMENTED();
-  } else {
-    Log::Print("unexpected: receiving debugger connection event.\n");
-    UNIMPLEMENTED();
-  }
-}
-
-
-void DebuggerConnectionImpl::Handler(uword args) {
-  static const int kMaxEvents = 4;
-  struct epoll_event events[kMaxEvents];
-  while (1) {
-    const int no_timeout = -1;
-    intptr_t result = TEMP_FAILURE_RETRY(
-        epoll_wait(epoll_fd_, events, kMaxEvents, no_timeout));
-    ASSERT(EAGAIN == EWOULDBLOCK);
-    if (result == -1) {
-      if (errno != EWOULDBLOCK) {
-        perror("epoll_wait failed");
-      }
-    } else {
-      ASSERT(result <= kMaxEvents);
-      for (int i = 0; i < result; i++) {
-        HandleEvent(&events[i]);
-      }
-    }
-  }
-}
-
-
-void DebuggerConnectionImpl::SetupPollQueue() {
-  int result = NO_RETRY_EXPECTED(pipe(wakeup_fds_));
-  if (result != 0) {
-    FATAL1("Pipe creation failed with error %d\n", result);
-  }
-  FDUtils::SetNonBlocking(wakeup_fds_[0]);
-
-  static const int kEpollInitialSize = 16;
-  epoll_fd_ = NO_RETRY_EXPECTED(epoll_create(kEpollInitialSize));
-  if (epoll_fd_ == -1) {
-    FATAL("Failed creating epoll file descriptor");
-  }
-
-  // Register the wakeup _fd with the epoll instance.
-  struct epoll_event event;
-  event.events = EPOLLIN;
-  event.data.fd = wakeup_fds_[0];
-  int status = NO_RETRY_EXPECTED(epoll_ctl(
-                   epoll_fd_, EPOLL_CTL_ADD, wakeup_fds_[0], &event));
-  if (status == -1) {
-    FATAL("Failed adding wakeup fd to epoll instance");
-  }
-
-  // Register the listener_fd with the epoll instance.
-  event.events = EPOLLIN;
-  event.data.fd = DebuggerConnectionHandler::listener_fd_;
-  status = NO_RETRY_EXPECTED(epoll_ctl(epoll_fd_, EPOLL_CTL_ADD,
-               DebuggerConnectionHandler::listener_fd_, &event));
-  if (status == -1) {
-    FATAL("Failed adding listener fd to epoll instance");
-  }
-}
-
-
-void DebuggerConnectionImpl::StartHandler(int port_number) {
-  ASSERT(DebuggerConnectionHandler::listener_fd_ != -1);
-  SetupPollQueue();
-  int result = Thread::Start(&DebuggerConnectionImpl::Handler, 0);
-  if (result != 0) {
-    FATAL1("Failed to start debugger connection handler thread: %d\n", result);
-  }
-}
-
-
-intptr_t DebuggerConnectionImpl::Send(intptr_t socket,
-                                      const char* buf,
-                                      int len) {
-  return TEMP_FAILURE_RETRY(write(socket, buf, len));
-}
-
-
-intptr_t DebuggerConnectionImpl::Receive(intptr_t socket, char* buf, int len) {
-  return TEMP_FAILURE_RETRY(read(socket, buf, len));
-}
-
-}  // namespace bin
-}  // namespace dart
-
-#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/dbg_connection_android.h b/runtime/bin/dbg_connection_android.h
deleted file mode 100644
index 8975294..0000000
--- a/runtime/bin/dbg_connection_android.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef BIN_DBG_CONNECTION_ANDROID_H_
-#define BIN_DBG_CONNECTION_ANDROID_H_
-
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <sys/socket.h>
-
-
-namespace dart {
-namespace bin {
-
-class DebuggerConnectionImpl {
- public:
-  static void StartHandler(int port_number);
-  static void StopHandler(intptr_t debug_fd) {}
-  static intptr_t Send(intptr_t socket, const char* buf, int len);
-  static intptr_t Receive(intptr_t socket, char* buf, int len);
-
- private:
-  static void SetupPollQueue();
-  static void HandleEvent(struct epoll_event* event);
-  static void Handler(uword args);
-
-  // File descriptors for pipes used to communicate with the debugger thread.
-  static int wakeup_fds_[2];
-
-  // File descriptor for the polling queue.
-  static intptr_t epoll_fd_;
-};
-
-}  // namespace bin
-}  // namespace dart
-
-#endif  // BIN_DBG_CONNECTION_ANDROID_H_
diff --git a/runtime/bin/dbg_connection_linux.cc b/runtime/bin/dbg_connection_linux.cc
deleted file mode 100644
index a55557d..0000000
--- a/runtime/bin/dbg_connection_linux.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "platform/globals.h"
-#if defined(TARGET_OS_LINUX)
-
-#include <errno.h>  // NOLINT
-#include <stdio.h>  // NOLINT
-#include <stdlib.h>  // NOLINT
-#include <sys/epoll.h>  // NOLINT
-
-#include "platform/signal_blocker.h"
-#include "bin/dbg_connection.h"
-#include "bin/fdutils.h"
-#include "bin/log.h"
-#include "bin/socket.h"
-
-
-namespace dart {
-namespace bin {
-
-int DebuggerConnectionImpl::epoll_fd_ = -1;
-int DebuggerConnectionImpl::wakeup_fds_[2] = {-1, -1};
-
-
-void DebuggerConnectionImpl::HandleEvent(struct epoll_event* event) {
-  if (event->data.fd == DebuggerConnectionHandler::listener_fd_) {
-    if (DebuggerConnectionHandler::IsConnected()) {
-      FATAL("Cannot connect to more than one debugger.\n");
-    }
-    intptr_t fd = ServerSocket::Accept(event->data.fd);
-    if (fd < 0) {
-      FATAL("Accepting new debugger connection failed.\n");
-    }
-    FDUtils::SetBlocking(fd);
-    DebuggerConnectionHandler::AcceptDbgConnection(fd);
-    // TODO(hausner): add the debugger wire socket fd to the event poll queue
-    // once we poll the debugger connection.
-  } else if (event->data.fd == wakeup_fds_[0]) {
-    // Sync message. Not yet implemented.
-    UNIMPLEMENTED();
-  } else {
-    Log::Print("unexpected: receiving debugger connection event.\n");
-    UNIMPLEMENTED();
-  }
-}
-
-
-void DebuggerConnectionImpl::Handler(uword args) {
-  static const int kMaxEvents = 4;
-  struct epoll_event events[kMaxEvents];
-  while (1) {
-    const int no_timeout = -1;
-    intptr_t result = TEMP_FAILURE_RETRY(
-        epoll_wait(epoll_fd_, events, kMaxEvents, no_timeout));
-    ASSERT(EAGAIN == EWOULDBLOCK);
-    if (result == -1) {
-      if (errno != EWOULDBLOCK) {
-        perror("epoll_wait failed");
-      }
-    } else {
-      ASSERT(result <= kMaxEvents);
-      for (int i = 0; i < result; i++) {
-        HandleEvent(&events[i]);
-      }
-    }
-  }
-}
-
-
-void DebuggerConnectionImpl::SetupPollQueue() {
-  int result = NO_RETRY_EXPECTED(pipe(wakeup_fds_));
-  if (result != 0) {
-    FATAL1("Pipe creation failed with error %d\n", result);
-  }
-  FDUtils::SetNonBlocking(wakeup_fds_[0]);
-
-  static const int kEpollInitialSize = 16;
-  epoll_fd_ = NO_RETRY_EXPECTED(epoll_create(kEpollInitialSize));
-  if (epoll_fd_ == -1) {
-    FATAL("Failed creating epoll file descriptor");
-  }
-
-  // Register the wakeup _fd with the epoll instance.
-  struct epoll_event event;
-  event.events = EPOLLIN;
-  event.data.fd = wakeup_fds_[0];
-  int status = NO_RETRY_EXPECTED(epoll_ctl(
-      epoll_fd_, EPOLL_CTL_ADD, wakeup_fds_[0], &event));
-  if (status == -1) {
-    FATAL("Failed adding wakeup fd to epoll instance");
-  }
-
-  // Register the listener_fd with the epoll instance.
-  event.events = EPOLLIN;
-  event.data.fd = DebuggerConnectionHandler::listener_fd_;
-  status = NO_RETRY_EXPECTED(epoll_ctl(epoll_fd_, EPOLL_CTL_ADD,
-      DebuggerConnectionHandler::listener_fd_, &event));
-  if (status == -1) {
-    FATAL("Failed adding listener fd to epoll instance");
-  }
-}
-
-
-void DebuggerConnectionImpl::StartHandler(int port_number) {
-  ASSERT(DebuggerConnectionHandler::listener_fd_ != -1);
-  SetupPollQueue();
-  int result = Thread::Start(&DebuggerConnectionImpl::Handler, 0);
-  if (result != 0) {
-    FATAL1("Failed to start debugger connection handler thread: %d\n", result);
-  }
-}
-
-
-intptr_t DebuggerConnectionImpl::Send(intptr_t socket,
-                                      const char* buf,
-                                      int len) {
-  return TEMP_FAILURE_RETRY(write(socket, buf, len));
-}
-
-
-intptr_t DebuggerConnectionImpl::Receive(intptr_t socket, char* buf, int len) {
-  return TEMP_FAILURE_RETRY(read(socket, buf, len));
-}
-
-}  // namespace bin
-}  // namespace dart
-
-#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/dbg_connection_linux.h b/runtime/bin/dbg_connection_linux.h
deleted file mode 100644
index fcbd16e..0000000
--- a/runtime/bin/dbg_connection_linux.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef BIN_DBG_CONNECTION_LINUX_H_
-#define BIN_DBG_CONNECTION_LINUX_H_
-
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <sys/socket.h>
-
-
-namespace dart {
-namespace bin {
-
-class DebuggerConnectionImpl {
- public:
-  static void StartHandler(int port_number);
-  static void StopHandler(intptr_t debug_fd) {}
-  static intptr_t Send(intptr_t socket, const char* buf, int len);
-  static intptr_t Receive(intptr_t socket, char* buf, int len);
-
- private:
-  static void SetupPollQueue();
-  static void HandleEvent(struct epoll_event* event);
-  static void Handler(uword args);
-
-  // File descriptors for pipes used to communicate with the debugger thread.
-  static int wakeup_fds_[2];
-
-  // File descriptor for the polling queue.
-  static int epoll_fd_;
-};
-
-}  // namespace bin
-}  // namespace dart
-
-#endif  // BIN_DBG_CONNECTION_LINUX_H_
diff --git a/runtime/bin/dbg_connection_macos.cc b/runtime/bin/dbg_connection_macos.cc
deleted file mode 100644
index 4da21cd..0000000
--- a/runtime/bin/dbg_connection_macos.cc
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "platform/globals.h"
-#if defined(TARGET_OS_MACOS)
-
-#include <errno.h>  // NOLINT
-#include <stdio.h>  // NOLINT
-#include <stdlib.h>  // NOLINT
-#include <string.h>  // NOLINT
-#include <sys/event.h>  // NOLINT
-#include <unistd.h>  // NOLINT
-
-#include "bin/dartutils.h"
-#include "bin/dbg_connection.h"
-#include "bin/fdutils.h"
-#include "bin/log.h"
-#include "bin/socket.h"
-#include "platform/signal_blocker.h"
-#include "platform/utils.h"
-
-
-namespace dart {
-namespace bin {
-
-#define INVALID_FD -1
-
-int DebuggerConnectionImpl::kqueue_fd_ = INVALID_FD;
-int DebuggerConnectionImpl::wakeup_fds_[2] = {INVALID_FD, INVALID_FD};
-
-
-// Used by VM threads to send a message to the debugger connetion
-// handler thread.
-void DebuggerConnectionImpl::SendMessage(MessageType id) {
-  ASSERT(wakeup_fds_[1] != INVALID_FD);
-  struct Message msg;
-  msg.msg_id = id;
-  int result = FDUtils::WriteToBlocking(wakeup_fds_[1], &msg, sizeof(msg));
-  if (result != sizeof(msg)) {
-    if (result == -1) {
-      perror("Wakeup message failure: ");
-    }
-    FATAL1("Wakeup message failure. Wrote %d bytes.", result);
-  }
-}
-
-
-// Used by the debugger connection handler to read the messages sent
-// by the VM.
-bool DebuggerConnectionImpl::ReceiveMessage(Message* msg) {
-  int total_read = 0;
-  int bytes_read = 0;
-  int remaining = sizeof(Message);
-  uint8_t* buf = reinterpret_cast<uint8_t*>(msg);
-  while (remaining > 0) {
-    bytes_read =
-        TEMP_FAILURE_RETRY(read(wakeup_fds_[0], buf + total_read, remaining));
-    if ((bytes_read < 0) && (total_read == 0)) {
-      return false;
-    }
-    if (bytes_read > 0) {
-      total_read += bytes_read;
-      remaining -= bytes_read;
-    }
-  }
-  ASSERT(remaining >= 0);
-  return remaining == 0;
-}
-
-
-void DebuggerConnectionImpl::HandleEvent(struct kevent* event) {
-  intptr_t ident = event->ident;
-  if (ident == DebuggerConnectionHandler::listener_fd_) {
-    if (DebuggerConnectionHandler::IsConnected()) {
-      FATAL("Cannot connect to more than one debugger.\n");
-    }
-    intptr_t fd = ServerSocket::Accept(ident);
-    if (fd < 0) {
-      FATAL("Accepting new debugger connection failed.\n");
-    }
-    FDUtils::SetBlocking(fd);
-    DebuggerConnectionHandler::AcceptDbgConnection(fd);
-
-    /* For now, don't poll the debugger connection.
-    struct kevent ev_add;
-    EV_SET(&ev_add, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
-    int status =
-        TEMP_FAILURE_RETRY(kevent(kqueue_fd_, &ev_add, 1, NULL, 0, NULL));
-    if (status == -1) {
-      const int kBufferSize = 1024;
-      char error_message[kBufferSize];
-      strerror_r(errno, error_message, kBufferSize);
-      FATAL1("Failed adding debugger socket to kqueue: %s\n", error_message);
-    }
-    */
-  } else if (ident == wakeup_fds_[0]) {
-    Message msg;
-    if (ReceiveMessage(&msg)) {
-      Log::Print("Received sync message id %d.\n", msg.msg_id);
-    }
-  } else {
-    Log::Print("unexpected: receiving debugger connection event.\n");
-    UNIMPLEMENTED();
-  }
-}
-
-
-void DebuggerConnectionImpl::Handler(uword args) {
-  static const int kMaxEvents = 4;
-  struct kevent events[kMaxEvents];
-
-  while (1) {
-    // Wait indefinitely for an event.
-    int result = TEMP_FAILURE_RETRY(
-        kevent(kqueue_fd_, NULL, 0, events, kMaxEvents, NULL));
-    if (result == -1) {
-      const int kBufferSize = 1024;
-      char error_message[kBufferSize];
-      strerror_r(errno, error_message, kBufferSize);
-      FATAL1("kevent failed %s\n", error_message);
-    } else {
-      ASSERT(result <= kMaxEvents);
-      for (int i = 0; i < result; i++) {
-        HandleEvent(&events[i]);
-      }
-    }
-  }
-  Log::Print("shutting down debugger thread\n");
-}
-
-
-void DebuggerConnectionImpl::SetupPollQueue() {
-  int result;
-  result = NO_RETRY_EXPECTED(pipe(wakeup_fds_));
-  if (result != 0) {
-    FATAL1("Pipe creation failed with error %d\n", result);
-  }
-  FDUtils::SetNonBlocking(wakeup_fds_[0]);
-
-  kqueue_fd_ = NO_RETRY_EXPECTED(kqueue());
-  if (kqueue_fd_ == -1) {
-    FATAL("Failed creating kqueue\n");
-  }
-  // Register the wakeup_fd_ with the kqueue.
-  struct kevent event;
-  EV_SET(&event, wakeup_fds_[0], EVFILT_READ, EV_ADD, 0, 0, NULL);
-  int status = NO_RETRY_EXPECTED(kevent(kqueue_fd_, &event, 1, NULL, 0, NULL));
-  if (status == -1) {
-    const int kBufferSize = 1024;
-    char error_message[kBufferSize];
-    strerror_r(errno, error_message, kBufferSize);
-    FATAL1("Failed adding wakeup pipe fd to kqueue: %s\n", error_message);
-  }
-
-  // Register the listening socket.
-  EV_SET(&event, DebuggerConnectionHandler::listener_fd_,
-         EVFILT_READ, EV_ADD, 0, 0, NULL);
-  status = NO_RETRY_EXPECTED(kevent(kqueue_fd_, &event, 1, NULL, 0, NULL));
-  if (status == -1) {
-    const int kBufferSize = 1024;
-    char error_message[kBufferSize];
-    strerror_r(errno, error_message, kBufferSize);
-    FATAL1("Failed adding listener socket to kqueue: %s\n", error_message);
-  }
-}
-
-
-void DebuggerConnectionImpl::StartHandler(int port_number) {
-  ASSERT(DebuggerConnectionHandler::listener_fd_ != -1);
-  SetupPollQueue();
-  int result = Thread::Start(&DebuggerConnectionImpl::Handler, 0);
-  if (result != 0) {
-    FATAL1("Failed to start debugger connection handler thread: %d\n", result);
-  }
-}
-
-
-intptr_t DebuggerConnectionImpl::Send(intptr_t socket,
-                                      const char* buf,
-                                      int len) {
-  return TEMP_FAILURE_RETRY(write(socket, buf, len));
-}
-
-
-intptr_t DebuggerConnectionImpl::Receive(intptr_t socket, char* buf, int len) {
-  return TEMP_FAILURE_RETRY(read(socket, buf, len));
-}
-
-}  // namespace bin
-}  // namespace dart
-
-#endif  // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/dbg_connection_macos.h b/runtime/bin/dbg_connection_macos.h
deleted file mode 100644
index 064238e..0000000
--- a/runtime/bin/dbg_connection_macos.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef BIN_DBG_CONNECTION_MACOS_H_
-#define BIN_DBG_CONNECTION_MACOS_H_
-
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <sys/socket.h>
-
-
-namespace dart {
-namespace bin {
-
-class DebuggerConnectionImpl {
- public:
-  static void StartHandler(int port_number);
-  static void StopHandler(intptr_t debug_fd) {}
-  static intptr_t Send(intptr_t socket, const char* buf, int len);
-  static intptr_t Receive(intptr_t socket, char* buf, int len);
-
- private:
-  enum MessageType {
-    kAddDbgFd = 1,
-    kRemoveDbgFd,
-    kQuit
-  };
-
-  struct Message {
-    MessageType msg_id;
-  };
-
-  static void SendMessage(MessageType id);
-  static bool ReceiveMessage(Message* msg);
-
-  static void SetupPollQueue();
-  static void HandleEvent(struct kevent* event);
-  static void Handler(uword args);
-
-
-
-  // File descriptors for pipes used to communicate with the debugger thread.
-  static int wakeup_fds_[2];
-  // File descriptor for the polling queue.
-  static int kqueue_fd_;
-};
-
-}  // namespace bin
-}  // namespace dart
-
-#endif  // BIN_DBG_CONNECTION_MACOS_H_
diff --git a/runtime/bin/dbg_connection_win.cc b/runtime/bin/dbg_connection_win.cc
deleted file mode 100644
index 49bc4a9..0000000
--- a/runtime/bin/dbg_connection_win.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "platform/globals.h"
-#if defined(TARGET_OS_WINDOWS)
-
-#include "bin/dbg_connection.h"
-
-#include "bin/eventhandler.h"
-#include "bin/lockers.h"
-#include "bin/log.h"
-#include "bin/thread.h"
-
-namespace dart {
-namespace bin {
-
-Monitor* DebuggerConnectionImpl::handler_monitor_ = new Monitor();
-ThreadId DebuggerConnectionImpl::handler_thread_id_ = Thread::kInvalidThreadId;
-bool DebuggerConnectionImpl::handler_thread_running_ = false;
-
-
-void DebuggerConnectionImpl::NotifyThreadStarted() {
-  MonitorLocker ml(handler_monitor_);
-  ASSERT(!handler_thread_running_);
-  ASSERT(handler_thread_id_ == Thread::kInvalidThreadId);
-  handler_thread_running_ = true;
-  handler_thread_id_ = Thread::GetCurrentThreadId();
-  ml.Notify();
-}
-
-
-void DebuggerConnectionImpl::WaitForThreadStarted() {
-  MonitorLocker ml(handler_monitor_);
-  while (!handler_thread_running_) {
-    ml.Wait();
-  }
-  ASSERT(handler_thread_id_ != Thread::kInvalidThreadId);
-}
-
-
-void DebuggerConnectionImpl::NotifyThreadFinished() {
-  MonitorLocker ml(handler_monitor_);
-  ASSERT(handler_thread_running_);
-  ASSERT(handler_thread_id_ != Thread::kInvalidThreadId);
-  handler_thread_running_ = false;
-  ml.Notify();
-}
-
-
-void DebuggerConnectionImpl::WaitForThreadFinished() {
-  MonitorLocker ml(handler_monitor_);
-  while (handler_thread_running_) {
-    ml.Wait();
-  }
-  ASSERT(handler_thread_id_ != Thread::kInvalidThreadId);
-  Thread::Join(handler_thread_id_);
-  handler_thread_id_ = Thread::kInvalidThreadId;
-}
-
-
-void DebuggerConnectionImpl::ThreadEntry(uword args) {
-  NotifyThreadStarted();
-  ListenSocket* listen_socket =
-      reinterpret_cast<ListenSocket*>(DebuggerConnectionHandler::listener_fd_);
-  SOCKET client_socket = accept(listen_socket->socket(), NULL, NULL);
-  if (client_socket == INVALID_SOCKET) {
-    FATAL("Accepting new debugger connection failed.\n");
-  }
-  ClientSocket* socket = new ClientSocket(client_socket);
-  DebuggerConnectionHandler::AcceptDbgConnection(
-      reinterpret_cast<intptr_t>(socket));
-  NotifyThreadFinished();
-}
-
-
-void DebuggerConnectionImpl::StartHandler(int port_number) {
-  ASSERT(DebuggerConnectionHandler::listener_fd_ != -1);
-  int result = Thread::Start(&DebuggerConnectionImpl::ThreadEntry, 0);
-  if (result != 0) {
-    FATAL1("Failed to start debugger connection handler thread: %d\n", result);
-  }
-  WaitForThreadStarted();
-}
-
-
-void DebuggerConnectionImpl::StopHandler(intptr_t debug_fd) {
-  Send(debug_fd, NULL, 0);
-  WaitForThreadFinished();
-}
-
-
-intptr_t DebuggerConnectionImpl::Send(intptr_t socket,
-                                      const char* buf,
-                                      int len) {
-  ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(socket);
-  return send(client_socket->socket(), buf, len, 0);
-}
-
-
-intptr_t DebuggerConnectionImpl::Receive(intptr_t socket, char* buf, int len) {
-  ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(socket);
-  return recv(client_socket->socket(), buf, len, 0);
-}
-
-}  // namespace bin
-}  // namespace dart
-
-#endif  // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/dbg_connection_win.h b/runtime/bin/dbg_connection_win.h
deleted file mode 100644
index 8f5d0c6..0000000
--- a/runtime/bin/dbg_connection_win.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef BIN_DBG_CONNECTION_WIN_H_
-#define BIN_DBG_CONNECTION_WIN_H_
-
-#include "bin/lockers.h"
-#include "bin/thread.h"
-
-namespace dart {
-namespace bin {
-
-class DebuggerConnectionImpl {
- public:
-  static void StartHandler(int port_number);
-  static void StopHandler(intptr_t debug_fd);
-  static intptr_t Send(intptr_t socket, const char* buf, int len);
-  static intptr_t Receive(intptr_t socket, char* buf, int len);
-
- private:
-  static void ThreadEntry(uword args);
-  static void NotifyThreadStarted();
-  static void WaitForThreadStarted();
-  static void NotifyThreadFinished();
-  static void WaitForThreadFinished();
-
-  static Monitor* handler_monitor_;
-  static ThreadId handler_thread_id_;
-  static bool handler_thread_running_;
-};
-
-}  // namespace bin
-}  // namespace dart
-
-#endif  // BIN_DBG_CONNECTION_WIN_H_
diff --git a/runtime/bin/dbg_message.cc b/runtime/bin/dbg_message.cc
deleted file mode 100644
index d0f13d7..0000000
--- a/runtime/bin/dbg_message.cc
+++ /dev/null
@@ -1,1431 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "bin/dbg_connection.h"
-#include "bin/dbg_message.h"
-#include "bin/dartutils.h"
-#include "bin/lockers.h"
-#include "bin/thread.h"
-#include "bin/utils.h"
-
-#include "platform/globals.h"
-#include "platform/json.h"
-#include "platform/utils.h"
-
-#include "include/dart_api.h"
-
-
-namespace dart {
-namespace bin {
-
-bool MessageParser::IsValidMessage() const {
-  if (buf_length_ == 0) {
-    return false;
-  }
-  dart::JSONReader msg_reader(buf_);
-  return msg_reader.EndOfObject() != NULL;
-}
-
-
-int MessageParser::MessageId() const {
-  dart::JSONReader r(buf_);
-  r.Seek("id");
-  if (r.Type() == dart::JSONReader::kInteger) {
-    return atoi(r.ValueChars());
-  } else {
-    return -1;
-  }
-}
-
-
-const char* MessageParser::Params() const {
-  dart::JSONReader r(buf_);
-  r.Seek("params");
-  if (r.Type() == dart::JSONReader::kObject) {
-    return r.ValueChars();
-  } else {
-    return NULL;
-  }
-}
-
-
-bool MessageParser::HasParam(const char* name) const {
-  const char* params = Params();
-  ASSERT(params != NULL);
-  dart::JSONReader r(params);
-  return r.Seek(name);
-}
-
-
-intptr_t MessageParser::GetIntParam(const char* name) const {
-  const char* params = Params();
-  ASSERT(params != NULL);
-  dart::JSONReader r(params);
-  r.Seek(name);
-  ASSERT(r.Type() == dart::JSONReader::kInteger);
-  return strtol(r.ValueChars(), NULL, 10);
-}
-
-
-int64_t MessageParser::GetInt64Param(const char* name) const {
-  const char* params = Params();
-  ASSERT(params != NULL);
-  dart::JSONReader r(params);
-  r.Seek(name);
-  ASSERT(r.Type() == dart::JSONReader::kInteger);
-  return strtoll(r.ValueChars(), NULL, 10);
-}
-
-
-intptr_t MessageParser::GetOptIntParam(const char* name,
-                                       intptr_t default_val) const {
-  const char* params = Params();
-  ASSERT(params != NULL);
-  dart::JSONReader r(params);
-  r.Seek(name);
-  if (r.Type() == dart::JSONReader::kInteger) {
-    return strtol(r.ValueChars(), NULL, 10);
-  } else {
-    return default_val;
-  }
-}
-
-
-static const char* GetStringChars(Dart_Handle str) {
-  ASSERT(Dart_IsString(str));
-  const char* chars;
-  Dart_Handle res = Dart_StringToCString(str, &chars);
-  ASSERT(!Dart_IsError(res));
-  return chars;
-}
-
-
-static int64_t GetIntValue(Dart_Handle int_handle) {
-  int64_t int64_val = -1;
-  ASSERT(Dart_IsInteger(int_handle));
-  Dart_Handle res = Dart_IntegerToInt64(int_handle, &int64_val);
-  ASSERT_NOT_ERROR(res);
-  return int64_val;
-}
-
-
-char* MessageParser::GetStringParam(const char* name) const {
-  const char* params = Params();
-  ASSERT(params != NULL);
-  dart::JSONReader pr(params);
-  pr.Seek(name);
-  if (pr.Type() != dart::JSONReader::kString) {
-    return NULL;
-  }
-  intptr_t buflen = pr.ValueLen() + 1;
-  char* param_chars = reinterpret_cast<char*>(malloc(buflen));
-  pr.GetDecodedValueChars(param_chars, buflen);
-  return param_chars;
-}
-
-
-static void FormatEncodedCharsTrunc(dart::TextBuffer* buf,
-                                    Dart_Handle str,
-                                    intptr_t max_chars) {
-  intptr_t str_len = 0;
-  Dart_Handle res = Dart_StringLength(str, &str_len);
-  ASSERT_NOT_ERROR(res);
-  intptr_t num_chars = (str_len > max_chars) ? max_chars : str_len;
-  uint16_t* codeunits =
-      reinterpret_cast<uint16_t*>(malloc(num_chars * sizeof(uint16_t)));
-  ASSERT(codeunits != NULL);
-  intptr_t actual_len = num_chars;
-  res = Dart_StringToUTF16(str, codeunits, &actual_len);
-  ASSERT_NOT_ERROR(res);
-  ASSERT(num_chars == actual_len);
-  for (int i = 0; i < num_chars; i++) {
-    buf->EscapeAndAddCodeUnit(codeunits[i]);
-  }
-  if (str_len > max_chars) {
-    buf->Printf("...");
-  }
-  free(codeunits);
-}
-
-
-static void FormatEncodedChars(dart::TextBuffer* buf, Dart_Handle str) {
-  intptr_t str_len = 0;
-  Dart_Handle res = Dart_StringLength(str, &str_len);
-  ASSERT_NOT_ERROR(res);
-  uint16_t* codeunits =
-      reinterpret_cast<uint16_t*>(malloc(str_len * sizeof(uint16_t)));
-  ASSERT(codeunits != NULL);
-  intptr_t actual_len = str_len;
-  res = Dart_StringToUTF16(str, codeunits, &actual_len);
-  ASSERT_NOT_ERROR(res);
-  ASSERT(str_len == actual_len);
-  for (int i = 0; i < str_len; i++) {
-    buf->EscapeAndAddCodeUnit(codeunits[i]);
-  }
-  free(codeunits);
-}
-
-
-static void FormatEncodedString(dart::TextBuffer* buf, Dart_Handle str) {
-  buf->AddChar('\"');
-  FormatEncodedChars(buf, str);
-  buf->AddChar('\"');
-}
-
-
-static void FormatTextualValue(dart::TextBuffer* buf,
-                               Dart_Handle object,
-                               intptr_t max_chars,
-                               bool expand_list);
-
-
-static void FormatTextualListValue(dart::TextBuffer* buf,
-                                   Dart_Handle list,
-                                   intptr_t max_chars) {
-  intptr_t len = 0;
-  Dart_Handle res = Dart_ListLength(list, &len);
-  ASSERT_NOT_ERROR(res);
-  const intptr_t initial_buffer_length = buf->length();
-  // Maximum number of characters we print for array elements.
-  const intptr_t max_buffer_length = initial_buffer_length + max_chars;
-  buf->Printf("[");
-  for (int i = 0; i < len; i++) {
-    if (i > 0) {
-      buf->Printf(", ");
-    }
-    Dart_Handle elem = Dart_ListGetAt(list, i);
-    const intptr_t max_element_chars = 50;
-    FormatTextualValue(buf, elem, max_element_chars, false);
-    if (buf->length() > max_buffer_length) {
-      buf->Printf(", ...");
-      break;
-    }
-  }
-  buf->Printf("]");
-}
-
-
-static void FormatTextualValue(dart::TextBuffer* buf,
-                               Dart_Handle object,
-                               intptr_t max_chars,
-                               bool expand_list) {
-  ASSERT(!Dart_IsError(object));
-  if (Dart_IsList(object)) {
-    if (expand_list) {
-      FormatTextualListValue(buf, object, max_chars);
-    } else {
-      buf->Printf("[...]");
-    }
-  } else if (Dart_IsNull(object)) {
-    buf->Printf("null");
-  } else if (Dart_IsString(object)) {
-    buf->Printf("\\\"");
-    FormatEncodedCharsTrunc(buf, object, max_chars);
-    buf->Printf("\\\"");
-  } else if (Dart_IsNumber(object) || Dart_IsBoolean(object)) {
-    Dart_Handle text = Dart_ToString(object);
-    ASSERT(!Dart_IsNull(text) && !Dart_IsError(text));
-    FormatEncodedCharsTrunc(buf, text, max_chars);
-  } else {
-    Dart_Handle type = Dart_InstanceGetType(object);
-    ASSERT_NOT_ERROR(type);
-    type = Dart_ToString(type);
-    ASSERT_NOT_ERROR(type);
-    buf->Printf("object of type ");
-    FormatEncodedCharsTrunc(buf, type, max_chars);
-  }
-}
-
-
-static void FormatValue(dart::TextBuffer* buf, Dart_Handle object) {
-  bool print_text_field = true;
-  if (Dart_IsNumber(object)) {
-    buf->Printf("\"kind\":\"number\"");
-  } else if (Dart_IsString(object)) {
-    buf->Printf("\"kind\":\"string\"");
-  } else if (Dart_IsBoolean(object)) {
-    buf->Printf("\"kind\":\"boolean\"");
-  } else if (Dart_IsList(object)) {
-    intptr_t len = 0;
-    Dart_Handle res = Dart_ListLength(object, &len);
-    ASSERT_NOT_ERROR(res);
-    buf->Printf("\"kind\":\"list\",\"length\":%" Pd "", len);
-  } else if (Dart_IsClosure(object)) {
-    Dart_Handle name, signature;
-    Dart_CodeLocation location;
-    Dart_Handle res = Dart_GetClosureInfo(object, &name, &signature, &location);
-    ASSERT_NOT_ERROR(res);
-    buf->Printf("\"kind\":\"function\",\"name\":\"%s\"", GetStringChars(name));
-    buf->Printf(",\"signature\":\"%s\"", GetStringChars(signature));
-    if (!Dart_IsNull(location.script_url)) {
-      ASSERT(Dart_IsString(location.script_url));
-      buf->Printf(",\"location\": { \"url\":");
-      FormatEncodedString(buf, location.script_url);
-      buf->Printf(",\"libraryId\":%d,", location.library_id);
-      buf->Printf("\"tokenOffset\":%d}", location.token_pos);
-    }
-    print_text_field = false;
-  } else {
-    buf->Printf("\"kind\":\"object\"");
-    intptr_t class_id = 0;
-    Dart_Handle res = Dart_GetObjClassId(object, &class_id);
-    if (!Dart_IsError(res)) {
-      buf->Printf(",\"classId\":%" Pd "", class_id);
-    }
-  }
-  if (print_text_field) {
-    buf->Printf(",\"text\":\"");
-    const intptr_t max_chars = 1024;
-    FormatTextualValue(buf, object, max_chars, true);
-    buf->Printf("\"");
-  }
-}
-
-
-static void FormatValueObj(dart::TextBuffer* buf, Dart_Handle object) {
-  buf->Printf("{");
-  FormatValue(buf, object);
-  buf->Printf("}");
-}
-
-
-static void FormatRemoteObj(dart::TextBuffer* buf, Dart_Handle object) {
-  intptr_t obj_id = Dart_CacheObject(object);
-  ASSERT(obj_id >= 0);
-  buf->Printf("{\"objectId\":%" Pd ",", obj_id);
-  FormatValue(buf, object);
-  buf->Printf("}");
-}
-
-
-static void FormatNamedValue(dart::TextBuffer* buf,
-                             Dart_Handle object_name,
-                             Dart_Handle object) {
-  ASSERT(Dart_IsString(object_name));
-  buf->Printf("{\"name\":\"%s\",", GetStringChars(object_name));
-  buf->Printf("\"value\":");
-  FormatRemoteObj(buf, object);
-  buf->Printf("}");
-}
-
-
-static void FormatNamedValueList(dart::TextBuffer* buf,
-                                 Dart_Handle obj_list) {
-  ASSERT(Dart_IsList(obj_list));
-  intptr_t list_length = 0;
-  Dart_Handle res = Dart_ListLength(obj_list, &list_length);
-  ASSERT_NOT_ERROR(res);
-  ASSERT(list_length % 2 == 0);
-  buf->Printf("[");
-  for (int i = 0; i + 1 < list_length; i += 2) {
-    Dart_Handle name_handle = Dart_ListGetAt(obj_list, i);
-    ASSERT_NOT_ERROR(name_handle);
-    Dart_Handle value_handle = Dart_ListGetAt(obj_list, i + 1);
-    ASSERT_NOT_ERROR(value_handle);
-    if (i > 0) {
-      buf->Printf(",");
-    }
-    FormatNamedValue(buf, name_handle, value_handle);
-  }
-  buf->Printf("]");
-}
-
-
-static const char* FormatClassProps(dart::TextBuffer* buf,
-                                    intptr_t cls_id) {
-  Dart_Handle name, static_fields;
-  intptr_t super_id = -1;
-  intptr_t library_id = -1;
-  Dart_Handle res =
-      Dart_GetClassInfo(cls_id, &name, &library_id, &super_id, &static_fields);
-  RETURN_IF_ERROR(res);
-  RETURN_IF_ERROR(name);
-  buf->Printf("{\"name\":\"%s\",", GetStringChars(name));
-  if (super_id > 0) {
-    buf->Printf("\"superclassId\":%" Pd ",", super_id);
-  }
-  buf->Printf("\"libraryId\":%" Pd ",", library_id);
-  RETURN_IF_ERROR(static_fields);
-  buf->Printf("\"fields\":");
-  FormatNamedValueList(buf, static_fields);
-  buf->Printf("}");
-  return NULL;
-}
-
-
-static const char* FormatLibraryProps(dart::TextBuffer* buf,
-                                      intptr_t lib_id) {
-  Dart_Handle url = Dart_GetLibraryURL(lib_id);
-  RETURN_IF_ERROR(url);
-  buf->Printf("{\"url\":");
-  FormatEncodedString(buf, url);
-
-  // Whether debugging is enabled.
-  bool is_debuggable = false;
-  Dart_Handle res = Dart_GetLibraryDebuggable(lib_id, &is_debuggable);
-  RETURN_IF_ERROR(res);
-  buf->Printf(",\"debuggingEnabled\":%s",
-              is_debuggable ? "\"true\"" : "\"false\"");
-
-  // Imports and prefixes.
-  Dart_Handle import_list = Dart_GetLibraryImports(lib_id);
-  RETURN_IF_ERROR(import_list);
-  ASSERT(Dart_IsList(import_list));
-  intptr_t list_length = 0;
-  res = Dart_ListLength(import_list, &list_length);
-  RETURN_IF_ERROR(res);
-  buf->Printf(",\"imports\":[");
-  for (intptr_t i = 0; i + 1 < list_length; i += 2) {
-    Dart_Handle lib_id = Dart_ListGetAt(import_list, i + 1);
-    ASSERT_NOT_ERROR(lib_id);
-    buf->Printf("%s{\"libraryId\":%" Pd64 ",",
-                (i > 0) ? ",": "",
-                GetIntValue(lib_id));
-
-    Dart_Handle name = Dart_ListGetAt(import_list, i);
-    ASSERT_NOT_ERROR(name);
-    buf->Printf("\"prefix\":\"%s\"}",
-                Dart_IsNull(name) ? "" : GetStringChars(name));
-  }
-  buf->Printf("],");
-
-  // Global variables in the library.
-  Dart_Handle global_vars = Dart_GetLibraryFields(lib_id);
-  RETURN_IF_ERROR(global_vars);
-  buf->Printf("\"globals\":");
-  FormatNamedValueList(buf, global_vars);
-  buf->Printf("}");
-  return NULL;
-}
-
-
-static const char* FormatObjProps(dart::TextBuffer* buf,
-                                  Dart_Handle object) {
-  intptr_t class_id;
-  if (Dart_IsNull(object)) {
-    buf->Printf("{\"classId\":-1,\"fields\":[]}");
-    return NULL;
-  }
-  Dart_Handle res = Dart_GetObjClassId(object, &class_id);
-  RETURN_IF_ERROR(res);
-  buf->Printf("{\"classId\": %" Pd ",", class_id);
-  buf->Printf("\"kind\":\"object\",\"fields\":");
-  Dart_Handle fields = Dart_GetInstanceFields(object);
-  RETURN_IF_ERROR(fields);
-  FormatNamedValueList(buf, fields);
-  buf->Printf("}");
-  return NULL;
-}
-
-
-static const char* FormatListSlice(dart::TextBuffer* buf,
-                                   Dart_Handle list,
-                                   intptr_t list_length,
-                                   intptr_t index,
-                                   intptr_t slice_length) {
-  intptr_t end_index = index + slice_length;
-  ASSERT(end_index <= list_length);
-  buf->Printf("{\"index\":%" Pd ",", index);
-  buf->Printf("\"length\":%" Pd ",", slice_length);
-  buf->Printf("\"elements\":[");
-  for (intptr_t i = index; i < end_index; i++) {
-    Dart_Handle value = Dart_ListGetAt(list, i);
-    if (i > index) {
-      buf->Printf(",");
-    }
-    FormatValueObj(buf, value);
-  }
-  buf->Printf("]}");
-  return NULL;
-}
-
-
-static void FormatLocationFromTrace(dart::TextBuffer* msg,
-                                    Dart_StackTrace trace,
-                                    const char* prefix) {
-  intptr_t trace_len = 0;
-  Dart_Handle res = Dart_StackTraceLength(trace, &trace_len);
-  ASSERT_NOT_ERROR(res);
-  if (trace_len == 0) {
-    return;
-  }
-  Dart_ActivationFrame frame;
-  res = Dart_GetActivationFrame(trace, 0, &frame);
-  ASSERT_NOT_ERROR(res);
-  Dart_CodeLocation location;
-  res = Dart_ActivationFrameGetLocation(frame, NULL, NULL, &location);
-  ASSERT_NOT_ERROR(res);
-  if (!Dart_IsNull(location.script_url)) {
-    ASSERT(Dart_IsString(location.script_url));
-    msg->Printf("%s\"location\": { \"url\":", prefix);
-    FormatEncodedString(msg, location.script_url);
-    msg->Printf(",\"libraryId\":%d,", location.library_id);
-    msg->Printf("\"tokenOffset\":%d}", location.token_pos);
-  }
-}
-
-
-static void FormatCallFrames(dart::TextBuffer* msg, Dart_StackTrace trace) {
-  intptr_t trace_len = 0;
-  Dart_Handle res = Dart_StackTraceLength(trace, &trace_len);
-  ASSERT_NOT_ERROR(res);
-  msg->Printf("\"callFrames\" : [ ");
-  for (int i = 0; i < trace_len; i++) {
-    Dart_ActivationFrame frame;
-    res = Dart_GetActivationFrame(trace, i, &frame);
-    ASSERT_NOT_ERROR(res);
-    Dart_Handle func_name;
-    Dart_Handle func;
-    Dart_CodeLocation location;
-    res = Dart_ActivationFrameGetLocation(frame, &func_name, &func, &location);
-    ASSERT_NOT_ERROR(res);
-    ASSERT(Dart_IsString(func_name));
-    msg->Printf("%s{\"functionName\":", (i > 0) ? "," : "");
-    FormatEncodedString(msg, func_name);
-    if (!Dart_IsNull(location.script_url)) {
-      ASSERT(Dart_IsString(location.script_url));
-      msg->Printf(",\"location\": { \"url\":");
-      FormatEncodedString(msg, location.script_url);
-      msg->Printf(",\"libraryId\":%d,", location.library_id);
-      msg->Printf("\"tokenOffset\":%d}", location.token_pos);
-    }
-    ASSERT_NOT_ERROR(func);
-    Dart_Handle origin = Dart_GetFunctionOrigin(func);
-    ASSERT_NOT_ERROR(origin);
-    if (Dart_IsInteger(origin)) {
-      int64_t class_id = GetIntValue(origin);
-      msg->Printf(",\"classId\":%" Pd64 "", class_id);
-    }
-    Dart_Handle locals = Dart_GetLocalVariables(frame);
-    ASSERT_NOT_ERROR(locals);
-    msg->Printf(",\"locals\":");
-    FormatNamedValueList(msg, locals);
-    msg->Printf("}");
-  }
-  msg->Printf("]");
-}
-
-
-typedef bool (*CommandHandler)(DbgMessage* msg);
-
-struct JSONDebuggerCommand {
-  const char* cmd_string;
-  CommandHandler handler_function;
-};
-
-
-static JSONDebuggerCommand debugger_commands[] = {
-  { "resume", DbgMessage::HandleResumeCmd },
-  { "stepInto", DbgMessage::HandleStepIntoCmd },
-  { "stepOut", DbgMessage::HandleStepOutCmd },
-  { "stepOver", DbgMessage::HandleStepOverCmd },
-  { "getLibraries", DbgMessage::HandleGetLibrariesCmd },
-  { "getClassProperties", DbgMessage::HandleGetClassPropsCmd },
-  { "getLibraryProperties", DbgMessage::HandleGetLibPropsCmd },
-  { "setLibraryProperties", DbgMessage::HandleSetLibPropsCmd },
-  { "evaluateExpr", DbgMessage::HandleEvaluateExprCmd },
-  { "getObjectProperties", DbgMessage::HandleGetObjPropsCmd },
-  { "getListElements", DbgMessage::HandleGetListCmd },
-  { "getGlobalVariables", DbgMessage::HandleGetGlobalsCmd },
-  { "getScriptURLs", DbgMessage::HandleGetScriptURLsCmd },
-  { "getScriptSource", DbgMessage::HandleGetSourceCmd },
-  { "getLineNumberTable", DbgMessage::HandleGetLineNumbersCmd },
-  { "getStackTrace", DbgMessage::HandleGetStackTraceCmd },
-  { "setBreakpoint", DbgMessage::HandleSetBpCmd },
-  { "setPauseOnException", DbgMessage::HandlePauseOnExcCmd },
-  { "removeBreakpoint", DbgMessage::HandleRemBpCmd },
-  { NULL, NULL }
-};
-
-
-bool DbgMessage::HandleMessage() {
-  // Dispatch to the appropriate handler for the command.
-  int max_index = (sizeof(debugger_commands) / sizeof(JSONDebuggerCommand));
-  ASSERT(cmd_idx_ < max_index);
-  return (*debugger_commands[cmd_idx_].handler_function)(this);
-}
-
-
-void DbgMessage::SendReply(dart::TextBuffer* reply) {
-  DebuggerConnectionHandler::SendMsg(debug_fd(), reply);
-}
-
-
-void DbgMessage::SendErrorReply(int msg_id, const char* err_msg) {
-  DebuggerConnectionHandler::SendError(debug_fd(), msg_id, err_msg);
-}
-
-
-bool DbgMessage::HandleResumeCmd(DbgMessage* in_msg) {
-  ASSERT(in_msg != NULL);
-  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
-  int msg_id = msg_parser.MessageId();
-  dart::TextBuffer msg(64);
-  msg.Printf("{ \"id\": %d }", msg_id);
-  in_msg->SendReply(&msg);
-  return true;
-}
-
-
-bool DbgMessage::HandleStepIntoCmd(DbgMessage* in_msg) {
-  Dart_Handle res = Dart_SetStepInto();
-  ASSERT_NOT_ERROR(res);
-  return HandleResumeCmd(in_msg);
-}
-
-
-bool DbgMessage::HandleStepOutCmd(DbgMessage* in_msg) {
-  Dart_Handle res = Dart_SetStepOut();
-  ASSERT_NOT_ERROR(res);
-  return HandleResumeCmd(in_msg);
-}
-
-
-bool DbgMessage::HandleStepOverCmd(DbgMessage* in_msg) {
-  Dart_Handle res = Dart_SetStepOver();
-  ASSERT_NOT_ERROR(res);
-  return HandleResumeCmd(in_msg);
-}
-
-
-bool DbgMessage::HandleGetLibrariesCmd(DbgMessage* in_msg) {
-  ASSERT(in_msg != NULL);
-  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
-  int msg_id = msg_parser.MessageId();
-  dart::TextBuffer msg(64);
-  msg.Printf("{ \"id\": %d, \"result\": { \"libraries\": [", msg_id);
-  Dart_Handle lib_ids = Dart_GetLibraryIds();
-  ASSERT_NOT_ERROR(lib_ids);
-  intptr_t num_libs;
-  Dart_Handle res = Dart_ListLength(lib_ids, &num_libs);
-  ASSERT_NOT_ERROR(res);
-  for (intptr_t i = 0; i < num_libs; i++) {
-    Dart_Handle lib_id_handle = Dart_ListGetAt(lib_ids, i);
-    ASSERT(Dart_IsInteger(lib_id_handle));
-    int64_t lib_id = GetIntValue(lib_id_handle);
-    ASSERT((lib_id >= kIntptrMin) && (lib_id <= kIntptrMax));
-    Dart_Handle lib_url = Dart_GetLibraryURL(static_cast<intptr_t>(lib_id));
-    ASSERT_NOT_ERROR(lib_url);
-    ASSERT(Dart_IsString(lib_url));
-    msg.Printf("%s{\"id\":%" Pd64 ",\"url\":", (i == 0) ? "" : ", ", lib_id);
-    FormatEncodedString(&msg, lib_url);
-    msg.Printf("}");
-  }
-  msg.Printf("]}}");
-  in_msg->SendReply(&msg);
-  return false;
-}
-
-
-bool DbgMessage::HandleGetClassPropsCmd(DbgMessage* in_msg) {
-  ASSERT(in_msg != NULL);
-  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
-  int msg_id = msg_parser.MessageId();
-  intptr_t cls_id = msg_parser.GetIntParam("classId");
-  dart::TextBuffer msg(64);
-  msg.Printf("{\"id\":%d, \"result\":", msg_id);
-  const char* err = FormatClassProps(&msg, cls_id);
-  if (err != NULL) {
-    in_msg->SendErrorReply(msg_id, err);
-    return false;
-  }
-  msg.Printf("}");
-  in_msg->SendReply(&msg);
-  return false;
-}
-
-
-bool DbgMessage::HandleGetLibPropsCmd(DbgMessage* in_msg) {
-  ASSERT(in_msg != NULL);
-  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
-  int msg_id = msg_parser.MessageId();
-  intptr_t lib_id = msg_parser.GetIntParam("libraryId");
-  dart::TextBuffer msg(64);
-  msg.Printf("{\"id\":%d, \"result\":", msg_id);
-  const char* err = FormatLibraryProps(&msg, lib_id);
-  if (err != NULL) {
-    in_msg->SendErrorReply(msg_id, err);
-    return false;
-  }
-  msg.Printf("}");
-  in_msg->SendReply(&msg);
-  return false;
-}
-
-
-bool DbgMessage::HandleSetLibPropsCmd(DbgMessage* in_msg) {
-  ASSERT(in_msg != NULL);
-  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
-  int msg_id = msg_parser.MessageId();
-  intptr_t lib_id = msg_parser.GetIntParam("libraryId");
-  const char* enable_request = msg_parser.GetStringParam("debuggingEnabled");
-  bool enable;
-  if (strcmp(enable_request, "true") == 0) {
-    enable = true;
-  } else if (strcmp(enable_request, "false") == 0) {
-    enable = false;
-  } else {
-    in_msg->SendErrorReply(msg_id, "illegal argument for 'debuggingEnabled'");
-    return false;
-  }
-  Dart_Handle res = Dart_SetLibraryDebuggable(lib_id, enable);
-  if (Dart_IsError(res)) {
-    in_msg->SendErrorReply(msg_id, Dart_GetError(res));
-    return false;
-  }
-  bool enabled = false;
-  res = Dart_GetLibraryDebuggable(lib_id, &enabled);
-  if (Dart_IsError(res)) {
-    in_msg->SendErrorReply(msg_id, Dart_GetError(res));
-    return false;
-  }
-  dart::TextBuffer msg(64);
-  msg.Printf("{\"id\":%d, \"result\": {\"debuggingEnabled\": \"%s\"}}",
-             msg_id,
-             enabled ? "true" : "false");
-  in_msg->SendReply(&msg);
-  return false;
-}
-
-
-bool DbgMessage::HandleEvaluateExprCmd(DbgMessage* in_msg) {
-  ASSERT(in_msg != NULL);
-  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
-  int msg_id = msg_parser.MessageId();
-  Dart_Handle target = Dart_Null();
-  Dart_ActivationFrame frame = NULL;
-
-  if (msg_parser.HasParam("libraryId")) {
-    intptr_t lib_id = msg_parser.GetIntParam("libraryId");
-    target = Dart_GetLibraryFromId(lib_id);
-  } else if (msg_parser.HasParam("classId")) {
-    intptr_t cls_id = msg_parser.GetIntParam("classId");
-    target = Dart_GetClassFromId(cls_id);
-  } else if (msg_parser.HasParam("objectId")) {
-    intptr_t obj_id = msg_parser.GetIntParam("objectId");
-    target = Dart_GetCachedObject(obj_id);
-  } else if (msg_parser.HasParam("frameId")) {
-    intptr_t frame_index = msg_parser.GetIntParam("frameId");
-    Dart_Handle res;
-    Dart_StackTrace stack_trace;
-    res = Dart_GetStackTrace(&stack_trace);
-    ASSERT_NOT_ERROR(res);
-    intptr_t trace_length = 0;
-    res = Dart_StackTraceLength(stack_trace, &trace_length);
-    ASSERT_NOT_ERROR(res);
-    if (frame_index >= trace_length) {
-      in_msg->SendErrorReply(msg_id, "illegal frame index");
-      return false;
-    }
-    res = Dart_GetActivationFrame(stack_trace, frame_index, &frame);
-    ASSERT_NOT_ERROR(res);
-  } else {
-    in_msg->SendErrorReply(msg_id, "illegal evaluation target");
-    return false;
-  }
-
-  char* expr_chars = msg_parser.GetStringParam("expression");
-  Dart_Handle expr = Dart_NewStringFromCString(expr_chars);
-  if (Dart_IsError(expr)) {
-    in_msg->SendErrorReply(msg_id, Dart_GetError(expr));
-    return false;
-  }
-
-  Dart_Handle eval_result = Dart_Null();
-  if (frame != NULL) {
-    eval_result = Dart_ActivationFrameEvaluate(frame, expr);
-  } else {
-    if (Dart_IsError(target)) {
-      in_msg->SendErrorReply(msg_id, Dart_GetError(target));
-      return false;
-    }
-    eval_result = Dart_EvaluateExpr(target, expr);
-  }
-  if (Dart_IsError(eval_result)) {
-    in_msg->SendErrorReply(msg_id, Dart_GetError(eval_result));
-    return false;
-  }
-
-  dart::TextBuffer msg(64);
-  msg.Printf("{\"id\":%d, \"result\":", msg_id);
-  FormatRemoteObj(&msg, eval_result);
-  msg.Printf("}");
-  in_msg->SendReply(&msg);
-  return false;
-}
-
-
-bool DbgMessage::HandleGetObjPropsCmd(DbgMessage* in_msg) {
-  ASSERT(in_msg != NULL);
-  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
-  int msg_id = msg_parser.MessageId();
-  intptr_t obj_id = msg_parser.GetIntParam("objectId");
-  Dart_Handle obj = Dart_GetCachedObject(obj_id);
-  if (Dart_IsError(obj)) {
-    in_msg->SendErrorReply(msg_id, Dart_GetError(obj));
-    return false;
-  }
-  dart::TextBuffer msg(64);
-  msg.Printf("{\"id\":%d, \"result\":", msg_id);
-  const char* err = FormatObjProps(&msg, obj);
-  if (err != NULL) {
-    in_msg->SendErrorReply(msg_id, err);
-    return false;
-  }
-  msg.Printf("}");
-  in_msg->SendReply(&msg);
-  return false;
-}
-
-
-bool DbgMessage::HandleGetListCmd(DbgMessage* in_msg) {
-  const intptr_t kDefaultSliceLength = 100;
-  ASSERT(in_msg != NULL);
-  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
-  int msg_id = msg_parser.MessageId();
-  intptr_t obj_id = msg_parser.GetIntParam("objectId");
-  Dart_Handle list = Dart_GetCachedObject(obj_id);
-  if (Dart_IsError(list)) {
-    in_msg->SendErrorReply(msg_id, Dart_GetError(list));
-    return false;
-  }
-  if (!Dart_IsList(list)) {
-    in_msg->SendErrorReply(msg_id, "object is not a list");
-    return false;
-  }
-  intptr_t list_length = 0;
-  Dart_Handle res = Dart_ListLength(list, &list_length);
-  if (Dart_IsError(res)) {
-    in_msg->SendErrorReply(msg_id, Dart_GetError(res));
-    return false;
-  }
-
-  intptr_t index = msg_parser.GetIntParam("index");
-  if (index < 0) {
-    index = 0;
-  } else if (index > list_length) {
-    index = list_length;
-  }
-
-  // If no slice length is given, get only one element. If slice length
-  // is given as 0, get entire list.
-  intptr_t slice_length = msg_parser.GetOptIntParam("length", 1);
-  if (slice_length == 0) {
-    slice_length = list_length - index;
-  }
-  if ((index + slice_length) > list_length) {
-    slice_length = list_length - index;
-  }
-  ASSERT(slice_length >= 0);
-  if (slice_length > kDefaultSliceLength) {
-    slice_length = kDefaultSliceLength;
-  }
-  dart::TextBuffer msg(64);
-  msg.Printf("{\"id\":%d, \"result\":", msg_id);
-  if (slice_length == 1) {
-    Dart_Handle value = Dart_ListGetAt(list, index);
-    FormatRemoteObj(&msg, value);
-  } else {
-    FormatListSlice(&msg, list, list_length, index, slice_length);
-  }
-  msg.Printf("}");
-  in_msg->SendReply(&msg);
-  return false;
-}
-
-
-bool DbgMessage::HandleGetGlobalsCmd(DbgMessage* in_msg) {
-  ASSERT(in_msg != NULL);
-  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
-  int msg_id = msg_parser.MessageId();
-  intptr_t lib_id = msg_parser.GetIntParam("libraryId");
-  dart::TextBuffer msg(64);
-  msg.Printf("{\"id\":%d, \"result\": { \"globals\":", msg_id);
-  Dart_Handle globals = Dart_GetGlobalVariables(lib_id);
-  ASSERT_NOT_ERROR(globals);
-  FormatNamedValueList(&msg, globals);
-  msg.Printf("}}");
-  in_msg->SendReply(&msg);
-  return false;
-}
-
-
-bool DbgMessage::HandleGetScriptURLsCmd(DbgMessage* in_msg) {
-  ASSERT(in_msg != NULL);
-  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
-  int msg_id = msg_parser.MessageId();
-  dart::TextBuffer msg(64);
-  intptr_t lib_id = msg_parser.GetIntParam("libraryId");
-  Dart_Handle lib_url = Dart_GetLibraryURL(lib_id);
-  ASSERT_NOT_ERROR(lib_url);
-  Dart_Handle urls = Dart_GetScriptURLs(lib_url);
-  if (Dart_IsError(urls)) {
-    in_msg->SendErrorReply(msg_id, Dart_GetError(urls));
-    return false;
-  }
-  ASSERT(Dart_IsList(urls));
-  intptr_t num_urls = 0;
-  Dart_ListLength(urls, &num_urls);
-  msg.Printf("{ \"id\": %d, ", msg_id);
-  msg.Printf("\"result\": { \"urls\": [");
-  for (int i = 0; i < num_urls; i++) {
-    Dart_Handle script_url = Dart_ListGetAt(urls, i);
-    if (i > 0) {
-      msg.Printf(",");
-    }
-    FormatEncodedString(&msg, script_url);
-  }
-  msg.Printf("]}}");
-  in_msg->SendReply(&msg);
-  return false;
-}
-
-
-bool DbgMessage::HandleGetSourceCmd(DbgMessage* in_msg) {
-  ASSERT(in_msg != NULL);
-  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
-  int msg_id = msg_parser.MessageId();
-  dart::TextBuffer msg(64);
-  intptr_t lib_id = msg_parser.GetIntParam("libraryId");
-  char* url_chars = msg_parser.GetStringParam("url");
-  ASSERT(url_chars != NULL);
-  Dart_Handle url = DartUtils::NewString(url_chars);
-  ASSERT_NOT_ERROR(url);
-  free(url_chars);
-  url_chars = NULL;
-  Dart_Handle source = Dart_ScriptGetSource(lib_id, url);
-  if (Dart_IsError(source)) {
-    in_msg->SendErrorReply(msg_id, Dart_GetError(source));
-    return false;
-  }
-  msg.Printf("{ \"id\": %d, ", msg_id);
-  msg.Printf("\"result\": { \"text\": ");
-  FormatEncodedString(&msg, source);
-  msg.Printf("}}");
-  in_msg->SendReply(&msg);
-  return false;
-}
-
-
-bool DbgMessage::HandleGetLineNumbersCmd(DbgMessage* in_msg) {
-  ASSERT(in_msg != NULL);
-  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
-  int msg_id = msg_parser.MessageId();
-  dart::TextBuffer msg(64);
-  intptr_t lib_id = msg_parser.GetIntParam("libraryId");
-  char* url_chars = msg_parser.GetStringParam("url");
-  ASSERT(url_chars != NULL);
-  Dart_Handle url = DartUtils::NewString(url_chars);
-  ASSERT_NOT_ERROR(url);
-  free(url_chars);
-  url_chars = NULL;
-  Dart_Handle info = Dart_ScriptGetTokenInfo(lib_id, url);
-  if (Dart_IsError(info)) {
-    in_msg->SendErrorReply(msg_id, Dart_GetError(info));
-    return false;
-  }
-  ASSERT(Dart_IsList(info));
-  intptr_t info_len = 0;
-  Dart_Handle res = Dart_ListLength(info, &info_len);
-  ASSERT_NOT_ERROR(res);
-  msg.Printf("{ \"id\": %d, ", msg_id);
-  msg.Printf("\"result\": { \"lines\": [");
-  Dart_Handle elem;
-  intptr_t num_elems = 0;
-  for (intptr_t i = 0; i < info_len; i++) {
-    elem = Dart_ListGetAt(info, i);
-    if (Dart_IsNull(elem)) {
-      msg.Printf((i == 0) ? "[" : "], [");
-      num_elems = 0;
-    } else {
-      ASSERT(Dart_IsInteger(elem));
-      int64_t value = GetIntValue(elem);
-      if (num_elems == 0) {
-        msg.Printf("%" Pd64 "", value);
-      } else {
-        msg.Printf(",%" Pd64 "", value);
-      }
-      num_elems++;
-    }
-  }
-  msg.Printf("]]}}");
-  in_msg->SendReply(&msg);
-  return false;
-}
-
-
-bool DbgMessage::HandleGetStackTraceCmd(DbgMessage* in_msg) {
-  ASSERT(in_msg != NULL);
-  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
-  int msg_id = msg_parser.MessageId();
-  Dart_StackTrace trace;
-  Dart_Handle res = Dart_GetStackTrace(&trace);
-  ASSERT_NOT_ERROR(res);
-  dart::TextBuffer msg(128);
-  msg.Printf("{ \"id\": %d, \"result\": {", msg_id);
-  FormatCallFrames(&msg, trace);
-  msg.Printf("}}");
-  in_msg->SendReply(&msg);
-  return false;
-}
-
-
-bool DbgMessage::HandleSetBpCmd(DbgMessage* in_msg) {
-  ASSERT(in_msg != NULL);
-  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
-  int msg_id = msg_parser.MessageId();
-  char* url_chars = msg_parser.GetStringParam("url");
-  ASSERT(url_chars != NULL);
-  Dart_Handle url = DartUtils::NewString(url_chars);
-  ASSERT_NOT_ERROR(url);
-  free(url_chars);
-  url_chars = NULL;
-  intptr_t line_number = msg_parser.GetIntParam("line");
-  Dart_Handle bp_id = Dart_SetBreakpoint(url, line_number);
-  if (Dart_IsError(bp_id)) {
-    in_msg->SendErrorReply(msg_id, Dart_GetError(bp_id));
-    return false;
-  }
-  ASSERT(Dart_IsInteger(bp_id));
-  uint64_t bp_id_value;
-  Dart_Handle res = Dart_IntegerToUint64(bp_id, &bp_id_value);
-  ASSERT_NOT_ERROR(res);
-  dart::TextBuffer msg(64);
-  msg.Printf("{ \"id\": %d, \"result\": { \"breakpointId\": %" Pu64 " }}",
-             msg_id, bp_id_value);
-  in_msg->SendReply(&msg);
-  return false;
-}
-
-
-bool DbgMessage::HandlePauseOnExcCmd(DbgMessage* in_msg) {
-  ASSERT(in_msg != NULL);
-  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
-  int msg_id = msg_parser.MessageId();
-  char* exc_chars = msg_parser.GetStringParam("exceptions");
-  Dart_ExceptionPauseInfo info = kNoPauseOnExceptions;
-  if (strcmp(exc_chars, "none") == 0) {
-    info = kNoPauseOnExceptions;
-  } else if (strcmp(exc_chars, "all") == 0) {
-    info = kPauseOnAllExceptions;
-  } else if (strcmp(exc_chars, "unhandled") == 0) {
-    info = kPauseOnUnhandledExceptions;
-  } else {
-    in_msg->SendErrorReply(msg_id, "illegal value for parameter 'exceptions'");
-    return false;
-  }
-  Dart_Handle res = Dart_SetExceptionPauseInfo(info);
-  ASSERT_NOT_ERROR(res);
-  dart::TextBuffer msg(32);
-  msg.Printf("{ \"id\": %d }", msg_id);
-  in_msg->SendReply(&msg);
-  return false;
-}
-
-
-bool DbgMessage::HandleRemBpCmd(DbgMessage* in_msg) {
-  ASSERT(in_msg != NULL);
-  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
-  int msg_id = msg_parser.MessageId();
-  int bpt_id = msg_parser.GetIntParam("breakpointId");
-  Dart_Handle res = Dart_RemoveBreakpoint(bpt_id);
-  if (Dart_IsError(res)) {
-    in_msg->SendErrorReply(msg_id, Dart_GetError(res));
-    return false;
-  }
-  dart::TextBuffer msg(32);
-  msg.Printf("{ \"id\": %d }", msg_id);
-  in_msg->SendReply(&msg);
-  return false;
-}
-
-
-void DbgMsgQueue::AddMessage(int32_t cmd_idx,
-                             const char* start,
-                             const char* end,
-                             intptr_t debug_fd) {
-  if ((end > start) && ((end - start) < kMaxInt32)) {
-    MonitorLocker ml(&msg_queue_lock_);
-    DbgMessage* msg = new DbgMessage(cmd_idx, start, end, debug_fd);
-    if (msglist_head_ == NULL) {
-      ASSERT(msglist_tail_ == NULL);
-      msglist_head_ = msg;
-      msglist_tail_ = msg;
-      ml.Notify();
-    } else {
-      ASSERT(msglist_tail_ != NULL);
-      msglist_tail_->set_next(msg);
-      msglist_tail_ = msg;
-    }
-  }
-}
-
-
-void DbgMsgQueue::Notify() {
-  MonitorLocker ml(&msg_queue_lock_);
-  ml.Notify();
-}
-
-
-bool DbgMsgQueue::HandlePendingMessages() {
-  // Handle all available debug messages, up to a resume request.
-  bool resume_requested = false;
-  while (msglist_head_ != NULL && !resume_requested) {
-    ASSERT(msglist_tail_ != NULL);
-    DbgMessage* msg = msglist_head_;
-    msglist_head_ = msglist_head_->next();
-    if (msglist_head_ == NULL) {
-      msglist_tail_ = NULL;
-    }
-    resume_requested = msg->HandleMessage();
-    delete msg;
-  }
-  return resume_requested;
-}
-
-
-void DbgMsgQueue::MessageLoop() {
-  MonitorLocker ml(&msg_queue_lock_);
-  is_running_ = false;
-
-  // Request notification on isolate messages.  This allows us to
-  // respond to vm service messages while at breakpoint.
-  Dart_SetMessageNotifyCallback(DbgMsgQueueList::NotifyIsolate);
-
-  while (true) {
-    // Handle all available vm service messages, up to a resume
-    // request.
-    bool resume = false;
-    while (!resume && Dart_HasServiceMessages()) {
-      msg_queue_lock_.Exit();
-      resume = Dart_HandleServiceMessages();
-      msg_queue_lock_.Enter();
-    }
-    if (resume) {
-      break;
-    }
-
-    // Handle all available debug messages, up to a resume request.
-    if (HandlePendingMessages()) {
-      break;
-    }
-
-    // Wait for more debug or vm service messages.
-    Monitor::WaitResult res = ml.Wait();
-    ASSERT(res == Monitor::kNotified);
-  }
-  Dart_SetMessageNotifyCallback(NULL);
-  is_interrupted_ = false;
-  is_running_ = true;
-}
-
-
-void DbgMsgQueue::InterruptIsolate() {
-  Dart_Isolate isolate = Dart_GetIsolate(isolate_id_);
-  MonitorLocker ml(&msg_queue_lock_);
-  if (is_running_ && !is_interrupted_) {
-    is_interrupted_ = true;
-    Dart_InterruptIsolate(isolate);
-  }
-}
-
-
-void DbgMsgQueue::QueueOutputMsg(dart::TextBuffer* msg) {
-  queued_output_messages_.Printf("%s", msg->buf());
-}
-
-
-void DbgMsgQueue::SendQueuedMsgs() {
-  if (queued_output_messages_.length() > 0) {
-    DebuggerConnectionHandler::BroadcastMsg(&queued_output_messages_);
-    queued_output_messages_.Clear();
-  }
-}
-
-
-void DbgMsgQueue::SendBreakpointEvent(intptr_t bp_id,
-                                      const Dart_CodeLocation& location) {
-  dart::TextBuffer msg(128);
-  msg.Printf("{ \"event\": \"paused\", \"params\": { ");
-  msg.Printf("\"reason\": \"breakpoint\", ");
-  msg.Printf("\"isolateId\": %" Pd64 "", isolate_id_);
-  if (bp_id != ILLEGAL_BREAKPOINT_ID) {
-    msg.Printf(",\"breakpointId\": %" Pd "", bp_id);
-  }
-  if (!Dart_IsNull(location.script_url)) {
-    ASSERT(Dart_IsString(location.script_url));
-    msg.Printf(",\"location\": { \"url\":");
-    FormatEncodedString(&msg, location.script_url);
-    msg.Printf(",\"libraryId\":%d,", location.library_id);
-    msg.Printf("\"tokenOffset\":%d}", location.token_pos);
-  }
-  msg.Printf("}}");
-  DebuggerConnectionHandler::BroadcastMsg(&msg);
-}
-
-
-// TODO(hausner): Remove stack trace parameter once we remove the stack
-// trace from the paused event in the wire protocol.
-void DbgMsgQueue::SendExceptionEvent(Dart_Handle exception,
-                                     Dart_StackTrace stack_trace) {
-  intptr_t exception_id = Dart_CacheObject(exception);
-  ASSERT(exception_id >= 0);
-  dart::TextBuffer msg(128);
-  msg.Printf("{ \"event\": \"paused\", \"params\": {");
-  msg.Printf("\"reason\": \"exception\", ");
-  msg.Printf("\"isolateId\": %" Pd64 ", ", isolate_id_);
-  msg.Printf("\"exception\":");
-  FormatRemoteObj(&msg, exception);
-  FormatLocationFromTrace(&msg, stack_trace, ", ");
-  msg.Printf("}}");
-  DebuggerConnectionHandler::BroadcastMsg(&msg);
-}
-
-
-// TODO(hausner): Remove stack trace parameter once we remove the stack
-// trace from the interrupted event in the wire protocol.
-void DbgMsgQueue::SendIsolateEvent(Dart_IsolateId isolate_id,
-                                   Dart_IsolateEvent kind) {
-  dart::TextBuffer msg(128);
-  if (kind == kInterrupted) {
-    Dart_StackTrace trace;
-    Dart_Handle res = Dart_GetStackTrace(&trace);
-    ASSERT_NOT_ERROR(res);
-    msg.Printf("{ \"event\": \"paused\", \"params\": { ");
-    msg.Printf("\"reason\": \"interrupted\", ");
-    msg.Printf("\"isolateId\": %" Pd64 "", isolate_id);
-    FormatLocationFromTrace(&msg, trace, ", ");
-    msg.Printf("}}");
-  } else {
-    msg.Printf("{ \"event\": \"isolate\", \"params\": { ");
-    if (kind == kCreated) {
-      msg.Printf("\"reason\": \"created\", ");
-    } else {
-      ASSERT(kind == kShutdown);
-      msg.Printf("\"reason\": \"shutdown\", ");
-    }
-    msg.Printf("\"id\": %" Pd64 " ", isolate_id);
-    msg.Printf("}}");
-  }
-  DebuggerConnectionHandler::BroadcastMsg(&msg);
-}
-
-
-DbgMsgQueue* DbgMsgQueueList::list_ = NULL;
-Mutex* DbgMsgQueueList::msg_queue_list_lock_ = new Mutex();
-
-
-void DbgMsgQueueList::Initialize() {
-  // Setup handlers for isolate events, breakpoints, exceptions and
-  // delayed breakpoints.
-  Dart_SetIsolateEventHandler(IsolateEventHandler);
-  Dart_SetPausedEventHandler(PausedEventHandler);
-  Dart_SetBreakpointResolvedHandler(BptResolvedHandler);
-  Dart_SetExceptionThrownHandler(ExceptionThrownHandler);
-}
-
-
-int32_t DbgMsgQueueList::LookupIsolateCommand(const char* buf,
-                                              int32_t buflen) {
-  // Check if we have a isolate specific debugger command.
-  int32_t i = 0;
-  while (debugger_commands[i].cmd_string != NULL) {
-    if (strncmp(buf, debugger_commands[i].cmd_string, buflen) == 0) {
-      return i;
-    }
-    i++;
-  }
-  return kInvalidCommand;
-}
-
-
-bool DbgMsgQueueList::AddIsolateMessage(Dart_IsolateId isolate_id,
-                                        int32_t cmd_idx,
-                                        const char* start,
-                                        const char* end,
-                                        intptr_t debug_fd) {
-  MutexLocker ml(msg_queue_list_lock_);
-  DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueueLocked(isolate_id);
-  if (queue != NULL) {
-    queue->AddMessage(cmd_idx, start, end, debug_fd);
-    return true;
-  }
-  return false;
-}
-
-
-void DbgMsgQueueList::NotifyIsolate(Dart_Isolate isolate) {
-  MutexLocker ml(msg_queue_list_lock_);
-  Dart_IsolateId isolate_id = Dart_GetIsolateId(isolate);
-  DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueueLocked(isolate_id);
-  if (queue != NULL) {
-    queue->Notify();
-  }
-}
-
-
-bool DbgMsgQueueList::InterruptIsolate(Dart_IsolateId isolate_id) {
-  MutexLocker ml(msg_queue_list_lock_);
-  DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueueLocked(isolate_id);
-  if (queue != NULL) {
-    queue->InterruptIsolate();
-    return true;
-  }
-  return false;
-}
-
-
-DbgMsgQueue* DbgMsgQueueList::AddIsolateMsgQueue(Dart_IsolateId isolate_id) {
-  MutexLocker ml(msg_queue_list_lock_);
-
-  DbgMsgQueue* queue = new DbgMsgQueue(isolate_id, list_);
-  ASSERT(queue != NULL);
-  list_ = queue;
-  return queue;
-}
-
-
-DbgMsgQueue* DbgMsgQueueList::GetIsolateMsgQueue(Dart_IsolateId isolate_id) {
-  MutexLocker ml(msg_queue_list_lock_);
-  ASSERT(Dart_GetIsolate(isolate_id) == Dart_CurrentIsolate());
-  return GetIsolateMsgQueueLocked(isolate_id);
-}
-
-
-DbgMsgQueue* DbgMsgQueueList::GetIsolateMsgQueueLocked(Dart_IsolateId id) {
-  if (list_ == NULL) {
-    return NULL;  // No items in the list.
-  }
-
-  // Find message queue corresponding to isolate id.
-  DbgMsgQueue* iterator = list_;
-  while (iterator != NULL && iterator->isolate_id() != id) {
-    iterator = iterator->next();
-  }
-  return iterator;
-}
-
-
-void DbgMsgQueueList::RemoveIsolateMsgQueue(Dart_IsolateId isolate_id) {
-  MutexLocker ml(msg_queue_list_lock_);
-  if (list_ == NULL) {
-    return;  // No items in the list.
-  }
-  DbgMsgQueue* queue = list_;
-  if (queue->isolate_id() == isolate_id) {
-    list_ = queue->next();  // Remove from list.
-    delete queue;  // Delete the message queue.
-    return;
-  } else {
-    DbgMsgQueue* iterator = queue;
-    queue = queue->next();
-    while (queue != NULL) {
-      if (queue->isolate_id() == isolate_id) {
-        iterator->set_next(queue->next());  // Remove from list.
-        delete queue;  // Delete the message queue.
-        return;
-      }
-      iterator = queue;
-      queue = queue->next();
-    }
-  }
-  UNREACHABLE();
-}
-
-
-void DbgMsgQueueList::ListIsolateIds(dart::TextBuffer* msg) {
-  MutexLocker ml(msg_queue_list_lock_);
-  if (list_ == NULL) {
-    return;  // No items in the list.
-  }
-  DbgMsgQueue* queue = list_;
-  msg->Printf("%" Pd64 "", queue->isolate_id());
-  queue = queue->next();
-  while (queue != NULL) {
-    msg->Printf(",%" Pd64 "", queue->isolate_id());
-    queue = queue->next();
-  }
-}
-
-
-void DbgMsgQueueList::BptResolvedHandler(Dart_IsolateId isolate_id,
-                                         intptr_t bp_id,
-                                         const Dart_CodeLocation& location) {
-  Dart_EnterScope();
-  dart::TextBuffer msg(128);
-  msg.Printf("{ \"event\": \"breakpointResolved\", \"params\": {");
-  msg.Printf("\"breakpointId\": %" Pd "", bp_id);
-
-  msg.Printf(", \"isolateId\":%" Pd64 "", isolate_id);
-  ASSERT(!Dart_IsNull(location.script_url));
-  ASSERT(Dart_IsString(location.script_url));
-  msg.Printf(", \"location\":{\"url\":");
-  FormatEncodedString(&msg, location.script_url);
-  msg.Printf(",\"libraryId\":%d", location.library_id);
-  msg.Printf(",\"tokenOffset\":%d}}}", location.token_pos);
-
-  DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id);
-  ASSERT(msg_queue != NULL);
-  msg_queue->QueueOutputMsg(&msg);
-  Dart_ExitScope();
-}
-
-
-void DbgMsgQueueList::PausedEventHandler(Dart_IsolateId isolate_id,
-                                         intptr_t bp_id,
-                                         const Dart_CodeLocation& loc) {
-  DebuggerConnectionHandler::WaitForConnection();
-  Dart_EnterScope();
-  DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id);
-  ASSERT(msg_queue != NULL);
-  msg_queue->SendQueuedMsgs();
-  msg_queue->SendBreakpointEvent(bp_id, loc);
-  msg_queue->MessageLoop();
-  Dart_ExitScope();
-}
-
-
-void DbgMsgQueueList::ExceptionThrownHandler(Dart_IsolateId isolate_id,
-                                             Dart_Handle exception,
-                                             Dart_StackTrace stack_trace) {
-  DebuggerConnectionHandler::WaitForConnection();
-  Dart_EnterScope();
-  DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id);
-  ASSERT(msg_queue != NULL);
-  msg_queue->SendQueuedMsgs();
-  msg_queue->SendExceptionEvent(exception, stack_trace);
-  msg_queue->MessageLoop();
-  Dart_ExitScope();
-}
-
-
-void DbgMsgQueueList::IsolateEventHandler(Dart_IsolateId isolate_id,
-                                          Dart_IsolateEvent kind) {
-  if (kind == kCreated) {
-    DebuggerConnectionHandler::WaitForConnection();
-    Dart_EnterScope();
-    DbgMsgQueue* msg_queue = AddIsolateMsgQueue(isolate_id);
-    msg_queue->SendIsolateEvent(isolate_id, kind);
-    Dart_ExitScope();
-  } else {
-    DebuggerConnectionHandler::WaitForConnection();
-    DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id);
-    ASSERT(msg_queue != NULL);
-    Dart_EnterScope();
-    msg_queue->SendQueuedMsgs();
-    msg_queue->SendIsolateEvent(isolate_id, kind);
-    if (kind == kInterrupted) {
-      msg_queue->MessageLoop();
-    } else {
-      ASSERT(kind == kShutdown);
-      RemoveIsolateMsgQueue(isolate_id);
-    }
-    Dart_ExitScope();
-    // If there is no receive message queue, do not wait for a connection, and
-    // ignore the message.
-  }
-}
-
-}  // namespace bin
-}  // namespace dart
diff --git a/runtime/bin/dbg_message.h b/runtime/bin/dbg_message.h
deleted file mode 100644
index 0714174..0000000
--- a/runtime/bin/dbg_message.h
+++ /dev/null
@@ -1,282 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef BIN_DBG_MESSAGE_H_
-#define BIN_DBG_MESSAGE_H_
-
-#include "bin/builtin.h"
-#include "bin/thread.h"
-#include "bin/utils.h"
-
-#include "include/dart_tools_api.h"
-
-#include "platform/globals.h"
-#include "platform/json.h"
-
-
-namespace dart {
-namespace bin {
-
-// TODO(hausner): Need better error handling.
-#define ASSERT_NOT_ERROR(handle)          \
-  ASSERT(!Dart_IsError(handle))
-
-#define RETURN_IF_ERROR(handle)           \
-  if (Dart_IsError(handle)) {             \
-    return Dart_GetError(handle);         \
-  }
-
-
-// Class to parse a JSON debug command message.
-class MessageParser {
- public:
-  MessageParser(const char* buf, int buf_length)
-      : buf_(buf), buf_length_(buf_length) {
-  }
-  ~MessageParser() { }
-
-  // Accessors.
-  const char* buf() const { return buf_; }
-
-  bool IsValidMessage() const;
-  int MessageId() const;
-
-  const char* Params() const;
-  bool HasParam(const char* name) const;
-  intptr_t GetIntParam(const char* name) const;
-  int64_t GetInt64Param(const char* name) const;
-  intptr_t GetOptIntParam(const char* name, intptr_t default_val) const;
-
-  // GetStringParam mallocs the buffer that it returns. Caller must free.
-  char* GetStringParam(const char* name) const;
-
- private:
-  const char* buf_;
-  int buf_length_;
-
-  DISALLOW_COPY_AND_ASSIGN(MessageParser);
-};
-
-
-// Class which represents a debug command message and handles it.
-class DbgMessage {
- public:
-  DbgMessage(int32_t cmd_idx, const char* start,
-             const char* end, intptr_t debug_fd)
-      : next_(NULL), cmd_idx_(cmd_idx),
-        buffer_(NULL), buffer_len_(end - start),
-        debug_fd_(debug_fd) {
-    buffer_ = reinterpret_cast<char*>(malloc(buffer_len_));
-    ASSERT(buffer_ != NULL);
-    memmove(buffer_, start, buffer_len_);
-  }
-  ~DbgMessage() {
-    next_ = NULL;
-    free(buffer_);
-  }
-
-  // Accessors.
-  DbgMessage* next() const { return next_; }
-  void set_next(DbgMessage* next) { next_ = next; }
-  char* buffer() const { return buffer_; }
-  int32_t buffer_len() const { return buffer_len_; }
-  intptr_t debug_fd() const { return debug_fd_; }
-
-  // Handle debugger command message.
-  // Returns true if the execution needs to resume after this message is
-  // handled, false otherwise.
-  bool HandleMessage();
-
-  // Send reply after successful handling of command.
-  void SendReply(dart::TextBuffer* msg);
-
-  // Reply error returned by the command handler.
-  void SendErrorReply(int msg_id, const char* err_msg);
-
-  // Handlers for specific commands, they are static because these
-  // functions are populated as function pointers into a dispatch table.
-  static bool HandleResumeCmd(DbgMessage* msg);
-  static bool HandleStepIntoCmd(DbgMessage* msg);
-  static bool HandleStepOverCmd(DbgMessage* msg);
-  static bool HandleStepOutCmd(DbgMessage* msg);
-  static bool HandleGetLibrariesCmd(DbgMessage* msg);
-  static bool HandleGetClassPropsCmd(DbgMessage* msg);
-  static bool HandleGetLibPropsCmd(DbgMessage* msg);
-  static bool HandleSetLibPropsCmd(DbgMessage* msg);
-  static bool HandleGetGlobalsCmd(DbgMessage* msg);
-  static bool HandleEvaluateExprCmd(DbgMessage* msg);
-  static bool HandleGetObjPropsCmd(DbgMessage* msg);
-  static bool HandleGetListCmd(DbgMessage* msg);
-  static bool HandleGetScriptURLsCmd(DbgMessage* msg);
-  static bool HandleGetSourceCmd(DbgMessage* msg);
-  static bool HandleGetLineNumbersCmd(DbgMessage* msg);
-  static bool HandleGetStackTraceCmd(DbgMessage* msg);
-  static bool HandlePauseOnExcCmd(DbgMessage* msg);
-  static bool HandleSetBpCmd(DbgMessage* msg);
-  static bool HandleRemBpCmd(DbgMessage* msg);
-
- private:
-  DbgMessage* next_;  // Next message in the queue.
-  int32_t cmd_idx_;  // Isolate specific debugger command index.
-  char* buffer_;  // Debugger command message.
-  int32_t buffer_len_;  // Length of the debugger command message.
-  intptr_t debug_fd_;  // Debugger connection on which replies are to be sent.
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(DbgMessage);
-};
-
-
-// Class which represents a queue of debug command messages sent to an isolate.
-class DbgMsgQueue {
- public:
-  DbgMsgQueue(Dart_IsolateId isolate_id, DbgMsgQueue* next)
-      : is_running_(true),
-        is_interrupted_(false),
-        msglist_head_(NULL),
-        msglist_tail_(NULL),
-        queued_output_messages_(64),
-        isolate_id_(isolate_id),
-        next_(next) {
-  }
-  ~DbgMsgQueue() {
-    DbgMessage* msg = msglist_head_;
-    while (msglist_head_ != NULL) {
-      msglist_head_ = msglist_head_->next();
-      delete msg;
-      msg = msglist_head_;
-    }
-    msglist_tail_ = NULL;
-    isolate_id_ = ILLEGAL_ISOLATE_ID;
-    next_ = NULL;
-  }
-
-  // Accessors.
-  Dart_IsolateId isolate_id() const { return isolate_id_; }
-  DbgMsgQueue* next() const { return next_; }
-  void set_next(DbgMsgQueue* next) { next_ = next; }
-
-  // Add specified debug command message to the queue.
-  void AddMessage(int32_t cmd_idx,
-                  const char* start,
-                  const char* end,
-                  intptr_t debug_fd);
-
-  // Notify an isolate of a pending vmservice message.
-  void Notify();
-
-  // Run a message loop which handles messages as they arrive until
-  // normal program execution resumes.
-  void MessageLoop();
-
-  // Handle any pending debug command messages in the queue.  Return
-  // value indicates whether a resume has been requested.
-  bool HandlePendingMessages();
-
-  // Interrupt Isolate.
-  void InterruptIsolate();
-
-  // Queue output messages, these are sent out when we hit an event.
-  void QueueOutputMsg(dart::TextBuffer* msg);
-
-  // Send all queued messages over to the debugger.
-  void SendQueuedMsgs();
-
-  // Send breakpoint event message over to the debugger.
-  void SendBreakpointEvent(intptr_t bp_id, const Dart_CodeLocation& location);
-
-  // Send Exception event message over to the debugger.
-  void SendExceptionEvent(Dart_Handle exception, Dart_StackTrace trace);
-
-  // Send Isolate event message over to the debugger.
-  void SendIsolateEvent(Dart_IsolateId isolate_id, Dart_IsolateEvent kind);
-
- private:
-  bool is_running_;  // True if isolate is running and not in the debugger loop.
-  bool is_interrupted_;  // True if interrupt command is pending.
-
-  DbgMessage* msglist_head_;  // Start of debugger messages list.
-  DbgMessage* msglist_tail_;  // End of debugger messages list.
-
-  // Text buffer that accumulates messages to be output.
-  dart::TextBuffer queued_output_messages_;
-
-  Dart_IsolateId isolate_id_;  // Id of the isolate tied to this queue.
-
-  DbgMsgQueue* next_;  // Used for creating a list of message queues.
-
-  // The isolate waits on this condition variable when it needs to process
-  // debug messages.
-  Monitor msg_queue_lock_;
-
-  DISALLOW_COPY_AND_ASSIGN(DbgMsgQueue);
-};
-
-
-// Maintains a list of message queues.
-class DbgMsgQueueList {
- public:
-  static const int32_t kInvalidCommand = -1;
-
-  // Initialize the message queue processing by setting up the appropriate
-  // handlers.
-  static void Initialize();
-
-  // Parses the input message and returns the command index if the message
-  // contains a valid isolate specific command.
-  // It returns kInvalidCommand otherwise.
-  static int32_t LookupIsolateCommand(const char* buf, int32_t buflen);
-
-  // Queue debugger message targetted for the isolate.
-  static bool AddIsolateMessage(Dart_IsolateId isolate_id,
-                                int32_t cmd_idx,
-                                const char* start,
-                                const char* end,
-                                intptr_t debug_fd);
-
-  // Notify an isolate of a pending vmservice message.
-  static void NotifyIsolate(Dart_Isolate isolate);
-
-  // Interrupt isolate.
-  static bool InterruptIsolate(Dart_IsolateId isolate_id);
-
-  // Add Debugger Message Queue corresponding to the Isolate.
-  static DbgMsgQueue* AddIsolateMsgQueue(Dart_IsolateId isolate_id);
-
-  // Get Debugger Message Queue corresponding to the Isolate.
-  static DbgMsgQueue* GetIsolateMsgQueue(Dart_IsolateId isolate_id);
-
-  // Remove Debugger Message Queue corresponding to the Isolate.
-  static void RemoveIsolateMsgQueue(Dart_IsolateId isolate_id);
-
-  // Generic handlers for breakpoints, exceptions and delayed breakpoint
-  // resolution.
-  static void BptResolvedHandler(Dart_IsolateId isolate_id,
-                                 intptr_t bp_id,
-                                 const Dart_CodeLocation& location);
-  static void PausedEventHandler(Dart_IsolateId isolate_id,
-                                 intptr_t bp_id,
-                                 const Dart_CodeLocation& loc);
-  static void ExceptionThrownHandler(Dart_IsolateId isolate_id,
-                                     Dart_Handle exception,
-                                     Dart_StackTrace stack_trace);
-  static void IsolateEventHandler(Dart_IsolateId isolate_id,
-                                  Dart_IsolateEvent kind);
-
-  // Print list of isolate ids of all message queues into text buffer.
-  static void ListIsolateIds(dart::TextBuffer* msg);
-
- private:
-  static DbgMsgQueue* GetIsolateMsgQueueLocked(Dart_IsolateId isolate_id);
-
-  static DbgMsgQueue* list_;
-  static Mutex* msg_queue_list_lock_;
-
-  DISALLOW_ALLOCATION();
-  DISALLOW_IMPLICIT_CONSTRUCTORS(DbgMsgQueueList);
-};
-
-}  // namespace bin
-}  // namespace dart
-
-#endif  // BIN_DBG_MESSAGE_H_
diff --git a/runtime/bin/embedded_dart_io.h b/runtime/bin/embedded_dart_io.h
index e19b21a..4d7dbae 100644
--- a/runtime/bin/embedded_dart_io.h
+++ b/runtime/bin/embedded_dart_io.h
@@ -11,6 +11,19 @@
 // Bootstraps 'dart:io'.
 void BootstrapDartIo();
 
+// Tells the system whether to capture Stdout events.
+void SetCaptureStdout(bool value);
+
+// Tells the system whether to capture Stderr events.
+void SetCaptureStderr(bool value);
+
+// Should Stdout events be captured?
+bool ShouldCaptureStdout();
+
+// Should Stderr events be captured?
+bool ShouldCaptureStderr();
+
+
 }  // namespace bin
 }  // namespace dart
 
diff --git a/runtime/bin/eventhandler_macos.cc b/runtime/bin/eventhandler_macos.cc
index fa2dbf6..edd0485 100644
--- a/runtime/bin/eventhandler_macos.cc
+++ b/runtime/bin/eventhandler_macos.cc
@@ -132,7 +132,7 @@
   if (status == -1) {
     const int kBufferSize = 1024;
     char error_message[kBufferSize];
-    strerror_r(errno, error_message, kBufferSize);
+    Utils::StrError(errno, error_message, kBufferSize);
     FATAL1("Failed adding interrupt fd to kqueue: %s\n", error_message);
   }
 }
@@ -358,7 +358,7 @@
     if ((events[i].flags & EV_ERROR) != 0) {
       const int kBufferSize = 1024;
       char error_message[kBufferSize];
-      strerror_r(events[i].data, error_message, kBufferSize);
+      Utils::StrError(events[i].data, error_message, kBufferSize);
       FATAL1("kevent failed %s\n", error_message);
     }
     if (events[i].udata == NULL) {
@@ -440,7 +440,7 @@
     if (result == -1) {
       const int kBufferSize = 1024;
       char error_message[kBufferSize];
-      strerror_r(errno, error_message, kBufferSize);
+      Utils::StrError(errno, error_message, kBufferSize);
       FATAL1("kevent failed %s\n", error_message);
     } else {
       handler_impl->HandleTimeout();
diff --git a/runtime/bin/file.cc b/runtime/bin/file.cc
index cfd5637..1face6b 100644
--- a/runtime/bin/file.cc
+++ b/runtime/bin/file.cc
@@ -6,6 +6,7 @@
 
 #include "bin/builtin.h"
 #include "bin/dartutils.h"
+#include "bin/embedded_dart_io.h"
 #include "bin/io_buffer.h"
 #include "bin/utils.h"
 
@@ -18,13 +19,31 @@
 static const int kMSPerSecond = 1000;
 
 // Are we capturing output from stdout for the VM service?
-bool File::capture_stdout_ = false;
+static bool capture_stdout = false;
 
 // Are we capturing output from stderr for the VM service?
-bool File::capture_stderr_ = false;
+static bool capture_stderr = false;
 
-// Are we capturing output from either stdout or stderr for the VM Service?
-bool File::capture_any_ = false;
+
+void SetCaptureStdout(bool value) {
+  capture_stdout = value;
+}
+
+
+void SetCaptureStderr(bool value) {
+  capture_stderr = value;
+}
+
+
+bool ShouldCaptureStdout() {
+  return capture_stdout;
+}
+
+
+bool ShouldCaptureStderr() {
+  return capture_stderr;
+}
+
 
 
 // The file pointer has been passed into Dart as an intptr_t and it is safe
@@ -62,13 +81,13 @@
     remaining -= bytes_written;  // Reduce the number of remaining bytes.
     current_buffer += bytes_written;  // Move the buffer forward.
   }
-  if (capture_any_) {
+  if (capture_stdout || capture_stderr) {
     intptr_t fd = GetFD();
-    if (fd == STDOUT_FILENO && capture_stdout_) {
+    if (fd == STDOUT_FILENO && capture_stdout) {
       Dart_ServiceSendDataEvent("Stdout", "WriteEvent",
                                 reinterpret_cast<const uint8_t*>(buffer),
                                 num_bytes);
-    } else if (fd == STDERR_FILENO && capture_stderr_) {
+    } else if (fd == STDERR_FILENO && capture_stderr) {
       Dart_ServiceSendDataEvent("Stderr", "WriteEvent",
                                 reinterpret_cast<const uint8_t*>(buffer),
                                 num_bytes);
diff --git a/runtime/bin/file.h b/runtime/bin/file.h
index 28e85e3..633c006 100644
--- a/runtime/bin/file.h
+++ b/runtime/bin/file.h
@@ -187,18 +187,6 @@
   static CObject* StatRequest(const CObjectArray& request);
   static CObject* LockRequest(const CObjectArray& request);
 
-  static void set_capture_stdout(bool value) {
-    capture_stdout_ = value;
-    capture_any_ = (capture_stdout_ || capture_stderr_);
-  }
-  static bool capture_stdout() { return capture_stdout_; }
-
-  static void set_capture_stderr(bool value) {
-    capture_stderr_ = value;
-    capture_any_ = (capture_stdout_ || capture_stderr_);
-  }
-  static bool capture_stderr() { return capture_stderr_; }
-
  private:
   explicit File(FileHandle* handle) : handle_(handle) { }
   void Close();
@@ -208,10 +196,6 @@
   // FileHandle is an OS specific class which stores data about the file.
   FileHandle* handle_;  // OS specific handle for the file.
 
-  static bool capture_stdout_;
-  static bool capture_stderr_;
-  static bool capture_any_;
-
   DISALLOW_COPY_AND_ASSIGN(File);
 };
 
diff --git a/runtime/bin/file_android.cc b/runtime/bin/file_android.cc
index 35b6388..cc29740 100644
--- a/runtime/bin/file_android.cc
+++ b/runtime/bin/file_android.cc
@@ -19,6 +19,7 @@
 #include "bin/log.h"
 
 #include "platform/signal_blocker.h"
+#include "platform/utils.h"
 
 
 namespace dart {
@@ -57,7 +58,7 @@
     if (err != 0) {
       const int kBufferSize = 1024;
       char error_message[kBufferSize];
-      strerror_r(errno, error_message, kBufferSize);
+      Utils::StrError(errno, error_message, kBufferSize);
       Log::PrintErr("%s\n", error_message);
     }
   }
@@ -422,7 +423,7 @@
   if (result == -1) {
     const int kBufferSize = 1024;
     char error_message[kBufferSize];
-    strerror_r(errno, error_message, kBufferSize);
+    Utils::StrError(errno, error_message, kBufferSize);
     FATAL2("Failed stat on file descriptor %d: %s", fd, error_message);
   }
   if (S_ISCHR(buf.st_mode)) return kTerminal;
diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc
index ff801ad..d289c21 100644
--- a/runtime/bin/file_linux.cc
+++ b/runtime/bin/file_linux.cc
@@ -15,9 +15,10 @@
 #include <unistd.h>  // NOLINT
 #include <libgen.h>  // NOLINT
 
-#include "platform/signal_blocker.h"
 #include "bin/builtin.h"
 #include "bin/log.h"
+#include "platform/signal_blocker.h"
+#include "platform/utils.h"
 
 
 namespace dart {
@@ -56,7 +57,7 @@
     if (err != 0) {
       const int kBufferSize = 1024;
       char error_buf[kBufferSize];
-      Log::PrintErr("%s\n", strerror_r(errno, error_buf, kBufferSize));
+      Log::PrintErr("%s\n", Utils::StrError(errno, error_buf, kBufferSize));
     }
   }
   handle_->set_fd(kClosedFd);
@@ -429,7 +430,7 @@
     const int kBufferSize = 1024;
     char error_buf[kBufferSize];
     FATAL2("Failed stat on file descriptor %d: %s", fd,
-           strerror_r(errno, error_buf, kBufferSize));
+           Utils::StrError(errno, error_buf, kBufferSize));
   }
   if (S_ISCHR(buf.st_mode)) return kTerminal;
   if (S_ISFIFO(buf.st_mode)) return kPipe;
diff --git a/runtime/bin/file_macos.cc b/runtime/bin/file_macos.cc
index ddc19cc..6187e94 100644
--- a/runtime/bin/file_macos.cc
+++ b/runtime/bin/file_macos.cc
@@ -20,6 +20,7 @@
 #include "bin/log.h"
 
 #include "platform/signal_blocker.h"
+#include "platform/utils.h"
 
 namespace dart {
 namespace bin {
@@ -57,7 +58,7 @@
     if (err != 0) {
       const int kBufferSize = 1024;
       char error_message[kBufferSize];
-      strerror_r(errno, error_message, kBufferSize);
+      Utils::StrError(errno, error_message, kBufferSize);
       Log::PrintErr("%s\n", error_message);
     }
   }
@@ -394,7 +395,7 @@
   if (result == -1) {
     const int kBufferSize = 1024;
     char error_message[kBufferSize];
-    strerror_r(errno, error_message, kBufferSize);
+    Utils::StrError(errno, error_message, kBufferSize);
     FATAL2("Failed stat on file descriptor %d: %s", fd, error_message);
   }
   if (S_ISCHR(buf.st_mode)) return kTerminal;
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 72c5460..29485e2 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -11,8 +11,8 @@
 
 #include "bin/builtin.h"
 #include "bin/dartutils.h"
-#include "bin/dbg_connection.h"
 #include "bin/directory.h"
+#include "bin/embedded_dart_io.h"
 #include "bin/eventhandler.h"
 #include "bin/extensions.h"
 #include "bin/file.h"
@@ -21,9 +21,11 @@
 #include "bin/platform.h"
 #include "bin/process.h"
 #include "bin/thread.h"
+#include "bin/utils.h"
 #include "bin/vmservice_impl.h"
 #include "platform/globals.h"
 #include "platform/hashmap.h"
+#include "platform/text_buffer.h"
 
 namespace dart {
 namespace bin {
@@ -42,20 +44,6 @@
 static const char* snapshot_filename = NULL;
 
 
-// Global state that indicates whether there is a debug breakpoint.
-// This pointer points into an argv buffer and does not need to be
-// free'd.
-static const char* breakpoint_at = NULL;
-
-
-// Global state that indicates whether we should open a connection
-// and listen for a debugger to connect.
-static bool start_debugger = false;
-static const char* debug_ip = NULL;
-static int debug_port = -1;
-static const char* DEFAULT_DEBUG_IP = "127.0.0.1";
-static const int DEFAULT_DEBUG_PORT = 5858;
-
 // Value of the --package-root flag.
 // (This pointer points into an argv buffer and does not need to be
 // free'd.)
@@ -142,7 +130,6 @@
   }
 
   if (do_vm_shutdown) {
-    DebuggerConnectionHandler::StopHandler();
     EventHandler::Stop();
   }
   Platform::Exit(exit_code);
@@ -193,17 +180,6 @@
 }
 
 
-static bool ProcessBreakpointOption(const char* funcname,
-                                    CommandLineOptions* vm_options) {
-  ASSERT(funcname != NULL);
-  if (*funcname == '\0') {
-    return false;
-  }
-  breakpoint_at = funcname;
-  return true;
-}
-
-
 static bool ProcessPackageRootOption(const char* arg,
                                      CommandLineOptions* vm_options) {
   ASSERT(arg != NULL);
@@ -369,22 +345,6 @@
 }
 
 
-static bool ProcessDebugOption(const char* option_value,
-                               CommandLineOptions* vm_options) {
-  ASSERT(option_value != NULL);
-  if (!ExtractPortAndIP(option_value, &debug_port, &debug_ip,
-                        DEFAULT_DEBUG_PORT, DEFAULT_DEBUG_IP)) {
-    Log::PrintErr("unrecognized --debug option syntax. "
-                  "Use --debug[:<port number>[/<IPv4 address>]]\n");
-    return false;
-  }
-
-  breakpoint_at = "main";
-  start_debugger = true;
-  return true;
-}
-
-
 static bool ProcessScriptSnapshotOptionHelper(const char* filename,
                                               bool* snapshot_option) {
   *snapshot_option = false;
@@ -458,17 +418,6 @@
 }
 
 
-extern bool trace_debug_protocol;
-static bool ProcessTraceDebugProtocolOption(const char* arg,
-                                            CommandLineOptions* vm_options) {
-  if (*arg != '\0') {
-    return false;
-  }
-  trace_debug_protocol = true;
-  return true;
-}
-
-
 static bool ProcessTraceLoadingOption(const char* arg,
                                       CommandLineOptions* vm_options) {
   if (*arg != '\0') {
@@ -522,9 +471,7 @@
   { "--version", ProcessVersionOption },
 
   // VM specific options to the standalone dart program.
-  { "--break-at=", ProcessBreakpointOption },
   { "--compile_all", ProcessCompileAllOption },
-  { "--debug", ProcessDebugOption },
   { "--enable-vm-service", ProcessEnableVmServiceOption },
   { "--gen-precompiled-snapshot", ProcessGenPrecompiledSnapshotOption },
   { "--noopt", ProcessNooptOption },
@@ -533,7 +480,6 @@
   { "--shutdown", ProcessShutdownOption },
   { "--snapshot=", ProcessScriptSnapshotOption },
   { "--snapshot-after-run=", ProcessScriptSnapshotAfterRunOption },
-  { "--trace-debug-protocol", ProcessTraceDebugProtocolOption },
   { "--trace-loading", ProcessTraceLoadingOption },
   { NULL, NULL }
 };
@@ -963,25 +909,6 @@
 }
 
 
-static Dart_Handle SetBreakpoint(const char* breakpoint_at,
-                                 Dart_Handle library) {
-  char* bpt_function = strdup(breakpoint_at);
-  Dart_Handle class_name;
-  Dart_Handle function_name;
-  char* dot = strchr(bpt_function, '.');
-  if (dot == NULL) {
-    class_name = DartUtils::NewString("");
-    function_name = DartUtils::NewString(breakpoint_at);
-  } else {
-    *dot = '\0';
-    class_name = DartUtils::NewString(bpt_function);
-    function_name = DartUtils::NewString(dot + 1);
-  }
-  free(bpt_function);
-  return Dart_OneTimeBreakAtEntry(library, class_name, function_name);
-}
-
-
 char* BuildIsolateName(const char* script_name,
                        const char* func_name) {
   // Skip past any slashes in the script name.
@@ -1028,14 +955,21 @@
   DartScope scope;
   // TODO(ajohnsen): Store the library/function in isolate data or user_data.
   Dart_Handle dart_io_str = Dart_NewStringFromCString("dart:io");
-  if (Dart_IsError(dart_io_str)) return ServiceRequestError(dart_io_str);
+  if (Dart_IsError(dart_io_str)) {
+    return ServiceRequestError(dart_io_str);
+  }
+
   Dart_Handle io_lib = Dart_LookupLibrary(dart_io_str);
-  if (Dart_IsError(io_lib)) return ServiceRequestError(io_lib);
+  if (Dart_IsError(io_lib)) {
+    return ServiceRequestError(io_lib);
+  }
+
   Dart_Handle handler_function_name =
       Dart_NewStringFromCString("_serviceObjectHandler");
   if (Dart_IsError(handler_function_name)) {
     return ServiceRequestError(handler_function_name);
   }
+
   // TODO(johnmccutchan): paths is no longer used.  Update the io
   // _serviceObjectHandler function to use json rpc.
   Dart_Handle paths = Dart_NewList(0);
@@ -1047,10 +981,15 @@
   }
   Dart_Handle args[] = {paths, keys, values};
   Dart_Handle result = Dart_Invoke(io_lib, handler_function_name, 3, args);
-  if (Dart_IsError(result)) return ServiceRequestError(result);
+  if (Dart_IsError(result)) {
+    return ServiceRequestError(result);
+  }
+
   const char *json;
   result = Dart_StringToCString(result, &json);
-  if (Dart_IsError(result)) return ServiceRequestError(result);
+  if (Dart_IsError(result)) {
+    return ServiceRequestError(result);
+  }
   return strdup(json);
 }
 
@@ -1061,10 +1000,10 @@
 
 static bool ServiceStreamListenCallback(const char* stream_id) {
   if (strcmp(stream_id, kStdoutStreamId) == 0) {
-    File::set_capture_stdout(true);
+    SetCaptureStdout(true);
     return true;
   } else if (strcmp(stream_id, kStderrStreamId) == 0) {
-    File::set_capture_stderr(true);
+    SetCaptureStderr(true);
     return true;
   }
   return false;
@@ -1073,9 +1012,9 @@
 
 static void ServiceStreamCancelCallback(const char* stream_id) {
   if (strcmp(stream_id, kStdoutStreamId) == 0) {
-    File::set_capture_stdout(false);
+    SetCaptureStdout(false);
   } else if (strcmp(stream_id, kStderrStreamId) == 0) {
-    File::set_capture_stderr(false);
+    SetCaptureStderr(false);
   }
 }
 
@@ -1198,7 +1137,6 @@
       free(error);
     }
     if (do_vm_shutdown) {
-      DebuggerConnectionHandler::StopHandler();
       EventHandler::Stop();
     }
     Platform::Exit((exit_code != 0) ? exit_code : kErrorExitCode);
@@ -1315,18 +1253,6 @@
           Dart_NewStringFromCString("_getMainClosure"), 0, NULL);
       CHECK_RESULT(main_closure);
 
-      // Set debug breakpoint if specified on the command line before calling
-      // the main function.
-      if (breakpoint_at != NULL) {
-        result = SetBreakpoint(breakpoint_at, root_lib);
-        if (Dart_IsError(result)) {
-          ErrorExit(kErrorExitCode,
-                    "Error setting breakpoint at '%s': %s\n",
-                    breakpoint_at,
-                    Dart_GetError(result));
-        }
-      }
-
       // Call _startIsolate in the isolate library to enable dispatching the
       // initial startup message.
       const intptr_t kNumIsolateArgs = 2;
@@ -1433,18 +1359,6 @@
   // Start event handler.
   EventHandler::Start();
 
-  // Start the debugger wire protocol handler if necessary.
-  if (start_debugger) {
-    ASSERT(debug_port >= 0);
-    bool print_msg = verbose_debug_seen || (debug_port == 0);
-    debug_port = DebuggerConnectionHandler::StartHandler(debug_ip, debug_port);
-    if (print_msg) {
-      Log::Print("Debugger listening on port %d\n", debug_port);
-    }
-  } else {
-    DebuggerConnectionHandler::InitForVmService();
-  }
-
   const uint8_t* instructions_snapshot = NULL;
   if (has_run_precompiled_snapshot) {
     instructions_snapshot = reinterpret_cast<const uint8_t*>(
@@ -1465,7 +1379,6 @@
       GetVMServiceAssetsArchiveCallback);
   if (error != NULL) {
     if (do_vm_shutdown) {
-      DebuggerConnectionHandler::StopHandler();
       EventHandler::Stop();
     }
     fprintf(stderr, "VM initialization failed: %s\n", error);
@@ -1493,7 +1406,6 @@
     free(error);
   }
   if (do_vm_shutdown) {
-    DebuggerConnectionHandler::StopHandler();
     EventHandler::Stop();
   }
 
diff --git a/runtime/bin/process.cc b/runtime/bin/process.cc
index 8188693..f9d3457 100644
--- a/runtime/bin/process.cc
+++ b/runtime/bin/process.cc
@@ -3,8 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 #include "bin/dartutils.h"
-#include "bin/dbg_connection.h"
-#include "bin/eventhandler.h"
 #include "bin/io_buffer.h"
 #include "bin/log.h"
 #include "bin/platform.h"
diff --git a/runtime/bin/process_android.cc b/runtime/bin/process_android.cc
index 9265531..b9d245b 100644
--- a/runtime/bin/process_android.cc
+++ b/runtime/bin/process_android.cc
@@ -22,6 +22,7 @@
 #include "bin/thread.h"
 
 #include "platform/signal_blocker.h"
+#include "platform/utils.h"
 
 
 extern char **environ;
@@ -644,7 +645,7 @@
   void SetChildOsErrorMessage() {
     const int kBufferSize = 1024;
     char error_message[kBufferSize];
-    strerror_r(errno, error_message, kBufferSize);
+    Utils::StrError(errno, error_message, kBufferSize);
     *os_error_message_ = strdup(error_message);
   }
 
@@ -655,7 +656,7 @@
     int child_errno = errno;
     const int kBufferSize = 1024;
     char os_error_message[kBufferSize];
-    strerror_r(errno, os_error_message, kBufferSize);
+    Utils::StrError(errno, os_error_message, kBufferSize);
     int bytes_written =
         FDUtils::WriteToBlocking(
             exec_control_[1], &child_errno, sizeof(child_errno));
diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc
index cd9c639..30f188f 100644
--- a/runtime/bin/process_linux.cc
+++ b/runtime/bin/process_linux.cc
@@ -16,11 +16,12 @@
 #include <sys/wait.h>  // NOLINT
 #include <unistd.h>  // NOLINT
 
-#include "platform/signal_blocker.h"
 #include "bin/fdutils.h"
 #include "bin/lockers.h"
 #include "bin/log.h"
 #include "bin/thread.h"
+#include "platform/signal_blocker.h"
+#include "platform/utils.h"
 
 
 extern char **environ;
@@ -643,7 +644,7 @@
   void SetChildOsErrorMessage() {
     const int kBufferSize = 1024;
     char error_buf[kBufferSize];
-    *os_error_message_ = strdup(strerror_r(errno, error_buf, kBufferSize));
+    *os_error_message_ = strdup(Utils::StrError(errno, error_buf, kBufferSize));
   }
 
 
@@ -653,7 +654,7 @@
     int child_errno = errno;
     const int kBufferSize = 1024;
     char error_buf[kBufferSize];
-    char* os_error_message = strerror_r(errno, error_buf, kBufferSize);
+    char* os_error_message = Utils::StrError(errno, error_buf, kBufferSize);
     int bytes_written =
         FDUtils::WriteToBlocking(
             exec_control_[1], &child_errno, sizeof(child_errno));
diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc
index f694958..1ce34f9 100644
--- a/runtime/bin/process_macos.cc
+++ b/runtime/bin/process_macos.cc
@@ -25,6 +25,7 @@
 #include "bin/thread.h"
 
 #include "platform/signal_blocker.h"
+#include "platform/utils.h"
 
 
 
@@ -660,7 +661,7 @@
   void SetChildOsErrorMessage() {
     const int kBufferSize = 1024;
     char error_message[kBufferSize];
-    strerror_r(errno, error_message, kBufferSize);
+    Utils::StrError(errno, error_message, kBufferSize);
     *os_error_message_ = strdup(error_message);
   }
 
@@ -671,7 +672,7 @@
     int child_errno = errno;
     const int kBufferSize = 1024;
     char os_error_message[kBufferSize];
-    strerror_r(errno, os_error_message, kBufferSize);
+    Utils::StrError(errno, os_error_message, kBufferSize);
     int bytes_written =
         FDUtils::WriteToBlocking(
             exec_control_[1], &child_errno, sizeof(child_errno));
diff --git a/runtime/bin/run_vm_tests.cc b/runtime/bin/run_vm_tests.cc
index 19ef7e9b..bfb597b 100644
--- a/runtime/bin/run_vm_tests.cc
+++ b/runtime/bin/run_vm_tests.cc
@@ -107,7 +107,7 @@
   ASSERT(set_vm_flags_success);
   const char* err_msg = Dart::InitOnce(dart::bin::vm_isolate_snapshot_buffer,
                                        NULL,
-                                       NULL, NULL, NULL, NULL,
+                                       NULL, NULL,
                                        dart::bin::DartUtils::OpenFile,
                                        dart::bin::DartUtils::ReadFile,
                                        dart::bin::DartUtils::WriteFile,
diff --git a/runtime/bin/thread.h b/runtime/bin/thread.h
index 60dc75f2..d4a67bc 100644
--- a/runtime/bin/thread.h
+++ b/runtime/bin/thread.h
@@ -33,8 +33,8 @@
 
 class Thread {
  public:
-  static ThreadLocalKey kUnsetThreadLocalKey;
-  static ThreadId kInvalidThreadId;
+  static const ThreadLocalKey kUnsetThreadLocalKey;
+  static const ThreadId kInvalidThreadId;
 
   typedef void (*ThreadStartFunction) (uword parameter);
 
diff --git a/runtime/bin/thread_android.cc b/runtime/bin/thread_android.cc
index 62143ef..f84a988 100644
--- a/runtime/bin/thread_android.cc
+++ b/runtime/bin/thread_android.cc
@@ -11,6 +11,7 @@
 #include <sys/time.h>  // NOLINT
 
 #include "platform/assert.h"
+#include "platform/utils.h"
 
 namespace dart {
 namespace bin {
@@ -19,7 +20,7 @@
   if (result != 0) { \
     const int kBufferSize = 1024; \
     char error_message[kBufferSize]; \
-    strerror_r(result, error_message, kBufferSize); \
+    Utils::StrError(result, error_message, kBufferSize); \
     FATAL2("pthread error: %d (%s)", result, error_message); \
   }
 
@@ -29,7 +30,7 @@
   if (result != 0) { \
     const int kBufferSize = 1024; \
     char error_message[kBufferSize]; \
-    strerror_r(result, error_message, kBufferSize); \
+    Utils::StrError(result, error_message, kBufferSize); \
     fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", \
             __FILE__, __LINE__, result, error_message); \
     return result; \
@@ -113,8 +114,9 @@
 }
 
 
-ThreadLocalKey Thread::kUnsetThreadLocalKey = static_cast<pthread_key_t>(-1);
-ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(0);
+const ThreadLocalKey Thread::kUnsetThreadLocalKey =
+    static_cast<pthread_key_t>(-1);
+const ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(0);
 
 ThreadLocalKey Thread::CreateThreadLocal() {
   pthread_key_t key = kUnsetThreadLocalKey;
diff --git a/runtime/bin/thread_linux.cc b/runtime/bin/thread_linux.cc
index eaa4f2a..1e01a77 100644
--- a/runtime/bin/thread_linux.cc
+++ b/runtime/bin/thread_linux.cc
@@ -12,6 +12,7 @@
 #include <sys/time.h>  // NOLINT
 
 #include "platform/assert.h"
+#include "platform/utils.h"
 
 namespace dart {
 namespace bin {
@@ -21,7 +22,7 @@
     const int kBufferSize = 1024; \
     char error_buf[kBufferSize]; \
     FATAL2("pthread error: %d (%s)", result, \
-           strerror_r(result, error_buf, kBufferSize)); \
+           Utils::StrError(result, error_buf, kBufferSize)); \
   }
 
 
@@ -32,7 +33,7 @@
     char error_buf[kBufferSize]; \
     fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", \
             __FILE__, __LINE__, result, \
-            strerror_r(result, error_buf, kBufferSize)); \
+            Utils::StrError(result, error_buf, kBufferSize)); \
     return result; \
   }
 #else
@@ -114,8 +115,9 @@
 }
 
 
-ThreadLocalKey Thread::kUnsetThreadLocalKey = static_cast<pthread_key_t>(-1);
-ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(0);
+const ThreadLocalKey Thread::kUnsetThreadLocalKey =
+    static_cast<pthread_key_t>(-1);
+const ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(0);
 
 ThreadLocalKey Thread::CreateThreadLocal() {
   pthread_key_t key = kUnsetThreadLocalKey;
diff --git a/runtime/bin/thread_macos.cc b/runtime/bin/thread_macos.cc
index 52ac76c..28c747d 100644
--- a/runtime/bin/thread_macos.cc
+++ b/runtime/bin/thread_macos.cc
@@ -19,6 +19,7 @@
 #include <mach/thread_act.h>  // NOLINT
 
 #include "platform/assert.h"
+#include "platform/utils.h"
 
 namespace dart {
 namespace bin {
@@ -27,7 +28,7 @@
   if (result != 0) { \
     const int kBufferSize = 1024; \
     char error_message[kBufferSize]; \
-    strerror_r(result, error_message, kBufferSize); \
+    Utils::StrError(result, error_message, kBufferSize); \
     FATAL2("pthread error: %d (%s)", result, error_message); \
   }
 
@@ -37,7 +38,7 @@
   if (result != 0) { \
     const int kBufferSize = 1024; \
     char error_message[kBufferSize]; \
-    strerror_r(result, error_message, kBufferSize); \
+    Utils::StrError(result, error_message, kBufferSize); \
     fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", \
             __FILE__, __LINE__, result, error_message); \
     return result; \
@@ -106,8 +107,9 @@
 }
 
 
-ThreadLocalKey Thread::kUnsetThreadLocalKey = static_cast<pthread_key_t>(-1);
-ThreadId Thread::kInvalidThreadId = reinterpret_cast<ThreadId>(NULL);
+const ThreadLocalKey Thread::kUnsetThreadLocalKey =
+    static_cast<pthread_key_t>(-1);
+const ThreadId Thread::kInvalidThreadId = reinterpret_cast<ThreadId>(NULL);
 
 ThreadLocalKey Thread::CreateThreadLocal() {
   pthread_key_t key = kUnsetThreadLocalKey;
diff --git a/runtime/bin/thread_win.cc b/runtime/bin/thread_win.cc
index 05949a1..44941bb 100644
--- a/runtime/bin/thread_win.cc
+++ b/runtime/bin/thread_win.cc
@@ -70,8 +70,8 @@
   return 0;
 }
 
-ThreadLocalKey Thread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
-ThreadId Thread::kInvalidThreadId = 0;
+const ThreadLocalKey Thread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
+const ThreadId Thread::kInvalidThreadId = 0;
 
 ThreadLocalKey Thread::CreateThreadLocal() {
   ThreadLocalKey key = TlsAlloc();
diff --git a/runtime/bin/utils_android.cc b/runtime/bin/utils_android.cc
index 00cf93d..d96eb5d 100644
--- a/runtime/bin/utils_android.cc
+++ b/runtime/bin/utils_android.cc
@@ -12,6 +12,7 @@
 
 #include "bin/utils.h"
 #include "platform/assert.h"
+#include "platform/utils.h"
 
 
 namespace dart {
@@ -22,7 +23,7 @@
   set_code(errno);
   const int kBufferSize = 1024;
   char error_message[kBufferSize];
-  strerror_r(errno, error_message, kBufferSize);
+  Utils::StrError(errno, error_message, kBufferSize);
   SetMessage(error_message);
 }
 
@@ -33,7 +34,7 @@
   if (sub_system == kSystem) {
     const int kBufferSize = 1024;
     char error_message[kBufferSize];
-    strerror_r(code, error_message, kBufferSize);
+    Utils::StrError(code, error_message, kBufferSize);
     SetMessage(error_message);
   } else if (sub_system == kGetAddressInfo) {
     SetMessage(gai_strerror(code));
diff --git a/runtime/bin/utils_linux.cc b/runtime/bin/utils_linux.cc
index f3d8654..f84ba33 100644
--- a/runtime/bin/utils_linux.cc
+++ b/runtime/bin/utils_linux.cc
@@ -12,6 +12,7 @@
 
 #include "bin/utils.h"
 #include "platform/assert.h"
+#include "platform/utils.h"
 
 
 namespace dart {
@@ -22,7 +23,7 @@
   set_code(errno);
   const int kBufferSize = 1024;
   char error_buf[kBufferSize];
-  SetMessage(strerror_r(errno, error_buf, kBufferSize));
+  SetMessage(Utils::StrError(errno, error_buf, kBufferSize));
 }
 
 
@@ -32,7 +33,7 @@
   if (sub_system == kSystem) {
     const int kBufferSize = 1024;
     char error_buf[kBufferSize];
-    SetMessage(strerror_r(code, error_buf, kBufferSize));
+    SetMessage(Utils::StrError(code, error_buf, kBufferSize));
   } else if (sub_system == kGetAddressInfo) {
     SetMessage(gai_strerror(code));
   } else {
diff --git a/runtime/bin/utils_macos.cc b/runtime/bin/utils_macos.cc
index 4004f38..1d792c9 100644
--- a/runtime/bin/utils_macos.cc
+++ b/runtime/bin/utils_macos.cc
@@ -12,6 +12,7 @@
 
 #include "bin/utils.h"
 #include "platform/assert.h"
+#include "platform/utils.h"
 
 
 namespace dart {
@@ -22,7 +23,7 @@
   set_code(errno);
   const int kBufferSize = 1024;
   char error_message[kBufferSize];
-  strerror_r(errno, error_message, kBufferSize);
+  Utils::StrError(errno, error_message, kBufferSize);
   SetMessage(error_message);
 }
 
@@ -33,7 +34,7 @@
   if (sub_system == kSystem) {
     const int kBufferSize = 1024;
     char error_message[kBufferSize];
-    strerror_r(code, error_message, kBufferSize);
+    Utils::StrError(code, error_message, kBufferSize);
     SetMessage(error_message);
   } else if (sub_system == kGetAddressInfo) {
     SetMessage(gai_strerror(code));
diff --git a/runtime/bin/vmservice/loader.dart b/runtime/bin/vmservice/loader.dart
index cd94f57..38b62b1 100644
--- a/runtime/bin/vmservice/loader.dart
+++ b/runtime/bin/vmservice/loader.dart
@@ -62,32 +62,16 @@
   });
 }
 
-var dataUriRegex = new RegExp(
-    r"data:([\w-]+/[\w-]+)?(;charset=([\w-]+))?(;base64)?,(.*)");
-
 void _loadDataUri(SendPort sp, int id, Uri uri) {
   try {
-    var match = dataUriRegex.firstMatch(uri.toString());
-    if (match == null) throw "Malformed data uri";
-
-    var mimeType = match.group(1);
-    var encoding = match.group(3);
-    var maybeBase64 = match.group(4);
-    var encodedData = match.group(5);
-
-    if (mimeType != "application/dart") {
+    if (uri.data.mimeType != "application/dart") {
       throw "MIME-type must be application/dart";
     }
-    if (encoding != "utf-8") {
-      // Default is ASCII. The C++ portion of the embedder assumes UTF-8.
+    if (uri.data.charset != "utf-8") {
+      // The C++ portion of the embedder assumes UTF-8.
       throw "Only utf-8 encoding is supported";
     }
-    if (maybeBase64 != null) {
-      throw "Only percent encoding is supported";
-    }
-
-    var data = UTF8.encode(Uri.decodeComponent(encodedData));
-    _sendResourceResponse(sp, id, data);
+    _sendResourceResponse(sp, id, uri.data.contentAsBytes());
   } catch (e) {
     _sendResourceResponse(sp, id, "Invalid data uri ($uri):\n  $e");
   }
diff --git a/runtime/bin/vmservice/vmservice_io.dart b/runtime/bin/vmservice/vmservice_io.dart
index 1f7eee2..987af55 100644
--- a/runtime/bin/vmservice/vmservice_io.dart
+++ b/runtime/bin/vmservice/vmservice_io.dart
@@ -5,6 +5,7 @@
 library vmservice_io;
 
 import 'dart:async';
+import 'dart:collection';
 import 'dart:convert';
 import 'dart:io';
 import 'dart:isolate';
@@ -27,7 +28,7 @@
 // HTTP server.
 Server server;
 Future<Server> serverFuture;
-Map<String, Asset> assets;
+HashMap<String, Asset> assets;
 
 _onShutdown() {
   if (server != null) {
diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc
index 2a38c32..f46a66a 100644
--- a/runtime/bin/vmservice_impl.cc
+++ b/runtime/bin/vmservice_impl.cc
@@ -12,7 +12,7 @@
 #include "bin/platform.h"
 #include "bin/thread.h"
 #include "bin/utils.h"
-#include "platform/json.h"
+#include "platform/text_buffer.h"
 
 namespace dart {
 namespace bin {
@@ -31,8 +31,9 @@
   }
 
 #define kLibrarySourceNamePrefix "/vmservice"
-static const char* kVMServiceIOLibraryUri = "dart:vmservice_io";
-static const char* kVMServiceIOLibraryScriptResourceName = "vmservice_io.dart";
+static const char* const kVMServiceIOLibraryUri = "dart:vmservice_io";
+static const char* const kVMServiceIOLibraryScriptResourceName =
+    "vmservice_io.dart";
 
 struct ResourcesEntry {
   const char* path_;
diff --git a/runtime/dart-runtime.gyp b/runtime/dart-runtime.gyp
index e5c8805..fd3701e 100644
--- a/runtime/dart-runtime.gyp
+++ b/runtime/dart-runtime.gyp
@@ -55,6 +55,40 @@
       },
     },
     {
+      'target_name': 'libdart_precompiled',
+      'type': 'static_library',
+      'dependencies': [
+        'libdart_lib',
+        'libdart_vm_precompiled',
+        'libdouble_conversion',
+        'generate_version_cc_file#host',
+      ],
+      'include_dirs': [
+        '.',
+      ],
+      'sources': [
+        'include/dart_api.h',
+        'include/dart_mirrors_api.h',
+        'include/dart_native_api.h',
+        'include/dart_tools_api.h',
+        'vm/dart_api_impl.cc',
+        'vm/debugger_api_impl.cc',
+        'vm/mirrors_api_impl.cc',
+        'vm/native_api_impl.cc',
+        'vm/version.h',
+        '<(version_cc_file)',
+      ],
+      'defines': [
+        # The only effect of DART_SHARED_LIB is to export the Dart API entries.
+        'DART_SHARED_LIB',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          'include',
+        ],
+      },
+    },
+    {
       'target_name': 'generate_version_cc_file',
       'type': 'none',
       'toolsets':['host'],
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 29826af..9666364 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -501,140 +501,6 @@
     Dart_Isolate isolate,
     Dart_WeakPersistentHandle object);
 
-/**
- * Allocates a prologue weak persistent handle for an object.
- *
- * Prologue weak persistent handles are similar to weak persistent
- * handles but exhibit different behavior during garbage collections
- * that invoke the prologue and epilogue callbacks.  While weak
- * persistent handles always weakly reference their referents,
- * prologue weak persistent handles weakly reference their referents
- * only during a garbage collection that invokes the prologue and
- * epilogue callbacks.  During all other garbage collections, prologue
- * weak persistent handles strongly reference their referents.
- *
- * This handle has the lifetime of the current isolate unless the object
- * pointed to by the handle is garbage collected, in this case the VM
- * automatically deletes the handle after invoking the callback associated
- * with the handle. The handle can also be explicitly deallocated by
- * calling Dart_DeleteWeakPersistentHandle.
- *
- * If the object becomes unreachable the callback is invoked with the weak
- * persistent handle and the peer as arguments. This gives the native code the
- * ability to cleanup data associated with the object and clear out any cached
- * references to the handle. All references to this handle after the callback
- * will be invalid. It is illegal to call into the VM from the callback.
- * If the handle is deleted before the object becomes unreachable,
- * the callback is never invoked.
- *
- * Requires there to be a current isolate.
- *
- * \param object An object.
- * \param peer A pointer to a native object or NULL.  This value is
- *   provided to callback when it is invoked.
- * \param external_allocation_size The number of externally allocated
- *   bytes for peer. Used to inform the garbage collector.
- * \param callback A function pointer that will be invoked sometime
- *   after the object is garbage collected, unless the handle has been deleted.
- *   A valid callback needs to be specified it cannot be NULL.
- *
- * \return Success if the prologue weak persistent handle was created.
- *   Otherwise, returns an error.
- */
-DART_EXPORT Dart_WeakPersistentHandle Dart_NewPrologueWeakPersistentHandle(
-    Dart_Handle object,
-    void* peer,
-    intptr_t external_allocation_size,
-    Dart_WeakPersistentHandleFinalizer callback);
-
-/**
- * Is this object a prologue weak persistent handle?
- *
- * Requires there to be a current isolate.
- */
-DART_EXPORT bool Dart_IsPrologueWeakPersistentHandle(
-    Dart_WeakPersistentHandle object);
-
-typedef struct _Dart_WeakReferenceSetBuilder* Dart_WeakReferenceSetBuilder;
-typedef struct _Dart_WeakReferenceSet* Dart_WeakReferenceSet;
-
-/**
- * Constructs a weak references set builder.
- *
- * \returns a pointer to the weak reference set builder if successful.
- *   Otherwise, returns NULL.
- */
-DART_EXPORT Dart_WeakReferenceSetBuilder Dart_NewWeakReferenceSetBuilder();
-
-/**
- * Constructs a set of weak references from the Cartesian product of
- * the objects in the key set and the objects in values set.
- *
- * \param set_builder The weak references set builder which was created
- *   using Dart_NewWeakReferenceSetBuilder().
- * \param key An object reference.  This references will be
- *   considered weak by the garbage collector.
- * \param value An object reference.  This reference will be
- *   considered weak by garbage collector unless any object reference
- *   in 'keys' is found to be strong.
- *
- * \return a pointer to the weak reference set if successful.
- *   Otherwise, returns NULL.
- */
-DART_EXPORT Dart_WeakReferenceSet Dart_NewWeakReferenceSet(
-    Dart_WeakReferenceSetBuilder set_builder,
-    Dart_WeakPersistentHandle key,
-    Dart_WeakPersistentHandle value);
-
-/**
- * Append the pair of key/value object references to the weak references set.
- *
- * \param reference_set A weak references set into which the pair of key/value
- *   needs to be added.
- * \param key An object reference.  This references will be
- *   considered weak by the garbage collector.
- * \param value An object reference.  This reference will be
- *   considered weak by garbage collector unless any object reference
- *   in 'keys' is found to be strong.
- *
- * \return Success if the prologue weak persistent handle was created.
- *   Otherwise, returns an error.
- */
-DART_EXPORT Dart_Handle Dart_AppendToWeakReferenceSet(
-    Dart_WeakReferenceSet reference_set,
-    Dart_WeakPersistentHandle key,
-    Dart_WeakPersistentHandle value);
-
-/**
- * Append the key object reference to the weak references set.
- *
- * \param reference_set A weak references set into which the key
- *   needs to be added.
- * \param key An object reference.  This references will be
- *   considered weak by the garbage collector.
- *
- * \return Success if the prologue weak persistent handle was created.
- *   Otherwise, returns an error.
- */
-DART_EXPORT Dart_Handle Dart_AppendKeyToWeakReferenceSet(
-    Dart_WeakReferenceSet reference_set,
-    Dart_WeakPersistentHandle key);
-
-/**
- * Append the value object reference to the weak references set.
- *
- * \param reference_set A weak references set into which the key
- *   needs to be added.
- * \param value An object reference.  This references will be
- *   considered weak by the garbage collector.
- *
- * \return Success if the prologue weak persistent handle was created.
- *   Otherwise, returns an error.
- */
-DART_EXPORT Dart_Handle Dart_AppendValueToWeakReferenceSet(
-    Dart_WeakReferenceSet reference_set,
-    Dart_WeakPersistentHandle value);
-
 
 /*
  * ============================
@@ -785,28 +651,14 @@
 /**
  * An isolate interrupt callback function.
  *
- * This callback, provided by the embedder, is called when an isolate
- * is interrupted as a result of a call to Dart_InterruptIsolate().
- * When the callback is called, Dart_CurrentIsolate can be used to
- * figure out which isolate is being interrupted.
- *
- * \return The embedder returns true if the isolate should continue
- *   execution. If the embedder returns false, the isolate will be
- *   unwound (currently unimplemented).
+ * This callback has been DEPRECATED.
  */
 typedef bool (*Dart_IsolateInterruptCallback)();
-/* TODO(turnidge): Define and implement unwinding. */
 
 /**
  * An isolate unhandled exception callback function.
  *
- * This callback, provided by the embedder, is called when an unhandled
- * exception or internal error is thrown during isolate execution. When the
- * callback is invoked, Dart_CurrentIsolate can be used to figure out which
- * isolate was running when the exception was thrown.
- *
- * \param error The unhandled exception or error.  This handle's scope is
- *   only valid until the embedder returns from this callback.
+ * This callback has been DEPRECATED.
  */
 typedef void (*Dart_IsolateUnhandledExceptionCallback)(Dart_Handle error);
 
@@ -888,10 +740,8 @@
  *   instructions, or NULL if no snapshot is provided.
  * \param create A function to be called during isolate creation.
  *   See Dart_IsolateCreateCallback.
- * \param interrupt A function to be called when an isolate is interrupted.
- *   See Dart_IsolateInterruptCallback.
- * \param unhandled_exception A function to be called if an isolate has an
- *   unhandled exception.  Set Dart_IsolateUnhandledExceptionCallback.
+ * \param interrupt This parameter has been DEPRECATED.
+ * \param unhandled_exception This parameter has been DEPRECATED.
  * \param shutdown A function to be called when an isolate is shutdown.
  *   See Dart_IsolateShutdownCallback.
  *
diff --git a/runtime/lib/core_patch.dart b/runtime/lib/core_patch.dart
index 79749fd..224d532 100644
--- a/runtime/lib/core_patch.dart
+++ b/runtime/lib/core_patch.dart
@@ -73,3 +73,7 @@
     }
   }
 }
+
+patch class StackTrace {
+  /* patch */ static StackTrace get current native "StackTrace_current";
+}
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index 00efcae..dc52798 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -24,6 +24,9 @@
 
 namespace dart {
 
+DEFINE_FLAG(bool, i_like_slow_isolate_spawn, false,
+            "Block the parent thread when loading spawned isolates.");
+
 static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) {
   void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
   return reinterpret_cast<uint8_t*>(new_ptr);
@@ -217,16 +220,28 @@
       Dart_Port on_exit_port = onExit.IsNull() ? ILLEGAL_PORT : onExit.Id();
       Dart_Port on_error_port = onError.IsNull() ? ILLEGAL_PORT : onError.Id();
 
-      Dart::thread_pool()->Run(new SpawnIsolateTask(
-          new IsolateSpawnState(port.Id(),
-                                isolate->origin_id(),
-                                isolate->init_callback_data(),
-                                func,
-                                message,
-                                paused.value(),
-                                fatal_errors,
-                                on_exit_port,
-                                on_error_port)));
+      ThreadPool::Task* spawn_task =
+          new SpawnIsolateTask(
+              new IsolateSpawnState(port.Id(),
+                                    isolate->origin_id(),
+                                    isolate->init_callback_data(),
+                                    func,
+                                    message,
+                                    paused.value(),
+                                    fatal_errors,
+                                    on_exit_port,
+                                    on_error_port));
+      if (FLAG_i_like_slow_isolate_spawn) {
+        // We block the parent isolate while the child isolate loads.
+        Isolate* saved = Isolate::Current();
+        Thread::ExitIsolate();
+        spawn_task->Run();
+        delete spawn_task;
+        spawn_task = NULL;
+        Thread::EnterIsolate(saved);
+      } else {
+        Dart::thread_pool()->Run(spawn_task);
+      }
       return Object::null();
     }
   }
@@ -258,8 +273,8 @@
   if (handler != NULL) {
     Dart_EnterScope();
     Dart_Handle handle = handler(Dart_kCanonicalizeUrl,
-                                 Api::NewHandle(isolate, library.raw()),
-                                 Api::NewHandle(isolate, uri.raw()));
+                                 Api::NewHandle(thread, library.raw()),
+                                 Api::NewHandle(thread, uri.raw()));
     const Object& obj = Object::Handle(Api::UnwrapHandle(handle));
     if (obj.IsString()) {
       result = String2UTF8(String::Cast(obj));
@@ -302,6 +317,13 @@
   GET_NATIVE_ARGUMENT(String, package_root, arguments->NativeArgAt(10));
   GET_NATIVE_ARGUMENT(Array, packages, arguments->NativeArgAt(11));
 
+  if (Dart::IsRunningPrecompiledCode()) {
+    const Array& args = Array::Handle(Array::New(1));
+    args.SetAt(0, String::Handle(String::New(
+        "Isolate.spawnUri not supported under precompilation")));
+    Exceptions::ThrowByType(Exceptions::kUnsupported, args);
+    UNREACHABLE();
+  }
 
   // Canonicalize the uri with respect to the current isolate.
   const Library& root_lib =
@@ -339,25 +361,38 @@
   Dart_Port on_exit_port = onExit.IsNull() ? ILLEGAL_PORT : onExit.Id();
   Dart_Port on_error_port = onError.IsNull() ? ILLEGAL_PORT : onError.Id();
 
-  IsolateSpawnState* state = new IsolateSpawnState(
-      port.Id(),
-      isolate->init_callback_data(),
-      canonical_uri,
-      utf8_package_root,
-      const_cast<const char**>(utf8_package_map),
-      args,
-      message,
-      paused.value(),
-      fatal_errors,
-      on_exit_port,
-      on_error_port);
+  IsolateSpawnState* state =
+      new IsolateSpawnState(
+          port.Id(),
+          isolate->init_callback_data(),
+          canonical_uri,
+          utf8_package_root,
+          const_cast<const char**>(utf8_package_map),
+          args,
+          message,
+          paused.value(),
+          fatal_errors,
+          on_exit_port,
+          on_error_port);
+
   // If we were passed a value then override the default flags state for
   // checked mode.
   if (!checked.IsNull()) {
     state->isolate_flags()->set_checked(checked.value());
   }
 
-  Dart::thread_pool()->Run(new SpawnIsolateTask(state));
+  ThreadPool::Task* spawn_task = new SpawnIsolateTask(state);
+  if (FLAG_i_like_slow_isolate_spawn) {
+    // We block the parent isolate while the child isolate loads.
+    Isolate* saved = Isolate::Current();
+    Thread::ExitIsolate();
+    spawn_task->Run();
+    delete spawn_task;
+    spawn_task = NULL;
+    Thread::EnterIsolate(saved);
+  } else {
+    Dart::thread_pool()->Run(spawn_task);
+  }
   return Object::null();
 }
 
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 4b8627f..53af2c4 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -2024,8 +2024,7 @@
     token_pos = cls.token_pos();
   } else if (decl.IsField()) {
     const Field& field = Field::Cast(decl);
-    const Class& owner = Class::Handle(field.owner());
-    script = owner.script();
+    script = field.script();
     token_pos = field.token_pos();
   } else if (decl.IsTypeParameter()) {
     const TypeParameter& type_var = TypeParameter::Cast(decl);
diff --git a/runtime/lib/stacktrace.cc b/runtime/lib/stacktrace.cc
index 6175b24..7b79314 100644
--- a/runtime/lib/stacktrace.cc
+++ b/runtime/lib/stacktrace.cc
@@ -11,7 +11,8 @@
 namespace dart {
 
 static void IterateFrames(const GrowableObjectArray& code_list,
-                          const GrowableObjectArray& pc_offset_list) {
+                          const GrowableObjectArray& pc_offset_list,
+                          int skip_frames) {
   StackFrameIterator frames(StackFrameIterator::kDontValidateFrames);
   StackFrame* frame = frames.NextFrame();
   ASSERT(frame != NULL);  // We expect to find a dart invocation frame.
@@ -19,15 +20,35 @@
   Smi& offset = Smi::Handle();
   while (frame != NULL) {
     if (frame->IsDartFrame()) {
-      code = frame->LookupDartCode();
-      offset = Smi::New(frame->pc() - code.EntryPoint());
-      code_list.Add(code);
-      pc_offset_list.Add(offset);
+      if (skip_frames > 0) {
+        skip_frames--;
+      } else {
+        code = frame->LookupDartCode();
+        offset = Smi::New(frame->pc() - code.EntryPoint());
+        code_list.Add(code);
+        pc_offset_list.Add(offset);
+      }
     }
     frame = frames.NextFrame();
   }
 }
 
+// Creates a Stacktrace object from the current stack.
+//
+// Skips the first skip_frames Dart frames.
+static const Stacktrace& GetCurrentStacktrace(int skip_frames) {
+  const GrowableObjectArray& code_list =
+      GrowableObjectArray::Handle(GrowableObjectArray::New());
+  const GrowableObjectArray& pc_offset_list =
+      GrowableObjectArray::Handle(GrowableObjectArray::New());
+  IterateFrames(code_list, pc_offset_list, skip_frames);
+  const Array& code_array = Array::Handle(Array::MakeArray(code_list));
+  const Array& pc_offset_array =
+      Array::Handle(Array::MakeArray(pc_offset_list));
+  const Stacktrace& stacktrace = Stacktrace::Handle(
+      Stacktrace::New(code_array, pc_offset_array));
+  return stacktrace;
+}
 
 // An utility method for convenient printing of dart stack traces when
 // inside 'gdb'. Note: This function will only work when there is a
@@ -35,17 +56,13 @@
 // set in dart code and control is got inside 'gdb' without going through
 // the runtime or native transition stub.
 void _printCurrentStacktrace() {
-  const GrowableObjectArray& code_list =
-      GrowableObjectArray::Handle(GrowableObjectArray::New());
-  const GrowableObjectArray& pc_offset_list =
-      GrowableObjectArray::Handle(GrowableObjectArray::New());
-  IterateFrames(code_list, pc_offset_list);
-  const Array& code_array = Array::Handle(Array::MakeArray(code_list));
-  const Array& pc_offset_array =
-      Array::Handle(Array::MakeArray(pc_offset_list));
-  const Stacktrace& stacktrace = Stacktrace::Handle(
-      Stacktrace::New(code_array, pc_offset_array));
+  const Stacktrace& stacktrace = GetCurrentStacktrace(0);
   OS::PrintErr("=== Current Trace:\n%s===\n", stacktrace.ToCString());
 }
 
+DEFINE_NATIVE_ENTRY(StackTrace_current, 0) {
+  const Stacktrace& stacktrace = GetCurrentStacktrace(1);
+  return stacktrace.raw();
+}
+
 }  // namespace dart
diff --git a/runtime/lib/timeline.cc b/runtime/lib/timeline.cc
index a26c847..39fa28b 100644
--- a/runtime/lib/timeline.cc
+++ b/runtime/lib/timeline.cc
@@ -55,7 +55,9 @@
   }
 
   int64_t pid = OS::ProcessId();
-  int64_t tid = OSThread::ThreadIdToIntPtr(OSThread::GetCurrentThreadTraceId());
+  OSThread* os_thread = thread->os_thread();
+  ASSERT(os_thread != NULL);
+  int64_t tid = OSThread::ThreadIdToIntPtr(os_thread->trace_id());
 
   char* json = OS::SCreate(zone,
       "{\"name\":\"%s\",\"cat\":\"%s\",\"tid\":%" Pd64 ",\"pid\":%" Pd64 ","
@@ -101,7 +103,9 @@
 
   int64_t duration = end.AsInt64Value() - start.AsInt64Value();
   int64_t pid = OS::ProcessId();
-  int64_t tid = OSThread::ThreadIdToIntPtr(OSThread::GetCurrentThreadTraceId());
+  OSThread* os_thread = thread->os_thread();
+  ASSERT(os_thread != NULL);
+  int64_t tid = OSThread::ThreadIdToIntPtr(os_thread->trace_id());
 
   char* json = OS::SCreate(zone,
       "{\"name\":\"%s\",\"cat\":\"%s\",\"tid\":%" Pd64 ",\"pid\":%" Pd64 ","
@@ -144,7 +148,9 @@
   }
 
   int64_t pid = OS::ProcessId();
-  int64_t tid = OSThread::ThreadIdToIntPtr(OSThread::GetCurrentThreadTraceId());
+  OSThread* os_thread = thread->os_thread();
+  ASSERT(os_thread != NULL);
+  int64_t tid = OSThread::ThreadIdToIntPtr(os_thread->trace_id());
 
   char* json = OS::SCreate(zone,
       "{\"name\":\"%s\",\"cat\":\"%s\",\"tid\":%" Pd64 ",\"pid\":%" Pd64 ","
diff --git a/runtime/lib/vmservice.cc b/runtime/lib/vmservice.cc
index 12aadb6..83a25e1 100644
--- a/runtime/lib/vmservice.cc
+++ b/runtime/lib/vmservice.cc
@@ -3,9 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 #include "vm/bootstrap_natives.h"
-
 #include "vm/dart_api_impl.h"
+#include "vm/datastream.h"
 #include "vm/exceptions.h"
+#include "vm/growable_array.h"
 #include "vm/message.h"
 #include "vm/native_entry.h"
 #include "vm/object.h"
@@ -151,4 +152,245 @@
   return Service::RequestAssets();
 }
 
+
+// TODO(25041): When reading, this class copies out the filenames and contents
+// into new buffers. It does this because the lifetime of |bytes| is uncertain.
+// If |bytes| is pinned in memory, then we could instead load up
+// |filenames_| and |contents_| with pointers into |bytes| without making
+// copies.
+class TarArchive {
+ public:
+  TarArchive(uint8_t* bytes, intptr_t bytes_length)
+      : rs_(bytes, bytes_length) {}
+
+  void Read() {
+    while (HasNext()) {
+      char* filename;
+      uint8_t* data;
+      intptr_t data_length;
+      if (Next(&filename, &data, &data_length)) {
+        filenames_.Add(filename);
+        contents_.Add(data);
+        content_lengths_.Add(data_length);
+      }
+    }
+  }
+
+  char* NextFilename() {
+    return filenames_.RemoveLast();
+  }
+
+  uint8_t* NextContent() {
+    return contents_.RemoveLast();
+  }
+
+  intptr_t NextContentLength() {
+    return content_lengths_.RemoveLast();
+  }
+
+  bool HasMore() const {
+    return filenames_.length() > 0;
+  }
+
+  intptr_t Length() const { return filenames_.length(); }
+
+ private:
+  enum TarHeaderFields {
+    kTarHeaderFilenameOffset = 0,
+    kTarHeaderFilenameSize = 100,
+    kTarHeaderSizeOffset = 124,
+    kTarHeaderSizeSize = 12,
+    kTarHeaderTypeOffset = 156,
+    kTarHeaderTypeSize = 1,
+    kTarHeaderSize = 512,
+  };
+
+  enum TarType {
+    kTarAregType = '\0',
+    kTarRegType = '0',
+    kTarLnkType = '1',
+    kTarSymType = '2',
+    kTarChrType = '3',
+    kTarBlkType = '4',
+    kTarDirType = '5',
+    kTarFifoType = '6',
+    kTarContType = '7',
+    kTarXhdType = 'x',
+    kTarXglType = 'g',
+  };
+
+  bool HasNext() const {
+    return !EndOfArchive();
+  }
+
+  bool Next(char** filename, uint8_t** data, intptr_t* data_length) {
+    intptr_t startOfBlock = rs_.Position();
+    *filename = ReadFilename();
+    rs_.SetPosition(startOfBlock + kTarHeaderSizeOffset);
+    intptr_t size = ReadSize();
+    rs_.SetPosition(startOfBlock + kTarHeaderTypeOffset);
+    TarType type = ReadType();
+    SeekToNextBlock(kTarHeaderSize);
+    if ((type != kTarRegType) && (type != kTarAregType)) {
+      SkipContents(size);
+      return false;
+    }
+    ReadContents(data, size);
+    *data_length = size;
+    return true;
+  }
+
+  void SeekToNextBlock(intptr_t blockSize) {
+    intptr_t remainder = blockSize - (rs_.Position() % blockSize);
+    rs_.Advance(remainder);
+  }
+
+  uint8_t PeekByte(intptr_t i) const {
+    return *(rs_.AddressOfCurrentPosition() + i);
+  }
+
+  bool EndOfArchive() const {
+    if (rs_.PendingBytes() < (kTarHeaderSize * 2)) {
+      return true;
+    }
+    for (intptr_t i = 0; i < (kTarHeaderSize * 2); i++) {
+      if (PeekByte(i) != 0) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  TarType ReadType() {
+    return static_cast<TarType>(ReadStream::Raw<1, uint8_t>::Read(&rs_));
+  }
+
+  void SkipContents(intptr_t size) {
+    rs_.Advance(size);
+    SeekToNextBlock(kTarHeaderSize);
+  }
+
+  intptr_t ReadCString(char** s, intptr_t length) {
+    intptr_t to_read = Utils::Minimum(length, rs_.PendingBytes());
+    char* result = new char[to_read + 1];
+    strncpy(result,
+            reinterpret_cast<const char*>(rs_.AddressOfCurrentPosition()),
+            to_read);
+    result[to_read] = '\0';
+    rs_.SetPosition(rs_.Position() + to_read);
+    *s = result;
+    return to_read;
+  }
+
+  intptr_t ReadSize() {
+    char* octalSize;
+    unsigned int size;
+
+    ReadCString(&octalSize, kTarHeaderSizeSize);
+    int result = sscanf(octalSize, "%o", &size);
+    delete[] octalSize;
+
+    if (result != 1) {
+      return 0;
+    }
+    return size;
+  }
+
+  char* ReadFilename() {
+    char* result;
+    intptr_t result_length = ReadCString(&result, kTarHeaderFilenameSize);
+    if (result[0] == '/') {
+      return result;
+    }
+    char* fixed_result = new char[result_length + 2];  // '/' + '\0'.
+    fixed_result[0] = '/';
+    strncpy(&fixed_result[1], result, result_length);
+    fixed_result[result_length + 1] = '\0';
+    delete[] result;
+    return fixed_result;
+  }
+
+  void ReadContents(uint8_t** data, intptr_t size) {
+    uint8_t* result = new uint8_t[size];
+    rs_.ReadBytes(result, size);
+    SeekToNextBlock(kTarHeaderSize);
+    *data = result;
+  }
+
+  ReadStream rs_;
+  GrowableArray<char*> filenames_;
+  GrowableArray<uint8_t*> contents_;
+  GrowableArray<intptr_t> content_lengths_;
+
+  DISALLOW_COPY_AND_ASSIGN(TarArchive);
+};
+
+
+static void ContentsFinalizer(void* isolate_callback_data,
+                              Dart_WeakPersistentHandle handle,
+                              void* peer) {
+  uint8_t* data = reinterpret_cast<uint8_t*>(peer);
+  delete[] data;
+}
+
+
+static void FilenameFinalizer(void* peer) {
+  char* filename = reinterpret_cast<char*>(peer);
+  delete[] filename;
+}
+
+
+DEFINE_NATIVE_ENTRY(VMService_DecodeAssets, 1) {
+  GET_NON_NULL_NATIVE_ARGUMENT(TypedData, data, arguments->NativeArgAt(0));
+  Api::Scope scope(thread);
+
+  Dart_Handle data_handle = Api::NewHandle(thread, data.raw());
+
+  Dart_TypedData_Type typ;
+  void* bytes;
+  intptr_t length;
+  Dart_Handle err = Dart_TypedDataAcquireData(
+      data_handle, &typ, &bytes, &length);
+  ASSERT(!Dart_IsError(err));
+
+  TarArchive archive(reinterpret_cast<uint8_t*>(bytes), length);
+  archive.Read();
+
+  err = Dart_TypedDataReleaseData(data_handle);
+  ASSERT(!Dart_IsError(err));
+
+  intptr_t archive_size = archive.Length();
+
+  const Array& result_list = Array::Handle(thread->zone(),
+    Array::New(2 * archive_size));
+
+  intptr_t idx = 0;
+  while (archive.HasMore()) {
+    char* filename = archive.NextFilename();
+    uint8_t* contents = archive.NextContent();
+    intptr_t contents_length = archive.NextContentLength();
+
+    Dart_Handle dart_filename = Dart_NewExternalLatin1String(
+        reinterpret_cast<uint8_t*>(filename),
+        strlen(filename),
+        filename,
+        FilenameFinalizer);
+    ASSERT(!Dart_IsError(dart_filename));
+
+    Dart_Handle dart_contents = Dart_NewExternalTypedData(
+        Dart_TypedData_kUint8, contents, contents_length);
+    ASSERT(!Dart_IsError(dart_contents));
+    Dart_NewWeakPersistentHandle(
+        dart_contents, contents, contents_length, ContentsFinalizer);
+
+    result_list.SetAt(idx, Api::UnwrapStringHandle(
+        thread->zone(), dart_filename));
+    result_list.SetAt(idx + 1, Api::UnwrapExternalTypedDataHandle(
+        thread->zone(), dart_contents));
+    idx += 2;
+  }
+
+  return result_list.raw();
+}
+
 }  // namespace dart
diff --git a/runtime/lib/vmservice_patch.dart b/runtime/lib/vmservice_patch.dart
index a885004..3db7bca 100644
--- a/runtime/lib/vmservice_patch.dart
+++ b/runtime/lib/vmservice_patch.dart
@@ -2,6 +2,25 @@
 // 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.
 
+patch class Asset {
+  /// Call to request assets from the embedder.
+  /* patch */ static HashMap<String, Asset> request() {
+    HashMap<String, Asset> assets = new HashMap<String, Asset>();
+    Uint8List tarBytes = _requestAssets();
+    if (tarBytes == null) {
+      return assets;
+    }
+    List assetList = _decodeAssets(tarBytes);
+    for (int i = 0; i < assetList.length; i += 2) {
+      var a = new Asset(assetList[i], assetList[i + 1]);
+      assets[a.name] = a;
+    }
+    return assets;
+  }
+}
+
+List _decodeAssets(Uint8List data) native "VMService_DecodeAssets";
+
 patch bool sendIsolateServiceMessage(SendPort sp, List m)
     native "VMService_SendIsolateServiceMessage";
 patch void sendRootServiceMessage(List m)
@@ -10,4 +29,4 @@
 patch void _onExit() native "VMService_OnExit";
 patch bool _vmListenStream(String streamId) native "VMService_ListenStream";
 patch void _vmCancelStream(String streamId) native "VMService_CancelStream";
-patch Uint8List _requestAssets() native "VMService_RequestAssets";
\ No newline at end of file
+patch Uint8List _requestAssets() native "VMService_RequestAssets";
diff --git a/runtime/observatory/lib/src/elements/class_ref.dart b/runtime/observatory/lib/src/elements/class_ref.dart
index 5eebe73..b8895c6 100644
--- a/runtime/observatory/lib/src/elements/class_ref.dart
+++ b/runtime/observatory/lib/src/elements/class_ref.dart
@@ -4,23 +4,33 @@
 
 library class_ref_element;
 
+import 'package:observatory/service.dart';
 import 'package:polymer/polymer.dart';
 import 'service_ref.dart';
+import 'dart:async';
 
 @CustomTag('class-ref')
 class ClassRefElement extends ServiceRefElement {
+  @observable bool asValue = false;
+
   ClassRefElement.created() : super.created();
 
-  refChanged(oldValue) {
-    super.refChanged(oldValue);
-    _updateShadowDom();
+  String makeExpandKey(String key) {
+    return '${expandKey}/${key}';
   }
 
-  void _updateShadowDom() {
-    clearShadowRoot();
-    if (ref == null) {
-      return;
+  dynamic expander() {
+    return expandEvent;
+  }
+
+  void expandEvent(bool expand, Function onDone) {
+    if (expand) {
+      Class cls = ref;
+      cls.reload().then((result) {
+        return Future.wait(cls.fields.map((field) => field.reload()));
+      }).whenComplete(onDone);
+    } else {
+      onDone();
     }
-    insertLinkIntoShadowRoot(name, url, hoverText);
   }
 }
\ No newline at end of file
diff --git a/runtime/observatory/lib/src/elements/class_ref.html b/runtime/observatory/lib/src/elements/class_ref.html
index e3f908a..c3ddec7 100644
--- a/runtime/observatory/lib/src/elements/class_ref.html
+++ b/runtime/observatory/lib/src/elements/class_ref.html
@@ -1,8 +1,34 @@
 <link rel="import" href="../../../../packages/polymer/polymer.html">
+<link rel="import" href="curly_block.html">
+<link rel="import" href="observatory_element.html">
 <link rel="import" href="service_ref.html">
 
 <polymer-element name="class-ref" extends="service-ref">
-  <template><link rel="stylesheet" href="css/shared.css"></template>
+  <template>
+    <link rel="stylesheet" href="css/shared.css">
+    <style>
+      .indented {
+        margin-left: 1.5em;
+        font: 400 14px 'Montserrat', sans-serif;
+        line-height: 150%;
+      }
+    </style><!--
+    --><a on-click="{{ goto }}" _href="{{ url }}">{{ ref.name }}</a><!--
+    --><template if="{{ asValue }}">
+      <curly-block callback="{{ expander() }}" expandKey="{{ expandKey }}">
+        <div class="indented">
+          <template repeat="{{ field in ref.fields }}">
+            <template if="{{ field.isStatic }}">
+              {{ field.name }}&nbsp;:&nbsp;
+              <any-service-ref ref="{{ field.staticValue }}"
+                               expandKey="{{ makeExpandKey(field.name) }}">
+              </any-service-ref><br>
+            </template>
+          </template>
+        </div>
+      </curly-block>
+    </template><!--
+  --></template>
 </polymer-element>
 
 <script type="application/dart" src="class_ref.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/class_tree.html b/runtime/observatory/lib/src/elements/class_tree.html
index 7f40600..c1e9635 100644
--- a/runtime/observatory/lib/src/elements/class_tree.html
+++ b/runtime/observatory/lib/src/elements/class_tree.html
@@ -27,16 +27,14 @@
       }
     </style>
     <nav-bar>
-      <top-nav-menu last="{{ true }}"></top-nav-menu>
+      <top-nav-menu></top-nav-menu>
+      <vm-nav-menu vm="{{ isolate.vm }}"></vm-nav-menu>
+      <isolate-nav-menu isolate="{{ isolate }}"></isolate-nav-menu>
+      <nav-menu link="{{ makeLink('/class-tree', isolate) }}" anchor="class hierarchy" last="{{ true }}"></nav-menu>
     </nav-bar>
     <div class="content-centered">
       <h1>Class Hierarchy</h1>
       <table id="tableTree" class="table">
-        <thead id="tableTreeHeader">
-          <tr>
-            <th>Class</th>
-          </tr>
-        </thead>
         <tbody id="tableTreeBody"></tbody>
       </table>
     </div>
diff --git a/runtime/observatory/lib/src/elements/class_view.dart b/runtime/observatory/lib/src/elements/class_view.dart
index 998f82d..8c67ebc 100644
--- a/runtime/observatory/lib/src/elements/class_view.dart
+++ b/runtime/observatory/lib/src/elements/class_view.dart
@@ -15,6 +15,7 @@
 class ClassViewElement extends ObservatoryElement {
   @published Class cls;
   @observable ServiceMap instances;
+  @observable int reachableBytes;
   @observable int retainedBytes;
   @observable ObservableList mostRetained;
   SampleBufferControlElement sampleBufferControlElement;
@@ -44,6 +45,12 @@
   }
 
   // TODO(koda): Add no-arg "calculate-link" instead of reusing "eval-link".
+  Future<ServiceObject> reachableSize(var dummy) {
+    return cls.isolate.getReachableSize(cls).then((Instance obj) {
+      reachableBytes = int.parse(obj.valueAsString);
+    });
+  }
+
   Future<ServiceObject> retainedSize(var dummy) {
     return cls.isolate.getRetainedSize(cls).then((Instance obj) {
       retainedBytes = int.parse(obj.valueAsString);
diff --git a/runtime/observatory/lib/src/elements/class_view.html b/runtime/observatory/lib/src/elements/class_view.html
index 5dadba6..6e59887 100644
--- a/runtime/observatory/lib/src/elements/class_view.html
+++ b/runtime/observatory/lib/src/elements/class_view.html
@@ -181,6 +181,19 @@
             </div>
           </div>
           <div class="memberItem">
+            <div class="memberName">total reachable memory size</div>
+            <div class="memberValue">
+              <template if="{{ reachableBytes == null }}">
+                <eval-link callback="{{ reachableSize }}"
+                           label="[calculate]">
+                </eval-link>
+              </template>
+              <template if="{{ reachableBytes != null }}">
+                {{ reachableBytes | formatSize }}
+              </template>
+            </div>
+          </div>
+          <div class="memberItem">
             <div class="memberName">total retained memory size</div>
             <div class="memberValue">
               <template if="{{ retainedBytes == null }}">
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index f464581..cf78a26 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -2231,6 +2231,23 @@
         busy = false;
       });
   }
+
+  @observable
+  get properLocals {
+    var locals = new List();
+    var homeMethod = frame.function.homeMethod;
+    if (homeMethod.dartOwner is Class && homeMethod.isStatic) {
+      locals.add(
+          {'name' : '<class>',
+           'value' : homeMethod.dartOwner});
+    } else if (homeMethod.dartOwner is Library) {
+      locals.add(
+          {'name' : '<library>',
+           'value' : homeMethod.dartOwner});
+    }
+    locals.addAll(frame.variables);
+    return locals;
+  }
 }
 
 @CustomTag('debugger-message')
diff --git a/runtime/observatory/lib/src/elements/debugger.html b/runtime/observatory/lib/src/elements/debugger.html
index 5b74667..981f260 100644
--- a/runtime/observatory/lib/src/elements/debugger.html
+++ b/runtime/observatory/lib/src/elements/debugger.html
@@ -267,16 +267,13 @@
               </source-inset>
             </div>
             <div class="flex-item-vars">
-              <div style="padding:10px;" class="memberList">
-                <template repeat="{{ v in frame.variables }}">
-                  <div class="memberItem">
-                    <div class="memberName">{{ v['name']}}</div>
-                    <div class="memberValue">
-                      <any-service-ref ref="{{ v['value'] }}"
-                                       expandKey="{{ makeExpandKey(v['name']) }}">
-                      </any-service-ref>
-                    </div>
-                  </div>
+              <div style="padding-left:2em;" class="memberList">
+                <template repeat="{{ v in properLocals }}">
+                  {{ v['name']}}&nbsp;:&nbsp;
+                  <any-service-ref ref="{{ v['value'] }}"
+                                   expandKey="{{ makeExpandKey(v['name']) }}"
+                                   asValue="{{ true }}">
+                  </any-service-ref><br>
                 </template>
               </div>
             </div>
diff --git a/runtime/observatory/lib/src/elements/flag_list.html b/runtime/observatory/lib/src/elements/flag_list.html
index 017e28d..9a39cbb 100644
--- a/runtime/observatory/lib/src/elements/flag_list.html
+++ b/runtime/observatory/lib/src/elements/flag_list.html
@@ -8,6 +8,7 @@
     <link rel="stylesheet" href="css/shared.css">
     <nav-bar>
       <top-nav-menu></top-nav-menu>
+      <vm-nav-menu vm="{{ app.vm }}"></vm-nav-menu>
       <nav-menu link="{{ makeLink('/flags') }}" anchor="flags" last="{{ true }}"></nav-menu>
       <nav-refresh callback="{{ refresh }}"></nav-refresh>
     </nav-bar>
diff --git a/runtime/observatory/lib/src/elements/instance_ref.html b/runtime/observatory/lib/src/elements/instance_ref.html
index 57dcec9..7125f16 100644
--- a/runtime/observatory/lib/src/elements/instance_ref.html
+++ b/runtime/observatory/lib/src/elements/instance_ref.html
@@ -87,6 +87,9 @@
                                expandKey="{{ makeExpandKey(index.toString()) }}">
               </any-service-ref><br>
             </template>
+            <template if="{{ ref.length != ref.elements.length }}">
+              <div><em>{{ ref.length - ref.elements.length }} omitted elements</em></div>
+            </template>
           </div>
         </curly-block>
       </template>
@@ -103,6 +106,9 @@
                                  expandKey="{{ makeExpandKey('value') }}">
               </any-service-ref><br>
             </template>
+            <template if="{{ ref.length != ref.association.length }}">
+              <div><em>{{ ref.length - ref.association.length }} omitted association</em></div>
+            </template>
           </div>
         </curly-block>
       </template>
@@ -115,6 +121,9 @@
               [ {{ index }} ]&nbsp;&nbsp;
               {{ ref.typedElements[index].toString() }}<br>
             </template>
+            <template if="{{ ref.length != ref.typedElements.length }}">
+              <div><em>{{ ref.length - ref.typedElements.length }} omitted elements</em></div>
+            </template>
           </div>
         </curly-block>
       </template>
diff --git a/runtime/observatory/lib/src/elements/instance_view.html b/runtime/observatory/lib/src/elements/instance_view.html
index 28f093f..f54059f 100644
--- a/runtime/observatory/lib/src/elements/instance_view.html
+++ b/runtime/observatory/lib/src/elements/instance_view.html
@@ -154,7 +154,7 @@
         </template>
 
         <template if="{{ instance.elements.isNotEmpty }}">
-          elements ({{ instance.elements.length }})
+          elements ({{ instance.length }})
           <curly-block expand="{{ instance.elements.length <= 100 }}">
             <div class="memberList">
               <template repeat="{{ index in instance.elements.asMap().keys }}">
@@ -166,12 +166,20 @@
                   </div>
                 </div>
               </template>
+	      <template if="{{ instance.length != instance.elements.length }}">
+                <div class="memberItem">
+                  <div class="memberName">...</div>
+                  <div class="memberValue">
+                    <em>{{ instance.length - instance.elements.length }} omitted elements</em>
+                  </div>
+                </div>
+              </template>
             </div>
           </curly-block><br><br>
         </template>
 
         <template if="{{ instance.associations.isNotEmpty }}">
-          associations ({{ instance.elements.length }})
+          associations ({{ instance.length }})
           <curly-block expand="{{ instance.associations.length <= 100 }}">
             <div class="memberList">
               <template repeat="{{ association in instance.associations }}">
@@ -184,12 +192,20 @@
                   </div>
                 </div>
               </template>
+	      <template if="{{ instance.length != instance.associations.length }}">
+                <div class="memberItem">
+                  <div class="memberName">...</div>
+                  <div class="memberValue">
+                    <em>{{ instance.length - instance.associations.length }} omitted associations</em>
+                  </div>
+                </div>
+              </template>
             </div>
           </curly-block><br><br>
         </template>
 
         <template if="{{ instance.typedElements.isNotEmpty }}">
-          elements ({{ instance.typedElements.length }})
+          elements ({{ instance.length }})
           <curly-block expand="{{ instance.typedElements.length <= 100 }}">
             <div class="memberList">
               <template repeat="{{ index in instance.typedElements.asMap().keys }}">
@@ -198,6 +214,14 @@
                   <div class="memberValue">{{ instance.typedElements[index].toString() }}</div>
                 </div>
               </template>
+	      <template if="{{ instance.length != instance.typedElements.length }}">
+                <div class="memberItem">
+                  <div class="memberName">...</div>
+                  <div class="memberValue">
+                    <em>{{ instance.length - instance.elements.length }} omitted elements</em>
+                  </div>
+                </div>
+              </template>
             </div>
           </curly-block><br><br>
         </template>
diff --git a/runtime/observatory/lib/src/elements/library_ref.dart b/runtime/observatory/lib/src/elements/library_ref.dart
index cbe7d4b..4f65a39 100644
--- a/runtime/observatory/lib/src/elements/library_ref.dart
+++ b/runtime/observatory/lib/src/elements/library_ref.dart
@@ -4,10 +4,33 @@
 
 library library_ref_element;
 
+import 'package:observatory/service.dart';
 import 'package:polymer/polymer.dart';
 import 'service_ref.dart';
+import 'dart:async';
 
 @CustomTag('library-ref')
 class LibraryRefElement extends ServiceRefElement {
+  @observable bool asValue = false;
+
   LibraryRefElement.created() : super.created();
+
+  String makeExpandKey(String key) {
+    return '${expandKey}/${key}';
+  }
+
+  dynamic expander() {
+    return expandEvent;
+  }
+
+  void expandEvent(bool expand, Function onDone) {
+    if (expand) {
+      Library lib = ref;
+      lib.reload().then((result) {
+        return Future.wait(lib.variables.map((field) => field.reload()));
+      }).whenComplete(onDone);
+    } else {
+      onDone();
+    }
+  }
 }
diff --git a/runtime/observatory/lib/src/elements/library_ref.html b/runtime/observatory/lib/src/elements/library_ref.html
index 30272a4..a4313c1 100644
--- a/runtime/observatory/lib/src/elements/library_ref.html
+++ b/runtime/observatory/lib/src/elements/library_ref.html
@@ -1,15 +1,39 @@
 <link rel="import" href="../../../../packages/polymer/polymer.html">
+<link rel="import" href="curly_block.html">
+<link rel="import" href="observatory_element.html">
 <link rel="import" href="service_ref.html">
 
 <polymer-element name="library-ref" extends="service-ref">
-  <template><link rel="stylesheet" href="css/shared.css"><!--
-    --><template if="{{ nameIsEmpty }}"><!--
-      --><a on-click="{{ goto }}" _href="{{ url }}">unnamed</a><!--
-    --></template><!--
-    --><template if="{{ !nameIsEmpty }}"><!--
-      --><a on-click="{{ goto }}" _href="{{ url }}">{{ name }}</a><!--
-    --></template><!--
-  --></template>
+  <template>
+    <link rel="stylesheet" href="css/shared.css">
+    <style>
+      .indented {
+      margin-left: 1.5em;
+      font: 400 14px 'Montserrat', sans-serif;
+      line-height: 150%;
+      }
+    </style>
+    <template if="{{ nameIsEmpty }}">
+      <a on-click="{{ goto }}" _href="{{ url }}">unnamed</a>
+    </template>
+    <template if="{{ !nameIsEmpty }}">
+      <a on-click="{{ goto }}" _href="{{ url }}">{{ name }}</a>
+    </template>
+    <template if="{{ asValue }}">
+      <curly-block callback="{{ expander() }}" expandKey="{{ expandKey }}">
+        <div class="indented">
+          <template repeat="{{ field in ref.variables }}">
+            <template if="{{ field.isStatic }}">
+              {{ field.name }}&nbsp;:&nbsp;
+              <any-service-ref ref="{{ field.staticValue }}"
+                               expandKey="{{ makeExpandKey(field.name) }}">
+              </any-service-ref><br>
+            </template>
+          </template>
+        </div>
+      </curly-block>
+    </template>
+  </template>
 </polymer-element>
 
 <script type="application/dart" src="library_ref.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/object_common.dart b/runtime/observatory/lib/src/elements/object_common.dart
index eea85ff..1deb5d6 100644
--- a/runtime/observatory/lib/src/elements/object_common.dart
+++ b/runtime/observatory/lib/src/elements/object_common.dart
@@ -15,10 +15,18 @@
   @published ServiceMap path;
   @published ServiceMap inboundReferences;
   @observable int retainedBytes = null;
+  @observable int reachableBytes = null;
 
   ObjectCommonElement.created() : super.created();
 
   // TODO(koda): Add no-arg "calculate-link" instead of reusing "eval-link".
+  Future<ServiceObject> reachableSize(var dummy) {
+    return object.isolate.getReachableSize(object).then((Instance obj) {
+      // TODO(turnidge): Handle collected/expired objects gracefully.
+      reachableBytes = int.parse(obj.valueAsString);
+    });
+  }
+
   Future<ServiceObject> retainedSize(var dummy) {
     return object.isolate.getRetainedSize(object).then((Instance obj) {
       // TODO(turnidge): Handle collected/expired objects gracefully.
diff --git a/runtime/observatory/lib/src/elements/object_common.html b/runtime/observatory/lib/src/elements/object_common.html
index 7cad87a..14311e0 100644
--- a/runtime/observatory/lib/src/elements/object_common.html
+++ b/runtime/observatory/lib/src/elements/object_common.html
@@ -26,6 +26,20 @@
         <div class="memberValue">{{ object.size | formatSize }}</div>
       </div>
 
+      <div class="memberItem" title="Space reachable from this object, excluding class references">
+        <div class="memberName">reachable size</div>
+        <div class="memberValue">
+          <template if="{{ reachableBytes == null }}">
+            <eval-link callback="{{ reachableSize }}"
+                       label="[calculate]">
+            </eval-link>
+          </template>
+          <template if="{{ reachableBytes != null }}">
+            {{ reachableBytes | formatSize }}
+          </template>
+        </div>
+      </div>
+
       <div class="memberItem" title="Space that would be reclaimed if references to this object were replaced with null">
         <div class="memberName">retained size</div>
         <div class="memberValue">
diff --git a/runtime/observatory/lib/src/elements/service_ref.dart b/runtime/observatory/lib/src/elements/service_ref.dart
index 9798795..e9aad6d 100644
--- a/runtime/observatory/lib/src/elements/service_ref.dart
+++ b/runtime/observatory/lib/src/elements/service_ref.dart
@@ -5,10 +5,14 @@
 library service_ref_element;
 
 import 'dart:html';
+
 import 'package:logging/logging.dart';
-import 'package:polymer/polymer.dart';
-import 'observatory_element.dart';
 import 'package:observatory/service.dart';
+import 'package:polymer/polymer.dart';
+
+import 'class_ref.dart';
+import 'library_ref.dart';
+import 'observatory_element.dart';
 
 @CustomTag('service-ref')
 class ServiceRefElement extends ObservatoryElement {
@@ -81,14 +85,16 @@
 class AnyServiceRefElement extends ObservatoryElement {
   @published ServiceObject ref;
   @published String expandKey;
+  @published bool asValue = false;
   AnyServiceRefElement.created() : super.created();
 
   Element _constructElementForRef() {
     var type = ref.type;
     switch (type) {
      case 'Class':
-        ServiceRefElement element = new Element.tag('class-ref');
+        ClassRefElement element = new Element.tag('class-ref');
         element.ref = ref;
+        element.asValue = asValue;
         return element;
       case 'Code':
         ServiceRefElement element = new Element.tag('code-ref');
@@ -111,8 +117,9 @@
         element.ref = ref;
         return element;
       case 'Library':
-        ServiceRefElement element = new Element.tag('library-ref');
+        LibraryRefElement element = new Element.tag('library-ref');
         element.ref = ref;
+        element.asValue = asValue;
         return element;
       case 'Object':
         ServiceRefElement element = new Element.tag('object-ref');
diff --git a/runtime/observatory/lib/src/elements/timeline_page.html b/runtime/observatory/lib/src/elements/timeline_page.html
index 95764ea..50b063d 100644
--- a/runtime/observatory/lib/src/elements/timeline_page.html
+++ b/runtime/observatory/lib/src/elements/timeline_page.html
@@ -3,19 +3,21 @@
 <link rel="import" href="observatory_element.html">
 
 <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>
-			<nav-menu link="{{ makeLink('/timeline') }}" anchor="timeline" last="{{ true }}"></nav-menu>
-			<nav-refresh callback="{{ 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-bar>
-		<iframe id="root" frameborder="0" src="../../../../timeline.html"></iframe>
-	</template>
+  <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 callback="{{ 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-bar>
+    <iframe id="root" frameborder="0" src="../../../../timeline.html">
+    </iframe>
+  </template>
 </polymer-element>
 <script type="application/dart" src="timeline_page.dart"></script>
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index f7775c1..8c9717f 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -4,6 +4,11 @@
 
 part of service;
 
+// Some value smaller than the object ring, so requesting a large array
+// doesn't result in an expired ref because the elements lapped it in the
+// object ring.
+const int kDefaultFieldLimit = 100;
+
 /// Helper function for canceling a Future<StreamSubscription>.
 Future cancelFutureSubscription(
     Future<StreamSubscription> subscriptionFuture) async {
@@ -284,6 +289,7 @@
   Future<ObservableMap> _fetchDirect() {
     Map params = {
       'objectId': id,
+      'count': kDefaultFieldLimit,
     };
     return isolate.invokeRpcNoUpgrade('getObject', params);
   }
@@ -1288,6 +1294,7 @@
     }
     Map params = {
       'objectId': objectId,
+      'count': kDefaultFieldLimit,
     };
     return isolate.invokeRpc('getObject', params);
   }
@@ -1688,6 +1695,13 @@
     return invokeRpc('evaluateInFrame', params);
   }
 
+  Future<ServiceObject> getReachableSize(ServiceObject target) {
+    Map params = {
+      'targetId': target.id,
+    };
+    return invokeRpc('_getReachableSize', params);
+  }
+
   Future<ServiceObject> getRetainedSize(ServiceObject target) {
     Map params = {
       'targetId': target.id,
@@ -2632,6 +2646,14 @@
     icDataArray = map['_icDataArray'];
     field = map['_field'];
   }
+
+  ServiceFunction get homeMethod {
+    var m = this;
+    while (m.dartOwner is ServiceFunction) {
+      m = m.dartOwner;
+    }
+    return m;
+  }
 }
 
 
diff --git a/runtime/observatory/tests/service/get_object_rpc_test.dart b/runtime/observatory/tests/service/get_object_rpc_test.dart
index 882b016..6bfa71f 100644
--- a/runtime/observatory/tests/service/get_object_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_object_rpc_test.dart
@@ -774,7 +774,7 @@
   (Isolate isolate) async {
     // Call eval to get a class id.
     var evalResult = await eval(isolate, 'new _DummyClass()');
-    var id = "${evalResult['class']['id']}/fields/0";
+    var id = "${evalResult['class']['id']}/fields/dummyVar";
     var params = {
       'objectId': id,
     };
@@ -796,7 +796,7 @@
   (Isolate isolate) async {
     // Call eval to get a class id.
     var evalResult = await eval(isolate, 'new _DummyClass()');
-    var id = "${evalResult['class']['id']}/fields/9999";
+    var id = "${evalResult['class']['id']}/fields/mythicalField";
     var params = {
       'objectId': id,
     };
diff --git a/runtime/observatory/tests/service/reachable_size_test.dart b/runtime/observatory/tests/service/reachable_size_test.dart
new file mode 100644
index 0000000..5c346e3
--- /dev/null
+++ b/runtime/observatory/tests/service/reachable_size_test.dart
@@ -0,0 +1,71 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--error_on_bad_type --error_on_bad_override
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+
+class Pair {
+  var x, y;
+}
+
+var p1;
+var p2;
+
+buildGraph() {
+  p1 = new Pair();
+  p2 = new Pair();
+
+  // Adds to both reachable and retained size.
+  p1.x = new List();
+  p2.x = new List();
+
+  // Adds to reachable size only.
+  p1.y = p2.y = new List();
+}
+
+getReachableSize(ServiceObject obj) {
+  return obj.isolate.getReachableSize(obj).then((Instance obj) {
+    return int.parse(obj.valueAsString);
+  });
+}
+
+getRetainedSize(ServiceObject obj) {
+  return obj.isolate.getRetainedSize(obj).then((Instance obj) {
+    return int.parse(obj.valueAsString);
+  });
+}
+
+var tests = [
+(Isolate isolate) async {
+  Instance p1 = await rootLibraryFieldValue(isolate, "p1");
+  Instance p2 = await rootLibraryFieldValue(isolate, "p2");
+
+  // In general, shallow <= retained <= reachable. In this program,
+  // 0 < shallow < retained < reachable.
+
+  int p1_shallow = p1.size;
+  int p1_retained = await getRetainedSize(p1);
+  int p1_reachable = await getReachableSize(p1);
+
+  expect(0, lessThan(p1_shallow));
+  expect(p1_shallow, lessThan(p1_retained));
+  expect(p1_retained, lessThan(p1_reachable));
+
+  int p2_shallow = p2.size;
+  int p2_retained = await getRetainedSize(p2);
+  int p2_reachable = await getReachableSize(p2);
+
+  expect(0, lessThan(p2_shallow));
+  expect(p2_shallow, lessThan(p2_retained));
+  expect(p2_retained, lessThan(p2_reachable));
+
+  expect(p1_shallow, equals(p2_shallow));
+  expect(p1_retained, equals(p2_retained));
+  expect(p1_reachable, equals(p2_reachable));
+},
+];
+
+main(args) => runIsolateTests(args, tests, testeeBefore: buildGraph);
diff --git a/runtime/observatory/tests/service/test_helper.dart b/runtime/observatory/tests/service/test_helper.dart
index 6248b43..58de4e6 100644
--- a/runtime/observatory/tests/service/test_helper.dart
+++ b/runtime/observatory/tests/service/test_helper.dart
@@ -319,6 +319,17 @@
 }
 
 
+Future<Instance> rootLibraryFieldValue(Isolate isolate,
+                                       String fieldName) async {
+  Library rootLib = await isolate.rootLibrary.load();
+  Field field = rootLib.variables.singleWhere((v) => v.name == fieldName);
+  await field.load();
+  Instance value = field.staticValue;
+  await value.load();
+  return value;
+}
+
+
 /// Runs [tests] in sequence, each of which should take an [Isolate] and
 /// return a [Future]. Code for setting up state can run before and/or
 /// concurrently with the tests. Uses [mainArgs] to determine whether
diff --git a/runtime/observatory/tests/ui/inspector.dart b/runtime/observatory/tests/ui/inspector.dart
index fd6d0c3..c34f2d9 100644
--- a/runtime/observatory/tests/ui/inspector.dart
+++ b/runtime/observatory/tests/ui/inspector.dart
@@ -24,6 +24,10 @@
 class A <T> {}
 class B <S extends num> {}
 
+class S {}
+class M {}
+class MA extends S with M {}
+
 class Node {
   static var classField;
 
@@ -112,6 +116,10 @@
     return x;
   }
 
+  static staticMain() {
+    node.main();
+  }
+
   main() {
     print("Started main");
 
@@ -240,7 +248,7 @@
   Node.classField = 'Class field value';
   typed = new Typed();
   node = new Node();
-  node.main();
+  Node.staticMain();
 }
 
 class C {
diff --git a/runtime/platform/json.cc b/runtime/platform/json.cc
deleted file mode 100644
index 6457a87..0000000
--- a/runtime/platform/json.cc
+++ /dev/null
@@ -1,636 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "platform/json.h"
-
-#include "platform/assert.h"
-#include "platform/globals.h"
-#include "platform/utils.h"
-#include "vm/os.h"
-
-namespace dart {
-
-JSONScanner::JSONScanner(const char* json_text) {
-  SetText(json_text);
-}
-
-
-void JSONScanner::SetText(const char* json_text) {
-  current_pos_ = json_text;
-  token_start_ = json_text;
-  token_length_ = 0;
-  token_ = TokenIllegal;
-}
-
-
-void JSONScanner::Recognize(Token t) {
-  ++current_pos_;
-  token_ = t;
-}
-
-
-bool JSONScanner::IsLetter(char ch) const {
-  return (('A' <= ch) && (ch <= 'Z')) || (('a' <= ch) && (ch <= 'z'));
-}
-
-
-bool JSONScanner::IsDigit(char ch) const {
-  return ('0' <= ch) && (ch <= '9');
-}
-
-
-bool JSONScanner::IsLiteral(const char* literal) {
-  int i = 0;
-  while ((literal[i] != '\0') && (current_pos_[i] == literal[i])) {
-    i++;
-  }
-  if ((literal[i] == '\0') && !IsLetter(current_pos_[i])) {
-    current_pos_ += i;
-    return true;
-  }
-  return false;
-}
-
-
-bool JSONScanner::IsStringLiteral(const char* literal) const {
-  if (token_ != TokenString) {
-    return false;
-  }
-  int i = 0;
-  while ((i < token_length_) && (token_start_[i] == literal[i])) {
-    i++;
-  }
-  return (i == token_length_) && (literal[i] == '\0');
-}
-
-
-void JSONScanner::Skip(Token matching_token) {
-  while (!EOM() && (token_ != TokenIllegal)) {
-    Scan();
-    if (token_ == TokenLBrace) {
-      Skip(TokenRBrace);
-    } else if (token_ == TokenLBrack) {
-      Skip(TokenRBrack);
-    } else if (token_ == matching_token) {
-      return;
-    } else if ((token_ == TokenRBrace) || (token_ == TokenRBrack)) {
-      // Mismatched brace or bracket.
-      token_ = TokenIllegal;
-    }
-  }
-}
-
-
-void JSONScanner::ScanString() {
-  ASSERT(*current_pos_ == '"');
-  ++current_pos_;
-  token_start_ = current_pos_;
-  while (*current_pos_ != '"') {
-    if (*current_pos_ == '\0') {
-      token_length_ = 0;
-      token_ = TokenIllegal;
-      return;
-    } else if (*current_pos_ == '\\') {
-      ++current_pos_;
-      if (*current_pos_ == '"') {
-        // Consume escaped double quote.
-        ++current_pos_;
-      }
-    } else {
-      ++current_pos_;
-    }
-  }
-  token_ = TokenString;
-  token_length_ = current_pos_ - token_start_;
-  ++current_pos_;
-}
-
-
-void JSONScanner::ScanNumber() {
-  if (*current_pos_ == '-') {
-    ++current_pos_;
-  }
-  if (!IsDigit(*current_pos_)) {
-    token_ = TokenIllegal;
-    token_length_ = 0;
-    return;
-  }
-  while (IsDigit(*current_pos_)) {
-    ++current_pos_;
-  }
-  if ((*current_pos_ == '.') ||
-      (*current_pos_ == 'e') ||
-      (*current_pos_ == 'E')) {
-    // Floating point numbers not supported.
-    token_ = TokenIllegal;
-    token_length_ = 0;
-    return;
-  }
-  token_ = TokenInteger;
-  token_length_ = current_pos_ - token_start_;
-}
-
-
-void JSONScanner::Scan() {
-  while ((*current_pos_ == ' ') ||
-         (*current_pos_ == '\t') ||
-         (*current_pos_ == '\n')) {
-    ++current_pos_;
-  }
-  token_start_ = current_pos_;
-  if (*current_pos_ == '\0') {
-    token_length_ = 0;
-    token_ = TokenEOM;
-    return;
-  }
-  switch (*current_pos_) {
-    case '{':
-      Recognize(TokenLBrace);
-      break;
-    case '}':
-      Recognize(TokenRBrace);
-      break;
-    case '[':
-      Recognize(TokenLBrack);
-      break;
-    case ']':
-      Recognize(TokenRBrack);
-      break;
-    case ':':
-      Recognize(TokenColon);
-      break;
-    case ',':
-      Recognize(TokenComma);
-      break;
-    case '"':
-      ScanString();
-      break;
-    case '0':
-    case '1':
-    case '2':
-    case '3':
-    case '4':
-    case '5':
-    case '6':
-    case '7':
-    case '8':
-    case '9':
-    case '-':
-      ScanNumber();
-      break;
-    default:
-      if (IsLiteral("true")) {
-        token_ = TokenTrue;
-        token_length_ = 4;
-      } else if (IsLiteral("false")) {
-        token_ = TokenFalse;
-        token_length_ = 5;
-      } else if (IsLiteral("null")) {
-        token_ = TokenNull;
-        token_length_ = 4;
-      } else {
-        token_length_ = 0;
-        token_ = TokenIllegal;
-      }
-  }
-}
-
-
-JSONReader::JSONReader(const char* json_object)
-: scanner_(json_object) {
-  Set(json_object);
-}
-
-
-void JSONReader::Set(const char* json_object) {
-  scanner_.SetText(json_object);
-  json_object_ = json_object;
-  error_ = false;
-}
-
-
-bool JSONReader::CheckMessage() {
-  scanner_.SetText(json_object_);
-  scanner_.Scan();
-  CheckObject();
-  return true;
-}
-
-
-void JSONReader::CheckValue() {
-  switch (scanner_.CurrentToken()) {
-    case JSONScanner::TokenLBrace:
-      CheckObject();
-      break;
-    case JSONScanner::TokenLBrack:
-      CheckArray();
-      break;
-    case JSONScanner::TokenString: {
-      // Check the encoding.
-      const char* s = ValueChars();
-      int remaining = ValueLen();
-      while (remaining > 0) {
-        if ((*s == '\n') || (*s == '\t')) {
-          OS::Print("Un-escaped character in JSON string: '%s'\n",
-                    ValueChars());
-          FATAL("illegal character in JSON string value");
-        }
-        s++;
-        remaining--;
-      }
-      scanner_.Scan();
-      break;
-    }
-    case JSONScanner::TokenInteger:
-    case JSONScanner::TokenTrue:
-    case JSONScanner::TokenFalse:
-    case JSONScanner::TokenNull:
-      scanner_.Scan();
-      break;
-    default:
-      OS::Print("Malformed JSON: expected a value but got '%s'\n",
-                scanner_.TokenChars());
-      FATAL("illegal JSON value found");
-  }
-}
-
-
-#if defined (DEBUG)
-#define CHECK_TOKEN(token)                                                     \
-  if (scanner_.CurrentToken() != token) {                                      \
-    OS::Print("Malformed JSON: expected %s but got '%s'\n",                    \
-              #token, scanner_.TokenChars());                                  \
-    intptr_t offset = scanner_.TokenChars() - this->json_object_;              \
-    OS::Print("Malformed JSON: expected %s at offset %" Pd "of buffer:\n%s\n", \
-              #token, offset, this->json_object_);                             \
-    ASSERT(scanner_.CurrentToken() == token);                                  \
-  }
-#else
-#define CHECK_TOKEN(token)
-#endif
-
-
-void JSONReader::CheckArray() {
-  CHECK_TOKEN(JSONScanner::TokenLBrack);
-  scanner_.Scan();
-  while (scanner_.CurrentToken() != JSONScanner::TokenRBrack) {
-    CheckValue();
-    if (scanner_.CurrentToken() != JSONScanner::TokenComma) {
-      break;
-    }
-    scanner_.Scan();
-  }
-  CHECK_TOKEN(JSONScanner::TokenRBrack);
-  scanner_.Scan();
-}
-
-
-void JSONReader::CheckObject() {
-  CHECK_TOKEN(JSONScanner::TokenLBrace);
-  scanner_.Scan();
-  while (scanner_.CurrentToken() == JSONScanner::TokenString) {
-    scanner_.Scan();
-    CHECK_TOKEN(JSONScanner::TokenColon);
-    scanner_.Scan();
-    CheckValue();
-    if (scanner_.CurrentToken() != JSONScanner::TokenComma) {
-      break;
-    }
-    scanner_.Scan();
-  }
-  CHECK_TOKEN(JSONScanner::TokenRBrace);
-  scanner_.Scan();
-}
-
-#undef CHECK_TOKEN
-
-
-bool JSONReader::Seek(const char* name) {
-  error_ = false;
-  scanner_.SetText(json_object_);
-  scanner_.Scan();
-  if (scanner_.CurrentToken() != JSONScanner::TokenLBrace) {
-    error_ = true;
-    return false;
-  }
-  scanner_.Scan();
-  if (scanner_.CurrentToken() == JSONScanner::TokenRBrace) {
-    return false;
-  }
-  while (scanner_.CurrentToken() == JSONScanner::TokenString) {
-    bool found = scanner_.IsStringLiteral(name);
-    scanner_.Scan();
-    if (scanner_.CurrentToken() != JSONScanner::TokenColon) {
-      error_ = true;
-      return false;
-    }
-    scanner_.Scan();
-    switch (scanner_.CurrentToken()) {
-      case JSONScanner::TokenString:
-      case JSONScanner::TokenInteger:
-      case JSONScanner::TokenLBrace:
-      case JSONScanner::TokenLBrack:
-      case JSONScanner::TokenTrue:
-      case JSONScanner::TokenFalse:
-      case JSONScanner::TokenNull:
-        // Found a legal value.
-        if (found) {
-          return true;
-        }
-        break;
-      default:
-        error_ = true;
-        return false;
-    }
-    // Skip the value.
-    if (scanner_.CurrentToken() == JSONScanner::TokenLBrace) {
-      scanner_.Skip(JSONScanner::TokenRBrace);
-      if (scanner_.CurrentToken() != JSONScanner::TokenRBrace) {
-        error_ = true;
-        return false;
-      }
-    } else if (scanner_.CurrentToken() == JSONScanner::TokenLBrack) {
-      scanner_.Skip(JSONScanner::TokenRBrack);
-      if (scanner_.CurrentToken() != JSONScanner::TokenRBrack) {
-        error_ = true;
-        return false;
-      }
-    }
-    scanner_.Scan();  // Value or closing brace or bracket.
-    if (scanner_.CurrentToken() == JSONScanner::TokenComma) {
-      scanner_.Scan();
-    } else if (scanner_.CurrentToken() == JSONScanner::TokenRBrace) {
-      return false;
-    } else {
-      error_ = true;
-      return false;
-    }
-  }
-  error_ = true;
-  return false;
-}
-
-
-const char* JSONReader::EndOfObject() {
-  bool found = Seek("***");  // Look for illegally named value.
-  ASSERT(!found);
-  if (!found && !error_) {
-    const char* s = scanner_.TokenChars();
-    ASSERT(*s == '}');
-    return s;
-  }
-  return NULL;
-}
-
-
-JSONReader::JSONType JSONReader::Type() const {
-  if (error_) {
-    return kNone;
-  }
-  switch (scanner_.CurrentToken()) {
-    case JSONScanner::TokenString:
-      return kString;
-    case JSONScanner::TokenInteger:
-      return kInteger;
-    case JSONScanner::TokenLBrace:
-      return kObject;
-    case JSONScanner::TokenLBrack:
-      return kArray;
-    case JSONScanner::TokenTrue:
-    case JSONScanner::TokenFalse:
-    case JSONScanner::TokenNull:
-      return kLiteral;
-    default:
-      return kNone;
-  }
-}
-
-
-void JSONReader::GetRawValueChars(char* buf, intptr_t buflen) const {
-  if (Type() == kNone) {
-    return;
-  }
-  intptr_t max = buflen - 1;
-  if (ValueLen() < max) {
-    max = ValueLen();
-  }
-  const char* val = ValueChars();
-  intptr_t i = 0;
-  for (; i < max; i++) {
-    buf[i] = val[i];
-  }
-  buf[i] = '\0';
-}
-
-
-void JSONReader::GetDecodedValueChars(char* buf, intptr_t buflen) const {
-  if (Type() == kNone) {
-    return;
-  }
-  const intptr_t last_idx = buflen - 1;
-  const intptr_t value_len = ValueLen();
-  const char* val = ValueChars();
-  intptr_t buf_idx = 0;
-  intptr_t val_idx = 0;
-  while ((buf_idx < last_idx) && (val_idx < value_len)) {
-    char ch = val[val_idx];
-    val_idx++;
-    buf[buf_idx] = ch;
-    if ((ch == '\\') && (val_idx < value_len)) {
-      switch (val[val_idx]) {
-        case '"':
-        case '\\':
-        case '/':
-          buf[buf_idx] = val[val_idx];
-          val_idx++;
-          break;
-        case 'b':
-          buf[buf_idx] = '\b';
-          val_idx++;
-          break;
-        case 'f':
-          buf[buf_idx] = '\f';
-          val_idx++;
-          break;
-        case 'n':
-          buf[buf_idx] = '\n';
-          val_idx++;
-          break;
-        case 'r':
-          buf[buf_idx] = '\r';
-          val_idx++;
-          break;
-        case 't':
-          buf[buf_idx] = '\t';
-          val_idx++;
-          break;
-        case 'u':
-          // \u00XX
-          // If the value is malformed or > 255, ignore and copy the
-          // encoded characters.
-          if ((val_idx < value_len - 4) &&
-              (val[val_idx + 1] == '0') && (val[val_idx + 2] == '0') &&
-              Utils::IsHexDigit(val[val_idx + 3]) &&
-              Utils::IsHexDigit(val[val_idx + 4])) {
-            buf[buf_idx] = 16 * Utils::HexDigitToInt(val[val_idx + 3]) +
-                Utils::HexDigitToInt(val[val_idx + 4]);
-            val_idx += 5;
-          }
-          break;
-        default:
-          // Nothing. Copy the character after the backslash
-          // in the next loop iteration.
-          break;
-      }
-    }
-    buf_idx++;
-  }
-  buf[buf_idx] = '\0';
-}
-
-
-TextBuffer::TextBuffer(intptr_t buf_size) {
-  ASSERT(buf_size > 0);
-  buf_ = reinterpret_cast<char*>(malloc(buf_size));
-  buf_size_ = buf_size;
-  Clear();
-}
-
-
-TextBuffer::~TextBuffer() {
-  free(buf_);
-  buf_ = NULL;
-}
-
-
-void TextBuffer::Clear() {
-  msg_len_ = 0;
-  buf_[0] = '\0';
-}
-
-
-const char* TextBuffer::Steal() {
-  const char* r = buf_;
-  buf_ = NULL;
-  buf_size_ = 0;
-  msg_len_ = 0;
-  return r;
-}
-
-
-void TextBuffer::AddChar(char ch) {
-  EnsureCapacity(sizeof(ch));
-  buf_[msg_len_] = ch;
-  msg_len_++;
-  buf_[msg_len_] = '\0';
-}
-
-
-intptr_t TextBuffer::Printf(const char* format, ...) {
-  va_list args;
-  va_start(args, format);
-  intptr_t remaining = buf_size_ - msg_len_;
-  ASSERT(remaining >= 0);
-  intptr_t len = OS::VSNPrint(buf_ + msg_len_, remaining, format, args);
-  va_end(args);
-  if (len >= remaining) {
-    EnsureCapacity(len);
-    remaining = buf_size_ - msg_len_;
-    ASSERT(remaining > len);
-    va_list args2;
-    va_start(args2, format);
-    intptr_t len2 = OS::VSNPrint(buf_ + msg_len_, remaining, format, args2);
-    va_end(args2);
-    ASSERT(len == len2);
-  }
-  msg_len_ += len;
-  buf_[msg_len_] = '\0';
-  return len;
-}
-
-
-// Write a UTF-16 code unit so it can be read by a JSON parser in a string
-// literal. Use escape sequences for characters other than printable ASCII.
-void TextBuffer::EscapeAndAddCodeUnit(uint32_t codeunit) {
-  switch (codeunit) {
-    case '"':
-      Printf("%s", "\\\"");
-      break;
-    case '\\':
-      Printf("%s", "\\\\");
-      break;
-    case '/':
-      Printf("%s", "\\/");
-      break;
-    case '\b':
-      Printf("%s", "\\b");
-      break;
-    case '\f':
-      Printf("%s", "\\f");
-      break;
-    case '\n':
-      Printf("%s", "\\n");
-      break;
-    case '\r':
-      Printf("%s", "\\r");
-      break;
-    case '\t':
-      Printf("%s", "\\t");
-      break;
-    default:
-      if (codeunit < 0x20) {
-        // Encode character as \u00HH.
-        uint32_t digit2 = (codeunit >> 4) & 0xf;
-        uint32_t digit3 = (codeunit & 0xf);
-        Printf("\\u00%c%c",
-               digit2 > 9 ? 'A' + (digit2 - 10) : '0' + digit2,
-               digit3 > 9 ? 'A' + (digit3 - 10) : '0' + digit3);
-      } else if (codeunit > 127) {
-        // Encode character as \uHHHH.
-        uint32_t digit0 = (codeunit >> 12) & 0xf;
-        uint32_t digit1 = (codeunit >> 8) & 0xf;
-        uint32_t digit2 = (codeunit >> 4) & 0xf;
-        uint32_t digit3 = (codeunit & 0xf);
-        Printf("\\u%c%c%c%c",
-               digit0 > 9 ? 'A' + (digit0 - 10) : '0' + digit0,
-               digit1 > 9 ? 'A' + (digit1 - 10) : '0' + digit1,
-               digit2 > 9 ? 'A' + (digit2 - 10) : '0' + digit2,
-               digit3 > 9 ? 'A' + (digit3 - 10) : '0' + digit3);
-      } else {
-        AddChar(codeunit);
-      }
-  }
-}
-
-
-void TextBuffer::AddString(const char* s) {
-  Printf("%s", s);
-}
-
-
-void TextBuffer::AddEscapedString(const char* s) {
-  intptr_t len = strlen(s);
-  for (int i = 0; i < len; i++) {
-    EscapeAndAddCodeUnit(s[i]);
-  }
-}
-
-
-void TextBuffer::EnsureCapacity(intptr_t len) {
-  intptr_t remaining = buf_size_ - msg_len_;
-  if (remaining <= len) {
-    const int kBufferSpareCapacity = 64;  // Somewhat arbitrary.
-    // TODO(turnidge): do we need to guard against overflow or other
-    // security issues here? Text buffers are used by the debugger
-    // to send user-controlled data (e.g. values of string variables) to
-    // the debugger front-end.
-    intptr_t new_size = buf_size_ + len + kBufferSpareCapacity;
-    char* new_buf = reinterpret_cast<char*>(realloc(buf_, new_size));
-    ASSERT(new_buf != NULL);
-    buf_ = new_buf;
-    buf_size_ = new_size;
-  }
-}
-
-}  // namespace dart
diff --git a/runtime/platform/json.h b/runtime/platform/json.h
deleted file mode 100644
index 35e975f0..0000000
--- a/runtime/platform/json.h
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef PLATFORM_JSON_H_
-#define PLATFORM_JSON_H_
-
-#include "vm/allocation.h"
-#include "vm/globals.h"
-
-namespace dart {
-
-
-// A low level interface to tokenize JSON strings.
-class JSONScanner : ValueObject {
- public:
-  enum Token {
-    TokenIllegal = 0,
-    TokenLBrace,
-    TokenRBrace,
-    TokenLBrack,
-    TokenRBrack,
-    TokenColon,
-    TokenComma,
-    TokenString,
-    TokenInteger,
-    TokenTrue,
-    TokenFalse,
-    TokenNull,
-    TokenEOM
-  };
-  explicit JSONScanner(const char* json_text);
-
-  void SetText(const char* json_text);
-  void Scan();
-  Token CurrentToken() const { return token_; }
-  bool EOM() const { return token_ == TokenEOM; }
-  const char* TokenChars() const { return token_start_; }
-  int TokenLen() const { return token_length_; }
-  bool IsStringLiteral(const char* literal) const;
-  void Skip(Token matching_token);
-
- private:
-  bool IsLetter(char ch) const;
-  bool IsDigit(char ch) const;
-  bool IsLiteral(const char* literal);
-  void ScanNumber();
-  void ScanString();
-  void Recognize(Token t);
-
-  const char* current_pos_;
-  const char* token_start_;
-  int token_length_;
-  Token token_;
-};
-
-
-// JSONReader is a higher level interface that allows for lookup of
-// name-value pairs in JSON objects.
-class JSONReader : ValueObject {
- public:
-  enum JSONType {
-    kString,
-    kInteger,
-    kObject,
-    kArray,
-    kLiteral,
-    kNone
-  };
-
-  explicit JSONReader(const char* json_object);
-  void Set(const char* json_object);
-
-  // Returns true if a pair with the given name was found.
-  bool Seek(const char* name);
-
-  // Returns true if a syntax error was found.
-  bool Error() const { return error_; }
-
-  // Returns a pointer to the matching closing brace if the text starts
-  // with a valid JSON object. Returns NULL otherwise.
-  const char* EndOfObject();
-
-  JSONType Type() const;
-  const char* ValueChars() const {
-    return (Type() != kNone) ? scanner_.TokenChars() : NULL;
-  }
-  int ValueLen() const {
-    return (Type() != kNone) ? scanner_.TokenLen() : 0;
-  }
-  void GetRawValueChars(char* buf, intptr_t buflen) const;
-  void GetDecodedValueChars(char* buf, intptr_t buflen) const;
-  bool IsStringLiteral(const char* literal) const {
-    return scanner_.IsStringLiteral(literal);
-  }
-  bool IsTrue() const {
-    return scanner_.CurrentToken() == JSONScanner::TokenTrue;
-  }
-  bool IsFalse() const {
-    return scanner_.CurrentToken() == JSONScanner::TokenFalse;
-  }
-  bool IsNull() const {
-    return scanner_.CurrentToken() == JSONScanner::TokenNull;
-  }
-
-  // Debugging method to check for validity of a JSON message.
-  bool CheckMessage();
-
- private:
-  void CheckObject();
-  void CheckArray();
-  void CheckValue();
-
-  JSONScanner scanner_;
-  const char* json_object_;
-  bool error_;
-};
-
-
-// TextBuffer maintains a dynamic character buffer with a printf-style way to
-// append text.
-class TextBuffer : ValueObject {
- public:
-  explicit TextBuffer(intptr_t buf_size);
-  ~TextBuffer();
-
-  intptr_t Printf(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
-  void AddChar(char ch);
-  void EscapeAndAddCodeUnit(uint32_t cu);
-  void AddString(const char* s);
-  void AddEscapedString(const char* s);
-
-  void Clear();
-
-  char* buf() { return buf_; }
-  intptr_t length() { return msg_len_; }
-
-  // Steal ownership of the buffer pointer.
-  // NOTE: TextBuffer is empty afterwards.
-  const char* Steal();
-
- private:
-  void EnsureCapacity(intptr_t len);
-  char* buf_;
-  intptr_t buf_size_;
-  intptr_t msg_len_;
-};
-
-}  // namespace dart
-
-#endif  // PLATFORM_JSON_H_
diff --git a/runtime/platform/platform_headers.gypi b/runtime/platform/platform_headers.gypi
index bf99985..6619720 100644
--- a/runtime/platform/platform_headers.gypi
+++ b/runtime/platform/platform_headers.gypi
@@ -13,8 +13,8 @@
     'globals.h',
     'hashmap.h',
     'inttypes_support_win.h',
-    'json.h',
     'memory_sanitizer.h',
+    'text_buffer.h',
     'utils.h',
   ],
 }
diff --git a/runtime/platform/platform_sources.gypi b/runtime/platform/platform_sources.gypi
index 5885f73..7327ad3 100644
--- a/runtime/platform/platform_sources.gypi
+++ b/runtime/platform/platform_sources.gypi
@@ -7,9 +7,9 @@
   'sources': [
     'assert.cc',
     'hashmap.cc',
-    'json.cc',
     'floating_point_win.cc',
     'signal_blocker.h',
+    'text_buffer.cc',
     'utils.cc',
   ],
 }
diff --git a/runtime/platform/text_buffer.cc b/runtime/platform/text_buffer.cc
new file mode 100644
index 0000000..b9c6ac7
--- /dev/null
+++ b/runtime/platform/text_buffer.cc
@@ -0,0 +1,157 @@
+// 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.
+
+#include "platform/text_buffer.h"
+
+#include "platform/assert.h"
+#include "platform/globals.h"
+#include "platform/utils.h"
+#include "vm/os.h"
+
+namespace dart {
+
+TextBuffer::TextBuffer(intptr_t buf_size) {
+  ASSERT(buf_size > 0);
+  buf_ = reinterpret_cast<char*>(malloc(buf_size));
+  buf_size_ = buf_size;
+  Clear();
+}
+
+
+TextBuffer::~TextBuffer() {
+  free(buf_);
+  buf_ = NULL;
+}
+
+
+void TextBuffer::Clear() {
+  msg_len_ = 0;
+  buf_[0] = '\0';
+}
+
+
+const char* TextBuffer::Steal() {
+  const char* r = buf_;
+  buf_ = NULL;
+  buf_size_ = 0;
+  msg_len_ = 0;
+  return r;
+}
+
+
+void TextBuffer::AddChar(char ch) {
+  EnsureCapacity(sizeof(ch));
+  buf_[msg_len_] = ch;
+  msg_len_++;
+  buf_[msg_len_] = '\0';
+}
+
+
+intptr_t TextBuffer::Printf(const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  intptr_t remaining = buf_size_ - msg_len_;
+  ASSERT(remaining >= 0);
+  intptr_t len = OS::VSNPrint(buf_ + msg_len_, remaining, format, args);
+  va_end(args);
+  if (len >= remaining) {
+    EnsureCapacity(len);
+    remaining = buf_size_ - msg_len_;
+    ASSERT(remaining > len);
+    va_list args2;
+    va_start(args2, format);
+    intptr_t len2 = OS::VSNPrint(buf_ + msg_len_, remaining, format, args2);
+    va_end(args2);
+    ASSERT(len == len2);
+  }
+  msg_len_ += len;
+  buf_[msg_len_] = '\0';
+  return len;
+}
+
+
+// Write a UTF-16 code unit so it can be read by a JSON parser in a string
+// literal. Use escape sequences for characters other than printable ASCII.
+void TextBuffer::EscapeAndAddCodeUnit(uint32_t codeunit) {
+  switch (codeunit) {
+    case '"':
+      Printf("%s", "\\\"");
+      break;
+    case '\\':
+      Printf("%s", "\\\\");
+      break;
+    case '/':
+      Printf("%s", "\\/");
+      break;
+    case '\b':
+      Printf("%s", "\\b");
+      break;
+    case '\f':
+      Printf("%s", "\\f");
+      break;
+    case '\n':
+      Printf("%s", "\\n");
+      break;
+    case '\r':
+      Printf("%s", "\\r");
+      break;
+    case '\t':
+      Printf("%s", "\\t");
+      break;
+    default:
+      if (codeunit < 0x20) {
+        // Encode character as \u00HH.
+        uint32_t digit2 = (codeunit >> 4) & 0xf;
+        uint32_t digit3 = (codeunit & 0xf);
+        Printf("\\u00%c%c",
+               digit2 > 9 ? 'A' + (digit2 - 10) : '0' + digit2,
+               digit3 > 9 ? 'A' + (digit3 - 10) : '0' + digit3);
+      } else if (codeunit > 127) {
+        // Encode character as \uHHHH.
+        uint32_t digit0 = (codeunit >> 12) & 0xf;
+        uint32_t digit1 = (codeunit >> 8) & 0xf;
+        uint32_t digit2 = (codeunit >> 4) & 0xf;
+        uint32_t digit3 = (codeunit & 0xf);
+        Printf("\\u%c%c%c%c",
+               digit0 > 9 ? 'A' + (digit0 - 10) : '0' + digit0,
+               digit1 > 9 ? 'A' + (digit1 - 10) : '0' + digit1,
+               digit2 > 9 ? 'A' + (digit2 - 10) : '0' + digit2,
+               digit3 > 9 ? 'A' + (digit3 - 10) : '0' + digit3);
+      } else {
+        AddChar(codeunit);
+      }
+  }
+}
+
+
+void TextBuffer::AddString(const char* s) {
+  Printf("%s", s);
+}
+
+
+void TextBuffer::AddEscapedString(const char* s) {
+  intptr_t len = strlen(s);
+  for (int i = 0; i < len; i++) {
+    EscapeAndAddCodeUnit(s[i]);
+  }
+}
+
+
+void TextBuffer::EnsureCapacity(intptr_t len) {
+  intptr_t remaining = buf_size_ - msg_len_;
+  if (remaining <= len) {
+    const int kBufferSpareCapacity = 64;  // Somewhat arbitrary.
+    // TODO(turnidge): do we need to guard against overflow or other
+    // security issues here? Text buffers are used by the debugger
+    // to send user-controlled data (e.g. values of string variables) to
+    // the debugger front-end.
+    intptr_t new_size = buf_size_ + len + kBufferSpareCapacity;
+    char* new_buf = reinterpret_cast<char*>(realloc(buf_, new_size));
+    ASSERT(new_buf != NULL);
+    buf_ = new_buf;
+    buf_size_ = new_size;
+  }
+}
+
+}  // namespace dart
diff --git a/runtime/platform/text_buffer.h b/runtime/platform/text_buffer.h
new file mode 100644
index 0000000..f8f0c2f
--- /dev/null
+++ b/runtime/platform/text_buffer.h
@@ -0,0 +1,45 @@
+// 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.
+
+#ifndef PLATFORM_TEXT_BUFFER_H_
+#define PLATFORM_TEXT_BUFFER_H_
+
+#include "vm/allocation.h"
+#include "vm/globals.h"
+
+namespace dart {
+
+
+// TextBuffer maintains a dynamic character buffer with a printf-style way to
+// append text.
+class TextBuffer : ValueObject {
+ public:
+  explicit TextBuffer(intptr_t buf_size);
+  ~TextBuffer();
+
+  intptr_t Printf(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
+  void AddChar(char ch);
+  void EscapeAndAddCodeUnit(uint32_t cu);
+  void AddString(const char* s);
+  void AddEscapedString(const char* s);
+
+  void Clear();
+
+  char* buf() { return buf_; }
+  intptr_t length() { return msg_len_; }
+
+  // Steal ownership of the buffer pointer.
+  // NOTE: TextBuffer is empty afterwards.
+  const char* Steal();
+
+ private:
+  void EnsureCapacity(intptr_t len);
+  char* buf_;
+  intptr_t buf_size_;
+  intptr_t msg_len_;
+};
+
+}  // namespace dart
+
+#endif  // PLATFORM_TEXT_BUFFER_H_
diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h
index 54ebf4d..9e4a384 100644
--- a/runtime/platform/utils.h
+++ b/runtime/platform/utils.h
@@ -214,6 +214,8 @@
     return true;
 #endif
   }
+
+  static char* StrError(int err, char* buffer, size_t bufsize);
 };
 
 }  // namespace dart
diff --git a/runtime/platform/utils_android.h b/runtime/platform/utils_android.h
index 904f6f4..7709442 100644
--- a/runtime/platform/utils_android.h
+++ b/runtime/platform/utils_android.h
@@ -60,6 +60,13 @@
   return htole64(value);
 }
 
+inline char* Utils::StrError(int err, char* buffer, size_t bufsize) {
+  if (strerror_r(err, buffer, bufsize) != 0) {
+    snprintf(buffer, bufsize, "%s", "strerror_r failed");
+  }
+  return buffer;
+}
+
 }  // namespace dart
 
 #endif  // PLATFORM_UTILS_ANDROID_H_
diff --git a/runtime/platform/utils_linux.h b/runtime/platform/utils_linux.h
index f2af4d1..bb9594f 100644
--- a/runtime/platform/utils_linux.h
+++ b/runtime/platform/utils_linux.h
@@ -60,6 +60,21 @@
   return htole64(value);
 }
 
+
+inline char* Utils::StrError(int err, char* buffer, size_t bufsize) {
+#if !defined(__GLIBC__) ||                                              \
+((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE)
+  // Use the XSI version.
+  if (strerror_r(err, buffer, bufsize) != 0) {
+    snprintf(buffer, bufsize, "%s", "strerror_r failed");
+  }
+  return buffer;
+#else
+  // Use the GNU specific version.
+  return strerror_r(err, buffer, bufsize);
+#endif
+}
+
 }  // namespace dart
 
 #endif  // PLATFORM_UTILS_LINUX_H_
diff --git a/runtime/platform/utils_macos.h b/runtime/platform/utils_macos.h
index 3fa29849..7c2a966 100644
--- a/runtime/platform/utils_macos.h
+++ b/runtime/platform/utils_macos.h
@@ -60,6 +60,13 @@
   return OSSwapHostToLittleInt64(value);
 }
 
+inline char* Utils::StrError(int err, char* buffer, size_t bufsize) {
+  if (strerror_r(err, buffer, bufsize) != 0) {
+    snprintf(buffer, bufsize, "%s", "strerror_r failed");
+  }
+  return buffer;
+}
+
 }  // namespace dart
 
 #endif  // PLATFORM_UTILS_MACOS_H_
diff --git a/runtime/tests/vm/dart/data_uri_failures_test.dart b/runtime/tests/vm/dart/data_uri_failures_test.dart
deleted file mode 100644
index 2df3195..0000000
--- a/runtime/tests/vm/dart/data_uri_failures_test.dart
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'data:text/plain;charset=utf-8,foo%28%29%20%3D%3E%2042%3B';  /// wrongmime: ok
-import 'data:;charset=utf-8,foo%28%29%20%3D%3E%2042%3B';  /// nomime: ok
-import 'data:application/dart;charset=utf-16,foo%28%29%20%3D%3E%2042%3B';  /// utf16: runtime error
-import 'data:application/dart,foo%28%29%20%3D%3E%2042%3B';  /// nocharset: ok
-import 'data:application/dart;charset=utf-8,foo?%9g';  /// badencodeddate: runtime error
-import 'data:application/dart;charset=utf-8;base64,Zm9vKCkgPT4gNDI7';  /// base64: ok
-
-main() {
-}
\ No newline at end of file
diff --git a/runtime/tests/vm/dart/data_uri_import_test.dart b/runtime/tests/vm/dart/data_uri_import_test.dart
index 2430b95..8ce4e1a 100644
--- a/runtime/tests/vm/dart/data_uri_import_test.dart
+++ b/runtime/tests/vm/dart/data_uri_import_test.dart
@@ -3,7 +3,13 @@
 // BSD-style license that can be found in the LICENSE file.
 
 // foo() => 42;
-import 'data:application/dart;charset=utf-8,foo%28%29%20%3D%3E%2042%3B';
+import 'data:application/dart;charset=utf-8,foo%28%29%20%3D%3E%2042%3B';  /// percentencoded: ok
+import 'data:text/plain;charset=utf-8,foo%28%29%20%3D%3E%2042%3B';  /// wrongmime: ok
+import 'data:;charset=utf-8,foo%28%29%20%3D%3E%2042%3B';  /// nomime: ok
+import 'data:application/dart;charset=utf-16,foo%28%29%20%3D%3E%2042%3B';  /// utf16: runtime error
+import 'data:application/dart,foo%28%29%20%3D%3E%2042%3B';  /// nocharset: ok
+import 'data:application/dart;charset=utf-8,foo?%9g';  /// badencodeddate: runtime error
+import 'data:application/dart;charset=utf-8;base64,Zm9vKCkgPT4gNDI7';  /// base64: ok
 
 import "package:expect/expect.dart";
 
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 07373d4..faa6779 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -12,13 +12,15 @@
 # Flaky on buildbot. Issue 5133 and 10409.
 cc/Sleep: Pass, Fail
 
+dart/data_uri_import_test/none: SkipByDesign
+
 [ $mode == debug ]
 # This is a benchmark that is not informative in debug mode.
 cc/CorelibIsolateStartup: Skip
 # Negative tests of VerifiedMemory should crash iff in DEBUG mode.
 # TODO(koda): Improve support for negative tests.
-cc/VerifyImplicit_Crash: Crash
-cc/VerifyExplicit_Crash: Crash
+cc/VerifyImplicit_Crash: Crash, Timeout  # Timeout: Issue #24596
+cc/VerifyExplicit_Crash: Crash, Timeout  # Timeout: Issue #24596
 
 # The following section refers to the dart vm tests which live under
 # runtime/tests/vm/dart.
@@ -56,10 +58,9 @@
 dart/data_uri*test: Skip
 
 [ $runtime == vm ]
-dart/data_uri_failures_test/wrongmime: RuntimeError, OK # VM is more restrictive than the browser
-dart/data_uri_failures_test/nomime: RuntimeError, OK
-dart/data_uri_failures_test/nocharset: RuntimeError, OK
-dart/data_uri_failures_test/base64: RuntimeError, OK
+dart/data_uri_import_test/wrongmime: RuntimeError, OK # VM is more restrictive than the browser
+dart/data_uri_import_test/nomime: RuntimeError, OK
+dart/data_uri_import_test/nocharset: RuntimeError, OK
 
 [ $arch == mips ]
 cc/StaticNonNullSumCallCodegen: Crash, Pass # Issue 17440
diff --git a/runtime/vm/assembler_arm64_test.cc b/runtime/vm/assembler_arm64_test.cc
index a187ee8..9320421 100644
--- a/runtime/vm/assembler_arm64_test.cc
+++ b/runtime/vm/assembler_arm64_test.cc
@@ -1625,14 +1625,17 @@
 static void EnterTestFrame(Assembler* assembler) {
   __ EnterFrame(0);
   __ Push(CODE_REG);
+  __ Push(THR);
   __ TagAndPushPP();
   __ ldr(CODE_REG, Address(R0, VMHandles::kOffsetOfRawPtrInHandle));
+  __ mov(THR, R1);
   __ LoadPoolPointer(PP);
 }
 
 
 static void LeaveTestFrame(Assembler* assembler) {
   __ PopAndUntagPP();
+  __ Pop(THR);
   __ Pop(CODE_REG);
   __ LeaveFrame();
 }
@@ -1652,7 +1655,7 @@
 
 
 ASSEMBLER_TEST_RUN(LoadImmediatePPSmall, test) {
-  EXPECT_EQ(42, test->InvokeWithCode<int64_t>());
+  EXPECT_EQ(42, test->InvokeWithCodeAndThread<int64_t>());
 }
 
 
@@ -1667,7 +1670,7 @@
 
 
 ASSEMBLER_TEST_RUN(LoadImmediatePPMed, test) {
-  EXPECT_EQ(0xf1234123, test->InvokeWithCode<int64_t>());
+  EXPECT_EQ(0xf1234123, test->InvokeWithCodeAndThread<int64_t>());
 }
 
 
@@ -1682,7 +1685,7 @@
 
 
 ASSEMBLER_TEST_RUN(LoadImmediatePPMed2, test) {
-  EXPECT_EQ(0x4321f1234124, test->InvokeWithCode<int64_t>());
+  EXPECT_EQ(0x4321f1234124, test->InvokeWithCodeAndThread<int64_t>());
 }
 
 
@@ -1698,23 +1701,15 @@
 
 ASSEMBLER_TEST_RUN(LoadImmediatePPLarge, test) {
   EXPECT_EQ(static_cast<int64_t>(0x9287436598237465),
-            test->InvokeWithCode<int64_t>());
+            test->InvokeWithCodeAndThread<int64_t>());
 }
 
 
-#define ASSEMBLER_TEST_RUN_WITH_THREAD(result_type, var_name) \
-  Thread* thread = Thread::Current(); \
-  result_type var_name = test->InvokeWithCode<result_type>(thread);
-
-
 // LoadObject null.
 ASSEMBLER_TEST_GENERATE(LoadObjectNull, assembler) {
   __ SetupDartSP(kTestStackSpace);
   EnterTestFrame(assembler);
-  __ Push(THR);
-  __ mov(THR, R1);
   __ LoadObject(R0, Object::null_object());
-  __ Pop(THR);
   LeaveTestFrame(assembler);
   __ mov(CSP, SP);
   __ ret();
@@ -1722,18 +1717,14 @@
 
 
 ASSEMBLER_TEST_RUN(LoadObjectNull, test) {
-  ASSEMBLER_TEST_RUN_WITH_THREAD(RawObject*, result);
-  EXPECT_EQ(Object::null(), result);
+  EXPECT_EQ(Object::null(), test->InvokeWithCodeAndThread<RawObject*>());
 }
 
 
 ASSEMBLER_TEST_GENERATE(LoadObjectTrue, assembler) {
   __ SetupDartSP(kTestStackSpace);
   EnterTestFrame(assembler);
-  __ Push(THR);
-  __ mov(THR, R1);
   __ LoadObject(R0, Bool::True());
-  __ Pop(THR);
   LeaveTestFrame(assembler);
   __ mov(CSP, SP);
   __ ret();
@@ -1741,18 +1732,14 @@
 
 
 ASSEMBLER_TEST_RUN(LoadObjectTrue, test) {
-  ASSEMBLER_TEST_RUN_WITH_THREAD(RawObject*, result);
-  EXPECT_EQ(Bool::True().raw(), result);
+  EXPECT_EQ(Bool::True().raw(), test->InvokeWithCodeAndThread<RawObject*>());
 }
 
 
 ASSEMBLER_TEST_GENERATE(LoadObjectFalse, assembler) {
   __ SetupDartSP(kTestStackSpace);
   EnterTestFrame(assembler);
-  __ Push(THR);
-  __ mov(THR, R1);
   __ LoadObject(R0, Bool::False());
-  __ Pop(THR);
   LeaveTestFrame(assembler);
   __ mov(CSP, SP);
   __ ret();
@@ -1760,8 +1747,7 @@
 
 
 ASSEMBLER_TEST_RUN(LoadObjectFalse, test) {
-  ASSEMBLER_TEST_RUN_WITH_THREAD(RawObject*, result);
-  EXPECT_EQ(Bool::False().raw(), result);
+  EXPECT_EQ(Bool::False().raw(), test->InvokeWithCodeAndThread<RawObject*>());
 }
 
 
@@ -3591,7 +3577,7 @@
   __ SetupDartSP(kTestStackSpace);
   EnterTestFrame(assembler);
   Label miss, done;
-  __ ComputeRange(R0, R1, R2, &miss);
+  __ ComputeRange(R0, R2, R3, &miss);
   __ b(&done);
 
   __ Bind(&miss);
@@ -3605,7 +3591,8 @@
 
 
 ASSEMBLER_TEST_RUN(ComputeRange, test) {
-#define RANGE_OF(arg_type, v) test->InvokeWithCode<intptr_t, arg_type>(v)
+#define RANGE_OF(arg_type, v)                                                  \
+  test->InvokeWithCodeAndThread<intptr_t, arg_type>(v)
 
   EXPECT_EQ(ICData::kInt32RangeBit, RANGE_OF(RawSmi*, Smi::New(0)));
   EXPECT_EQ(ICData::kInt32RangeBit, RANGE_OF(RawSmi*, Smi::New(1)));
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 9c4b45d..b3a1d09 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -785,57 +785,29 @@
 }
 
 void Assembler::notps(XmmRegister dst) {
-  static const struct ALIGN16 {
-    uint32_t a;
-    uint32_t b;
-    uint32_t c;
-    uint32_t d;
-  } float_not_constant =
-      { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
-  LoadImmediate(
-      TMP, Immediate(reinterpret_cast<intptr_t>(&float_not_constant)));
+  // { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+  movq(TMP, Address(THR, Thread::float_not_address_offset()));
   xorps(dst, Address(TMP, 0));
 }
 
 
 void Assembler::negateps(XmmRegister dst) {
-  static const struct ALIGN16 {
-    uint32_t a;
-    uint32_t b;
-    uint32_t c;
-    uint32_t d;
-  } float_negate_constant =
-      { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
-  LoadImmediate(
-      TMP, Immediate(reinterpret_cast<intptr_t>(&float_negate_constant)));
+  // { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }
+  movq(TMP, Address(THR, Thread::float_negate_address_offset()));
   xorps(dst, Address(TMP, 0));
 }
 
 
 void Assembler::absps(XmmRegister dst) {
-  static const struct ALIGN16 {
-    uint32_t a;
-    uint32_t b;
-    uint32_t c;
-    uint32_t d;
-  } float_absolute_constant =
-      { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
-  LoadImmediate(
-      TMP, Immediate(reinterpret_cast<intptr_t>(&float_absolute_constant)));
+  // { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF }
+  movq(TMP, Address(THR, Thread::float_absolute_address_offset()));
   andps(dst, Address(TMP, 0));
 }
 
 
 void Assembler::zerowps(XmmRegister dst) {
-  static const struct ALIGN16 {
-    uint32_t a;
-    uint32_t b;
-    uint32_t c;
-    uint32_t d;
-  } float_zerow_constant =
-      { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
-  LoadImmediate(
-      TMP, Immediate(reinterpret_cast<intptr_t>(&float_zerow_constant)));
+  // { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 }
+  movq(TMP, Address(THR, Thread::float_zerow_address_offset()));
   andps(dst, Address(TMP, 0));
 }
 
@@ -1017,13 +989,8 @@
 
 
 void Assembler::negatepd(XmmRegister dst) {
-  static const struct ALIGN16 {
-    uint64_t a;
-    uint64_t b;
-  } double_negate_constant =
-      { 0x8000000000000000LL, 0x8000000000000000LL };
-  LoadImmediate(
-      TMP, Immediate(reinterpret_cast<intptr_t>(&double_negate_constant)));
+  // { 0x8000000000000000LL, 0x8000000000000000LL }
+  movq(TMP, Address(THR, Thread::double_negate_address_offset()));
   xorpd(dst, Address(TMP, 0));
 }
 
@@ -1065,13 +1032,8 @@
 
 
 void Assembler::abspd(XmmRegister dst) {
-  static const struct ALIGN16 {
-    uint64_t a;
-    uint64_t b;
-  } double_absolute_const =
-      { 0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL };
-  LoadImmediate(
-      TMP, Immediate(reinterpret_cast<intptr_t>(&double_absolute_const)));
+  // { 0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL }
+  movq(TMP, Address(THR, Thread::double_abs_address_offset()));
   andpd(dst, Address(TMP, 0));
 }
 
@@ -3160,25 +3122,15 @@
 
 
 void Assembler::DoubleNegate(XmmRegister d) {
-  static const struct ALIGN16 {
-    uint64_t a;
-    uint64_t b;
-  } double_negate_constant =
-      {0x8000000000000000LL, 0x8000000000000000LL};
-  LoadImmediate(
-      TMP, Immediate(reinterpret_cast<intptr_t>(&double_negate_constant)));
+  // {0x8000000000000000LL, 0x8000000000000000LL}
+  movq(TMP, Address(THR, Thread::double_negate_address_offset()));
   xorpd(d, Address(TMP, 0));
 }
 
 
 void Assembler::DoubleAbs(XmmRegister reg) {
-  static const struct ALIGN16 {
-    uint64_t a;
-    uint64_t b;
-  } double_abs_constant =
-      {0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL};
-  LoadImmediate(TMP,
-      Immediate(reinterpret_cast<intptr_t>(&double_abs_constant)));
+  // {0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL}
+  movq(TMP, Address(THR, Thread::double_abs_address_offset()));
   andpd(reg, Address(TMP, 0));
 }
 
diff --git a/runtime/vm/assembler_x64_test.cc b/runtime/vm/assembler_x64_test.cc
index a78f3ca..eb8219d 100644
--- a/runtime/vm/assembler_x64_test.cc
+++ b/runtime/vm/assembler_x64_test.cc
@@ -2021,16 +2021,21 @@
 
 
 static void EnterTestFrame(Assembler* assembler) {
+  COMPILE_ASSERT(THR != CallingConventions::kArg1Reg);
+  COMPILE_ASSERT(CODE_REG != CallingConventions::kArg2Reg);
   __ EnterFrame(0);
   __ pushq(CODE_REG);
   __ pushq(PP);
+  __ pushq(THR);
   __ movq(CODE_REG, Address(CallingConventions::kArg1Reg,
                             VMHandles::kOffsetOfRawPtrInHandle));
+  __ movq(THR, CallingConventions::kArg2Reg);
   __ LoadPoolPointer(PP);
 }
 
 
 static void LeaveTestFrame(Assembler* assembler) {
+  __ popq(THR);
   __ popq(PP);
   __ popq(CODE_REG);
   __ LeaveFrame();
@@ -2053,7 +2058,7 @@
 
 
 ASSEMBLER_TEST_RUN(PackedDoubleNegate, test) {
-  double res = test->InvokeWithCode<double>();
+  double res = test->InvokeWithCodeAndThread<double>();
   EXPECT_FLOAT_EQ(-1.0, res, 0.000001f);
 }
 
@@ -2074,7 +2079,7 @@
 
 
 ASSEMBLER_TEST_RUN(PackedDoubleAbsolute, test) {
-  double res = test->InvokeWithCode<double>();
+  double res = test->InvokeWithCodeAndThread<double>();
   EXPECT_FLOAT_EQ(1.0, res, 0.000001f);
 }
 
@@ -2520,7 +2525,7 @@
 
 
 ASSEMBLER_TEST_RUN(PackedNegate, test) {
-  float res = test->InvokeWithCode<float>();
+  float res = test->InvokeWithCodeAndThread<float>();
   EXPECT_FLOAT_EQ(-12.3f, res, 0.001f);
 }
 
@@ -2538,7 +2543,7 @@
 
 
 ASSEMBLER_TEST_RUN(PackedAbsolute, test) {
-  float res = test->InvokeWithCode<float>();
+  float res = test->InvokeWithCodeAndThread<float>();
   EXPECT_FLOAT_EQ(15.3f, res, 0.001f);
 }
 
@@ -2554,7 +2559,7 @@
 
 
 ASSEMBLER_TEST_RUN(PackedSetWZero, test) {
-  float res = test->InvokeWithCode<float>();
+  float res = test->InvokeWithCodeAndThread<float>();
   EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
 }
 
@@ -2678,7 +2683,7 @@
 
 
 ASSEMBLER_TEST_RUN(PackedLogicalNot, test) {
-  uint32_t res = test->InvokeWithCode<uint32_t>();
+  uint32_t res = test->InvokeWithCodeAndThread<uint32_t>();
   EXPECT_EQ(static_cast<uword>(0x0), res);
 }
 
@@ -3092,8 +3097,7 @@
   __ CompareObject(RCX, smi);
   __ j(NOT_EQUAL, &fail);
   __ movl(RAX, Immediate(1));  // OK
-  __ popq(PP);  // Restore caller's pool pointer.
-  __ LeaveFrame();
+  LeaveTestFrame(assembler);
   __ ret();
   __ Bind(&fail);
   __ movl(RAX, Immediate(0));  // Fail.
@@ -3103,7 +3107,7 @@
 
 
 ASSEMBLER_TEST_RUN(TestObjectCompare, test) {
-  bool res = test->InvokeWithCode<bool>();
+  bool res = test->InvokeWithCodeAndThread<bool>();
   EXPECT_EQ(true, res);
 }
 
@@ -3415,10 +3419,13 @@
 ASSEMBLER_TEST_GENERATE(DoubleAbs, assembler) {
   EnterTestFrame(assembler);
 #if defined(TARGET_OS_WINDOWS)
-  // First argument is code object, MSVC passes second argument in XMM1.
-  __ DoubleAbs(XMM1);
-  __ movaps(XMM0, XMM1);
+  // First argument is code object, second argument is thread. MSVC passes
+  // third argument in XMM2.
+  __ DoubleAbs(XMM2);
+  __ movaps(XMM0, XMM2);
 #else
+  // SysV ABI allocates integral and double registers for arguments
+  // independently.
   __ DoubleAbs(XMM0);
 #endif
   LeaveTestFrame(assembler);
@@ -3428,10 +3435,10 @@
 
 ASSEMBLER_TEST_RUN(DoubleAbs, test) {
   double val = -12.45;
-  double res =  test->InvokeWithCode<double, double>(val);
+  double res =  test->InvokeWithCodeAndThread<double, double>(val);
   EXPECT_FLOAT_EQ(-val, res, 0.001);
   val = 12.45;
-  res = test->InvokeWithCode<double, double>(val);
+  res = test->InvokeWithCodeAndThread<double, double>(val);
   EXPECT_FLOAT_EQ(val, res, 0.001);
 }
 
diff --git a/runtime/vm/ast.cc b/runtime/vm/ast.cc
index 48bd053..8698e26 100644
--- a/runtime/vm/ast.cc
+++ b/runtime/vm/ast.cc
@@ -122,6 +122,16 @@
 }
 
 
+bool StringInterpolateNode::IsPotentiallyConst() const {
+  for (int i = 0; i < value_->length(); i++) {
+    if (!value_->ElementAt(i)->IsPotentiallyConst()) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
 bool LiteralNode::IsPotentiallyConst() const {
   return true;
 }
diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h
index 14934fd..0e9b68c 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -92,7 +92,6 @@
 #define DECLARE_COMMON_NODE_FUNCTIONS(type)                                    \
   virtual void Visit(AstNodeVisitor* visitor);                                 \
   virtual const char* PrettyName() const;                                      \
-  virtual bool Is##type() const { return true; }                               \
   virtual type* As##type() { return this; }
 
 
@@ -107,7 +106,7 @@
   intptr_t token_pos() const { return token_pos_; }
 
 #define AST_TYPE_CHECK(BaseName)                                               \
-  virtual bool Is##BaseName##Node() const { return false; }                    \
+  bool Is##BaseName##Node() { return As##BaseName##Node() != NULL; }           \
   virtual BaseName##Node* As##BaseName##Node() { return NULL; }
 
   FOR_EACH_NODE(AST_TYPE_CHECK)
@@ -411,6 +410,8 @@
 
   ArrayNode* value() const { return value_; }
 
+  virtual bool IsPotentiallyConst() const;
+
   DECLARE_COMMON_NODE_FUNCTIONS(StringInterpolateNode);
 
  private:
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index 1b22bc5..dc2fcdf 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -55,7 +55,7 @@
 BENCHMARK(CorelibCompilerStats) {
   bin::Builtin::SetNativeResolver(bin::Builtin::kBuiltinLibrary);
   bin::Builtin::SetNativeResolver(bin::Builtin::kIOLibrary);
-  CompilerStats* stats = Isolate::Current()->compiler_stats();
+  CompilerStats* stats = thread->isolate()->compiler_stats();
   ASSERT(stats != NULL);
   stats->EnableBenchmark();
   Timer timer(true, "Compiler stats compiling all of Core lib");
@@ -77,7 +77,7 @@
 BENCHMARK(CorelibIsolateStartup) {
   const int kNumIterations = 1000;
   Timer timer(true, "CorelibIsolateStartup");
-  Isolate* isolate = Isolate::Current();
+  Isolate* isolate = thread->isolate();
   Thread::ExitIsolate();
   for (int i = 0; i < kNumIterations; i++) {
     timer.Start();
@@ -416,7 +416,7 @@
         reinterpret_cast<Dart_NativeEntryResolver>(NativeResolver));
     EXPECT_VALID(lib);
   }
-  CompilerStats* stats = Isolate::Current()->compiler_stats();
+  CompilerStats* stats = thread->isolate()->compiler_stats();
   ASSERT(stats != NULL);
   stats->EnableBenchmark();
   Timer timer(true, "Compile all of dart2js benchmark");
@@ -545,7 +545,7 @@
   // Need to load the script into the dart: core library due to
   // the import of dart:_internal.
   TestCase::LoadCoreTestScript(kScriptChars, NULL);
-  Api::CheckAndFinalizePendingClasses(Isolate::Current());
+  Api::CheckAndFinalizePendingClasses(thread);
 
   // Write snapshot with object content.
   FullSnapshotWriter writer(&vm_isolate_snapshot_buffer,
@@ -582,7 +582,7 @@
   // Need to load the script into the dart: core library due to
   // the import of dart:_internal.
   TestCase::LoadCoreTestScript(kScriptChars, NULL);
-  Api::CheckAndFinalizePendingClasses(Isolate::Current());
+  Api::CheckAndFinalizePendingClasses(thread);
 
   // Write snapshot with object content.
   FullSnapshotWriter writer(&vm_isolate_snapshot_buffer,
@@ -623,7 +623,7 @@
       "\n";
   const intptr_t kLoopCount = 1000000;
   TestCase::LoadTestScript(kScriptChars, NULL);
-  Api::CheckAndFinalizePendingClasses(Isolate::Current());
+  Api::CheckAndFinalizePendingClasses(thread);
   Dart_Isolate isolate = Dart_CurrentIsolate();
   Timer timer(true, "Enter and Exit isolate");
   timer.Start();
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index 5d7bdc39..7596920 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -181,7 +181,6 @@
                                   const Library& lib,
                                   const String& uri) {
   Zone* zone = thread->zone();
-  Isolate* isolate = thread->isolate();
   const String& part_source = String::Handle(
       zone, GetLibrarySource(lib, uri, false));
   const String& lib_uri = String::Handle(zone, lib.url());
@@ -201,7 +200,7 @@
   const Script& part_script = Script::Handle(
       zone, Script::New(part_uri, part_source, RawScript::kSourceTag));
   const Error& error = Error::Handle(zone, Compile(lib, part_script));
-  return Api::NewHandle(isolate, error.raw());
+  return Api::NewHandle(thread, error.raw());
 }
 
 
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 03393de..315ce85 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -151,6 +151,7 @@
   V(DateNatives_localTimeZoneAdjustmentInSeconds, 0)                           \
   V(AssertionError_throwNew, 2)                                                \
   V(Async_rethrow, 2)                                                          \
+  V(StackTrace_current, 0)                                                     \
   V(TypeError_throwNew, 5)                                                     \
   V(FallThroughError_throwNew, 1)                                              \
   V(AbstractClassInstantiationError_throwNew, 2)                               \
@@ -406,6 +407,7 @@
   V(VMService_ListenStream, 1)                                                 \
   V(VMService_CancelStream, 1)                                                 \
   V(VMService_RequestAssets, 0)                                                \
+  V(VMService_DecodeAssets, 1)                                                 \
 
 class BootstrapNatives : public AllStatic {
  public:
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 2aba065..b981608 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -13,7 +13,6 @@
 #include "vm/debugger.h"
 #include "vm/deopt_instructions.h"
 #include "vm/exceptions.h"
-#include "vm/intermediate_language.h"
 #include "vm/object_store.h"
 #include "vm/message.h"
 #include "vm/message_handler.h"
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 3ce52e1..c42072f 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -77,6 +77,7 @@
 bool Compiler::always_optimize_ = false;
 bool Compiler::allow_recompilation_ = true;
 
+#ifndef DART_PRECOMPILED
 
 // TODO(zerny): Factor out unoptimizing/optimizing pipelines and remove
 // separate helpers functions & `optimizing` args.
@@ -315,7 +316,7 @@
   LongJumpScope jump;
   if (setjmp(*jump.Set()) == 0) {
     if (FLAG_trace_compiler) {
-      THR_Print("Compiling Class %s '%s'\n", "", cls.ToCString());
+      THR_Print("Compiling Class '%s'\n", cls.ToCString());
     }
 
     // Add the primary class which needs to be parsed to the parse list.
@@ -548,7 +549,9 @@
 
           FlowGraphInliner inliner(flow_graph,
                                    &inline_id_to_function,
-                                   &caller_inline_id);
+                                   &caller_inline_id,
+                                   use_speculative_inlining,
+                                   &inlining_black_list);
           inliner.Inline();
           // Use lists are maintained and validated by the inliner.
           DEBUG_ASSERT(flow_graph->VerifyUseLists());
@@ -1387,24 +1390,6 @@
       func.ClearCode();
     }
   }
-
-  // Inner functions get added to the closures array. As part of compilation
-  // more closures can be added to the end of the array. Compile all the
-  // closures until we have reached the end of the "worklist".
-  const GrowableObjectArray& closures =
-      GrowableObjectArray::Handle(zone,
-          Isolate::Current()->object_store()->closure_functions());
-  for (int i = 0; i < closures.Length(); i++) {
-    func ^= closures.At(i);
-    if ((func.Owner() == cls.raw()) && !func.HasCode()) {
-      error = CompileFunction(thread, func);
-      if (!error.IsNull()) {
-        return error.raw();
-      }
-      func.ClearICDataArray();
-      func.ClearCode();
-    }
-  }
   return error.raw();
 }
 
@@ -1731,9 +1716,7 @@
 
 void BackgroundCompiler::Stop(BackgroundCompiler* task) {
   ASSERT(Isolate::Current()->background_compiler() == task);
-  if (task == NULL) {
-    return;
-  }
+  ASSERT(task != NULL);
   BackgroundCompilationQueue* function_queue = task->function_queue();
 
   Monitor* queue_monitor = task->queue_monitor_;
@@ -1792,4 +1775,112 @@
   }
 }
 
+
+#else  // DART_PRECOMPILED
+
+
+DEFINE_RUNTIME_ENTRY(CompileFunction, 1) {
+  UNREACHABLE();
+}
+
+
+bool Compiler::IsBackgroundCompilation() {
+  UNREACHABLE();
+  return false;
+}
+
+
+RawError* Compiler::Compile(const Library& library, const Script& script) {
+  UNREACHABLE();
+  return Error::null();
+}
+
+
+RawError* Compiler::CompileClass(const Class& cls) {
+  UNREACHABLE();
+  return Error::null();
+}
+
+
+RawError* Compiler::CompileFunction(Thread* thread,
+                                    const Function& function) {
+  UNREACHABLE();
+  return Error::null();
+}
+
+
+RawError* Compiler::EnsureUnoptimizedCode(Thread* thread,
+                                          const Function& function) {
+  UNREACHABLE();
+  return Error::null();
+}
+
+
+RawError* Compiler::CompileOptimizedFunction(Thread* thread,
+                                             const Function& function,
+                                             intptr_t osr_id) {
+  UNREACHABLE();
+  return Error::null();
+}
+
+
+RawError* Compiler::CompileParsedFunction(
+    ParsedFunction* parsed_function) {
+  UNREACHABLE();
+  return Error::null();
+}
+
+
+void Compiler::ComputeLocalVarDescriptors(const Code& code) {
+  UNREACHABLE();
+}
+
+
+RawError* Compiler::CompileAllFunctions(const Class& cls) {
+  UNREACHABLE();
+  return Error::null();
+}
+
+
+void Compiler::CompileStaticInitializer(const Field& field) {
+  UNREACHABLE();
+}
+
+
+RawObject* Compiler::EvaluateStaticInitializer(const Field& field) {
+  ASSERT(field.HasPrecompiledInitializer());
+  const Function& initializer =
+      Function::Handle(field.PrecompiledInitializer());
+  return DartEntry::InvokeFunction(initializer, Object::empty_array());
+}
+
+
+
+RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) {
+  UNREACHABLE();
+  return Object::null();
+}
+
+
+void BackgroundCompiler::CompileOptimized(const Function& function) {
+  UNREACHABLE();
+}
+
+
+void BackgroundCompiler::VisitPointers(ObjectPointerVisitor* visitor) {
+  UNREACHABLE();
+}
+
+
+void BackgroundCompiler::Stop(BackgroundCompiler* task) {
+  UNREACHABLE();
+}
+
+
+void BackgroundCompiler::EnsureInit(Thread* thread) {
+  UNREACHABLE();
+}
+
+#endif  // DART_PRECOMPILED
+
 }  // namespace dart
diff --git a/runtime/vm/constant_propagator.cc b/runtime/vm/constant_propagator.cc
index 61c09a6..5e4f53c 100644
--- a/runtime/vm/constant_propagator.cc
+++ b/runtime/vm/constant_propagator.cc
@@ -19,6 +19,8 @@
 DEFINE_FLAG(bool, trace_constant_propagation, false,
     "Print constant propagation and useless code elimination.");
 
+DECLARE_FLAG(bool, fields_may_be_reset);
+
 // Quick access to the current zone and isolate.
 #define I (isolate())
 #define Z (graph_->zone())
@@ -704,14 +706,16 @@
 
 
 void ConstantPropagator::VisitLoadStaticField(LoadStaticFieldInstr* instr) {
-  const Field& field = instr->StaticField();
-  ASSERT(field.is_static());
-  Instance& obj = Instance::Handle(Z, field.StaticValue());
-  if (field.is_final() && (obj.raw() != Object::sentinel().raw()) &&
-      (obj.raw() != Object::transition_sentinel().raw())) {
-    if (obj.IsSmi() || obj.IsOld()) {
-      SetValue(instr, obj);
-      return;
+  if (!FLAG_fields_may_be_reset) {
+    const Field& field = instr->StaticField();
+    ASSERT(field.is_static());
+    Instance& obj = Instance::Handle(Z, field.StaticValue());
+    if (field.is_final() && (obj.raw() != Object::sentinel().raw()) &&
+        (obj.raw() != Object::transition_sentinel().raw())) {
+      if (obj.IsSmi() || obj.IsOld()) {
+        SetValue(instr, obj);
+        return;
+      }
     }
   }
   SetValue(instr, non_constant_);
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 14ff0e7..eb12276 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -73,8 +73,6 @@
 const char* Dart::InitOnce(const uint8_t* vm_isolate_snapshot,
                            const uint8_t* instructions_snapshot,
                            Dart_IsolateCreateCallback create,
-                           Dart_IsolateInterruptCallback interrupt,
-                           Dart_IsolateUnhandledExceptionCallback unhandled,
                            Dart_IsolateShutdownCallback shutdown,
                            Dart_FileOpenCallback file_open,
                            Dart_FileReadCallback file_read,
@@ -90,11 +88,8 @@
   Isolate::SetEntropySourceCallback(entropy_source);
   OS::InitOnce();
   VirtualMemory::InitOnce();
-  Thread::InitOnceBeforeIsolate();
-  Thread::EnsureInit();
+  OSThread::InitOnce();
   Timeline::InitOnce();
-  Thread* thread = Thread::Current();
-  thread->set_name("Dart_Initialize");
   TimelineDurationScope tds(Timeline::GetVMStream(),
                             "Dart::InitOnce");
   Isolate::InitOnce();
@@ -108,7 +103,6 @@
   Metric::InitOnce();
   StoreBuffer::InitOnce();
   MarkingStack::InitOnce();
-  Thread::EnsureInit();
 
 #if defined(USING_SIMULATOR)
   Simulator::InitOnce();
@@ -120,8 +114,6 @@
   ASSERT(thread_pool_ == NULL);
   thread_pool_ = new ThreadPool();
   {
-    Thread* T = Thread::Current();
-    ASSERT(T != NULL);
     ASSERT(vm_isolate_ == NULL);
     ASSERT(Flags::Initialized());
     const bool is_vm_isolate = true;
@@ -137,6 +129,8 @@
     ASSERT(vm_isolate_ == Isolate::Current());
     ASSERT(vm_isolate_ == Thread::Current()->isolate());
 
+    Thread* T = Thread::Current();
+    ASSERT(T != NULL);
     StackZone zone(T);
     HandleScope handle_scope(T);
     Object::InitNull(vm_isolate_);
@@ -180,7 +174,9 @@
     } else {
       Symbols::InitOnce(vm_isolate_);
     }
-    Thread::InitOnceAfterObjectAndStubCode();
+    // We need to initialize the constants here for the vm isolate thread due to
+    // bootstrapping issues.
+    T->InitVMConstants();
     Scanner::InitOnce();
 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
     // Dart VM requires at least SSE2.
@@ -199,8 +195,6 @@
 
   Thread::ExitIsolate();  // Unregister the VM isolate from this thread.
   Isolate::SetCreateCallback(create);
-  Isolate::SetInterruptCallback(interrupt);
-  Isolate::SetUnhandledExceptionCallback(unhandled);
   Isolate::SetShutdownCallback(shutdown);
 
   Service::SetGetServiceAssetsCallback(get_service_assets);
@@ -250,7 +244,6 @@
     thread_pool_ = NULL;
 
     // Set the VM isolate as current isolate.
-    Thread::EnsureInit();
     Thread::EnterIsolate(vm_isolate_);
 
     ShutdownIsolate();
@@ -260,7 +253,12 @@
     TargetCPUFeatures::Cleanup();
     StoreBuffer::ShutDown();
 
-    Thread::Shutdown();
+    // Delete the current thread's TLS and set it's TLS to null.
+    // If it is the last thread then the destructor would call
+    // OSThread::Cleanup.
+    OSThread* os_thread = OSThread::Current();
+    OSThread::SetCurrent(NULL);
+    delete os_thread;
   } else {
     // Shutdown the service isolate.
     ServiceIsolate::Shutdown();
diff --git a/runtime/vm/dart.h b/runtime/vm/dart.h
index 3eded72..412eef2 100644
--- a/runtime/vm/dart.h
+++ b/runtime/vm/dart.h
@@ -24,8 +24,6 @@
       const uint8_t* vm_isolate_snapshot,
       const uint8_t* instructions_snapshot,
       Dart_IsolateCreateCallback create,
-      Dart_IsolateInterruptCallback interrupt,
-      Dart_IsolateUnhandledExceptionCallback unhandled,
       Dart_IsolateShutdownCallback shutdown,
       Dart_FileOpenCallback file_open,
       Dart_FileReadCallback file_read,
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 7f71986..5971023 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -64,7 +64,7 @@
 DEFINE_FLAG(bool, verify_acquired_data, false,
             "Verify correct API acquire/release of typed data.");
 
-ThreadLocalKey Api::api_native_key_ = OSThread::kUnsetThreadLocalKey;
+ThreadLocalKey Api::api_native_key_ = kUnsetThreadLocalKey;
 Dart_Handle Api::true_handle_ = NULL;
 Dart_Handle Api::false_handle_ = NULL;
 Dart_Handle Api::null_handle_ = NULL;
@@ -174,16 +174,14 @@
     return true;
   }
   Thread* thread = arguments->thread();
-  Isolate* isolate = thread->isolate();
-  ASSERT(isolate == Isolate::Current());
+  ASSERT(thread == Thread::Current());
   *peer = NULL;
   REUSABLE_OBJECT_HANDLESCOPE(thread);
   Object& obj = thread->ObjectHandle();
   obj = arguments->NativeArgAt(arg_index);
   if (RawObject::IsStringClassId(obj.GetClassId())) {
-    ASSERT(isolate->api_state() &&
-           isolate->api_state()->top_scope() != NULL);
-    *str = Api::NewHandle(isolate, obj.raw());
+    ASSERT(thread->api_top_scope() != NULL);
+    *str = Api::NewHandle(thread, obj.raw());
     return true;
   }
   if (obj.IsNull()) {
@@ -301,8 +299,8 @@
 }
 
 
-Heap::Space SpaceForExternal(Isolate* isolate, intptr_t size) {
-  Heap* heap = isolate->heap();
+Heap::Space SpaceForExternal(Thread* thread, intptr_t size) {
+  Heap* heap = thread->heap();
   // If 'size' would be a significant fraction of new space, then use old.
   static const int kExtNewRatio = 16;
   if (size > (heap->CapacityInWords(Heap::kNew) * kWordSize) / kExtNewRatio) {
@@ -347,18 +345,8 @@
 }
 
 
-WeakReferenceSetBuilder* ApiState::NewWeakReferenceSetBuilder() {
-  return new WeakReferenceSetBuilder(this);
-}
-
-
-void ApiState::DelayWeakReferenceSet(WeakReferenceSet* reference_set) {
-  WeakReferenceSet::Push(reference_set, &delayed_weak_reference_sets_);
-}
-
-
-Dart_Handle Api::InitNewHandle(Isolate* isolate, RawObject* raw) {
-  LocalHandles* local_handles = Api::TopScope(isolate)->local_handles();
+Dart_Handle Api::InitNewHandle(Thread* thread, RawObject* raw) {
+  LocalHandles* local_handles = Api::TopScope(thread)->local_handles();
   ASSERT(local_handles != NULL);
   LocalHandle* ref = local_handles->AllocateHandle();
   ref->set_raw(raw);
@@ -366,7 +354,7 @@
 }
 
 
-Dart_Handle Api::NewHandle(Isolate* isolate, RawObject* raw) {
+Dart_Handle Api::NewHandle(Thread* thread, RawObject* raw) {
   if (raw == Object::null()) {
     return Null();
   }
@@ -376,19 +364,17 @@
   if (raw == Bool::False().raw()) {
     return False();
   }
-  return InitNewHandle(isolate, raw);
+  return InitNewHandle(thread, raw);
 }
 
 
 RawObject* Api::UnwrapHandle(Dart_Handle object) {
 #if defined(DEBUG)
-  ASSERT(Thread::Current()->IsMutatorThread());
-  Isolate* isolate = Isolate::Current();
-  ASSERT(isolate != NULL);
-  ApiState* state = isolate->api_state();
-  ASSERT(state != NULL);
+  Thread* thread = Thread::Current();
+  ASSERT(thread->IsMutatorThread());
+  ASSERT(thread->isolate() != NULL);
   ASSERT(!FLAG_verify_handles ||
-         state->IsValidLocalHandle(object) ||
+         thread->IsValidLocalHandle(object) ||
          Dart::IsReadOnlyApiHandle(object));
   ASSERT(FinalizablePersistentHandle::raw_offset() == 0 &&
          PersistentHandle::raw_offset() == 0 &&
@@ -433,7 +419,8 @@
 }
 
 
-Dart_Handle Api::CheckAndFinalizePendingClasses(Isolate* isolate) {
+Dart_Handle Api::CheckAndFinalizePendingClasses(Thread* thread) {
+  Isolate* isolate = thread->isolate();
   if (!isolate->AllowClassFinalization()) {
     // Class finalization is blocked for the isolate. Do nothing.
     return Api::Success();
@@ -442,7 +429,7 @@
     return Api::Success();
   }
   ASSERT(isolate->object_store()->sticky_error() != Object::null());
-  return Api::NewHandle(isolate, isolate->object_store()->sticky_error());
+  return Api::NewHandle(thread, isolate->object_store()->sticky_error());
 }
 
 
@@ -467,7 +454,7 @@
   va_end(args2);
 
   const String& message = String::Handle(Z, String::New(buffer));
-  return Api::NewHandle(I, ApiError::New(message));
+  return Api::NewHandle(T, ApiError::New(message));
 }
 
 
@@ -488,20 +475,18 @@
 }
 
 
-ApiLocalScope* Api::TopScope(Isolate* isolate) {
-  ASSERT(isolate != NULL);
-  ApiState* state = isolate->api_state();
-  ASSERT(state != NULL);
-  ApiLocalScope* scope = state->top_scope();
+ApiLocalScope* Api::TopScope(Thread* thread) {
+  ASSERT(thread != NULL);
+  ApiLocalScope* scope = thread->api_top_scope();
   ASSERT(scope != NULL);
   return scope;
 }
 
 
 void Api::InitOnce() {
-  ASSERT(api_native_key_ == OSThread::kUnsetThreadLocalKey);
+  ASSERT(api_native_key_ == kUnsetThreadLocalKey);
   api_native_key_ = OSThread::CreateThreadLocal();
-  ASSERT(api_native_key_ != OSThread::kUnsetThreadLocalKey);
+  ASSERT(api_native_key_ != kUnsetThreadLocalKey);
 }
 
 
@@ -691,8 +676,7 @@
     Dart_WeakPersistentHandle handle) {
 #if defined(DEBUG)
   ApiState* state = Isolate::Current()->api_state();
-  ASSERT(state->IsValidWeakPersistentHandle(handle) ||
-         state->IsValidPrologueWeakPersistentHandle(handle));
+  ASSERT(state->IsValidWeakPersistentHandle(handle));
 #endif
   return reinterpret_cast<FinalizablePersistentHandle*>(handle);
 }
@@ -710,11 +694,7 @@
   (*callback)(isolate->init_callback_data(), object, peer);
   ApiState* state = isolate->api_state();
   ASSERT(state != NULL);
-  if (handle->IsPrologueWeakPersistent()) {
-    state->prologue_weak_persistent_handles().FreeHandle(handle);
-  } else {
-    state->weak_persistent_handles().FreeHandle(handle);
-  }
+  state->weak_persistent_handles().FreeHandle(handle);
 }
 
 
@@ -764,7 +744,7 @@
     const Error& error = Error::Cast(obj);
     const char* str = error.ToErrorCString();
     intptr_t len = strlen(str) + 1;
-    char* str_copy = Api::TopScope(I)->zone()->Alloc<char>(len);
+    char* str_copy = Api::TopScope(T)->zone()->Alloc<char>(len);
     strncpy(str_copy, str, len);
     // Strip a possible trailing '\n'.
     if ((len > 1) && (str_copy[len - 2] == '\n')) {
@@ -789,7 +769,7 @@
   const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
   if (obj.IsUnhandledException()) {
     const UnhandledException& error = UnhandledException::Cast(obj);
-    return Api::NewHandle(I, error.exception());
+    return Api::NewHandle(T, error.exception());
   } else if (obj.IsError()) {
     return Api::NewError("This error is not an unhandled exception error.");
   } else {
@@ -803,7 +783,7 @@
   const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
   if (obj.IsUnhandledException()) {
     const UnhandledException& error = UnhandledException::Cast(obj);
-    return Api::NewHandle(I, error.stacktrace());
+    return Api::NewHandle(T, error.stacktrace());
   } else if (obj.IsError()) {
     return Api::NewError("This error is not an unhandled exception error.");
   } else {
@@ -819,7 +799,7 @@
   CHECK_CALLBACK_STATE(T);
 
   const String& message = String::Handle(Z, String::New(error));
-  return Api::NewHandle(I, ApiError::New(message));
+  return Api::NewHandle(T, ApiError::New(message));
 }
 
 
@@ -838,13 +818,12 @@
     }
   }
   const Stacktrace& stacktrace = Stacktrace::Handle(Z);
-  return Api::NewHandle(I, UnhandledException::New(obj, stacktrace));
+  return Api::NewHandle(T, UnhandledException::New(obj, stacktrace));
 }
 
 
 DART_EXPORT Dart_Handle Dart_PropagateError(Dart_Handle handle) {
   Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
   {
     const Object& obj = Object::Handle(thread->zone(),
         Api::UnwrapHandle(handle));
@@ -862,8 +841,6 @@
   }
 
   // Unwind all the API scopes till the exit frame before propagating.
-  ApiState* state = isolate->api_state();
-  ASSERT(state != NULL);
   const Error* error;
   {
     // We need to preserve the error object across the destruction of zones
@@ -872,7 +849,7 @@
     // handle for it in the surviving zone.
     NoSafepointScope no_safepoint;
     RawError* raw_error = Api::UnwrapErrorHandle(thread->zone(), handle).raw();
-    state->UnwindScopes(thread->top_exit_frame_info());
+    thread->UnwindScopes(thread->top_exit_frame_info());
     // Note that thread's zone is different here than at the beginning of this
     // function.
     error = &Error::Handle(thread->zone(), raw_error);
@@ -897,15 +874,15 @@
   DARTSCOPE(Thread::Current());
   const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object));
   if (obj.IsString()) {
-    return Api::NewHandle(I, obj.raw());
+    return Api::NewHandle(T, obj.raw());
   } else if (obj.IsInstance()) {
     CHECK_CALLBACK_STATE(T);
     const Instance& receiver = Instance::Cast(obj);
-    return Api::NewHandle(I, DartLibraryCalls::ToString(receiver));
+    return Api::NewHandle(T, DartLibraryCalls::ToString(receiver));
   } else {
     CHECK_CALLBACK_STATE(T);
     // This is a VM internal object. Call the C++ method of printing.
-    return Api::NewHandle(I, String::New(obj.ToCString()));
+    return Api::NewHandle(T, String::New(obj.ToCString()));
   }
 }
 
@@ -971,29 +948,32 @@
 
 DART_EXPORT Dart_Handle Dart_HandleFromPersistent(
     Dart_PersistentHandle object) {
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   CHECK_ISOLATE(isolate);
   ApiState* state = isolate->api_state();
   ASSERT(state != NULL);
   PersistentHandle* ref = PersistentHandle::Cast(object);
-  return Api::NewHandle(isolate, ref->raw());
+  return Api::NewHandle(thread, ref->raw());
 }
 
 
 DART_EXPORT Dart_Handle Dart_HandleFromWeakPersistent(
     Dart_WeakPersistentHandle object) {
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   CHECK_ISOLATE(isolate);
   ApiState* state = isolate->api_state();
   ASSERT(state != NULL);
   FinalizablePersistentHandle* weak_ref =
       FinalizablePersistentHandle::Cast(object);
-  return Api::NewHandle(isolate, weak_ref->raw());
+  return Api::NewHandle(thread, weak_ref->raw());
 }
 
 
 DART_EXPORT Dart_PersistentHandle Dart_NewPersistentHandle(Dart_Handle object) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   ApiState* state = I->api_state();
   ASSERT(state != NULL);
   const Object& old_ref = Object::Handle(Z, Api::UnwrapHandle(object));
@@ -1006,6 +986,7 @@
 DART_EXPORT void Dart_SetPersistentHandle(Dart_PersistentHandle obj1,
                                           Dart_Handle obj2) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   ApiState* state = I->api_state();
   ASSERT(state != NULL);
   ASSERT(state->IsValidPersistentHandle(obj1));
@@ -1018,7 +999,6 @@
 static Dart_WeakPersistentHandle AllocateFinalizableHandle(
     Thread* thread,
     Dart_Handle object,
-    bool is_prologue,
     void* peer,
     intptr_t external_allocation_size,
     Dart_WeakPersistentHandleFinalizer callback) {
@@ -1027,7 +1007,6 @@
   ref = Api::UnwrapHandle(object);
   FinalizablePersistentHandle* finalizable_ref =
       FinalizablePersistentHandle::New(thread->isolate(),
-                                       is_prologue,
                                        ref,
                                        peer,
                                        callback,
@@ -1048,26 +1027,6 @@
   }
   return AllocateFinalizableHandle(thread,
                                    object,
-                                   false,
-                                   peer,
-                                   external_allocation_size,
-                                   callback);
-}
-
-
-DART_EXPORT Dart_WeakPersistentHandle Dart_NewPrologueWeakPersistentHandle(
-    Dart_Handle object,
-    void* peer,
-    intptr_t external_allocation_size,
-    Dart_WeakPersistentHandleFinalizer callback) {
-  Thread* thread = Thread::Current();
-  CHECK_ISOLATE(thread->isolate());
-  if (callback == NULL) {
-    return NULL;
-  }
-  return AllocateFinalizableHandle(thread,
-                                   object,
-                                   true,
                                    peer,
                                    external_allocation_size,
                                    callback);
@@ -1098,81 +1057,7 @@
   FinalizablePersistentHandle* weak_ref =
       FinalizablePersistentHandle::Cast(object);
   weak_ref->EnsureFreeExternal(isolate);
-  if (weak_ref->IsPrologueWeakPersistent()) {
-    ASSERT(state->IsValidPrologueWeakPersistentHandle(object));
-    state->prologue_weak_persistent_handles().FreeHandle(weak_ref);
-  } else {
-    ASSERT(!state->IsValidPrologueWeakPersistentHandle(object));
-    state->weak_persistent_handles().FreeHandle(weak_ref);
-  }
-}
-
-
-DART_EXPORT bool Dart_IsPrologueWeakPersistentHandle(
-    Dart_WeakPersistentHandle object) {
-  FinalizablePersistentHandle* weak_ref =
-      FinalizablePersistentHandle::Cast(object);
-  return weak_ref->IsPrologueWeakPersistent();
-}
-
-
-DART_EXPORT Dart_WeakReferenceSetBuilder Dart_NewWeakReferenceSetBuilder() {
-  Isolate* isolate = Isolate::Current();
-  CHECK_ISOLATE(isolate);
-  ApiState* state = isolate->api_state();
-  ASSERT(state != NULL);
-  return reinterpret_cast<Dart_WeakReferenceSetBuilder>(
-      state->NewWeakReferenceSetBuilder());
-}
-
-
-DART_EXPORT Dart_WeakReferenceSet Dart_NewWeakReferenceSet(
-    Dart_WeakReferenceSetBuilder set_builder,
-    Dart_WeakPersistentHandle key,
-    Dart_WeakPersistentHandle value) {
-  ASSERT(set_builder != NULL && key != NULL);
-  WeakReferenceSetBuilder* builder =
-      reinterpret_cast<WeakReferenceSetBuilder*>(set_builder);
-  ApiState* state = builder->api_state();
-  ASSERT(state == Isolate::Current()->api_state());
-  WeakReferenceSet* reference_set = builder->NewWeakReferenceSet();
-  reference_set->AppendKey(key);
-  if (value != NULL) {
-    reference_set->AppendValue(value);
-  }
-  state->DelayWeakReferenceSet(reference_set);
-  return reinterpret_cast<Dart_WeakReferenceSet>(reference_set);
-}
-
-
-DART_EXPORT Dart_Handle Dart_AppendToWeakReferenceSet(
-    Dart_WeakReferenceSet reference_set,
-    Dart_WeakPersistentHandle key,
-    Dart_WeakPersistentHandle value) {
-  ASSERT(reference_set != NULL);
-  WeakReferenceSet* set = reinterpret_cast<WeakReferenceSet*>(reference_set);
-  set->Append(key, value);
-  return Api::Success();
-}
-
-
-DART_EXPORT Dart_Handle Dart_AppendKeyToWeakReferenceSet(
-    Dart_WeakReferenceSet reference_set,
-    Dart_WeakPersistentHandle key) {
-  ASSERT(reference_set != NULL);
-  WeakReferenceSet* set = reinterpret_cast<WeakReferenceSet*>(reference_set);
-  set->AppendKey(key);
-  return Api::Success();
-}
-
-
-DART_EXPORT Dart_Handle Dart_AppendValueToWeakReferenceSet(
-    Dart_WeakReferenceSet reference_set,
-    Dart_WeakPersistentHandle value) {
-  ASSERT(reference_set != NULL);
-  WeakReferenceSet* set = reinterpret_cast<WeakReferenceSet*>(reference_set);
-  set->AppendValue(value);
-  return Api::Success();
+  state->weak_persistent_handles().FreeHandle(weak_ref);
 }
 
 
@@ -1217,53 +1102,6 @@
 }
 
 
-class PrologueWeakVisitor : public HandleVisitor {
- public:
-  PrologueWeakVisitor(Thread* thread,
-                      Dart_GcPrologueWeakHandleCallback callback)
-      :  HandleVisitor(thread),
-         callback_(callback) {
-  }
-
-
-  void VisitHandle(uword addr) {
-    NoSafepointScope no_safepoint;
-    FinalizablePersistentHandle* handle =
-        reinterpret_cast<FinalizablePersistentHandle*>(addr);
-    RawObject* raw_obj = handle->raw();
-    if (raw_obj->IsHeapObject()) {
-      ASSERT(handle->IsPrologueWeakPersistent());
-      ReusableInstanceHandleScope reused_instance_handle(thread());
-      Instance& instance = reused_instance_handle.Handle();
-      instance ^= reinterpret_cast<RawInstance*>(handle->raw());
-      intptr_t num_native_fields = instance.NumNativeFields();
-      intptr_t* native_fields = instance.NativeFieldsDataAddr();
-      if (native_fields != NULL) {
-        callback_(thread()->isolate()->init_callback_data(),
-                  reinterpret_cast<Dart_WeakPersistentHandle>(addr),
-                  num_native_fields,
-                  native_fields);
-      }
-    }
-  }
-
- private:
-  Dart_GcPrologueWeakHandleCallback callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(PrologueWeakVisitor);
-};
-
-
-DART_EXPORT Dart_Handle Dart_VisitPrologueWeakHandles(
-    Dart_GcPrologueWeakHandleCallback callback) {
-  Thread* thread = Thread::Current();
-  CHECK_ISOLATE(thread->isolate());
-  PrologueWeakVisitor visitor(thread, callback);
-  thread->isolate()->VisitPrologueWeakPersistentHandles(&visitor);
-  return Api::Success();
-}
-
-
 // --- Initialization and Globals ---
 
 DART_EXPORT const char* Dart_VersionString() {
@@ -1286,9 +1124,17 @@
   if ((instructions_snapshot != NULL) && !FLAG_precompilation) {
     return strdup("Flag --precompilation was not specified.");
   }
+  if (interrupt != NULL) {
+    return strdup("Dart_Initialize: "
+                  "Setting of interrupt callback is not supported.");
+  }
+  if (unhandled != NULL) {
+    return strdup("Dart_Initialize: "
+                  "Setting of unhandled exception callback is not supported.");
+  }
   const char* err_msg = Dart::InitOnce(vm_isolate_snapshot,
                                        instructions_snapshot,
-                                       create, interrupt, unhandled, shutdown,
+                                       create, shutdown,
                                        file_open, file_read, file_write,
                                        file_close, entropy_source,
                                        get_service_assets);
@@ -1365,7 +1211,6 @@
                                             char** error) {
   CHECK_NO_ISOLATE(Isolate::Current());
   char* isolate_name = BuildIsolateName(script_uri, main);
-  Thread::EnsureInit();
 
   // Setup default flags in case none were passed.
   Dart_IsolateFlags api_flags;
@@ -1447,11 +1292,11 @@
 
 DART_EXPORT Dart_Handle Dart_DebugName() {
   DARTSCOPE(Thread::Current());
-  return Api::NewHandle(I, String::New(I->name()));
+  Isolate* I = T->isolate();
+  return Api::NewHandle(T, String::New(I->name()));
 }
 
 
-
 DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate) {
   CHECK_NO_ISOLATE(Isolate::Current());
   // TODO(16615): Validate isolate parameter.
@@ -1459,26 +1304,25 @@
   if (iso->HasMutatorThread()) {
     FATAL("Multiple mutators within one isolate is not supported.");
   }
-  Thread::EnsureInit();
   Thread::EnterIsolate(iso);
 }
 
 
 DART_EXPORT void Dart_ThreadDisableProfiling() {
-  Thread* T = Thread::Current();
-  if (T == NULL) {
+  OSThread* os_thread = OSThread::Current();
+  if (os_thread == NULL) {
     return;
   }
-  T->DisableThreadInterrupts();
+  os_thread->DisableThreadInterrupts();
 }
 
 
 DART_EXPORT void Dart_ThreadEnableProfiling() {
-  Thread* T = Thread::Current();
-  if (T == NULL) {
+  OSThread* os_thread = OSThread::Current();
+  if (os_thread == NULL) {
     return;
   }
-  T->EnableThreadInterrupts();
+  os_thread->EnableThreadInterrupts();
 }
 
 
@@ -1508,7 +1352,7 @@
 static uint8_t* ApiReallocate(uint8_t* ptr,
                               intptr_t old_size,
                               intptr_t new_size) {
-  return Api::TopScope(Isolate::Current())->zone()->Realloc<uint8_t>(
+  return Api::TopScope(Thread::Current())->zone()->Realloc<uint8_t>(
       ptr, old_size, new_size);
 }
 
@@ -1520,6 +1364,7 @@
     intptr_t* isolate_snapshot_size) {
   ASSERT(FLAG_load_deferred_eagerly);
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   if (vm_isolate_snapshot_buffer != NULL &&
       vm_isolate_snapshot_size == NULL) {
     RETURN_NULL_ERROR(vm_isolate_snapshot_size);
@@ -1531,7 +1376,7 @@
     RETURN_NULL_ERROR(isolate_snapshot_size);
   }
   // Finalize all classes if needed.
-  Dart_Handle state = Api::CheckAndFinalizePendingClasses(I);
+  Dart_Handle state = Api::CheckAndFinalizePendingClasses(T);
   if (::Dart_IsError(state)) {
     return state;
   }
@@ -1560,6 +1405,7 @@
                                          uint8_t** buffer,
                                          intptr_t* size) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   if (buffer == NULL) {
     RETURN_NULL_ERROR(buffer);
   }
@@ -1567,7 +1413,7 @@
     RETURN_NULL_ERROR(size);
   }
   // Finalize all classes if needed.
-  Dart_Handle state = Api::CheckAndFinalizePendingClasses(I);
+  Dart_Handle state = Api::CheckAndFinalizePendingClasses(T);
   if (::Dart_IsError(state)) {
     return state;
   }
@@ -1656,7 +1502,7 @@
 DART_EXPORT Dart_Handle Dart_RunLoop() {
   Thread* T = Thread::Current();
   Isolate* I = T->isolate();
-  CHECK_ISOLATE_SCOPE(I);
+  CHECK_API_SCOPE(T);
   CHECK_CALLBACK_STATE(T);
   Monitor monitor;
   MonitorLocker ml(&monitor);
@@ -1676,7 +1522,7 @@
     Thread::EnterIsolate(I);
   }
   if (I->object_store()->sticky_error() != Object::null()) {
-    Dart_Handle error = Api::NewHandle(I, I->object_store()->sticky_error());
+    Dart_Handle error = Api::NewHandle(T, I->object_store()->sticky_error());
     I->object_store()->clear_sticky_error();
     return error;
   }
@@ -1689,14 +1535,13 @@
 
 
 DART_EXPORT Dart_Handle Dart_HandleMessage() {
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  CHECK_ISOLATE_SCOPE(isolate);
-  CHECK_CALLBACK_STATE(thread);
-  if (isolate->message_handler()->HandleNextMessage() != MessageHandler::kOK) {
-    Dart_Handle error = Api::NewHandle(isolate,
-                                       isolate->object_store()->sticky_error());
-    isolate->object_store()->clear_sticky_error();
+  Thread* T = Thread::Current();
+  Isolate* I = T->isolate();
+  CHECK_API_SCOPE(T);
+  CHECK_CALLBACK_STATE(T);
+  if (I->message_handler()->HandleNextMessage() != MessageHandler::kOK) {
+    Dart_Handle error = Api::NewHandle(T, I->object_store()->sticky_error());
+    I->object_store()->clear_sticky_error();
     return error;
   }
   return Api::Success();
@@ -1704,15 +1549,15 @@
 
 
 DART_EXPORT bool Dart_HandleServiceMessages() {
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  CHECK_ISOLATE_SCOPE(isolate);
-  CHECK_CALLBACK_STATE(thread);
+  Thread* T = Thread::Current();
+  Isolate* I = T->isolate();
+  CHECK_API_SCOPE(T);
+  CHECK_CALLBACK_STATE(T);
 
-  ASSERT(isolate->GetAndClearResumeRequest() == false);
+  ASSERT(I->GetAndClearResumeRequest() == false);
   MessageHandler::MessageStatus status =
-      isolate->message_handler()->HandleOOBMessages();
-  bool resume = isolate->GetAndClearResumeRequest();
+      I->message_handler()->HandleOOBMessages();
+  bool resume = I->GetAndClearResumeRequest();
   return (status != MessageHandler::kOK) || resume;
 }
 
@@ -1760,7 +1605,7 @@
                          CURRENT_FUNC,
                          port_id);
   }
-  return Api::NewHandle(I, SendPort::New(port_id));
+  return Api::NewHandle(T, SendPort::New(port_id));
 }
 
 
@@ -1793,34 +1638,30 @@
   Thread* thread = Thread::Current();
   Isolate* isolate = thread->isolate();
   CHECK_ISOLATE(isolate);
-  ApiState* state = isolate->api_state();
-  ASSERT(state != NULL);
-  ApiLocalScope* new_scope = state->reusable_scope();
+  ApiLocalScope* new_scope = thread->api_reusable_scope();
   if (new_scope == NULL) {
-    new_scope = new ApiLocalScope(state->top_scope(),
+    new_scope = new ApiLocalScope(thread->api_top_scope(),
                                   thread->top_exit_frame_info());
     ASSERT(new_scope != NULL);
   } else {
     new_scope->Reinit(thread,
-                      state->top_scope(),
+                      thread->api_top_scope(),
                       thread->top_exit_frame_info());
-    state->set_reusable_scope(NULL);
+    thread->set_api_reusable_scope(NULL);
   }
-  state->set_top_scope(new_scope);  // New scope is now the top scope.
+  thread->set_api_top_scope(new_scope);  // New scope is now the top scope.
 }
 
 
 DART_EXPORT void Dart_ExitScope() {
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  CHECK_ISOLATE_SCOPE(isolate);
-  ApiState* state = isolate->api_state();
-  ApiLocalScope* scope = state->top_scope();
-  ApiLocalScope* reusable_scope = state->reusable_scope();
-  state->set_top_scope(scope->previous());  // Reset top scope to previous.
+  Thread* T = Thread::Current();
+  CHECK_API_SCOPE(T);
+  ApiLocalScope* scope = T->api_top_scope();
+  ApiLocalScope* reusable_scope = T->api_reusable_scope();
+  T->set_api_top_scope(scope->previous());  // Reset top scope to previous.
   if (reusable_scope == NULL) {
-    scope->Reset(thread);  // Reset the old scope which we just exited.
-    state->set_reusable_scope(scope);
+    scope->Reset(T);  // Reset the old scope which we just exited.
+    T->set_api_reusable_scope(scope);
   } else {
     ASSERT(reusable_scope != scope);
     delete scope;
@@ -1830,11 +1671,9 @@
 
 DART_EXPORT uint8_t* Dart_ScopeAllocate(intptr_t size) {
   Zone* zone;
-  Isolate* isolate = Isolate::Current();
-  if (isolate != NULL) {
-    ApiState* state = isolate->api_state();
-    if (state == NULL) return NULL;
-    ApiLocalScope* scope = state->top_scope();
+  Thread* thread = Thread::Current();
+  if (thread != NULL) {
+    ApiLocalScope* scope = thread->api_top_scope();
     zone = scope->zone();
   } else {
     ApiNativeScope* scope = ApiNativeScope::Current();
@@ -1878,7 +1717,7 @@
     *value = Bool::Cast(result).value();
     return Api::Success();
   } else if (result.IsError()) {
-    return Api::NewHandle(I, result.raw());
+    return Api::NewHandle(T, result.raw());
   } else {
     return Api::NewError("Expected boolean result from ==");
   }
@@ -2053,6 +1892,7 @@
 DART_EXPORT bool Dart_IsFuture(Dart_Handle handle) {
   TRACE_API_CALL(CURRENT_FUNC);
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
   if (obj.IsInstance()) {
     const Class& future_class =
@@ -2075,15 +1915,16 @@
 
 DART_EXPORT Dart_Handle Dart_InstanceGetType(Dart_Handle instance) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   const Object& obj = Object::Handle(Z, Api::UnwrapHandle(instance));
   if (obj.IsNull()) {
-    return Api::NewHandle(I, I->object_store()->null_type());
+    return Api::NewHandle(T, I->object_store()->null_type());
   }
   if (!obj.IsInstance()) {
     RETURN_TYPE_ERROR(Z, instance, Instance);
   }
   const Type& type = Type::Handle(Instance::Cast(obj).GetType());
-  return Api::NewHandle(I, type.Canonicalize());
+  return Api::NewHandle(T, type.Canonicalize());
 }
 
 
@@ -2145,19 +1986,19 @@
   CHECK_ISOLATE(isolate);
   if (Smi::IsValid(value)) {
     NOHANDLESCOPE(thread);
-    return Api::NewHandle(isolate, Smi::New(static_cast<intptr_t>(value)));
+    return Api::NewHandle(thread, Smi::New(static_cast<intptr_t>(value)));
   }
   // Slow path for Mints and Bigints.
   DARTSCOPE(thread);
   CHECK_CALLBACK_STATE(thread);
-  return Api::NewHandle(isolate, Integer::New(value));
+  return Api::NewHandle(thread, Integer::New(value));
 }
 
 
 DART_EXPORT Dart_Handle Dart_NewIntegerFromUint64(uint64_t value) {
   DARTSCOPE(Thread::Current());
   CHECK_CALLBACK_STATE(T);
-  return Api::NewHandle(I, Integer::NewFromUint64(value));
+  return Api::NewHandle(T, Integer::NewFromUint64(value));
 }
 
 
@@ -2165,7 +2006,7 @@
   DARTSCOPE(Thread::Current());
   CHECK_CALLBACK_STATE(T);
   const String& str_obj = String::Handle(Z, String::New(str));
-  return Api::NewHandle(I, Integer::New(str_obj));
+  return Api::NewHandle(T, Integer::New(str_obj));
 }
 
 
@@ -2238,7 +2079,7 @@
 
 
 static uword BigintAllocate(intptr_t size) {
-  return Api::TopScope(Isolate::Current())->zone()->AllocUnsafe(size);
+  return Api::TopScope(Thread::Current())->zone()->AllocUnsafe(size);
 }
 
 
@@ -2263,7 +2104,7 @@
 DART_EXPORT Dart_Handle Dart_NewDouble(double value) {
   DARTSCOPE(Thread::Current());
   CHECK_CALLBACK_STATE(T);
-  return Api::NewHandle(I, Double::New(value));
+  return Api::NewHandle(T, Double::New(value));
 }
 
 
@@ -2334,7 +2175,7 @@
     RETURN_NULL_ERROR(str);
   }
   CHECK_CALLBACK_STATE(T);
-  return Api::NewHandle(I, String::New(str));
+  return Api::NewHandle(T, String::New(str));
 }
 
 
@@ -2350,7 +2191,7 @@
                          CURRENT_FUNC);
   }
   CHECK_CALLBACK_STATE(T);
-  return Api::NewHandle(I, String::FromUTF8(utf8_array, length));
+  return Api::NewHandle(T, String::FromUTF8(utf8_array, length));
 }
 
 
@@ -2362,7 +2203,7 @@
   }
   CHECK_LENGTH(length, String::kMaxElements);
   CHECK_CALLBACK_STATE(T);
-  return Api::NewHandle(I, String::FromUTF16(utf16_array, length));
+  return Api::NewHandle(T, String::FromUTF16(utf16_array, length));
 }
 
 
@@ -2374,7 +2215,7 @@
   }
   CHECK_LENGTH(length, String::kMaxElements);
   CHECK_CALLBACK_STATE(T);
-  return Api::NewHandle(I, String::FromUTF32(utf32_array, length));
+  return Api::NewHandle(T, String::FromUTF32(utf32_array, length));
 }
 
 
@@ -2389,12 +2230,11 @@
   }
   CHECK_LENGTH(length, String::kMaxElements);
   CHECK_CALLBACK_STATE(T);
-  return Api::NewHandle(I,
-                        String::NewExternal(latin1_array,
-                                            length,
-                                            peer,
-                                            cback,
-                                            SpaceForExternal(I, length)));
+  return Api::NewHandle(T, String::NewExternal(latin1_array,
+                                               length,
+                                               peer,
+                                               cback,
+                                               SpaceForExternal(T, length)));
 }
 
 
@@ -2409,12 +2249,11 @@
   CHECK_LENGTH(length, String::kMaxElements);
   CHECK_CALLBACK_STATE(T);
   intptr_t bytes = length * sizeof(*utf16_array);
-  return Api::NewHandle(I,
-                        String::NewExternal(utf16_array,
-                                            length,
-                                            peer,
-                                            cback,
-                                            SpaceForExternal(I, bytes)));
+  return Api::NewHandle(T, String::NewExternal(utf16_array,
+                                               length,
+                                               peer,
+                                               cback,
+                                               SpaceForExternal(T, bytes)));
 }
 
 
@@ -2429,7 +2268,7 @@
     RETURN_TYPE_ERROR(Z, object, String);
   }
   intptr_t string_length = Utf8::Length(str_obj);
-  char* res = Api::TopScope(I)->zone()->Alloc<char>(string_length + 1);
+  char* res = Api::TopScope(T)->zone()->Alloc<char>(string_length + 1);
   if (res == NULL) {
     return Api::NewError("Unable to allocate memory");
   }
@@ -2456,7 +2295,7 @@
     RETURN_TYPE_ERROR(Z, str, String);
   }
   intptr_t str_len = Utf8::Length(str_obj);
-  *utf8_array = Api::TopScope(I)->zone()->Alloc<uint8_t>(str_len);
+  *utf8_array = Api::TopScope(T)->zone()->Alloc<uint8_t>(str_len);
   if (*utf8_array == NULL) {
     return Api::NewError("Unable to allocate memory");
   }
@@ -2576,7 +2415,7 @@
     }
     return str;
   }
-  return Api::NewHandle(I, str_obj.MakeExternal(array, length, peer, cback));
+  return Api::NewHandle(T, str_obj.MakeExternal(array, length, peer, cback));
 }
 
 
@@ -2610,7 +2449,7 @@
   DARTSCOPE(Thread::Current());
   CHECK_LENGTH(length, Array::kMaxElements);
   CHECK_CALLBACK_STATE(T);
-  return Api::NewHandle(I, Array::New(length));
+  return Api::NewHandle(T, Array::New(length));
 }
 
 
@@ -2684,17 +2523,17 @@
     return Api::NewError("Length of List object is greater than the "
                          "maximum value that 'len' parameter can hold");
   } else if (retval.IsError()) {
-    return Api::NewHandle(I, retval.raw());
+    return Api::NewHandle(T, retval.raw());
   } else {
     return Api::NewError("Length of List object is not an integer");
   }
 }
 
 
-#define GET_LIST_ELEMENT(isolate, type, obj, index)                            \
+#define GET_LIST_ELEMENT(thread, type, obj, index)                             \
   const type& array_obj = type::Cast(obj);                                     \
   if ((index >= 0) && (index < array_obj.Length())) {                          \
-    return Api::NewHandle(isolate, array_obj.At(index));                       \
+    return Api::NewHandle(thread, array_obj.At(index));                        \
   }                                                                            \
   return Api::NewError("Invalid index passed in to access list element");      \
 
@@ -2703,9 +2542,9 @@
   DARTSCOPE(Thread::Current());
   const Object& obj = Object::Handle(Z, Api::UnwrapHandle(list));
   if (obj.IsArray()) {
-    GET_LIST_ELEMENT(I, Array, obj, index);
+    GET_LIST_ELEMENT(T, Array, obj, index);
   } else if (obj.IsGrowableObjectArray()) {
-    GET_LIST_ELEMENT(I, GrowableObjectArray, obj, index);
+    GET_LIST_ELEMENT(T, GrowableObjectArray, obj, index);
   } else if (obj.IsError()) {
     return list;
   } else {
@@ -2713,7 +2552,7 @@
     // Check and handle a dart object that implements the List interface.
     const Instance& instance = Instance::Handle(Z, GetListInstance(Z, obj));
     if (!instance.IsNull()) {
-      return Api::NewHandle(I, Send1Arg(
+      return Api::NewHandle(T, Send1Arg(
           instance,
           Symbols::IndexToken(),
           Instance::Handle(Z, Integer::New(index))));
@@ -2723,11 +2562,11 @@
 }
 
 
-#define GET_LIST_RANGE(isolate, type, obj, offset, length)                     \
+#define GET_LIST_RANGE(thread, type, obj, offset, length)                      \
   const type& array_obj = type::Cast(obj);                                     \
   if ((offset >= 0) && (offset + length <= array_obj.Length())) {              \
     for (intptr_t index = 0; index < length; ++index) {                        \
-      result[index] = Api::NewHandle(isolate, array_obj.At(index + offset));   \
+      result[index] = Api::NewHandle(thread, array_obj.At(index + offset));    \
     }                                                                          \
     return Api::Success();                                                     \
   }                                                                            \
@@ -2744,9 +2583,9 @@
   }
   const Object& obj = Object::Handle(Z, Api::UnwrapHandle(list));
   if (obj.IsArray()) {
-    GET_LIST_RANGE(I, Array, obj, offset, length);
+    GET_LIST_RANGE(T, Array, obj, offset, length);
   } else if (obj.IsGrowableObjectArray()) {
-    GET_LIST_RANGE(I, GrowableObjectArray, obj, offset, length);
+    GET_LIST_RANGE(T, GrowableObjectArray, obj, offset, length);
   } else if (obj.IsError()) {
     return list;
   } else {
@@ -2768,8 +2607,8 @@
         for (intptr_t i = 0; i < length; ++i) {
           index = Integer::New(i);
           args.SetAt(1, index);
-          Dart_Handle value = Api::NewHandle(I,
-              DartEntry::InvokeFunction(function, args));
+          Dart_Handle value = Api::NewHandle(
+              T, DartEntry::InvokeFunction(function, args));
           if (::Dart_IsError(value))
             return value;
           result[i] = value;
@@ -2831,8 +2670,8 @@
         args.SetAt(0, instance);
         args.SetAt(1, index_obj);
         args.SetAt(2, value_obj);
-        return Api::NewHandle(I, DartEntry::InvokeFunction(function,
-                                                                 args));
+        return Api::NewHandle(
+            T, DartEntry::InvokeFunction(function, args));
       }
     }
     return Api::NewError("Object does not implement the 'List' interface");
@@ -2849,7 +2688,6 @@
 
 static RawObject* ThrowArgumentError(const char* exception_message) {
   Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
   Zone* zone = thread->zone();
   // Lookup the class ArgumentError in dart:core.
   const String& lib_url = String::Handle(String::New("dart:core"));
@@ -2898,13 +2736,11 @@
   }
   // Unwind all the API scopes till the exit frame before throwing an
   // exception.
-  ApiState* state = isolate->api_state();
-  ASSERT(state != NULL);
   const Instance* saved_exception;
   {
     NoSafepointScope no_safepoint;
     RawInstance* raw_exception = exception.raw();
-    state->UnwindScopes(thread->top_exit_frame_info());
+    thread->UnwindScopes(thread->top_exit_frame_info());
     saved_exception = &Instance::Handle(raw_exception);
   }
   Exceptions::Throw(thread, *saved_exception);
@@ -2921,8 +2757,8 @@
     for (int i = 0; i < length; i++) {                                         \
       element = array.At(offset + i);                                          \
       if (!element.IsInteger()) {                                              \
-        return Api::NewHandle(I,                                               \
-            ThrowArgumentError("List contains non-int elements"));             \
+        return Api::NewHandle(                                                 \
+            T, ThrowArgumentError("List contains non-int elements"));          \
                                                                                \
       }                                                                        \
       const Integer& integer = Integer::Cast(element);                         \
@@ -3026,7 +2862,7 @@
         args.SetAt(1, intobj);
         result = DartEntry::InvokeFunction(function, args);
         if (result.IsError()) {
-          return Api::NewHandle(I, result.raw());
+          return Api::NewHandle(T, result.raw());
         }
         if (!result.IsInteger()) {
           return Api::NewError("%s expects the argument 'list' to be "
@@ -3115,7 +2951,7 @@
         const Object& result = Object::Handle(Z,
             DartEntry::InvokeFunction(function, args));
         if (result.IsError()) {
-          return Api::NewHandle(I, result.raw());
+          return Api::NewHandle(T, result.raw());
         }
       }
       return Api::Success();
@@ -3137,8 +2973,8 @@
     if (!(key_obj.IsInstance() || key_obj.IsNull())) {
       return Api::NewError("Key is not an instance");
     }
-    return Api::NewHandle(I,
-        Send1Arg(instance, Symbols::IndexToken(), Instance::Cast(key_obj)));
+    return Api::NewHandle(
+        T, Send1Arg(instance, Symbols::IndexToken(), Instance::Cast(key_obj)));
   }
   return Api::NewError("Object does not implement the 'Map' interface");
 }
@@ -3154,7 +2990,7 @@
     if (!(key_obj.IsInstance() || key_obj.IsNull())) {
       return Api::NewError("Key is not an instance");
     }
-    return Api::NewHandle(I, Send1Arg(
+    return Api::NewHandle(T, Send1Arg(
        instance,
        String::Handle(Z, String::New("containsKey")),
        Instance::Cast(key_obj)));
@@ -3172,9 +3008,9 @@
     const Object& iterator = Object::Handle(Send0Arg(
         instance, String::Handle(Z, String::New("get:keys"))));
     if (!iterator.IsInstance()) {
-      return Api::NewHandle(I, iterator.raw());
+      return Api::NewHandle(T, iterator.raw());
     }
-    return Api::NewHandle(I, Send0Arg(
+    return Api::NewHandle(T, Send0Arg(
         Instance::Cast(iterator),
         String::Handle(String::New("toList"))));
   }
@@ -3311,7 +3147,6 @@
 
 static Dart_Handle NewByteData(Thread* thread, intptr_t length) {
   CHECK_LENGTH(length, TypedData::MaxElements(kTypedDataInt8ArrayCid));
-  Isolate* isolate = thread->isolate();
   Zone* zone = thread->zone();
   Object& result = Object::Handle(zone);
   result = GetByteDataConstructor(thread, Symbols::ByteDataDot(), 1);
@@ -3329,22 +3164,21 @@
   // Invoke the constructor and return the new object.
   result = DartEntry::InvokeFunction(factory, args);
   ASSERT(result.IsInstance() || result.IsNull() || result.IsError());
-  return Api::NewHandle(isolate, result.raw());
+  return Api::NewHandle(thread, result.raw());
 }
 
 
-static Dart_Handle NewTypedData(Isolate* isolate,
+static Dart_Handle NewTypedData(Thread* thread,
                                 intptr_t cid,
                                 intptr_t length) {
   CHECK_LENGTH(length, TypedData::MaxElements(cid));
-  return Api::NewHandle(isolate, TypedData::New(cid, length));
+  return Api::NewHandle(thread, TypedData::New(cid, length));
 }
 
 
 static Dart_Handle NewExternalTypedData(
     Thread* thread, intptr_t cid, void* data, intptr_t length) {
   CHECK_LENGTH(length, ExternalTypedData::MaxElements(cid));
-  Isolate* isolate = thread->isolate();
   Zone* zone = thread->zone();
   intptr_t bytes = length * ExternalTypedData::ElementSizeInBytes(cid);
   const ExternalTypedData& result = ExternalTypedData::Handle(
@@ -3352,15 +3186,14 @@
       ExternalTypedData::New(cid,
                              reinterpret_cast<uint8_t*>(data),
                              length,
-                             SpaceForExternal(isolate, bytes)));
-  return Api::NewHandle(isolate, result.raw());
+                             SpaceForExternal(thread, bytes)));
+  return Api::NewHandle(thread, result.raw());
 }
 
 
 static Dart_Handle NewExternalByteData(
     Thread* thread, void* data, intptr_t length) {
   Zone* zone = thread->zone();
-  Isolate* isolate = thread->isolate();
   Dart_Handle ext_data = NewExternalTypedData(
       thread, kExternalTypedDataUint8ArrayCid, data, length);
   if (::Dart_IsError(ext_data)) {
@@ -3390,7 +3223,7 @@
   // Invoke the constructor and return the new object.
   result = DartEntry::InvokeFunction(factory, args);
   ASSERT(result.IsNull() || result.IsInstance() || result.IsError());
-  return Api::NewHandle(isolate, result.raw());
+  return Api::NewHandle(thread, result.raw());
 }
 
 
@@ -3402,29 +3235,29 @@
     case Dart_TypedData_kByteData :
       return NewByteData(T, length);
     case Dart_TypedData_kInt8 :
-      return NewTypedData(I, kTypedDataInt8ArrayCid, length);
+      return NewTypedData(T, kTypedDataInt8ArrayCid, length);
     case Dart_TypedData_kUint8 :
-      return NewTypedData(I, kTypedDataUint8ArrayCid, length);
+      return NewTypedData(T, kTypedDataUint8ArrayCid, length);
     case Dart_TypedData_kUint8Clamped :
-      return NewTypedData(I, kTypedDataUint8ClampedArrayCid, length);
+      return NewTypedData(T, kTypedDataUint8ClampedArrayCid, length);
     case Dart_TypedData_kInt16 :
-      return NewTypedData(I, kTypedDataInt16ArrayCid, length);
+      return NewTypedData(T, kTypedDataInt16ArrayCid, length);
     case Dart_TypedData_kUint16 :
-      return NewTypedData(I, kTypedDataUint16ArrayCid, length);
+      return NewTypedData(T, kTypedDataUint16ArrayCid, length);
     case Dart_TypedData_kInt32 :
-      return NewTypedData(I, kTypedDataInt32ArrayCid, length);
+      return NewTypedData(T, kTypedDataInt32ArrayCid, length);
     case Dart_TypedData_kUint32 :
-      return NewTypedData(I, kTypedDataUint32ArrayCid, length);
+      return NewTypedData(T, kTypedDataUint32ArrayCid, length);
     case Dart_TypedData_kInt64 :
-      return NewTypedData(I, kTypedDataInt64ArrayCid, length);
+      return NewTypedData(T, kTypedDataInt64ArrayCid, length);
     case Dart_TypedData_kUint64 :
-      return NewTypedData(I, kTypedDataUint64ArrayCid, length);
+      return NewTypedData(T, kTypedDataUint64ArrayCid, length);
     case Dart_TypedData_kFloat32 :
-      return NewTypedData(I, kTypedDataFloat32ArrayCid,  length);
+      return NewTypedData(T, kTypedDataFloat32ArrayCid,  length);
     case Dart_TypedData_kFloat64 :
-      return NewTypedData(I, kTypedDataFloat64ArrayCid, length);
+      return NewTypedData(T, kTypedDataFloat64ArrayCid, length);
     case Dart_TypedData_kFloat32x4:
-      return NewTypedData(I, kTypedDataFloat32x4ArrayCid, length);
+      return NewTypedData(T, kTypedDataFloat32x4ArrayCid, length);
     default:
       return Api::NewError("%s expects argument 'type' to be of 'TypedData'",
                            CURRENT_FUNC);
@@ -3447,41 +3280,41 @@
     case Dart_TypedData_kByteData:
       return NewExternalByteData(T, data, length);
     case Dart_TypedData_kInt8:
-      return NewExternalTypedData(T,
-          kExternalTypedDataInt8ArrayCid, data, length);
+      return NewExternalTypedData(
+          T, kExternalTypedDataInt8ArrayCid, data, length);
     case Dart_TypedData_kUint8:
-      return NewExternalTypedData(T,
-          kExternalTypedDataUint8ArrayCid, data, length);
+      return NewExternalTypedData(
+          T, kExternalTypedDataUint8ArrayCid, data, length);
     case Dart_TypedData_kUint8Clamped:
-      return NewExternalTypedData(T,
-          kExternalTypedDataUint8ClampedArrayCid, data, length);
+      return NewExternalTypedData(
+          T, kExternalTypedDataUint8ClampedArrayCid, data, length);
     case Dart_TypedData_kInt16:
-      return NewExternalTypedData(T,
-          kExternalTypedDataInt16ArrayCid, data, length);
+      return NewExternalTypedData(
+          T, kExternalTypedDataInt16ArrayCid, data, length);
     case Dart_TypedData_kUint16:
-      return NewExternalTypedData(T,
-          kExternalTypedDataUint16ArrayCid, data, length);
+      return NewExternalTypedData(
+          T, kExternalTypedDataUint16ArrayCid, data, length);
     case Dart_TypedData_kInt32:
-      return NewExternalTypedData(T,
-          kExternalTypedDataInt32ArrayCid, data, length);
+      return NewExternalTypedData(
+          T, kExternalTypedDataInt32ArrayCid, data, length);
     case Dart_TypedData_kUint32:
-      return NewExternalTypedData(T,
-          kExternalTypedDataUint32ArrayCid, data, length);
+      return NewExternalTypedData(
+          T, kExternalTypedDataUint32ArrayCid, data, length);
     case Dart_TypedData_kInt64:
-      return NewExternalTypedData(T,
-          kExternalTypedDataInt64ArrayCid, data, length);
+      return NewExternalTypedData(
+          T, kExternalTypedDataInt64ArrayCid, data, length);
     case Dart_TypedData_kUint64:
-      return NewExternalTypedData(T,
-          kExternalTypedDataUint64ArrayCid, data, length);
+      return NewExternalTypedData(
+          T, kExternalTypedDataUint64ArrayCid, data, length);
     case Dart_TypedData_kFloat32:
-      return NewExternalTypedData(T,
-          kExternalTypedDataFloat32ArrayCid, data, length);
+      return NewExternalTypedData(
+          T, kExternalTypedDataFloat32ArrayCid, data, length);
     case Dart_TypedData_kFloat64:
-      return NewExternalTypedData(T,
-          kExternalTypedDataFloat64ArrayCid, data, length);
+      return NewExternalTypedData(
+          T, kExternalTypedDataFloat64ArrayCid, data, length);
     case Dart_TypedData_kFloat32x4:
-      return NewExternalTypedData(T,
-          kExternalTypedDataFloat32x4ArrayCid, data, length);
+      return NewExternalTypedData(
+          T, kExternalTypedDataFloat32x4ArrayCid, data, length);
     default:
       return Api::NewError("%s expects argument 'type' to be of"
                            " 'external TypedData'", CURRENT_FUNC);
@@ -3537,7 +3370,7 @@
   // Invoke the factory constructor and return the new object.
   result = DartEntry::InvokeFunction(factory, args);
   ASSERT(result.IsInstance() || result.IsNull() || result.IsError());
-  return Api::NewHandle(I, result.raw());
+  return Api::NewHandle(T, result.raw());
 }
 
 
@@ -3579,6 +3412,7 @@
                                                   void** data,
                                                   intptr_t* len) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   intptr_t class_id = Api::ClassId(object);
   if (!RawObject::IsExternalTypedDataClassId(class_id) &&
       !RawObject::IsTypedDataViewClassId(class_id) &&
@@ -3668,6 +3502,7 @@
 
 DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle object) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   intptr_t class_id = Api::ClassId(object);
   if (!RawObject::IsExternalTypedDataClassId(class_id) &&
       !RawObject::IsTypedDataViewClassId(class_id) &&
@@ -3704,7 +3539,7 @@
   }
   const Instance& instance = Api::UnwrapInstanceHandle(zone, object);
   ASSERT(!instance.IsNull());
-  return Api::NewHandle(isolate, ByteBuffer::Data(instance));
+  return Api::NewHandle(thread, ByteBuffer::Data(instance));
 }
 
 
@@ -3785,11 +3620,6 @@
         CURRENT_FUNC);
   }
   Class& cls = Class::Handle(Z, type_obj.type_class());
-#if defined(DEBUG)
-  if (!cls.is_allocated() && Dart::IsRunningPrecompiledCode()) {
-    return Api::NewError("Precompilation dropped '%s'", cls.ToCString());
-  }
-#endif
   TypeArguments& type_arguments =
       TypeArguments::Handle(Z, type_obj.arguments());
 
@@ -3815,7 +3645,7 @@
                               constr_name,
                               number_of_arguments);
   if (result.IsError()) {
-    return Api::NewHandle(I, result.raw());
+    return Api::NewHandle(T, result.raw());
   }
   ASSERT(result.IsFunction());
   Function& constructor = Function::Handle(Z);
@@ -3828,7 +3658,7 @@
     constructor = constructor.RedirectionTarget();
     if (constructor.IsNull()) {
       ASSERT(redirect_type.IsMalformed());
-      return Api::NewHandle(I, redirect_type.error());
+      return Api::NewHandle(T, redirect_type.error());
     }
 
     if (!redirect_type.IsInstantiated()) {
@@ -3838,7 +3668,7 @@
       redirect_type ^= redirect_type.InstantiateFrom(type_arguments,
                                                      &bound_error);
       if (!bound_error.IsNull()) {
-        return Api::NewHandle(I, bound_error.raw());
+        return Api::NewHandle(T, bound_error.raw());
       }
       redirect_type ^= redirect_type.Canonicalize();
     }
@@ -3849,6 +3679,11 @@
     cls = type_obj.type_class();
   }
   if (constructor.IsGenerativeConstructor()) {
+#if defined(DEBUG)
+    if (!cls.is_allocated() && Dart::IsRunningPrecompiledCode()) {
+      return Api::NewError("Precompilation dropped '%s'", cls.ToCString());
+    }
+#endif
     // Create the new object.
     new_object = Instance::New(cls);
   }
@@ -3877,7 +3712,7 @@
     argument = Api::UnwrapHandle(arguments[i]);
     if (!argument.IsNull() && !argument.IsInstance()) {
       if (argument.IsError()) {
-        return Api::NewHandle(I, argument.raw());
+        return Api::NewHandle(T, argument.raw());
       } else {
         return Api::NewError(
             "%s expects arguments[%d] to be an Instance handle.",
@@ -3890,7 +3725,7 @@
   // Invoke the constructor and return the new object.
   result = DartEntry::InvokeFunction(constructor, args);
   if (result.IsError()) {
-    return Api::NewHandle(I, result.raw());
+    return Api::NewHandle(T, result.raw());
   }
 
   if (constructor.IsGenerativeConstructor()) {
@@ -3899,7 +3734,7 @@
     ASSERT(result.IsNull() || result.IsInstance());
     new_object ^= result.raw();
   }
-  return Api::NewHandle(I, new_object.raw());
+  return Api::NewHandle(T, new_object.raw());
 }
 
 
@@ -3948,9 +3783,9 @@
   const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(T));
   if (!error.IsNull()) {
     // An error occurred, return error object.
-    return Api::NewHandle(I, error.raw());
+    return Api::NewHandle(T, error.raw());
   }
-  return Api::NewHandle(I, AllocateObject(T, cls));
+  return Api::NewHandle(T, AllocateObject(T, cls));
 }
 
 
@@ -3978,7 +3813,7 @@
   const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(T));
   if (!error.IsNull()) {
     // An error occurred, return error object.
-    return Api::NewHandle(I, error.raw());
+    return Api::NewHandle(T, error.raw());
   }
   if (num_native_fields != cls.num_native_fields()) {
     return Api::NewError(
@@ -3987,7 +3822,7 @@
   }
   const Instance& instance = Instance::Handle(Z, AllocateObject(T, cls));
   instance.SetNativeFields(num_native_fields, native_fields);
-  return Api::NewHandle(I, instance.raw());
+  return Api::NewHandle(T, instance.raw());
 }
 
 
@@ -3997,7 +3832,6 @@
                                   int extra_args,
                                   Array* args) {
   Zone* zone = thread->zone();
-  Isolate* isolate = thread->isolate();
   // Check for malformed arguments in the arguments list.
   *args = Array::New(num_args + extra_args);
   Object& arg = Object::Handle(zone);
@@ -4006,7 +3840,7 @@
     if (!arg.IsNull() && !arg.IsInstance()) {
       *args = Array::null();
       if (arg.IsError()) {
-        return Api::NewHandle(isolate, arg.raw());
+        return Api::NewHandle(thread, arg.raw());
       } else {
         return Api::NewError(
             "%s expects arguments[%d] to be an Instance handle.",
@@ -4076,17 +3910,17 @@
     }
     Dart_Handle result;
     Array& args = Array::Handle(Z);
-    result = SetupArguments(T,
-        number_of_arguments, arguments, extra_args, &args);
+    result = SetupArguments(
+        T, number_of_arguments, arguments, extra_args, &args);
     if (!::Dart_IsError(result)) {
       args.SetAt(0, instance);
       args.SetAt(1, Smi::Handle(Z, Smi::New(Function::kCtorPhaseAll)));
       const Object& retval = Object::Handle(Z,
           DartEntry::InvokeFunction(constructor, args));
       if (retval.IsError()) {
-        result = Api::NewHandle(I, retval.raw());
+        result = Api::NewHandle(T, retval.raw());
       } else {
-        result = Api::NewHandle(I, instance.raw());
+        result = Api::NewHandle(T, instance.raw());
       }
     }
     return result;
@@ -4142,7 +3976,7 @@
     // Setup args and check for malformed arguments in the arguments list.
     result = SetupArguments(T, number_of_arguments, arguments, 0, &args);
     if (!::Dart_IsError(result)) {
-      result = Api::NewHandle(I, DartEntry::InvokeFunction(function, args));
+      result = Api::NewHandle(T, DartEntry::InvokeFunction(function, args));
     }
     return result;
   } else if (obj.IsNull() || obj.IsInstance()) {
@@ -4166,7 +4000,7 @@
         args.SetAt(0, instance);
         const Array& args_descriptor =
           Array::Handle(Z, ArgumentsDescriptor::New(args.Length()));
-        result = Api::NewHandle(I,
+        result = Api::NewHandle(T,
                                 DartEntry::InvokeNoSuchMethod(instance,
                                                               function_name,
                                                               args,
@@ -4178,7 +4012,7 @@
     result = SetupArguments(T, number_of_arguments, arguments, 1, &args);
     if (!::Dart_IsError(result)) {
       args.SetAt(0, instance);
-      result = Api::NewHandle(I, DartEntry::InvokeFunction(function, args));
+      result = Api::NewHandle(T, DartEntry::InvokeFunction(function, args));
     }
     return result;
   } else if (obj.IsLibrary()) {
@@ -4213,7 +4047,7 @@
     // Setup args and check for malformed arguments in the arguments list.
     result = SetupArguments(T, number_of_arguments, arguments, 0, &args);
     if (!::Dart_IsError(result)) {
-      result = Api::NewHandle(I, DartEntry::InvokeFunction(function, args));
+      result = Api::NewHandle(T, DartEntry::InvokeFunction(function, args));
     }
     return result;
   } else {
@@ -4251,7 +4085,7 @@
     args.SetAt(i + 1, obj);
   }
   // Now try to invoke the closure.
-  return Api::NewHandle(I, DartEntry::InvokeClosure(args));
+  return Api::NewHandle(T, DartEntry::InvokeClosure(args));
 }
 
 
@@ -4289,10 +4123,10 @@
 
     if (!getter.IsNull()) {
       // Invoke the getter and return the result.
-      return Api::NewHandle(I,
-          DartEntry::InvokeFunction(getter, Object::empty_array()));
+      return Api::NewHandle(
+          T, DartEntry::InvokeFunction(getter, Object::empty_array()));
     } else if (!field.IsNull()) {
-      return Api::NewHandle(I, field.StaticValue());
+      return Api::NewHandle(T, field.StaticValue());
     } else {
       return Api::NewError("%s: did not find static field '%s'.",
                            CURRENT_FUNC, field_name.ToCString());
@@ -4320,13 +4154,12 @@
     if (getter.IsNull()) {
       const Array& args_descriptor =
           Array::Handle(Z, ArgumentsDescriptor::New(args.Length()));
-      return Api::NewHandle(I,
-                            DartEntry::InvokeNoSuchMethod(instance,
-                                                          getter_name,
-                                                          args,
-                                                          args_descriptor));
+      return Api::NewHandle(T, DartEntry::InvokeNoSuchMethod(instance,
+                                                             getter_name,
+                                                             args,
+                                                             args_descriptor));
     }
-    return Api::NewHandle(I, DartEntry::InvokeFunction(getter, args));
+    return Api::NewHandle(T, DartEntry::InvokeFunction(getter, args));
 
   } else if (obj.IsLibrary()) {
     // To access a top-level we may need to use the Field or the
@@ -4355,11 +4188,11 @@
 
     if (!getter.IsNull()) {
       // Invoke the getter and return the result.
-      return Api::NewHandle(I,
-          DartEntry::InvokeFunction(getter, Object::empty_array()));
+      return Api::NewHandle(
+          T, DartEntry::InvokeFunction(getter, Object::empty_array()));
     }
     if (!field.IsNull()) {
-      return Api::NewHandle(I, field.StaticValue());
+      return Api::NewHandle(T, field.StaticValue());
     }
     return Api::NewError("%s: did not find top-level variable '%s'.",
                          CURRENT_FUNC, field_name.ToCString());
@@ -4424,7 +4257,7 @@
       const Object& result = Object::Handle(Z,
           DartEntry::InvokeFunction(setter, args));
       if (result.IsError()) {
-        return Api::NewHandle(I, result.raw());
+        return Api::NewHandle(T, result.raw());
       } else {
         return Api::Success();
       }
@@ -4469,12 +4302,12 @@
     if (setter.IsNull()) {
       const Array& args_descriptor =
           Array::Handle(Z, ArgumentsDescriptor::New(args.Length()));
-      return Api::NewHandle(I, DartEntry::InvokeNoSuchMethod(instance,
+      return Api::NewHandle(T, DartEntry::InvokeNoSuchMethod(instance,
                                                              setter_name,
                                                              args,
                                                              args_descriptor));
     }
-    return Api::NewHandle(I, DartEntry::InvokeFunction(setter, args));
+    return Api::NewHandle(T, DartEntry::InvokeFunction(setter, args));
 
   } else if (obj.IsLibrary()) {
     // To access a top-level we may need to use the Field or the
@@ -4502,7 +4335,7 @@
       const Object& result =
           Object::Handle(Z, DartEntry::InvokeFunction(setter, args));
       if (result.IsError()) {
-        return Api::NewHandle(I, result.raw());
+        return Api::NewHandle(T, result.raw());
       }
       return Api::Success();
     }
@@ -4548,14 +4381,12 @@
 
   // Unwind all the API scopes till the exit frame before throwing an
   // exception.
-  ApiState* state = isolate->api_state();
-  ASSERT(state != NULL);
   const Instance* saved_exception;
   {
     NoSafepointScope no_safepoint;
     RawInstance* raw_exception =
         Api::UnwrapInstanceHandle(zone, exception).raw();
-    state->UnwindScopes(thread->top_exit_frame_info());
+    thread->UnwindScopes(thread->top_exit_frame_info());
     saved_exception = &Instance::Handle(raw_exception);
   }
   Exceptions::Throw(thread, *saved_exception);
@@ -4588,8 +4419,6 @@
 
   // Unwind all the API scopes till the exit frame before throwing an
   // exception.
-  ApiState* state = isolate->api_state();
-  ASSERT(state != NULL);
   const Instance* saved_exception;
   const Stacktrace* saved_stacktrace;
   {
@@ -4598,7 +4427,7 @@
         Api::UnwrapInstanceHandle(zone, exception).raw();
     RawStacktrace* raw_stacktrace =
         Api::UnwrapStacktraceHandle(zone, stacktrace).raw();
-    state->UnwindScopes(thread->top_exit_frame_info());
+    thread->UnwindScopes(thread->top_exit_frame_info());
     saved_exception = &Instance::Handle(raw_exception);
     saved_stacktrace = &Stacktrace::Handle(raw_stacktrace);
   }
@@ -4634,7 +4463,7 @@
     return Api::NewError(
         "Unable to create native wrapper class : already exists");
   }
-  return Api::NewHandle(I, cls.RareType());
+  return Api::NewHandle(T, cls.RareType());
 }
 
 
@@ -4814,12 +4643,10 @@
       }
 
       case Dart_NativeArgument_kInstance: {
-        Isolate* isolate = arguments->thread()->isolate();
-        ASSERT(isolate == Isolate::Current());
-        ASSERT(isolate->api_state() &&
-               isolate->api_state()->top_scope() != NULL);
-        native_value->as_instance =
-            Api::NewHandle(isolate, arguments->NativeArgAt(arg_index));
+        ASSERT(arguments->thread() == Thread::Current());
+        ASSERT(arguments->thread()->api_top_scope() != NULL);
+        native_value->as_instance = Api::NewHandle(
+            arguments->thread(), arguments->NativeArgAt(arg_index));
         break;
       }
 
@@ -4841,7 +4668,7 @@
         "%s: argument 'index' out of range. Expected 0..%d but saw %d.",
         CURRENT_FUNC, arguments->NativeArgCount() - 1, index);
   }
-  return Api::NewHandle(arguments->thread()->isolate(),
+  return Api::NewHandle(arguments->thread(),
                         arguments->NativeArgAt(index));
 }
 
@@ -4978,8 +4805,7 @@
   Isolate* isolate = arguments->thread()->isolate();
   ASSERT(isolate == Isolate::Current());
   ASSERT(isolate->api_state() != NULL &&
-         (isolate->api_state()->IsValidWeakPersistentHandle(rval) ||
-          isolate->api_state()->IsValidPrologueWeakPersistentHandle(rval)));
+         (isolate->api_state()->IsValidWeakPersistentHandle(rval)));
 #endif
   Api::SetWeakHandleReturnValue(arguments, rval);
 }
@@ -4992,7 +4818,7 @@
   Dart_EnvironmentCallback callback = isolate->environment_callback();
   String& result = String::Handle(thread->zone());
   if (callback != NULL) {
-    Dart_Handle response = callback(Api::NewHandle(isolate, name.raw()));
+    Dart_Handle response = callback(Api::NewHandle(thread, name.raw()));
     if (::Dart_IsString(response)) {
       result ^= Api::UnwrapHandle(response);
     } else if (::Dart_IsError(response)) {
@@ -5086,9 +4912,9 @@
   const Error& error =
       Error::Handle(thread->zone(), Compiler::Compile(lib, script));
   if (error.IsNull()) {
-    *result = Api::NewHandle(thread->isolate(), lib.raw());
+    *result = Api::NewHandle(thread, lib.raw());
   } else {
-    *result = Api::NewHandle(thread->isolate(), error.raw());
+    *result = Api::NewHandle(thread, error.raw());
     // Compilation errors are not Dart instances, so just mark the library
     // as having failed to load without providing an error instance.
     lib.SetLoadError(Object::null_instance());
@@ -5101,6 +4927,7 @@
                                         intptr_t line_offset,
                                         intptr_t column_offset) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   const String& url_str = Api::UnwrapStringHandle(Z, url);
   if (url_str.IsNull()) {
     RETURN_TYPE_ERROR(Z, url, String);
@@ -5145,6 +4972,7 @@
 DART_EXPORT Dart_Handle Dart_LoadScriptFromSnapshot(const uint8_t* buffer,
                                                     intptr_t buffer_len) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   StackZone zone(T);
   if (buffer == NULL) {
     RETURN_NULL_ERROR(buffer);
@@ -5174,19 +5002,20 @@
   ScriptSnapshotReader reader(snapshot->content(), snapshot->length(), T);
   const Object& tmp = Object::Handle(Z, reader.ReadScriptSnapshot());
   if (tmp.IsError()) {
-    return Api::NewHandle(I, tmp.raw());
+    return Api::NewHandle(T, tmp.raw());
   }
   library ^= tmp.raw();
   library.set_debuggable(true);
   I->object_store()->set_root_library(library);
-  return Api::NewHandle(I, library.raw());
+  return Api::NewHandle(T, library.raw());
 }
 
 
 DART_EXPORT Dart_Handle Dart_RootLibrary() {
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   CHECK_ISOLATE(isolate);
-  return Api::NewHandle(isolate, isolate->object_store()->root_library());
+  return Api::NewHandle(thread, isolate->object_store()->root_library());
 }
 
 
@@ -5220,7 +5049,7 @@
     return Api::NewError("Class '%s' not found in library '%s'.",
                          cls_name.ToCString(), lib_name.ToCString());
   }
-  return Api::NewHandle(I, cls.RareType());
+  return Api::NewHandle(T, cls.RareType());
 }
 
 
@@ -5255,7 +5084,7 @@
       return Api::NewError("Invalid number of type arguments specified, "
                            "got %" Pd " expected 0", number_of_type_arguments);
     }
-    return Api::NewHandle(I, Type::NewNonParameterizedType(cls));
+    return Api::NewHandle(T, Type::NewNonParameterizedType(cls));
   }
   intptr_t num_expected_type_arguments = cls.NumTypeParameters();
   TypeArguments& type_args_obj = TypeArguments::Handle();
@@ -5293,7 +5122,7 @@
       Type::New(cls, type_args_obj, Scanner::kNoSourcePos));
   instantiated_type ^= ClassFinalizer::FinalizeType(
       cls, instantiated_type, ClassFinalizer::kCanonicalize);
-  return Api::NewHandle(I, instantiated_type.raw());
+  return Api::NewHandle(T, instantiated_type.raw());
 }
 
 
@@ -5305,7 +5134,7 @@
   }
   const String& url = String::Handle(Z, lib.url());
   ASSERT(!url.IsNull());
-  return Api::NewHandle(I, url.raw());
+  return Api::NewHandle(T, url.raw());
 }
 
 
@@ -5320,7 +5149,7 @@
     return Api::NewError("%s: library '%s' not found.",
                          CURRENT_FUNC, url_str.ToCString());
   } else {
-    return Api::NewHandle(I, library.raw());
+    return Api::NewHandle(T, library.raw());
   }
 }
 
@@ -5328,6 +5157,7 @@
 DART_EXPORT Dart_Handle Dart_LibraryHandleError(Dart_Handle library_in,
                                                 Dart_Handle error_in) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
 
   const Library& lib = Api::UnwrapLibraryHandle(Z, library_in);
   if (lib.IsNull()) {
@@ -5357,6 +5187,7 @@
                                          intptr_t line_offset,
                                          intptr_t column_offset) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   const String& url_str = Api::UnwrapStringHandle(Z, url);
   if (url_str.IsNull()) {
     RETURN_TYPE_ERROR(Z, url, String);
@@ -5403,7 +5234,7 @@
   // If this is the dart:_builtin library, register it with the VM.
   if (url_str.Equals("dart:_builtin")) {
     I->object_store()->set_builtin_library(library);
-    Dart_Handle state = Api::CheckAndFinalizePendingClasses(I);
+    Dart_Handle state = Api::CheckAndFinalizePendingClasses(T);
     if (::Dart_IsError(state)) {
       return state;
     }
@@ -5416,6 +5247,7 @@
                                                   Dart_Handle import,
                                                   Dart_Handle prefix) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   const Library& library_vm = Api::UnwrapLibraryHandle(Z, library);
   if (library_vm.IsNull()) {
     RETURN_TYPE_ERROR(Z, library, Library);
@@ -5460,6 +5292,7 @@
                                         intptr_t line_offset,
                                         intptr_t column_offset) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   const Library& lib = Api::UnwrapLibraryHandle(Z, library);
   if (lib.IsNull()) {
     RETURN_TYPE_ERROR(Z, library, Library);
@@ -5498,6 +5331,7 @@
                                               Dart_Handle url,
                                               Dart_Handle patch_source) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   const Library& lib = Api::UnwrapLibraryHandle(Z, library);
   if (lib.IsNull()) {
     RETURN_TYPE_ERROR(Z, library, Library);
@@ -5527,6 +5361,7 @@
 // futures of loadLibrary calls (deferred library loading).
 DART_EXPORT Dart_Handle Dart_FinalizeLoading(bool complete_futures) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   CHECK_CALLBACK_STATE(T);
 
   I->DoneLoading();
@@ -5535,7 +5370,7 @@
   // invoing of _completeDeferredLoads) into Isolate::DoneLoading().
 
   // Finalize all classes if needed.
-  Dart_Handle state = Api::CheckAndFinalizePendingClasses(I);
+  Dart_Handle state = Api::CheckAndFinalizePendingClasses(T);
   if (::Dart_IsError(state)) {
     return state;
   }
@@ -5567,7 +5402,7 @@
         Object::Handle(Z, DartEntry::InvokeFunction(function, args));
     I->object_store()->clear_pending_deferred_loads();
     if (res.IsError() || res.IsUnhandledException()) {
-      return Api::NewHandle(I, res.raw());
+      return Api::NewHandle(T, res.raw());
     }
   }
   return Api::Success();
@@ -5704,6 +5539,7 @@
                                                   const uint8_t* bytes,
                                                   intptr_t bytes_length) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   if (stream_id == NULL) {
     RETURN_NULL_ERROR(stream_id);
   }
@@ -5899,6 +5735,10 @@
 
 DART_EXPORT bool Dart_GlobalTimelineGetTrace(Dart_StreamConsumer consumer,
                                              void* user_data) {
+  // To support various embedders, it must be possible to call this function
+  // from a thread for which we have not entered an Isolate and set up a Thread
+  // TLS object. Therefore, a Zone may not be available, a StackZone cannot be
+  // created, and no ZoneAllocated objects can be allocated.
   if (consumer == NULL) {
     return false;
   }
@@ -5907,8 +5747,6 @@
     // Nothing has been recorded.
     return false;
   }
-  Thread* T = Thread::Current();
-  StackZone zone(T);
   Timeline::ReclaimCachedBlocksFromThreads();
   JSONStream js;
   TimelineEventFilter filter;
@@ -6031,7 +5869,7 @@
   if (!FLAG_precompilation) {
     return Dart_NewApiError("Flag --precompilation was not specified.");
   }
-  Dart_Handle result = Api::CheckAndFinalizePendingClasses(I);
+  Dart_Handle result = Api::CheckAndFinalizePendingClasses(T);
   if (::Dart_IsError(result)) {
     return result;
   }
@@ -6039,7 +5877,7 @@
   const Error& error = Error::Handle(Precompiler::CompileAll(entry_points,
                                                              reset_fields));
   if (!error.IsNull()) {
-    return Api::NewHandle(I, error.raw());
+    return Api::NewHandle(T, error.raw());
   }
   return Api::Success();
 }
@@ -6054,6 +5892,7 @@
     intptr_t* instructions_snapshot_size) {
   ASSERT(FLAG_load_deferred_eagerly);
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   if (I->compilation_allowed()) {
     return Dart_NewApiError("Isolate is not precompiled. "
                             "Did you forget to call Dart_Precompile?");
@@ -6077,7 +5916,7 @@
     RETURN_NULL_ERROR(instructions_snapshot_size);
   }
   // Finalize all classes if needed.
-  Dart_Handle state = Api::CheckAndFinalizePendingClasses(I);
+  Dart_Handle state = Api::CheckAndFinalizePendingClasses(T);
   if (::Dart_IsError(state)) {
     return state;
   }
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 76b3aba..ccd8fa1 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -56,13 +56,12 @@
   } while (0)
 
 // Checks that the current isolate is not NULL and that it has an API scope.
-#define CHECK_ISOLATE_SCOPE(isolate)                                           \
+#define CHECK_API_SCOPE(thread)                                                \
   do {                                                                         \
-    Isolate* tmp = (isolate);                                                  \
-    CHECK_ISOLATE(tmp);                                                        \
-    ApiState* state = tmp->api_state();                                        \
-    ASSERT(state);                                                             \
-    if (state->top_scope() == NULL) {                                          \
+    Thread* tmpT = (thread);                                                   \
+    Isolate* tmpI = tmpT->isolate();                                           \
+    CHECK_ISOLATE(tmpI);                                                       \
+    if (tmpT->api_top_scope() == NULL) {                                       \
       FATAL1("%s expects to find a current scope. Did you forget to call "     \
            "Dart_EnterScope?", CURRENT_FUNC);                                  \
     }                                                                          \
@@ -70,8 +69,7 @@
 
 #define DARTSCOPE(thread)                                                      \
   Thread* T = (thread);                                                        \
-  Isolate* I = T->isolate();                                                   \
-  CHECK_ISOLATE_SCOPE(I);                                                      \
+  CHECK_API_SCOPE(T);                                                          \
   HANDLESCOPE(T);
 
 
@@ -124,7 +122,7 @@
   };
 
   // Creates a new local handle.
-  static Dart_Handle NewHandle(Isolate* isolate, RawObject* raw);
+  static Dart_Handle NewHandle(Thread* thread, RawObject* raw);
 
   // Unwraps the raw object from the handle.
   static RawObject* UnwrapHandle(Dart_Handle object);
@@ -146,7 +144,7 @@
   // Returns an Error handle if isolate is in an inconsistent state
   // or there was an error while finalizing classes.
   // Returns a Success handle when no error condition exists.
-  static Dart_Handle CheckAndFinalizePendingClasses(Isolate *isolate);
+  static Dart_Handle CheckAndFinalizePendingClasses(Thread *thread);
 
   // Casts the internal Isolate* type to the external Dart_Isolate type.
   static Dart_Isolate CastIsolate(Isolate* isolate);
@@ -216,7 +214,7 @@
   }
 
   // Retrieves the top ApiLocalScope.
-  static ApiLocalScope* TopScope(Isolate* isolate);
+  static ApiLocalScope* TopScope(Thread* thread);
 
   // Performs one-time initialization needed by the API.
   static void InitOnce();
@@ -273,7 +271,7 @@
                                             const String& name);
 
  private:
-  static Dart_Handle InitNewHandle(Isolate* isolate, RawObject* raw);
+  static Dart_Handle InitNewHandle(Thread* thread, RawObject* raw);
 
   // Thread local key used by the API. Currently holds the current
   // ApiNativeScope if any.
@@ -286,23 +284,6 @@
   friend class ApiNativeScope;
 };
 
-class IsolateSaver {
- public:
-  explicit IsolateSaver(Isolate* current_isolate)
-      : saved_isolate_(current_isolate) {
-  }
-  ~IsolateSaver() {
-    // TODO(koda): Audit users; they should know whether they're in an isolate.
-    if (saved_isolate_ != NULL) {
-      Thread::EnterIsolate(saved_isolate_);
-    }
-  }
- private:
-  Isolate* saved_isolate_;
-
-  DISALLOW_COPY_AND_ASSIGN(IsolateSaver);
-};
-
 // Start a scope in which no Dart API call backs are allowed.
 #define START_NO_CALLBACK_SCOPE(thread)                                        \
   thread->IncrementNoCallbackScopeDepth()
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 3f5056f..1499f37 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -8,7 +8,7 @@
 #include "include/dart_native_api.h"
 #include "include/dart_tools_api.h"
 #include "platform/assert.h"
-#include "platform/json.h"
+#include "platform/text_buffer.h"
 #include "platform/utils.h"
 #include "vm/class_finalizer.h"
 #include "vm/dart_api_impl.h"
@@ -397,7 +397,6 @@
 
 
 TEST_CASE(ErrorHandleTypes) {
-  Isolate* isolate = Isolate::Current();
   const String& compile_message = String::Handle(String::New("CompileError"));
   const String& fatal_message = String::Handle(String::New("FatalError"));
 
@@ -406,9 +405,9 @@
   Dart_Handle exception_error =
       Dart_NewUnhandledExceptionError(NewString("ExceptionError"));
   Dart_Handle compile_error =
-      Api::NewHandle(isolate, LanguageError::New(compile_message));
+      Api::NewHandle(thread, LanguageError::New(compile_message));
   Dart_Handle fatal_error =
-      Api::NewHandle(isolate, UnwindError::New(fatal_message));
+      Api::NewHandle(thread, UnwindError::New(fatal_message));
 
   EXPECT_VALID(not_error);
   EXPECT(Dart_IsError(api_error));
@@ -450,13 +449,12 @@
 
 
 TEST_CASE(UnhandleExceptionError) {
-  Isolate* isolate = Isolate::Current();
   const char* exception_cstr = "";
 
   // Test with an API Error.
   const char* kApiError = "Api Error Exception Test.";
   Dart_Handle api_error = Api::NewHandle(
-      isolate,
+      thread,
       ApiError::New(String::Handle(String::New(kApiError))));
   Dart_Handle exception_error = Dart_NewUnhandledExceptionError(api_error);
   EXPECT(!Dart_IsApiError(exception_error));
@@ -471,7 +469,7 @@
   const String& compile_message =
       String::Handle(String::New(kCompileError));
   Dart_Handle compile_error =
-      Api::NewHandle(isolate, LanguageError::New(compile_message));
+      Api::NewHandle(thread, LanguageError::New(compile_message));
   exception_error = Dart_NewUnhandledExceptionError(compile_error);
   EXPECT(!Dart_IsApiError(exception_error));
   EXPECT(Dart_IsUnhandledExceptionError(exception_error));
@@ -484,14 +482,14 @@
   const String& fatal_message =
       String::Handle(String::New("FatalError Exception Test."));
   Dart_Handle fatal_error =
-      Api::NewHandle(isolate, UnwindError::New(fatal_message));
+      Api::NewHandle(thread, UnwindError::New(fatal_message));
   exception_error = Dart_NewUnhandledExceptionError(fatal_error);
   EXPECT(Dart_IsError(exception_error));
   EXPECT(!Dart_IsUnhandledExceptionError(exception_error));
 
   // Test with a Regular object.
   const char* kRegularString = "Regular String Exception Test.";
-  Dart_Handle obj = Api::NewHandle(isolate, String::New(kRegularString));
+  Dart_Handle obj = Api::NewHandle(thread, String::New(kRegularString));
   exception_error = Dart_NewUnhandledExceptionError(obj);
   EXPECT(!Dart_IsApiError(exception_error));
   EXPECT(Dart_IsUnhandledExceptionError(exception_error));
@@ -617,7 +615,7 @@
 
   // Non-instance objects.
   {
-    DARTSCOPE(Thread::Current());
+    DARTSCOPE(thread);
     Dart_Handle lib1 = Dart_LookupLibrary(dart_core);
     Dart_Handle lib2 = Dart_LookupLibrary(dart_mirrors);
 
@@ -662,7 +660,7 @@
 
   // Non-instance objects.
   {
-    DARTSCOPE(Thread::Current());
+    DARTSCOPE(thread);
     Dart_Handle lib1 = Dart_LookupLibrary(dart_core);
     Dart_Handle lib2 = Dart_LookupLibrary(dart_mirrors);
 
@@ -1226,7 +1224,7 @@
         NULL);
     EXPECT_VALID(small16);
     {
-      DARTSCOPE(Thread::Current());
+      DARTSCOPE(thread);
       String& handle = String::Handle();
       handle ^= Api::UnwrapHandle(big8);
       EXPECT(handle.IsOld());
@@ -1260,7 +1258,7 @@
         kSmallLength);
     EXPECT_VALID(small);
     {
-      DARTSCOPE(Thread::Current());
+      DARTSCOPE(thread);
       ExternalTypedData& handle = ExternalTypedData::Handle();
       handle ^= Api::UnwrapHandle(big);
       EXPECT(handle.IsOld());
@@ -2379,23 +2377,21 @@
 UNIT_TEST_CASE(EnterExitScope) {
   TestIsolateScope __test_isolate__;
 
-  Isolate* isolate = Isolate::Current();
-  EXPECT(isolate != NULL);
-  ApiState* state = isolate->api_state();
-  EXPECT(state != NULL);
-  ApiLocalScope* scope = state->top_scope();
+  Thread* thread = Thread::Current();
+  EXPECT(thread != NULL);
+  ApiLocalScope* scope = thread->api_top_scope();
   Dart_EnterScope();
   {
-    EXPECT(state->top_scope() != NULL);
+    EXPECT(thread->api_top_scope() != NULL);
     DARTSCOPE(Thread::Current());
     const String& str1 = String::Handle(String::New("Test String"));
-    Dart_Handle ref = Api::NewHandle(isolate, str1.raw());
+    Dart_Handle ref = Api::NewHandle(thread, str1.raw());
     String& str2 = String::Handle();
     str2 ^= Api::UnwrapHandle(ref);
     EXPECT(str1.Equals(str2));
   }
   Dart_ExitScope();
-  EXPECT(scope == state->top_scope());
+  EXPECT(scope == thread->api_top_scope());
 }
 
 
@@ -2409,17 +2405,17 @@
   EXPECT(isolate != NULL);
   ApiState* state = isolate->api_state();
   EXPECT(state != NULL);
-  ApiLocalScope* scope = state->top_scope();
+  ApiLocalScope* scope = thread->api_top_scope();
   Dart_PersistentHandle handles[2000];
   Dart_EnterScope();
   {
     DARTSCOPE(Thread::Current());
-    Dart_Handle ref1 = Api::NewHandle(isolate, String::New(kTestString1));
+    Dart_Handle ref1 = Api::NewHandle(thread, String::New(kTestString1));
     for (int i = 0; i < 1000; i++) {
       handles[i] = Dart_NewPersistentHandle(ref1);
     }
     Dart_EnterScope();
-    Dart_Handle ref2 = Api::NewHandle(isolate, String::New(kTestString2));
+    Dart_Handle ref2 = Api::NewHandle(thread, String::New(kTestString2));
     for (int i = 1000; i < 2000; i++) {
       handles[i] = Dart_NewPersistentHandle(ref2);
     }
@@ -2460,7 +2456,7 @@
       EXPECT(str.Equals(kTestString2));
     }
   }
-  EXPECT(scope == state->top_scope());
+  EXPECT(scope == thread->api_top_scope());
   EXPECT_EQ(2001, state->CountPersistentHandles());
   Dart_ShutdownIsolate();
 }
@@ -2502,22 +2498,22 @@
   const char* kTestString2 = "Test String2";
   TestIsolateScope __test_isolate__;
 
-  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(Thread::Current());
+  Isolate* isolate = T->isolate();
   EXPECT(isolate != NULL);
   ApiState* state = isolate->api_state();
   EXPECT(state != NULL);
-  DARTSCOPE(Thread::Current());
   String& str = String::Handle();
 
   // Start with a known persistent handle.
-  Dart_Handle ref1 = Api::NewHandle(isolate, String::New(kTestString1));
+  Dart_Handle ref1 = Api::NewHandle(T, String::New(kTestString1));
   Dart_PersistentHandle obj = Dart_NewPersistentHandle(ref1);
   EXPECT(state->IsValidPersistentHandle(obj));
   str ^= PersistentHandle::Cast(obj)->raw();
   EXPECT(str.Equals(kTestString1));
 
   // Now create another local handle and assign it to the persistent handle.
-  Dart_Handle ref2 = Api::NewHandle(isolate, String::New(kTestString2));
+  Dart_Handle ref2 = Api::NewHandle(T, String::New(kTestString2));
   Dart_SetPersistentHandle(obj, ref2);
   str ^= PersistentHandle::Cast(obj)->raw();
   EXPECT(str.Equals(kTestString2));
@@ -2585,9 +2581,8 @@
     // Create an object in old space.
     Dart_Handle old_ref;
     {
-      Isolate* isolate = Isolate::Current();
       DARTSCOPE(Thread::Current());
-      old_ref = Api::NewHandle(isolate, String::New("old string", Heap::kOld));
+      old_ref = Api::NewHandle(thread, String::New("old string", Heap::kOld));
       EXPECT_VALID(old_ref);
     }
 
@@ -2753,7 +2748,6 @@
                                          kWeak1ExternalSize,
                                          NopCallback);
     EXPECT_VALID(AsHandle(weak1));
-    EXPECT(!Dart_IsPrologueWeakPersistentHandle(weak1));
     Dart_ExitScope();
   }
   Dart_PersistentHandle strong_ref = NULL;
@@ -2788,33 +2782,6 @@
 }
 
 
-TEST_CASE(PrologueWeakPersistentHandleExternalAllocationSize) {
-  Heap* heap = Isolate::Current()->heap();
-  EXPECT(heap->ExternalInWords(Heap::kNew) == 0);
-  EXPECT(heap->ExternalInWords(Heap::kOld) == 0);
-  Dart_WeakPersistentHandle pwph = NULL;
-  static const intptr_t kWeakExternalSize = 1 * KB;
-  {
-    Dart_EnterScope();
-    Dart_Handle obj = NewString("a string");
-    EXPECT_VALID(obj);
-    pwph = Dart_NewPrologueWeakPersistentHandle(
-        obj, NULL, kWeakExternalSize, NopCallback);
-    EXPECT_VALID(AsHandle(pwph));
-    Dart_ExitScope();
-  }
-  EXPECT(heap->ExternalInWords(Heap::kNew) == kWeakExternalSize / kWordSize);
-  EXPECT(heap->ExternalInWords(Heap::kOld) == 0);
-  // Promoting the string should transfer the external size to old.
-  GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
-  GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
-  EXPECT(heap->ExternalInWords(Heap::kNew) == 0);
-  EXPECT(heap->ExternalInWords(Heap::kOld) == kWeakExternalSize / kWordSize);
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  EXPECT(heap->ExternalInWords(Heap::kOld) == 0);
-}
-
-
 TEST_CASE(WeakPersistentHandleExternalAllocationSizeNewspaceGC) {
   Dart_Isolate isolate = reinterpret_cast<Dart_Isolate>(Isolate::Current());
   Heap* heap = Isolate::Current()->heap();
@@ -2860,14 +2827,14 @@
   // Check that external allocation in old space can trigger GC.
   Isolate* isolate = Isolate::Current();
   Dart_EnterScope();
-  Dart_Handle live = Api::NewHandle(isolate, String::New("live", Heap::kOld));
+  Dart_Handle live = Api::NewHandle(thread, String::New("live", Heap::kOld));
   EXPECT_VALID(live);
   Dart_WeakPersistentHandle weak = NULL;
   EXPECT_EQ(0, isolate->heap()->ExternalInWords(Heap::kOld));
   const intptr_t kSmallExternalSize = 1 * KB;
   {
     Dart_EnterScope();
-    Dart_Handle dead = Api::NewHandle(isolate, String::New("dead", Heap::kOld));
+    Dart_Handle dead = Api::NewHandle(thread, String::New("dead", Heap::kOld));
     EXPECT_VALID(dead);
     weak = Dart_NewWeakPersistentHandle(dead,
                                         NULL,
@@ -2927,402 +2894,6 @@
 static Dart_WeakPersistentHandle weak1 = NULL;
 static Dart_WeakPersistentHandle weak2 = NULL;
 static Dart_WeakPersistentHandle weak3 = NULL;
-static Dart_WeakPersistentHandle weak4 = NULL;
-
-
-static void ObjectGroupsCallback(void* isolate_callback_data,
-                                 Dart_WeakPersistentHandle handle,
-                                 void* peer) {
-  if (handle == weak1) {
-    weak1 = NULL;
-  } else if (handle == weak2) {
-    weak2 = NULL;
-  } else if (handle == weak3) {
-    weak3 = NULL;
-  } else if (handle == weak4) {
-    weak4 = NULL;
-  }
-}
-
-
-TEST_CASE(ObjectGroups) {
-  Dart_PersistentHandle strong = NULL;
-  Dart_WeakPersistentHandle strong_weak = NULL;
-
-  Dart_EnterScope();
-  {
-    Isolate* isolate = Isolate::Current();
-    DARTSCOPE(Thread::Current());
-
-    Dart_Handle local = Api::NewHandle(
-        isolate, String::New("strongly reachable", Heap::kOld));
-    strong = Dart_NewPersistentHandle(local);
-    strong_weak = Dart_NewWeakPersistentHandle(local, NULL, 0, NopCallback);
-    EXPECT_VALID(AsHandle(strong));
-    EXPECT(!Dart_IsNull(AsHandle(strong)));
-
-    weak1 = Dart_NewWeakPersistentHandle(
-        Api::NewHandle(isolate, String::New("weakly reachable 1", Heap::kOld)),
-        NULL, 0, ObjectGroupsCallback);
-    EXPECT_VALID(AsHandle(weak1));
-    EXPECT(!Dart_IsNull(AsHandle(weak1)));
-
-    weak2 = Dart_NewWeakPersistentHandle(
-        Api::NewHandle(isolate, String::New("weakly reachable 2", Heap::kOld)),
-        NULL, 0, ObjectGroupsCallback);
-    EXPECT_VALID(AsHandle(weak2));
-    EXPECT(!Dart_IsNull(AsHandle(weak2)));
-
-    weak3 = Dart_NewWeakPersistentHandle(
-        Api::NewHandle(isolate, String::New("weakly reachable 3", Heap::kOld)),
-        NULL, 0, ObjectGroupsCallback);
-    EXPECT_VALID(AsHandle(weak3));
-    EXPECT(!Dart_IsNull(AsHandle(weak3)));
-
-    weak4 = Dart_NewWeakPersistentHandle(
-        Api::NewHandle(isolate, String::New("weakly reachable 4", Heap::kOld)),
-        NULL, 0, ObjectGroupsCallback);
-    EXPECT_VALID(AsHandle(weak4));
-    EXPECT(!Dart_IsNull(AsHandle(weak4)));
-  }
-  Dart_ExitScope();
-
-  {
-    Dart_EnterScope();
-    EXPECT_VALID(AsHandle(strong));
-    EXPECT_VALID(AsHandle(weak1));
-    EXPECT_VALID(AsHandle(weak2));
-    EXPECT_VALID(AsHandle(weak3));
-    EXPECT_VALID(AsHandle(weak4));
-    Dart_ExitScope();
-  }
-
-  GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
-
-  {
-    Dart_EnterScope();
-    // New space collection should not affect old space objects
-    EXPECT(!Dart_IsNull(AsHandle(weak1)));
-    EXPECT(!Dart_IsNull(AsHandle(weak2)));
-    EXPECT(!Dart_IsNull(AsHandle(weak3)));
-    EXPECT(!Dart_IsNull(AsHandle(weak4)));
-    Dart_ExitScope();
-  }
-
-  {
-    Dart_WeakReferenceSetBuilder builder = Dart_NewWeakReferenceSetBuilder();
-    EXPECT_NOTNULL(builder);
-
-    Dart_WeakReferenceSet set = Dart_NewWeakReferenceSet(builder, weak1, weak1);
-    EXPECT_NOTNULL(set);
-    EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, strong_weak, strong_weak));
-
-    set = Dart_NewWeakReferenceSet(builder, weak2, weak2);
-    EXPECT_NOTNULL(set);
-    EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, weak1, weak1));
-
-    set = Dart_NewWeakReferenceSet(builder, weak3, weak3);
-    EXPECT_NOTNULL(set);
-    EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, weak2, weak2));
-
-    set = Dart_NewWeakReferenceSet(builder, weak4, weak4);
-    EXPECT_NOTNULL(set);
-    EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, weak3, weak3));
-
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  }
-
-  {
-    Dart_EnterScope();
-    // All weak references should be preserved.
-    EXPECT(!Dart_IsNull(AsHandle(strong_weak)));
-    EXPECT(!Dart_IsNull(AsHandle(weak1)));
-    EXPECT(!Dart_IsNull(AsHandle(weak2)));
-    EXPECT(!Dart_IsNull(AsHandle(weak3)));
-    EXPECT(!Dart_IsNull(AsHandle(weak4)));
-    Dart_ExitScope();
-  }
-
-  {
-    Dart_EnterScope();
-    Dart_WeakReferenceSetBuilder builder = Dart_NewWeakReferenceSetBuilder();
-    EXPECT_NOTNULL(builder);
-
-    Dart_WeakReferenceSet set = Dart_NewWeakReferenceSet(builder, weak1, weak1);
-    EXPECT_NOTNULL(set);
-    EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, strong_weak, strong_weak));
-
-    set = Dart_NewWeakReferenceSet(builder, weak2, weak2);
-    EXPECT_NOTNULL(set);
-    EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, weak1, weak1));
-
-    set = Dart_NewWeakReferenceSet(builder, weak2, weak2);
-    EXPECT_NOTNULL(set);
-
-    // Strong reference to weak3 to retain weak3 and weak4.
-    Dart_PersistentHandle weak3_strong_ref =
-        Dart_NewPersistentHandle(AsHandle(weak3));
-    EXPECT_VALID(AsHandle(weak3_strong_ref));
-
-    set = Dart_NewWeakReferenceSet(builder, weak4, weak4);
-    EXPECT_NOTNULL(set);
-    EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, weak3, weak3));
-
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-
-    // Delete strong reference to weak3.
-    Dart_DeletePersistentHandle(weak3_strong_ref);
-    Dart_ExitScope();
-  }
-
-  {
-    Dart_EnterScope();
-    // All weak references should be preserved.
-    EXPECT(!Dart_IsNull(AsHandle(strong_weak)));
-    EXPECT(!Dart_IsNull(AsHandle(weak1)));
-    EXPECT(!Dart_IsNull(AsHandle(weak2)));
-    EXPECT(!Dart_IsNull(AsHandle(weak3)));
-    EXPECT(!Dart_IsNull(AsHandle(weak4)));
-    Dart_ExitScope();
-  }
-
-  {
-    Dart_WeakReferenceSetBuilder builder = Dart_NewWeakReferenceSetBuilder();
-    EXPECT_NOTNULL(builder);
-
-    Dart_WeakReferenceSet set = Dart_NewWeakReferenceSet(builder, weak1, weak1);
-    EXPECT_NOTNULL(set);
-    EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, strong_weak, strong_weak));
-
-    set = Dart_NewWeakReferenceSet(builder, weak2, weak2);
-    EXPECT_NOTNULL(set);
-    EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, weak1, weak1));
-
-    set = Dart_NewWeakReferenceSet(builder, weak2, weak2);
-    EXPECT_NOTNULL(set);
-
-    set = Dart_NewWeakReferenceSet(builder, weak4, weak4);
-    EXPECT_NOTNULL(set);
-    EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, weak3, weak3));
-
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  }
-
-  {
-    Dart_EnterScope();
-    // Only weak1 and weak2 should be preserved.
-    EXPECT(!Dart_IsNull(AsHandle(strong_weak)));
-    EXPECT(!Dart_IsNull(AsHandle(weak1)));
-    EXPECT(!Dart_IsNull(AsHandle(weak2)));
-    EXPECT(weak3 == NULL);
-    EXPECT(weak4 == NULL);
-    Dart_ExitScope();
-  }
-
-  {
-    Dart_WeakReferenceSetBuilder builder = Dart_NewWeakReferenceSetBuilder();
-    EXPECT_NOTNULL(builder);
-
-    Dart_WeakPersistentHandle lweak3 = Dart_NewWeakPersistentHandle(
-        Dart_Null(), NULL, 0, NopCallback);
-
-    Dart_WeakReferenceSet set = Dart_NewWeakReferenceSet(builder, weak1, weak1);
-    EXPECT_NOTNULL(set);
-    EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, strong_weak, strong_weak));
-
-    // lweak3 is unreferenced so weak2 is unreferenced and should be cleared
-    set = Dart_NewWeakReferenceSet(builder, weak2, weak2);
-    EXPECT_NOTNULL(set);
-    EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, lweak3, lweak3));
-
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  }
-
-  {
-    Dart_EnterScope();
-    // Only weak1 should be preserved, weak3 should not preserve weak2.
-    EXPECT(!Dart_IsNull(AsHandle(strong_weak)));
-    EXPECT(!Dart_IsNull(AsHandle(weak1)));
-    EXPECT(weak2 == NULL);
-    EXPECT(weak3 == NULL);  // was cleared, should remain cleared
-    EXPECT(weak4 == NULL);  // was cleared, should remain cleared
-    Dart_ExitScope();
-  }
-
-  {
-    Dart_WeakReferenceSetBuilder builder = Dart_NewWeakReferenceSetBuilder();
-    EXPECT_NOTNULL(builder);
-
-    Dart_WeakPersistentHandle lweak2 = Dart_NewWeakPersistentHandle(
-        Dart_Null(), NULL, 0, NopCallback);
-    Dart_WeakPersistentHandle lweak3 = Dart_NewWeakPersistentHandle(
-        Dart_Null(), NULL, 0, NopCallback);
-    Dart_WeakPersistentHandle lweak4 = Dart_NewWeakPersistentHandle(
-        Dart_Null(), NULL, 0, NopCallback);
-    // lweak{2,3,4} are cleared and should have no effect on weak1
-    Dart_WeakReferenceSet set =
-        Dart_NewWeakReferenceSet(builder, strong_weak, strong_weak);
-    EXPECT_NOTNULL(set);
-    EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, lweak2, lweak2));
-    EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, lweak3, lweak3));
-    EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, lweak4, lweak4));
-
-    // weak1 is weakly reachable and should be cleared
-    set = Dart_NewWeakReferenceSet(builder, weak1, weak1);
-    EXPECT_NOTNULL(set);
-
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  }
-
-  {
-    Dart_EnterScope();
-    // All weak references should now be cleared.
-    EXPECT(!Dart_IsNull(AsHandle(strong_weak)));
-    EXPECT(weak1 == NULL);
-    EXPECT(weak2 == NULL);
-    EXPECT(weak3 == NULL);
-    EXPECT(weak4 == NULL);
-    Dart_ExitScope();
-  }
-}
-
-
-TEST_CASE(DuplicateWeakReferenceSetEntries) {
-  Isolate* isolate = Isolate::Current();
-  Dart_PersistentHandle strong = NULL;
-  Dart_WeakPersistentHandle weak = NULL;  // A weak handle to strong.
-
-  Dart_EnterScope();
-  {
-    DARTSCOPE(Thread::Current());
-
-    // Strong handle to keep the reference set alive.
-    Dart_Handle local = Api::NewHandle(isolate, String::New("string"));
-    strong = Dart_NewPersistentHandle(local);
-    EXPECT_VALID(AsHandle(strong));
-    EXPECT(!Dart_IsNull(AsHandle(strong)));
-    // Corresponding weak handle to use as key and duplicated value.
-    weak = Dart_NewWeakPersistentHandle(local, NULL, 0, NopCallback);
-    EXPECT_VALID(AsHandle(weak));
-    EXPECT(!Dart_IsNull(AsHandle(weak)));
-  }
-  Dart_ExitScope();
-
-  {
-    Dart_EnterScope();
-    // Create the weak reference set.
-    Dart_WeakReferenceSetBuilder builder = Dart_NewWeakReferenceSetBuilder();
-    EXPECT_NOTNULL(builder);
-    // Register the key and the first copy of the value.
-    Dart_WeakReferenceSet set = Dart_NewWeakReferenceSet(builder, weak, weak);
-    EXPECT_NOTNULL(set);
-    // Add the second copy of the value.
-    Dart_Handle result = Dart_AppendValueToWeakReferenceSet(set, weak);
-    EXPECT_VALID(result);
-
-    // Trigger GC to ensure that we can visit duplicate entries in weak
-    // reference sets.
-    isolate->heap()->CollectGarbage(Heap::kNew);
-    Dart_ExitScope();
-  }
-}
-
-
-static Dart_WeakPersistentHandle old_pwph = NULL;
-static Dart_WeakPersistentHandle new_pwph = NULL;
-
-
-static void PrologueWeakHandleCallback(void* isolate_callback_data,
-                                       Dart_WeakPersistentHandle handle,
-                                       void* peer) {
-  if (handle == old_pwph) {
-    old_pwph = NULL;
-  } else if (handle == new_pwph) {
-    new_pwph = NULL;
-  }
-}
-
-
-TEST_CASE(PrologueWeakPersistentHandles) {
-  Dart_EnterScope();
-  {
-    Isolate* isolate = Isolate::Current();
-    DARTSCOPE(Thread::Current());
-    new_pwph = Dart_NewPrologueWeakPersistentHandle(
-        Api::NewHandle(isolate,
-                       String::New("new space prologue weak", Heap::kNew)),
-        NULL, 0, PrologueWeakHandleCallback);
-    EXPECT_VALID(AsHandle(new_pwph));
-    EXPECT(!Dart_IsNull(AsHandle(new_pwph)));
-    old_pwph = Dart_NewPrologueWeakPersistentHandle(
-        Api::NewHandle(isolate,
-                       String::New("old space prologue weak", Heap::kOld)),
-        NULL, 0, PrologueWeakHandleCallback);
-    EXPECT_VALID(AsHandle(old_pwph));
-    EXPECT(!Dart_IsNull(AsHandle(old_pwph)));
-  }
-  Dart_ExitScope();
-
-  {
-    Dart_EnterScope();
-    EXPECT_VALID(AsHandle(new_pwph));
-    EXPECT(!Dart_IsNull(AsHandle(new_pwph)));
-    EXPECT(Dart_IsPrologueWeakPersistentHandle(new_pwph));
-    EXPECT_VALID(AsHandle(old_pwph));
-    EXPECT(!Dart_IsNull(AsHandle(old_pwph)));
-    EXPECT(Dart_IsPrologueWeakPersistentHandle(old_pwph));
-    Dart_ExitScope();
-  }
-
-  // Garbage collect new space without invoking API callbacks.
-  GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
-
-  {
-    Dart_EnterScope();
-    // Both prologue weak handles should be preserved.
-    EXPECT(!Dart_IsNull(AsHandle(new_pwph)));
-    EXPECT(!Dart_IsNull(AsHandle(old_pwph)));
-    Dart_ExitScope();
-  }
-
-  // Garbage collect old space without invoking API callbacks.
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld,
-                                             Heap::kIgnoreApiCallbacks,
-                                             Heap::kGCTestCase);
-
-  {
-    Dart_EnterScope();
-    // Both prologue weak handles should be preserved.
-    EXPECT(!Dart_IsNull(AsHandle(new_pwph)));
-    EXPECT(!Dart_IsNull(AsHandle(old_pwph)));
-    Dart_ExitScope();
-  }
-
-  // Garbage collect new space invoking API callbacks.
-  GCTestHelper::CollectNewSpace(Heap::kInvokeApiCallbacks);
-
-  {
-    Dart_EnterScope();
-    // The prologue weak handle with a new space referent should now be
-    // cleared.  The old space referent should be preserved.
-    EXPECT(new_pwph == NULL);
-    EXPECT(!Dart_IsNull(AsHandle(old_pwph)));
-    Dart_ExitScope();
-  }
-
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld,
-                                             Heap::kInvokeApiCallbacks,
-                                             Heap::kGCTestCase);
-
-  {
-    Dart_EnterScope();
-    // The prologue weak handle with an old space referent should now be
-    // cleared.  The new space referent should remain cleared.
-    EXPECT(new_pwph == NULL);
-    EXPECT(old_pwph == NULL);
-    Dart_ExitScope();
-  }
-}
 
 
 static void ImplicitReferencesCallback(void* isolate_callback_data,
@@ -3344,11 +2915,10 @@
 
   Dart_EnterScope();
   {
-    Isolate* isolate = Isolate::Current();
     DARTSCOPE(Thread::Current());
 
     Dart_Handle local = Api::NewHandle(
-        isolate, String::New("strongly reachable", Heap::kOld));
+        thread, String::New("strongly reachable", Heap::kOld));
     strong = Dart_NewPersistentHandle(local);
     strong_weak = Dart_NewWeakPersistentHandle(local, NULL, 0, NopCallback);
 
@@ -3359,19 +2929,19 @@
     EXPECT(Dart_IdentityEquals(AsHandle(strong), AsHandle(strong_weak)))
 
     weak1 = Dart_NewWeakPersistentHandle(
-        Api::NewHandle(isolate, String::New("weakly reachable 1", Heap::kOld)),
+        Api::NewHandle(thread, String::New("weakly reachable 1", Heap::kOld)),
         NULL, 0, ImplicitReferencesCallback);
     EXPECT(!Dart_IsNull(AsHandle(weak1)));
     EXPECT_VALID(AsHandle(weak1));
 
     weak2 = Dart_NewWeakPersistentHandle(
-        Api::NewHandle(isolate, String::New("weakly reachable 2", Heap::kOld)),
+        Api::NewHandle(thread, String::New("weakly reachable 2", Heap::kOld)),
         NULL, 0, ImplicitReferencesCallback);
     EXPECT(!Dart_IsNull(AsHandle(weak2)));
     EXPECT_VALID(AsHandle(weak2));
 
     weak3 = Dart_NewWeakPersistentHandle(
-        Api::NewHandle(isolate, String::New("weakly reachable 3", Heap::kOld)),
+        Api::NewHandle(thread, String::New("weakly reachable 3", Heap::kOld)),
         NULL, 0, ImplicitReferencesCallback);
     EXPECT(!Dart_IsNull(AsHandle(weak3)));
     EXPECT_VALID(AsHandle(weak3));
@@ -3398,53 +2968,6 @@
     EXPECT(!Dart_IsNull(AsHandle(weak3)));
     Dart_ExitScope();
   }
-
-  // A strongly referenced key should preserve all the values.
-  {
-    Dart_WeakReferenceSetBuilder builder = Dart_NewWeakReferenceSetBuilder();
-    EXPECT_NOTNULL(builder);
-
-    Dart_WeakReferenceSet set =
-        Dart_NewWeakReferenceSet(builder, strong_weak, 0);
-    EXPECT_NOTNULL(set);
-    EXPECT_VALID(Dart_AppendValueToWeakReferenceSet(set, weak1));
-    EXPECT_VALID(Dart_AppendValueToWeakReferenceSet(set, weak2));
-    EXPECT_VALID(Dart_AppendValueToWeakReferenceSet(set, weak3));
-
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  }
-
-  {
-    Dart_EnterScope();
-    // All weak references should be preserved.
-    EXPECT_VALID(AsHandle(strong_weak));
-    EXPECT(!Dart_IsNull(AsHandle(weak1)));
-    EXPECT(!Dart_IsNull(AsHandle(weak2)));
-    EXPECT(!Dart_IsNull(AsHandle(weak3)));
-    Dart_ExitScope();
-  }
-
-  // Key membership does not imply a strong reference.
-  {
-    Dart_WeakReferenceSetBuilder builder = Dart_NewWeakReferenceSetBuilder();
-    EXPECT_NOTNULL(builder);
-
-    Dart_WeakReferenceSet set =
-        Dart_NewWeakReferenceSet(builder, strong_weak, weak1);
-    EXPECT_NOTNULL(set);
-    EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, weak3, weak2));
-
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  }
-
-  {
-    Dart_EnterScope();
-    // All weak references except weak3 should be preserved.
-    EXPECT(!Dart_IsNull(AsHandle(weak1)));
-    EXPECT(!Dart_IsNull(AsHandle(weak2)));
-    EXPECT(weak3 == NULL);
-    Dart_ExitScope();
-  }
 }
 
 
@@ -3455,11 +2978,10 @@
 
   Dart_EnterScope();
   {
-    Isolate* isolate = Isolate::Current();
     DARTSCOPE(Thread::Current());
 
     Dart_Handle local = Api::NewHandle(
-        isolate, String::New("strongly reachable", Heap::kOld));
+        thread, String::New("strongly reachable", Heap::kOld));
     strong = Dart_NewPersistentHandle(local);
     strong_weak = Dart_NewWeakPersistentHandle(local, NULL, 0, NopCallback);
 
@@ -3470,19 +2992,19 @@
     EXPECT(Dart_IdentityEquals(AsHandle(strong), AsHandle(strong_weak)))
 
     weak1 = Dart_NewWeakPersistentHandle(
-        Api::NewHandle(isolate, String::New("weakly reachable 1", Heap::kNew)),
+        Api::NewHandle(thread, String::New("weakly reachable 1", Heap::kNew)),
         NULL, 0, ImplicitReferencesCallback);
     EXPECT(!Dart_IsNull(AsHandle(weak1)));
     EXPECT_VALID(AsHandle(weak1));
 
     weak2 = Dart_NewWeakPersistentHandle(
-        Api::NewHandle(isolate, String::New("weakly reachable 2", Heap::kNew)),
+        Api::NewHandle(thread, String::New("weakly reachable 2", Heap::kNew)),
         NULL, 0, ImplicitReferencesCallback);
     EXPECT(!Dart_IsNull(AsHandle(weak2)));
     EXPECT_VALID(AsHandle(weak2));
 
     weak3 = Dart_NewWeakPersistentHandle(
-        Api::NewHandle(isolate, String::New("weakly reachable 3", Heap::kNew)),
+        Api::NewHandle(thread, String::New("weakly reachable 3", Heap::kNew)),
         NULL, 0, ImplicitReferencesCallback);
     EXPECT(!Dart_IsNull(AsHandle(weak3)));
     EXPECT_VALID(AsHandle(weak3));
@@ -3508,41 +3030,6 @@
     EXPECT(!Dart_IsNull(AsHandle(weak3)));
     Dart_ExitScope();
   }
-
-  // A strongly referenced key should preserve all the values.
-  {
-    Dart_WeakReferenceSetBuilder builder = Dart_NewWeakReferenceSetBuilder();
-    EXPECT_NOTNULL(builder);
-
-    Dart_WeakReferenceSet set =
-        Dart_NewWeakReferenceSet(builder, strong_weak, 0);
-    EXPECT_NOTNULL(set);
-    EXPECT_VALID(Dart_AppendValueToWeakReferenceSet(set, weak1));
-    EXPECT_VALID(Dart_AppendValueToWeakReferenceSet(set, weak2));
-    EXPECT_VALID(Dart_AppendValueToWeakReferenceSet(set, weak3));
-
-    GCTestHelper::CollectNewSpace(Heap::kInvokeApiCallbacks);
-  }
-
-  {
-    Dart_EnterScope();
-    // All weak references should be preserved.
-    EXPECT(!Dart_IsNull(AsHandle(weak1)));
-    EXPECT(!Dart_IsNull(AsHandle(weak2)));
-    EXPECT(!Dart_IsNull(AsHandle(weak3)));
-    Dart_ExitScope();
-  }
-
-  GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
-
-  {
-    Dart_EnterScope();
-    // No weak references should be preserved.
-    EXPECT(weak1 == NULL);
-    EXPECT(weak2 == NULL);
-    EXPECT(weak3 == NULL);
-    Dart_ExitScope();
-  }
 }
 
 
@@ -3715,9 +3202,7 @@
   Thread* thread = Thread::Current();
   Isolate* isolate = thread->isolate();
   EXPECT(isolate != NULL);
-  ApiState* state = isolate->api_state();
-  EXPECT(state != NULL);
-  ApiLocalScope* scope = state->top_scope();
+  ApiLocalScope* scope = thread->api_top_scope();
   Dart_Handle handles[300];
   {
     StackZone zone(thread);
@@ -3727,9 +3212,9 @@
     // Start a new scope and allocate some local handles.
     Dart_EnterScope();
     for (int i = 0; i < 100; i++) {
-      handles[i] = Api::NewHandle(isolate, Smi::New(i));
+      handles[i] = Api::NewHandle(thread, Smi::New(i));
     }
-    EXPECT_EQ(100, state->CountLocalHandles());
+    EXPECT_EQ(100, thread->CountLocalHandles());
     for (int i = 0; i < 100; i++) {
       val ^= Api::UnwrapHandle(handles[i]);
       EXPECT_EQ(i, val.Value());
@@ -3738,9 +3223,9 @@
     {
       Dart_EnterScope();
       for (int i = 100; i < 200; i++) {
-        handles[i] = Api::NewHandle(isolate, Smi::New(i));
+        handles[i] = Api::NewHandle(thread, Smi::New(i));
       }
-      EXPECT_EQ(200, state->CountLocalHandles());
+      EXPECT_EQ(200, thread->CountLocalHandles());
       for (int i = 100; i < 200; i++) {
         val ^= Api::UnwrapHandle(handles[i]);
         EXPECT_EQ(i, val.Value());
@@ -3750,25 +3235,25 @@
       {
         Dart_EnterScope();
         for (int i = 200; i < 300; i++) {
-          handles[i] = Api::NewHandle(isolate, Smi::New(i));
+          handles[i] = Api::NewHandle(thread, Smi::New(i));
         }
-        EXPECT_EQ(300, state->CountLocalHandles());
+        EXPECT_EQ(300, thread->CountLocalHandles());
         for (int i = 200; i < 300; i++) {
           val ^= Api::UnwrapHandle(handles[i]);
           EXPECT_EQ(i, val.Value());
         }
-        EXPECT_EQ(300, state->CountLocalHandles());
+        EXPECT_EQ(300, thread->CountLocalHandles());
         VERIFY_ON_TRANSITION;
         Dart_ExitScope();
       }
-      EXPECT_EQ(200, state->CountLocalHandles());
+      EXPECT_EQ(200, thread->CountLocalHandles());
       Dart_ExitScope();
     }
-    EXPECT_EQ(100, state->CountLocalHandles());
+    EXPECT_EQ(100, thread->CountLocalHandles());
     Dart_ExitScope();
   }
-  EXPECT_EQ(0, state->CountLocalHandles());
-  EXPECT(scope == state->top_scope());
+  EXPECT_EQ(0, thread->CountLocalHandles());
+  EXPECT(scope == thread->api_top_scope());
   Dart_ShutdownIsolate();
 }
 
@@ -3778,25 +3263,23 @@
 // exits.
 UNIT_TEST_CASE(LocalZoneMemory) {
   TestCase::CreateTestIsolate();
-  Isolate* isolate = Isolate::Current();
-  EXPECT(isolate != NULL);
-  ApiState* state = isolate->api_state();
-  EXPECT(state != NULL);
-  ApiLocalScope* scope = state->top_scope();
+  Thread* thread = Thread::Current();
+  EXPECT(thread != NULL);
+  ApiLocalScope* scope = thread->api_top_scope();
   {
     // Start a new scope and allocate some memory.
     Dart_EnterScope();
     for (int i = 0; i < 100; i++) {
       Dart_ScopeAllocate(16);
     }
-    EXPECT_EQ(1600, state->ZoneSizeInBytes());
+    EXPECT_EQ(1600, thread->ZoneSizeInBytes());
     // Start another scope and allocate some more memory.
     {
       Dart_EnterScope();
       for (int i = 0; i < 100; i++) {
         Dart_ScopeAllocate(16);
       }
-      EXPECT_EQ(3200, state->ZoneSizeInBytes());
+      EXPECT_EQ(3200, thread->ZoneSizeInBytes());
       {
         // Start another scope and allocate some more memory.
         {
@@ -3804,18 +3287,18 @@
           for (int i = 0; i < 200; i++) {
             Dart_ScopeAllocate(16);
           }
-          EXPECT_EQ(6400, state->ZoneSizeInBytes());
+          EXPECT_EQ(6400, thread->ZoneSizeInBytes());
           Dart_ExitScope();
         }
       }
-      EXPECT_EQ(3200, state->ZoneSizeInBytes());
+      EXPECT_EQ(3200, thread->ZoneSizeInBytes());
       Dart_ExitScope();
     }
-    EXPECT_EQ(1600, state->ZoneSizeInBytes());
+    EXPECT_EQ(1600, thread->ZoneSizeInBytes());
     Dart_ExitScope();
   }
-  EXPECT_EQ(0, state->ZoneSizeInBytes());
-  EXPECT(scope == state->top_scope());
+  EXPECT_EQ(0, thread->ZoneSizeInBytes());
+  EXPECT(scope == thread->api_top_scope());
   Dart_ShutdownIsolate();
 }
 
@@ -5344,7 +4827,7 @@
   Thread* thread = Thread::Current();
   const Library& library_obj = Api::UnwrapLibraryHandle(thread->zone(), lib);
   const String& name = String::Handle(String::New(str));
-  return Api::NewHandle(thread->isolate(), library_obj.PrivateName(name));
+  return Api::NewHandle(thread, library_obj.PrivateName(name));
 }
 
 
@@ -5755,11 +5238,7 @@
   const char* kScriptChars =
       "int test() native \"ThrowException_native\";";
   Dart_Handle result;
-  Isolate* isolate = Isolate::Current();
-  EXPECT(isolate != NULL);
-  ApiState* state = isolate->api_state();
-  EXPECT(state != NULL);
-  intptr_t size = state->ZoneSizeInBytes();
+  intptr_t size = thread->ZoneSizeInBytes();
   Dart_EnterScope();  // Start a Dart API scope for invoking API functions.
 
   // Load up a test script which extends the native wrapper class.
@@ -5778,7 +5257,7 @@
   EXPECT(Dart_ErrorHasException(result));
 
   Dart_ExitScope();  // Exit the Dart API scope.
-  EXPECT_EQ(size, state->ZoneSizeInBytes());
+  EXPECT_EQ(size, thread->ZoneSizeInBytes());
 }
 
 
@@ -7598,24 +7077,15 @@
   const char* kScriptChars =
       "import 'builtin';\n"
       "import 'dart:isolate';\n"
-      "void entry(message) {\n"
-      "  var data = message[0];\n"
-      "  var replyTo = message[1];\n"
-      "  if (data) {\n"
-      "    throw new Exception('MakeChildExit');\n"
-      "  } else {\n"
-      "    replyTo.send('hello');\n"
-      "  }\n"
-      "}\n"
-      "\n"
-      "void main(exc_child, exc_parent) {\n"
-      "  var receivePort = new RawReceivePort();\n"
-      "  Isolate.spawn(entry, [exc_child, receivePort.sendPort]);\n"
-      "  receivePort.handler = (message) {\n"
-      "    receivePort.close();\n"
-      "    if (message != 'hello') throw new Exception('ShouldNotHappen');\n"
-      "    if (exc_parent) throw new Exception('MakeParentExit');\n"
+      "void main(shouldThrowException) {\n"
+      "  var rp = new RawReceivePort();\n"
+      "  rp.handler = (msg) {\n"
+      "    rp.close();\n"
+      "    if (shouldThrowException) {\n"
+      "      throw new Exception('ExceptionFromTimer');\n"
+      "    }\n"
       "  };\n"
+      "  rp.sendPort.send(1);\n"
       "}\n";
 
   if (Dart_CurrentIsolate() != NULL) {
@@ -7643,28 +7113,10 @@
 }
 
 
-// The error string from the last unhandled exception. This value is only
-// valid until the next Dart_ExitScope().
-static char* last_exception = NULL;
-
-
-static void RunLoopUnhandledExceptionCallback(Dart_Handle exception) {
-  Dart_Handle error_string = Dart_ToString(exception);
-  EXPECT_VALID(error_string);
-  const char* error_text;
-  Dart_Handle result = Dart_StringToCString(error_string, &error_text);
-  // Duplicate the string since error text is freed when callback is finished.
-  last_exception = strdup(error_text);
-  EXPECT_VALID(result);
-}
-
-
 // Common code for RunLoop_Success/RunLoop_Failure.
-static void RunLoopTest(bool throw_exception_child,
-                        bool throw_exception_parent) {
+static void RunLoopTest(bool throw_exception) {
   Dart_IsolateCreateCallback saved = Isolate::CreateCallback();
   Isolate::SetCreateCallback(RunLoopTestCallback);
-  Isolate::SetUnhandledExceptionCallback(RunLoopUnhandledExceptionCallback);
   Dart_Isolate isolate = RunLoopTestCallback(
       NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
@@ -7674,29 +7126,15 @@
   EXPECT_VALID(lib);
 
   Dart_Handle result;
-  Dart_Handle args[2];
-  args[0] = (throw_exception_child ? Dart_True() : Dart_False());
-  args[1] = (throw_exception_parent ? Dart_True() : Dart_False());
-  result = Dart_Invoke(lib, NewString("main"), 2, args);
+  Dart_Handle args[1];
+  args[0] = (throw_exception ? Dart_True() : Dart_False());
+  result = Dart_Invoke(lib, NewString("main"), 1, args);
   EXPECT_VALID(result);
-  if (throw_exception_child) {
-    // TODO(tball): fix race-condition
-    // EXPECT_NOTNULL(last_exception);
-    // EXPECT_STREQ("UnhandledException", last_exception);
+  result = Dart_RunLoop();
+  if (throw_exception) {
+    EXPECT_ERROR(result, "Exception: ExceptionFromTimer");
   } else {
-    result = Dart_RunLoop();
-    if (throw_exception_parent) {
-      EXPECT_ERROR(result, "Exception: MakeParentExit");
-      EXPECT_NOTNULL(last_exception);
-      EXPECT_STREQ("UnhandledException", last_exception);
-    } else {
-      EXPECT_VALID(result);
-      EXPECT(last_exception == NULL);
-    }
-  }
-  if (last_exception != NULL) {
-    free(last_exception);
-    last_exception = NULL;
+    EXPECT_VALID(result);
   }
 
   Dart_ExitScope();
@@ -7707,18 +7145,12 @@
 
 
 UNIT_TEST_CASE(RunLoop_Success) {
-  RunLoopTest(false, false);
+  RunLoopTest(false);
 }
 
 
-// This test exits the vm.  Listed as FAIL in vm.status.
-UNIT_TEST_CASE(RunLoop_ExceptionChild) {
-  RunLoopTest(true, false);
-}
-
-
-UNIT_TEST_CASE(RunLoop_ExceptionParent) {
-  RunLoopTest(false, true);
+UNIT_TEST_CASE(RunLoop_Exception) {
+  RunLoopTest(true);
 }
 
 
@@ -7805,81 +7237,6 @@
 }
 
 
-// This callback handles isolate interrupts for the IsolateInterrupt
-// test.  It ignores the first two interrupts and throws an exception
-// on the third interrupt.
-const int kInterruptCount = 10;
-static int interrupt_count = 0;
-static bool IsolateInterruptTestCallback() {
-  OS::Print(" ========== Interrupt callback called #%d\n", interrupt_count + 1);
-  {
-    MonitorLocker ml(sync);
-    interrupt_count++;
-    ml.Notify();
-  }
-  if (interrupt_count == kInterruptCount) {
-    Dart_EnterScope();
-    Dart_Handle lib = Dart_LookupLibrary(NewString(TestCase::url()));
-    EXPECT_VALID(lib);
-    Dart_Handle exc = NewString("foo");
-    EXPECT_VALID(exc);
-    Dart_Handle result = Dart_ThrowException(exc);
-    EXPECT_VALID(result);
-    UNREACHABLE();  // Dart_ThrowException only returns if it gets an error.
-    return false;
-  }
-  ASSERT(interrupt_count < kInterruptCount);
-  return true;
-}
-
-
-TEST_CASE(IsolateInterrupt) {
-  Dart_IsolateInterruptCallback saved = Isolate::InterruptCallback();
-  Isolate::SetInterruptCallback(IsolateInterruptTestCallback);
-
-  sync = new Monitor();
-  int result = OSThread::Start(BusyLoop_start, 0);
-  EXPECT_EQ(0, result);
-
-  {
-    MonitorLocker ml(sync);
-    // Wait for the other isolate to enter main.
-    while (!main_entered) {
-      ml.Wait();
-    }
-  }
-
-  // Send a number of interrupts to the other isolate. All but the
-  // last allow execution to continue. The last causes an exception in
-  // the isolate.
-  for (int i = 0; i < kInterruptCount; i++) {
-    // Space out the interrupts a bit.
-    OS::Sleep(i + 1);
-    Dart_InterruptIsolate(shared_isolate);
-    {
-      MonitorLocker ml(sync);
-      // Wait for interrupt_count to be increased.
-      while (interrupt_count == i) {
-        ml.Wait();
-      }
-      OS::Print(" ========== Interrupt processed #%d\n", interrupt_count);
-    }
-  }
-
-  {
-    MonitorLocker ml(sync);
-    // Wait for our isolate to finish.
-    while (shared_isolate != NULL) {
-      ml.Wait();
-    }
-  }
-
-  // We should have received the expected number of interrupts.
-  EXPECT_EQ(kInterruptCount, interrupt_count);
-
-  Isolate::SetInterruptCallback(saved);
-}
-
 static void* saved_callback_data;
 static void IsolateShutdownTestCallback(void* callback_data) {
   saved_callback_data = callback_data;
@@ -8600,7 +7957,7 @@
 // by one.
 TEST_CASE(OneOldSpacePeer) {
   Isolate* isolate = Isolate::Current();
-  Dart_Handle str = Api::NewHandle(isolate, String::New("str", Heap::kOld));
+  Dart_Handle str = Api::NewHandle(thread, String::New("str", Heap::kOld));
   EXPECT_VALID(str);
   EXPECT(Dart_IsString(str));
   EXPECT_EQ(0, isolate->heap()->PeerCount());
@@ -8633,7 +7990,7 @@
   Dart_EnterScope();
   {
     DARTSCOPE(Thread::Current());
-    Dart_Handle str = Api::NewHandle(isolate, String::New("str", Heap::kOld));
+    Dart_Handle str = Api::NewHandle(T, String::New("str", Heap::kOld));
     EXPECT_VALID(str);
     EXPECT(Dart_IsString(str));
     EXPECT_EQ(0, isolate->heap()->PeerCount());
@@ -8662,7 +8019,7 @@
 // by two.
 TEST_CASE(TwoOldSpacePeers) {
   Isolate* isolate = Isolate::Current();
-  Dart_Handle s1 = Api::NewHandle(isolate, String::New("s1", Heap::kOld));
+  Dart_Handle s1 = Api::NewHandle(thread, String::New("s1", Heap::kOld));
   EXPECT_VALID(s1);
   EXPECT(Dart_IsString(s1));
   EXPECT_EQ(0, isolate->heap()->PeerCount());
@@ -8675,7 +8032,7 @@
   o1 = &o1;
   EXPECT_VALID(Dart_GetPeer(s1, &o1));
   EXPECT(o1 == reinterpret_cast<void*>(&p1));
-  Dart_Handle s2 = Api::NewHandle(isolate, String::New("s2", Heap::kOld));
+  Dart_Handle s2 = Api::NewHandle(thread, String::New("s2", Heap::kOld));
   EXPECT_VALID(s2);
   EXPECT(Dart_IsString(s2));
   EXPECT_EQ(1, isolate->heap()->PeerCount());
@@ -8709,7 +8066,7 @@
   Dart_EnterScope();
   {
     DARTSCOPE(Thread::Current());
-    Dart_Handle s1 = Api::NewHandle(isolate, String::New("s1", Heap::kOld));
+    Dart_Handle s1 = Api::NewHandle(T, String::New("s1", Heap::kOld));
     EXPECT_VALID(s1);
     EXPECT(Dart_IsString(s1));
     EXPECT_EQ(0, isolate->heap()->PeerCount());
@@ -8722,7 +8079,7 @@
     o1 = &o1;
     EXPECT_VALID(Dart_GetPeer(s1, &o1));
     EXPECT(o1 == reinterpret_cast<void*>(&p1));
-    Dart_Handle s2 = Api::NewHandle(isolate, String::New("s2", Heap::kOld));
+    Dart_Handle s2 = Api::NewHandle(T, String::New("s2", Heap::kOld));
     EXPECT_VALID(s2);
     EXPECT(Dart_IsString(s2));
     EXPECT_EQ(1, isolate->heap()->PeerCount());
@@ -8815,8 +8172,7 @@
 
     // Test with single character canonical string, it should not become
     // external string but the peer should be setup for it.
-    Isolate* isolate = Isolate::Current();
-    Dart_Handle canonical_str = Api::NewHandle(isolate, Symbols::New("*"));
+    Dart_Handle canonical_str = Api::NewHandle(thread, Symbols::New("*"));
     EXPECT(Dart_IsString(canonical_str));
     EXPECT(!Dart_IsExternalString(canonical_str));
     uint8_t ext_canonical_str[kLength];
@@ -8907,7 +8263,7 @@
     const char* symbol_ascii = "?unseen";
     expected_length = strlen(symbol_ascii);
     Dart_Handle symbol_str =
-        Api::NewHandle(isolate, Symbols::New(symbol_ascii, expected_length));
+        Api::NewHandle(thread, Symbols::New(symbol_ascii, expected_length));
     EXPECT_VALID(symbol_str);
     EXPECT(Dart_IsString(symbol_str));
     EXPECT(Dart_IsStringLatin1(symbol_str));
@@ -9782,8 +9138,14 @@
 
   // Grab the global trace.
   AppendData data;
-  success = Dart_GlobalTimelineGetTrace(AppendStreamConsumer, &data);
-  EXPECT(success);
+  {
+    Thread* T = Thread::Current();
+    StackZone zone(T);
+    success = Dart_GlobalTimelineGetTrace(AppendStreamConsumer, &data);
+    EXPECT(success);
+    // The call should do no zone allocation.
+    EXPECT(zone.SizeInBytes() == 0);
+  }
   buffer = reinterpret_cast<char*>(data.buffer);
   buffer_length = data.buffer_length;
   EXPECT(buffer_length > 0);
@@ -9823,8 +9185,13 @@
   }
 
   // Grab the global trace.
-  success = Dart_GlobalTimelineGetTrace(AppendStreamConsumer, &data);
-  EXPECT(success);
+  {
+    Thread* T = Thread::Current();
+    StackZone zone(T);
+    success = Dart_GlobalTimelineGetTrace(AppendStreamConsumer, &data);
+    EXPECT(success);
+    EXPECT(zone.SizeInBytes() == 0);
+  }
   buffer = reinterpret_cast<char*>(data.buffer);
   buffer_length = data.buffer_length;
   EXPECT(buffer_length > 0);
@@ -9849,4 +9216,165 @@
   free(data.buffer);
 }
 
+
+class GlobalTimelineThreadData {
+ public:
+  GlobalTimelineThreadData()
+      : monitor_(new Monitor()),
+        data_(new AppendData()),
+        running_(true),
+        join_id_(OSThread::kInvalidThreadJoinId) {
+  }
+
+  ~GlobalTimelineThreadData() {
+    delete monitor_;
+    monitor_ = NULL;
+    free(data_->buffer);
+    data_->buffer = NULL;
+    data_->buffer_length = 0;
+    delete data_;
+    data_ = NULL;
+  }
+
+  Monitor* monitor() const { return monitor_; }
+  bool running() const { return running_; }
+  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_;
+};
+
+
+static void GlobalTimelineThread(uword parameter) {
+  GlobalTimelineThreadData* data =
+      reinterpret_cast<GlobalTimelineThreadData*>(parameter);
+  Thread* T = Thread::Current();
+  // When there is no current Thread, then Zone allocation will fail.
+  EXPECT(T == NULL);
+  {
+    MonitorLocker ml(data->monitor());
+    bool success =
+        Dart_GlobalTimelineGetTrace(AppendStreamConsumer, data->data());
+    EXPECT(success);
+    data->set_running(false);
+    data->set_join_id(OSThread::Current()->join_id());
+    ml.Notify();
+  }
+}
+
+
+// This test is the same as the one above except that the calls to
+// Dart_GlobalTimelineGetTrace are made from a fresh thread. This ensures that
+// we can call the function from a thread for which we have not set up a
+// Thread object.
+TEST_CASE(Timeline_Dart_GlobalTimelineGetTrace_Threaded) {
+  const char* kScriptChars =
+    "bar() => 'z';\n"
+    "foo() => 'a';\n"
+    "main() => foo();\n";
+
+  // Enable all streams.
+  Dart_GlobalTimelineSetRecordedStreams(DART_TIMELINE_STREAM_ALL |
+                                        DART_TIMELINE_STREAM_VM);
+  Dart_Handle lib;
+  {
+    // Add something to the VM stream.
+    TimelineDurationScope tds(Timeline::GetVMStream(),
+                              "TestVMDuration");
+    lib = TestCase::LoadTestScript(kScriptChars, NULL);
+  }
+
+  // Invoke main, which will be compiled resulting in a compiler event in
+  // the timeline.
+  Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+  EXPECT_VALID(result);
+
+  const char* buffer = NULL;
+  intptr_t buffer_length = 0;
+
+  // Run Dart_GlobalTimelineGetTrace on a fresh thread.
+  GlobalTimelineThreadData data;
+  int err = OSThread::Start("Timeline test thread",
+      GlobalTimelineThread, reinterpret_cast<uword>(&data));
+  EXPECT(err == 0);
+  {
+    MonitorLocker ml(data.monitor());
+    while (data.running()) {
+      ml.Wait();
+    }
+    buffer = reinterpret_cast<char*>(data.buffer());
+    buffer_length = data.buffer_length();
+    OSThread::Join(data.join_id());
+  }
+  EXPECT(buffer_length > 0);
+  EXPECT(buffer != NULL);
+
+  // Response starts with a '{' character and not a '['.
+  EXPECT(buffer[0] == '{');
+  // Response ends with a '}' character and not a ']'.
+  EXPECT(buffer[buffer_length - 1] == '\0');
+  EXPECT(buffer[buffer_length - 2] == '}');
+
+  // Heartbeat test.
+  EXPECT_SUBSTRING("\"name\":\"TestVMDuration\"", buffer);
+  EXPECT_SUBSTRING("\"cat\":\"Compiler\"", buffer);
+  EXPECT_SUBSTRING("\"name\":\"CompileFunction\"", buffer);
+  EXPECT_SUBSTRING("\"function\":\"::_main\"", buffer);
+  EXPECT_NOTSUBSTRING("\"function\":\"::_bar\"", buffer);
+
+  // Retrieving the global trace resulted in all open blocks being reclaimed.
+  // Add some new events and verify that both sets of events are present
+  // in the resulting trace.
+  {
+    // Add something to the VM stream.
+    TimelineDurationScope tds(Timeline::GetVMStream(),
+                              "TestVMDuration2");
+    // Invoke bar, which will be compiled resulting in a compiler event in
+    // the timeline.
+    result = Dart_Invoke(lib, NewString("bar"), 0, NULL);
+  }
+
+  // Grab the global trace.
+  GlobalTimelineThreadData data2;
+  err = OSThread::Start("Timeline test thread",
+      GlobalTimelineThread, reinterpret_cast<uword>(&data2));
+  EXPECT(err == 0);
+  {
+    MonitorLocker ml(data2.monitor());
+    while (data2.running()) {
+      ml.Wait();
+    }
+    buffer = reinterpret_cast<char*>(data2.buffer());
+    buffer_length = data2.buffer_length();
+    OSThread::Join(data2.join_id());
+  }
+
+  EXPECT(buffer_length > 0);
+  EXPECT(buffer != NULL);
+  // Response starts with a '{' character and not a '['.
+  EXPECT(buffer[0] == '{');
+  // Response ends with a '}' character and not a ']'.
+  EXPECT(buffer[buffer_length - 1] == '\0');
+  EXPECT(buffer[buffer_length - 2] == '}');
+
+  // Heartbeat test for old events.
+  EXPECT_SUBSTRING("\"name\":\"TestVMDuration\"", buffer);
+  EXPECT_SUBSTRING("\"cat\":\"Compiler\"", buffer);
+  EXPECT_SUBSTRING("\"name\":\"CompileFunction\"", buffer);
+  EXPECT_SUBSTRING("\"function\":\"::_main\"", buffer);
+
+  // Heartbeat test for new events.
+  EXPECT_SUBSTRING("\"name\":\"TestVMDuration2\"", buffer);
+  EXPECT_SUBSTRING("\"function\":\"::_bar\"", buffer);
+}
+
 }  // namespace dart
diff --git a/runtime/vm/dart_api_state.h b/runtime/vm/dart_api_state.h
index 207aab4..e0f6e00 100644
--- a/runtime/vm/dart_api_state.h
+++ b/runtime/vm/dart_api_state.h
@@ -203,7 +203,6 @@
  public:
   static FinalizablePersistentHandle* New(
       Isolate* isolate,
-      bool is_prologue,
       const Object& object,
       void* peer,
       Dart_WeakPersistentHandleFinalizer callback,
@@ -251,22 +250,13 @@
     set_external_size(0);
   }
 
-  bool IsPrologueWeakPersistent() {
-    return PrologueWeakBit::decode(external_data_);
-  }
-
-  void SetPrologueWeakPersistent(bool value) {
-    external_data_ = PrologueWeakBit::update(value, external_data_);
-  }
-
   static FinalizablePersistentHandle* Cast(Dart_WeakPersistentHandle handle);
 
  private:
   enum {
     kExternalNewSpaceBit = 0,
-    kPrologueWeakBit = 1,
-    kExternalSizeBits = 2,
-    kExternalSizeBitsSize = (kBitsPerWord - 2),
+    kExternalSizeBits = 1,
+    kExternalSizeBitsSize = (kBitsPerWord - 1),
   };
 
   // This part of external_data_ is the number of externally allocated bytes.
@@ -277,8 +267,6 @@
   // This bit of external_data_ is true if the referent was created in new
   // space and UpdateRelocated has not yet detected any promotion.
   class ExternalNewSpaceBit : public BitField<bool, kExternalNewSpaceBit, 1> {};
-  // This bit is used to indicate that it is a prologue weak persistent handle.
-  class PrologueWeakBit : public BitField<bool, kPrologueWeakBit, 1> {};
 
   friend class FinalizablePersistentHandles;
 
@@ -673,11 +661,6 @@
 };
 
 
-// Forward declarations.
-class WeakReferenceSetBuilder;
-class WeakReferenceSet;
-
-
 // Implementation of the API State used in dart api for maintaining
 // local scopes, persistent handles etc. These are setup on a per isolate
 // basis and destroyed when the isolate is shutdown.
@@ -685,20 +668,11 @@
  public:
   ApiState() : persistent_handles_(),
                weak_persistent_handles_(),
-               prologue_weak_persistent_handles_(),
-               reusable_scope_(NULL),
-               top_scope_(NULL),
-               delayed_weak_reference_sets_(NULL),
                null_(NULL),
                true_(NULL),
                false_(NULL),
                acquired_error_(NULL) {}
   ~ApiState() {
-    while (top_scope_ != NULL) {
-      ApiLocalScope* scope = top_scope_;
-      top_scope_ = top_scope_->previous();
-      delete scope;
-    }
     if (null_ != NULL) {
       persistent_handles().FreeHandle(null_);
       null_ = NULL;
@@ -718,77 +692,18 @@
   }
 
   // Accessors.
-  ApiLocalScope* reusable_scope() const { return reusable_scope_; }
-  void set_reusable_scope(ApiLocalScope* value) {
-    ASSERT(value == NULL || reusable_scope_ == NULL);
-    reusable_scope_ = value;
-  }
-  ApiLocalScope* top_scope() const { return top_scope_; }
-  void set_top_scope(ApiLocalScope* value) { top_scope_ = value; }
-
   PersistentHandles& persistent_handles() { return persistent_handles_; }
 
   FinalizablePersistentHandles& weak_persistent_handles() {
     return weak_persistent_handles_;
   }
 
-  FinalizablePersistentHandles& prologue_weak_persistent_handles() {
-    return prologue_weak_persistent_handles_;
-  }
-
-  WeakReferenceSet* delayed_weak_reference_sets() {
-    return delayed_weak_reference_sets_;
-  }
-  void set_delayed_weak_reference_sets(WeakReferenceSet* reference_set) {
-    delayed_weak_reference_sets_ = reference_set;
-  }
-
-  void UnwindScopes(uword stack_marker) {
-    // Unwind all scopes using the same stack_marker, i.e. all scopes allocated
-    // under the same top_exit_frame_info.
-    while (top_scope_ != NULL &&
-           top_scope_->stack_marker() != 0 &&
-           top_scope_->stack_marker() == stack_marker) {
-      ApiLocalScope* scope = top_scope_;
-      top_scope_ = top_scope_->previous();
-      delete scope;
-    }
-  }
-
-  void VisitObjectPointers(ObjectPointerVisitor* visitor,
-                           bool visit_prologue_weak_handles) {
-    ApiLocalScope* scope = top_scope_;
-    while (scope != NULL) {
-      scope->local_handles()->VisitObjectPointers(visitor);
-      scope = scope->previous();
-    }
+  void VisitObjectPointers(ObjectPointerVisitor* visitor) {
     persistent_handles().VisitObjectPointers(visitor);
-    if (visit_prologue_weak_handles) {
-      prologue_weak_persistent_handles().VisitObjectPointers(visitor);
-    }
   }
 
-  void VisitWeakHandles(HandleVisitor* visitor,
-                        bool visit_prologue_weak_handles) {
+  void VisitWeakHandles(HandleVisitor* visitor) {
     weak_persistent_handles().VisitHandles(visitor);
-    if (visit_prologue_weak_handles) {
-      prologue_weak_persistent_handles().VisitHandles(visitor);
-    }
-  }
-
-  void VisitPrologueWeakHandles(HandleVisitor* visitor) {
-    prologue_weak_persistent_handles().VisitHandles(visitor);
-  }
-
-  bool IsValidLocalHandle(Dart_Handle object) const {
-    ApiLocalScope* scope = top_scope_;
-    while (scope != NULL) {
-      if (scope->local_handles()->IsValidHandle(object)) {
-        return true;
-      }
-      scope = scope->previous();
-    }
-    return false;
   }
 
   bool IsValidPersistentHandle(Dart_PersistentHandle object) const {
@@ -799,37 +714,14 @@
     return weak_persistent_handles_.IsValidHandle(object);
   }
 
-  bool IsValidPrologueWeakPersistentHandle(
-      Dart_WeakPersistentHandle object) const {
-    return prologue_weak_persistent_handles_.IsValidHandle(object);
-  }
-
   bool IsProtectedHandle(PersistentHandle* object) const {
     if (object == NULL) return false;
     return object == null_ || object == true_ || object == false_;
   }
 
-  int CountLocalHandles() const {
-    int total = 0;
-    ApiLocalScope* scope = top_scope_;
-    while (scope != NULL) {
-      total += scope->local_handles()->CountHandles();
-      scope = scope->previous();
-    }
-    return total;
-  }
   int CountPersistentHandles() const {
     return persistent_handles_.CountHandles();
   }
-  int ZoneSizeInBytes() const {
-    int total = 0;
-    ApiLocalScope* scope = top_scope_;
-    while (scope != NULL) {
-      total += scope->zone()->SizeInBytes();
-      scope = scope->previous();
-    }
-    return total;
-  }
 
   void SetupAcquiredError() {
     ASSERT(acquired_error_ == NULL);
@@ -845,19 +737,11 @@
     return acquired_error_;
   }
 
-  WeakReferenceSetBuilder* NewWeakReferenceSetBuilder();
-
-  void DelayWeakReferenceSet(WeakReferenceSet* reference_set);
-
   WeakTable* acquired_table() { return &acquired_table_; }
 
  private:
   PersistentHandles persistent_handles_;
   FinalizablePersistentHandles weak_persistent_handles_;
-  FinalizablePersistentHandles prologue_weak_persistent_handles_;
-  ApiLocalScope* reusable_scope_;
-  ApiLocalScope* top_scope_;
-  WeakReferenceSet* delayed_weak_reference_sets_;
   WeakTable acquired_table_;
 
   // Persistent handles to important objects.
@@ -870,123 +754,16 @@
 };
 
 
-class WeakReferenceSet {
- public:
-  explicit WeakReferenceSet(Zone* zone)
-      : next_(NULL),
-        keys_(1, zone),
-        values_(1, zone) {
-  }
-  ~WeakReferenceSet() {}
-
-  WeakReferenceSet* next() const { return next_; }
-
-  intptr_t num_keys() const { return keys_.length(); }
-  RawObject** get_key(intptr_t i) {
-    ASSERT(i >= 0);
-    ASSERT(i < num_keys());
-    FinalizablePersistentHandle* ref =
-        FinalizablePersistentHandle::Cast(keys_[i]);
-    return ref->raw_addr();
-  }
-
-  intptr_t num_values() const { return values_.length(); }
-  RawObject** get_value(intptr_t i) {
-    ASSERT(i >= 0);
-    ASSERT(i < num_values());
-    FinalizablePersistentHandle* ref =
-        FinalizablePersistentHandle::Cast(values_[i]);
-    return ref->raw_addr();
-  }
-
-  bool SingletonKeyEqualsValue() const {
-    ASSERT((num_keys() == 1) && (num_values() == 1));
-    return (keys_[0] == values_[0]);
-  }
-
-  void Append(Dart_WeakPersistentHandle key, Dart_WeakPersistentHandle value) {
-    keys_.Add(key);
-    values_.Add(value);
-  }
-
-  void AppendKey(Dart_WeakPersistentHandle key) {
-    keys_.Add(key);
-  }
-
-  void AppendValue(Dart_WeakPersistentHandle value) {
-    values_.Add(value);
-  }
-
-  static WeakReferenceSet* Pop(WeakReferenceSet** queue) {
-    ASSERT(queue != NULL);
-    WeakReferenceSet* head = *queue;
-    if (head != NULL) {
-      *queue = head->next();
-      head->next_ = NULL;
-    }
-    return head;
-  }
-
-  static void Push(WeakReferenceSet* reference_set, WeakReferenceSet** queue) {
-    ASSERT(reference_set != NULL);
-    ASSERT(queue != NULL);
-    reference_set->next_ = *queue;
-    *queue = reference_set;
-  }
-
-  void* operator new(uword size, Zone* zone) {
-    return reinterpret_cast<void*>(zone->AllocUnsafe(size));
-  }
-
-  // Disallow explicit deallocation of WeakReferenceSet.
-  void operator delete(void* pointer) { UNREACHABLE(); }
-
- private:
-  WeakReferenceSet* next_;
-  ApiGrowableArray<Dart_WeakPersistentHandle> keys_;
-  ApiGrowableArray<Dart_WeakPersistentHandle> values_;
-
-  DISALLOW_COPY_AND_ASSIGN(WeakReferenceSet);
-};
-
-
-class WeakReferenceSetBuilder {
- public:
-  ApiState* api_state() const {
-    return api_state_;
-  }
-
-  WeakReferenceSet* NewWeakReferenceSet() {
-    return new (zone_) WeakReferenceSet(zone_);
-  }
-
- private:
-  explicit WeakReferenceSetBuilder(ApiState* api_state)
-      : api_state_(api_state),
-        zone_(api_state->top_scope()->zone()) {
-  }
-
-  ApiState* api_state_;
-  Zone* zone_;
-
-  friend class ApiState;
-  DISALLOW_IMPLICIT_CONSTRUCTORS(WeakReferenceSetBuilder);
-};
-
-
 inline FinalizablePersistentHandle* FinalizablePersistentHandle::New(
     Isolate* isolate,
-    bool is_prologue,
     const Object& object,
     void* peer,
     Dart_WeakPersistentHandleFinalizer callback,
     intptr_t external_size) {
   ApiState* state = isolate->api_state();
   ASSERT(state != NULL);
-  FinalizablePersistentHandle* ref = is_prologue ?
-      state->prologue_weak_persistent_handles().AllocateHandle() :
+  FinalizablePersistentHandle* ref =
       state->weak_persistent_handles().AllocateHandle();
-  ref->SetPrologueWeakPersistent(is_prologue);
   ref->set_raw(object);
   ref->set_peer(peer);
   ref->set_callback(callback);
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index 63e2689..5a252e5 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -33,26 +33,39 @@
 
 class ScopedIsolateStackLimits : public ValueObject {
  public:
-  explicit ScopedIsolateStackLimits(Isolate* isolate)
-      : isolate_(isolate), stack_base_(Isolate::GetCurrentStackPointer()) {
-    ASSERT(isolate_ != NULL);
-    ASSERT(isolate_ == Isolate::Current());
-    if (stack_base_ >= isolate_->stack_base()) {
-      isolate_->SetStackLimitFromStackBase(stack_base_);
+  explicit ScopedIsolateStackLimits(Thread* thread)
+      : thread_(thread), saved_stack_limit_(0) {
+    ASSERT(thread != NULL);
+    // Set the thread's stack_base based on the current
+    // stack pointer, we keep refining this value as we
+    // see higher stack pointers (Note: we assume the stack
+    // grows from high to low addresses).
+    OSThread* os_thread = thread->os_thread();
+    ASSERT(os_thread != NULL);
+    uword current_sp = Isolate::GetCurrentStackPointer();
+    if (current_sp > os_thread->stack_base()) {
+      os_thread->set_stack_base(current_sp);
     }
+    // Save the Isolate's current stack limit and adjust the stack
+    // limit based on the thread's stack_base.
+    Isolate* isolate = thread->isolate();
+    ASSERT(isolate == Isolate::Current());
+    saved_stack_limit_ = isolate->saved_stack_limit();
+    isolate->SetStackLimitFromStackBase(os_thread->stack_base());
   }
 
   ~ScopedIsolateStackLimits() {
-    ASSERT(isolate_ == Isolate::Current());
-    if (isolate_->stack_base() == stack_base_) {
-      // Bottomed out.
-      isolate_->ClearStackLimit();
-    }
+    Isolate* isolate = thread_->isolate();
+    ASSERT(isolate == Isolate::Current());
+    // Since we started with a stack limit of 0 we should be getting back
+    // to a stack limit of 0 when all nested invocations are done and
+    // we have bottomed out.
+    isolate->SetStackLimit(saved_stack_limit_);
   }
 
  private:
-  Isolate* isolate_;
-  uword stack_base_;
+  Thread* thread_;
+  uword saved_stack_limit_;
 };
 
 
@@ -84,7 +97,6 @@
   // compiled.
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
-  Isolate* isolate = thread->isolate();
   ASSERT(thread->IsMutatorThread());
   if (!function.HasCode()) {
     const Error& error = Error::Handle(
@@ -99,7 +111,7 @@
   const Code& code = Code::Handle(zone, function.CurrentCode());
   ASSERT(!code.IsNull());
   ASSERT(thread->no_callback_scope_depth() == 0);
-  ScopedIsolateStackLimits stack_limit(isolate);
+  ScopedIsolateStackLimits stack_limit(thread);
   SuspendLongJumpScope suspend_long_jump_scope(thread);
 #if defined(USING_SIMULATOR)
   return bit_copy<RawObject*, int64_t>(Simulator::Current()->Call(
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 0be47b7..aea2178 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -258,13 +258,19 @@
 }
 
 
-bool Debugger::HasEventHandler() {
+bool Debugger::HasAnyEventHandler() {
   return ((event_handler_ != NULL) ||
           Service::isolate_stream.enabled() ||
           Service::debug_stream.enabled());
 }
 
 
+bool Debugger::HasDebugEventHandler() {
+  return ((event_handler_ != NULL) ||
+          Service::debug_stream.enabled());
+}
+
+
 static bool ServiceNeedsDebuggerEvent(DebuggerEvent::EventType type) {
   switch (type) {
     case DebuggerEvent::kBreakpointResolved:
@@ -289,8 +295,6 @@
 
 
 void Debugger::InvokeEventHandler(DebuggerEvent* event) {
-  ASSERT(HasEventHandler());
-
   // Give the event to the Service first, as the debugger event handler
   // may go into a message loop and the Service will not.
   //
@@ -301,7 +305,8 @@
     Service::HandleEvent(&service_event);
   }
 
-  if (FLAG_steal_breakpoints && event->IsPauseEvent()) {
+  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) {
@@ -325,7 +330,7 @@
 
 
 void Debugger::SignalIsolateEvent(DebuggerEvent::EventType type) {
-  if (HasEventHandler()) {
+  if (HasAnyEventHandler()) {
     DebuggerEvent event(isolate_, type);
     ASSERT(event.isolate_id() != ILLEGAL_ISOLATE_ID);
     if (type == DebuggerEvent::kIsolateInterrupted) {
@@ -347,21 +352,9 @@
 
 
 RawError* Debugger::SignalIsolateInterrupted() {
-  if (HasEventHandler()) {
+  if (HasDebugEventHandler()) {
     SignalIsolateEvent(DebuggerEvent::kIsolateInterrupted);
   }
-  Dart_IsolateInterruptCallback callback = isolate_->InterruptCallback();
-  if (callback != NULL) {
-    if (!(*callback)()) {
-      if (FLAG_trace_isolates) {
-        OS::Print("[!] Embedder api: terminating isolate:\n"
-                  "\tisolate:    %s\n", isolate_->name());
-      }
-      const String& msg =
-          String::Handle(String::New("isolate terminated by embedder"));
-      return UnwindError::New(msg);
-    }
-  }
 
   // If any error occurred while in the debug message loop, return it here.
   const Error& error =
@@ -1120,6 +1113,7 @@
       if (var_name.raw() != Symbols::AsyncOperation().raw()) {
         JSONObject jsvar(&jsvars);
         jsvar.AddProperty("type", "BoundVariable");
+        var_name = String::IdentifierPrettyName(var_name);
         jsvar.AddProperty("name", var_name.ToCString());
         jsvar.AddProperty("value", var_value, !full);
         // TODO(turnidge): Do we really want to provide this on every
@@ -1410,7 +1404,7 @@
 
 
 void Debugger::SignalBpResolved(Breakpoint* bpt) {
-  if (HasEventHandler() && !bpt->IsSingleShot()) {
+  if (HasDebugEventHandler() && !bpt->IsSingleShot()) {
     DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointResolved);
     event.set_breakpoint(bpt);
     InvokeEventHandler(&event);
@@ -1631,7 +1625,7 @@
   // interested in exception events.
   if (ignore_breakpoints_ ||
       IsPaused() ||
-      (!HasEventHandler()) ||
+      (!HasDebugEventHandler()) ||
       (exc_pause_info_ == kNoPauseOnExceptions)) {
     return;
   }
@@ -2615,9 +2609,6 @@
 
 RawError* Debugger::DebuggerStepCallback() {
   ASSERT(isolate_->single_step());
-  // We can't get here unless the debugger event handler enabled
-  // single stepping.
-  ASSERT(HasEventHandler());
   // Don't pause recursively.
   if (IsPaused()) {
     return Error::null();
@@ -2685,7 +2676,7 @@
   // 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.
-  if (ignore_breakpoints_ || IsPaused() || !HasEventHandler()) {
+  if (ignore_breakpoints_ || IsPaused()) {
     return Error::null();
   }
   DebuggerStackTrace* stack_trace = CollectStackTrace();
@@ -2774,10 +2765,14 @@
   // 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.
-  if (ignore_breakpoints_ || IsPaused() || !HasEventHandler()) {
+  if (ignore_breakpoints_ || IsPaused()) {
     return;
   }
 
+  if (!HasDebugEventHandler()) {
+    OS::Print("Hit debugger!");
+  }
+
   DebuggerStackTrace* stack_trace = CollectStackTrace();
   ASSERT(stack_trace->Length() > 0);
   ASSERT(stack_trace_ == NULL);
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index aaa2b84..acb69ec 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -584,7 +584,8 @@
     kSingleStep
   };
 
-  static bool HasEventHandler();
+  static bool HasAnyEventHandler();
+  static bool HasDebugEventHandler();
   void InvokeEventHandler(DebuggerEvent* event);
 
   void FindCompiledFunctions(const Script& script,
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index bd6883c..7e1ec45 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -56,6 +56,7 @@
 
 DART_EXPORT intptr_t Dart_CacheObject(Dart_Handle object_in) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object_in));
   if (obj.IsApiError()) {
     return -1;
@@ -66,11 +67,12 @@
 
 DART_EXPORT Dart_Handle Dart_GetCachedObject(intptr_t obj_id) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   if (!I->debugger()->IsValidObjectId(obj_id)) {
     return Api::NewError("%s: object id %" Pd " is invalid",
                          CURRENT_FUNC, obj_id);
   }
-  return Api::NewHandle(I, I->debugger()->GetCachedObject(obj_id));
+  return Api::NewHandle(T, I->debugger()->GetCachedObject(obj_id));
 }
 
 
@@ -117,7 +119,7 @@
     if (paused_event_handler != NULL) {
       Dart_CodeLocation location;
       ActivationFrame* top_frame = event->top_frame();
-      location.script_url = Api::NewHandle(isolate, top_frame->SourceUrl());
+      location.script_url = Api::NewHandle(thread, top_frame->SourceUrl());
       const Library& lib = Library::Handle(top_frame->Library());
       location.library_id = lib.index();
       location.token_pos = top_frame->TokenPos();
@@ -138,7 +140,7 @@
       Script& script = Script::Handle(zone);
       intptr_t token_pos;
       bpt->bpt_location()->GetCodeLocation(&library, &script, &token_pos);
-      location.script_url = Api::NewHandle(isolate, script.url());
+      location.script_url = Api::NewHandle(thread, script.url());
       location.library_id = library.index();
       location.token_pos = token_pos;
       (*bp_resolved_handler)(isolate_id, bpt->id(), location);
@@ -146,7 +148,7 @@
   } else if (event->type() == DebuggerEvent::kExceptionThrown) {
     if (exc_thrown_handler != NULL) {
       Dart_Handle exception =
-          Api::NewHandle(isolate, event->exception()->raw());
+          Api::NewHandle(thread, event->exception()->raw());
       Dart_StackTrace trace =
       reinterpret_cast<Dart_StackTrace>(isolate->debugger()->StackTrace());
       (*exc_thrown_handler)(isolate_id, exception, trace);
@@ -199,6 +201,7 @@
 DART_EXPORT Dart_Handle Dart_SetExceptionPauseInfo(
                             Dart_ExceptionPauseInfo pause_info) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   I->debugger()->SetExceptionPauseInfo(pause_info);
   return Api::Success();
 }
@@ -206,12 +209,14 @@
 
 DART_EXPORT Dart_ExceptionPauseInfo Dart_GetExceptionPauseInfo() {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   return I->debugger()->GetExceptionPauseInfo();
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetStackTrace(Dart_StackTrace* trace) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   CHECK_NOT_NULL(trace);
   *trace = reinterpret_cast<Dart_StackTrace>(
       I->debugger()->CurrentStackTrace());
@@ -231,6 +236,7 @@
     if (dart_stacktrace.IsNull()) {
       *trace = NULL;
     } else {
+      Isolate* I = T->isolate();
       *trace = reinterpret_cast<Dart_StackTrace>(
         I->debugger()->StackTraceFrom(dart_stacktrace));
     }
@@ -251,10 +257,10 @@
   DARTSCOPE(Thread::Current());
   CHECK_AND_CAST(ActivationFrame, frame, activation_frame);
   if (function_name != NULL) {
-    *function_name = Api::NewHandle(I, frame->QualifiedFunctionName());
+    *function_name = Api::NewHandle(T, frame->QualifiedFunctionName());
   }
   if (script_url != NULL) {
-    *script_url = Api::NewHandle(I, frame->SourceUrl());
+    *script_url = Api::NewHandle(T, frame->SourceUrl());
   }
   if (line_number != NULL) {
     *line_number = frame->LineNumber();
@@ -276,14 +282,14 @@
   DARTSCOPE(Thread::Current());
   CHECK_AND_CAST(ActivationFrame, frame, activation_frame);
   if (function_name != NULL) {
-    *function_name = Api::NewHandle(I, frame->QualifiedFunctionName());
+    *function_name = Api::NewHandle(T, frame->QualifiedFunctionName());
   }
   if (function != NULL) {
-    *function = Api::NewHandle(I, frame->function().raw());
+    *function = Api::NewHandle(T, frame->function().raw());
   }
 
   if (location != NULL) {
-    location->script_url = Api::NewHandle(I, frame->SourceUrl());
+    location->script_url = Api::NewHandle(T, frame->SourceUrl());
     const Library& lib = Library::Handle(Z, frame->Library());
     location->library_id = lib.index();
     location->token_pos = frame->TokenPos();
@@ -320,7 +326,7 @@
                             Dart_ActivationFrame activation_frame) {
   DARTSCOPE(Thread::Current());
   CHECK_AND_CAST(ActivationFrame, frame, activation_frame);
-  return Api::NewHandle(I, frame->GetLocalVariables());
+  return Api::NewHandle(T, frame->GetLocalVariables());
 }
 
 
@@ -328,6 +334,7 @@
                             Dart_Handle script_url_in,
                             intptr_t line_number) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   UNWRAP_AND_CHECK_PARAM(String, script_url, script_url_in);
 
   Debugger* debugger = I->debugger();
@@ -343,6 +350,7 @@
 
 DART_EXPORT Dart_Handle Dart_GetBreakpointURL(intptr_t bp_id) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   Debugger* debugger = I->debugger();
 
   Breakpoint* bpt = debugger->GetBreakpointById(bp_id);
@@ -350,12 +358,13 @@
     return Api::NewError("%s: breakpoint with id %" Pd " does not exist",
                            CURRENT_FUNC, bp_id);
   }
-  return Api::NewHandle(I, bpt->bpt_location()->url());
+  return Api::NewHandle(T, bpt->bpt_location()->url());
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetBreakpointLine(intptr_t bp_id) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   Debugger* debugger = I->debugger();
 
   Breakpoint* bpt = debugger->GetBreakpointById(bp_id);
@@ -376,6 +385,7 @@
                             Dart_Handle class_name_in,
                             Dart_Handle function_name_in) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   UNWRAP_AND_CHECK_PARAM(Library, library, library_in);
   UNWRAP_AND_CHECK_PARAM(String, class_name, class_name_in);
   UNWRAP_AND_CHECK_PARAM(String, function_name, function_name_in);
@@ -415,6 +425,7 @@
                             Dart_Handle class_name_in,
                             Dart_Handle function_name_in) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   UNWRAP_AND_CHECK_PARAM(Library, library, library_in);
   UNWRAP_AND_CHECK_PARAM(String, class_name, class_name_in);
   UNWRAP_AND_CHECK_PARAM(String, function_name, function_name_in);
@@ -442,7 +453,7 @@
   const Error& error = Error::Handle(Z,
       debugger->OneTimeBreakAtEntry(bp_target));
   if (!error.IsNull()) {
-    return Api::NewHandle(I, error.raw());
+    return Api::NewHandle(T, error.raw());
   }
   return Api::Success();
 }
@@ -450,6 +461,7 @@
 
 DART_EXPORT Dart_Handle Dart_RemoveBreakpoint(intptr_t bp_id) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   I->debugger()->RemoveBreakpoint(bp_id);
   return Api::Success();
 }
@@ -457,6 +469,7 @@
 
 DART_EXPORT Dart_Handle Dart_SetStepOver() {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   I->debugger()->SetStepOver();
   return Api::Success();
 }
@@ -464,6 +477,7 @@
 
 DART_EXPORT Dart_Handle Dart_SetStepInto() {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   I->debugger()->SetSingleStep();
   return Api::Success();
 }
@@ -471,6 +485,7 @@
 
 DART_EXPORT Dart_Handle Dart_SetStepOut() {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   I->debugger()->SetStepOut();
   return Api::Success();
 }
@@ -478,44 +493,48 @@
 
 DART_EXPORT Dart_Handle Dart_GetInstanceFields(Dart_Handle object_in) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   UNWRAP_AND_CHECK_PARAM(Instance, obj, object_in);
-  return Api::NewHandle(I, I->debugger()->GetInstanceFields(obj));
+  return Api::NewHandle(T, I->debugger()->GetInstanceFields(obj));
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetStaticFields(Dart_Handle target) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   const Type& type_obj = Api::UnwrapTypeHandle(Z, target);
   if (type_obj.IsNull()) {
     return Api::NewError("%s expects argument 'target' to be a type",
                          CURRENT_FUNC);
   }
   const Class& cls = Class::Handle(Z, type_obj.type_class());
-  return Api::NewHandle(I, I->debugger()->GetStaticFields(cls));
+  return Api::NewHandle(T, I->debugger()->GetStaticFields(cls));
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetLibraryFields(intptr_t library_id) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   const Library& lib =
       Library::Handle(Z, Library::GetLibrary(library_id));
   if (lib.IsNull()) {
     return Api::NewError("%s: %" Pd " is not a valid library id",
                          CURRENT_FUNC, library_id);
   }
-  return Api::NewHandle(I, I->debugger()->GetLibraryFields(lib));
+  return Api::NewHandle(T, I->debugger()->GetLibraryFields(lib));
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetGlobalVariables(intptr_t library_id) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
 
   const Library& lib = Library::Handle(Z, Library::GetLibrary(library_id));
   if (lib.IsNull()) {
     return Api::NewError("%s: %" Pd " is not a valid library id",
                          CURRENT_FUNC, library_id);
   }
-  return Api::NewHandle(I, I->debugger()->GetGlobalFields(lib));
+  return Api::NewHandle(T, I->debugger()->GetGlobalFields(lib));
 }
 
 
@@ -525,7 +544,7 @@
   DARTSCOPE(Thread::Current());
   CHECK_AND_CAST(ActivationFrame, frame, activation_frame);
   UNWRAP_AND_CHECK_PARAM(String, expr, expr_in);
-  return Api::NewHandle(I, frame->Evaluate(expr));
+  return Api::NewHandle(T, frame->Evaluate(expr));
 }
 
 
@@ -543,22 +562,22 @@
   // Type extends Instance, must check first.
   if (target.IsType()) {
     const Class& cls = Class::Handle(Z, Type::Cast(target).type_class());
-    return Api::NewHandle(I, cls.Evaluate(expr,
+    return Api::NewHandle(T, cls.Evaluate(expr,
                                           Array::empty_array(),
                                           Array::empty_array()));
   } else if (target.IsInstance()) {
     const Instance& inst = Instance::Cast(target);
-    return Api::NewHandle(I, inst.Evaluate(expr,
+    return Api::NewHandle(T, inst.Evaluate(expr,
                                            Array::empty_array(),
                                            Array::empty_array()));
   } else if (target.IsLibrary()) {
     const Library& lib = Library::Cast(target);
-    return Api::NewHandle(I, lib.Evaluate(expr,
+    return Api::NewHandle(T, lib.Evaluate(expr,
                                           Array::empty_array(),
                                           Array::empty_array()));
   } else if (target.IsClass()) {
     const Class& cls = Class::Cast(target);
-    return Api::NewHandle(I, cls.Evaluate(expr,
+    return Api::NewHandle(T, cls.Evaluate(expr,
                                           Array::empty_array(),
                                           Array::empty_array()));
   }
@@ -569,7 +588,7 @@
 DART_EXPORT Dart_Handle Dart_GetObjClass(Dart_Handle object_in) {
   DARTSCOPE(Thread::Current());
   UNWRAP_AND_CHECK_PARAM(Instance, obj, object_in);
-  return Api::NewHandle(I, obj.GetType());
+  return Api::NewHandle(T, obj.GetType());
 }
 
 
@@ -585,11 +604,12 @@
 
 DART_EXPORT Dart_Handle Dart_GetClassFromId(intptr_t class_id) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   if (!I->class_table()->IsValidIndex(class_id)) {
     return Api::NewError("%s: %" Pd " is not a valid class id",
                          CURRENT_FUNC, class_id);
   }
-  return Api::NewHandle(I, I->class_table()->At(class_id));
+  return Api::NewHandle(T, I->class_table()->At(class_id));
 }
 
 
@@ -613,7 +633,7 @@
     if (type.IsNull()) {
       return Dart_Null();
     }
-    return Api::NewHandle(I, type.Canonicalize());
+    return Api::NewHandle(T, type.Canonicalize());
   }
   // Set up the type arguments array for the super class type.
   const Class& super_cls = Class::Handle(cls.SuperClass());
@@ -635,7 +655,7 @@
       Type::New(super_cls, super_type_args_array, Scanner::kNoSourcePos));
   ASSERT(!instantiated_type.IsNull());
   instantiated_type.SetIsFinalized();
-  return Api::NewHandle(I, instantiated_type.Canonicalize());
+  return Api::NewHandle(T, instantiated_type.Canonicalize());
 }
 
 
@@ -654,10 +674,10 @@
   const Function& func = Function::Handle(Closure::function(instance));
   ASSERT(!func.IsNull());
   if (name != NULL) {
-    *name = Api::NewHandle(I, func.QualifiedUserVisibleName());
+    *name = Api::NewHandle(T, func.QualifiedUserVisibleName());
   }
   if (signature != NULL) {
-    *signature = Api::NewHandle(I, func.UserVisibleSignature());
+    *signature = Api::NewHandle(T, func.UserVisibleSignature());
   }
 
   if (location != NULL) {
@@ -669,11 +689,11 @@
       // Note func.script() is not the same as cls.script() for eval functions.
       const Script& script = Script::Handle(Z, func.script());
       ASSERT(!script.IsNull());
-      location->script_url = Api::NewHandle(I, script.url());
+      location->script_url = Api::NewHandle(T, script.url());
       location->library_id = lib.index();
       location->token_pos = func.token_pos();
     } else {
-      location->script_url = Api::NewHandle(I, String::null());
+      location->script_url = Api::NewHandle(T, String::null());
       location->library_id = -1;
       location->token_pos = -1;
     }
@@ -689,13 +709,14 @@
                             intptr_t* super_class_id,
                             Dart_Handle* static_fields) {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
   if (!I->class_table()->IsValidIndex(cls_id)) {
     return Api::NewError("%s: %" Pd " is not a valid class id",
                          CURRENT_FUNC, cls_id);
   }
   Class& cls = Class::Handle(Z, I->class_table()->At(cls_id));
   if (class_name != NULL) {
-    *class_name = Api::NewHandle(I, cls.Name());
+    *class_name = Api::NewHandle(T, cls.Name());
   }
   if (library_id != NULL) {
     const Library& lib = Library::Handle(Z, cls.library());
@@ -710,7 +731,7 @@
   }
   if (static_fields != NULL) {
     *static_fields =
-        Api::NewHandle(I, I->debugger()->GetStaticFields(cls));
+        Api::NewHandle(T, I->debugger()->GetStaticFields(cls));
   }
   return Api::Success();
 }
@@ -732,7 +753,7 @@
                          CURRENT_FUNC, script_url.ToCString(),
                          String::Handle(lib.url()).ToCString());
   }
-  return Api::NewHandle(I, script.Source());
+  return Api::NewHandle(T, script.Source());
 }
 
 
@@ -755,7 +776,7 @@
 
   const GrowableObjectArray& info =
       GrowableObjectArray::Handle(script.GenerateLineNumberArray());
-  return Api::NewHandle(I, Array::MakeArray(info));
+  return Api::NewHandle(T, Array::MakeArray(info));
 }
 
 
@@ -778,7 +799,7 @@
                          library_url.ToCString());
   }
 
-  return Api::NewHandle(I, script.GenerateSource());
+  return Api::NewHandle(T, script.GenerateSource());
 }
 
 
@@ -802,12 +823,13 @@
     url = script.url();
     script_list.SetAt(i, url);
   }
-  return Api::NewHandle(I, script_list.raw());
+  return Api::NewHandle(T, script_list.raw());
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetLibraryIds() {
   DARTSCOPE(Thread::Current());
+  Isolate* I = T->isolate();
 
   const GrowableObjectArray& libs =
       GrowableObjectArray::Handle(Z, I->object_store()->libraries());
@@ -822,7 +844,7 @@
     ASSERT(Smi::IsValid(lib.index()));
     library_id_list.SetAt(i, Smi::Handle(Smi::New(lib.index())));
   }
-  return Api::NewHandle(I, library_id_list.raw());
+  return Api::NewHandle(T, library_id_list.raw());
 }
 
 
@@ -833,7 +855,7 @@
     return Api::NewError("%s: %" Pd " is not a valid library id",
                          CURRENT_FUNC, library_id);
   }
-  return Api::NewHandle(I, lib.raw());
+  return Api::NewHandle(T, lib.raw());
 }
 
 
@@ -885,7 +907,7 @@
       import_list.Add(Smi::Handle(Smi::New(imported.index())));
     }
   }
-  return Api::NewHandle(I, Array::MakeArray(import_list));
+  return Api::NewHandle(T, Array::MakeArray(import_list));
 }
 
 
@@ -896,7 +918,7 @@
     return Api::NewError("%s: %" Pd " is not a valid library id",
                          CURRENT_FUNC, library_id);
   }
-  return Api::NewHandle(I, lib.url());
+  return Api::NewHandle(T, lib.url());
 }
 
 
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index 1bfc4ce..cd1b8c8 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -1515,7 +1515,7 @@
   sync = new Monitor();
   EXPECT(interrupt_isolate_id == ILLEGAL_ISOLATE_ID);
   Dart_SetPausedEventHandler(InterruptIsolateHandler);
-  int result = OSThread::Start(InterruptIsolateRun, 0);
+  int result = OSThread::Start("DebugInterruptIsolate", InterruptIsolateRun, 0);
   EXPECT_EQ(0, result);
 
   // Wait for the test isolate to be created.
diff --git a/runtime/vm/flags.cc b/runtime/vm/flags.cc
index f38639f..c1ec041 100644
--- a/runtime/vm/flags.cc
+++ b/runtime/vm/flags.cc
@@ -288,8 +288,8 @@
   if (*equals != '=') {
     // No explicit option argument. Determine if there is a "no_" prefix
     // preceding the name.
-    const char* kNo1Prefix = "no_";
-    const char* kNo2Prefix = "no-";
+    const char* const kNo1Prefix = "no_";
+    const char* const kNo2Prefix = "no-";
     const intptr_t kNo1PrefixLen = strlen(kNo1Prefix);
     const intptr_t kNo2PrefixLen = strlen(kNo2Prefix);
     if (strncmp(option, kNo1Prefix, kNo1PrefixLen) == 0) {
@@ -359,7 +359,7 @@
 
   qsort(flags_, num_flags_, sizeof flags_[0], CompareFlagNames);
 
-  const char* kPrefix = "--";
+  const char* const kPrefix = "--";
   const intptr_t kPrefixLen = strlen(kPrefix);
 
   int i = 0;
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index e40887b..6d47957 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -103,8 +103,8 @@
     // loading, deoptimization, ...). Noopt mode simulates behavior
     // of precompiled code, therefore do not allow recompilation.
     Compiler::set_allow_recompilation(false);
-    // TODO(srdjan): Enable CHA deoptimization when eager class finalization is
-    // implemented, either with precompilation or as a special pass.
+    // Precompilation finalizes all classes and thus allows CHA optimizations.
+    // Do not require CHA triggered deoptimization.
     FLAG_use_cha_deopt = false;
     // Calling the PrintStopMessage stub is not supported in precompiled code
     // since it is done at places where no pool pointer is loaded.
@@ -546,11 +546,6 @@
 #endif
   }
 
-  if (inline_id_to_function_.length() > max_inlining_id + 1) {
-    // TODO(srdjan): Some inlined function can disappear,
-    // truncate 'inline_id_to_function_'.
-  }
-
   if (is_optimizing()) {
     LogBlock lb;
     intervals.Add(IntervalStruct(prev_offset, prev_inlining_id));
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 448b70a..ded5e74 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -1312,7 +1312,7 @@
   __ lw(T0, Address(SP, (argument_count - 1) * kWordSize));
   if (ic_data.NumArgsTested() == 1) {
     __ LoadUniqueObject(S5, ic_data);
-    __ BranchLink(*StubCode::ICLookup_entry());
+    __ BranchLinkPatchable(*StubCode::ICLookup_entry());
   } else {
     const String& name = String::Handle(zone(), ic_data.target_name());
     const Array& arguments_descriptor =
@@ -1323,7 +1323,7 @@
         MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor));
 
     __ LoadUniqueObject(S5, cache);
-    __ BranchLink(*StubCode::MegamorphicLookup_entry());
+    __ BranchLinkPatchable(*StubCode::MegamorphicLookup_entry());
   }
   __ jalr(T1);
 
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 930da8d..7cd46a0 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -11,6 +11,7 @@
 #include "vm/flow_graph_builder.h"
 #include "vm/flow_graph_compiler.h"
 #include "vm/flow_graph_optimizer.h"
+#include "vm/flow_graph_type_propagator.h"
 #include "vm/il_printer.h"
 #include "vm/intrinsifier.h"
 #include "vm/longjump.h"
@@ -776,10 +777,19 @@
 
       {
         CSTAT_TIMER_SCOPE(thread(), graphinliner_opt_timer);
-        // TODO(zerny): Do more optimization passes on the callee graph.
-        FlowGraphOptimizer optimizer(callee_graph);
+        // TODO(fschneider): Improve suppression of speculative inlining.
+        // Deopt-ids overlap between caller and callee.
+        FlowGraphOptimizer optimizer(callee_graph,
+                                     inliner_->use_speculative_inlining_,
+                                     inliner_->inlining_black_list_);
         if (Compiler::always_optimize()) {
           optimizer.PopulateWithICData();
+
+          optimizer.ApplyClassIds();
+          DEBUG_ASSERT(callee_graph->VerifyUseLists());
+
+          FlowGraphTypePropagator::Propagate(callee_graph);
+          DEBUG_ASSERT(callee_graph->VerifyUseLists());
         }
         optimizer.ApplyICData();
         DEBUG_ASSERT(callee_graph->VerifyUseLists());
@@ -1469,7 +1479,9 @@
 
 bool PolymorphicInliner::TryInlineRecognizedMethod(intptr_t receiver_cid,
                                                    const Function& target) {
-  FlowGraphOptimizer optimizer(owner_->caller_graph());
+  FlowGraphOptimizer optimizer(owner_->caller_graph(),
+                               false,  // Speculative inlining not applicable.
+                               NULL);
   TargetEntryInstr* entry;
   Definition* last;
   // Replace the receiver argument with a redefinition to prevent code from
@@ -1775,11 +1787,16 @@
 FlowGraphInliner::FlowGraphInliner(
     FlowGraph* flow_graph,
     GrowableArray<const Function*>* inline_id_to_function,
-    GrowableArray<intptr_t>* caller_inline_id)
+    GrowableArray<intptr_t>* caller_inline_id,
+    bool use_speculative_inlining,
+    GrowableArray<intptr_t>* inlining_black_list)
     : flow_graph_(flow_graph),
       inline_id_to_function_(inline_id_to_function),
       caller_inline_id_(caller_inline_id),
-      trace_inlining_(ShouldTraceInlining(flow_graph)) {
+      trace_inlining_(ShouldTraceInlining(flow_graph)),
+      use_speculative_inlining_(use_speculative_inlining),
+      inlining_black_list_(inlining_black_list) {
+  ASSERT(!use_speculative_inlining || (inlining_black_list != NULL));
 }
 
 
@@ -1819,7 +1836,7 @@
 
 
 // Use function name to determine if inlineable operator.
-// TODO(srdjan): add names as necessary
+// Add names as necessary.
 static bool IsInlineableOperator(const Function& function) {
   return (function.name() == Symbols::IndexToken().raw()) ||
          (function.name() == Symbols::AssignIndexToken().raw()) ||
@@ -1839,7 +1856,8 @@
 
   if (function.IsImplicitGetterFunction() || function.IsGetterFunction() ||
       function.IsImplicitSetterFunction() || function.IsSetterFunction() ||
-      IsInlineableOperator(function)) {
+      IsInlineableOperator(function) ||
+      (function.kind() == RawFunction::kConstructor)) {
     const intptr_t count = function.optimized_instruction_count();
     if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) {
       return true;
diff --git a/runtime/vm/flow_graph_inliner.h b/runtime/vm/flow_graph_inliner.h
index 114348b..6e3ce09 100644
--- a/runtime/vm/flow_graph_inliner.h
+++ b/runtime/vm/flow_graph_inliner.h
@@ -18,7 +18,9 @@
  public:
   FlowGraphInliner(FlowGraph* flow_graph,
                    GrowableArray<const Function*>* inline_id_to_function,
-                   GrowableArray<intptr_t>* caller_inline_id);
+                   GrowableArray<intptr_t>* caller_inline_id,
+                   bool use_speculative_inlining,
+                   GrowableArray<intptr_t>* inlining_black_list);
 
   // The flow graph is destructively updated upon inlining.
   void Inline();
@@ -41,6 +43,8 @@
   GrowableArray<const Function*>* inline_id_to_function_;
   GrowableArray<intptr_t>* caller_inline_id_;
   const bool trace_inlining_;
+  const bool use_speculative_inlining_;
+  GrowableArray<intptr_t>* inlining_black_list_;
 
   DISALLOW_COPY_AND_ASSIGN(FlowGraphInliner);
 };
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index feb72c1..15642fc 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -18,6 +18,7 @@
 #include "vm/intermediate_language.h"
 #include "vm/object_store.h"
 #include "vm/parser.h"
+#include "vm/precompiler.h"
 #include "vm/resolver.h"
 #include "vm/scopes.h"
 #include "vm/stack_frame.h"
@@ -49,12 +50,14 @@
 DEFINE_FLAG(bool, trace_smi_widening, false, "Trace Smi->Int32 widening pass.");
 #endif
 
+DECLARE_FLAG(bool, precompilation);
 DECLARE_FLAG(bool, polymorphic_with_deopt);
 DECLARE_FLAG(bool, source_lines);
 DECLARE_FLAG(bool, trace_cha);
 DECLARE_FLAG(bool, trace_field_guards);
 DECLARE_FLAG(bool, trace_type_check_elimination);
 DECLARE_FLAG(bool, warn_on_javascript_compatibility);
+DECLARE_FLAG(bool, fields_may_be_reset);
 
 // Quick access to the current isolate and zone.
 #define I (isolate())
@@ -266,12 +269,32 @@
           Resolver::ResolveDynamicForReceiverClass(owner_class,
                                                    call->function_name(),
                                                    args_desc));
-      if (function.IsNull()) {
-        return false;
+      if (!function.IsNull()) {
+        const ICData& ic_data = ICData::ZoneHandle(Z,
+            ICData::NewFrom(*call->ic_data(), class_ids.length()));
+        ic_data.AddReceiverCheck(owner_class.id(), function);
+        call->set_ic_data(&ic_data);
+        return true;
       }
+    }
+  }
+
+  if (FLAG_precompilation &&
+      (isolate()->object_store()->unique_dynamic_targets() != Array::null())) {
+    // Check if the target is unique.
+    Function& target_function = Function::Handle(Z);
+    Precompiler::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)) {
+      const intptr_t cid = Class::Handle(Z, target_function.Owner()).id();
       const ICData& ic_data = ICData::ZoneHandle(Z,
-          ICData::NewFrom(*call->ic_data(), class_ids.length()));
-      ic_data.AddReceiverCheck(owner_class.id(), function);
+          ICData::NewFrom(*call->ic_data(), 1));
+      ic_data.AddReceiverCheck(cid, target_function);
       call->set_ic_data(&ic_data);
       return true;
     }
@@ -959,12 +982,11 @@
   if (ic_data.NumArgsTested() != 2) {
     return false;
   }
-  Function& target = Function::Handle();
   const intptr_t len = ic_data.NumberOfChecks();
   GrowableArray<intptr_t> class_ids;
   for (intptr_t i = 0; i < len; i++) {
     if (ic_data.IsUsedAt(i)) {
-      ic_data.GetCheckAt(i, &class_ids, &target);
+      ic_data.GetClassIdsAt(i, &class_ids);
       ASSERT(class_ids.length() == 2);
       if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) ||
           !ClassIdIsOneOf(class_ids[1], argument_class_ids)) {
@@ -982,12 +1004,11 @@
   if (ic_data.NumArgsTested() != 2) {
     return false;
   }
-  Function& target = Function::Handle();
   const intptr_t len = ic_data.NumberOfChecks();
   for (intptr_t i = 0; i < len; i++) {
     if (ic_data.IsUsedAt(i)) {
       GrowableArray<intptr_t> class_ids;
-      ic_data.GetCheckAt(i, &class_ids, &target);
+      ic_data.GetClassIdsAt(i, &class_ids);
       ASSERT(class_ids.length() == 2);
       if ((class_ids[0] == receiver_class_id) &&
           (class_ids[1] == argument_class_id)) {
@@ -2358,9 +2379,8 @@
   ASSERT(call->HasICData());
   const ICData& ic_data = *call->ic_data();
   ASSERT(ic_data.HasOneTarget());
-  Function& target = Function::Handle(Z);
   GrowableArray<intptr_t> class_ids;
-  ic_data.GetCheckAt(0, &class_ids, &target);
+  ic_data.GetClassIdsAt(0, &class_ids);
   ASSERT(class_ids.length() == 1);
   // Inline implicit instance getter.
   const String& field_name =
@@ -4839,6 +4859,7 @@
          instr_it.Advance()) {
       BinarySmiOpInstr* smi_op = instr_it.Current()->AsBinarySmiOp();
       if ((smi_op != NULL) &&
+          smi_op->HasSSATemp() &&
           BenefitsFromWidening(smi_op) &&
           CanBeWidened(smi_op)) {
         candidates.Add(smi_op);
@@ -5655,8 +5676,13 @@
     return "<?>";
   }
 
-  bool IsFinalField() const {
-    return (kind() == kField) && field().is_final();
+  // Fields that are considered immutable by load optimization.
+  // Handle static finals as non-final with precompilation because
+  // they may be reset to uninitialized after compilation.
+  bool IsImmutableField() const {
+    return (kind() == kField)
+        && field().is_final()
+        && (!field().is_static() || !FLAG_fields_may_be_reset);
   }
 
   intptr_t Hashcode() const {
@@ -5993,7 +6019,7 @@
 
   // Compute least generic alias for the place and assign alias id to it.
   void AddRepresentative(Place* place) {
-    if (!place->IsFinalField()) {
+    if (!place->IsImmutableField()) {
       const Place* alias = CanonicalizeAlias(place->ToAlias());
       EnsureSet(&representatives_, alias->id())->Add(place->id());
 
@@ -6199,7 +6225,7 @@
   // This essentially means that no stores to the same location can
   // occur in other functions.
   bool IsIndependentFromEffects(Place* place) {
-    if (place->IsFinalField()) {
+    if (place->IsImmutableField()) {
       // Note that we can't use LoadField's is_immutable attribute here because
       // some VM-fields (those that have no corresponding Field object and
       // accessed through offset alone) can share offset but have different
@@ -6633,7 +6659,7 @@
               aliased_set_->LookupAliasId(place.ToAlias());
           if (alias_id != AliasedSet::kNoAlias) {
             killed = aliased_set_->GetKilledSet(alias_id);
-          } else if (!place.IsFinalField()) {
+          } else if (!place.IsImmutableField()) {
             // We encountered unknown alias: this means intrablock load
             // forwarding refined parameter of this store, for example
             //
@@ -7537,7 +7563,7 @@
         bool is_load = false;
         bool is_store = false;
         Place place(instr, &is_load, &is_store);
-        if (place.IsFinalField()) {
+        if (place.IsImmutableField()) {
           // Loads/stores of final fields do not participate.
           continue;
         }
@@ -7626,7 +7652,7 @@
         bool is_store = false;
         Place place(instr, &is_load, &is_store);
         ASSERT(!is_load && is_store);
-        if (place.IsFinalField()) {
+        if (place.IsImmutableField()) {
           // Final field do not participate in dead store elimination.
           continue;
         }
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index 4a28be0..9d500aa 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -16,10 +16,10 @@
 
 class FlowGraphOptimizer : public FlowGraphVisitor {
  public:
-  explicit FlowGraphOptimizer(
+  FlowGraphOptimizer(
       FlowGraph* flow_graph,
-      bool use_speculative_inlining = false,
-      GrowableArray<intptr_t>* inlining_black_list = NULL)
+      bool use_speculative_inlining,
+      GrowableArray<intptr_t>* inlining_black_list)
       : FlowGraphVisitor(flow_graph->reverse_postorder()),
         flow_graph_(flow_graph),
         use_speculative_inlining_(use_speculative_inlining),
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 986615f..60c20aef 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -17,6 +17,7 @@
 DECLARE_FLAG(bool, propagate_types);
 DECLARE_FLAG(bool, trace_cha);
 DECLARE_FLAG(bool, use_cha_deopt);
+DECLARE_FLAG(bool, fields_may_be_reset);
 
 
 void FlowGraphTypePropagator::Propagate(FlowGraph* flow_graph) {
@@ -149,8 +150,6 @@
     }
   }
 
-  HandleBranchOnStrictCompare(block);
-
   for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) {
     PropagateRecursive(block->dominated_blocks()[i]);
   }
@@ -159,61 +158,6 @@
 }
 
 
-void FlowGraphTypePropagator::HandleBranchOnStrictCompare(
-    BlockEntryInstr* block) {
-  BranchInstr* branch = block->last_instruction()->AsBranch();
-  if (branch == NULL) {
-    return;
-  }
-
-  StrictCompareInstr* compare = branch->comparison()->AsStrictCompare();
-  if ((compare == NULL) || !compare->right()->BindsToConstant()) {
-    return;
-  }
-
-  const intptr_t rollback_point = rollback_.length();
-
-  Definition* defn = compare->left()->definition();
-  const Object& right = compare->right()->BoundConstant();
-  intptr_t cid = right.GetClassId();
-
-  if (defn->IsLoadClassId() && right.IsSmi()) {
-    defn = defn->AsLoadClassId()->object()->definition();
-    cid = Smi::Cast(right).Value();
-  }
-
-  if (!CheckClassInstr::IsImmutableClassId(cid)) {
-    if ((cid == kOneByteStringCid) || (cid == kTwoByteStringCid)) {
-      SetTypeOf(defn, ZoneCompileType::Wrap(CompileType::String()));
-      PropagateRecursive((compare->kind() == Token::kEQ_STRICT) ?
-          branch->true_successor() : branch->false_successor());
-      RollbackTo(rollback_point);
-    }
-    return;
-  }
-
-  if (compare->kind() == Token::kEQ_STRICT) {
-    if (cid == kNullCid) {
-      branch->set_constrained_type(MarkNonNullable(defn));
-      PropagateRecursive(branch->false_successor());
-    }
-
-    SetCid(defn, cid);
-    PropagateRecursive(branch->true_successor());
-  } else if (compare->kind() == Token::kNE_STRICT) {
-    if (cid == kNullCid) {
-      branch->set_constrained_type(MarkNonNullable(defn));
-      PropagateRecursive(branch->true_successor());
-    }
-
-    SetCid(defn, cid);
-    PropagateRecursive(branch->false_successor());
-  }
-
-  RollbackTo(rollback_point);
-}
-
-
 void FlowGraphTypePropagator::RollbackTo(intptr_t rollback_point) {
   for (intptr_t i = rollback_.length() - 1; i >= rollback_point; i--) {
     types_[rollback_[i].index()] = rollback_[i].type();
@@ -1009,7 +953,7 @@
     abstract_type = &AbstractType::ZoneHandle(field.type());
   }
   ASSERT(field.is_static());
-  if (field.is_final()) {
+  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()) &&
diff --git a/runtime/vm/flow_graph_type_propagator.h b/runtime/vm/flow_graph_type_propagator.h
index 4b1baf4..3c10917 100644
--- a/runtime/vm/flow_graph_type_propagator.h
+++ b/runtime/vm/flow_graph_type_propagator.h
@@ -20,7 +20,6 @@
   void Propagate();
 
   void PropagateRecursive(BlockEntryInstr* block);
-  void HandleBranchOnStrictCompare(BlockEntryInstr* block);
 
   void RollbackTo(intptr_t rollback_point);
 
diff --git a/runtime/vm/gc_marker.cc b/runtime/vm/gc_marker.cc
index 2e63be3..45e84d2 100644
--- a/runtime/vm/gc_marker.cc
+++ b/runtime/vm/gc_marker.cc
@@ -499,12 +499,10 @@
 
 void GCMarker::IterateRoots(Isolate* isolate,
                             ObjectPointerVisitor* visitor,
-                            bool visit_prologue_weak_persistent_handles,
                             intptr_t slice_index, intptr_t num_slices) {
   ASSERT(0 <= slice_index && slice_index < num_slices);
   if ((slice_index == 0) || (num_slices <= 1)) {
     isolate->VisitObjectPointers(visitor,
-                                 visit_prologue_weak_persistent_handles,
                                  StackFrameIterator::kDontValidateFrames);
   }
   if ((slice_index == 1) || (num_slices <= 1)) {
@@ -516,73 +514,10 @@
 }
 
 
-void GCMarker::IterateWeakRoots(Isolate* isolate,
-                                HandleVisitor* visitor,
-                                bool visit_prologue_weak_persistent_handles) {
+void GCMarker::IterateWeakRoots(Isolate* isolate, HandleVisitor* visitor) {
   ApiState* state = isolate->api_state();
   ASSERT(state != NULL);
-  isolate->VisitWeakPersistentHandles(visitor,
-                                      visit_prologue_weak_persistent_handles);
-}
-
-
-template<class MarkingVisitorType>
-void GCMarker::IterateWeakReferences(Isolate* isolate,
-                                     MarkingVisitorType* visitor) {
-  ApiState* state = isolate->api_state();
-  ASSERT(state != NULL);
-  while (true) {
-    WeakReferenceSet* queue = state->delayed_weak_reference_sets();
-    if (queue == NULL) {
-      // The delay queue is empty therefore no clean-up is required.
-      return;
-    }
-    state->set_delayed_weak_reference_sets(NULL);
-    while (queue != NULL) {
-      WeakReferenceSet* reference_set = WeakReferenceSet::Pop(&queue);
-      ASSERT(reference_set != NULL);
-      intptr_t num_keys = reference_set->num_keys();
-      intptr_t num_values = reference_set->num_values();
-      if ((num_keys == 1) && (num_values == 1) &&
-          reference_set->SingletonKeyEqualsValue()) {
-        // We do not have to process sets that have just one key/value pair
-        // and the key and value are identical.
-        continue;
-      }
-      bool is_unreachable = true;
-      // Test each key object for reachability.  If a key object is
-      // reachable, all value objects should be marked.
-      for (intptr_t k = 0; k < num_keys; ++k) {
-        if (!IsUnreachable(*reference_set->get_key(k))) {
-          for (intptr_t v = 0; v < num_values; ++v) {
-            visitor->VisitPointer(reference_set->get_value(v));
-          }
-          is_unreachable = false;
-          // Since we have found a key object that is reachable and all
-          // value objects have been marked we can break out of iterating
-          // this set and move on to the next set.
-          break;
-        }
-      }
-      // If all key objects are unreachable put the reference on a
-      // delay queue.  This reference will be revisited if another
-      // reference is marked.
-      if (is_unreachable) {
-        state->DelayWeakReferenceSet(reference_set);
-      }
-    }
-    if (!visitor->DrainMarkingStack()) {
-      // Break out of the loop if there has been no forward process.
-      // All key objects in the weak reference sets are unreachable
-      // so we reset the weak reference sets queue.
-      state->set_delayed_weak_reference_sets(NULL);
-      break;
-    }
-  }
-  ASSERT(state->delayed_weak_reference_sets() == NULL);
-  // All weak reference sets are zone allocated and unmarked references which
-  // were on the delay queue will be freed when the zone is released in the
-  // epilog callback.
+  isolate->VisitWeakPersistentHandles(visitor);
 }
 
 
@@ -643,7 +578,6 @@
            DelaySet* delay_set,
            ThreadBarrier* barrier,
            bool collect_code,
-           bool visit_prologue_weak_persistent_handles,
            intptr_t task_index,
            intptr_t num_tasks,
            uintptr_t* num_busy)
@@ -655,8 +589,6 @@
         delay_set_(delay_set),
         barrier_(barrier),
         collect_code_(collect_code),
-        visit_prologue_weak_persistent_handles_(
-            visit_prologue_weak_persistent_handles),
         task_index_(task_index),
         num_tasks_(num_tasks),
         num_busy_(num_busy) {
@@ -672,9 +604,7 @@
       SyncMarkingVisitor visitor(isolate_, heap_, page_space_, marking_stack_,
                                  delay_set_, skipped_code_functions);
       // Phase 1: Iterate over roots and drain marking stack in tasks.
-      marker_->IterateRoots(isolate_, &visitor,
-                            visit_prologue_weak_persistent_handles_,
-                            task_index_, num_tasks_);
+      marker_->IterateRoots(isolate_, &visitor, task_index_, num_tasks_);
       do {
         visitor.DrainMarkingStack();
 
@@ -723,7 +653,6 @@
   DelaySet* delay_set_;
   ThreadBarrier* barrier_;
   bool collect_code_;
-  bool visit_prologue_weak_persistent_handles_;
   const intptr_t task_index_;
   const intptr_t num_tasks_;
   uintptr_t* num_busy_;
@@ -764,7 +693,6 @@
     Zone* zone = stack_zone.GetZone();
     MarkingStack marking_stack;
     DelaySet delay_set;
-    const bool visit_prologue_weak_persistent_handles = !invoke_api_callbacks;
     marked_bytes_ = 0;
     const int num_tasks = FLAG_marker_tasks;
     if (num_tasks == 0) {
@@ -773,13 +701,10 @@
           collect_code ? new(zone) SkippedCodeFunctions() : NULL;
       UnsyncMarkingVisitor mark(isolate, heap_, page_space, &marking_stack,
                                 &delay_set, skipped_code_functions);
-      IterateRoots(isolate, &mark, visit_prologue_weak_persistent_handles,
-                   0, 1);
+      IterateRoots(isolate, &mark, 0, 1);
       mark.DrainMarkingStack();
-      IterateWeakReferences(isolate, &mark);
       MarkingWeakVisitor mark_weak;
-      IterateWeakRoots(isolate, &mark_weak,
-                       !visit_prologue_weak_persistent_handles);
+      IterateWeakRoots(isolate, &mark_weak);
       // All marking done; detach code, etc.
       FinalizeResultsFrom(&mark);
     } else {
@@ -791,7 +716,6 @@
         MarkTask* mark_task =
             new MarkTask(this, isolate, heap_, page_space, &marking_stack,
                          &delay_set, &barrier, collect_code,
-                         visit_prologue_weak_persistent_handles,
                          i, num_tasks, &num_busy);
         ThreadPool* pool = Dart::thread_pool();
         pool->Run(mark_task);
@@ -803,10 +727,8 @@
           collect_code ? new(zone) SkippedCodeFunctions() : NULL;
       SyncMarkingVisitor mark(isolate, heap_, page_space, &marking_stack,
                               &delay_set, skipped_code_functions);
-      IterateWeakReferences(isolate, &mark);
       MarkingWeakVisitor mark_weak;
-      IterateWeakRoots(isolate, &mark_weak,
-                       !visit_prologue_weak_persistent_handles);
+      IterateWeakRoots(isolate, &mark_weak);
       barrier.Sync();
 
       // Phase 3: Finalize results from all markers (detach code, etc.).
diff --git a/runtime/vm/gc_marker.h b/runtime/vm/gc_marker.h
index 93b209a..f1e473a 100644
--- a/runtime/vm/gc_marker.h
+++ b/runtime/vm/gc_marker.h
@@ -38,11 +38,8 @@
   void Epilogue(Isolate* isolate, bool invoke_api_callbacks);
   void IterateRoots(Isolate* isolate,
                     ObjectPointerVisitor* visitor,
-                    bool visit_prologue_weak_persistent_handles,
                     intptr_t slice_index, intptr_t num_slices);
-  void IterateWeakRoots(Isolate* isolate,
-                        HandleVisitor* visitor,
-                        bool visit_prologue_weak_persistent_handles);
+  void IterateWeakRoots(Isolate* isolate, HandleVisitor* visitor);
   template<class MarkingVisitorType>
   void IterateWeakReferences(Isolate* isolate, MarkingVisitorType* visitor);
   void ProcessWeakTables(PageSpace* page_space);
diff --git a/runtime/vm/globals.h b/runtime/vm/globals.h
index 77e486a..f5eef18 100644
--- a/runtime/vm/globals.h
+++ b/runtime/vm/globals.h
@@ -27,8 +27,8 @@
 const intptr_t kSmiMax = (static_cast<intptr_t>(1) << kSmiBits) - 1;
 const intptr_t kSmiMin =  -(static_cast<intptr_t>(1) << kSmiBits);
 
-const double kPosInfinity = bit_cast<double>(DART_UINT64_C(0x7ff0000000000000));
-const double kNegInfinity = bit_cast<double>(DART_UINT64_C(0xfff0000000000000));
+#define kPosInfinity bit_cast<double>(DART_UINT64_C(0x7ff0000000000000))
+#define kNegInfinity bit_cast<double>(DART_UINT64_C(0xfff0000000000000))
 
 // The expression ARRAY_SIZE(array) is a compile-time constant of type
 // size_t which represents the number of elements of the given
diff --git a/runtime/vm/guard_field_test.cc b/runtime/vm/guard_field_test.cc
index 6d8c47c..d0ecb6e 100644
--- a/runtime/vm/guard_field_test.cc
+++ b/runtime/vm/guard_field_test.cc
@@ -4,7 +4,6 @@
 
 #include "vm/dart_api_impl.h"
 #include "vm/dart_api_state.h"
-#include "vm/intermediate_language.h"
 #include "vm/object.h"
 #include "vm/unit_test.h"
 
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 4b38ab3..52d5ce9 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -398,7 +398,8 @@
 
 
 EffectSet LoadStaticFieldInstr::Dependencies() const {
-  return StaticField().is_final() ? EffectSet::None() : EffectSet::All();
+  return (StaticField().is_final() && !FLAG_fields_may_be_reset)
+      ? EffectSet::None() : EffectSet::All();
 }
 
 
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 6d20157..f8133ef 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -7,7 +7,7 @@
 #include "include/dart_api.h"
 #include "include/dart_native_api.h"
 #include "platform/assert.h"
-#include "platform/json.h"
+#include "platform/text_buffer.h"
 #include "vm/class_finalizer.h"
 #include "vm/code_observers.h"
 #include "vm/compiler.h"
@@ -631,14 +631,6 @@
     }
   }
 
-  // Invoke the isolate's unhandled exception callback if there is one.
-  if (Isolate::UnhandledExceptionCallback() != NULL) {
-    Dart_EnterScope();
-    Dart_Handle error = Api::NewHandle(I, result.raw());
-    (Isolate::UnhandledExceptionCallback())(error);
-    Dart_ExitScope();
-  }
-
   // Generate the error and stacktrace strings for the error message.
   String& exc_str = String::Handle(T->zone());
   String& stacktrace_str = String::Handle(T->zone());
@@ -766,7 +758,6 @@
       simulator_(NULL),
       mutex_(new Mutex()),
       saved_stack_limit_(0),
-      stack_base_(0),
       stack_overflow_flags_(0),
       stack_overflow_count_(0),
       message_handler_(NULL),
@@ -798,7 +789,9 @@
       field_invalidation_gen_(kInvalidGen),
       prefix_invalidation_gen_(kInvalidGen) {
   flags_.CopyFrom(api_flags);
-  Thread::Current()->set_vm_tag(VMTag::kEmbedderTagId);
+  // TODO(asiva): A Thread is not available here, need to figure out
+  // how the vm_tag (kEmbedderTagId) can be set, these tags need to
+  // move to the OSThread structure.
   set_user_tag(UserTags::kDefaultUserTag);
 }
 
@@ -987,19 +980,7 @@
 }
 
 
-// TODO(5411455): Use flag to override default value and Validate the
-// stack size by querying OS.
-uword Isolate::GetSpecifiedStackSize() {
-  ASSERT(Isolate::kStackSizeBuffer < OSThread::GetMaxStackSize());
-  uword stack_size = OSThread::GetMaxStackSize() - Isolate::kStackSizeBuffer;
-  return stack_size;
-}
-
-
 void Isolate::SetStackLimitFromStackBase(uword stack_base) {
-  // Set stack base.
-  stack_base_ = stack_base;
-
   // Set stack limit.
 #if defined(USING_SIMULATOR)
   // Ignore passed-in native stack top and use Simulator stack top.
@@ -1008,7 +989,7 @@
   stack_base = sim->StackTop();
   // The overflow area is accounted for by the simulator.
 #endif
-  SetStackLimit(stack_base - GetSpecifiedStackSize());
+  SetStackLimit(stack_base - OSThread::GetSpecifiedStackSize());
 }
 
 
@@ -1026,19 +1007,6 @@
 
 void Isolate::ClearStackLimit() {
   SetStackLimit(~static_cast<uword>(0));
-  stack_base_ = 0;
-}
-
-
-bool Isolate::GetProfilerStackBounds(uword* lower, uword* upper) const {
-  uword stack_upper = stack_base_;
-  if (stack_upper == 0) {
-    return false;
-  }
-  uword stack_lower = stack_upper - GetSpecifiedStackSize();
-  *lower = stack_lower;
-  *upper = stack_upper;
-  return true;
 }
 
 
@@ -1322,7 +1290,6 @@
 static MessageHandler::MessageStatus RunIsolate(uword parameter) {
   Isolate* isolate = reinterpret_cast<Isolate*>(parameter);
   IsolateSpawnState* state = NULL;
-  Thread* thread = Thread::Current();
   {
     // TODO(turnidge): Is this locking required here at all anymore?
     MutexLocker ml(isolate->mutex());
@@ -1330,6 +1297,7 @@
   }
   {
     StartIsolateScope start_scope(isolate);
+    Thread* thread = Thread::Current();
     ASSERT(thread->isolate() == isolate);
     StackZone zone(thread);
     HandleScope handle_scope(thread);
@@ -1432,8 +1400,8 @@
   {
     // Print the error if there is one.  This may execute dart code to
     // print the exception object, so we need to use a StartIsolateScope.
-    Thread* thread = Thread::Current();
     StartIsolateScope start_scope(isolate);
+    Thread* thread = Thread::Current();
     ASSERT(thread->isolate() == isolate);
     StackZone zone(thread);
     HandleScope handle_scope(thread);
@@ -1505,18 +1473,6 @@
 }
 
 
-static int MostUsedFunctionFirst(const Function* const* a,
-                                 const Function* const* b) {
-  if ((*a)->usage_counter() > (*b)->usage_counter()) {
-    return -1;
-  } else if ((*a)->usage_counter() < (*b)->usage_counter()) {
-    return 1;
-  } else {
-    return 0;
-  }
-}
-
-
 void Isolate::AddClosureFunction(const Function& function) const {
   GrowableObjectArray& closures =
       GrowableObjectArray::Handle(object_store()->closure_functions());
@@ -1573,47 +1529,6 @@
 }
 
 
-static void AddFunctionsFromClass(const Class& cls,
-                                  GrowableArray<const Function*>* functions) {
-  const Array& class_functions = Array::Handle(cls.functions());
-  // Class 'dynamic' is allocated/initialized in a special way, leaving
-  // the functions field NULL instead of empty.
-  const int func_len = class_functions.IsNull() ? 0 : class_functions.Length();
-  for (int j = 0; j < func_len; j++) {
-    Function& function = Function::Handle();
-    function ^= class_functions.At(j);
-    if (function.usage_counter() > 0) {
-      functions->Add(&function);
-    }
-  }
-}
-
-
-void Isolate::PrintInvokedFunctions() {
-  ASSERT(this == Isolate::Current());
-  const GrowableObjectArray& libraries =
-      GrowableObjectArray::Handle(object_store()->libraries());
-  Library& library = Library::Handle();
-  GrowableArray<const Function*> invoked_functions;
-  for (int i = 0; i < libraries.Length(); i++) {
-    library ^= libraries.At(i);
-    Class& cls = Class::Handle();
-    ClassDictionaryIterator iter(library,
-                                 ClassDictionaryIterator::kIteratePrivate);
-    while (iter.HasNext()) {
-      cls = iter.GetNextClass();
-      AddFunctionsFromClass(cls, &invoked_functions);
-    }
-  }
-  invoked_functions.Sort(MostUsedFunctionFirst);
-  for (int i = 0; i < invoked_functions.length(); i++) {
-    OS::Print("%10" Pd " x %s\n",
-        invoked_functions[i]->usage_counter(),
-        invoked_functions[i]->ToFullyQualifiedCString());
-  }
-}
-
-
 class FinalizeWeakPersistentHandlesVisitor : public HandleVisitor {
  public:
   FinalizeWeakPersistentHandlesVisitor() : HandleVisitor(Thread::Current()) {
@@ -1670,7 +1585,6 @@
   // Finalize any weak persistent handles with a non-null referent.
   FinalizeWeakPersistentHandlesVisitor visitor;
   api_state()->weak_persistent_handles().VisitHandles(&visitor);
-  api_state()->prologue_weak_persistent_handles().VisitHandles(&visitor);
 
   if (FLAG_trace_isolates) {
     heap()->PrintSizes();
@@ -1695,7 +1609,9 @@
 void Isolate::Shutdown() {
   ASSERT(this == Isolate::Current());
   // Wait until all background compilation has finished.
-  BackgroundCompiler::Stop(background_compiler_);
+  if (background_compiler_ != NULL) {
+    BackgroundCompiler::Stop(background_compiler_);
+  }
 
 #if defined(DEBUG)
   if (heap_ != NULL) {
@@ -1758,15 +1674,10 @@
   // TODO(5411455): For now just make sure there are no current isolates
   // as we are shutting down the isolate.
   Thread::ExitIsolate();
-  // All threads should have exited by now.
-  thread_registry()->CheckNotScheduled(this);
 }
 
 
 Dart_IsolateCreateCallback Isolate::create_callback_ = NULL;
-Dart_IsolateInterruptCallback Isolate::interrupt_callback_ = NULL;
-Dart_IsolateUnhandledExceptionCallback
-    Isolate::unhandled_exception_callback_ = NULL;
 Dart_IsolateShutdownCallback Isolate::shutdown_callback_ = NULL;
 Dart_FileOpenCallback Isolate::file_open_callback_ = NULL;
 Dart_FileReadCallback Isolate::file_read_callback_ = NULL;
@@ -1779,15 +1690,13 @@
 bool Isolate::creation_enabled_ = false;
 
 void Isolate::IterateObjectPointers(ObjectPointerVisitor* visitor,
-                                    bool visit_prologue_weak_handles,
                                     bool validate_frames) {
   HeapIterationScope heap_iteration_scope;
-  VisitObjectPointers(visitor, visit_prologue_weak_handles, validate_frames);
+  VisitObjectPointers(visitor, validate_frames);
 }
 
 
 void Isolate::VisitObjectPointers(ObjectPointerVisitor* visitor,
-                                  bool visit_prologue_weak_handles,
                                   bool validate_frames) {
   ASSERT(visitor != NULL);
 
@@ -1802,7 +1711,7 @@
 
   // Visit the dart api state for all local and persistent handles.
   if (api_state() != NULL) {
-    api_state()->VisitObjectPointers(visitor, visit_prologue_weak_handles);
+    api_state()->VisitObjectPointers(visitor);
   }
 
   // Visit the current tag which is stored in the isolate.
@@ -1843,17 +1752,9 @@
 }
 
 
-void Isolate::VisitWeakPersistentHandles(HandleVisitor* visitor,
-                                         bool visit_prologue_weak_handles) {
+void Isolate::VisitWeakPersistentHandles(HandleVisitor* visitor) {
   if (api_state() != NULL) {
-    api_state()->VisitWeakHandles(visitor, visit_prologue_weak_handles);
-  }
-}
-
-
-void Isolate::VisitPrologueWeakPersistentHandles(HandleVisitor* visitor) {
-  if (api_state() != NULL) {
-    api_state()->VisitPrologueWeakHandles(visitor);
+    api_state()->VisitWeakHandles(visitor);
   }
 }
 
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 547ce08..95068b7 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -121,13 +121,10 @@
 
   // Visit all object pointers.
   void IterateObjectPointers(ObjectPointerVisitor* visitor,
-                             bool visit_prologue_weak_persistent_handles,
                              bool validate_frames);
 
   // Visits weak object pointers.
-  void VisitWeakPersistentHandles(HandleVisitor* visitor,
-                                  bool visit_prologue_weak_persistent_handles);
-  void VisitPrologueWeakPersistentHandles(HandleVisitor* visitor);
+  void VisitWeakPersistentHandles(HandleVisitor* visitor);
 
   StoreBuffer* store_buffer() { return store_buffer_; }
 
@@ -254,8 +251,6 @@
   // The true stack limit for this isolate.
   uword saved_stack_limit() const { return saved_stack_limit_; }
 
-  uword stack_base() const { return stack_base_; }
-
   // Stack overflow flags
   enum {
     kOsrRequest = 0x1,  // Current stack overflow caused by OSR request.
@@ -274,13 +269,6 @@
   // stack overflow is called.
   uword GetAndClearStackOverflowFlags();
 
-  // Retrieve the stack address bounds for profiler.
-  bool GetProfilerStackBounds(uword* lower, uword* upper) const;
-
-  static uword GetSpecifiedStackSize();
-
-  static const intptr_t kStackSizeBuffer = (4 * KB * kWordSize);
-
   // Interrupt bits.
   enum {
     kVMInterrupt = 0x1,  // Internal VM checks: safepoints, store buffers, etc.
@@ -442,21 +430,6 @@
     return create_callback_;
   }
 
-  static void SetInterruptCallback(Dart_IsolateInterruptCallback cb) {
-    interrupt_callback_ = cb;
-  }
-  static Dart_IsolateInterruptCallback InterruptCallback() {
-    return interrupt_callback_;
-  }
-
-  static void SetUnhandledExceptionCallback(
-      Dart_IsolateUnhandledExceptionCallback cb) {
-    unhandled_exception_callback_ = cb;
-  }
-  static Dart_IsolateUnhandledExceptionCallback UnhandledExceptionCallback() {
-    return unhandled_exception_callback_;
-  }
-
   static void SetShutdownCallback(Dart_IsolateShutdownCallback cb) {
     shutdown_callback_ = cb;
   }
@@ -697,15 +670,12 @@
   void Shutdown();
 
   void BuildName(const char* name_prefix);
-  void PrintInvokedFunctions();
 
   void ProfileIdle();
 
   // Visit all object pointers. Caller must ensure concurrent sweeper is not
   // running, and the visitor must not allocate.
-  void VisitObjectPointers(ObjectPointerVisitor* visitor,
-                           bool visit_prologue_weak_persistent_handles,
-                           bool validate_frames);
+  void VisitObjectPointers(ObjectPointerVisitor* visitor, bool validate_frames);
 
   void set_user_tag(uword tag) {
     user_tag_ = tag;
@@ -742,6 +712,8 @@
   }
 
   // Accessed from generated code:
+  // TODO(asiva): Need to consider moving the stack_limit_ from isolate to
+  // being thread specific.
   uword stack_limit_;
   StoreBuffer* store_buffer_;
   Heap* heap_;
@@ -777,7 +749,6 @@
   Simulator* simulator_;
   Mutex* mutex_;  // protects stack_limit_, saved_stack_limit_, compiler stats.
   uword saved_stack_limit_;
-  uword stack_base_;
   uword stack_overflow_flags_;
   int32_t stack_overflow_count_;
   MessageHandler* message_handler_;
@@ -863,8 +834,6 @@
 #undef ISOLATE_TIMELINE_STREAM_VARIABLE
 
   static Dart_IsolateCreateCallback create_callback_;
-  static Dart_IsolateInterruptCallback interrupt_callback_;
-  static Dart_IsolateUnhandledExceptionCallback unhandled_exception_callback_;
   static Dart_IsolateShutdownCallback shutdown_callback_;
   static Dart_FileOpenCallback file_open_callback_;
   static Dart_FileReadCallback file_read_callback_;
@@ -914,7 +883,7 @@
     if (saved_isolate_ != new_isolate_) {
       ASSERT(Isolate::Current() == NULL);
       // Ensure this is not a nested 'isolate enter' with prior state.
-      ASSERT(new_isolate_->stack_base() == 0);
+      ASSERT(new_isolate_->saved_stack_limit() == 0);
       Thread::EnterIsolate(new_isolate_);
     }
   }
@@ -928,7 +897,7 @@
     if (saved_isolate_ != new_isolate_) {
       ASSERT(saved_isolate_ == NULL);
       // ASSERT that we have bottomed out of all Dart invocations.
-      ASSERT(new_isolate_->stack_base() == 0);
+      ASSERT(new_isolate_->saved_stack_limit() == 0);
       Thread::ExitIsolate();
     }
   }
diff --git a/runtime/vm/json_stream.h b/runtime/vm/json_stream.h
index 318702c..92cbc4e 100644
--- a/runtime/vm/json_stream.h
+++ b/runtime/vm/json_stream.h
@@ -6,7 +6,7 @@
 #define VM_JSON_STREAM_H_
 
 #include "include/dart_api.h"  // for Dart_Port
-#include "platform/json.h"
+#include "platform/text_buffer.h"
 #include "vm/allocation.h"
 #include "vm/service.h"
 
diff --git a/runtime/vm/json_test.cc b/runtime/vm/json_test.cc
index 6ca6760..245bdd6 100644
--- a/runtime/vm/json_test.cc
+++ b/runtime/vm/json_test.cc
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 #include "platform/assert.h"
-#include "platform/json.h"
+#include "platform/text_buffer.h"
 #include "vm/json_stream.h"
 #include "vm/unit_test.h"
 #include "vm/dart_api_impl.h"
@@ -11,131 +11,12 @@
 namespace dart {
 
 
-TEST_CASE(JSON_ScanJSON) {
-  const char* msg = "{ \"id\": 5, \"command\" : \"Debugger.pause\" }";
-
-  JSONScanner scanner(msg);
-  EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenIllegal);
-  scanner.Scan();
-  EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenLBrace);
-  scanner.Scan();
-  EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenString);
-  EXPECT(scanner.IsStringLiteral("id"));
-  scanner.Scan();
-  EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenColon);
-  scanner.Scan();
-  EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenInteger);
-  scanner.Scan();
-  EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenComma);
-  scanner.Scan();
-  EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenString);
-  EXPECT(scanner.IsStringLiteral("command"));
-  scanner.Scan();
-  EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenColon);
-  scanner.Scan();
-  EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenString);
-  EXPECT(scanner.IsStringLiteral("Debugger.pause"));
-  scanner.Scan();
-  EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenRBrace);
-  scanner.Scan();
-  EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenEOM);
-}
-
-
-TEST_CASE(JSON_SyntaxError) {
-    const char* jobj = "{ \"id\": 5, "
-                     "  \"command\" : \"Debugger.stop\""  // Missing comma.
-                     "  \"params\" : { "
-                     "    \"url\" : \"blah.dart\", "  // Missing comma.
-                     "    \"line\": 111, "
-                     "  },"
-                     "  \"foo\": \"outer foo\", "
-                     "}";
-  JSONReader reader(jobj);
-  bool found;
-
-  found = reader.Seek("id");
-  EXPECT(found);
-  EXPECT_EQ(reader.Type(), JSONReader::kInteger);
-  found = reader.Seek("params");
-  EXPECT(!found);
-  EXPECT(reader.Error());
-  EXPECT_EQ(reader.Type(), JSONReader::kNone);
-  EXPECT_EQ(0, reader.ValueLen());
-  EXPECT(reader.ValueChars() == NULL);
-}
-
-
-TEST_CASE(JSON_JSONReader) {
-  const char* jobj = "{ \"id\": 5, "
-                     "  \"command\" : \"Debugger.setBreakpoint\","
-                     "  \"params\" : { "
-                     "    \"url\" : \"blah.dart\", "
-                     "    \"foo\" : [null, 1, { }, \"bar\", true, false],"
-                     "    \"line\": 111, "
-                     "  },"
-                     "  \"foo\": \"outer foo\",     "
-                     "  \"quote\": \"\\\"\",        "
-                     "  \"white\": \"\\t \\n\",     "
-                     "}";
-
-  JSONReader reader(jobj);
-  bool found;
-  char s[128];
-
-  found = reader.Seek("id");
-  EXPECT(found);
-  EXPECT_EQ(reader.Type(), JSONReader::kInteger);
-  found = reader.Seek("foo");
-  EXPECT(found);
-  EXPECT_EQ(reader.Type(), JSONReader::kString);
-  EXPECT(reader.IsStringLiteral("outer foo"));
-
-  found = reader.Seek("quote");
-  EXPECT(found);
-  EXPECT_EQ(reader.Type(), JSONReader::kString);
-  reader.GetRawValueChars(s, sizeof s);
-  EXPECT_STREQ("\\\"", s);
-  reader.GetDecodedValueChars(s, sizeof s);
-  EXPECT_STREQ("\"", s);
-
-  found = reader.Seek("white");
-  EXPECT(found);
-  EXPECT_EQ(reader.Type(), JSONReader::kString);
-  reader.GetRawValueChars(s, sizeof s);
-  EXPECT_STREQ("\\t \\n", s);
-  reader.GetDecodedValueChars(s, sizeof s);
-  EXPECT_STREQ("\t \n", s);
-
-  found = reader.Seek("line");
-  EXPECT(!found);
-  found = reader.Seek("params");
-  EXPECT(found);
-  EXPECT_EQ(reader.Type(), JSONReader::kObject);
-  reader.Set(reader.ValueChars());
-  found = reader.Seek("foo");
-  EXPECT(found);
-  EXPECT_EQ(reader.Type(), JSONReader::kArray);
-  found = reader.Seek("non-existing");
-  EXPECT(!found);
-  found = reader.Seek("line");
-  EXPECT(found);
-  EXPECT_EQ(reader.Type(), JSONReader::kInteger);
-}
-
-
 TEST_CASE(JSON_TextBuffer) {
   TextBuffer w(5);  // Small enough to make buffer grow at least once.
   w.Printf("{ \"%s\" : %d", "length", 175);
   EXPECT_STREQ("{ \"length\" : 175", w.buf());
   w.Printf(", \"%s\" : \"%s\" }", "command", "stopIt");
   EXPECT_STREQ("{ \"length\" : 175, \"command\" : \"stopIt\" }", w.buf());
-
-  JSONReader r(w.buf());
-  bool found = r.Seek("command");
-  EXPECT(found);
-  EXPECT_EQ(r.Type(), JSONReader::kString);
-  EXPECT(r.IsStringLiteral("stopIt"));
 }
 
 
diff --git a/runtime/vm/locations.cc b/runtime/vm/locations.cc
index e460a2d..de4f773 100644
--- a/runtime/vm/locations.cc
+++ b/runtime/vm/locations.cc
@@ -6,8 +6,6 @@
 
 #include "vm/assembler.h"
 #include "vm/il_printer.h"
-#include "vm/intermediate_language.h"
-#include "vm/flow_graph_compiler.h"
 #include "vm/log.h"
 #include "vm/stack_frame.h"
 
diff --git a/runtime/vm/log.cc b/runtime/vm/log.cc
index e29432f..d576beb 100644
--- a/runtime/vm/log.cc
+++ b/runtime/vm/log.cc
@@ -32,7 +32,9 @@
   Thread* thread = Thread::Current();
   Isolate* isolate = thread->isolate();
   if (isolate != NULL && Log::ShouldLogForIsolate(isolate)) {
-    return thread->log();
+    OSThread* os_thread = thread->os_thread();
+    ASSERT(os_thread != NULL);
+    return os_thread->log();
   } else {
     return Log::NoOpLog();
   }
diff --git a/runtime/vm/message_handler_test.cc b/runtime/vm/message_handler_test.cc
index ae7edab..314eb7c 100644
--- a/runtime/vm/message_handler_test.cc
+++ b/runtime/vm/message_handler_test.cc
@@ -399,7 +399,7 @@
   info.handler = &handler;
   info.ports = ports;
   info.count = 10;
-  OSThread::Start(SendMessages, reinterpret_cast<uword>(&info));
+  OSThread::Start("SendMessages", SendMessages, reinterpret_cast<uword>(&info));
   while (sleep < kMaxSleep && handler.message_count() < 11) {
     OS::Sleep(10);
     sleep += 10;
diff --git a/runtime/vm/mirrors_api_impl.cc b/runtime/vm/mirrors_api_impl.cc
index 13b896c..4d0a348 100644
--- a/runtime/vm/mirrors_api_impl.cc
+++ b/runtime/vm/mirrors_api_impl.cc
@@ -30,7 +30,7 @@
   const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object));
   if (obj.IsType()) {
     const Class& cls = Class::Handle(Type::Cast(obj).type_class());
-    return Api::NewHandle(I, cls.UserVisibleName());
+    return Api::NewHandle(T, cls.UserVisibleName());
   } else {
     RETURN_TYPE_ERROR(Z, object, Class/Type);
   }
@@ -48,7 +48,7 @@
       RETURN_NULL_ERROR(str);
     }
     CHECK_CALLBACK_STATE(T);
-    return Api::NewHandle(I, String::New(str));
+    return Api::NewHandle(T, String::New(str));
   } else {
     RETURN_TYPE_ERROR(Z, object, Class/Type);
   }
@@ -85,7 +85,7 @@
     const Class& cls = Class::Handle(Z, Type::Cast(obj).type_class());
     const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(T));
     if (!error.IsNull()) {
-      return Api::NewHandle(I, error.raw());
+      return Api::NewHandle(T, error.raw());
     }
     const Array& func_array = Array::Handle(Z, cls.functions());
 
@@ -124,7 +124,7 @@
         "%s expects argument 'target' to be a class or library.",
         CURRENT_FUNC);
   }
-  return Api::NewHandle(I, Array::MakeArray(names));
+  return Api::NewHandle(T, Array::MakeArray(names));
 }
 
 
@@ -205,7 +205,7 @@
            func_kind == RawFunction::kConstructor);
   }
 #endif
-  return Api::NewHandle(I, func.raw());
+  return Api::NewHandle(T, func.raw());
 }
 
 
@@ -215,7 +215,7 @@
   if (func.IsNull()) {
     RETURN_TYPE_ERROR(Z, function, Function);
   }
-  return Api::NewHandle(I, func.UserVisibleName());
+  return Api::NewHandle(T, func.UserVisibleName());
 }
 
 
@@ -227,7 +227,7 @@
   }
   if (func.IsNonImplicitClosureFunction()) {
     RawFunction* parent_function = func.parent_function();
-    return Api::NewHandle(I, parent_function);
+    return Api::NewHandle(T, parent_function);
   }
   const Class& owner = Class::Handle(Z, func.Owner());
   ASSERT(!owner.IsNull());
@@ -240,9 +240,9 @@
       ASSERT(owner.IsDynamicClass() || owner.IsVoidClass());
     }
 #endif
-    return Api::NewHandle(I, owner.library());
+    return Api::NewHandle(T, owner.library());
   } else {
-    return Api::NewHandle(I, owner.RareType());
+    return Api::NewHandle(T, owner.RareType());
   }
 }
 
@@ -317,7 +317,7 @@
   }
   const String& name = String::Handle(Z, lib.name());
   ASSERT(!name.IsNull());
-  return Api::NewHandle(I, name.raw());
+  return Api::NewHandle(T, name.raw());
 }
 
 DART_EXPORT Dart_Handle Dart_LibraryGetClassNames(Dart_Handle library) {
@@ -347,7 +347,7 @@
       names.Add(name);
     }
   }
-  return Api::NewHandle(I, Array::MakeArray(names));
+  return Api::NewHandle(T, Array::MakeArray(names));
 }
 
 
@@ -363,7 +363,7 @@
   ASSERT(ClassFinalizer::AllClassesFinalized());
 
   RawFunction* rf = Closure::function(closure_obj);
-  return Api::NewHandle(I, rf);
+  return Api::NewHandle(T, rf);
 }
 
 }  // namespace dart
diff --git a/runtime/vm/native_api_impl.cc b/runtime/vm/native_api_impl.cc
index 9395bf3..c707c9e 100644
--- a/runtime/vm/native_api_impl.cc
+++ b/runtime/vm/native_api_impl.cc
@@ -22,6 +22,27 @@
 }
 
 
+class IsolateSaver {
+ public:
+  explicit IsolateSaver(Isolate* current_isolate)
+      : saved_isolate_(current_isolate) {
+    if (current_isolate != NULL) {
+      ASSERT(current_isolate == Isolate::Current());
+      Thread::ExitIsolate();
+    }
+  }
+  ~IsolateSaver() {
+    if (saved_isolate_ != NULL) {
+      Thread::EnterIsolate(saved_isolate_);
+    }
+  }
+ private:
+  Isolate* saved_isolate_;
+
+  DISALLOW_COPY_AND_ASSIGN(IsolateSaver);
+};
+
+
 DART_EXPORT bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message) {
   uint8_t* buffer = NULL;
   ApiMessageWriter writer(&buffer, allocator);
@@ -48,7 +69,6 @@
   }
   // Start the native port without a current isolate.
   IsolateSaver saver(Isolate::Current());
-  Thread::ExitIsolate();
 
   NativeMessageHandler* nmh = new NativeMessageHandler(name, handler);
   Dart_Port port_id = PortMap::CreatePort(nmh);
@@ -60,7 +80,6 @@
 DART_EXPORT bool Dart_CloseNativePort(Dart_Port native_port_id) {
   // Close the native port without a current isolate.
   IsolateSaver saver(Isolate::Current());
-  Thread::ExitIsolate();
 
   // TODO(turnidge): Check that the port is native before trying to close.
   return PortMap::ClosePort(native_port_id);
@@ -75,14 +94,14 @@
   if (error.IsNull()) {
     *result = Api::Success();
   } else {
-    *result = Api::NewHandle(thread->isolate(), error.raw());
+    *result = Api::NewHandle(thread, error.raw());
   }
 }
 
 
 DART_EXPORT Dart_Handle Dart_CompileAll() {
   DARTSCOPE(Thread::Current());
-  Dart_Handle result = Api::CheckAndFinalizePendingClasses(I);
+  Dart_Handle result = Api::CheckAndFinalizePendingClasses(T);
   if (::Dart_IsError(result)) {
     return result;
   }
diff --git a/runtime/vm/native_entry.cc b/runtime/vm/native_entry.cc
index adedfb7..92a99e8 100644
--- a/runtime/vm/native_entry.cc
+++ b/runtime/vm/native_entry.cc
@@ -36,7 +36,7 @@
   Dart_EnterScope();  // Enter a new Dart API scope as we invoke API entries.
   Dart_NativeEntryResolver resolver = library.native_entry_resolver();
   Dart_NativeFunction native_function =
-      resolver(Api::NewHandle(Isolate::Current(), function_name.raw()),
+      resolver(Api::NewHandle(Thread::Current(), function_name.raw()),
                number_of_arguments, auto_setup_scope);
   Dart_ExitScope();  // Exit the Dart API scope.
   return reinterpret_cast<NativeFunction>(native_function);
@@ -98,8 +98,8 @@
 
   ApiState* state = isolate->api_state();
   ASSERT(state != NULL);
-  ApiLocalScope* current_top_scope = state->top_scope();
-  ApiLocalScope* scope = state->reusable_scope();
+  ApiLocalScope* current_top_scope = thread->api_top_scope();
+  ApiLocalScope* scope = thread->api_reusable_scope();
   TRACE_NATIVE_CALL("0x%" Px "", reinterpret_cast<uintptr_t>(func));
   if (scope == NULL) {
     scope = new ApiLocalScope(current_top_scope,
@@ -109,19 +109,19 @@
     scope->Reinit(thread,
                   current_top_scope,
                   thread->top_exit_frame_info());
-    state->set_reusable_scope(NULL);
+    thread->set_api_reusable_scope(NULL);
   }
-  state->set_top_scope(scope);  // New scope is now the top scope.
+  thread->set_api_top_scope(scope);  // New scope is now the top scope.
 
   func(args);
 
   ASSERT(current_top_scope == scope->previous());
-  state->set_top_scope(current_top_scope);  // Reset top scope to previous.
-  if (state->reusable_scope() == NULL) {
+  thread->set_api_top_scope(current_top_scope);  // Reset top scope to previous.
+  if (thread->api_reusable_scope() == NULL) {
     scope->Reset(thread);  // Reset the old scope which we just exited.
-    state->set_reusable_scope(scope);
+    thread->set_api_reusable_scope(scope);
   } else {
-    ASSERT(state->reusable_scope() != scope);
+    ASSERT(thread->api_reusable_scope() != scope);
     delete scope;
   }
   DEOPTIMIZE_ALOT;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 2e4bf4a..169b42e 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -74,9 +74,9 @@
 DECLARE_FLAG(bool, write_protect_code);
 
 
-static const char* kGetterPrefix = "get:";
+static const char* const kGetterPrefix = "get:";
 static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix);
-static const char* kSetterPrefix = "set:";
+static const char* const kSetterPrefix = "set:";
 static const intptr_t kSetterPrefixLength = strlen(kSetterPrefix);
 
 // A cache of VM heap allocated preinitialized empty ic data entry arrays.
@@ -2218,29 +2218,6 @@
 }
 
 
-intptr_t Class::FindFunctionIndex(const Function& needle) const {
-  Thread* thread = Thread::Current();
-  if (EnsureIsFinalized(thread) != Error::null()) {
-    return -1;
-  }
-  REUSABLE_ARRAY_HANDLESCOPE(thread);
-  REUSABLE_FUNCTION_HANDLESCOPE(thread);
-  Array& funcs = thread->ArrayHandle();
-  Function& function = thread->FunctionHandle();
-  funcs ^= functions();
-  ASSERT(!funcs.IsNull());
-  const intptr_t len = funcs.Length();
-  for (intptr_t i = 0; i < len; i++) {
-    function ^= funcs.At(i);
-    if (function.raw() == needle.raw()) {
-      return i;
-    }
-  }
-  // No function found.
-  return -1;
-}
-
-
 RawFunction* Class::FunctionFromIndex(intptr_t idx) const {
   const Array& funcs = Array::Handle(functions());
   if ((idx < 0) || (idx >= funcs.Length())) {
@@ -2868,8 +2845,8 @@
   // Shared handles used during the iteration.
   String& member_name = String::Handle();
 
-  const PatchClass& patch_class =
-      PatchClass::Handle(PatchClass::New(*this, patch));
+  const PatchClass& patch_class = PatchClass::Handle(
+      PatchClass::New(*this, Script::Handle(patch.script())));
 
   Array& orig_list = Array::Handle(functions());
   intptr_t orig_len = orig_list.Length();
@@ -2971,8 +2948,10 @@
   SetFields(new_list);
 
   // The functions and fields in the patch class are no longer needed.
+  // The patch class itself is also no longer needed.
   patch.SetFunctions(Object::empty_array());
   patch.SetFields(Object::empty_array());
+  Library::Handle(patch.library()).RemovePatchClass(patch);
   return true;
 }
 
@@ -3097,46 +3076,6 @@
 }
 
 
-intptr_t Class::FindFieldIndex(const Field& needle) const {
-  Thread* thread = Thread::Current();
-  if (EnsureIsFinalized(thread) != Error::null()) {
-    return -1;
-  }
-  REUSABLE_ARRAY_HANDLESCOPE(thread);
-  REUSABLE_FIELD_HANDLESCOPE(thread);
-  REUSABLE_STRING_HANDLESCOPE(thread);
-  Array& fields_array = thread->ArrayHandle();
-  Field& field = thread->FieldHandle();
-  String& field_name = thread->StringHandle();
-  fields_array ^= fields();
-  ASSERT(!fields_array.IsNull());
-  String& needle_name = String::Handle(thread->zone());
-  needle_name ^= needle.name();
-  const intptr_t len = fields_array.Length();
-  for (intptr_t i = 0; i < len; i++) {
-    field ^= fields_array.At(i);
-    field_name ^= field.name();
-    if (field_name.Equals(needle_name)) {
-      return i;
-    }
-  }
-  // No field found.
-  return -1;
-}
-
-
-RawField* Class::FieldFromIndex(intptr_t idx) const {
-  const Array& flds = Array::Handle(fields());
-  if ((idx < 0) || (idx >= flds.Length())) {
-    return Field::null();
-  }
-  Field& field = Field::Handle();
-  field ^= flds.At(idx);
-  ASSERT(!field.IsNull());
-  return field.raw();
-}
-
-
 template <class FakeInstance>
 RawClass* Class::New(intptr_t index) {
   ASSERT(Object::class_class() != Class::null());
@@ -3600,6 +3539,14 @@
 }
 
 
+void Class::ResetFinalization() const {
+  ASSERT(IsTopLevel());
+  set_state_bits(ClassFinalizedBits::update(RawClass::kAllocated,
+                                            raw_ptr()->state_bits_));
+  set_state_bits(TypeFinalizedBit::update(false, raw_ptr()->state_bits_));
+}
+
+
 void Class::set_is_prefinalized() const {
   ASSERT(!is_finalized());
   set_state_bits(ClassFinalizedBits::update(RawClass::kPreFinalized,
@@ -3634,25 +3581,9 @@
 }
 
 
-void Class::SetPatchClass(const Class& cls) const {
-  ASSERT(GetPatchClass() == Class::null());
-  const GrowableObjectArray& patch_classes =
-      GrowableObjectArray::Handle(Library::Handle(library()).patch_classes());
-  patch_classes.Add(cls);
-}
-
-
 RawClass* Class::GetPatchClass() const {
-  const GrowableObjectArray& patch_classes =
-      GrowableObjectArray::Handle(Library::Handle(library()).patch_classes());
-  Class& pc = Class::Handle();
-  for (intptr_t i = 0; i < patch_classes.Length(); i++) {
-    pc ^= patch_classes.At(i);
-    if (pc.Name() == this->Name()) {  // Names are canonicalized.
-      return pc.raw();
-    }
-  }
-  return Class::null();
+  const Library& lib = Library::Handle(library());
+  return lib.GetPatchClass(String::Handle(Name()));
 }
 
 
@@ -5252,10 +5183,21 @@
 
 
 RawPatchClass* PatchClass::New(const Class& patched_class,
-                               const Class& source_class) {
+                               const Class& origin_class) {
   const PatchClass& result = PatchClass::Handle(PatchClass::New());
   result.set_patched_class(patched_class);
-  result.set_source_class(source_class);
+  result.set_origin_class(origin_class);
+  result.set_script(Script::Handle(origin_class.script()));
+  return result.raw();
+}
+
+
+RawPatchClass* PatchClass::New(const Class& patched_class,
+                               const Script& script) {
+  const PatchClass& result = PatchClass::Handle(PatchClass::New());
+  result.set_patched_class(patched_class);
+  result.set_origin_class(patched_class);
+  result.set_script(script);
   return result.raw();
 }
 
@@ -5269,19 +5211,18 @@
 }
 
 
-RawScript* PatchClass::Script() const {
-  const Class& source_class = Class::Handle(this->source_class());
-  return source_class.script();
-}
-
-
 void PatchClass::set_patched_class(const Class& value) const {
   StorePointer(&raw_ptr()->patched_class_, value.raw());
 }
 
 
-void PatchClass::set_source_class(const Class& value) const {
-  StorePointer(&raw_ptr()->source_class_, value.raw());
+void PatchClass::set_origin_class(const Class& value) const {
+  StorePointer(&raw_ptr()->origin_class_, value.raw());
+}
+
+
+void PatchClass::set_script(const Script& value) const {
+  StorePointer(&raw_ptr()->script_, value.raw());
 }
 
 
@@ -6880,7 +6821,7 @@
     return Class::Cast(obj).raw();
   }
   ASSERT(obj.IsPatchClass());
-  return PatchClass::Cast(obj).source_class();
+  return PatchClass::Cast(obj).origin_class();
 }
 
 
@@ -6901,7 +6842,7 @@
     return Class::Cast(obj).script();
   }
   ASSERT(obj.IsPatchClass());
-  return PatchClass::Cast(obj).Script();
+  return PatchClass::Cast(obj).script();
 }
 
 
@@ -7453,7 +7394,17 @@
     return Class::Cast(obj).raw();
   }
   ASSERT(obj.IsPatchClass());
-  return PatchClass::Cast(obj).source_class();
+  return PatchClass::Cast(obj).origin_class();
+}
+
+
+RawScript* Field::script() const {
+  const Object& obj = Object::Handle(raw_ptr()->owner_);
+  if (obj.IsClass()) {
+    return Class::Cast(obj).script();
+  }
+  ASSERT(obj.IsPatchClass());
+  return PatchClass::Cast(obj).script();
 }
 
 
@@ -7513,6 +7464,35 @@
 }
 
 
+RawField* Field::NewTopLevel(const String& name,
+                             bool is_final,
+                             bool is_const,
+                             const Object& owner,
+                             intptr_t 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);
+  }
+  return result.raw();
+}
+
 
 RawField* Field::Clone(const Class& new_owner) const {
   Field& clone = Field::Handle();
@@ -7584,14 +7564,16 @@
       "Field <%s.%s>:%s%s%s", cls_name, field_name, kF0, kF1, kF2);
 }
 
+
 void Field::PrintJSONImpl(JSONStream* stream, bool ref) const {
   JSONObject jsobj(stream);
   Class& cls = Class::Handle(owner());
-  intptr_t id = cls.FindFieldIndex(*this);
-  ASSERT(id >= 0);
-  intptr_t cid = cls.id();
+  String& field_name = String::Handle(name());
+  field_name = String::EncodeIRI(field_name);
   AddCommonObjectProperties(&jsobj, "Field", ref);
-  jsobj.AddFixedServiceId("classes/%" Pd "/fields/%" Pd "", cid, id);
+  jsobj.AddFixedServiceId("classes/%" Pd "/fields/%s",
+                          cls.id(), field_name.ToCString());
+
   const String& user_name = String::Handle(PrettyName());
   const String& vm_name = String::Handle(name());
   AddNameProperties(&jsobj, user_name, vm_name);
@@ -8994,6 +8976,10 @@
                               intptr_t to_line,
                               intptr_t to_column) const {
   const String& src = String::Handle(Source());
+  if (src.IsNull()) {
+    ASSERT(Dart::IsRunningPrecompiledCode());
+    return Symbols::OptimizedOut().raw();
+  }
   intptr_t length = src.Length();
   intptr_t line = 1 + line_offset();
   intptr_t column = 1;
@@ -9179,11 +9165,10 @@
 ClassDictionaryIterator::ClassDictionaryIterator(const Library& library,
                                                  IterationKind kind)
     : DictionaryIterator(library),
-      anon_array_((kind == kIteratePrivate) ?
-          Array::Handle(library.anonymous_classes()) : Object::empty_array()),
-      anon_size_((kind == kIteratePrivate) ?
-                 library.num_anonymous_classes() : 0),
-      anon_ix_(0) {
+      toplevel_class_(Class::Handle(
+          (kind == kIteratePrivate)
+              ? library.toplevel_class()
+              : Class::null())) {
   MoveToNextClass();
 }
 
@@ -9197,8 +9182,9 @@
     MoveToNextClass();
     return cls.raw();
   }
-  ASSERT(anon_ix_ < anon_size_);
-  cls ^= anon_array_.At(anon_ix_++);
+  ASSERT(!toplevel_class_.IsNull());
+  cls = toplevel_class_.raw();
+  toplevel_class_ = Class::null();
   return cls.raw();
 }
 
@@ -9345,6 +9331,52 @@
 }
 
 
+void Library::AddPatchClass(const Class& cls) const {
+  ASSERT(cls.is_patch());
+  ASSERT(GetPatchClass(String::Handle(cls.Name())) == Class::null());
+  const GrowableObjectArray& patch_classes =
+      GrowableObjectArray::Handle(this->patch_classes());
+  patch_classes.Add(cls);
+}
+
+
+RawClass* Library::GetPatchClass(const String& name) const {
+  const GrowableObjectArray& patch_classes =
+      GrowableObjectArray::Handle(this->patch_classes());
+  Object& obj = Object::Handle();
+  for (intptr_t i = 0; i < patch_classes.Length(); i++) {
+    obj = patch_classes.At(i);
+    if (obj.IsClass() &&
+        (Class::Cast(obj).Name() == name.raw())) {  // Names are canonicalized.
+      return Class::RawCast(obj.raw());
+    }
+  }
+  return Class::null();
+}
+
+
+void Library::RemovePatchClass(const Class& cls) const {
+  ASSERT(cls.is_patch());
+  const GrowableObjectArray& patch_classes =
+      GrowableObjectArray::Handle(this->patch_classes());
+  const intptr_t num_classes = patch_classes.Length();
+  intptr_t i = 0;
+  while (i < num_classes) {
+    if (cls.raw() == patch_classes.At(i)) break;
+    i++;
+  }
+  if (i == num_classes) return;
+  // Replace the entry with the script. We keep the script so that
+  // Library::LoadedScripts() can find it without having to iterate
+  // over the members of each class.
+  ASSERT(i < num_classes);  // We must have found a class.
+  Class& pc = Class::Handle();
+  pc ^= patch_classes.At(i);
+  const Script& patch_script = Script::Handle(pc.script());
+  patch_classes.SetAt(i, patch_script);
+}
+
+
 static RawString* MakeClassMetaName(const Class& cls) {
   return Symbols::FromConcat(Symbols::At(), String::Handle(cls.Name()));
 }
@@ -9383,32 +9415,31 @@
 }
 
 
-void Library::AddMetadata(const Class& cls,
+void Library::AddMetadata(const Object& owner,
                           const String& name,
                           intptr_t token_pos) const {
   const String& metaname = String::Handle(Symbols::New(name));
-  Field& field = Field::Handle(Field::New(metaname,
-                                          true,   // is_static
-                                          false,  // is_final
-                                          false,  // is_const
-                                          false,  // is_reflectable
-                                          cls,
-                                          Object::dynamic_type(),
-                                          token_pos));
+  const Field& field = Field::Handle(
+      Field::NewTopLevel(metaname,
+                         false,  // is_final
+                         false,  // is_const
+                         owner,
+                         token_pos));
+  field.SetFieldType(Object::dynamic_type());
+  field.set_is_reflectable(false);
   field.SetStaticValue(Array::empty_array(), true);
   GrowableObjectArray& metadata =
       GrowableObjectArray::Handle(this->metadata());
   metadata.Add(field, Heap::kOld);
-  cls.AddField(field);
 }
 
 
 void Library::AddClassMetadata(const Class& cls,
-                               const Class& toplevel_class,
+                               const Object& tl_owner,
                                intptr_t token_pos) const {
   // We use the toplevel class as the owner of a class's metadata field because
   // a class's metadata is in scope of the library, not the class.
-  AddMetadata(toplevel_class,
+  AddMetadata(tl_owner,
               String::Handle(MakeClassMetaName(cls)),
               token_pos);
 }
@@ -9416,7 +9447,7 @@
 
 void Library::AddFieldMetadata(const Field& field,
                                intptr_t token_pos) const {
-  AddMetadata(Class::Handle(field.origin()),
+  AddMetadata(Object::Handle(field.RawOwner()),
               String::Handle(MakeFieldMetaName(field)),
               token_pos);
 }
@@ -9424,7 +9455,7 @@
 
 void Library::AddFunctionMetadata(const Function& func,
                                   intptr_t token_pos) const {
-  AddMetadata(Class::Handle(func.origin()),
+  AddMetadata(Object::Handle(func.RawOwner()),
               String::Handle(MakeFunctionMetaName(func)),
               token_pos);
 }
@@ -9438,8 +9469,9 @@
 }
 
 
-void Library::AddLibraryMetadata(const Class& cls, intptr_t token_pos) const {
-  AddMetadata(cls, Symbols::TopLevel(), token_pos);
+void Library::AddLibraryMetadata(const Object& tl_owner,
+                                 intptr_t token_pos) const {
+  AddMetadata(tl_owner, Symbols::TopLevel(), token_pos);
 }
 
 
@@ -9491,8 +9523,7 @@
   Object& metadata = Object::Handle();
   metadata = field.StaticValue();
   if (field.StaticValue() == Object::empty_array().raw()) {
-    metadata = Parser::ParseMetadata(Class::Handle(field.owner()),
-                                     field.token_pos());
+    metadata = Parser::ParseMetadata(field);
     if (metadata.IsArray()) {
       ASSERT(Array::Cast(metadata).raw() != Object::empty_array().raw());
       field.SetStaticValue(Array::Cast(metadata), true);
@@ -9770,8 +9801,7 @@
       } else if (entry.IsFunction()) {
         owner_script = Function::Cast(entry).script();
       } else if (entry.IsField()) {
-        cls = Field::Cast(entry).owner();
-        owner_script = cls.script();
+        owner_script = Field::Cast(entry).script();
       } else {
         continue;
       }
@@ -9781,27 +9811,31 @@
     // Add all scripts from patch classes.
     GrowableObjectArray& patches = GrowableObjectArray::Handle(patch_classes());
     for (intptr_t i = 0; i < patches.Length(); i++) {
-      cls ^= patches.At(i);
-      owner_script = cls.script();
+      entry = patches.At(i);
+      if (entry.IsClass()) {
+        owner_script = Class::Cast(entry).script();
+      }  else {
+        ASSERT(entry.IsScript());
+        owner_script ^= Script::Cast(entry).raw();
+      }
       AddScriptIfUnique(scripts, owner_script);
     }
 
-    // Special case: Scripts that only contain external top-level functions are
-    // not included above, but can be referenced through a library's anonymous
-    // classes. Example: dart-core:identical.dart.
-    Array& anon_classes = Array::Handle(anonymous_classes());
-    Function& func = Function::Handle();
-    Array& functions = Array::Handle();
-    for (intptr_t i = 0; i < anon_classes.Length(); i++) {
-      cls ^= anon_classes.At(i);
-      if (cls.IsNull()) continue;
+    cls ^= toplevel_class();
+    if (!cls.IsNull()) {
       owner_script = cls.script();
       AddScriptIfUnique(scripts, owner_script);
-      functions = cls.functions();
+      // Special case: Scripts that only contain external top-level functions
+      // are not included above, but can be referenced through a library's
+      // anonymous classes. Example: dart-core:identical.dart.
+      Function& func = Function::Handle();
+      Array& functions = Array::Handle(cls.functions());
       for (intptr_t j = 0; j < functions.Length(); j++) {
         func ^= functions.At(j);
-        owner_script = func.script();
-        AddScriptIfUnique(scripts, owner_script);
+        if (func.is_external()) {
+          owner_script = func.script();
+          AddScriptIfUnique(scripts, owner_script);
+        }
       }
     }
 
@@ -10019,17 +10053,9 @@
 }
 
 
-void Library::AddAnonymousClass(const Class& cls) const {
-  intptr_t num_anonymous = this->raw_ptr()->num_anonymous_;
-  Array& anon_array = Array::Handle(this->raw_ptr()->anonymous_classes_);
-  if (num_anonymous == anon_array.Length()) {
-    intptr_t new_len = (num_anonymous == 0) ? 4 : num_anonymous * 2;
-    anon_array = Array::Grow(anon_array, new_len);
-    StorePointer(&raw_ptr()->anonymous_classes_, anon_array.raw());
-  }
-  anon_array.SetAt(num_anonymous, cls);
-  num_anonymous++;
-  StoreNonPointer(&raw_ptr()->num_anonymous_, num_anonymous);
+void Library::set_toplevel_class(const Class& value) const {
+  ASSERT(raw_ptr()->toplevel_class_ == Class::null());
+  StorePointer(&raw_ptr()->toplevel_class_, value.raw());
 }
 
 
@@ -10159,12 +10185,10 @@
                       Object::empty_array().raw());
   result.StorePointer(&result.raw_ptr()->metadata_,
                       GrowableObjectArray::New(4, Heap::kOld));
-  result.StorePointer(&result.raw_ptr()->anonymous_classes_,
-                      Object::empty_array().raw());
+  result.StorePointer(&result.raw_ptr()->toplevel_class_, Class::null());
   result.StorePointer(&result.raw_ptr()->patch_classes_,
                       GrowableObjectArray::New(Object::empty_array(),
                                                Heap::kOld));
-  result.StoreNonPointer(&result.raw_ptr()->num_anonymous_, 0);
   result.StorePointer(&result.raw_ptr()->imports_, Object::empty_array().raw());
   result.StorePointer(&result.raw_ptr()->exports_, Object::empty_array().raw());
   result.StorePointer(&result.raw_ptr()->loaded_scripts_, Array::null());
@@ -10219,12 +10243,8 @@
 RawObject* Library::Evaluate(const String& expr,
                              const Array& param_names,
                              const Array& param_values) const {
-  // Take a top-level class and evaluate the expression
-  // as a static function of the class.
-  Class& top_level_class = Class::Handle();
-  Array& top_level_classes = Array::Handle(anonymous_classes());
-  ASSERT(top_level_classes.Length() > 0);
-  top_level_class ^= top_level_classes.At(0);
+  // Evaluate the expression as a static function of the toplevel class.
+  Class& top_level_class = Class::Handle(toplevel_class());
   ASSERT(top_level_class.is_finalized());
   return top_level_class.Evaluate(expr, param_names, param_values);
 }
@@ -10751,8 +10771,8 @@
     const String& lib_url = String::Handle(zone, deferred_lib.url());
     Dart_LibraryTagHandler handler = isolate->library_tag_handler();
     handler(Dart_kImportTag,
-            Api::NewHandle(isolate, importer()),
-            Api::NewHandle(isolate, lib_url.raw()));
+            Api::NewHandle(thread, importer()),
+            Api::NewHandle(thread, lib_url.raw()));
   } else {
     // Another load request is in flight.
     ASSERT(deferred_lib.LoadRequested());
@@ -10889,19 +10909,17 @@
 }
 
 
-void Namespace::AddMetadata(intptr_t token_pos, const Class& owner_class) {
+void Namespace::AddMetadata(const Object& owner, intptr_t token_pos) {
   ASSERT(Field::Handle(metadata_field()).IsNull());
-  Field& field = Field::Handle(Field::New(Symbols::TopLevel(),
-                                          true,   // is_static
+  Field& field = Field::Handle(Field::NewTopLevel(Symbols::TopLevel(),
                                           false,  // is_final
                                           false,  // is_const
-                                          false,  // is_reflectable
-                                          owner_class,
-                                          Object::dynamic_type(),
+                                          owner,
                                           token_pos));
+  field.set_is_reflectable(false);
+  field.SetFieldType(Object::dynamic_type());
   field.SetStaticValue(Array::empty_array(), true);
   set_metadata_field(field);
-  owner_class.AddField(field);
 }
 
 
@@ -10914,8 +10932,7 @@
   Object& metadata = Object::Handle();
   metadata = field.StaticValue();
   if (field.StaticValue() == Object::empty_array().raw()) {
-    metadata = Parser::ParseMetadata(Class::Handle(field.owner()),
-                                     field.token_pos());
+    metadata = Parser::ParseMetadata(field);
     if (metadata.IsArray()) {
       ASSERT(Array::Cast(metadata).raw() != Object::empty_array().raw());
       field.SetStaticValue(Array::Cast(metadata), true);
@@ -11042,17 +11059,19 @@
 
 
 RawError* Library::CompileAll() {
-  Error& error = Error::Handle();
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  Error& error = Error::Handle(zone);
   const GrowableObjectArray& libs = GrowableObjectArray::Handle(
       Isolate::Current()->object_store()->libraries());
-  Library& lib = Library::Handle();
-  Class& cls = Class::Handle();
+  Library& lib = Library::Handle(zone);
+  Class& cls = Class::Handle(zone);
   for (int i = 0; i < libs.Length(); i++) {
     lib ^= libs.At(i);
     ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
     while (it.HasNext()) {
       cls = it.GetNextClass();
-      error = cls.EnsureIsFinalized(Thread::Current());
+      error = cls.EnsureIsFinalized(thread);
       if (!error.IsNull()) {
         return error.raw();
       }
@@ -11062,6 +11081,24 @@
       }
     }
   }
+
+  // Inner functions get added to the closures array. As part of compilation
+  // more closures can be added to the end of the array. Compile all the
+  // closures until we have reached the end of the "worklist".
+  const GrowableObjectArray& closures = GrowableObjectArray::Handle(zone,
+      Isolate::Current()->object_store()->closure_functions());
+  Function& func = Function::Handle(zone);
+  for (int i = 0; i < closures.Length(); i++) {
+    func ^= closures.At(i);
+    if (!func.HasCode()) {
+      error = Compiler::CompileFunction(thread, func);
+      if (!error.IsNull()) {
+        return error.raw();
+      }
+      func.ClearICDataArray();
+      func.ClearCode();
+    }
+  }
   return error.raw();
 }
 
@@ -12286,8 +12323,7 @@
   const intptr_t len = NumberOfChecks();
   for (intptr_t i = 0; i < len; i++) {
     GrowableArray<intptr_t> class_ids;
-    Function& target = Function::Handle();
-    GetCheckAt(i, &class_ids, &target);
+    GetClassIdsAt(i, &class_ids);
     bool matches = true;
     for (intptr_t k = 0; k < class_ids.length(); k++) {
       if (class_ids[k] != cids[k]) {
@@ -12446,6 +12482,19 @@
 }
 
 
+void ICData::GetClassIdsAt(intptr_t index,
+                           GrowableArray<intptr_t>* class_ids) const {
+  ASSERT(index < NumberOfChecks());
+  ASSERT(class_ids != NULL);
+  class_ids->Clear();
+  const Array& data = Array::Handle(ic_data());
+  intptr_t data_pos = index * TestEntryLength();
+  for (intptr_t i = 0; i < NumArgsTested(); i++) {
+    class_ids->Add(Smi::Value(Smi::RawCast(data.At(data_pos++))));
+  }
+}
+
+
 void ICData::GetOneClassCheckAt(intptr_t index,
                                 intptr_t* class_id,
                                 Function* target) const {
@@ -12469,8 +12518,7 @@
 
 intptr_t ICData::GetClassIdAt(intptr_t index, intptr_t arg_nr) const {
   GrowableArray<intptr_t> class_ids;
-  Function& target = Function::Handle();
-  GetCheckAt(index, &class_ids, &target);
+  GetClassIdsAt(index, &class_ids);
   return class_ids[arg_nr];
 }
 
@@ -12646,12 +12694,11 @@
   ASSERT(NumArgsTested() == 2);
   first->Clear();
   second->Clear();
-  Function& target = Function::Handle();
   GrowableArray<intptr_t> class_ids;
   const intptr_t len = NumberOfChecks();
   for (intptr_t i = 0; i < len; i++) {
     if (GetCountAt(i) > 0) {
-      GetCheckAt(i, &class_ids, &target);
+      GetClassIdsAt(i, &class_ids);
       ASSERT(class_ids.length() == 2);
       first->Add(class_ids[0]);
       second->Add(class_ids[1]);
@@ -12894,13 +12941,12 @@
   }
 
   bool initialized = false;
-  Function& t = Function::Handle();
   const intptr_t len = NumberOfChecks();
   GrowableArray<intptr_t> class_ids;
   for (intptr_t i = 0; i < len; i++) {
     if (IsUsedAt(i)) {
       initialized = true;
-      GetCheckAt(i, &class_ids, &t);
+      GetClassIdsAt(i, &class_ids);
       for (intptr_t j = 0; j < class_ids.length(); j++) {
         const intptr_t cid = class_ids[j];
         if ((cid != kSmiCid) && (cid != kMintCid)) {
@@ -13333,7 +13379,7 @@
   VerifiedMemory::Accept(region.start(), region.size());
   CPU::FlushICache(instrs.EntryPoint(), instrs.size());
 
-  code.set_compile_timestamp(OS::GetCurrentTimeMicros());
+  code.set_compile_timestamp(OS::GetCurrentTraceMicros());
   CodeObservers::NotifyAll(name,
                            instrs.EntryPoint(),
                            assembler->prologue_offset(),
@@ -17292,19 +17338,13 @@
     const int64_t right_value = other.AsInt64Value();
     switch (operation) {
       case Token::kADD: {
-        if (((left_value < 0) != (right_value < 0)) ||
-            ((left_value + right_value) < 0) == (left_value < 0)) {
+        if (!Utils::WillAddOverflow(left_value, right_value)) {
           return Integer::New(left_value + right_value, space);
         }
         break;
       }
       case Token::kSUB: {
-        // TODO(srdjan): Investigate why XCode 7 produces wrong code
-        // if the comparison is inlined as in above (Token::kADD).
-        const bool both_same_sign = (left_value < 0) == (right_value < 0);
-        const bool result_same_sign_as_left =
-            ((left_value - right_value) < 0) == (left_value < 0);
-        if (both_same_sign || result_same_sign_as_left) {
+        if (!Utils::WillSubOverflow(left_value, right_value)) {
           return Integer::New(left_value - right_value, space);
         }
         break;
@@ -19365,11 +19405,9 @@
     Dart_WeakPersistentHandleFinalizer callback) {
   ASSERT((callback != NULL && peer != NULL) ||
          (callback == NULL && peer == NULL));
-  const bool is_prologue = false;
   // TODO(19482): Make API consistent for external size of strings/typed data.
   const intptr_t external_size = 0;
   return FinalizablePersistentHandle::New(Isolate::Current(),
-                                          is_prologue,
                                           referent,
                                           peer,
                                           callback,
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 7c40e63..4bf0896 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1065,7 +1065,6 @@
   bool IsMixinApplication() const;
 
   RawClass* GetPatchClass() const;
-  void SetPatchClass(const Class& patch_class) const;
 
   // Interfaces is an array of Types.
   RawArray* interfaces() const { return raw_ptr()->interfaces_; }
@@ -1148,8 +1147,6 @@
   void SetFields(const Array& value) const;
   void AddField(const Field& field) const;
   void AddFields(const GrowableArray<const Field*>& fields) const;
-  intptr_t FindFieldIndex(const Field& field) const;
-  RawField* FieldFromIndex(intptr_t idx) const;
 
   // Returns an array of all fields of this class and its superclasses indexed
   // by offset in words.
@@ -1163,7 +1160,6 @@
   void SetFunctions(const Array& value) const;
   void AddFunction(const Function& function) const;
   void RemoveFunction(const Function& function) const;
-  intptr_t FindFunctionIndex(const Function& function) const;
   RawFunction* FunctionFromIndex(intptr_t idx) const;
   intptr_t FindImplicitClosureFunctionIndex(const Function& needle) const;
   RawFunction* ImplicitClosureFunctionFromIndex(intptr_t idx) const;
@@ -1238,6 +1234,8 @@
 
   void set_is_prefinalized() const;
 
+  void ResetFinalization() const;
+
   bool is_marked_for_parsing() const {
     return MarkedForParsingBit::decode(raw_ptr()->state_bits_);
   }
@@ -1486,6 +1484,7 @@
   friend class Object;
   friend class Type;
   friend class Intrinsifier;
+  friend class Precompiler;
 };
 
 
@@ -1719,8 +1718,8 @@
 class PatchClass : public Object {
  public:
   RawClass* patched_class() const { return raw_ptr()->patched_class_; }
-  RawClass* source_class() const { return raw_ptr()->source_class_; }
-  RawScript* Script() const;
+  RawClass* origin_class() const { return raw_ptr()->origin_class_; }
+  RawScript* script() const { return raw_ptr()->script_; }
 
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(RawPatchClass));
@@ -1731,11 +1730,15 @@
   }
 
   static RawPatchClass* New(const Class& patched_class,
-                            const Class& source_class);
+                            const Class& origin_class);
+
+  static RawPatchClass* New(const Class& patched_class,
+                            const Script& source);
 
  private:
   void set_patched_class(const Class& value) const;
-  void set_source_class(const Class& value) const;
+  void set_origin_class(const Class& value) const;
+  void set_script(const Script& value) const;
 
   static RawPatchClass* New();
 
@@ -1872,10 +1875,11 @@
 
   // Retrieving checks.
 
-  // TODO(srdjan): GetCheckAt without target.
   void GetCheckAt(intptr_t index,
                   GrowableArray<intptr_t>* class_ids,
                   Function* target) const;
+  void GetClassIdsAt(intptr_t index, GrowableArray<intptr_t>* class_ids) const;
+
   // Only for 'num_args_checked == 1'.
   void GetOneClassCheckAt(intptr_t index,
                           intptr_t* class_id,
@@ -2138,6 +2142,7 @@
   RawClass* Owner() const;
   RawClass* origin() const;
   RawScript* script() const;
+  RawObject* RawOwner() const { return raw_ptr()->owner_; }
 
   RawJSRegExp* regexp() const;
   intptr_t string_specialization_cid() const;
@@ -2865,6 +2870,9 @@
   bool is_reflectable() const {
     return ReflectableBit::decode(raw_ptr()->kind_bits_);
   }
+  void set_is_reflectable(bool value) const {
+    set_kind_bits(ReflectableBit::update(value, raw_ptr()->kind_bits_));
+  }
   bool is_double_initialized() const {
     return DoubleInitializedBit::decode(raw_ptr()->kind_bits_);
   }
@@ -2885,6 +2893,8 @@
 
   RawClass* owner() const;
   RawClass* origin() const;  // Either mixin class, or same as owner().
+  RawScript* script() const;
+  RawObject* RawOwner() const { return raw_ptr()->owner_; }
 
   RawAbstractType* type() const  { return raw_ptr()->type_; }
   // Used by class finalizer, otherwise initialized in constructor.
@@ -2903,6 +2913,12 @@
                        const AbstractType& type,
                        intptr_t token_pos);
 
+  static RawField* NewTopLevel(const String& name,
+                               bool is_final,
+                               bool is_const,
+                               const Object& owner,
+                               intptr_t token_pos);
+
   // Allocate new field object, clone values from this field. The
   // owner of the clone is new_owner.
   RawField* Clone(const Class& new_owner) const;
@@ -3091,9 +3107,6 @@
   void set_is_const(bool value) const {
     set_kind_bits(ConstBit::update(value, raw_ptr()->kind_bits_));
   }
-  void set_is_reflectable(bool value) const {
-    set_kind_bits(ReflectableBit::update(value, raw_ptr()->kind_bits_));
-  }
   void set_owner(const Object& value) const {
     StorePointer(&raw_ptr()->owner_, value.raw());
   }
@@ -3319,6 +3332,8 @@
 class ClassDictionaryIterator : public DictionaryIterator {
  public:
   enum IterationKind {
+    // TODO(hausner): fix call sites that use kIteratePrivate. There is only
+    // one top-level class per library left, not an array to iterate over.
     kIteratePrivate,
     kNoIteratePrivate
   };
@@ -3326,7 +3341,9 @@
   ClassDictionaryIterator(const Library& library,
                           IterationKind kind = kNoIteratePrivate);
 
-  bool HasNext() const { return (next_ix_ < size_) || (anon_ix_ < anon_size_); }
+  bool HasNext() const {
+      return (next_ix_ < size_) || !toplevel_class_.IsNull();
+  }
 
   // Returns a non-null raw class.
   RawClass* GetNextClass();
@@ -3334,9 +3351,7 @@
  private:
   void MoveToNextClass();
 
-  const Array& anon_array_;
-  const int anon_size_;  // Number of anonymous classes to iterate over.
-  int anon_ix_;  // Index of next anonymous class.
+  Class& toplevel_class_;
 
   DISALLOW_COPY_AND_ASSIGN(ClassDictionaryIterator);
 };
@@ -3379,6 +3394,10 @@
   void SetLoadError(const Instance& error) const;
   RawInstance* TransitiveLoadError() const;
 
+  void AddPatchClass(const Class& cls) const;
+  RawClass* GetPatchClass(const String& name) const;
+  void RemovePatchClass(const Class& cls) const;
+
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(RawLibrary));
   }
@@ -3432,17 +3451,19 @@
   void AddExport(const Namespace& ns) const;
 
   void AddClassMetadata(const Class& cls,
-                        const Class& toplevel_class,
+                        const Object& tl_owner,
                         intptr_t token_pos) const;
   void AddFieldMetadata(const Field& field, intptr_t token_pos) const;
   void AddFunctionMetadata(const Function& func, intptr_t token_pos) const;
-  void AddLibraryMetadata(const Class& cls, intptr_t token_pos) const;
+  void AddLibraryMetadata(const Object& tl_owner, intptr_t token_pos) const;
   void AddTypeParameterMetadata(const TypeParameter& param,
                                 intptr_t token_pos) const;
   RawObject* GetMetadata(const Object& obj) const;
 
-  intptr_t num_anonymous_classes() const { return raw_ptr()->num_anonymous_; }
-  RawArray* anonymous_classes() const { return raw_ptr()->anonymous_classes_; }
+  RawClass* toplevel_class() const {
+    return raw_ptr()->toplevel_class_;
+  }
+  void set_toplevel_class(const Class& value) const;
 
   RawGrowableObjectArray* patch_classes() const {
     return raw_ptr()->patch_classes_;
@@ -3590,7 +3611,7 @@
 
   RawString* MakeMetadataName(const Object& obj) const;
   RawField* GetMetadataField(const String& metaname) const;
-  void AddMetadata(const Class& cls,
+  void AddMetadata(const Object& owner,
                    const String& name,
                    intptr_t token_pos) const;
 
@@ -3613,7 +3634,7 @@
   RawArray* show_names() const { return raw_ptr()->show_names_; }
   RawArray* hide_names() const { return raw_ptr()->hide_names_; }
 
-  void AddMetadata(intptr_t token_pos, const Class& owner_class);
+  void AddMetadata(const Object& owner, intptr_t token_pos);
   RawObject* GetMetadata() const;
 
   static intptr_t InstanceSize() {
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc
index 2bc0d66..6c46997 100644
--- a/runtime/vm/object_graph.cc
+++ b/runtime/vm/object_graph.cc
@@ -173,7 +173,7 @@
 void ObjectGraph::IterateObjects(ObjectGraph::Visitor* visitor) {
   NoSafepointScope no_safepoint_scope_;
   Stack stack(isolate());
-  isolate()->IterateObjectPointers(&stack, false, false);
+  isolate()->IterateObjectPointers(&stack, false);
   stack.TraverseGraph(visitor);
   Unmarker::UnmarkAll(isolate());
 }
@@ -186,7 +186,41 @@
   RawObject* root_raw = root.raw();
   stack.VisitPointer(&root_raw);
   stack.TraverseGraph(visitor);
-  // TODO(koda): Optimize if we only visited a small subgraph.
+  Unmarker::UnmarkAll(isolate());
+}
+
+
+class InstanceAccumulator : public ObjectVisitor {
+ public:
+  explicit InstanceAccumulator(ObjectGraph::Stack* stack,
+                               intptr_t class_id,
+                               Isolate* isolate)
+    : ObjectVisitor(isolate), stack_(stack), class_id_(class_id) { }
+
+  void VisitObject(RawObject* obj) {
+    if (obj->GetClassId() == class_id_) {
+      RawObject* rawobj = obj;
+      stack_->VisitPointer(&rawobj);
+    }
+  }
+
+ private:
+  ObjectGraph::Stack* stack_;
+  const intptr_t class_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(InstanceAccumulator);
+};
+
+
+void ObjectGraph::IterateObjectsFrom(intptr_t class_id,
+                                     ObjectGraph::Visitor* visitor) {
+  NoSafepointScope no_safepoint_scope_;
+  Stack stack(isolate());
+
+  InstanceAccumulator accumulator(&stack, class_id, isolate());
+  isolate()->heap()->IterateObjects(&accumulator);
+
+  stack.TraverseGraph(visitor);
   Unmarker::UnmarkAll(isolate());
 }
 
@@ -240,6 +274,13 @@
 }
 
 
+intptr_t ObjectGraph::SizeReachableByInstance(const Object& obj) {
+  SizeVisitor total;
+  IterateObjectsFrom(obj, &total);
+  return total.size();
+}
+
+
 intptr_t ObjectGraph::SizeRetainedByClass(intptr_t class_id) {
   SizeVisitor total;
   IterateObjects(&total);
@@ -251,6 +292,13 @@
 }
 
 
+intptr_t ObjectGraph::SizeReachableByClass(intptr_t class_id) {
+  SizeVisitor total;
+  IterateObjectsFrom(class_id, &total);
+  return total.size();
+}
+
+
 class RetainingPathVisitor : public ObjectGraph::Visitor {
  public:
   // We cannot use a GrowableObjectArray, since we must not trigger GC.
@@ -473,7 +521,7 @@
   stream->WriteUnsigned(0);
   {
     WritePointerVisitor ptr_writer(isolate(), stream);
-    isolate()->IterateObjectPointers(&ptr_writer, false, false);
+    isolate()->IterateObjectPointers(&ptr_writer, false);
   }
   stream->WriteUnsigned(0);
   IterateObjects(&visitor);
diff --git a/runtime/vm/object_graph.h b/runtime/vm/object_graph.h
index 0a65bae..5187d5e 100644
--- a/runtime/vm/object_graph.h
+++ b/runtime/vm/object_graph.h
@@ -63,12 +63,15 @@
   // Like 'IterateObjects', but restricted to objects reachable from 'root'
   // (including 'root' itself).
   void IterateObjectsFrom(const Object& root, Visitor* visitor);
+  void IterateObjectsFrom(intptr_t class_id, Visitor* visitor);
 
   // The number of bytes retained by 'obj'.
   intptr_t SizeRetainedByInstance(const Object& obj);
+  intptr_t SizeReachableByInstance(const Object& obj);
 
   // The number of bytes retained by the set of all objects of the given class.
   intptr_t SizeRetainedByClass(intptr_t class_id);
+  intptr_t SizeReachableByClass(intptr_t class_id);
 
   // Finds some retaining path from the isolate roots to 'obj'. Populates the
   // provided array with pairs of (object, offset from parent in words),
diff --git a/runtime/vm/object_id_ring_test.cc b/runtime/vm/object_id_ring_test.cc
index 986757a..27347ea 100644
--- a/runtime/vm/object_id_ring_test.cc
+++ b/runtime/vm/object_id_ring_test.cc
@@ -133,7 +133,7 @@
   EXPECT(Dart_IsList(result));
   EXPECT_VALID(Dart_ListLength(result, &list_length));
   EXPECT_EQ(3, list_length);
-  Isolate* isolate = Isolate::Current();
+  Isolate* isolate = thread->isolate();
   Heap* heap = isolate->heap();
   ObjectIdRing* ring = isolate->object_id_ring();
   ObjectIdRing::LookupResult kind = ObjectIdRing::kInvalid;
@@ -174,7 +174,7 @@
   EXPECT_NE(RawObject::ToAddr(raw_obj1), RawObject::ToAddr(raw_object_moved1));
   EXPECT_NE(RawObject::ToAddr(raw_obj2), RawObject::ToAddr(raw_object_moved2));
   // Test that we still point at the same list.
-  Dart_Handle moved_handle = Api::NewHandle(isolate, raw_object_moved1);
+  Dart_Handle moved_handle = Api::NewHandle(thread, raw_object_moved1);
   EXPECT_VALID(moved_handle);
   EXPECT(!Dart_IsNull(moved_handle));
   EXPECT(Dart_IsList(moved_handle));
@@ -188,7 +188,7 @@
 
 // Test that the ring table is updated with nulls when the old GC collects.
 TEST_CASE(ObjectIdRingOldGCTest) {
-  Isolate* isolate = Isolate::Current();
+  Isolate* isolate = thread->isolate();
   Heap* heap = isolate->heap();
   ObjectIdRing* ring = isolate->object_id_ring();
 
@@ -199,7 +199,7 @@
     Dart_EnterScope();
     Dart_Handle result;
     // Create a string in the old heap.
-    result = Api::NewHandle(isolate, String::New("old", Heap::kOld));
+    result = Api::NewHandle(thread, String::New("old", Heap::kOld));
     EXPECT_VALID(result);
     intptr_t string_length = 0;
     // Inspect string.
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 90a346e..624e1fe 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -90,6 +90,7 @@
     handle_message_function_(Function::null()),
     library_load_error_table_(Array::null()),
     compile_time_constants_(Array::null()),
+    unique_dynamic_targets_(Array::null()),
     token_objects_(GrowableObjectArray::null()),
     token_objects_map_(Array::null()),
     megamorphic_cache_table_(GrowableObjectArray::null()),
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 193c847..db57663 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -444,6 +444,13 @@
     compile_time_constants_ = value.raw();
   }
 
+  RawArray* unique_dynamic_targets() const {
+    return unique_dynamic_targets_;
+  }
+  void set_unique_dynamic_targets(const Array& value) {
+    unique_dynamic_targets_ = value.raw();
+  }
+
   RawGrowableObjectArray* token_objects() const {
     return token_objects_;
   }
@@ -570,6 +577,7 @@
   RawObject** to_snapshot() {
     return reinterpret_cast<RawObject**>(&compile_time_constants_);
   }
+  RawArray* unique_dynamic_targets_;
   RawGrowableObjectArray* token_objects_;
   RawArray* token_objects_map_;
   RawGrowableObjectArray* megamorphic_cache_table_;
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index a4b2215..15a0021 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -3769,114 +3769,6 @@
 }
 
 
-TEST_CASE(FindFieldIndex) {
-  const char* kScriptChars =
-      "class A {\n"
-      "  var a;\n"
-      "  var b;\n"
-      "}\n"
-      "class B {\n"
-      "  var d;\n"
-      "}\n"
-      "test() {\n"
-      "  new A();\n"
-      "  new B();\n"
-      "}";
-  Dart_Handle h_lib = TestCase::LoadTestScript(kScriptChars, NULL);
-  EXPECT_VALID(h_lib);
-  Dart_Handle result = Dart_Invoke(h_lib, NewString("test"), 0, NULL);
-  EXPECT_VALID(result);
-  Library& lib = Library::Handle();
-  lib ^= Api::UnwrapHandle(h_lib);
-  EXPECT(!lib.IsNull());
-  const Class& class_a = Class::Handle(GetClass(lib, "A"));
-  const Array& class_a_fields = Array::Handle(class_a.fields());
-  const Class& class_b = Class::Handle(GetClass(lib, "B"));
-  const Field& field_a = Field::Handle(GetField(class_a, "a"));
-  const Field& field_b = Field::Handle(GetField(class_a, "b"));
-  const Field& field_d = Field::Handle(GetField(class_b, "d"));
-  intptr_t field_a_index = class_a.FindFieldIndex(field_a);
-  intptr_t field_b_index = class_a.FindFieldIndex(field_b);
-  intptr_t field_d_index = class_a.FindFieldIndex(field_d);
-  // Valid index.
-  EXPECT_GE(field_a_index, 0);
-  // Valid index.
-  EXPECT_GE(field_b_index, 0);
-  // Invalid index.
-  EXPECT_EQ(field_d_index, -1);
-  Field& field_a_from_index = Field::Handle();
-  field_a_from_index ^= class_a_fields.At(field_a_index);
-  ASSERT(!field_a_from_index.IsNull());
-  // Same field.
-  EXPECT_EQ(field_a.raw(), field_a_from_index.raw());
-  Field& field_b_from_index = Field::Handle();
-  field_b_from_index ^= class_a_fields.At(field_b_index);
-  ASSERT(!field_b_from_index.IsNull());
-  // Same field.
-  EXPECT_EQ(field_b.raw(), field_b_from_index.raw());
-}
-
-
-TEST_CASE(FindFunctionIndex) {
-  // Tests both FindFunctionIndex and FindImplicitClosureFunctionIndex.
-  const char* kScriptChars =
-      "class A {\n"
-      "  void a() {}\n"
-      "  Function b() { return a; }\n"
-      "}\n"
-      "class B {\n"
-      "  dynamic d() {}\n"
-      "}\n"
-      "var x;\n"
-      "test() {\n"
-      "  x = new A().b();\n"
-      "  x();\n"
-      "  new B();\n"
-      "  return x;\n"
-      "}";
-  Dart_Handle h_lib = TestCase::LoadTestScript(kScriptChars, NULL);
-  EXPECT_VALID(h_lib);
-  Dart_Handle result = Dart_Invoke(h_lib, NewString("test"), 0, NULL);
-  EXPECT_VALID(result);
-  Library& lib = Library::Handle();
-  lib ^= Api::UnwrapHandle(h_lib);
-  EXPECT(!lib.IsNull());
-  const Class& class_a = Class::Handle(GetClass(lib, "A"));
-  const Class& class_b = Class::Handle(GetClass(lib, "B"));
-  const Function& func_a = Function::Handle(GetFunction(class_a, "a"));
-  const Function& func_b = Function::Handle(GetFunction(class_a, "b"));
-  const Function& func_d = Function::Handle(GetFunction(class_b, "d"));
-  EXPECT(func_a.HasImplicitClosureFunction());
-  const Function& func_x = Function::Handle(func_a.ImplicitClosureFunction());
-  intptr_t func_a_index = class_a.FindFunctionIndex(func_a);
-  intptr_t func_b_index = class_a.FindFunctionIndex(func_b);
-  intptr_t func_d_index = class_a.FindFunctionIndex(func_d);
-  intptr_t func_x_index = class_a.FindImplicitClosureFunctionIndex(func_x);
-  // Valid index.
-  EXPECT_GE(func_a_index, 0);
-  // Valid index.
-  EXPECT_GE(func_b_index, 0);
-  // Invalid index.
-  EXPECT_EQ(func_d_index, -1);
-  // Valid index.
-  EXPECT_GE(func_x_index, 0);
-  Function& func_a_from_index = Function::Handle();
-  func_a_from_index ^= class_a.FunctionFromIndex(func_a_index);
-  EXPECT(!func_a_from_index.IsNull());
-  // Same function.
-  EXPECT_EQ(func_a.raw(), func_a_from_index.raw());
-  Function& func_b_from_index = Function::Handle();
-  func_b_from_index ^= class_a.FunctionFromIndex(func_b_index);
-  EXPECT(!func_b_from_index.IsNull());
-  // Same function.
-  EXPECT_EQ(func_b.raw(), func_b_from_index.raw());
-  // Retrieve implicit closure function.
-  Function& func_x_from_index = Function::Handle();
-  func_x_from_index ^= class_a.ImplicitClosureFunctionFromIndex(func_x_index);
-  EXPECT_EQ(func_x.raw(), func_x_from_index.raw());
-}
-
-
 TEST_CASE(FindClosureIndex) {
   // Allocate the class first.
   const String& class_name = String::Handle(Symbols::New("MyClass"));
diff --git a/runtime/vm/os_thread.cc b/runtime/vm/os_thread.cc
new file mode 100644
index 0000000..3789a60
--- /dev/null
+++ b/runtime/vm/os_thread.cc
@@ -0,0 +1,241 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/os_thread.h"
+
+#include "vm/atomic.h"
+#include "vm/lockers.h"
+#include "vm/log.h"
+#include "vm/thread_interrupter.h"
+
+namespace dart {
+
+// The single thread local key which stores all the thread local data
+// for a thread.
+ThreadLocalKey OSThread::thread_key_ = kUnsetThreadLocalKey;
+OSThread* OSThread::thread_list_head_ = NULL;
+Mutex* OSThread::thread_list_lock_ = NULL;
+
+
+OSThread::OSThread() :
+    BaseThread(true),
+    id_(OSThread::GetCurrentThreadId()),
+    join_id_(OSThread::GetCurrentThreadJoinId()),
+    trace_id_(OSThread::GetCurrentThreadTraceId()),
+    name_(NULL),
+    timeline_block_lock_(new Mutex()),
+    timeline_block_(NULL),
+    thread_list_next_(NULL),
+    thread_interrupt_disabled_(1),  // Thread interrupts disabled by default.
+    log_(new class Log()),
+    stack_base_(0),
+    thread_(NULL) {
+  AddThreadToList(this);
+}
+
+
+OSThread::~OSThread() {
+  RemoveThreadFromList(this);
+  delete log_;
+  log_ = NULL;
+  if (Timeline::recorder() != NULL) {
+    Timeline::recorder()->FinishBlock(timeline_block_);
+  }
+  timeline_block_ = NULL;
+  delete timeline_block_lock_;
+  free(name_);
+}
+
+
+void OSThread::DisableThreadInterrupts() {
+  ASSERT(OSThread::Current() == this);
+  AtomicOperations::FetchAndIncrement(&thread_interrupt_disabled_);
+}
+
+
+void OSThread::EnableThreadInterrupts() {
+  ASSERT(OSThread::Current() == this);
+  uintptr_t old =
+      AtomicOperations::FetchAndDecrement(&thread_interrupt_disabled_);
+  if (old == 1) {
+    // We just decremented from 1 to 0.
+    // Make sure the thread interrupter is awake.
+    ThreadInterrupter::WakeUp();
+  }
+  if (old == 0) {
+    // We just decremented from 0, this means we've got a mismatched pair
+    // of calls to EnableThreadInterrupts and DisableThreadInterrupts.
+    FATAL("Invalid call to OSThread::EnableThreadInterrupts()");
+  }
+}
+
+
+bool OSThread::ThreadInterruptsEnabled() {
+  return AtomicOperations::LoadRelaxed(&thread_interrupt_disabled_) == 0;
+}
+
+
+static void DeleteThread(void* thread) {
+  delete reinterpret_cast<OSThread*>(thread);
+}
+
+
+void OSThread::InitOnce() {
+  // Allocate the global OSThread lock.
+  ASSERT(thread_list_lock_ == NULL);
+  thread_list_lock_ = new Mutex();
+  ASSERT(thread_list_lock_ != NULL);
+
+  // Create the thread local key.
+  ASSERT(thread_key_ == kUnsetThreadLocalKey);
+  thread_key_ = CreateThreadLocal(DeleteThread);
+  ASSERT(thread_key_ != kUnsetThreadLocalKey);
+
+  // Create a new OSThread strcture and set it as the TLS.
+  OSThread* os_thread = new OSThread();
+  OSThread::SetCurrent(os_thread);
+  os_thread->set_name("Dart_Initialize");
+}
+
+
+void OSThread::Cleanup() {
+  if (thread_list_lock_ != NULL) {
+    // Delete the thread local key.
+    ASSERT(thread_key_ != kUnsetThreadLocalKey);
+    DeleteThreadLocal(thread_key_);
+    thread_key_ = kUnsetThreadLocalKey;
+
+    // Delete the global OSThread lock.
+    ASSERT(thread_list_lock_ != NULL);
+    delete thread_list_lock_;
+    thread_list_lock_ = NULL;
+  }
+}
+
+
+OSThread* OSThread::CreateAndSetUnknownThread() {
+  ASSERT(OSThread::Current() == NULL);
+  OSThread* os_thread = new OSThread();
+  OSThread::SetCurrent(os_thread);
+  os_thread->set_name("Unknown");
+  return os_thread;
+}
+
+
+bool OSThread::IsThreadInList(ThreadJoinId join_id) {
+  if (join_id == OSThread::kInvalidThreadJoinId) {
+    return false;
+  }
+  OSThreadIterator it;
+  while (it.HasNext()) {
+    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) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+OSThread* OSThread::GetOSThreadFromThread(Thread* thread) {
+  ASSERT(thread->os_thread() != NULL);
+  return thread->os_thread();
+}
+
+
+void OSThread::AddThreadToList(OSThread* thread) {
+  ASSERT(thread != NULL);
+  ASSERT(thread_list_lock_ != NULL);
+  MutexLocker ml(thread_list_lock_);
+
+  ASSERT(thread->thread_list_next_ == NULL);
+
+#if defined(DEBUG)
+  {
+    // Ensure that we aren't already in the list.
+    OSThread* current = thread_list_head_;
+    while (current != NULL) {
+      ASSERT(current != thread);
+      current = current->thread_list_next_;
+    }
+  }
+#endif
+
+  // Insert at head of list.
+  thread->thread_list_next_ = thread_list_head_;
+  thread_list_head_ = thread;
+}
+
+
+void OSThread::RemoveThreadFromList(OSThread* thread) {
+  {
+    ASSERT(thread != NULL);
+    ASSERT(thread_list_lock_ != NULL);
+    MutexLocker ml(thread_list_lock_);
+    OSThread* current = thread_list_head_;
+    OSThread* previous = NULL;
+
+    // Scan across list and remove |thread|.
+    while (current != NULL) {
+      if (current == thread) {
+        // We found |thread|, remove from list.
+        if (previous == NULL) {
+          thread_list_head_ = thread->thread_list_next_;
+        } else {
+          previous->thread_list_next_ = current->thread_list_next_;
+        }
+        thread->thread_list_next_ = NULL;
+        break;
+      }
+      previous = current;
+      current = current->thread_list_next_;
+    }
+  }
+  // Check if this is the last thread. The last thread does a cleanup
+  // which removes the thread local key and the associated mutex.
+  if (thread_list_head_ == NULL) {
+    Cleanup();
+  }
+}
+
+
+void OSThread::SetCurrent(OSThread* current) {
+  OSThread::SetThreadLocal(thread_key_, reinterpret_cast<uword>(current));
+}
+
+
+OSThreadIterator::OSThreadIterator() {
+  ASSERT(OSThread::thread_list_lock_ != NULL);
+  // Lock the thread list while iterating.
+  OSThread::thread_list_lock_->Lock();
+  next_ = OSThread::thread_list_head_;
+}
+
+
+OSThreadIterator::~OSThreadIterator() {
+  ASSERT(OSThread::thread_list_lock_ != NULL);
+  // Unlock the thread list when done.
+  OSThread::thread_list_lock_->Unlock();
+}
+
+
+bool OSThreadIterator::HasNext() const {
+  ASSERT(OSThread::thread_list_lock_ != NULL);
+  ASSERT(OSThread::thread_list_lock_->IsOwnedByCurrentThread());
+  return next_ != NULL;
+}
+
+
+OSThread* OSThreadIterator::Next() {
+  ASSERT(OSThread::thread_list_lock_ != NULL);
+  ASSERT(OSThread::thread_list_lock_->IsOwnedByCurrentThread());
+  OSThread* current = next_;
+  next_ = next_->thread_list_next_;
+  return current;
+}
+
+}  // namespace dart
diff --git a/runtime/vm/os_thread.h b/runtime/vm/os_thread.h
index 5929ef4..9371b45 100644
--- a/runtime/vm/os_thread.h
+++ b/runtime/vm/os_thread.h
@@ -6,6 +6,7 @@
 #define VM_OS_THREAD_H_
 
 #include "platform/globals.h"
+#include "vm/allocation.h"
 #include "vm/globals.h"
 
 // Declare the OS-specific types ahead of defining the generic classes.
@@ -23,13 +24,128 @@
 
 namespace dart {
 
-// Low-level operations on OS platform threads.
-// TODO(koda): Move to runtime/platform.
-class OSThread {
+// Forward declarations.
+class Log;
+class Mutex;
+class Thread;
+class TimelineEventBlock;
+
+class BaseThread {
  public:
-  static ThreadLocalKey kUnsetThreadLocalKey;
-  static ThreadId kInvalidThreadId;
-  static ThreadJoinId kInvalidThreadJoinId;
+  bool is_os_thread() const { return is_os_thread_; }
+
+ private:
+  explicit BaseThread(bool is_os_thread) : is_os_thread_(is_os_thread) {}
+  ~BaseThread() {}
+
+  bool is_os_thread_;
+
+  friend class Thread;
+  friend class OSThread;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(BaseThread);
+};
+
+
+// Low-level operations on OS platform threads.
+class OSThread : public BaseThread {
+ public:
+  OSThread();
+  ~OSThread();
+
+  ThreadId id() const {
+    ASSERT(id_ != OSThread::kInvalidThreadId);
+    return id_;
+  }
+
+  ThreadJoinId join_id() const {
+    ASSERT(join_id_ != OSThread::kInvalidThreadJoinId);
+    return join_id_;
+  }
+
+  ThreadId trace_id() const {
+    ASSERT(trace_id_ != OSThread::kInvalidThreadJoinId);
+    return trace_id_;
+  }
+
+  const char* name() const {
+    return name_;
+  }
+
+  void set_name(const char* name) {
+    ASSERT(OSThread::Current() == this);
+    ASSERT(name_ == NULL);
+    ASSERT(name != NULL);
+    name_ = strdup(name);
+  }
+
+  Mutex* timeline_block_lock() const {
+    return timeline_block_lock_;
+  }
+
+  // Only safe to access when holding |timeline_block_lock_|.
+  TimelineEventBlock* timeline_block() const {
+    return timeline_block_;
+  }
+
+  // Only safe to access when holding |timeline_block_lock_|.
+  void set_timeline_block(TimelineEventBlock* block) {
+    timeline_block_ = block;
+  }
+
+  Log* log() const { return log_; }
+
+  uword stack_base() const { return stack_base_; }
+  void set_stack_base(uword stack_base) { stack_base_ = stack_base; }
+
+  // Retrieve the stack address bounds for profiler.
+  bool GetProfilerStackBounds(uword* lower, uword* upper) const {
+    uword stack_upper = stack_base_;
+    if (stack_upper == 0) {
+      return false;
+    }
+    uword stack_lower = stack_upper - GetSpecifiedStackSize();
+    *lower = stack_lower;
+    *upper = stack_upper;
+    return true;
+  }
+
+  // Used to temporarily disable or enable thread interrupts.
+  void DisableThreadInterrupts();
+  void EnableThreadInterrupts();
+  bool ThreadInterruptsEnabled();
+
+  // The currently executing thread, or NULL if not yet initialized.
+  static OSThread* Current() {
+    BaseThread* thread = GetCurrentTLS();
+    OSThread* os_thread = NULL;
+    if (thread != NULL) {
+      if (thread->is_os_thread()) {
+        os_thread = reinterpret_cast<OSThread*>(thread);
+      } else {
+        Thread* vm_thread = reinterpret_cast<Thread*>(thread);
+        os_thread = GetOSThreadFromThread(vm_thread);
+      }
+    } else {
+      os_thread = CreateAndSetUnknownThread();
+    }
+    return os_thread;
+  }
+  static void SetCurrent(OSThread* current);
+
+  // TODO(5411455): Use flag to override default value and Validate the
+  // stack size by querying OS.
+  static uword GetSpecifiedStackSize() {
+    ASSERT(OSThread::kStackSizeBuffer < OSThread::GetMaxStackSize());
+    uword stack_size = OSThread::GetMaxStackSize() - OSThread::kStackSizeBuffer;
+    return stack_size;
+  }
+  static BaseThread* GetCurrentTLS() {
+    return reinterpret_cast<BaseThread*>(OSThread::GetThreadLocal(thread_key_));
+  }
+  static void SetCurrentTLS(uword value) {
+    SetThreadLocal(thread_key_, value);
+  }
 
   typedef void (*ThreadStartFunction) (uword parameter);
   typedef void (*ThreadDestructor) (void* parameter);
@@ -37,26 +153,95 @@
   // Start a thread running the specified function. Returns 0 if the
   // thread started successfuly and a system specific error code if
   // the thread failed to start.
-  static int Start(ThreadStartFunction function, uword parameters);
+  static int Start(
+      const char* name, ThreadStartFunction function, uword parameter);
 
   static ThreadLocalKey CreateThreadLocal(ThreadDestructor destructor = NULL);
   static void DeleteThreadLocal(ThreadLocalKey key);
   static uword GetThreadLocal(ThreadLocalKey key) {
     return ThreadInlineImpl::GetThreadLocal(key);
   }
+  static ThreadId GetCurrentThreadId();
   static void SetThreadLocal(ThreadLocalKey key, uword value);
   static intptr_t GetMaxStackSize();
-  static ThreadId GetCurrentThreadId();
-  static ThreadId GetCurrentThreadTraceId();
-  static intptr_t CurrentCurrentThreadIdAsIntPtr() {
-    return ThreadIdToIntPtr(GetCurrentThreadId());
-  }
-  static ThreadJoinId GetCurrentThreadJoinId();
   static void Join(ThreadJoinId id);
   static intptr_t ThreadIdToIntPtr(ThreadId id);
   static ThreadId ThreadIdFromIntPtr(intptr_t id);
   static bool Compare(ThreadId a, ThreadId b);
   static void GetThreadCpuUsage(ThreadId thread_id, int64_t* cpu_usage);
+
+  // Called at VM startup and shutdown.
+  static void InitOnce();
+
+  static bool IsThreadInList(ThreadJoinId join_id);
+
+  static const intptr_t kStackSizeBuffer = (4 * KB * kWordSize);
+
+  static const ThreadId kInvalidThreadId;
+  static const ThreadJoinId kInvalidThreadJoinId;
+
+ private:
+  // These methods should not be used in a generic way and hence
+  // are private, they have been added to solve the problem of
+  // accessing the VM thread structure from an OSThread object
+  // in the windows thread interrupter which is used for profiling.
+  // We could eliminate this requirement if the windows thread interrupter
+  // is implemented differently.
+  Thread* thread() const { return thread_; }
+  void set_thread(Thread* value) {
+    thread_ = value;
+  }
+
+  static void Cleanup();
+  static ThreadId GetCurrentThreadTraceId();
+  static ThreadJoinId GetCurrentThreadJoinId();
+  static OSThread* GetOSThreadFromThread(Thread* thread);
+  static void AddThreadToList(OSThread* thread);
+  static void RemoveThreadFromList(OSThread* thread);
+  static OSThread* CreateAndSetUnknownThread();
+
+  static ThreadLocalKey thread_key_;
+
+  const ThreadId id_;
+  const ThreadJoinId join_id_;
+  const ThreadId trace_id_;  // Used to interface with tracing tools.
+  char* name_;  // A name for this thread.
+
+  Mutex* timeline_block_lock_;
+  TimelineEventBlock* timeline_block_;
+
+  // All |Thread|s are registered in the thread list.
+  OSThread* thread_list_next_;
+
+  uintptr_t thread_interrupt_disabled_;
+  Log* log_;
+  uword stack_base_;
+  Thread* thread_;
+
+  static OSThread* thread_list_head_;
+  static Mutex* thread_list_lock_;
+
+  friend class OSThreadIterator;
+  friend class ThreadInterrupterWin;
+  friend class ThreadRegistry;
+};
+
+
+// Note that this takes the thread list lock, prohibiting threads from coming
+// on- or off-line.
+class OSThreadIterator : public ValueObject {
+ public:
+  OSThreadIterator();
+  ~OSThreadIterator();
+
+  // Returns false when there are no more threads left.
+  bool HasNext() const;
+
+  // Returns the current thread and moves forward.
+  OSThread* Next();
+
+ private:
+  OSThread* next_;
 };
 
 
diff --git a/runtime/vm/os_thread_android.cc b/runtime/vm/os_thread_android.cc
index f1c3a44..6f7ff34 100644
--- a/runtime/vm/os_thread_android.cc
+++ b/runtime/vm/os_thread_android.cc
@@ -11,6 +11,7 @@
 #include <sys/time.h>  // NOLINT
 
 #include "platform/assert.h"
+#include "platform/utils.h"
 
 namespace dart {
 
@@ -18,7 +19,7 @@
   if (result != 0) { \
     const int kBufferSize = 1024; \
     char error_message[kBufferSize]; \
-    strerror_r(result, error_message, kBufferSize); \
+    Utils::StrError(result, error_message, kBufferSize); \
     FATAL2("pthread error: %d (%s)", result, error_message); \
   }
 
@@ -36,7 +37,7 @@
   if (result != 0) { \
     const int kBufferSize = 1024; \
     char error_message[kBufferSize]; \
-    strerror_r(result, error_message, kBufferSize); \
+    Utils::StrError(result, error_message, kBufferSize); \
     fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", \
             __FILE__, __LINE__, result, error_message); \
     return result; \
@@ -64,14 +65,17 @@
 
 class ThreadStartData {
  public:
-  ThreadStartData(OSThread::ThreadStartFunction function,
+  ThreadStartData(const char* name,
+                  OSThread::ThreadStartFunction function,
                   uword parameter)
-      : function_(function), parameter_(parameter) {}
+      : name_(name), function_(function), parameter_(parameter) {}
 
+  const char* name() const { return name_; }
   OSThread::ThreadStartFunction function() const { return function_; }
   uword parameter() const { return parameter_; }
 
  private:
+  const char* name_;
   OSThread::ThreadStartFunction function_;
   uword parameter_;
 
@@ -85,10 +89,16 @@
 static void* ThreadStart(void* data_ptr) {
   ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
 
+  const char* name = data->name();
   OSThread::ThreadStartFunction function = data->function();
   uword parameter = data->parameter();
   delete data;
 
+  // Create new OSThread object and set as TLS for new thread.
+  OSThread* thread = new OSThread();
+  OSThread::SetCurrent(thread);
+  thread->set_name(name);
+
   // Call the supplied thread start function handing it its parameters.
   function(parameter);
 
@@ -96,7 +106,9 @@
 }
 
 
-int OSThread::Start(ThreadStartFunction function, uword parameter) {
+int OSThread::Start(const char* name,
+                    ThreadStartFunction function,
+                    uword parameter) {
   pthread_attr_t attr;
   int result = pthread_attr_init(&attr);
   RETURN_ON_PTHREAD_FAILURE(result);
@@ -104,7 +116,7 @@
   result = pthread_attr_setstacksize(&attr, OSThread::GetMaxStackSize());
   RETURN_ON_PTHREAD_FAILURE(result);
 
-  ThreadStartData* data = new ThreadStartData(function, parameter);
+  ThreadStartData* data = new ThreadStartData(name, function, parameter);
 
   pthread_t tid;
   result = pthread_create(&tid, &attr, ThreadStart, data);
@@ -117,10 +129,10 @@
 }
 
 
-ThreadLocalKey OSThread::kUnsetThreadLocalKey =
-    static_cast<pthread_key_t>(-1);
-ThreadId OSThread::kInvalidThreadId = static_cast<ThreadId>(0);
-ThreadJoinId OSThread::kInvalidThreadJoinId = static_cast<ThreadJoinId>(0);
+const ThreadId OSThread::kInvalidThreadId = static_cast<ThreadId>(0);
+const ThreadJoinId OSThread::kInvalidThreadJoinId =
+    static_cast<ThreadJoinId>(0);
+
 
 ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
   pthread_key_t key = kUnsetThreadLocalKey;
diff --git a/runtime/vm/os_thread_android.h b/runtime/vm/os_thread_android.h
index 061066e..c4f3981 100644
--- a/runtime/vm/os_thread_android.h
+++ b/runtime/vm/os_thread_android.h
@@ -20,13 +20,17 @@
 typedef pid_t ThreadId;
 typedef pthread_t ThreadJoinId;
 
+
+static const ThreadLocalKey kUnsetThreadLocalKey =
+    static_cast<pthread_key_t>(-1);
+
+
 class ThreadInlineImpl {
  private:
   ThreadInlineImpl() {}
   ~ThreadInlineImpl() {}
 
   static uword GetThreadLocal(ThreadLocalKey key) {
-    static ThreadLocalKey kUnsetThreadLocalKey = static_cast<pthread_key_t>(-1);
     ASSERT(key != kUnsetThreadLocalKey);
     return reinterpret_cast<uword>(pthread_getspecific(key));
   }
diff --git a/runtime/vm/os_thread_linux.cc b/runtime/vm/os_thread_linux.cc
index f48b6b0..4a08b84 100644
--- a/runtime/vm/os_thread_linux.cc
+++ b/runtime/vm/os_thread_linux.cc
@@ -13,27 +13,16 @@
 #include <sys/time.h>  // NOLINT
 
 #include "platform/assert.h"
+#include "platform/utils.h"
 
 namespace dart {
 
-static char* strerror_helper(int err, char* buffer, size_t bufsize) {
-#if !defined(__GLIBC__) || \
-    ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE)
-  // Use the standard version
-  return strerror_r(err, buffer, bufsize) == 0 ?
-    buffer : const_cast<char*>("strerror_r failed");
-#else
-  // Use the gnu specific version
-  return strerror_r(err, buffer, bufsize);
-#endif
-}
-
 #define VALIDATE_PTHREAD_RESULT(result) \
   if (result != 0) { \
     const int kBufferSize = 1024; \
     char error_buf[kBufferSize]; \
     FATAL2("pthread error: %d (%s)", result, \
-           strerror_helper(result, error_buf, kBufferSize)); \
+           Utils::StrError(result, error_buf, kBufferSize)); \
   }
 
 
@@ -52,7 +41,7 @@
     char error_buf[kBufferSize]; \
     fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", \
             __FILE__, __LINE__, result, \
-            strerror_helper(result, error_buf, kBufferSize)); \
+            Utils::StrError(result, error_buf, kBufferSize)); \
     return result; \
   }
 #else
@@ -78,14 +67,17 @@
 
 class ThreadStartData {
  public:
-  ThreadStartData(OSThread::ThreadStartFunction function,
+  ThreadStartData(const char* name,
+                  OSThread::ThreadStartFunction function,
                   uword parameter)
-      : function_(function), parameter_(parameter) {}
+      : name_(name), function_(function), parameter_(parameter) {}
 
+  const char* name() const { return name_; }
   OSThread::ThreadStartFunction function() const { return function_; }
   uword parameter() const { return parameter_; }
 
  private:
+  const char* name_;
   OSThread::ThreadStartFunction function_;
   uword parameter_;
 
@@ -99,10 +91,16 @@
 static void* ThreadStart(void* data_ptr) {
   ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
 
+  const char* name = data->name();
   OSThread::ThreadStartFunction function = data->function();
   uword parameter = data->parameter();
   delete data;
 
+  // Create new OSThread object and set as TLS for new thread.
+  OSThread* thread = new OSThread();
+  OSThread::SetCurrent(thread);
+  thread->set_name(name);
+
   // Call the supplied thread start function handing it its parameters.
   function(parameter);
 
@@ -110,7 +108,9 @@
 }
 
 
-int OSThread::Start(ThreadStartFunction function, uword parameter) {
+int OSThread::Start(const char* name,
+                    ThreadStartFunction function,
+                    uword parameter) {
   pthread_attr_t attr;
   int result = pthread_attr_init(&attr);
   RETURN_ON_PTHREAD_FAILURE(result);
@@ -118,7 +118,7 @@
   result = pthread_attr_setstacksize(&attr, OSThread::GetMaxStackSize());
   RETURN_ON_PTHREAD_FAILURE(result);
 
-  ThreadStartData* data = new ThreadStartData(function, parameter);
+  ThreadStartData* data = new ThreadStartData(name, function, parameter);
 
   pthread_t tid;
   result = pthread_create(&tid, &attr, ThreadStart, data);
@@ -131,10 +131,10 @@
 }
 
 
-ThreadLocalKey OSThread::kUnsetThreadLocalKey =
-    static_cast<pthread_key_t>(-1);
-ThreadId OSThread::kInvalidThreadId = static_cast<ThreadId>(0);
-ThreadJoinId OSThread::kInvalidThreadJoinId = static_cast<ThreadJoinId>(0);
+const ThreadId OSThread::kInvalidThreadId = static_cast<ThreadId>(0);
+const ThreadJoinId OSThread::kInvalidThreadJoinId =
+    static_cast<ThreadJoinId>(0);
+
 
 ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
   pthread_key_t key = kUnsetThreadLocalKey;
diff --git a/runtime/vm/os_thread_linux.h b/runtime/vm/os_thread_linux.h
index 5901214..306229b 100644
--- a/runtime/vm/os_thread_linux.h
+++ b/runtime/vm/os_thread_linux.h
@@ -20,13 +20,17 @@
 typedef pthread_t ThreadId;
 typedef pthread_t ThreadJoinId;
 
+
+static const ThreadLocalKey kUnsetThreadLocalKey =
+    static_cast<pthread_key_t>(-1);
+
+
 class ThreadInlineImpl {
  private:
   ThreadInlineImpl() {}
   ~ThreadInlineImpl() {}
 
   static uword GetThreadLocal(ThreadLocalKey key) {
-    static ThreadLocalKey kUnsetThreadLocalKey = static_cast<pthread_key_t>(-1);
     ASSERT(key != kUnsetThreadLocalKey);
     return reinterpret_cast<uword>(pthread_getspecific(key));
   }
diff --git a/runtime/vm/os_thread_macos.cc b/runtime/vm/os_thread_macos.cc
index 851a467..2fa58d8 100644
--- a/runtime/vm/os_thread_macos.cc
+++ b/runtime/vm/os_thread_macos.cc
@@ -19,6 +19,7 @@
 #include <mach/thread_act.h>  // NOLINT
 
 #include "platform/assert.h"
+#include "platform/utils.h"
 
 namespace dart {
 
@@ -26,7 +27,7 @@
   if (result != 0) { \
     const int kBufferSize = 1024; \
     char error_message[kBufferSize]; \
-    strerror_r(result, error_message, kBufferSize); \
+    Utils::StrError(result, error_message, kBufferSize); \
     FATAL2("pthread error: %d (%s)", result, error_message); \
   }
 
@@ -44,7 +45,7 @@
   if (result != 0) { \
     const int kBufferSize = 1024; \
     char error_message[kBufferSize]; \
-    strerror_r(result, error_message, kBufferSize); \
+    Utils::StrError(result, error_message, kBufferSize); \
     fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", \
             __FILE__, __LINE__, result, error_message); \
     return result; \
@@ -57,14 +58,17 @@
 
 class ThreadStartData {
  public:
-  ThreadStartData(OSThread::ThreadStartFunction function,
+  ThreadStartData(const char* name,
+                  OSThread::ThreadStartFunction function,
                   uword parameter)
-      : function_(function), parameter_(parameter) {}
+      : name_(name), function_(function), parameter_(parameter) {}
 
+  const char* name() const { return name_; }
   OSThread::ThreadStartFunction function() const { return function_; }
   uword parameter() const { return parameter_; }
 
  private:
+  const char* name_;
   OSThread::ThreadStartFunction function_;
   uword parameter_;
 
@@ -78,10 +82,16 @@
 static void* ThreadStart(void* data_ptr) {
   ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
 
+  const char* name = data->name();
   OSThread::ThreadStartFunction function = data->function();
   uword parameter = data->parameter();
   delete data;
 
+  // Create new OSThread object and set as TLS for new thread.
+  OSThread* thread = new OSThread();
+  OSThread::SetCurrent(thread);
+  thread->set_name(name);
+
   // Call the supplied thread start function handing it its parameters.
   function(parameter);
 
@@ -89,7 +99,9 @@
 }
 
 
-int OSThread::Start(ThreadStartFunction function, uword parameter) {
+int OSThread::Start(const char* name,
+                    ThreadStartFunction function,
+                    uword parameter) {
   pthread_attr_t attr;
   int result = pthread_attr_init(&attr);
   RETURN_ON_PTHREAD_FAILURE(result);
@@ -97,7 +109,7 @@
   result = pthread_attr_setstacksize(&attr, OSThread::GetMaxStackSize());
   RETURN_ON_PTHREAD_FAILURE(result);
 
-  ThreadStartData* data = new ThreadStartData(function, parameter);
+  ThreadStartData* data = new ThreadStartData(name, function, parameter);
 
   pthread_t tid;
   result = pthread_create(&tid, &attr, ThreadStart, data);
@@ -110,12 +122,11 @@
 }
 
 
-ThreadLocalKey OSThread::kUnsetThreadLocalKey =
-    static_cast<pthread_key_t>(-1);
-ThreadId OSThread::kInvalidThreadId = reinterpret_cast<ThreadId>(NULL);
-ThreadJoinId OSThread::kInvalidThreadJoinId =
+const ThreadId OSThread::kInvalidThreadId = reinterpret_cast<ThreadId>(NULL);
+const ThreadJoinId OSThread::kInvalidThreadJoinId =
     reinterpret_cast<ThreadJoinId>(NULL);
 
+
 ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
   pthread_key_t key = kUnsetThreadLocalKey;
   int result = pthread_key_create(&key, destructor);
diff --git a/runtime/vm/os_thread_macos.h b/runtime/vm/os_thread_macos.h
index 63b4f02..4909edf 100644
--- a/runtime/vm/os_thread_macos.h
+++ b/runtime/vm/os_thread_macos.h
@@ -20,6 +20,11 @@
 typedef pthread_t ThreadId;
 typedef pthread_t ThreadJoinId;
 
+
+static const ThreadLocalKey kUnsetThreadLocalKey =
+    static_cast<pthread_key_t>(-1);
+
+
 class ThreadInlineImpl {
  private:
   ThreadInlineImpl() {}
diff --git a/runtime/vm/os_thread_win.cc b/runtime/vm/os_thread_win.cc
index fd8de38..52fbd98 100644
--- a/runtime/vm/os_thread_win.cc
+++ b/runtime/vm/os_thread_win.cc
@@ -20,13 +20,17 @@
 
 class ThreadStartData {
  public:
-  ThreadStartData(OSThread::ThreadStartFunction function, uword parameter)
-      : function_(function), parameter_(parameter) {}
+  ThreadStartData(const char* name,
+                  OSThread::ThreadStartFunction function,
+                  uword parameter)
+      : name_(name), function_(function), parameter_(parameter) {}
 
+  const char* name() const { return name_; }
   OSThread::ThreadStartFunction function() const { return function_; }
   uword parameter() const { return parameter_; }
 
  private:
+  const char* name_;
   OSThread::ThreadStartFunction function_;
   uword parameter_;
 
@@ -40,12 +44,18 @@
 static unsigned int __stdcall ThreadEntry(void* data_ptr) {
   ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
 
+  const char* name = data->name();
   OSThread::ThreadStartFunction function = data->function();
   uword parameter = data->parameter();
   delete data;
 
   MonitorData::GetMonitorWaitDataForThread();
 
+  // Create new OSThread object and set as TLS for new thread.
+  OSThread* thread = new OSThread();
+  OSThread::SetCurrent(thread);
+  thread->set_name(name);
+
   // Call the supplied thread start function handing it its parameters.
   function(parameter);
 
@@ -56,8 +66,10 @@
 }
 
 
-int OSThread::Start(ThreadStartFunction function, uword parameter) {
-  ThreadStartData* start_data = new ThreadStartData(function, parameter);
+int OSThread::Start(const char* name,
+                    ThreadStartFunction function,
+                    uword parameter) {
+  ThreadStartData* start_data = new ThreadStartData(name, function, parameter);
   uint32_t tid;
   uintptr_t thread = _beginthreadex(NULL, OSThread::GetMaxStackSize(),
                                     ThreadEntry, start_data, 0, &tid);
@@ -74,9 +86,10 @@
   return 0;
 }
 
-ThreadLocalKey OSThread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
-ThreadId OSThread::kInvalidThreadId = 0;
-ThreadJoinId OSThread::kInvalidThreadJoinId = 0;
+
+const ThreadId OSThread::kInvalidThreadId = 0;
+const ThreadJoinId OSThread::kInvalidThreadJoinId = 0;
+
 
 ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
   ThreadLocalKey key = TlsAlloc();
@@ -115,6 +128,8 @@
 
 
 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();
 }
 
@@ -261,8 +276,7 @@
 }
 
 
-ThreadLocalKey MonitorWaitData::monitor_wait_data_key_ =
-    OSThread::kUnsetThreadLocalKey;
+ThreadLocalKey MonitorWaitData::monitor_wait_data_key_ = kUnsetThreadLocalKey;
 
 
 Monitor::Monitor() {
@@ -312,8 +326,7 @@
 
 
 void MonitorWaitData::ThreadExit() {
-  if (MonitorWaitData::monitor_wait_data_key_ !=
-      OSThread::kUnsetThreadLocalKey) {
+  if (MonitorWaitData::monitor_wait_data_key_ != kUnsetThreadLocalKey) {
     uword raw_wait_data =
       OSThread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_);
     // Clear in case this is called a second time.
@@ -421,8 +434,7 @@
 MonitorWaitData* MonitorData::GetMonitorWaitDataForThread() {
   // Ensure that the thread local key for monitor wait data objects is
   // initialized.
-  ASSERT(MonitorWaitData::monitor_wait_data_key_ !=
-         OSThread::kUnsetThreadLocalKey);
+  ASSERT(MonitorWaitData::monitor_wait_data_key_ != kUnsetThreadLocalKey);
 
   // Get the MonitorWaitData object containing the event for this
   // thread from thread local storage. Create it if it does not exist.
diff --git a/runtime/vm/os_thread_win.h b/runtime/vm/os_thread_win.h
index 5398182..790306d 100644
--- a/runtime/vm/os_thread_win.h
+++ b/runtime/vm/os_thread_win.h
@@ -20,13 +20,16 @@
 typedef DWORD ThreadId;
 typedef DWORD ThreadJoinId;
 
+
+static const ThreadLocalKey kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
+
+
 class ThreadInlineImpl {
  private:
   ThreadInlineImpl() {}
   ~ThreadInlineImpl() {}
 
   static uword GetThreadLocal(ThreadLocalKey key) {
-    static ThreadLocalKey kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
     ASSERT(key != kUnsetThreadLocalKey);
     return reinterpret_cast<uword>(TlsGetValue(key));
   }
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index c3fb3fe..e20ff43 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -3,6 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 
 #include "vm/parser.h"
+#include "vm/flags.h"
+
+#ifndef DART_PRECOMPILED
 
 #include "lib/invocation_mirror.h"
 #include "platform/utils.h"
@@ -13,7 +16,6 @@
 #include "vm/compiler_stats.h"
 #include "vm/dart_api_impl.h"
 #include "vm/dart_entry.h"
-#include "vm/flags.h"
 #include "vm/growable_array.h"
 #include "vm/handles.h"
 #include "vm/hash_table.h"
@@ -826,12 +828,11 @@
 
 RawObject* Parser::ParseFunctionParameters(const Function& func) {
   ASSERT(!func.IsNull());
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  StackZone stack_zone(thread);
-  Zone* zone = stack_zone.GetZone();
   LongJumpScope jump;
   if (setjmp(*jump.Set()) == 0) {
+    Thread* thread = Thread::Current();
+    StackZone stack_zone(thread);
+    Zone* zone = stack_zone.GetZone();
     const Script& script = Script::Handle(zone, func.script());
     const Class& owner = Class::Handle(zone, func.Owner());
     ASSERT(!owner.IsNull());
@@ -862,6 +863,8 @@
     }
     return param_descriptor.raw();
   } else {
+    Thread* thread = Thread::Current();
+    Isolate* isolate = thread->isolate();
     Error& error = Error::Handle();
     error = isolate->object_store()->sticky_error();
     isolate->object_store()->clear_sticky_error();
@@ -1005,14 +1008,15 @@
 }
 
 
-RawObject* Parser::ParseMetadata(const Class& cls, intptr_t token_pos) {
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  StackZone stack_zone(thread);
-  Zone* zone = stack_zone.GetZone();
+RawObject* Parser::ParseMetadata(const Field& meta_data) {
   LongJumpScope jump;
   if (setjmp(*jump.Set()) == 0) {
-    const Script& script = Script::Handle(zone, cls.script());
+    Thread* thread = Thread::Current();
+    StackZone stack_zone(thread);
+    Zone* zone = stack_zone.GetZone();
+    const Class& owner_class = Class::Handle(zone, meta_data.owner());
+    const Script& script = Script::Handle(zone, meta_data.script());
+    const intptr_t token_pos = meta_data.token_pos();
     // Parsing metadata can involve following paths in the parser that are
     // normally used for expressions and assume current_function is non-null,
     // so we create a fake function to use as the current_function rather than
@@ -1025,17 +1029,21 @@
         false,  // is_abstract
         false,  // is_external
         false,  // is_native
-        cls,
+        Object::Handle(zone, meta_data.RawOwner()),
         token_pos));
     fake_function.set_is_debuggable(false);
     ParsedFunction* parsed_function =
         new ParsedFunction(thread, fake_function);
     Parser parser(script, parsed_function, token_pos);
-    parser.set_current_class(cls);
+    parser.set_current_class(owner_class);
 
     RawObject* metadata = parser.EvaluateMetadata();
     return metadata;
   } else {
+    Thread* thread = Thread::Current();
+    Isolate* isolate = thread->isolate();
+    StackZone stack_zone(thread);
+    Zone* zone = stack_zone.GetZone();
     Error& error = Error::Handle(zone);
     error = isolate->object_store()->sticky_error();
     isolate->object_store()->clear_sticky_error();
@@ -1143,18 +1151,14 @@
   // TODO(koda): Should there be a StackZone here?
   Zone* zone = thread->zone();
 
-  const Class& script_cls = Class::Handle(zone, field.origin());
-  const Script& script = Script::Handle(zone, script_cls.script());
-
   const String& field_name = String::Handle(zone, field.name());
   String& init_name = String::Handle(zone,
       Symbols::FromConcat(Symbols::InitPrefix(), field_name));
 
+  const Script& script = Script::Handle(zone, field.script());
   Object& initializer_owner = Object::Handle(field.owner());
-  if (field.owner() != field.origin()) {
-    initializer_owner =
-        PatchClass::New(Class::Handle(field.owner()), script_cls);
-  }
+  initializer_owner =
+      PatchClass::New(Class::Handle(field.owner()), script);
 
   const Function& initializer = Function::ZoneHandle(zone,
       Function::New(init_name,
@@ -1845,6 +1849,13 @@
       const bool no_explicit_default_values = false;
       ParseFormalParameterList(no_explicit_default_values, false, &func_params);
 
+      // In top-level and mixin functions, the source may be in a different
+      // script than the script of the current class.
+      Object& sig_func_owner = Object::Handle(Z, current_class().raw());
+      if (current_class().script() != script_.raw()) {
+        sig_func_owner = PatchClass::New(current_class(), script_);
+      }
+
       // The field 'is_static' has no meaning for signature functions.
       const Function& signature_function = Function::Handle(Z,
           Function::New(*parameter.name,
@@ -1854,18 +1865,18 @@
                         /* is_abstract = */ false,
                         /* is_external = */ false,
                         /* is_native = */ false,
-                        current_class(),
+                        sig_func_owner,
                         parameter.name_pos));
       signature_function.set_result_type(result_type);
       signature_function.set_is_debuggable(false);
       AddFormalParamsToFunction(&func_params, signature_function);
-      const String& signature = String::Handle(Z,
-                                               signature_function.Signature());
+      const String& signature =
+          String::Handle(Z, signature_function.Signature());
       // Lookup the signature class, i.e. the class whose name is the signature.
       // We only lookup in the current library, but not in its imports, and only
       // create a new canonical signature class if it does not exist yet.
-      Class& signature_class = Class::ZoneHandle(Z,
-          library_.LookupLocalClass(signature));
+      Class& signature_class =
+          Class::ZoneHandle(Z, library_.LookupLocalClass(signature));
       if (signature_class.IsNull()) {
         signature_class = Class::NewSignatureClass(signature,
                                                    signature_function,
@@ -2522,7 +2533,7 @@
 
     if (found) continue;
 
-    field.RecordStore(Object::Handle(Z));
+    field.RecordStore(Object::null_object());
   }
 }
 
@@ -2689,12 +2700,12 @@
 
       // List argumentNames.
       // The missing implicit setter of the field has no argument names.
-      nsm_args->Add(new(Z) LiteralNode(init_pos, Array::ZoneHandle(Z)));
+      nsm_args->Add(new(Z) LiteralNode(init_pos, Object::null_array()));
 
       // List existingArgumentNames.
       // There is no setter for the final field, thus there are
       // no existing names.
-      nsm_args->Add(new(Z) LiteralNode(init_pos, Array::ZoneHandle(Z)));
+      nsm_args->Add(new(Z) LiteralNode(init_pos, Object::null_array()));
 
       AstNode* nsm_call =
           MakeStaticCall(Symbols::NoSuchMethodError(),
@@ -4412,7 +4423,7 @@
 
 
 void Parser::ParseEnumDeclaration(const GrowableObjectArray& pending_classes,
-                                  const Class& toplevel_class,
+                                  const Object& tl_owner,
                                   intptr_t metadata_pos) {
   TRACE_PARSER("ParseEnumDeclaration");
   const intptr_t declaration_pos = (metadata_pos > 0) ? metadata_pos
@@ -4454,7 +4465,7 @@
   cls.set_is_synthesized_class();
   cls.set_is_enum_class();
   if (metadata_pos >= 0) {
-    library_.AddClassMetadata(cls, toplevel_class, metadata_pos);
+    library_.AddClassMetadata(cls, tl_owner, metadata_pos);
   }
   cls.set_super_type(Type::Handle(Z, Type::ObjectType()));
   pending_classes.Add(cls, Heap::kOld);
@@ -4462,7 +4473,7 @@
 
 
 void Parser::ParseClassDeclaration(const GrowableObjectArray& pending_classes,
-                                   const Class& toplevel_class,
+                                   const Object& tl_owner,
                                    intptr_t metadata_pos) {
   TRACE_PARSER("ParseClassDeclaration");
   bool is_patch = false;
@@ -4577,7 +4588,7 @@
     cls.set_is_abstract();
   }
   if (metadata_pos >= 0) {
-    library_.AddClassMetadata(cls, toplevel_class, metadata_pos);
+    library_.AddClassMetadata(cls, tl_owner, metadata_pos);
   }
 
   const bool is_mixin_declaration = (CurrentToken() == Token::kASSIGN);
@@ -4633,13 +4644,12 @@
   }
 
   if (is_patch) {
+    cls.set_is_patch();
     // Apply the changes to the patched class looked up above.
     ASSERT(obj.raw() == library_.LookupLocalObject(class_name));
     // The patched class must not be finalized yet.
-    const Class& orig_class = Class::Cast(obj);
-    ASSERT(!orig_class.is_finalized());
-    orig_class.SetPatchClass(cls);
-    cls.set_is_patch();
+    ASSERT(!Class::Cast(obj).is_finalized());
+    library_.AddPatchClass(cls);
   }
   pending_classes.Add(cls, Heap::kOld);
 
@@ -4957,7 +4967,7 @@
 
 void Parser::ParseMixinAppAlias(
     const GrowableObjectArray& pending_classes,
-    const Class& toplevel_class,
+    const Object& tl_owner,
     intptr_t metadata_pos) {
   TRACE_PARSER("ParseMixinAppAlias");
   const intptr_t classname_pos = TokenPos();
@@ -5011,7 +5021,7 @@
   ExpectSemicolon();
   pending_classes.Add(mixin_application, Heap::kOld);
   if (metadata_pos >= 0) {
-    library_.AddClassMetadata(mixin_application, toplevel_class, metadata_pos);
+    library_.AddClassMetadata(mixin_application, tl_owner, metadata_pos);
   }
 }
 
@@ -5057,7 +5067,7 @@
 
 
 void Parser::ParseTypedef(const GrowableObjectArray& pending_classes,
-                          const Class& toplevel_class,
+                          const Object& tl_owner,
                           intptr_t metadata_pos) {
   TRACE_PARSER("ParseTypedef");
   intptr_t declaration_pos = (metadata_pos > 0) ? metadata_pos : TokenPos();
@@ -5067,7 +5077,7 @@
     if (FLAG_warn_mixin_typedef) {
       ReportWarning(TokenPos(), "deprecated mixin application typedef");
     }
-    ParseMixinAppAlias(pending_classes, toplevel_class, metadata_pos);
+    ParseMixinAppAlias(pending_classes, tl_owner, metadata_pos);
     return;
   }
 
@@ -5178,7 +5188,7 @@
   pending_classes.Add(function_type_alias, Heap::kOld);
   if (metadata_pos >= 0) {
     library_.AddClassMetadata(function_type_alias,
-                              toplevel_class,
+                              tl_owner,
                               metadata_pos);
   }
 }
@@ -5415,6 +5425,7 @@
 
 
 void Parser::ParseTopLevelVariable(TopLevel* top_level,
+                                   const Object& owner,
                                    intptr_t metadata_pos) {
   TRACE_PARSER("ParseTopLevelVariable");
   const bool is_const = (CurrentToken() == Token::kCONST);
@@ -5450,8 +5461,10 @@
 
     const bool is_reflectable =
         !(library_.is_dart_scheme() && library_.IsPrivate(var_name));
-    field = Field::New(var_name, is_static, is_final, is_const, is_reflectable,
-                       current_class(), type, name_pos);
+
+    field = Field::NewTopLevel(var_name, is_final, is_const, owner, name_pos);
+    field.SetFieldType(type);
+    field.set_is_reflectable(is_reflectable);
     field.SetStaticValue(Object::null_instance(), true);
     top_level->AddField(field);
     library_.AddObject(field, var_name);
@@ -5479,13 +5492,11 @@
                                /* is_abstract = */ false,
                                /* is_external = */ false,
                                /* is_native = */ false,
-                               current_class(),
+                               owner,
                                name_pos);
         getter.set_result_type(type);
         getter.set_is_debuggable(false);
-        if (library_.is_dart_scheme() && library_.IsPrivate(var_name)) {
-          getter.set_is_reflectable(false);
-        }
+        getter.set_is_reflectable(is_reflectable);
         top_level->AddFunction(getter);
       }
     } else if (is_final) {
@@ -5532,6 +5543,7 @@
 
 
 void Parser::ParseTopLevelFunction(TopLevel* top_level,
+                                   const Object& owner,
                                    intptr_t metadata_pos) {
   TRACE_PARSER("ParseTopLevelFunction");
   const intptr_t decl_begin_pos = TokenPos();
@@ -5623,7 +5635,7 @@
                     /* is_abstract = */ false,
                     is_external,
                     is_native,
-                    current_class(),
+                    owner,
                     decl_begin_pos));
   func.set_result_type(result_type);
   func.set_end_token_pos(function_end_pos);
@@ -5639,6 +5651,12 @@
   if (!is_patch) {
     library_.AddObject(func, func_name);
   } else {
+    // Need to remove the previously added function that is being patched.
+    const Class& toplevel_cls = Class::Handle(Z, library_.toplevel_class());
+    const Function& replaced_func =
+        Function::Handle(Z, toplevel_cls.LookupStaticFunction(func_name));
+    ASSERT(!replaced_func.IsNull());
+    toplevel_cls.RemoveFunction(replaced_func);
     library_.ReplaceObject(func, func_name);
   }
   if (metadata_pos >= 0) {
@@ -5648,6 +5666,7 @@
 
 
 void Parser::ParseTopLevelAccessor(TopLevel* top_level,
+                                   const Object& owner,
                                    intptr_t metadata_pos) {
   TRACE_PARSER("ParseTopLevelAccessor");
   const intptr_t decl_begin_pos = TokenPos();
@@ -5778,7 +5797,7 @@
                     /* is_abstract = */ false,
                     is_external,
                     is_native,
-                    current_class(),
+                    owner,
                     decl_begin_pos));
   func.set_result_type(result_type);
   func.set_end_token_pos(accessor_end_pos);
@@ -5795,6 +5814,14 @@
   if (!is_patch) {
     library_.AddObject(func, accessor_name);
   } else {
+    // Need to remove the previously added accessor that is being patched.
+    const Class& toplevel_cls = Class::Handle(Z,
+        owner.IsClass() ? Class::Cast(owner).raw()
+                        : PatchClass::Cast(owner).patched_class());
+    const Function& replaced_func =
+        Function::Handle(Z, toplevel_cls.LookupFunction(accessor_name));
+    ASSERT(!replaced_func.IsNull());
+    toplevel_cls.RemoveFunction(replaced_func);
     library_.ReplaceObject(func, accessor_name);
   }
   if (metadata_pos >= 0) {
@@ -5821,8 +5848,8 @@
   I->BlockClassFinalization();
   Api::Scope api_scope(T);
   Dart_Handle result = handler(tag,
-                               Api::NewHandle(I, library_.raw()),
-                               Api::NewHandle(I, url.raw()));
+                               Api::NewHandle(T, library_.raw()),
+                               Api::NewHandle(T, url.raw()));
   I->UnblockClassFinalization();
   if (Dart_IsError(result)) {
     // In case of an error we append an explanatory error message to the
@@ -5874,7 +5901,8 @@
 }
 
 
-void Parser::ParseLibraryImportExport(intptr_t metadata_pos) {
+void Parser::ParseLibraryImportExport(const Object& tl_owner,
+                                      intptr_t metadata_pos) {
   bool is_import = (CurrentToken() == Token::kIMPORT);
   bool is_export = (CurrentToken() == Token::kEXPORT);
   ASSERT(is_import || is_export);
@@ -5959,7 +5987,7 @@
   Namespace& ns = Namespace::Handle(Z,
       Namespace::New(library, show_names, hide_names));
   if (metadata_pos >= 0) {
-    ns.AddMetadata(metadata_pos, current_class());
+    ns.AddMetadata(tl_owner, metadata_pos);
   }
 
   // Ensure that private dart:_ libraries are only imported into dart:
@@ -6022,7 +6050,7 @@
 }
 
 
-void Parser::ParseLibraryDefinition() {
+void Parser::ParseLibraryDefinition(const Object& tl_owner) {
   TRACE_PARSER("ParseLibraryDefinition");
 
   // Handle the script tag.
@@ -6045,14 +6073,14 @@
     }
     ParseLibraryName();
     if (metadata_pos >= 0) {
-      library_.AddLibraryMetadata(current_class(), metadata_pos);
+      library_.AddLibraryMetadata(tl_owner, metadata_pos);
     }
     rewind_pos = TokenPos();
     metadata_pos = SkipMetadata();
   }
   while ((CurrentToken() == Token::kIMPORT) ||
       (CurrentToken() == Token::kEXPORT)) {
-    ParseLibraryImportExport(metadata_pos);
+    ParseLibraryImportExport(tl_owner, metadata_pos);
     rewind_pos = TokenPos();
     metadata_pos = SkipMetadata();
   }
@@ -6104,13 +6132,21 @@
   SetPosition(0);
   is_top_level_ = true;
   TopLevel top_level(Z);
-  Class& toplevel_class = Class::Handle(Z,
-      Class::New(Symbols::TopLevel(), script_, TokenPos()));
-  toplevel_class.set_library(library_);
+
+  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.set_library(library_);
+    library_.set_toplevel_class(toplevel_class);
+    tl_owner = toplevel_class.raw();
+  } else {
+    tl_owner = PatchClass::New(toplevel_class, script_);
+  }
 
   if (is_library_source() || is_patch_source()) {
     set_current_class(toplevel_class);
-    ParseLibraryDefinition();
+    ParseLibraryDefinition(tl_owner);
   } else if (is_part_source()) {
     ParsePartHeader();
   }
@@ -6120,27 +6156,27 @@
     set_current_class(cls);  // No current class.
     intptr_t metadata_pos = SkipMetadata();
     if (CurrentToken() == Token::kCLASS) {
-      ParseClassDeclaration(pending_classes, toplevel_class, metadata_pos);
+      ParseClassDeclaration(pending_classes, tl_owner, metadata_pos);
     } else if (CurrentToken() == Token::kENUM) {
-      ParseEnumDeclaration(pending_classes, toplevel_class, metadata_pos);
+      ParseEnumDeclaration(pending_classes, tl_owner, metadata_pos);
     } else if ((CurrentToken() == Token::kTYPEDEF) &&
                (LookaheadToken(1) != Token::kLPAREN)) {
       set_current_class(toplevel_class);
-      ParseTypedef(pending_classes, toplevel_class, metadata_pos);
+      ParseTypedef(pending_classes, tl_owner, metadata_pos);
     } else if ((CurrentToken() == Token::kABSTRACT) &&
         (LookaheadToken(1) == Token::kCLASS)) {
-      ParseClassDeclaration(pending_classes, toplevel_class, metadata_pos);
+      ParseClassDeclaration(pending_classes, tl_owner, metadata_pos);
     } else if (is_patch_source() && IsSymbol(Symbols::Patch()) &&
                (LookaheadToken(1) == Token::kCLASS)) {
-      ParseClassDeclaration(pending_classes, toplevel_class, metadata_pos);
+      ParseClassDeclaration(pending_classes, tl_owner, metadata_pos);
     } else {
       set_current_class(toplevel_class);
       if (IsVariableDeclaration()) {
-        ParseTopLevelVariable(&top_level, metadata_pos);
+        ParseTopLevelVariable(&top_level, tl_owner, metadata_pos);
       } else if (IsFunctionDeclaration()) {
-        ParseTopLevelFunction(&top_level, metadata_pos);
+        ParseTopLevelFunction(&top_level, tl_owner, metadata_pos);
       } else if (IsTopLevelAccessor()) {
-        ParseTopLevelAccessor(&top_level, metadata_pos);
+        ParseTopLevelAccessor(&top_level, tl_owner, metadata_pos);
       } else if (CurrentToken() == Token::kEOS) {
         break;
       } else {
@@ -6149,19 +6185,16 @@
     }
   }
 
-  if ((library_.num_anonymous_classes() == 0) ||
-      (top_level.fields().length() > 0) ||
-      (top_level.functions().length() > 0)) {
+  if (top_level.fields().length() > 0) {
     toplevel_class.AddFields(top_level.fields());
-    const intptr_t len = top_level.functions().length();
-    const Array& array = Array::Handle(Z, Array::New(len, Heap::kOld));
-    for (intptr_t i = 0; i < len; i++) {
-      array.SetAt(i, *top_level.functions()[i]);
-    }
-    toplevel_class.SetFunctions(array);
-    library_.AddAnonymousClass(toplevel_class);
-    pending_classes.Add(toplevel_class, Heap::kOld);
   }
+  for (intptr_t i = 0; i < top_level.functions().length(); i++) {
+    toplevel_class.AddFunction(*top_level.functions()[i]);
+  }
+  if (toplevel_class.is_finalized()) {
+    toplevel_class.ResetFinalization();
+  }
+  pending_classes.Add(toplevel_class, Heap::kOld);
 }
 
 
@@ -6220,9 +6253,7 @@
 
 void Parser::OpenAsyncClosure() {
   TRACE_PARSER("OpenAsyncClosure");
-
   async_temp_scope_ = current_block_->scope;
-
   OpenAsyncTryBlock();
 }
 
@@ -7440,7 +7471,7 @@
     // Initialize variable with null.
     variable = new(Z) LocalVariable(
         assign_pos, ident, type);
-    AstNode* null_expr = new(Z) LiteralNode(ident_pos, Instance::ZoneHandle(Z));
+    AstNode* null_expr = new(Z) LiteralNode(ident_pos, Object::null_instance());
     initialization = new(Z) StoreLocalNode(
         ident_pos, variable, null_expr);
   }
@@ -10282,7 +10313,7 @@
   arguments->Add(new(Z) LiteralNode(
       type_pos, Integer::ZoneHandle(Z, Integer::New(type_pos))));
   // Src value argument.
-  arguments->Add(new(Z) LiteralNode(type_pos, Instance::ZoneHandle(Z)));
+  arguments->Add(new(Z) LiteralNode(type_pos, Object::null_instance()));
   // Dst type name argument.
   arguments->Add(new(Z) LiteralNode(type_pos, Symbols::Malformed()));
   // Dst name argument.
@@ -10341,7 +10372,7 @@
       Smi::New(InvocationMirror::EncodeType(im_call, im_type)))));
   // List arguments.
   if (function_arguments == NULL) {
-    arguments->Add(new(Z) LiteralNode(call_pos, Array::ZoneHandle(Z)));
+    arguments->Add(new(Z) LiteralNode(call_pos, Object::null_array()));
   } else {
     ArrayNode* array = new(Z) ArrayNode(
         call_pos,
@@ -10351,7 +10382,7 @@
   }
   // List argumentNames.
   if (function_arguments == NULL) {
-    arguments->Add(new(Z) LiteralNode(call_pos, Array::ZoneHandle(Z)));
+    arguments->Add(new(Z) LiteralNode(call_pos, Object::null_array()));
   } else {
     arguments->Add(new(Z) LiteralNode(call_pos, function_arguments->names()));
   }
@@ -10554,7 +10585,7 @@
     LocalVariable* left_temp = result->AddInitializer(lhs);
     const intptr_t no_pos = Scanner::kNoSourcePos;
     LiteralNode* null_operand =
-        new(Z) LiteralNode(no_pos, Instance::ZoneHandle(Z));
+        new(Z) LiteralNode(no_pos, Object::null_instance());
     LoadLocalNode* load_left_temp = new(Z) LoadLocalNode(no_pos, left_temp);
     ComparisonNode* null_compare =
         new(Z) ComparisonNode(no_pos,
@@ -12130,8 +12161,8 @@
   }
   const Array& args_descriptor = Array::Handle(Z,
       ArgumentsDescriptor::New(num_arguments, arguments->names()));
-  Object& result = Object::Handle(Z);
-  result = DartEntry::InvokeFunction(constructor, arg_values, args_descriptor);
+  const Object& result = Object::Handle(Z,
+      DartEntry::InvokeFunction(constructor, arg_values, args_descriptor));
   if (result.IsError()) {
       // An exception may not occur in every parse attempt, i.e., the
       // generated AST is not deterministic. Therefore mark the function as
@@ -13868,7 +13899,7 @@
     primary = new(Z) LiteralNode(TokenPos(), Bool::False());
     ConsumeToken();
   } else if (token == Token::kNULL) {
-    primary = new(Z) LiteralNode(TokenPos(), Instance::ZoneHandle(Z));
+    primary = new(Z) LiteralNode(TokenPos(), Object::null_instance());
     ConsumeToken();
   } else if (token == Token::kLPAREN) {
     ConsumeToken();
@@ -13877,7 +13908,7 @@
     SetAllowFunctionLiterals(saved_mode);
     ExpectToken(Token::kRPAREN);
   } else if (token == Token::kDOUBLE) {
-    Double& double_value = Double::ZoneHandle(Z, CurrentDoubleLiteral());
+    const Double& double_value = Double::ZoneHandle(Z, CurrentDoubleLiteral());
     if (double_value.IsNull()) {
       ReportError("invalid double literal");
     }
@@ -14339,3 +14370,90 @@
 }
 
 }  // namespace dart
+
+
+#else  // DART_PRECOMPILED
+
+
+namespace dart {
+
+DEFINE_FLAG(bool, enable_mirrors, true,
+    "Disable to make importing dart:mirrors an error.");
+DEFINE_FLAG(bool, load_deferred_eagerly, false,
+    "Load deferred libraries eagerly.");
+DEFINE_FLAG(bool, link_natives_lazily, false, "Link native calls lazily");
+
+LocalVariable* ParsedFunction::EnsureExpressionTemp() {
+  UNREACHABLE();
+  return NULL;
+}
+
+
+void ParsedFunction::SetNodeSequence(SequenceNode* node_sequence) {
+  UNREACHABLE();
+}
+
+
+void ParsedFunction::SetRegExpCompileData(
+    RegExpCompileData* regexp_compile_data) {
+  UNREACHABLE();
+}
+
+
+void ParsedFunction::AllocateVariables() {
+  UNREACHABLE();
+}
+
+
+void ParsedFunction::AllocateIrregexpVariables(intptr_t num_stack_locals) {
+  UNREACHABLE();
+}
+
+
+void Parser::ParseCompilationUnit(const Library& library,
+                                  const Script& script) {
+  UNREACHABLE();
+}
+
+
+void Parser::ParseClass(const Class& cls) {
+  UNREACHABLE();
+}
+
+
+RawObject* Parser::ParseFunctionParameters(const Function& func) {
+  UNREACHABLE();
+  return Object::null();
+}
+
+
+void Parser::ParseFunction(ParsedFunction* parsed_function) {
+  UNREACHABLE();
+}
+
+
+RawObject* Parser::ParseMetadata(const Field& meta_data) {
+  UNREACHABLE();
+  return Object::null();
+}
+
+
+ParsedFunction* Parser::ParseStaticFieldInitializer(const Field& field) {
+  UNREACHABLE();
+  return NULL;
+}
+
+
+ArgumentListNode* Parser::BuildNoSuchMethodArguments(
+    intptr_t call_pos,
+    const String& function_name,
+    const ArgumentListNode& function_args,
+    const LocalVariable* temp_for_last_arg,
+    bool is_super_invocation) {
+  UNREACHABLE();
+  return NULL;
+}
+
+}  // namespace dart
+
+#endif  // DART_PRECOMPILED
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 433a0c4..98bb8a0 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -205,7 +205,7 @@
   // Parse and evaluate the metadata expressions at token_pos in the
   // class namespace of class cls (which can be the implicit toplevel
   // class if the metadata is at the top-level).
-  static RawObject* ParseMetadata(const Class& cls, intptr_t token_pos);
+  static RawObject* ParseMetadata(const Field& meta_data);
 
   // Build a function containing the initializer expression of the
   // given static field.
@@ -399,22 +399,25 @@
   // Support for parsing of scripts.
   void ParseTopLevel();
   void ParseEnumDeclaration(const GrowableObjectArray& pending_classes,
-                            const Class& toplevel_class,
+                            const Object& tl_owner,
                             intptr_t metadata_pos);
   void ParseEnumDefinition(const Class& cls);
   void ParseClassDeclaration(const GrowableObjectArray& pending_classes,
-                             const Class& toplevel_class,
+                             const Object& tl_owner,
                              intptr_t metadata_pos);
   void ParseClassDefinition(const Class& cls);
   void ParseMixinAppAlias(const GrowableObjectArray& pending_classes,
-                          const Class& toplevel_class,
+                          const Object& tl_owner,
                           intptr_t metadata_pos);
   void ParseTypedef(const GrowableObjectArray& pending_classes,
-                    const Class& toplevel_class,
+                    const Object& tl_owner,
                     intptr_t metadata_pos);
-  void ParseTopLevelVariable(TopLevel* top_level, intptr_t metadata_pos);
-  void ParseTopLevelFunction(TopLevel* top_level, intptr_t metadata_pos);
-  void ParseTopLevelAccessor(TopLevel* top_level, intptr_t metadata_pos);
+  void ParseTopLevelVariable(TopLevel* top_level,
+                             const Object& owner, intptr_t metadata_pos);
+  void ParseTopLevelFunction(TopLevel* top_level,
+                             const Object& owner, intptr_t metadata_pos);
+  void ParseTopLevelAccessor(TopLevel* top_level,
+                             const Object& owner, intptr_t metadata_pos);
   RawArray* EvaluateMetadata();
 
   RawFunction::AsyncModifier ParseFunctionModifier();
@@ -424,9 +427,10 @@
                                    intptr_t token_pos,
                                    const String& url);
   void ParseIdentList(GrowableObjectArray* names);
-  void ParseLibraryDefinition();
+  void ParseLibraryDefinition(const Object& tl_owner);
   void ParseLibraryName();
-  void ParseLibraryImportExport(intptr_t metadata_pos);
+  void ParseLibraryImportExport(const Object& tl_owner,
+                                intptr_t metadata_pos);
   void ParseLibraryPart();
   void ParsePartHeader();
   void ParseLibraryNameObsoleteSyntax();
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index 56e4ffc..0b533f0 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -4,8 +4,10 @@
 
 #include "vm/precompiler.h"
 
+#include "vm/cha.h"
 #include "vm/code_patcher.h"
 #include "vm/compiler.h"
+#include "vm/hash_table.h"
 #include "vm/isolate.h"
 #include "vm/log.h"
 #include "vm/longjump.h"
@@ -22,6 +24,10 @@
 #define Z (zone())
 
 
+DEFINE_FLAG(bool, collect_dynamic_function_names, false,
+    "In precompilation collects all dynamic function names in order to"
+    " identify unique targets");
+DEFINE_FLAG(bool, print_unique_targets, false, "Print unique dynaic targets");
 DEFINE_FLAG(bool, trace_precompiler, false, "Trace precompiler.");
 
 
@@ -94,6 +100,8 @@
     // iterations.
     ClearAllCode();
 
+    CollectDynamicFunctionNames();
+
     // Start with the allocations and invocations that happen from C++.
     AddRoots(embedder_entry_points);
 
@@ -124,12 +132,12 @@
 
 
 void Precompiler::ClearAllCode() {
-  class CodeCodeFunctionVisitor : public FunctionVisitor {
+  class ClearCodeFunctionVisitor : public FunctionVisitor {
     void VisitFunction(const Function& function) {
       function.ClearCode();
     }
   };
-  CodeCodeFunctionVisitor visitor;
+  ClearCodeFunctionVisitor visitor;
   VisitFunctions(&visitor);
 }
 
@@ -588,6 +596,11 @@
 
   class_count_++;
   cls.set_is_allocated(true);
+  error_ = cls.EnsureIsFinalized(T);
+  if (!error_.IsNull()) {
+    Jump(error_);
+  }
+
   changed_ = true;
 
   if (FLAG_trace_precompiler) {
@@ -703,11 +716,161 @@
 }
 
 
+class NameFunctionsTraits {
+ public:
+  static bool IsMatch(const Object& a, const Object& b) {
+    return a.IsString() && b.IsString() &&
+        String::Cast(a).Equals(String::Cast(b));
+  }
+  static uword Hash(const Object& obj) {
+    return String::Cast(obj).Hash();
+  }
+  static RawObject* NewKey(const String& str) {
+    return str.raw();
+  }
+};
+
+typedef UnorderedHashMap<NameFunctionsTraits> Table;
+
+
+class FunctionsTraits {
+ public:
+  static bool IsMatch(const Object& a, const Object& b) {
+    Zone* zone = Thread::Current()->zone();
+    String& a_s = String::Handle(zone);
+    String& b_s = String::Handle(zone);
+    a_s = a.IsFunction() ? Function::Cast(a).name() : String::Cast(a).raw();
+    b_s = b.IsFunction() ? Function::Cast(b).name() : String::Cast(b).raw();
+    ASSERT(a_s.IsSymbol() && b_s.IsSymbol());
+    return a_s.raw() == b_s.raw();
+  }
+  static uword Hash(const Object& obj) {
+    if (obj.IsFunction()) {
+      return String::Handle(Function::Cast(obj).name()).Hash();
+    } else {
+      ASSERT(String::Cast(obj).IsSymbol());
+      return String::Cast(obj).Hash();
+    }
+  }
+  static RawObject* NewKey(const Function& function) {
+    return function.raw();
+  }
+};
+
+typedef UnorderedHashSet<FunctionsTraits> UniqueFunctionsSet;
+
+
+static void AddNameToFunctionsTable(Zone* zone,
+                                    Table* table,
+                                    const String& fname,
+                                    const Function& function) {
+  Array& farray = Array::Handle(zone);
+  farray ^= table->InsertNewOrGetValue(fname, Array::empty_array());
+  farray = Array::Grow(farray, farray.Length() + 1);
+  farray.SetAt(farray.Length() - 1, function);
+  table->UpdateValue(fname, farray);
+}
+
+
+void Precompiler::CollectDynamicFunctionNames() {
+  if (!FLAG_collect_dynamic_function_names) {
+    return;
+  }
+  Library& lib = Library::Handle(Z);
+  Class& cls = Class::Handle(Z);
+  Array& functions = Array::Handle(Z);
+  Function& function = Function::Handle(Z);
+  String& fname = String::Handle(Z);
+  Array& farray = Array::Handle(Z);
+
+  Table table(HashTables::New<Table>(100));
+  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.
+      }
+      functions = cls.functions();
+      for (intptr_t j = 0; j < functions.Length(); j++) {
+        function ^= functions.At(j);
+        if (function.IsDynamicFunction()) {
+          fname = function.name();
+          if (function.IsSetterFunction() ||
+              function.IsImplicitSetterFunction()) {
+            AddNameToFunctionsTable(zone(), &table, fname, function);
+          } else if (function.IsGetterFunction() ||
+                     function.IsImplicitGetterFunction()) {
+            // Enter both getter and non getter name.
+            AddNameToFunctionsTable(zone(), &table, fname, function);
+            fname = Field::NameFromGetter(fname);
+            AddNameToFunctionsTable(zone(), &table, fname, function);
+          } else {
+            // Regular function. Enter both getter and non getter name.
+            AddNameToFunctionsTable(zone(), &table, fname, function);
+            fname = Field::GetterName(fname);
+            AddNameToFunctionsTable(zone(), &table, fname, function);
+          }
+        }
+      }
+    }
+  }
+
+  // Locate all entries with one function only, and whose owner is neither
+  // subclassed nor implemented.
+  Table::Iterator iter(&table);
+  String& key = String::Handle(Z);
+  UniqueFunctionsSet functions_set(HashTables::New<UniqueFunctionsSet>(20));
+  while (iter.MoveNext()) {
+    intptr_t curr_key = iter.Current();
+    key ^= table.GetKey(curr_key);
+    farray ^= table.GetOrNull(key);
+    ASSERT(!farray.IsNull());
+    if (farray.Length() == 1) {
+      function ^= farray.At(0);
+      cls = function.Owner();
+      if (!CHA::IsImplemented(cls) && !CHA::HasSubclasses(cls)) {
+        functions_set.Insert(function);
+      }
+    }
+  }
+
+  if (FLAG_print_unique_targets) {
+    UniqueFunctionsSet::Iterator unique_iter(&functions_set);
+    while (unique_iter.MoveNext()) {
+      intptr_t curr_key = unique_iter.Current();
+      function ^= functions_set.GetKey(curr_key);
+      THR_Print("* %s\n", function.ToQualifiedCString());
+    }
+    THR_Print("%" Pd " of %" Pd " dynamic selectors are unique\n",
+        functions_set.NumOccupied(), table.NumOccupied());
+  }
+
+  isolate()->object_store()->set_unique_dynamic_targets(
+      functions_set.Release());
+  table.Release();
+}
+
+
+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::DropUncompiledFunctions() {
   Library& lib = Library::Handle(Z);
   Class& cls = Class::Handle(Z);
   Array& functions = Array::Handle(Z);
   Function& function = Function::Handle(Z);
+  Function& function2 = Function::Handle(Z);
   GrowableObjectArray& retained_functions = GrowableObjectArray::Handle(Z);
   GrowableObjectArray& closures = GrowableObjectArray::Handle(Z);
 
@@ -724,7 +887,16 @@
       retained_functions = GrowableObjectArray::New();
       for (intptr_t j = 0; j < functions.Length(); j++) {
         function ^= functions.At(j);
-        if (function.HasCode()) {
+        bool retain = function.HasCode();
+        if (!retain && function.HasImplicitClosureFunction()) {
+          // It can happen that all uses of an implicit closure inline their
+          // target function, leaving the target function uncompiled. Keep
+          // the target function anyway so we can enumerate it to bind its
+          // static calls, etc.
+          function2 = function.ImplicitClosureFunction();
+          retain = function2.HasCode();
+        }
+        if (retain) {
           retained_functions.Add(function);
           function.DropUncompiledImplicitClosureFunction();
         } else {
@@ -775,7 +947,10 @@
     }
 
     void VisitFunction(const Function& function) {
-      ASSERT(function.HasCode());
+      if (!function.HasCode()) {
+        ASSERT(function.HasImplicitClosureFunction());
+        return;
+      }
       code_ = function.CurrentCode();
       table_ = code_.static_calls_target_table();
 
@@ -832,6 +1007,10 @@
     }
 
     void VisitFunction(const Function& function) {
+      if (!function.HasCode()) {
+        ASSERT(function.HasImplicitClosureFunction());
+        return;
+      }
       code_ = function.CurrentCode();
       stackmaps_ = code_.stackmaps();
       if (stackmaps_.IsNull()) return;
@@ -871,6 +1050,7 @@
   Library& lib = Library::Handle(Z);
   Class& cls = Class::Handle(Z);
   Array& functions = Array::Handle(Z);
+  Object& object = Object::Handle(Z);
   Function& function = Function::Handle(Z);
   GrowableObjectArray& closures = GrowableObjectArray::Handle(Z);
 
@@ -892,6 +1072,15 @@
           visitor->VisitFunction(function);
         }
       }
+
+      functions = cls.invocation_dispatcher_cache();
+      for (intptr_t j = 0; j < functions.Length(); j++) {
+        object = functions.At(j);
+        if (object.IsFunction()) {
+          function ^= functions.At(j);
+          visitor->VisitFunction(function);
+        }
+      }
     }
   }
   closures = isolate()->object_store()->closure_functions();
@@ -922,7 +1111,10 @@
       if (cls.IsDynamicClass()) {
         continue;  // class 'dynamic' is in the read-only VM isolate.
       }
-      cls.EnsureIsFinalized(T);
+      error_ = cls.EnsureIsFinalized(T);
+      if (!error_.IsNull()) {
+        Jump(error_);
+      }
     }
   }
   I->set_all_classes_finalized(true);
diff --git a/runtime/vm/precompiler.h b/runtime/vm/precompiler.h
index 3710edf..50f9551 100644
--- a/runtime/vm/precompiler.h
+++ b/runtime/vm/precompiler.h
@@ -93,6 +93,16 @@
       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);
+
  private:
   Precompiler(Thread* thread, bool reset_fields);
 
@@ -115,6 +125,7 @@
   void CheckForNewDynamicFunctions();
 
   void DropUncompiledFunctions();
+  void CollectDynamicFunctionNames();
   void BindStaticCalls();
   void DedupStackmaps();
   void ResetPrecompilerState();
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index d1d52b8..af80f9f 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -712,7 +712,6 @@
     // We are executing Dart code. We have frame pointers.
     dart_stack_walker->walk();
   } else {
-    sample->set_vm_tag(VMTag::kEmbedderTagId);
     sample->SetAt(0, pc);
   }
 
@@ -747,17 +746,19 @@
                                              uword* stack_lower,
                                              uword* stack_upper) {
   ASSERT(thread != NULL);
-  Isolate* isolate = thread->isolate();
-  ASSERT(isolate != NULL);
+  OSThread* os_thread = thread->os_thread();
+  ASSERT(os_thread != NULL);
   ASSERT(stack_lower != NULL);
   ASSERT(stack_upper != NULL);
 #if defined(USING_SIMULATOR)
   const bool in_dart_code = thread->IsExecutingDartCode();
   if (in_dart_code) {
+    Isolate* isolate = thread->isolate();
+    ASSERT(isolate != NULL);
     Simulator* simulator = isolate->simulator();
     *stack_lower = simulator->StackBase();
     *stack_upper = simulator->StackTop();
-  } else if (!isolate->GetProfilerStackBounds(stack_lower, stack_upper)) {
+  } else if (!os_thread->GetProfilerStackBounds(stack_lower, stack_upper)) {
     // Could not get stack boundary.
     return false;
   }
@@ -765,7 +766,7 @@
     return false;
   }
 #else
-  if (!isolate->GetProfilerStackBounds(stack_lower, stack_upper) ||
+  if (!os_thread->GetProfilerStackBounds(stack_lower, stack_upper) ||
       (*stack_lower == 0) || (*stack_upper == 0)) {
     // Could not get stack boundary.
     return false;
@@ -782,12 +783,12 @@
   }
 
   if ((sp < *stack_lower) || (sp >= *stack_upper)) {
-    // Stack pointer is outside isolate stack boundary.
+    // Stack pointer is outside thread's stack boundary.
     return false;
   }
 
   if ((fp < *stack_lower) || (fp >= *stack_upper)) {
-    // Frame pointer is outside isolate stack boundary.
+    // Frame pointer is outside threads's stack boundary.
     return false;
   }
 
@@ -819,7 +820,7 @@
   Isolate* isolate = thread->isolate();
   ASSERT(sample_buffer != NULL);
   Sample* sample = sample_buffer->ReserveSample();
-  sample->Init(isolate, OS::GetCurrentTimeMicros(), tid);
+  sample->Init(isolate, OS::GetCurrentTraceMicros(), tid);
   uword vm_tag = thread->vm_tag();
 #if defined(USING_SIMULATOR)
   // When running in the simulator, the runtime entry function address
@@ -859,6 +860,8 @@
 
 void Profiler::SampleAllocation(Thread* thread, intptr_t cid) {
   ASSERT(thread != NULL);
+  OSThread* os_thread = thread->os_thread();
+  ASSERT(os_thread != NULL);
   Isolate* isolate = thread->isolate();
   if (!CheckIsolate(isolate)) {
     return;
@@ -895,9 +898,7 @@
       return;
     }
 
-    Sample* sample = SetupSample(thread,
-                                 sample_buffer,
-                                 OSThread::GetCurrentThreadId());
+    Sample* sample = SetupSample(thread, sample_buffer, os_thread->id());
     sample->SetAllocationCid(cid);
     ProfilerNativeStackWalker native_stack_walker(isolate,
                                                   sample,
@@ -909,9 +910,7 @@
                                                   sp);
     native_stack_walker.walk();
   } else if (exited_dart_code) {
-    Sample* sample = SetupSample(thread,
-                                 sample_buffer,
-                                 OSThread::GetCurrentThreadId());
+    Sample* sample = SetupSample(thread, sample_buffer, os_thread->id());
     sample->SetAllocationCid(cid);
     ProfilerDartExitStackWalker dart_exit_stack_walker(thread,
                                                        isolate,
@@ -921,11 +920,8 @@
   } else {
     // Fall back.
     uintptr_t pc = GetProgramCounter();
-    Sample* sample = SetupSample(thread,
-                                 sample_buffer,
-                                 OSThread::GetCurrentThreadId());
+    Sample* sample = SetupSample(thread, sample_buffer, os_thread->id());
     sample->SetAllocationCid(cid);
-    sample->set_vm_tag(VMTag::kEmbedderTagId);
     sample->SetAt(0, pc);
   }
 }
@@ -934,6 +930,8 @@
 void Profiler::SampleThread(Thread* thread,
                             const InterruptedThreadState& state) {
   ASSERT(thread != NULL);
+  OSThread* os_thread = thread->os_thread();
+  ASSERT(os_thread != NULL);
   Isolate* isolate = thread->isolate();
 
   if (StubCode::HasBeenInitialized() &&
@@ -1002,9 +1000,7 @@
   }
 
   // Setup sample.
-  Sample* sample = SetupSample(thread,
-                               sample_buffer,
-                               OSThread::GetCurrentThreadId());
+  Sample* sample = SetupSample(thread, sample_buffer, os_thread->id());
   // Increment counter for vm tag.
   VMTagCounters* counters = isolate->vm_tag_counters();
   ASSERT(counters != NULL);
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index 7ed4c36..a35da30 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -152,12 +152,12 @@
   explicit AllocationFilter(Isolate* isolate, intptr_t cid)
       : SampleFilter(isolate),
         cid_(cid),
-        enable_embedder_ticks_(false) {
+        enable_vm_ticks_(false) {
   }
 
   bool FilterSample(Sample* sample) {
-    if (!enable_embedder_ticks_ &&
-        (sample->vm_tag() == VMTag::kEmbedderTagId)) {
+    if (!enable_vm_ticks_ &&
+        (sample->vm_tag() == VMTag::kVMTagId)) {
       // We don't want to see embedder ticks in the test.
       return false;
     }
@@ -165,13 +165,13 @@
            (sample->allocation_cid() == cid_);
   }
 
-  void set_enable_embedder_ticks(bool enable) {
-    enable_embedder_ticks_ = enable;
+  void set_enable_vm_ticks(bool enable) {
+    enable_vm_ticks_ = enable;
   }
 
  private:
   intptr_t cid_;
-  bool enable_embedder_ticks_;
+  bool enable_vm_ticks_;
 };
 
 
@@ -835,7 +835,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, class_class.id());
-    filter.set_enable_embedder_ticks(true);
+    filter.set_enable_vm_ticks(true);
     profile.Build(thread, &filter, Profile::kNoTags);
     // We should have one allocation sample.
     EXPECT_EQ(1, profile.sample_count());
@@ -864,7 +864,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, class_class.id());
-    filter.set_enable_embedder_ticks(true);
+    filter.set_enable_vm_ticks(true);
     profile.Build(thread, &filter, Profile::kNoTags);
     // We should still only have one allocation sample.
     EXPECT_EQ(1, profile.sample_count());
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 9b335eb..b178fed 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -614,6 +614,7 @@
   friend class Scavenger;
   friend class ScavengerVisitor;
   friend class SizeExcludingClassVisitor;  // GetClassId
+  friend class InstanceAccumulator;  // GetClassId
   friend class RetainingPathVisitor;  // GetClassId
   friend class SkippedCodeFunctions;  // StorePointer
   friend class InstructionsReader;  // tags_ check
@@ -740,9 +741,10 @@
     return reinterpret_cast<RawObject**>(&ptr()->patched_class_);
   }
   RawClass* patched_class_;
-  RawClass* source_class_;
+  RawClass* origin_class_;
+  RawScript* script_;
   RawObject** to() {
-    return reinterpret_cast<RawObject**>(&ptr()->source_class_);
+    return reinterpret_cast<RawObject**>(&ptr()->script_);
   }
 
   friend class Function;
@@ -977,7 +979,7 @@
   RawString* private_key_;
   RawArray* dictionary_;         // Top-level names in this library.
   RawGrowableObjectArray* metadata_;  // Metadata on classes, methods etc.
-  RawArray* anonymous_classes_;  // Classes containing top-level elements.
+  RawClass* toplevel_class_;  // Class containing top-level elements.
   RawGrowableObjectArray* patch_classes_;
   RawArray* imports_;            // List of Namespaces imported without prefix.
   RawArray* exports_;            // List of re-exported Namespaces.
@@ -994,7 +996,6 @@
   Dart_NativeEntryResolver native_entry_resolver_;  // Resolves natives.
   Dart_NativeEntrySymbol native_entry_symbol_resolver_;
   classid_t index_;             // Library id number.
-  classid_t num_anonymous_;     // Number of entries in anonymous_classes_.
   uint16_t num_imports_;        // Number of entries in imports_.
   int8_t load_state_;           // Of type LibraryState.
   bool corelib_imported_;
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index c492b79..38e1f17 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -81,7 +81,6 @@
 
     // Set all the object fields.
     READ_OBJECT_FIELDS(cls, cls.raw()->from(), cls.raw()->to(), kAsReference);
-
     ASSERT(!cls.IsInFullSnapshot() || (kind == Snapshot::kFull));
   } else {
     cls ^= reader->ReadClassId(object_id);
@@ -1069,8 +1068,6 @@
     // Set all non object fields.
     library.StoreNonPointer(&library.raw_ptr()->index_,
                             reader->ReadClassIDValue());
-    library.StoreNonPointer(&library.raw_ptr()->num_anonymous_,
-                            reader->ReadClassIDValue());
     library.StoreNonPointer(&library.raw_ptr()->num_imports_,
                             reader->Read<uint16_t>());
     library.StoreNonPointer(&library.raw_ptr()->load_state_,
@@ -1140,7 +1137,6 @@
     ASSERT((kind == Snapshot::kFull) || !ptr()->is_in_fullsnapshot_);
     // Write out all non object fields.
     writer->WriteClassIDValue(ptr()->index_);
-    writer->WriteClassIDValue(ptr()->num_anonymous_);
     writer->Write<uint16_t>(ptr()->num_imports_);
     writer->Write<int8_t>(ptr()->load_state_);
     writer->Write<bool>(ptr()->corelib_imported_);
diff --git a/runtime/vm/runtime_entry.h b/runtime/vm/runtime_entry.h
index 97b5623..4004e4f 100644
--- a/runtime/vm/runtime_entry.h
+++ b/runtime/vm/runtime_entry.h
@@ -45,8 +45,7 @@
         is_leaf_(is_leaf),
         is_float_(is_float),
         next_(NULL) {
-    // Strip off const for registration.
-    VMTag::RegisterRuntimeEntry(const_cast<RuntimeEntry*>(this));
+    VMTag::RegisterRuntimeEntry(this);
   }
   ~RuntimeEntry() {}
 
diff --git a/runtime/vm/scavenger.cc b/runtime/vm/scavenger.cc
index c2822b5..6d9799e 100644
--- a/runtime/vm/scavenger.cc
+++ b/runtime/vm/scavenger.cc
@@ -255,12 +255,9 @@
 
 class ScavengerWeakVisitor : public HandleVisitor {
  public:
-  // 'prologue_weak_were_strong' is currently only used for sanity checking.
-  explicit ScavengerWeakVisitor(Scavenger* scavenger,
-                                bool prologue_weak_were_strong)
+  explicit ScavengerWeakVisitor(Scavenger* scavenger)
       :  HandleVisitor(Thread::Current()),
-         scavenger_(scavenger),
-         prologue_weak_were_strong_(prologue_weak_were_strong) {
+         scavenger_(scavenger) {
     ASSERT(scavenger->heap_->isolate() == Thread::Current()->isolate());
   }
 
@@ -269,8 +266,6 @@
       reinterpret_cast<FinalizablePersistentHandle*>(addr);
     RawObject** p = handle->raw_addr();
     if (scavenger_->IsUnreachable(p)) {
-      ASSERT(!handle->IsPrologueWeakPersistent() ||
-             !prologue_weak_were_strong_);
       handle->UpdateUnreachable(thread()->isolate());
     } else {
       handle->UpdateRelocated(thread()->isolate());
@@ -279,7 +274,6 @@
 
  private:
   Scavenger* scavenger_;
-  bool prologue_weak_were_strong_;
 
   DISALLOW_COPY_AND_ASSIGN(ScavengerWeakVisitor);
 };
@@ -561,12 +555,9 @@
 }
 
 
-void Scavenger::IterateRoots(Isolate* isolate,
-                             ScavengerVisitor* visitor,
-                             bool visit_prologue_weak_persistent_handles) {
+void Scavenger::IterateRoots(Isolate* isolate, ScavengerVisitor* visitor) {
   int64_t start = OS::GetCurrentTimeMicros();
   isolate->VisitObjectPointers(visitor,
-                               visit_prologue_weak_persistent_handles,
                                StackFrameIterator::kDontValidateFrames);
   int64_t middle = OS::GetCurrentTimeMicros();
   IterateStoreBuffers(isolate, visitor);
@@ -600,81 +591,8 @@
 }
 
 
-void Scavenger::IterateWeakReferences(Isolate* isolate,
-                                      ScavengerVisitor* visitor) {
-  ApiState* state = isolate->api_state();
-  ASSERT(state != NULL);
-  while (true) {
-    WeakReferenceSet* queue = state->delayed_weak_reference_sets();
-    if (queue == NULL) {
-      // The delay queue is empty therefore no clean-up is required.
-      return;
-    }
-    state->set_delayed_weak_reference_sets(NULL);
-    while (queue != NULL) {
-      WeakReferenceSet* reference_set = WeakReferenceSet::Pop(&queue);
-      ASSERT(reference_set != NULL);
-      intptr_t num_keys = reference_set->num_keys();
-      intptr_t num_values = reference_set->num_values();
-      if ((num_keys == 1) && (num_values == 1) &&
-          reference_set->SingletonKeyEqualsValue()) {
-        // We do not have to process sets that have just one key/value pair
-        // and the key and value are identical.
-        continue;
-      }
-      bool is_unreachable = true;
-      // Test each key object for reachability.  If a key object is
-      // reachable, all value objects should be scavenged.
-      for (intptr_t k = 0; k < num_keys; ++k) {
-        if (!IsUnreachable(reference_set->get_key(k))) {
-          for (intptr_t v = 0; v < num_values; ++v) {
-            RawObject** raw_obj_addr = reference_set->get_value(v);
-            RawObject* raw_obj = *raw_obj_addr;
-            // Only visit heap objects which are in from space, aka new objects
-            // not in to space. This avoids visiting a value multiple times
-            // during a scavenge.
-            if (raw_obj->IsHeapObject() &&
-                raw_obj->IsNewObject() &&
-                !to_->Contains(RawObject::ToAddr(raw_obj))) {
-              visitor->VisitPointer(raw_obj_addr);
-            }
-          }
-          is_unreachable = false;
-          // Since we have found a key object that is reachable and all
-          // value objects have been marked we can break out of iterating
-          // this set and move on to the next set.
-          break;
-        }
-      }
-      // If all key objects are unreachable put the reference on a
-      // delay queue.  This reference will be revisited if another
-      // reference is scavenged.
-      if (is_unreachable) {
-        state->DelayWeakReferenceSet(reference_set);
-      }
-    }
-    if ((resolved_top_ < top_) || PromotedStackHasMore()) {
-      ProcessToSpace(visitor);
-    } else {
-      // Break out of the loop if there has been no forward process.
-      // All key objects in the weak reference sets are unreachable
-      // so we reset the weak reference sets queue.
-      state->set_delayed_weak_reference_sets(NULL);
-      break;
-    }
-  }
-  ASSERT(state->delayed_weak_reference_sets() == NULL);
-  // All weak reference sets are zone allocated and unmarked references which
-  // were on the delay queue will be freed when the zone is released in the
-  // epilog callback.
-}
-
-
-void Scavenger::IterateWeakRoots(Isolate* isolate,
-                                 HandleVisitor* visitor,
-                                 bool visit_prologue_weak_persistent_handles) {
-  isolate->VisitWeakPersistentHandles(visitor,
-                                      visit_prologue_weak_persistent_handles);
+void Scavenger::IterateWeakRoots(Isolate* isolate, HandleVisitor* visitor) {
+  isolate->VisitWeakPersistentHandles(visitor);
 }
 
 
@@ -873,16 +791,12 @@
     // Setup the visitor and run the scavenge.
     ScavengerVisitor visitor(isolate, this, from);
     page_space->AcquireDataLock();
-    const bool prologue_weak_are_strong = !invoke_api_callbacks;
-    IterateRoots(isolate, &visitor, prologue_weak_are_strong);
+    IterateRoots(isolate, &visitor);
     int64_t start = OS::GetCurrentTimeMicros();
     ProcessToSpace(&visitor);
     int64_t middle = OS::GetCurrentTimeMicros();
-    IterateWeakReferences(isolate, &visitor);
-    ScavengerWeakVisitor weak_visitor(this, prologue_weak_are_strong);
-    // Include the prologue weak handles, since we must process any promotion.
-    const bool visit_prologue_weak_handles = true;
-    IterateWeakRoots(isolate, &weak_visitor, visit_prologue_weak_handles);
+    ScavengerWeakVisitor weak_visitor(this);
+    IterateWeakRoots(isolate, &weak_visitor);
     visitor.Finalize();
     ProcessWeakTables();
     page_space->ReleaseDataLock();
diff --git a/runtime/vm/scavenger.h b/runtime/vm/scavenger.h
index af3f129..11a0aa1 100644
--- a/runtime/vm/scavenger.h
+++ b/runtime/vm/scavenger.h
@@ -231,14 +231,10 @@
   SemiSpace* Prologue(Isolate* isolate, bool invoke_api_callbacks);
   void IterateStoreBuffers(Isolate* isolate, ScavengerVisitor* visitor);
   void IterateObjectIdTable(Isolate* isolate, ScavengerVisitor* visitor);
-  void IterateRoots(Isolate* isolate,
-                    ScavengerVisitor* visitor,
-                    bool visit_prologue_weak_persistent_handles);
+  void IterateRoots(Isolate* isolate, ScavengerVisitor* visitor);
   void IterateWeakProperties(Isolate* isolate, ScavengerVisitor* visitor);
   void IterateWeakReferences(Isolate* isolate, ScavengerVisitor* visitor);
-  void IterateWeakRoots(Isolate* isolate,
-                        HandleVisitor* visitor,
-                        bool visit_prologue_weak_persistent_handles);
+  void IterateWeakRoots(Isolate* isolate, HandleVisitor* visitor);
   void ProcessToSpace(ScavengerVisitor* visitor);
   uword ProcessWeakProperty(RawWeakProperty* raw_weak,
                             ScavengerVisitor* visitor);
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 50d1aa4..ccc2d58 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -97,7 +97,7 @@
 EmbedderServiceHandler* Service::isolate_service_handler_head_ = NULL;
 EmbedderServiceHandler* Service::root_service_handler_head_ = NULL;
 struct ServiceMethodDescriptor;
-ServiceMethodDescriptor* FindMethod(const char* method_name);
+const ServiceMethodDescriptor* FindMethod(const char* method_name);
 
 
 // Support for streams defined in embedders.
@@ -491,7 +491,7 @@
 
 class EnumParameter : public MethodParameter {
  public:
-  EnumParameter(const char* name, bool required, const char** enums)
+  EnumParameter(const char* name, bool required, const char* const* enums)
       : MethodParameter(name, required),
         enums_(enums) {
   }
@@ -509,14 +509,14 @@
   }
 
  private:
-  const char** enums_;
+  const char* const* enums_;
 };
 
 
 // If the key is not found, this function returns the last element in the
 // values array. This can be used to encode the default value.
 template<typename T>
-T EnumMapper(const char* value, const char** enums, T* values) {
+T EnumMapper(const char* value, const char* const* enums, T* values) {
   ASSERT(value != NULL);
   intptr_t i = 0;
   for (i = 0; enums[i] != NULL; i++) {
@@ -644,7 +644,7 @@
     }
     const char* c_method_name = method_name.ToCString();
 
-    ServiceMethodDescriptor* method = FindMethod(c_method_name);
+    const ServiceMethodDescriptor* method = FindMethod(c_method_name);
     if (method != NULL) {
       if (!ValidateParameters(method->parameters, &js)) {
         js.PostReply();
@@ -1271,22 +1271,24 @@
     return func.raw();
 
   } else if (strcmp(parts[2], "fields") == 0) {
-    // Field ids look like: "classes/17/fields/11"
+    // Field ids look like: "classes/17/fields/name"
     if (num_parts != 4) {
       return Object::sentinel().raw();
     }
-    intptr_t id;
-    if (!GetIntegerId(parts[3], &id)) {
+    const char* encoded_id = parts[3];
+    String& id = String::Handle(zone, String::New(encoded_id));
+    id = String::DecodeIRI(id);
+    if (id.IsNull()) {
       return Object::sentinel().raw();
     }
-    Field& field = Field::Handle(zone, cls.FieldFromIndex(id));
+    Field& field = Field::Handle(zone, cls.LookupField(id));
     if (field.IsNull()) {
       return Object::sentinel().raw();
     }
     return field.raw();
 
   } else if (strcmp(parts[2], "functions") == 0) {
-    // Function ids look like: "classes/17/functions/11"
+    // Function ids look like: "classes/17/functions/name"
     if (num_parts != 4) {
       return Object::sentinel().raw();
     }
@@ -1385,12 +1387,12 @@
     return Object::sentinel().raw();
   }
   uword pc;
-  static const char* kCollectedPrefix = "collected-";
+  static const char* const kCollectedPrefix = "collected-";
   static intptr_t kCollectedPrefixLen = strlen(kCollectedPrefix);
-  static const char* kNativePrefix = "native-";
-  static intptr_t kNativePrefixLen = strlen(kNativePrefix);
-  static const char* kReusedPrefix = "reused-";
-  static intptr_t kReusedPrefixLen = strlen(kReusedPrefix);
+  static const char* const kNativePrefix = "native-";
+  static const intptr_t kNativePrefixLen = strlen(kNativePrefix);
+  static const char* const kReusedPrefix = "reused-";
+  static const intptr_t kReusedPrefixLen = strlen(kReusedPrefix);
   const char* id = parts[1];
   if (strncmp(kCollectedPrefix, id, kCollectedPrefixLen) == 0) {
     if (!GetUnsignedIntegerId(&id[kCollectedPrefixLen], &pc, 16)) {
@@ -1764,16 +1766,14 @@
 
 static const MethodParameter* get_retained_size_params[] = {
   ISOLATE_PARAMETER,
+  new IdParameter("targetId", true),
   NULL,
 };
 
 
 static bool GetRetainedSize(Thread* thread, JSONStream* js) {
   const char* target_id = js->LookupParam("targetId");
-  if (target_id == NULL) {
-    PrintMissingParamError(js, "targetId");
-    return true;
-  }
+  ASSERT(target_id != NULL);
   ObjectIdRing::LookupResult lookup_result;
   Object& obj = Object::Handle(LookupHeapObject(thread, target_id,
                                                 &lookup_result));
@@ -1806,6 +1806,48 @@
 }
 
 
+static const MethodParameter* get_reachable_size_params[] = {
+  ISOLATE_PARAMETER,
+  new IdParameter("targetId", true),
+  NULL,
+};
+
+
+static bool GetReachableSize(Thread* thread, JSONStream* js) {
+  const char* target_id = js->LookupParam("targetId");
+  ASSERT(target_id != NULL);
+  ObjectIdRing::LookupResult lookup_result;
+  Object& obj = Object::Handle(LookupHeapObject(thread, target_id,
+                                                &lookup_result));
+  if (obj.raw() == Object::sentinel().raw()) {
+    if (lookup_result == ObjectIdRing::kCollected) {
+      PrintSentinel(js, kCollectedSentinel);
+    } else if (lookup_result == ObjectIdRing::kExpired) {
+      PrintSentinel(js, kExpiredSentinel);
+    } else {
+      PrintInvalidParamError(js, "targetId");
+    }
+    return true;
+  }
+  // TODO(rmacnak): There is no way to get the size retained by a class object.
+  // SizeRetainedByClass should be a separate RPC.
+  if (obj.IsClass()) {
+    const Class& cls = Class::Cast(obj);
+    ObjectGraph graph(thread);
+    intptr_t retained_size = graph.SizeReachableByClass(cls.id());
+    const Object& result = Object::Handle(Integer::New(retained_size));
+    result.PrintJSON(js, true);
+    return true;
+  }
+
+  ObjectGraph graph(thread);
+  intptr_t retained_size = graph.SizeReachableByInstance(obj);
+  const Object& result = Object::Handle(Integer::New(retained_size));
+  result.PrintJSON(js, true);
+  return true;
+}
+
+
 static const MethodParameter* evaluate_params[] = {
   ISOLATE_PARAMETER,
   NULL,
@@ -2446,14 +2488,14 @@
     return true;
   }
   // Verify id begins with "metrics/".
-  static const char* kMetricIdPrefix = "metrics/";
+  static const char* const kMetricIdPrefix = "metrics/";
   static intptr_t kMetricIdPrefixLen = strlen(kMetricIdPrefix);
   if (strncmp(metric_id, kMetricIdPrefix, kMetricIdPrefixLen) != 0) {
     PrintInvalidParamError(js, "metricId");
     return true;
   }
   // Check if id begins with "metrics/native/".
-  static const char* kNativeMetricIdPrefix = "metrics/native/";
+  static const char* const kNativeMetricIdPrefix = "metrics/native/";
   static intptr_t kNativeMetricIdPrefixLen = strlen(kNativeMetricIdPrefix);
   const bool native_metric =
       strncmp(metric_id, kNativeMetricIdPrefix, kNativeMetricIdPrefixLen) == 0;
@@ -2662,7 +2704,7 @@
 }
 
 
-static const char* tags_enum_names[] = {
+static const char* const tags_enum_names[] = {
   "None",
   "UserVM",
   "UserOnly",
@@ -2672,7 +2714,7 @@
 };
 
 
-static Profile::TagOrder tags_enum_values[] = {
+static const Profile::TagOrder tags_enum_values[] = {
   Profile::kNoTags,
   Profile::kUserVM,
   Profile::kUser,
@@ -3397,7 +3439,7 @@
 }
 
 
-static ServiceMethodDescriptor service_methods_[] = {
+static const ServiceMethodDescriptor service_methods_[] = {
   { "_dumpIdZone", DumpIdZone, NULL },
   { "_echo", Echo,
     NULL },
@@ -3455,6 +3497,8 @@
     get_object_by_address_params },
   { "_getPorts", GetPorts,
     get_ports_params },
+  { "_getReachableSize", GetReachableSize,
+    get_reachable_size_params },
   { "_getRetainedSize", GetRetainedSize,
     get_retained_size_params },
   { "_getRetainingPath", GetRetainingPath,
@@ -3504,11 +3548,11 @@
 };
 
 
-ServiceMethodDescriptor* FindMethod(const char* method_name) {
+const ServiceMethodDescriptor* FindMethod(const char* method_name) {
   intptr_t num_methods = sizeof(service_methods_) /
                          sizeof(service_methods_[0]);
   for (intptr_t i = 0; i < num_methods; i++) {
-    ServiceMethodDescriptor& method = service_methods_[i];
+    const ServiceMethodDescriptor& method = service_methods_[i];
     if (strcmp(method_name, method.name) == 0) {
       return &method;
     }
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index d824d4d..e71169d 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1134,6 +1134,11 @@
   //
   // This is provided for the WriteEvent event.
   string bytes [optional];
+
+  // The argument passed to dart:developer.inspect.
+  //
+  // This is provided for the Inspect event.
+  @Instance inspectee [optional];
 }
 ```
 
@@ -1196,7 +1201,10 @@
   GC,
 
   // Notification of bytes written, for example, to stdout/stderr.
-  WriteEvent
+  WriteEvent,
+
+  // Notification from dart:developer.inspect.
+  Inspect
 }
 ```
 
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index 1f70a67..eddb622 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -161,7 +161,7 @@
       "  x();\n"
       "}";
 
-  Isolate* isolate = Isolate::Current();
+  Isolate* isolate = thread->isolate();
   Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
   EXPECT_VALID(lib);
   Library& vmlib = Library::Handle();
@@ -184,7 +184,7 @@
   // Build a mock message handler and wrap it in a dart port.
   ServiceTestMessageHandler handler;
   Dart_Port port_id = PortMap::CreatePort(&handler);
-  Dart_Handle port = Api::NewHandle(isolate, SendPort::New(port_id));
+  Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
   EXPECT_VALID(port);
   EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
 
@@ -267,7 +267,7 @@
       "main() {\n"
       "}";
 
-  Isolate* isolate = Isolate::Current();
+  Isolate* isolate = thread->isolate();
 
   Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
   EXPECT_VALID(lib);
@@ -288,7 +288,7 @@
   // Build a mock message handler and wrap it in a dart port.
   ServiceTestMessageHandler handler;
   Dart_Port port_id = PortMap::CreatePort(&handler);
-  Dart_Handle port = Api::NewHandle(isolate, SendPort::New(port_id));
+  Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
   EXPECT_VALID(port);
   EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
 
@@ -326,7 +326,7 @@
     "  x();\n"
     "}";
 
-  Isolate* isolate = Isolate::Current();
+  Isolate* isolate = thread->isolate();
   Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
   EXPECT_VALID(lib);
   Library& vmlib = Library::Handle();
@@ -350,7 +350,7 @@
   // Build a mock message handler and wrap it in a dart port.
   ServiceTestMessageHandler handler;
   Dart_Port port_id = PortMap::CreatePort(&handler);
-  Dart_Handle port = Api::NewHandle(isolate, SendPort::New(port_id));
+  Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
   EXPECT_VALID(port);
   EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
 
@@ -387,7 +387,7 @@
     "  x();\n"
     "}";
 
-  Isolate* isolate = Isolate::Current();
+  Isolate* isolate = thread->isolate();
   Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
   EXPECT_VALID(lib);
   Library& vmlib = Library::Handle();
@@ -411,7 +411,7 @@
   // Build a mock message handler and wrap it in a dart port.
   ServiceTestMessageHandler handler;
   Dart_Port port_id = PortMap::CreatePort(&handler);
-  Dart_Handle port = Api::NewHandle(isolate, SendPort::New(port_id));
+  Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
   EXPECT_VALID(port);
   EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
 
@@ -437,14 +437,14 @@
       "main() {\n"
       "}";
 
-  Isolate* isolate = Isolate::Current();
+  Isolate* isolate = thread->isolate();
   Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
   EXPECT_VALID(lib);
 
   // Build a mock message handler and wrap it in a dart port.
   ServiceTestMessageHandler handler;
   Dart_Port port_id = PortMap::CreatePort(&handler);
-  Dart_Handle port = Api::NewHandle(isolate, SendPort::New(port_id));
+  Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
   EXPECT_VALID(port);
   EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
 
@@ -518,7 +518,6 @@
   Dart_RegisterRootServiceRequestCallback("alpha", alpha_callback, NULL);
   Dart_RegisterRootServiceRequestCallback("beta", beta_callback, NULL);
 
-  Isolate* isolate = Isolate::Current();
   Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
   EXPECT_VALID(lib);
   Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
@@ -527,7 +526,7 @@
   // Build a mock message handler and wrap it in a dart port.
   ServiceTestMessageHandler handler;
   Dart_Port port_id = PortMap::CreatePort(&handler);
-  Dart_Handle port = Api::NewHandle(isolate, SendPort::New(port_id));
+  Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
   EXPECT_VALID(port);
   EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
 
@@ -559,7 +558,7 @@
   Dart_RegisterIsolateServiceRequestCallback("alpha", alpha_callback, NULL);
   Dart_RegisterIsolateServiceRequestCallback("beta", beta_callback, NULL);
 
-  Isolate* isolate = Isolate::Current();
+  Isolate* isolate = thread->isolate();
   Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
   EXPECT_VALID(lib);
   Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
@@ -568,7 +567,7 @@
   // Build a mock message handler and wrap it in a dart port.
   ServiceTestMessageHandler handler;
   Dart_Port port_id = PortMap::CreatePort(&handler);
-  Dart_Handle port = Api::NewHandle(isolate, SendPort::New(port_id));
+  Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
   EXPECT_VALID(port);
   EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
 
@@ -598,7 +597,7 @@
       "  x = x / 13;\n"
       "}";
 
-  Isolate* isolate = Isolate::Current();
+  Isolate* isolate = thread->isolate();
   Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
   EXPECT_VALID(lib);
   Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
@@ -607,7 +606,7 @@
   // Build a mock message handler and wrap it in a dart port.
   ServiceTestMessageHandler handler;
   Dart_Port port_id = PortMap::CreatePort(&handler);
-  Dart_Handle port = Api::NewHandle(isolate, SendPort::New(port_id));
+  Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
   EXPECT_VALID(port);
   EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
 
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 74464c8..f3e6514 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -700,8 +700,8 @@
   // the size specified by the user and the buffer space needed for
   // handling stack overflow exceptions. To be safe in potential
   // stack underflows we also add some underflow buffer space.
-  stack_ = new char[(Isolate::GetSpecifiedStackSize() +
-                     Isolate::kStackSizeBuffer +
+  stack_ = new char[(OSThread::GetSpecifiedStackSize() +
+                     OSThread::kStackSizeBuffer +
                      kSimulatorStackUnderflowSize)];
   pc_modified_ = false;
   icount_ = 0;
@@ -1177,7 +1177,7 @@
   // To be safe in potential stack underflows we leave some buffer above and
   // set the stack top.
   return StackBase() +
-      (Isolate::GetSpecifiedStackSize() + Isolate::kStackSizeBuffer);
+      (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer);
 }
 
 
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index cf25e24..0f1ed56 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -746,8 +746,8 @@
   // the size specified by the user and the buffer space needed for
   // handling stack overflow exceptions. To be safe in potential
   // stack underflows we also add some underflow buffer space.
-  stack_ = new char[(Isolate::GetSpecifiedStackSize() +
-                     Isolate::kStackSizeBuffer +
+  stack_ = new char[(OSThread::GetSpecifiedStackSize() +
+                     OSThread::kStackSizeBuffer +
                      kSimulatorStackUnderflowSize)];
   pc_modified_ = false;
   icount_ = 0;
@@ -1055,7 +1055,7 @@
   // To be safe in potential stack underflows we leave some buffer above and
   // set the stack top.
   return StackBase() +
-      (Isolate::GetSpecifiedStackSize() + Isolate::kStackSizeBuffer);
+      (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer);
 }
 
 
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index 04e0b7f..5fabae7 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -699,8 +699,8 @@
   // the size specified by the user and the buffer space needed for
   // handling stack overflow exceptions. To be safe in potential
   // stack underflows we also add some underflow buffer space.
-  stack_ = new char[(Isolate::GetSpecifiedStackSize() +
-                     Isolate::kStackSizeBuffer +
+  stack_ = new char[(OSThread::GetSpecifiedStackSize() +
+                     OSThread::kStackSizeBuffer +
                      kSimulatorStackUnderflowSize)];
   icount_ = 0;
   delay_slot_ = false;
@@ -997,7 +997,7 @@
   // To be safe in potential stack underflows we leave some buffer above and
   // set the stack top.
   return StackBase() +
-      (Isolate::GetSpecifiedStackSize() + Isolate::kStackSizeBuffer);
+      (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer);
 }
 
 
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 8e6c28e..a57296f 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -1622,6 +1622,7 @@
 
 #define VM_OBJECT_CLASS_LIST(V)                                                \
   V(OneByteString)                                                             \
+  V(TwoByteString)                                                             \
   V(Mint)                                                                      \
   V(Bigint)                                                                    \
   V(Double)                                                                    \
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 1b73e39..c67a8ce 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -1074,7 +1074,7 @@
     // Create a test library and Load up a test script in it.
     TestCase::LoadTestScript(kScriptChars, NULL);
 
-    EXPECT_VALID(Api::CheckAndFinalizePendingClasses(Isolate::Current()));
+    EXPECT_VALID(Api::CheckAndFinalizePendingClasses(Thread::Current()));
 
     // Write out the script snapshot.
     result = Dart_CreateScriptSnapshot(&buffer, &size);
@@ -1177,7 +1177,7 @@
 
     // Create a test library and Load up a test script in it.
     TestCase::LoadTestScript(kScriptChars, NULL);
-    EXPECT_VALID(Api::CheckAndFinalizePendingClasses(thread->isolate()));
+    EXPECT_VALID(Api::CheckAndFinalizePendingClasses(thread));
     timer1.Stop();
     OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
 
@@ -1238,7 +1238,7 @@
 
     // Create a test library and Load up a test script in it.
     Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
-    EXPECT_VALID(Api::CheckAndFinalizePendingClasses(thread->isolate()));
+    EXPECT_VALID(Api::CheckAndFinalizePendingClasses(thread));
     timer1.Stop();
     OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
 
@@ -1382,7 +1382,7 @@
     EXPECT_VALID(Dart_LibraryImportLibrary(TestCase::lib(),
                                            import_lib,
                                            Dart_Null()));
-    EXPECT_VALID(Api::CheckAndFinalizePendingClasses(Isolate::Current()));
+    EXPECT_VALID(Api::CheckAndFinalizePendingClasses(Thread::Current()));
 
     // Get list of library URLs loaded and save the count.
     Dart_Handle libs = Dart_GetLibraryIds();
@@ -1618,7 +1618,7 @@
     EXPECT_VALID(Dart_LibraryImportLibrary(TestCase::lib(),
                                            import_lib,
                                            Dart_Null()));
-    EXPECT_VALID(Api::CheckAndFinalizePendingClasses(Isolate::Current()));
+    EXPECT_VALID(Api::CheckAndFinalizePendingClasses(Thread::Current()));
 
     // Write out the script snapshot.
     result = Dart_CreateScriptSnapshot(&buffer, &size);
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index 3ec07cb..65f7c3b 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -283,12 +283,11 @@
 }
 
 
-// TODO(johnmccutchan): Remove |isolate| argument.
 // Tell MemorySanitizer that generated code initializes part of the stack.
 // TODO(koda): Limit to frames that are actually written by generated code.
-static void UnpoisonStack(Isolate* isolate, uword fp) {
+static void UnpoisonStack(uword fp) {
   ASSERT(fp != 0);
-  uword size = isolate->GetSpecifiedStackSize();
+  uword size = OSThread::GetSpecifiedStackSize();
   MSAN_UNPOISON(reinterpret_cast<void*>(fp - size), 2 * size);
 }
 
@@ -355,7 +354,7 @@
     if (!HasNextFrame()) {
       return NULL;
     }
-    UnpoisonStack(thread_->isolate(), frames_.fp_);
+    UnpoisonStack(frames_.fp_);
     if (frames_.pc_ == 0) {
       // Iteration starts from an exit frame given by its fp.
       current_frame_ = NextExitFrame();
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 8c197ae..7624fa2 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -786,7 +786,7 @@
 
   // Copy the C stack pointer (R31) into the stack pointer we'll actually use
   // to access the stack, and put the C stack pointer at the stack limit.
-  __ SetupDartSP(Isolate::GetSpecifiedStackSize());
+  __ SetupDartSP(OSThread::GetSpecifiedStackSize());
   __ EnterFrame(0);
 
   // Push code object to PC marker slot.
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 0d84937..db6f42e 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -4,6 +4,7 @@
 
 #include "vm/thread.h"
 
+#include "vm/dart_api_state.h"
 #include "vm/growable_array.h"
 #include "vm/isolate.h"
 #include "vm/lockers.h"
@@ -20,183 +21,9 @@
 
 namespace dart {
 
-// The single thread local key which stores all the thread local data
-// for a thread.
-ThreadLocalKey Thread::thread_key_ = OSThread::kUnsetThreadLocalKey;
-Thread* Thread::thread_list_head_ = NULL;
-Mutex* Thread::thread_list_lock_ = NULL;
-
-// Remove |thread| from each isolate's thread registry.
-class ThreadPruner : public IsolateVisitor {
- public:
-  explicit ThreadPruner(Thread* thread)
-      : thread_(thread) {
-    ASSERT(thread_ != NULL);
-  }
-
-  void VisitIsolate(Isolate* isolate) {
-    ThreadRegistry* registry = isolate->thread_registry();
-    ASSERT(registry != NULL);
-    registry->PruneThread(thread_);
-  }
- private:
-  Thread* thread_;
-};
-
-
-void Thread::AddThreadToList(Thread* thread) {
-  ASSERT(thread != NULL);
-  ASSERT(thread->isolate() == NULL);
-  ASSERT(thread_list_lock_ != NULL);
-  MutexLocker ml(thread_list_lock_);
-
-  ASSERT(thread->thread_list_next_ == NULL);
-
-#if defined(DEBUG)
-  {
-    // Ensure that we aren't already in the list.
-    Thread* current = thread_list_head_;
-    while (current != NULL) {
-      ASSERT(current != thread);
-      current = current->thread_list_next_;
-    }
-  }
-#endif
-
-  // Insert at head of list.
-  thread->thread_list_next_ = thread_list_head_;
-  thread_list_head_ = thread;
-}
-
-
-void Thread::RemoveThreadFromList(Thread* thread) {
-  ASSERT(thread != NULL);
-  ASSERT(thread->isolate() == NULL);
-  ASSERT(thread_list_lock_ != NULL);
-  MutexLocker ml(thread_list_lock_);
-
-  // Handle case where |thread| is head of list.
-  if (thread_list_head_ == thread) {
-    thread_list_head_ = thread->thread_list_next_;
-    thread->thread_list_next_ = NULL;
-    return;
-  }
-
-  Thread* current = thread_list_head_;
-  Thread* previous = NULL;
-
-  // Scan across list and remove |thread|.
-  while (current != NULL) {
-    previous = current;
-    current = current->thread_list_next_;
-    if (current == thread) {
-      // We found |thread|, remove from list.
-      previous->thread_list_next_ = current->thread_list_next_;
-      thread->thread_list_next_ = NULL;
-      return;
-    }
-  }
-
-  UNREACHABLE();
-}
-
-
-bool Thread::IsThreadInList(ThreadId join_id) {
-  if (join_id == OSThread::kInvalidThreadJoinId) {
-    return false;
-  }
-  ThreadIterator it;
-  while (it.HasNext()) {
-    Thread* 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) {
-      return true;
-    }
-  }
-  return false;
-}
-
-
-static void DeleteThread(void* thread) {
-  delete reinterpret_cast<Thread*>(thread);
-}
-
-
-void Thread::Shutdown() {
-  if (thread_list_lock_ != NULL) {
-    // Delete the current thread.
-    Thread* thread = Current();
-    ASSERT(thread != NULL);
-    delete thread;
-    thread = NULL;
-    SetCurrent(NULL);
-
-    // Check that there are no more threads, then delete the lock.
-    {
-      MutexLocker ml(thread_list_lock_);
-      ASSERT(thread_list_head_ == NULL);
-    }
-
-    // Clean up TLS.
-    OSThread::DeleteThreadLocal(thread_key_);
-    thread_key_ = OSThread::kUnsetThreadLocalKey;
-
-    // Delete the thread list lock.
-    delete thread_list_lock_;
-    thread_list_lock_ = NULL;
-  }
-}
-
-
 Thread::~Thread() {
   // We should cleanly exit any isolate before destruction.
   ASSERT(isolate_ == NULL);
-  // Clear |this| from all isolate's thread registry.
-  ThreadPruner pruner(this);
-  Isolate::VisitIsolates(&pruner);
-  delete log_;
-  log_ = NULL;
-  RemoveThreadFromList(this);
-}
-
-
-void Thread::InitOnceBeforeIsolate() {
-  ASSERT(thread_list_lock_ == NULL);
-  thread_list_lock_ = new Mutex();
-  ASSERT(thread_list_lock_ != NULL);
-  ASSERT(thread_key_ == OSThread::kUnsetThreadLocalKey);
-  thread_key_ = OSThread::CreateThreadLocal(DeleteThread);
-  ASSERT(thread_key_ != OSThread::kUnsetThreadLocalKey);
-  ASSERT(Thread::Current() == NULL);
-  // Allocate a new Thread and postpone initialization of VM constants for
-  // this first thread.
-  Thread* thread = new Thread(false);
-  // Verify that current thread was set.
-  ASSERT(Thread::Current() == thread);
-}
-
-
-void Thread::InitOnceAfterObjectAndStubCode() {
-  Thread* thread = Thread::Current();
-  ASSERT(thread != NULL);
-  ASSERT(thread->isolate() == Dart::vm_isolate());
-  thread->InitVMConstants();
-}
-
-
-void Thread::SetCurrent(Thread* current) {
-  OSThread::SetThreadLocal(thread_key_, reinterpret_cast<uword>(current));
-}
-
-
-void Thread::EnsureInit() {
-  if (Thread::Current() == NULL) {
-    // Allocate a new Thread.
-    Thread* thread = new Thread();
-    // Verify that current thread was set.
-    ASSERT(Thread::Current() == thread);
-  }
 }
 
 
@@ -211,28 +38,32 @@
   object##_handle_(NULL),
 
 
-Thread::Thread(bool init_vm_constants)
-    : id_(OSThread::GetCurrentThreadId()),
-      join_id_(OSThread::GetCurrentThreadJoinId()),
-      trace_id_(OSThread::GetCurrentThreadTraceId()),
-      thread_interrupt_disabled_(1),  // Thread interrupts disabled by default.
+Thread::Thread(Isolate* isolate)
+    : BaseThread(false),
+      os_thread_(NULL),
       isolate_(NULL),
       heap_(NULL),
-      timeline_block_(NULL),
+      zone_(NULL),
+      api_reusable_scope_(NULL),
+      api_top_scope_(NULL),
+      top_exit_frame_info_(0),
+      top_resource_(NULL),
+      long_jump_base_(NULL),
       store_buffer_block_(NULL),
-      log_(new class Log()),
-      REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS)
-      REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT)
+      no_callback_scope_depth_(0),
+#if defined(DEBUG)
+      top_handle_scope_(NULL),
+      no_handle_scope_depth_(0),
+      no_safepoint_scope_depth_(0),
+#endif
       reusable_handles_(),
       cha_(NULL),
       deopt_id_(0),
       vm_tag_(0),
       pending_functions_(GrowableObjectArray::null()),
-      no_callback_scope_depth_(0),
-      thread_list_next_(NULL),
-      name_(NULL) {
-  ClearState();
-
+      REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS)
+      REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT)
+      next_(NULL) {
 #define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value)    \
   member_name = default_init_value;
 CACHED_CONSTANTS_LIST(DEFAULT_INIT)
@@ -248,14 +79,59 @@
 LEAF_RUNTIME_ENTRY_LIST(DEFAULT_INIT)
 #undef DEFAULT_INIT
 
-  if (init_vm_constants) {
+  // We cannot initialize the VM constants here for the vm isolate thread
+  // due to boot strapping issues.
+  if ((Dart::vm_isolate() != NULL) && (isolate != Dart::vm_isolate())) {
     InitVMConstants();
   }
-  SetCurrent(this);
-  AddThreadToList(this);
 }
 
 
+static const struct ALIGN16 {
+  uint64_t a;
+  uint64_t b;
+} double_negate_constant =
+    {0x8000000000000000LL, 0x8000000000000000LL};
+
+static const struct ALIGN16 {
+  uint64_t a;
+  uint64_t b;
+} double_abs_constant =
+    {0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL};
+
+static const struct ALIGN16 {
+  uint32_t a;
+  uint32_t b;
+  uint32_t c;
+  uint32_t d;
+} float_not_constant =
+    { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+
+static const struct ALIGN16 {
+  uint32_t a;
+  uint32_t b;
+  uint32_t c;
+  uint32_t d;
+} float_negate_constant =
+    { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
+
+static const struct ALIGN16 {
+  uint32_t a;
+  uint32_t b;
+  uint32_t c;
+  uint32_t d;
+} float_absolute_constant =
+    { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
+
+static const struct ALIGN16 {
+  uint32_t a;
+  uint32_t b;
+  uint32_t c;
+  uint32_t d;
+} float_zerow_constant =
+    { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
+
+
 void Thread::InitVMConstants() {
 #define ASSERT_VM_HEAP(type_name, member_name, init_expr, default_init_value)  \
   ASSERT((init_expr)->IsOldObject());
@@ -288,12 +164,6 @@
 }
 
 
-void Thread::ClearState() {
-  memset(&state_, 0, sizeof(state_));
-  pending_functions_ = GrowableObjectArray::null();
-}
-
-
 RawGrowableObjectArray* Thread::pending_functions() {
   if (pending_functions_ == GrowableObjectArray::null()) {
     pending_functions_ = GrowableObjectArray::New(Heap::kOld);
@@ -302,96 +172,67 @@
 }
 
 
-void Thread::Schedule(Isolate* isolate, bool bypass_safepoint) {
-  State st;
-  if (isolate->thread_registry()->RestoreStateTo(this, &st, bypass_safepoint)) {
-    ASSERT(isolate->thread_registry()->Contains(this));
-    state_ = st;
-  }
-}
-
-
-void Thread::Unschedule(bool bypass_safepoint) {
-  ThreadRegistry* reg = isolate_->thread_registry();
-  ASSERT(reg->Contains(this));
-  reg->SaveStateFrom(this, state_, bypass_safepoint);
-  ClearState();
-}
-
-
 void Thread::EnterIsolate(Isolate* isolate) {
-  Thread* thread = Thread::Current();
-  ASSERT(thread != NULL);
-  ASSERT(thread->isolate() == NULL);
-  ASSERT(!isolate->HasMutatorThread());
-  thread->isolate_ = isolate;
+  const bool kIsMutatorThread = true;
+  const bool kDontBypassSafepoints = false;
+  ThreadRegistry* tr = isolate->thread_registry();
+  Thread* thread = tr->Schedule(
+      isolate, kIsMutatorThread, kDontBypassSafepoints);
   isolate->MakeCurrentThreadMutator(thread);
   thread->set_vm_tag(VMTag::kVMTagId);
   ASSERT(thread->store_buffer_block_ == NULL);
   thread->StoreBufferAcquire();
-  ASSERT(isolate->heap() != NULL);
-  thread->heap_ = isolate->heap();
-  thread->Schedule(isolate);
-  thread->EnableThreadInterrupts();
 }
 
 
 void Thread::ExitIsolate() {
   Thread* thread = Thread::Current();
-  // TODO(koda): Audit callers; they should know whether they're in an isolate.
-  if (thread == NULL || thread->isolate() == NULL) return;
+  ASSERT(thread != NULL);
+  ASSERT(thread->IsMutatorThread());
 #if defined(DEBUG)
   ASSERT(!thread->IsAnyReusableHandleScopeActive());
 #endif  // DEBUG
-  thread->DisableThreadInterrupts();
   // Clear since GC will not visit the thread once it is unscheduled.
   thread->ClearReusableHandles();
-  Isolate* isolate = thread->isolate();
-  thread->Unschedule();
-  // TODO(koda): Move store_buffer_block_ into State.
   thread->StoreBufferRelease();
+  Isolate* isolate = thread->isolate();
+  ASSERT(isolate != NULL);
   if (isolate->is_runnable()) {
     thread->set_vm_tag(VMTag::kIdleTagId);
   } else {
     thread->set_vm_tag(VMTag::kLoadWaitTagId);
   }
+  const bool kIsMutatorThread = true;
+  const bool kDontBypassSafepoints = false;
+  ThreadRegistry* tr = isolate->thread_registry();
+  tr->Unschedule(thread, kIsMutatorThread, kDontBypassSafepoints);
   isolate->ClearMutatorThread();
-  thread->isolate_ = NULL;
-  ASSERT(Isolate::Current() == NULL);
-  thread->heap_ = NULL;
 }
 
 
 void Thread::EnterIsolateAsHelper(Isolate* isolate, bool bypass_safepoint) {
-  Thread* thread = Thread::Current();
-  ASSERT(thread != NULL);
-  ASSERT(thread->isolate() == NULL);
-  thread->isolate_ = isolate;
+  const bool kIsNotMutatorThread = false;
+  ThreadRegistry* tr = isolate->thread_registry();
+  Thread* thread = tr->Schedule(isolate, kIsNotMutatorThread, bypass_safepoint);
   ASSERT(thread->store_buffer_block_ == NULL);
   // TODO(koda): Use StoreBufferAcquire once we properly flush before Scavenge.
   thread->store_buffer_block_ =
       thread->isolate()->store_buffer()->PopEmptyBlock();
-  ASSERT(isolate->heap() != NULL);
-  thread->heap_ = isolate->heap();
-  // Do not update isolate->mutator_thread, but perform sanity check:
-  // this thread should not be both the main mutator and helper.
+  // This thread should not be the main mutator.
   ASSERT(!thread->IsMutatorThread());
-  thread->Schedule(isolate, bypass_safepoint);
-  thread->EnableThreadInterrupts();
 }
 
 
 void Thread::ExitIsolateAsHelper(bool bypass_safepoint) {
   Thread* thread = Thread::Current();
-  thread->DisableThreadInterrupts();
+  ASSERT(thread != NULL);
+  ASSERT(!thread->IsMutatorThread());
+  thread->StoreBufferRelease();
   Isolate* isolate = thread->isolate();
   ASSERT(isolate != NULL);
-  thread->Unschedule(bypass_safepoint);
-  // TODO(koda): Move store_buffer_block_ into State.
-  thread->StoreBufferRelease();
-  thread->isolate_ = NULL;
-  thread->heap_ = NULL;
-  ASSERT(!thread->IsMutatorThread());
+  const bool kIsNotMutatorThread = false;
+  ThreadRegistry* tr = isolate->thread_registry();
+  tr->Unschedule(thread, kIsNotMutatorThread, bypass_safepoint);
 }
 
 
@@ -459,23 +300,6 @@
 }
 
 
-CHA* Thread::cha() const {
-  ASSERT(isolate_ != NULL);
-  return cha_;
-}
-
-
-void Thread::set_cha(CHA* value) {
-  ASSERT(isolate_ != NULL);
-  cha_ = value;
-}
-
-
-Log* Thread::log() const {
-  return log_;
-}
-
-
 template<class C>
 C* Thread::AllocateReusableHandle() {
   C* handle = reinterpret_cast<C*>(reusable_handles_.AllocateScopedHandle());
@@ -498,38 +322,18 @@
   // Visit objects in thread specific handles area.
   reusable_handles_.VisitObjectPointers(visitor);
 
+  // Visit the pending functions.
   if (pending_functions_ != GrowableObjectArray::null()) {
     visitor->VisitPointer(
         reinterpret_cast<RawObject**>(&pending_functions_));
   }
-}
 
-
-void Thread::DisableThreadInterrupts() {
-  ASSERT(Thread::Current() == this);
-  AtomicOperations::FetchAndIncrement(&thread_interrupt_disabled_);
-}
-
-
-void Thread::EnableThreadInterrupts() {
-  ASSERT(Thread::Current() == this);
-  uintptr_t old =
-      AtomicOperations::FetchAndDecrement(&thread_interrupt_disabled_);
-  if (old == 1) {
-    // We just decremented from 1 to 0.
-    // Make sure the thread interrupter is awake.
-    ThreadInterrupter::WakeUp();
+  // Visit the api local scope as it has all the api local handles.
+  ApiLocalScope* scope = api_top_scope_;
+  while (scope != NULL) {
+    scope->local_handles()->VisitObjectPointers(visitor);
+    scope = scope->previous();
   }
-  if (old == 0) {
-    // We just decremented from 0, this means we've got a mismatched pair
-    // of calls to EnableThreadInterrupts and DisableThreadInterrupts.
-    FATAL("Invalid call to Thread::EnableThreadInterrupts()");
-  }
-}
-
-
-bool Thread::ThreadInterruptsEnabled() {
-  return AtomicOperations::LoadRelaxed(&thread_interrupt_disabled_) == 0;
 }
 
 
@@ -585,48 +389,69 @@
 }
 
 
-ThreadIterator::ThreadIterator() {
-  ASSERT(Thread::thread_list_lock_ != NULL);
-  // Lock the thread list while iterating.
-  Thread::thread_list_lock_->Lock();
-  next_ = Thread::thread_list_head_;
+bool Thread::IsValidLocalHandle(Dart_Handle object) const {
+  ApiLocalScope* scope = api_top_scope_;
+  while (scope != NULL) {
+    if (scope->local_handles()->IsValidHandle(object)) {
+      return true;
+    }
+    scope = scope->previous();
+  }
+  return false;
 }
 
 
-ThreadIterator::~ThreadIterator() {
-  ASSERT(Thread::thread_list_lock_ != NULL);
-  // Unlock the thread list when done.
-  Thread::thread_list_lock_->Unlock();
+int Thread::CountLocalHandles() const {
+  int total = 0;
+  ApiLocalScope* scope = api_top_scope_;
+  while (scope != NULL) {
+    total += scope->local_handles()->CountHandles();
+    scope = scope->previous();
+  }
+  return total;
 }
 
 
-bool ThreadIterator::HasNext() const {
-  ASSERT(Thread::thread_list_lock_ != NULL);
-  ASSERT(Thread::thread_list_lock_->IsOwnedByCurrentThread());
-  return next_ != NULL;
+int Thread::ZoneSizeInBytes() const {
+  int total = 0;
+  ApiLocalScope* scope = api_top_scope_;
+  while (scope != NULL) {
+    total += scope->zone()->SizeInBytes();
+    scope = scope->previous();
+  }
+  return total;
 }
 
 
-Thread* ThreadIterator::Next() {
-  ASSERT(Thread::thread_list_lock_ != NULL);
-  ASSERT(Thread::thread_list_lock_->IsOwnedByCurrentThread());
-  Thread* current = next_;
-  next_ = next_->thread_list_next_;
-  return current;
+void Thread::UnwindScopes(uword stack_marker) {
+  // Unwind all scopes using the same stack_marker, i.e. all scopes allocated
+  // under the same top_exit_frame_info.
+  ApiLocalScope* scope = api_top_scope_;
+  while (scope != NULL &&
+         scope->stack_marker() != 0 &&
+         scope->stack_marker() == stack_marker) {
+    api_top_scope_ = scope->previous();
+    delete scope;
+    scope = api_top_scope_;
+  }
 }
 
 
 DisableThreadInterruptsScope::DisableThreadInterruptsScope(Thread* thread)
     : StackResource(thread) {
   if (thread != NULL) {
-    thread->DisableThreadInterrupts();
+    OSThread* os_thread = thread->os_thread();
+    ASSERT(os_thread != NULL);
+    os_thread->DisableThreadInterrupts();
   }
 }
 
 
 DisableThreadInterruptsScope::~DisableThreadInterruptsScope() {
   if (thread() != NULL) {
-    thread()->EnableThreadInterrupts();
+    OSThread* os_thread = thread()->os_thread();
+    ASSERT(os_thread != NULL);
+    os_thread->EnableThreadInterrupts();
   }
 }
 
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index d4a3ea1..15483cb 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -5,6 +5,7 @@
 #ifndef VM_THREAD_H_
 #define VM_THREAD_H_
 
+#include "include/dart_api.h"
 #include "vm/globals.h"
 #include "vm/handles.h"
 #include "vm/os_thread.h"
@@ -14,6 +15,7 @@
 namespace dart {
 
 class AbstractType;
+class ApiLocalScope;
 class Array;
 class CHA;
 class Class;
@@ -28,9 +30,9 @@
 class Instance;
 class Isolate;
 class Library;
-class Log;
 class LongJumpScope;
 class Object;
+class OSThread;
 class PcDescriptors;
 class RawBool;
 class RawObject;
@@ -40,7 +42,6 @@
 class RuntimeEntry;
 class StackResource;
 class String;
-class TimelineEventBlock;
 class TypeArguments;
 class TypeParameter;
 class Zone;
@@ -78,7 +79,6 @@
   V(RawCode*, invoke_dart_code_stub_,                                          \
     StubCode::InvokeDartCode_entry()->code(), NULL)                            \
 
-
 #define CACHED_ADDRESSES_LIST(V)                                               \
   V(uword, update_store_buffer_entry_point_,                                   \
     StubCode::UpdateStoreBuffer_entry()->EntryPoint(), 0)                      \
@@ -86,27 +86,41 @@
     NativeEntry::NativeCallWrapperEntry(), 0)                                  \
   V(RawString**, predefined_symbols_address_,                                  \
     Symbols::PredefinedAddress(), NULL)                                        \
+  V(uword, double_negate_address_,                                             \
+    reinterpret_cast<uword>(&double_negate_constant), 0)                       \
+  V(uword, double_abs_address_,                                                \
+    reinterpret_cast<uword>(&double_abs_constant), 0)                          \
+  V(uword, float_not_address_,                                                 \
+    reinterpret_cast<uword>(&float_not_constant), 0)                           \
+  V(uword, float_negate_address_,                                              \
+    reinterpret_cast<uword>(&float_negate_constant), 0)                        \
+  V(uword, float_absolute_address_,                                            \
+    reinterpret_cast<uword>(&float_absolute_constant), 0)                      \
+  V(uword, float_zerow_address_,                                               \
+    reinterpret_cast<uword>(&float_zerow_constant), 0)                         \
 
 #define CACHED_CONSTANTS_LIST(V)                                               \
   CACHED_VM_OBJECTS_LIST(V)                                                    \
   CACHED_ADDRESSES_LIST(V)                                                     \
 
-
 // A VM thread; may be executing Dart code or performing helper tasks like
 // garbage collection or compilation. The Thread structure associated with
 // a thread is allocated by EnsureInit before entering an isolate, and destroyed
 // automatically when the underlying OS thread exits. NOTE: On Windows, CleanUp
 // must currently be called manually (issue 23474).
-class Thread {
+class Thread : public BaseThread {
  public:
+  ~Thread();
+
   // The currently executing thread, or NULL if not yet initialized.
   static Thread* Current() {
-    return reinterpret_cast<Thread*>(OSThread::GetThreadLocal(thread_key_));
+    BaseThread* thread = OSThread::GetCurrentTLS();
+    if (thread == NULL || thread->is_os_thread()) {
+      return NULL;
+    }
+    return reinterpret_cast<Thread*>(thread);
   }
 
-  // Initializes the current thread as a VM thread, if not already done.
-  static void EnsureInit();
-
   // Makes the current thread enter 'isolate'.
   static void EnterIsolate(Isolate* isolate);
   // Makes the current thread exit its isolate.
@@ -125,16 +139,26 @@
   // TODO(koda): Always run GC in separate thread.
   static void PrepareForGC();
 
-  // Called at VM startup.
-  static void InitOnceBeforeIsolate();
-  static void InitOnceAfterObjectAndStubCode();
-
-  // Called at VM shutdown
-  static void Shutdown();
-  ~Thread();
+  // OSThread corresponding to this thread.
+  OSThread* os_thread() const { return os_thread_; }
+  void set_os_thread(OSThread* os_thread) {
+    os_thread_ = os_thread;
+  }
 
   // The topmost zone used for allocation in this thread.
-  Zone* zone() const { return state_.zone; }
+  Zone* zone() const { return zone_; }
+
+  // The reusable api local scope for this thread.
+  ApiLocalScope* api_reusable_scope() const { return api_reusable_scope_; }
+  void set_api_reusable_scope(ApiLocalScope* value) {
+    ASSERT(value == NULL || api_reusable_scope_ == NULL);
+    api_reusable_scope_ = value;
+  }
+
+  // The api local scope for this thread, this where all local handles
+  // are allocated.
+  ApiLocalScope* api_top_scope() const { return api_top_scope_; }
+  void set_api_top_scope(ApiLocalScope* value) { api_top_scope_ = value; }
 
   // The isolate that this thread is operating on, or NULL if none.
   Isolate* isolate() const { return isolate_; }
@@ -150,8 +174,15 @@
   bool HasExitedDartCode() const;
 
   // The (topmost) CHA for the compilation in this thread.
-  CHA* cha() const;
-  void set_cha(CHA* value);
+  CHA* cha() const {
+    ASSERT(isolate_ != NULL);
+    return cha_;
+  }
+
+  void set_cha(CHA* value) {
+    ASSERT(isolate_ != NULL);
+    cha_ = value;
+  }
 
   int32_t no_callback_scope_depth() const {
     return no_callback_scope_depth_;
@@ -179,26 +210,28 @@
     return OFFSET_OF(Thread, store_buffer_block_);
   }
 
-  uword top_exit_frame_info() const { return state_.top_exit_frame_info; }
+  uword top_exit_frame_info() const { return top_exit_frame_info_; }
   static intptr_t top_exit_frame_info_offset() {
-    return OFFSET_OF(Thread, state_) + OFFSET_OF(State, top_exit_frame_info);
+    return OFFSET_OF(Thread, top_exit_frame_info_);
   }
 
-  StackResource* top_resource() const { return state_.top_resource; }
+  StackResource* top_resource() const { return top_resource_; }
   void set_top_resource(StackResource* value) {
-    state_.top_resource = value;
+    top_resource_ = value;
   }
   static intptr_t top_resource_offset() {
-    return OFFSET_OF(Thread, state_) + OFFSET_OF(State, top_resource);
+    return OFFSET_OF(Thread, top_resource_);
   }
 
+  // Heap of the isolate that this thread is operating on.
+  Heap* heap() const { return heap_; }
   static intptr_t heap_offset() {
     return OFFSET_OF(Thread, heap_);
   }
 
   int32_t no_handle_scope_depth() const {
 #if defined(DEBUG)
-    return state_.no_handle_scope_depth;
+    return no_handle_scope_depth_;
 #else
     return 0;
 #endif
@@ -206,21 +239,21 @@
 
   void IncrementNoHandleScopeDepth() {
 #if defined(DEBUG)
-    ASSERT(state_.no_handle_scope_depth < INT_MAX);
-    state_.no_handle_scope_depth += 1;
+    ASSERT(no_handle_scope_depth_ < INT_MAX);
+    no_handle_scope_depth_ += 1;
 #endif
   }
 
   void DecrementNoHandleScopeDepth() {
 #if defined(DEBUG)
-    ASSERT(state_.no_handle_scope_depth > 0);
-    state_.no_handle_scope_depth -= 1;
+    ASSERT(no_handle_scope_depth_ > 0);
+    no_handle_scope_depth_ -= 1;
 #endif
   }
 
   HandleScope* top_handle_scope() const {
 #if defined(DEBUG)
-    return state_.top_handle_scope;
+    return top_handle_scope_;
 #else
     return 0;
 #endif
@@ -228,13 +261,13 @@
 
   void set_top_handle_scope(HandleScope* handle_scope) {
 #if defined(DEBUG)
-    state_.top_handle_scope = handle_scope;
+    top_handle_scope_ = handle_scope;
 #endif
   }
 
   int32_t no_safepoint_scope_depth() const {
 #if defined(DEBUG)
-    return state_.no_safepoint_scope_depth;
+    return no_safepoint_scope_depth_;
 #else
     return 0;
 #endif
@@ -242,32 +275,18 @@
 
   void IncrementNoSafepointScopeDepth() {
 #if defined(DEBUG)
-    ASSERT(state_.no_safepoint_scope_depth < INT_MAX);
-    state_.no_safepoint_scope_depth += 1;
+    ASSERT(no_safepoint_scope_depth_ < INT_MAX);
+    no_safepoint_scope_depth_ += 1;
 #endif
   }
 
   void DecrementNoSafepointScopeDepth() {
 #if defined(DEBUG)
-    ASSERT(state_.no_safepoint_scope_depth > 0);
-    state_.no_safepoint_scope_depth -= 1;
+    ASSERT(no_safepoint_scope_depth_ > 0);
+    no_safepoint_scope_depth_ -= 1;
 #endif
   }
 
-  // Collection of isolate-specific state of a thread that is saved/restored
-  // on isolate exit/re-entry.
-  struct State {
-    Zone* zone;
-    uword top_exit_frame_info;
-    StackResource* top_resource;
-    LongJumpScope* long_jump_base;
-#if defined(DEBUG)
-    HandleScope* top_handle_scope;
-    intptr_t no_handle_scope_depth;
-    int32_t no_safepoint_scope_depth;
-#endif
-  };
-
 #define DEFINE_OFFSET_METHOD(type_name, member_name, expr, default_init_value) \
   static intptr_t member_name##offset() {                                      \
     return OFFSET_OF(Thread, member_name);                                     \
@@ -294,22 +313,6 @@
   static bool ObjectAtOffset(intptr_t offset, Object* object);
   static intptr_t OffsetFromThread(const RuntimeEntry* runtime_entry);
 
-  Mutex* timeline_block_lock() {
-    return &timeline_block_lock_;
-  }
-
-  // Only safe to access when holding |timeline_block_lock_|.
-  TimelineEventBlock* timeline_block() const {
-    return timeline_block_;
-  }
-
-  // Only safe to access when holding |timeline_block_lock_|.
-  void set_timeline_block(TimelineEventBlock* block) {
-    timeline_block_ = block;
-  }
-
-  class Log* log() const;
-
   static const intptr_t kNoDeoptId = -1;
   static const intptr_t kDeoptIdStep = 2;
   static const intptr_t kDeoptIdBeforeOffset = 0;
@@ -339,9 +342,9 @@
     return (deopt_id % kDeoptIdStep) == kDeoptIdAfterOffset;
   }
 
-  LongJumpScope* long_jump_base() const { return state_.long_jump_base; }
+  LongJumpScope* long_jump_base() const { return long_jump_base_; }
   void set_long_jump_base(LongJumpScope* value) {
-    state_.long_jump_base = value;
+    long_jump_base_ = value;
   }
 
   uword vm_tag() const {
@@ -354,36 +357,6 @@
     return OFFSET_OF(Thread, vm_tag_);
   }
 
-  ThreadId id() const {
-    ASSERT(id_ != OSThread::kInvalidThreadId);
-    return id_;
-  }
-
-  ThreadId join_id() const {
-    ASSERT(join_id_ != OSThread::kInvalidThreadJoinId);
-    return join_id_;
-  }
-
-  ThreadId trace_id() const {
-    ASSERT(trace_id_ != OSThread::kInvalidThreadJoinId);
-    return trace_id_;
-  }
-
-  const char* name() const {
-    return name_;
-  }
-
-  void set_name(const char* name) {
-    ASSERT(Thread::Current() == this);
-    ASSERT(name_ == NULL);
-    name_ = name;
-  }
-
-  // Used to temporarily disable or enable thread interrupts.
-  void DisableThreadInterrupts();
-  void EnableThreadInterrupts();
-  bool ThreadInterruptsEnabled();
-
 #if defined(DEBUG)
 #define REUSABLE_HANDLE_SCOPE_ACCESSORS(object)                                \
   void set_reusable_##object##_handle_scope_active(bool value) {               \
@@ -415,26 +388,44 @@
 
   RawGrowableObjectArray* pending_functions();
 
+  // Visit all object pointers.
   void VisitObjectPointers(ObjectPointerVisitor* visitor);
 
-  static bool IsThreadInList(ThreadId join_id);
+  bool IsValidLocalHandle(Dart_Handle object) const;
+  int CountLocalHandles() const;
+  int ZoneSizeInBytes() const;
+  void UnwindScopes(uword stack_marker);
+
+  void InitVMConstants();
 
  private:
   template<class T> T* AllocateReusableHandle();
 
-  static ThreadLocalKey thread_key_;
-
-  const ThreadId id_;
-  const ThreadId join_id_;
-  const ThreadId trace_id_;
-  uintptr_t thread_interrupt_disabled_;
+  OSThread* os_thread_;
   Isolate* isolate_;
   Heap* heap_;
-  State state_;
-  Mutex timeline_block_lock_;
-  TimelineEventBlock* timeline_block_;
+  Zone* zone_;
+  ApiLocalScope* api_reusable_scope_;
+  ApiLocalScope* api_top_scope_;
+  uword top_exit_frame_info_;
+  StackResource* top_resource_;
+  LongJumpScope* long_jump_base_;
   StoreBufferBlock* store_buffer_block_;
-  class Log* log_;
+  int32_t no_callback_scope_depth_;
+#if defined(DEBUG)
+  HandleScope* top_handle_scope_;
+  intptr_t no_handle_scope_depth_;
+  int32_t no_safepoint_scope_depth_;
+#endif
+  VMHandles reusable_handles_;
+
+  // Compiler state:
+  CHA* cha_;
+  intptr_t deopt_id_;  // Compilation specific counter.
+  uword vm_tag_;
+  RawGrowableObjectArray* pending_functions_;
+
+  // State that is cached in the TLS for fast access in generated code.
 #define DECLARE_MEMBERS(type_name, member_name, expr, default_init_value)      \
   type_name member_name;
 CACHED_CONSTANTS_LIST(DECLARE_MEMBERS)
@@ -463,50 +454,25 @@
 #undef REUSABLE_HANDLE_SCOPE_VARIABLE
 #endif  // defined(DEBUG)
 
-  VMHandles reusable_handles_;
+  Thread* next_;  // Used to chain the thread structures in an isolate.
 
-  // Compiler state:
-  CHA* cha_;
-  intptr_t deopt_id_;  // Compilation specific counter.
-  uword vm_tag_;
-  RawGrowableObjectArray* pending_functions_;
-
-  int32_t no_callback_scope_depth_;
-
-  // All |Thread|s are registered in the thread list.
-  Thread* thread_list_next_;
-
-  // A name for this thread.
-  const char* name_;
-
-  static Thread* thread_list_head_;
-  static Mutex* thread_list_lock_;
-
-  static void AddThreadToList(Thread* thread);
-  static void RemoveThreadFromList(Thread* thread);
-
-  explicit Thread(bool init_vm_constants = true);
-
-  void InitVMConstants();
-
-  void ClearState();
+  explicit Thread(Isolate* isolate);
 
   void StoreBufferRelease(
       StoreBuffer::ThresholdPolicy policy = StoreBuffer::kCheckThreshold);
   void StoreBufferAcquire();
 
   void set_zone(Zone* zone) {
-    state_.zone = zone;
+    zone_ = zone;
   }
 
   void set_top_exit_frame_info(uword top_exit_frame_info) {
-    state_.top_exit_frame_info = top_exit_frame_info;
+    top_exit_frame_info_ = top_exit_frame_info;
   }
 
-  static void SetCurrent(Thread* current);
-
-  void Schedule(Isolate* isolate, bool bypass_safepoint = false);
-  void Unschedule(bool bypass_safepoint = false);
+  static void SetCurrent(Thread* current) {
+    OSThread::SetCurrentTLS(reinterpret_cast<uword>(current));
+  }
 
 #define REUSABLE_FRIEND_DECLARATION(name)                                      \
   friend class Reusable##name##HandleScope;
@@ -517,31 +483,12 @@
   friend class Isolate;
   friend class Simulator;
   friend class StackZone;
-  friend class ThreadIterator;
-  friend class ThreadIteratorTestHelper;
   friend class ThreadRegistry;
 
   DISALLOW_COPY_AND_ASSIGN(Thread);
 };
 
 
-// Note that this takes the thread list lock, prohibiting threads from coming
-// on- or off-line.
-class ThreadIterator : public ValueObject {
- public:
-  ThreadIterator();
-  ~ThreadIterator();
-
-  // Returns false when there are no more threads left.
-  bool HasNext() const;
-
-  // Returns the current thread and moves forward.
-  Thread* Next();
-
- private:
-  Thread* next_;
-};
-
 #if defined(TARGET_OS_WINDOWS)
 // Clears the state of the current thread and frees the allocation.
 void WindowsThreadCleanUp();
diff --git a/runtime/vm/thread_interrupter.cc b/runtime/vm/thread_interrupter.cc
index 8a8af04..920baf6 100644
--- a/runtime/vm/thread_interrupter.cc
+++ b/runtime/vm/thread_interrupter.cc
@@ -75,7 +75,7 @@
   ASSERT(interrupter_thread_id_ == OSThread::kInvalidThreadJoinId);
   {
     MonitorLocker startup_ml(monitor_);
-    OSThread::Start(ThreadMain, 0);
+    OSThread::Start("ThreadInterrupter", ThreadMain, 0);
     while (!thread_running_) {
       startup_ml.Wait();
     }
@@ -153,7 +153,9 @@
   {
     // Signal to main thread we are ready.
     MonitorLocker startup_ml(monitor_);
-    interrupter_thread_id_ = OSThread::GetCurrentThreadJoinId();
+    OSThread* os_thread = OSThread::Current();
+    ASSERT(os_thread != NULL);
+    interrupter_thread_id_ = os_thread->join_id();
     thread_running_ = true;
     startup_ml.Notify();
   }
@@ -182,9 +184,9 @@
       monitor_->Exit();
 
       {
-        ThreadIterator it;
+        OSThreadIterator it;
         while (it.HasNext()) {
-          Thread* thread = it.Next();
+          OSThread* thread = it.Next();
           if (thread->ThreadInterruptsEnabled()) {
             interrupted_thread_count++;
             InterruptThread(thread);
diff --git a/runtime/vm/thread_interrupter.h b/runtime/vm/thread_interrupter.h
index 5357615..82e0474 100644
--- a/runtime/vm/thread_interrupter.h
+++ b/runtime/vm/thread_interrupter.h
@@ -35,7 +35,7 @@
   static void WakeUp();
 
   // Interrupt a thread.
-  static void InterruptThread(Thread* thread);
+  static void InterruptThread(OSThread* thread);
 
  private:
   static const intptr_t kMaxThreads = 4096;
diff --git a/runtime/vm/thread_interrupter_android.cc b/runtime/vm/thread_interrupter_android.cc
index 1c780ba..6656775 100644
--- a/runtime/vm/thread_interrupter_android.cc
+++ b/runtime/vm/thread_interrupter_android.cc
@@ -44,7 +44,7 @@
 };
 
 
-void ThreadInterrupter::InterruptThread(Thread* thread) {
+void ThreadInterrupter::InterruptThread(OSThread* thread) {
   if (FLAG_trace_thread_interrupter) {
     OS::Print("ThreadInterrupter interrupting %p\n",
               reinterpret_cast<void*>(thread->id()));
diff --git a/runtime/vm/thread_interrupter_linux.cc b/runtime/vm/thread_interrupter_linux.cc
index 2cb0f55..28ec681 100644
--- a/runtime/vm/thread_interrupter_linux.cc
+++ b/runtime/vm/thread_interrupter_linux.cc
@@ -43,7 +43,7 @@
 };
 
 
-void ThreadInterrupter::InterruptThread(Thread* thread) {
+void ThreadInterrupter::InterruptThread(OSThread* thread) {
   if (FLAG_trace_thread_interrupter) {
     OS::Print("ThreadInterrupter interrupting %p\n",
               reinterpret_cast<void*>(thread->id()));
diff --git a/runtime/vm/thread_interrupter_macos.cc b/runtime/vm/thread_interrupter_macos.cc
index c53ae13..a25c3c2 100644
--- a/runtime/vm/thread_interrupter_macos.cc
+++ b/runtime/vm/thread_interrupter_macos.cc
@@ -43,7 +43,7 @@
 };
 
 
-void ThreadInterrupter::InterruptThread(Thread* thread) {
+void ThreadInterrupter::InterruptThread(OSThread* thread) {
   if (FLAG_trace_thread_interrupter) {
     OS::Print("ThreadInterrupter interrupting %p\n", thread->id());
   }
@@ -64,4 +64,3 @@
 }  // namespace dart
 
 #endif  // defined(TARGET_OS_MACOS)
-
diff --git a/runtime/vm/thread_interrupter_win.cc b/runtime/vm/thread_interrupter_win.cc
index 4231d1e..ac613c1 100644
--- a/runtime/vm/thread_interrupter_win.cc
+++ b/runtime/vm/thread_interrupter_win.cc
@@ -52,19 +52,19 @@
   }
 
 
-  static void Interrupt(Thread* thread) {
-    ASSERT(!OSThread::Compare(GetCurrentThreadId(), thread->id()));
+  static void Interrupt(OSThread* os_thread) {
+    ASSERT(!OSThread::Compare(GetCurrentThreadId(), os_thread->id()));
     HANDLE handle = OpenThread(THREAD_GET_CONTEXT |
                                THREAD_QUERY_INFORMATION |
                                THREAD_SUSPEND_RESUME,
                                false,
-                               thread->id());
+                               os_thread->id());
     ASSERT(handle != NULL);
     DWORD result = SuspendThread(handle);
     if (result == kThreadError) {
       if (FLAG_trace_thread_interrupter) {
         OS::Print("ThreadInterrupter failed to suspend thread %p\n",
-                  reinterpret_cast<void*>(thread->id()));
+                  reinterpret_cast<void*>(os_thread->id()));
       }
       CloseHandle(handle);
       return;
@@ -75,19 +75,25 @@
       ResumeThread(handle);
       if (FLAG_trace_thread_interrupter) {
         OS::Print("ThreadInterrupter failed to get registers for %p\n",
-                  reinterpret_cast<void*>(thread->id()));
+                  reinterpret_cast<void*>(os_thread->id()));
       }
       CloseHandle(handle);
       return;
     }
-    Profiler::SampleThread(thread, its);
+    // Currently we sample only threads that are associated
+    // with an isolate. It is safe to call 'os_thread->thread()'
+    // here as the thread which is being queried is suspended.
+    Thread* thread = os_thread->thread();
+    if (thread != NULL) {
+      Profiler::SampleThread(thread, its);
+    }
     ResumeThread(handle);
     CloseHandle(handle);
   }
 };
 
 
-void ThreadInterrupter::InterruptThread(Thread* thread) {
+void ThreadInterrupter::InterruptThread(OSThread* thread) {
   if (FLAG_trace_thread_interrupter) {
     OS::Print("ThreadInterrupter suspending %p\n",
               reinterpret_cast<void*>(thread->id()));
@@ -113,4 +119,3 @@
 }  // namespace dart
 
 #endif  // defined(TARGET_OS_WINDOWS)
-
diff --git a/runtime/vm/thread_pool.cc b/runtime/vm/thread_pool.cc
index d5472a6..86d2f60 100644
--- a/runtime/vm/thread_pool.cc
+++ b/runtime/vm/thread_pool.cc
@@ -101,7 +101,9 @@
 
     // First tell all the workers to shut down.
     Worker* current = saved;
-    ThreadId id = OSThread::GetCurrentThreadId();
+    OSThread* os_thread = OSThread::Current();
+    ASSERT(os_thread != NULL);
+    ThreadId id = os_thread->id();
     while (current != NULL) {
       Worker* next = current->all_next_;
       ThreadId currentId = current->id();
@@ -245,7 +247,9 @@
 
   // The thread for worker will exit. Add its ThreadId to the join_list_
   // so that we can join on it at the next opportunity.
-  JoinList::AddLocked(OSThread::GetCurrentThreadJoinId(), &join_list_);
+  OSThread* os_thread = OSThread::Current();
+  ASSERT(os_thread != NULL);
+  JoinList::AddLocked(os_thread->join_id(), &join_list_);
   count_stopped_++;
   count_idle_--;
   return true;
@@ -333,7 +337,9 @@
     ASSERT(task_ != NULL);
   }
 #endif
-  int result = OSThread::Start(&Worker::Main, reinterpret_cast<uword>(this));
+  int result = OSThread::Start("Dart ThreadPool Worker",
+                               &Worker::Main,
+                               reinterpret_cast<uword>(this));
   if (result != 0) {
     FATAL1("Could not start worker thread: result = %d.", result);
   }
@@ -417,12 +423,11 @@
 
 // static
 void ThreadPool::Worker::Main(uword args) {
-  Thread::EnsureInit();
-  Thread* thread = Thread::Current();
-  thread->set_name("Dart ThreadPool Worker");
   Worker* worker = reinterpret_cast<Worker*>(args);
-  ThreadId id = OSThread::GetCurrentThreadId();
-  ThreadJoinId join_id = OSThread::GetCurrentThreadJoinId();
+  OSThread* os_thread = OSThread::Current();
+  ASSERT(os_thread != NULL);
+  ThreadId id = os_thread->id();
+  ThreadJoinId join_id = os_thread->join_id();
   ThreadPool* pool;
 
   {
diff --git a/runtime/vm/thread_registry.cc b/runtime/vm/thread_registry.cc
index f0f80e3..0d36e0d 100644
--- a/runtime/vm/thread_registry.cc
+++ b/runtime/vm/thread_registry.cc
@@ -10,6 +10,24 @@
 namespace dart {
 
 ThreadRegistry::~ThreadRegistry() {
+  // Go over the free thread list and delete the thread objects.
+  {
+    MonitorLocker ml(monitor_);
+    // At this point the mutator thread should be the only thread
+    // in the active list, delete it.
+    ASSERT(active_list_->next_ == NULL);
+    ASSERT(active_list_ == mutator_thread_);
+    delete mutator_thread_;
+    active_list_ = NULL;
+    mutator_thread_ = NULL;
+    // Now delete all the threads in the free list.
+    while (free_list_ != NULL) {
+      Thread* thread = free_list_;
+      free_list_ = thread->next_;
+      delete thread;
+    }
+  }
+
   // Delete monitor.
   delete monitor_;
 }
@@ -50,67 +68,125 @@
 }
 
 
-void ThreadRegistry::PruneThread(Thread* thread) {
+Thread* ThreadRegistry::Schedule(Isolate* isolate,
+                                 bool is_mutator,
+                                 bool bypass_safepoint) {
   MonitorLocker ml(monitor_);
-  intptr_t length = entries_.length();
-  if (length == 0) {
-    return;
+  // Wait for any rendezvous in progress.
+  while (!bypass_safepoint && in_rendezvous_) {
+    ml.Wait(Monitor::kNoTimeout);
   }
-  intptr_t found_index = -1;
-  for (intptr_t index = 0; index < length; index++) {
-    if (entries_.At(index).thread == thread) {
-      found_index = index;
-      break;
+  Thread* thread = NULL;
+  OSThread* os_thread = OSThread::Current();
+  ASSERT(os_thread != NULL);
+  ASSERT(isolate->heap() != NULL);
+  if (is_mutator) {
+    if (mutator_thread_ == NULL) {
+      mutator_thread_ = GetThreadFromFreelist(isolate);
+    }
+    thread = mutator_thread_;
+  } else {
+    thread = GetThreadFromFreelist(isolate);
+    ASSERT(thread->api_top_scope() == NULL);
+  }
+  thread->isolate_ = isolate;
+  thread->heap_ = isolate->heap();
+  thread->set_os_thread(os_thread);
+  os_thread->set_thread(thread);
+  Thread::SetCurrent(thread);
+  os_thread->EnableThreadInterrupts();
+  return thread;
+}
+
+
+void ThreadRegistry::Unschedule(Thread* thread,
+                                bool is_mutator,
+                                bool bypass_safepoint) {
+  MonitorLocker ml(monitor_);
+  OSThread* os_thread = thread->os_thread();
+  ASSERT(os_thread != NULL);
+  os_thread->DisableThreadInterrupts();
+  os_thread->set_thread(NULL);
+  OSThread::SetCurrent(os_thread);
+  thread->isolate_ = NULL;
+  thread->heap_ = NULL;
+  thread->set_os_thread(NULL);
+  if (!is_mutator) {
+    ASSERT(thread->api_top_scope() == NULL);
+    ReturnThreadToFreelist(thread);
+  }
+  if (!bypass_safepoint && in_rendezvous_) {
+    // Don't wait for this thread.
+    ASSERT(remaining_ > 0);
+    if (--remaining_ == 0) {
+      ml.NotifyAll();
     }
   }
-  if (found_index < 0) {
-    return;
-  }
-  entries_.RemoveAt(found_index);
 }
 
 
-ThreadRegistry::EntryIterator::EntryIterator(ThreadRegistry* registry)
-    : index_(0),
-      registry_(NULL) {
-  Reset(registry);
-}
-
-
-ThreadRegistry::EntryIterator::~EntryIterator() {
-  Reset(NULL);
-}
-
-
-void ThreadRegistry::EntryIterator::Reset(ThreadRegistry* registry) {
-  // Reset index.
-  index_ = 0;
-
-  // Unlock old registry.
-  if (registry_ != NULL) {
-    registry_->monitor_->Exit();
-  }
-
-  registry_ = registry;
-
-  // Lock new registry.
-  if (registry_ != NULL) {
-    registry_->monitor_->Enter();
+void ThreadRegistry::VisitObjectPointers(ObjectPointerVisitor* visitor,
+                                         bool validate_frames) {
+  MonitorLocker ml(monitor_);
+  Thread* thread = active_list_;
+  while (thread != NULL) {
+    if (thread->zone() != NULL) {
+      thread->zone()->VisitObjectPointers(visitor);
+    }
+    thread->VisitObjectPointers(visitor);
+    // Iterate over all the stack frames and visit objects on the stack.
+    StackFrameIterator frames_iterator(thread->top_exit_frame_info(),
+                                       validate_frames);
+    StackFrame* frame = frames_iterator.NextFrame();
+    while (frame != NULL) {
+      frame->VisitObjectPointers(visitor);
+      frame = frames_iterator.NextFrame();
+    }
+    thread = thread->next_;
   }
 }
 
 
-bool ThreadRegistry::EntryIterator::HasNext() const {
-  if (registry_ == NULL) {
-    return false;
+Thread* ThreadRegistry::GetThreadFromFreelist(Isolate* isolate) {
+  ASSERT(monitor_->IsOwnedByCurrentThread());
+  Thread* thread = NULL;
+  // Get thread structure from free list or create a new one.
+  if (free_list_ == NULL) {
+    thread = new Thread(isolate);
+  } else {
+    thread = free_list_;
+    free_list_ = thread->next_;
   }
-  return index_ < registry_->entries_.length();
+  // Add thread to active list.
+  thread->next_ = active_list_;
+  active_list_ = thread;
+  return thread;
 }
 
-
-const ThreadRegistry::Entry& ThreadRegistry::EntryIterator::Next() {
-  ASSERT(HasNext());
-  return registry_->entries_.At(index_++);
+void ThreadRegistry::ReturnThreadToFreelist(Thread* thread) {
+  ASSERT(thread != NULL);
+  ASSERT(thread->os_thread_ == NULL);
+  ASSERT(thread->isolate_ == NULL);
+  ASSERT(thread->heap_ == NULL);
+  ASSERT(monitor_->IsOwnedByCurrentThread());
+  // First remove the thread from the active list.
+  Thread* prev = NULL;
+  Thread* current = active_list_;
+  while (current != NULL) {
+    if (current == thread) {
+      if (prev == NULL) {
+        active_list_ = current->next_;
+      } else {
+        prev->next_ = current->next_;
+      }
+      break;
+    }
+    prev = current;
+    current = current->next_;
+  }
+  // Now add thread to the free list.
+  thread->next_ = free_list_;
+  free_list_ = thread;
 }
 
 
@@ -142,11 +218,10 @@
 
 intptr_t ThreadRegistry::CountScheduledLocked() {
   intptr_t count = 0;
-  for (int i = 0; i < entries_.length(); ++i) {
-    const Entry& entry = entries_[i];
-    if (entry.scheduled) {
-      ++count;
-    }
+  Thread* current = active_list_;
+  while (current != NULL) {
+    ++count;
+    current = current->next_;
   }
   return count;
 }
diff --git a/runtime/vm/thread_registry.h b/runtime/vm/thread_registry.h
index b78a761..f077c51 100644
--- a/runtime/vm/thread_registry.h
+++ b/runtime/vm/thread_registry.h
@@ -19,13 +19,17 @@
  public:
   ThreadRegistry()
       : monitor_(new Monitor()),
-        entries_(),
+        active_list_(NULL),
+        free_list_(NULL),
+        mutator_thread_(NULL),
         in_rendezvous_(false),
         remaining_(0),
         round_(0) {}
 
   ~ThreadRegistry();
 
+  Thread* active_list() const { return active_list_; }
+
   // Bring all threads in this isolate to a safepoint. The caller is
   // expected to be implicitly at a safepoint. The threads will wait
   // until ResumeAllThreads is called. First participates in any
@@ -49,146 +53,13 @@
   }
 
   bool AtSafepoint() const { return in_rendezvous_; }
-
-  bool RestoreStateTo(Thread* thread, Thread::State* state,
-                      bool bypass_safepoint) {
-    MonitorLocker ml(monitor_);
-    // Wait for any rendezvous in progress.
-    while (!bypass_safepoint && in_rendezvous_) {
-      ml.Wait(Monitor::kNoTimeout);
-    }
-    Entry* entry = FindEntry(thread);
-    if (entry != NULL) {
-      Thread::State st = entry->state;
-      // TODO(koda): Support same thread re-entering same isolate with
-      // Dart frames in between. For now, just assert it doesn't happen.
-      if (st.top_exit_frame_info != thread->top_exit_frame_info()) {
-        ASSERT(thread->top_exit_frame_info() == 0 ||
-               thread->top_exit_frame_info() > st.top_exit_frame_info);
-      }
-      ASSERT(!entry->scheduled);
-      entry->scheduled = true;
-#if defined(DEBUG)
-      // State field is not in use, so zap it.
-      memset(&entry->state, 0xda, sizeof(entry->state));
-#endif
-      *state = st;
-      return true;
-    }
-    Entry new_entry;
-    new_entry.thread = thread;
-    new_entry.scheduled = true;
-#if defined(DEBUG)
-    // State field is not in use, so zap it.
-    memset(&new_entry.state, 0xda, sizeof(new_entry.state));
-#endif
-    entries_.Add(new_entry);
-    return false;
-  }
-
-  void SaveStateFrom(Thread* thread, const Thread::State& state,
-                     bool bypass_safepoint) {
-    MonitorLocker ml(monitor_);
-    Entry* entry = FindEntry(thread);
-    ASSERT(entry != NULL);
-    ASSERT(entry->scheduled);
-    entry->scheduled = false;
-    entry->state = state;
-    if (!bypass_safepoint && in_rendezvous_) {
-      // Don't wait for this thread.
-      ASSERT(remaining_ > 0);
-      if (--remaining_ == 0) {
-        ml.NotifyAll();
-      }
-    }
-  }
-
-  bool Contains(Thread* thread) {
-    MonitorLocker ml(monitor_);
-    return (FindEntry(thread) != NULL);
-  }
-
-  void CheckNotScheduled(Isolate* isolate) {
-    MonitorLocker ml(monitor_);
-    for (int i = 0; i < entries_.length(); ++i) {
-      const Entry& entry = entries_[i];
-      if (entry.scheduled) {
-        FATAL3("Isolate %p still scheduled on %p (whose isolate_ is %p)\n",
-               isolate,
-               entry.thread,
-               entry.thread->isolate());
-      }
-    }
-  }
-
-  void VisitObjectPointers(ObjectPointerVisitor* visitor,
-                           bool validate_frames) {
-    MonitorLocker ml(monitor_);
-    for (int i = 0; i < entries_.length(); ++i) {
-      const Entry& entry = entries_[i];
-      const Thread::State& state =
-          entry.scheduled ? entry.thread->state_ : entry.state;
-      if (state.zone != NULL) {
-        state.zone->VisitObjectPointers(visitor);
-      }
-      if (entry.scheduled) {
-        ASSERT(entry.thread != NULL);
-        entry.thread->VisitObjectPointers(visitor);
-      }
-      // Iterate over all the stack frames and visit objects on the stack.
-      StackFrameIterator frames_iterator(state.top_exit_frame_info,
-                                         validate_frames);
-      StackFrame* frame = frames_iterator.NextFrame();
-      while (frame != NULL) {
-        frame->VisitObjectPointers(visitor);
-        frame = frames_iterator.NextFrame();
-      }
-    }
-  }
-
-  void PruneThread(Thread* thread);
-
-  void ReclaimTimelineBlocks();
-
-  struct Entry {
-    // NOTE: |thread| is deleted automatically when the thread exits.
-    // In other words, it is not safe to dereference |thread| unless you are on
-    // the thread itself.
-    Thread* thread;
-    bool scheduled;
-    Thread::State state;
-  };
-
-  class EntryIterator {
-   public:
-    explicit EntryIterator(ThreadRegistry* registry);
-    ~EntryIterator();
-
-    // Returns false when there are no more entries.
-    bool HasNext() const;
-
-    // Returns the next entry and moves forward.
-    const Entry& Next();
-
-   private:
-    void Reset(ThreadRegistry* registry);
-
-    intptr_t index_;
-    ThreadRegistry* registry_;
-  };
+  Thread* Schedule(Isolate* isolate, bool is_mutator, bool bypass_safepoint);
+  void Unschedule(Thread* thread, bool is_mutator, bool bypass_safepoint);
+  void VisitObjectPointers(ObjectPointerVisitor* visitor, bool validate_frames);
 
  private:
-  // Returns Entry corresponding to thread in registry or NULL.
-  // Note: Lock should be taken before this function is called.
-  // TODO(koda): Add method Monitor::IsOwnedByCurrentThread.
-  Entry* FindEntry(Thread* thread) {
-    for (int i = 0; i < entries_.length(); ++i) {
-      if (entries_[i].thread == thread) {
-        return &entries_[i];
-      }
-    }
-    return NULL;
-  }
+  Thread* GetThreadFromFreelist(Isolate* isolate);
+  void ReturnThreadToFreelist(Thread* thread);
 
   // Note: Lock should be taken before this function is called.
   void CheckSafepointLocked();
@@ -198,7 +69,22 @@
   intptr_t CountScheduledLocked();
 
   Monitor* monitor_;  // All access is synchronized through this monitor.
-  MallocGrowableArray<Entry> entries_;
+  Thread* active_list_;  // List of active threads in the isolate.
+  Thread* free_list_;  // Free list of Thread objects that can be reused.
+  // TODO(asiva): Currently we treat a mutator thread as a special thread
+  // 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 :
+  // - Dart_RunLoop()
+  // - IsolateSaver in Dart_NewNativePort
+  // - Isolate spawn (function/uri) under FLAG_i_like_slow_isolate_spawn
+  // We probably need a mechanism to return to the specific thread only
+  // for these specific cases. We should also determine if the embedder
+  // should allow exiting an isolate with live state in zones/handles in
+  // which case a new API for returning to the specific thread needs to be
+  // added.
+  Thread* mutator_thread_;
 
   // Safepoint rendezvous state.
   bool in_rendezvous_;    // A safepoint rendezvous request is in progress.
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index 7eb5849..ec998f8 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -38,7 +38,7 @@
   // This unit test case needs a running isolate.
   Dart_CreateIsolate(
       NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
-  Thread* thread = Thread::Current();
+  OSThread* thread = OSThread::Current();
   // Thread interrupter interferes with this test, disable interrupts.
   thread->DisableThreadInterrupts();
   Monitor* monitor = new Monitor();
@@ -134,7 +134,6 @@
         // Ensure that our particular zone is visited.
         isolate_->IterateObjectPointers(
             &counter,
-            /* visit_prologue_weak_handles = */ true,
             StackFrameIterator::kValidateFrames);
         EXPECT_EQ(1, counter.count());
       }
@@ -152,7 +151,6 @@
         // Ensure that our particular zone is visited.
         isolate_->IterateObjectPointers(
             &str_counter,
-            /* visit_prologue_weak_handles = */ true,
             StackFrameIterator::kValidateFrames);
         // We should visit the string object exactly once.
         EXPECT_EQ(1, str_counter.count());
@@ -279,7 +277,6 @@
         ObjectCounter counter(isolate_, &smi);
         isolate_->IterateObjectPointers(
             &counter,
-            /* visit_prologue_weak_handles = */ true,
             StackFrameIterator::kValidateFrames);
         {
           MutexLocker ml(mutex_);
@@ -410,18 +407,18 @@
   intptr_t thread_count_1 = 0;
 
   {
-    ThreadIterator ti;
+    OSThreadIterator ti;
     while (ti.HasNext()) {
-      Thread* thread = ti.Next();
+      OSThread* thread = ti.Next();
       EXPECT(thread != NULL);
       thread_count_0++;
     }
   }
 
   {
-    ThreadIterator ti;
+    OSThreadIterator ti;
     while (ti.HasNext()) {
-      Thread* thread = ti.Next();
+      OSThread* thread = ti.Next();
       EXPECT(thread != NULL);
       thread_count_1++;
     }
@@ -434,8 +431,8 @@
 
 
 TEST_CASE(ThreadIterator_FindSelf) {
-  Thread* current = Thread::Current();
-  EXPECT(Thread::IsThreadInList(current->join_id()));
+  OSThread* current = OSThread::Current();
+  EXPECT(OSThread::IsThreadInList(current->join_id()));
 }
 
 
@@ -446,16 +443,15 @@
 
 
 void ThreadIteratorTestMain(uword parameter) {
-  Thread::EnsureInit();
   ThreadIteratorTestParams* params =
       reinterpret_cast<ThreadIteratorTestParams*>(parameter);
-  Thread* thread = Thread::Current();
+  OSThread* thread = OSThread::Current();
   EXPECT(thread != NULL);
 
   MonitorLocker ml(params->monitor);
   params->spawned_thread_join_id = thread->join_id();
   EXPECT(params->spawned_thread_join_id != OSThread::kInvalidThreadJoinId);
-  EXPECT(Thread::IsThreadInList(thread->join_id()));
+  EXPECT(OSThread::IsThreadInList(thread->join_id()));
   ml.Notify();
 }
 
@@ -471,7 +467,9 @@
     MonitorLocker ml(params.monitor);
     EXPECT(params.spawned_thread_join_id == OSThread::kInvalidThreadJoinId);
     // Spawn thread and wait to receive the thread join id.
-    OSThread::Start(ThreadIteratorTestMain, reinterpret_cast<uword>(&params));
+    OSThread::Start("ThreadIteratorTest",
+                    ThreadIteratorTestMain,
+                    reinterpret_cast<uword>(&params));
     while (params.spawned_thread_join_id == OSThread::kInvalidThreadJoinId) {
       ml.Wait();
     }
@@ -480,7 +478,7 @@
     OSThread::Join(params.spawned_thread_join_id);
   }
 
-  EXPECT(!Thread::IsThreadInList(params.spawned_thread_join_id))
+  EXPECT(!OSThread::IsThreadInList(params.spawned_thread_join_id))
 
   delete params.monitor;
 }
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index d840767..331fb52 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -126,9 +126,9 @@
   }
 
   // Iterate over threads.
-  ThreadIterator it;
+  OSThreadIterator it;
   while (it.HasNext()) {
-    Thread* thread = it.Next();
+    OSThread* thread = it.Next();
     MutexLocker ml(thread->timeline_block_lock());
     // Grab block and clear it.
     TimelineEventBlock* block = thread->timeline_block();
@@ -350,7 +350,9 @@
   set_event_type(event_type);
   timestamp0_ = 0;
   timestamp1_ = 0;
-  thread_ = OSThread::GetCurrentThreadTraceId();
+  OSThread* os_thread = OSThread::Current();
+  ASSERT(os_thread != NULL);
+  thread_ = os_thread->trace_id();
   Isolate* isolate = Isolate::Current();
   if (isolate != NULL) {
     isolate_id_ = isolate->main_port();
@@ -641,9 +643,9 @@
 
 
 void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const {
-  ThreadIterator it;
+  OSThreadIterator it;
   while (it.HasNext()) {
-    Thread* thread = it.Next();
+    OSThread* thread = it.Next();
     const char* thread_name = thread->name();
     if (thread_name == NULL) {
       // Only emit a thread name if one was set.
@@ -666,7 +668,7 @@
 
 TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() {
   // Grab the current thread.
-  Thread* thread = Thread::Current();
+  OSThread* thread = OSThread::Current();
   ASSERT(thread != NULL);
   Mutex* thread_block_lock = thread->timeline_block_lock();
   ASSERT(thread_block_lock != NULL);
@@ -707,7 +709,7 @@
     return;
   }
   // Grab the current thread.
-  Thread* thread = Thread::Current();
+  OSThread* thread = OSThread::Current();
   ASSERT(thread != NULL);
   // Unlock the thread's block lock.
   Mutex* thread_block_lock = thread->timeline_block_lock();
@@ -901,9 +903,6 @@
 
 
 TimelineEvent* TimelineEventRingRecorder::StartEvent() {
-  // Grab the current thread.
-  Thread* thread = Thread::Current();
-  ASSERT(thread != NULL);
   return ThreadBlockStartEvent();
 }
 
@@ -986,9 +985,6 @@
 
 
 TimelineEvent* TimelineEventEndlessRecorder::StartEvent() {
-  // Grab the current thread.
-  Thread* thread = Thread::Current();
-  ASSERT(thread != NULL);
   return ThreadBlockStartEvent();
 }
 
@@ -1045,7 +1041,7 @@
   }
   head_ = NULL;
   block_index_ = 0;
-  Thread* thread = Thread::Current();
+  OSThread* thread = OSThread::Current();
   thread->set_timeline_block(NULL);
 }
 
@@ -1067,8 +1063,10 @@
 TimelineEvent* TimelineEventBlock::StartEvent() {
   ASSERT(!IsFull());
   if (FLAG_trace_timeline) {
-    OS::Print("StartEvent in block %p for thread %" Px "\n",
-              this, OSThread::CurrentCurrentThreadIdAsIntPtr());
+    OSThread* os_thread = OSThread::Current();
+    ASSERT(os_thread != NULL);
+    intptr_t tid = OSThread::ThreadIdToIntPtr(os_thread->id());
+    OS::Print("StartEvent in block %p for thread %" Px "\n", this, tid);
   }
   return &events_[length_++];
 }
@@ -1119,7 +1117,9 @@
 
 
 void TimelineEventBlock::Open() {
-  thread_id_ = OSThread::GetCurrentThreadTraceId();
+  OSThread* os_thread = OSThread::Current();
+  ASSERT(os_thread != NULL);
+  thread_id_ = os_thread->trace_id();
   in_use_ = true;
 }
 
diff --git a/runtime/vm/timeline_test.cc b/runtime/vm/timeline_test.cc
index 00fc839..2d9bb57 100644
--- a/runtime/vm/timeline_test.cc
+++ b/runtime/vm/timeline_test.cc
@@ -478,7 +478,9 @@
   ASSERT(recorder != NULL);
   Zone* zone = thread->zone();
   Isolate* isolate = thread->isolate();
-  ThreadId tid = OSThread::GetCurrentThreadTraceId();
+  OSThread* os_thread = thread->os_thread();
+  ASSERT(os_thread != NULL);
+  ThreadId tid = os_thread->trace_id();
 
   // Test case.
   TimelineTestHelper::FakeDuration(recorder, "a", 0, 10);
@@ -648,7 +650,9 @@
   ASSERT(recorder != NULL);
   Zone* zone = thread->zone();
   Isolate* isolate = thread->isolate();
-  ThreadId tid = OSThread::GetCurrentThreadTraceId();
+  OSThread* os_thread = thread->os_thread();
+  ASSERT(os_thread != NULL);
+  ThreadId tid = os_thread->trace_id();
 
   // Test case.
   TimelineTestHelper::FakeBegin(recorder, "a", 0);
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index 6e1ca5c..a8b063a 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -360,36 +360,44 @@
 
   uword entry() const { return code_.EntryPoint(); }
 
-  // Invoke/InvokeWithCode is used to call assembler test functions using the
-  // ABI calling convention.
+  // Invoke/InvokeWithCodeAndThread is used to call assembler test functions
+  // using the ABI calling convention.
   // ResultType is the return type of the assembler test function.
   // ArgNType is the type of the Nth argument.
 #if defined(USING_SIMULATOR)
 
 #if defined(ARCH_IS_64_BIT)
-  // TODO(fschneider): Make InvokeWithCode<> more general and work on 32-bit.
+  // TODO(fschneider): Make InvokeWithCodeAndThread<> more general and work on
+  // 32-bit.
   // Since Simulator::Call always return a int64_t, bit_cast does not work
   // on 32-bit platforms when returning an int32_t. Since template functions
   // don't support partial specialization, we'd need to introduce a helper
   // class to support 32-bit return types.
-  template<typename ResultType> ResultType InvokeWithCode() {
+  template<typename ResultType> ResultType InvokeWithCodeAndThread() {
     const bool fp_return = is_double<ResultType>::value;
     const bool fp_args = false;
+    Thread* thread = Thread::Current();
+    ASSERT(thread != NULL);
     return bit_cast<ResultType, int64_t>(Simulator::Current()->Call(
         bit_cast<intptr_t, uword>(entry()),
-        reinterpret_cast<intptr_t>(&code_), 0, 0, 0, fp_return, fp_args));
+        reinterpret_cast<intptr_t>(&code_),
+        reinterpret_cast<intptr_t>(thread),
+        0, 0, fp_return, fp_args));
   }
   template<typename ResultType, typename Arg1Type>
-  ResultType InvokeWithCode(Arg1Type arg1) {
+  ResultType InvokeWithCodeAndThread(Arg1Type arg1) {
     const bool fp_return = is_double<ResultType>::value;
     const bool fp_args = is_double<Arg1Type>::value;
     // TODO(fschneider): Support double arguments for simulator calls.
     COMPILE_ASSERT(!fp_args);
+    Thread* thread = Thread::Current();
+    ASSERT(thread != NULL);
     return bit_cast<ResultType, int64_t>(Simulator::Current()->Call(
         bit_cast<intptr_t, uword>(entry()),
         reinterpret_cast<intptr_t>(&code_),
+        reinterpret_cast<intptr_t>(thread),
         reinterpret_cast<intptr_t>(arg1),
-        0, 0, fp_return, fp_args));
+        0, fp_return, fp_args));
   }
 #endif  // ARCH_IS_64_BIT
 
@@ -413,15 +421,19 @@
         0, fp_return, fp_args);
   }
 #else
-  template<typename ResultType> ResultType InvokeWithCode() {
-    typedef ResultType (*FunctionType) (const Code&);
-    return reinterpret_cast<FunctionType>(entry())(code_);
+  template<typename ResultType> ResultType InvokeWithCodeAndThread() {
+    Thread* thread = Thread::Current();
+    ASSERT(thread != NULL);
+    typedef ResultType (*FunctionType) (const Code&, Thread*);
+    return reinterpret_cast<FunctionType>(entry())(code_, thread);
   }
 
   template<typename ResultType, typename Arg1Type>
-  ResultType InvokeWithCode(Arg1Type arg1) {
-    typedef ResultType (*FunctionType) (const Code&, Arg1Type);
-    return reinterpret_cast<FunctionType>(entry())(code_, arg1);
+  ResultType InvokeWithCodeAndThread(Arg1Type arg1) {
+    Thread* thread = Thread::Current();
+    ASSERT(thread != NULL);
+    typedef ResultType (*FunctionType) (const Code&, Thread*, Arg1Type);
+    return reinterpret_cast<FunctionType>(entry())(code_, thread, arg1);
   }
 
   template<typename ResultType,
diff --git a/runtime/vm/verifier.cc b/runtime/vm/verifier.cc
index 556a738..18ad438 100644
--- a/runtime/vm/verifier.cc
+++ b/runtime/vm/verifier.cc
@@ -79,12 +79,10 @@
   VerifyPointersVisitor visitor(isolate, allocated_set);
   // Visit all strongly reachable objects.
   isolate->IterateObjectPointers(&visitor,
-                                 false,  // skip prologue weak handles
                                  StackFrameIterator::kValidateFrames);
   VerifyWeakPointersVisitor weak_visitor(&visitor);
   // Visit weak handles and prologue weak handles.
-  isolate->VisitWeakPersistentHandles(&weak_visitor,
-                                      true);  // visit prologue weak handles
+  isolate->VisitWeakPersistentHandles(&weak_visitor);
   delete allocated_set;
 }
 
diff --git a/runtime/vm/vm.gypi b/runtime/vm/vm.gypi
index 9771a91..b3df320 100644
--- a/runtime/vm/vm.gypi
+++ b/runtime/vm/vm.gypi
@@ -96,6 +96,69 @@
         }]],
     },
     {
+      'target_name': 'libdart_vm_precompiled',
+      'type': 'static_library',
+      'toolsets':['host', 'target'],
+      'includes': [
+        'vm_sources.gypi',
+        '../platform/platform_headers.gypi',
+        '../platform/platform_sources.gypi',
+      ],
+      'sources/': [
+        # Exclude all _test.[cc|h] files.
+        ['exclude', '_test\\.(cc|h)$'],
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'defines': [
+        'DART_PRECOMPILED',
+      ],
+      'conditions': [
+        ['OS=="linux"', {
+          'link_settings': {
+            'libraries': [
+              '-lpthread',
+              '-lrt',
+              '-ldl',
+            ],
+          },
+        }],
+        ['OS=="android" and _toolset=="host"', {
+          'link_settings': {
+            'libraries': [
+              '-lpthread',
+              '-lrt',
+              '-ldl',
+            ],
+          },
+        }],
+        ['OS=="win"', {
+          'sources/' : [
+            ['exclude', 'gdbjit.cc'],
+          ],
+       }],
+       ['dart_vtune_support==0', {
+          'sources/' : [
+            ['exclude', 'vtune\\.(cc|h)$'],
+          ],
+       }],
+       ['dart_vtune_support==1', {
+          'include_dirs': ['<(dart_vtune_root)/include'],
+          'defines': ['DART_VTUNE_SUPPORT'],
+          'link_settings': {
+            'conditions': [
+              ['OS=="linux"', {
+                 'libraries': ['-ljitprofiling'],
+              }],
+              ['OS=="win"', {
+                 'libraries': ['-ljitprofiling.lib'],
+              }],
+            ],
+          },
+        }]],
+    },
+    {
       'target_name': 'libdart_vm_nosnapshot',
       'type': 'static_library',
       'toolsets':['host', 'target'],
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index 228abcb..f2cf962 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -315,6 +315,7 @@
     'os_linux.cc',
     'os_macos.cc',
     'os_test.cc',
+    'os_thread.cc',
     'os_thread.h',
     'os_thread_android.cc',
     'os_thread_android.h',
diff --git a/sdk/bin/dart2js b/sdk/bin/dart2js
index f448ba8..485d619 100755
--- a/sdk/bin/dart2js
+++ b/sdk/bin/dart2js
@@ -54,7 +54,7 @@
 
 if [ -z "$DART_CONFIGURATION" ];
 then
-  DART_CONFIGURATION="ReleaseIA32"
+  DART_CONFIGURATION="ReleaseX64"
 fi
 
 if [[ `uname` == 'Darwin' ]]; then
diff --git a/sdk/bin/dartanalyzer b/sdk/bin/dartanalyzer
index 9b4a2ab..c793551 100755
--- a/sdk/bin/dartanalyzer
+++ b/sdk/bin/dartanalyzer
@@ -43,7 +43,7 @@
 
 DART_ROOT="$(cd "${SDK_DIR}/.." ; pwd -P)"
 
-ANALYZER="$DART_ROOT/third_party/pkg/analyzer_cli/bin/analyzer.dart"
+ANALYZER="$DART_ROOT/pkg/analyzer_cli/bin/analyzer.dart"
 
 if [[ `uname` == 'Darwin' ]];
 then
diff --git a/sdk/bin/dartanalyzer.bat b/sdk/bin/dartanalyzer.bat
index ef041b0..0e0cb10 100644
--- a/sdk/bin/dartanalyzer.bat
+++ b/sdk/bin/dartanalyzer.bat
@@ -38,7 +38,7 @@
 rem Remove trailing backslash if there is one
 if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
 
-set ANALYZER=%DART_ROOT%\third_party\pkg\analyzer_cli\bin\analyzer.dart
+set ANALYZER=%DART_ROOT%\pkg\analyzer_cli\bin\analyzer.dart
 
 rem DART_CONFIGURATION defaults to ReleaseIA32
 if "%DART_CONFIGURATION%"=="" set DART_CONFIGURATION=ReleaseIA32
diff --git a/sdk/lib/_internal/js_runtime/lib/core_patch.dart b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
index 301517e..9dd31a4 100644
--- a/sdk/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
@@ -5,21 +5,22 @@
 // Patch file for dart:core classes.
 import "dart:_internal" as _symbol_dev;
 import 'dart:_interceptors';
-import 'dart:_js_helper' show patch,
+import 'dart:_js_helper' show checkInt,
+                              Closure,
+                              ConstantMap,
+                              getRuntimeType,
+                              JsLinkedHashMap,
+                              jsonEncodeNative,
+                              JSSyntaxRegExp,
+                              NoInline,
+                              objectHashCode,
+                              patch,
                               patch_full,
                               patch_lazy,
                               patch_startup,
-                              checkInt,
-                              getRuntimeType,
-                              jsonEncodeNative,
-                              JSSyntaxRegExp,
                               Primitives,
-                              ConstantMap,
-                              stringJoinUnchecked,
-                              objectHashCode,
-                              Closure,
                               readHttp,
-                              JsLinkedHashMap;
+                              stringJoinUnchecked;
 
 import 'dart:_foreign_helper' show JS;
 
@@ -671,3 +672,24 @@
     });
   }
 }
+
+@patch
+class StackTrace {
+  @patch
+  @NoInline()
+  static StackTrace get current {
+    var error = JS('', 'new Error()');
+    var stack = JS('String|Null', '#.stack', error);
+    if (stack is String) return new StackTrace.fromString(stack);
+    if (JS('', 'Error.captureStackTrace') != null) {
+      JS('void', 'Error.captureStackTrace(#)', error);
+      var stack = JS('String|Null', '#.stack', error);
+      if (stack is String) return new StackTrace.fromString(stack);
+    }
+    try {
+      throw 0;
+    } catch (_, stackTrace) {
+      return stackTrace;
+    }
+  }
+}
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index 30016f7..bcc2019 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -254,9 +254,9 @@
    * The call to `cleanUp` should not throw. If it does, the error will be an
    * uncaught asynchronous error.
    */
-  static Future<List> wait(Iterable<Future> futures,
+  static Future<List/*<T>*/> wait/*<T>*/(Iterable<Future/*<T>*/> futures,
                            {bool eagerError: false,
-                            void cleanUp(successValue)}) {
+                            void cleanUp(/*=T*/ successValue)}) {
     final _Future<List> result = new _Future<List>();
     List values;  // Collects the values. Set to null on error.
     int remaining = 0;  // How many futures are we waiting for.
@@ -407,7 +407,7 @@
    * with a `test` parameter, instead of handling both value and error in a
    * single [then] call.
    */
-  Future then(onValue(T value), { Function onError });
+  Future/*<S>*/ then/*<S>*/(/*=S*/ onValue(T value), { Function onError });
 
   /**
    * Handles errors emitted by this [Future].
diff --git a/sdk/lib/async/schedule_microtask.dart b/sdk/lib/async/schedule_microtask.dart
index acc4036..fac3f7f 100644
--- a/sdk/lib/async/schedule_microtask.dart
+++ b/sdk/lib/async/schedule_microtask.dart
@@ -8,9 +8,8 @@
 
 class _AsyncCallbackEntry {
   final _AsyncCallback callback;
-  final Zone zone;
   _AsyncCallbackEntry next;
-  _AsyncCallbackEntry(this.callback, this.zone);
+  _AsyncCallbackEntry(this.callback);
 }
 
 /** Head of single linked list of pending callbacks. */
@@ -39,23 +38,21 @@
     _AsyncCallbackEntry entry = _nextCallback;
     _nextCallback = entry.next;
     if (_nextCallback == null) _lastCallback = null;
-    Zone._current = entry.zone;
-    entry.callback();
+    (entry.callback)();
   }
 }
 
-void _microtaskLoopEntry() {
+void _startMicrotaskLoop() {
   _isInCallbackLoop = true;
   try {
     // Moved to separate function because try-finally prevents
     // good optimization.
     _microtaskLoop();
   } finally {
-    Zone._current = _ROOT_ZONE;
     _lastPriorityCallback = null;
     _isInCallbackLoop = false;
     if (_nextCallback != null) {
-      _AsyncRun._scheduleImmediate(_microtaskLoopEntry);
+      _AsyncRun._scheduleImmediate(_startMicrotaskLoop);
     }
   }
 }
@@ -66,11 +63,12 @@
  * The microtask is called after all other currently scheduled
  * microtasks, but as part of the current system event.
  */
-void _scheduleAsyncCallback(_AsyncCallbackEntry newEntry) {
+void _scheduleAsyncCallback(_AsyncCallback callback) {
+  _AsyncCallbackEntry newEntry = new _AsyncCallbackEntry(callback);
   if (_nextCallback == null) {
     _nextCallback = _lastCallback = newEntry;
     if (!_isInCallbackLoop) {
-      _AsyncRun._scheduleImmediate(_microtaskLoopEntry);
+      _AsyncRun._scheduleImmediate(_startMicrotaskLoop);
     }
   } else {
     _lastCallback.next = newEntry;
@@ -87,12 +85,13 @@
  * Is always run in the root zone.
  */
 void _schedulePriorityAsyncCallback(callback) {
-  _AsyncCallbackEntry entry =
-      new _AsyncCallbackEntry(callback, _ROOT_ZONE);
   if (_nextCallback == null) {
-    _scheduleAsyncCallback(entry);
+    _scheduleAsyncCallback(callback);
     _lastPriorityCallback = _lastCallback;
-  } else if (_lastPriorityCallback == null) {
+    return;
+  }
+  _AsyncCallbackEntry entry = new _AsyncCallbackEntry(callback);
+  if (_lastPriorityCallback == null) {
     entry.next = _nextCallback;
     _nextCallback = _lastPriorityCallback = entry;
   } else {
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 7766c81a..ae003e3 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -317,8 +317,8 @@
    * If a broadcast stream is listened to more than once, each subscription
    * will individually execute `map` for each event.
    */
-  Stream map(convert(T event)) {
-    return new _MapStream<T, dynamic>(this, convert);
+  Stream/*<S>*/ map/*<S>*/(/*=S*/ convert(T event)) {
+    return new _MapStream<T, dynamic/*=S*/>(this, convert);
   }
 
   /**
@@ -479,8 +479,8 @@
    * If a broadcast stream is listened to more than once, each subscription
    * will individually call `convert` and expand the events.
    */
-  Stream expand(Iterable convert(T value)) {
-    return new _ExpandStream<T, dynamic>(this, convert);
+  Stream/*<S>*/ expand(Iterable/*<S>*/ convert(T value)) {
+    return new _ExpandStream<T, dynamic/*=S*/>(this, convert);
   }
 
   /**
@@ -554,7 +554,9 @@
   }
 
   /** Reduces a sequence of values by repeatedly applying [combine]. */
-  Future fold(var initialValue, combine(var previous, T element)) {
+  Future/*<S>*/ fold/*<S>*/(var/*=S*/ initialValue,
+      /*=S*/ combine(var/*=S*/ previous, T element)) {
+
     _Future result = new _Future();
     var value = initialValue;
     StreamSubscription subscription;
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart
index 2520f4d..d84f01b 100644
--- a/sdk/lib/async/zone.dart
+++ b/sdk/lib/async/zone.dart
@@ -958,7 +958,7 @@
     // Use root zone as event zone if the function is already bound.
     zone = _ROOT_ZONE;
   }
-  _scheduleAsyncCallback(new _AsyncCallbackEntry(f, zone));
+  _scheduleAsyncCallback(f);
 }
 
 Timer _rootCreateTimer(Zone self, ZoneDelegate parent, Zone zone,
diff --git a/sdk/lib/collection/iterable.dart b/sdk/lib/collection/iterable.dart
index e89acc6f..c0d2ee0 100644
--- a/sdk/lib/collection/iterable.dart
+++ b/sdk/lib/collection/iterable.dart
@@ -15,12 +15,13 @@
   // - SetMixin
   // If changing a method here, also change the other copies.
 
-  Iterable map(f(E element)) => new MappedIterable<E, dynamic>(this, f);
+  Iterable/*<T>*/ map/*<T>*/(/*=T*/ f(E element)) =>
+      new MappedIterable<E, dynamic/*=T*/>(this, f);
 
   Iterable<E> where(bool f(E element)) => new WhereIterable<E>(this, f);
 
-  Iterable expand(Iterable f(E element)) =>
-      new ExpandIterable<E, dynamic>(this, f);
+  Iterable/*<T>*/ expand/*<T>*/(Iterable/*<T>*/ f(E element)) =>
+      new ExpandIterable<E, dynamic/*=T*/>(this, f);
 
   bool contains(Object element) {
     for (E e in this) {
@@ -45,8 +46,8 @@
     return value;
   }
 
-  dynamic fold(var initialValue,
-               dynamic combine(var previousValue, E element)) {
+  dynamic/*=T*/ fold/*<T>*/(var/*=T*/ initialValue,
+               dynamic/*=T*/ combine(var/*=T*/ previousValue, E element)) {
     var value = initialValue;
     for (E element in this) value = combine(value, element);
     return value;
diff --git a/sdk/lib/core/errors.dart b/sdk/lib/core/errors.dart
index 0229732..a47838b 100644
--- a/sdk/lib/core/errors.dart
+++ b/sdk/lib/core/errors.dart
@@ -165,12 +165,11 @@
 
   /**
    * Create an argument error for a `null` argument that must not be `null`.
-   *
-   * Shorthand for calling [ArgumentError.value] with a `null` value and a
-   * message of `"Must not be null"`.
    */
-  ArgumentError.notNull([String name])
-      : this.value(null, name, "Must not be null");
+  ArgumentError.notNull([this.name])
+      : _hasValue = false,
+        message = "Must not be null",
+        invalidValue = null;
 
   // Helper functions for toString overridden in subclasses.
   String get _errorName => "Invalid argument${!_hasValue ? "(s)" : ""}";
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index a327b6d..dd19502 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.dart
@@ -156,7 +156,8 @@
    * on any element where the result isn't needed.
    * For example, [elementAt] may call `f` only once.
    */
-  Iterable map(f(E element)) => new MappedIterable<E, dynamic>(this, f);
+  Iterable/*<T>*/ map/*<T>*/(/*=T*/ f(E e)) =>
+      new MappedIterable<E, dynamic/*=T*/>(this, f);
 
   /**
    * Returns a new lazy [Iterable] with all elements that satisfy the
@@ -182,8 +183,8 @@
    * The returned [Iterable] is lazy, and calls [f] for each element
    * of this every time it's iterated.
    */
-  Iterable expand(Iterable f(E element)) =>
-      new ExpandIterable<E, dynamic>(this, f);
+  Iterable/*<T>*/ expand/*<T>*/(Iterable/*<T>*/ f(E element)) =>
+      new ExpandIterable<E, dynamic/*=T*/>(this, f);
 
   /**
    * Returns true if the collection contains an element equal to [element].
@@ -270,8 +271,8 @@
    *     iterable.fold(0, (prev, element) => prev + element);
    *
    */
-  dynamic fold(var initialValue,
-               dynamic combine(var previousValue, E element)) {
+  dynamic/*=T*/ fold/*<T>*/(var/*=T*/ initialValue,
+               dynamic/*=T*/ combine(var/*=T*/ previousValue, E element)) {
     var value = initialValue;
     for (E element in this) value = combine(value, element);
     return value;
diff --git a/sdk/lib/core/pattern.dart b/sdk/lib/core/pattern.dart
index f47ba15..7f32c72 100644
--- a/sdk/lib/core/pattern.dart
+++ b/sdk/lib/core/pattern.dart
@@ -42,3 +42,90 @@
    */
   Match matchAsPrefix(String string, [int start = 0]);
 }
+
+/**
+ * A result from searching within a string.
+ *
+ * A Match or an [Iterable] of Match objects is returned from [Pattern]
+ * matching methods.
+ *
+ * The following example finds all matches of a [RegExp] in a [String]
+ * and iterates through the returned iterable of Match objects.
+ *
+ *     RegExp exp = new RegExp(r"(\w+)");
+ *     String str = "Parse my string";
+ *     Iterable<Match> matches = exp.allMatches(str);
+ *     for (Match m in matches) {
+ *       String match = m.group(0);
+ *       print(match);
+ *     }
+ *
+ * The output of the example is:
+ *
+ *     Parse
+ *     my
+ *     string
+ *
+ * Some patterns, regular expressions in particular, may record subtrings
+ * that were part of the matching. These are called _groups_ in the Match
+ * object. Some patterns may never have any groups, and their matches always
+ * have zero [groupCount].
+ */
+abstract class Match {
+  /**
+   * Returns the index in the string where the match starts.
+   */
+  int get start;
+
+  /**
+   * Returns the index in the string after the last character of the
+   * match.
+   */
+  int get end;
+
+  /**
+   * Returns the string matched by the given [group].
+   *
+   * If [group] is 0, returns the match of the pattern.
+   *
+   * The result may be `null` if the pattern didn't assign a value to it
+   * as part of this match.
+   */
+  String group(int group);
+
+  /**
+   * Returns the string matched by the given [group].
+   *
+   * If [group] is 0, returns the match of the pattern.
+   *
+   * Short alias for [Match.group].
+   */
+  String operator [](int group);
+
+  /**
+   * Returns a list of the groups with the given indices.
+   *
+   * The list contains the strings returned by [group] for each index in
+   * [groupIndices].
+   */
+  List<String> groups(List<int> groupIndices);
+
+  /**
+   * Returns the number of captured groups in the match.
+   *
+   * Some patterns may capture parts of the input that was used to
+   * compute the full match. This is the number of captured groups,
+   * which is also the maximal allowed argument to the [group] method.
+   */
+  int get groupCount;
+
+  /**
+   * The string on which this match was computed.
+   */
+  String get input;
+
+  /**
+   * The pattern used to search in [input].
+   */
+  Pattern get pattern;
+}
\ No newline at end of file
diff --git a/sdk/lib/core/regexp.dart b/sdk/lib/core/regexp.dart
index 049ff97..0d92345 100644
--- a/sdk/lib/core/regexp.dart
+++ b/sdk/lib/core/regexp.dart
@@ -5,94 +5,6 @@
 part of dart.core;
 
 /**
- * A result from searching within a string.
- *
- * A Match or an [Iterable] of Match objects is returned from [Pattern]
- * matching methods.
- *
- * The following example finds all matches of a [RegExp] in a [String]
- * and iterates through the returned iterable of Match objects.
- *
- *     RegExp exp = new RegExp(r"(\w+)");
- *     String str = "Parse my string";
- *     Iterable<Match> matches = exp.allMatches(str);
- *     for (Match m in matches) {
- *       String match = m.group(0);
- *       print(match);
- *     }
- *
- * The output of the example is:
- *
- *     Parse
- *     my
- *     string
- *
- * Some patterns, regular expressions in particular, may record subtrings
- * that were part of the matching. These are called _groups_ in the Match
- * object. Some patterns may never have any groups, and their matches always
- * have zero [groupCount].
- */
-abstract class Match {
-  /**
-   * Returns the index in the string where the match starts.
-   */
-  int get start;
-
-  /**
-   * Returns the index in the string after the last character of the
-   * match.
-   */
-  int get end;
-
-  /**
-   * Returns the string matched by the given [group].
-   *
-   * If [group] is 0, returns the match of the pattern.
-   *
-   * The result may be `null` if the pattern didn't assign a value to it
-   * as part of this match.
-   */
-  String group(int group);
-
-  /**
-   * Returns the string matched by the given [group].
-   *
-   * If [group] is 0, returns the match of the pattern.
-   *
-   * Short alias for [Match.group].
-   */
-  String operator [](int group);
-
-  /**
-   * Returns a list of the groups with the given indices.
-   *
-   * The list contains the strings returned by [group] for each index in
-   * [groupIndices].
-   */
-  List<String> groups(List<int> groupIndices);
-
-  /**
-   * Returns the number of captured groups in the match.
-   *
-   * Some patterns may capture parts of the input that was used to
-   * compute the full match. This is the number of captured groups,
-   * which is also the maximal allowed argument to the [group] method.
-   */
-  int get groupCount;
-
-  /**
-   * The string on which this match was computed.
-   */
-  String get input;
-
-  /**
-   * The pattern used to search in [input].
-   */
-  Pattern get pattern;
-}
-
-
-/**
  * A regular expression pattern.
  *
  * Regular expressions are [Pattern]s, and can as such be used to match strings
diff --git a/sdk/lib/core/stacktrace.dart b/sdk/lib/core/stacktrace.dart
index c8540dc..17abd38 100644
--- a/sdk/lib/core/stacktrace.dart
+++ b/sdk/lib/core/stacktrace.dart
@@ -31,6 +31,18 @@
   factory StackTrace.fromString(String stackTraceString) = _StringStackTrace;
 
   /**
+   * Returns a representation of the current stack trace.
+   *
+   * This is similar to what can be achieved by doing:
+   *
+   *     try { throw 0; } catch (_, stack) { return stack; }
+   *
+   * The getter achieves this without throwing, except on platforms that
+   * have no other way to get a stack trace.
+   */
+  external static StackTrace get current;
+
+  /**
    * Returns a [String] representation of the stack trace.
    *
    * The string represents the full stack trace starting from
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index d3b2073..8acae64 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -8464,7 +8464,26 @@
   @DomName('DedicatedWorkerGlobalScope.postMessage')
   @DocsEditable()
   @Experimental() // untriaged
-  void postMessage(Object message, [List<MessagePort> transfer]) native;
+  void postMessage(/*any*/ message, [List<MessagePort> transfer]) {
+    if (transfer != null) {
+      var message_1 = convertDartToNative_SerializedScriptValue(message);
+      _postMessage_1(message_1, transfer);
+      return;
+    }
+    var message_1 = convertDartToNative_SerializedScriptValue(message);
+    _postMessage_2(message_1);
+    return;
+  }
+  @JSName('postMessage')
+  @DomName('DedicatedWorkerGlobalScope.postMessage')
+  @DocsEditable()
+  @Experimental() // untriaged
+  void _postMessage_1(message, List<MessagePort> transfer) native;
+  @JSName('postMessage')
+  @DomName('DedicatedWorkerGlobalScope.postMessage')
+  @DocsEditable()
+  @Experimental() // untriaged
+  void _postMessage_2(message) native;
 
   /// Stream of `message` events handled by this [DedicatedWorkerGlobalScope].
   @DomName('DedicatedWorkerGlobalScope.onmessage')
@@ -9846,32 +9865,29 @@
 
   @DomName('Document.createElement')
   Element createElement(String tagName, [String typeExtension]) {
-    if (typeExtension == null) {
-      return _createElement_2(tagName);
-    } else {
-      return _createElement(tagName, typeExtension);
-    }
+    return (typeExtension == null)
+        ? _createElement_2(tagName)
+        : _createElement(tagName, typeExtension);
   }
 
   // The two-argument version of this is automatically generated, but we need to
   // omit the typeExtension if it's null on Firefox or we get an is="null" attribute.
   @DomName('Document.createElement')
-  _createElement_2(String tagName) => JS('', '#.createElement(#)', this, tagName);
+  _createElement_2(String tagName) =>
+      JS('Element', '#.createElement(#)', this, tagName);
 
   // The three-argument version of this is automatically generated, but we need to
   // omit the typeExtension if it's null on Firefox or we get an is="null" attribute.
   @DomName('Document.createElementNS')
   _createElementNS_2(String namespaceURI, String qualifiedName) =>
-      JS('', '#.createElementNS(#, #)', this, namespaceURI, qualifiedName);
+      JS('Element', '#.createElementNS(#, #)', this, namespaceURI, qualifiedName);
 
   @DomName('Document.createElementNS')
   @DocsEditable()
   Element createElementNS(String namespaceURI, String qualifiedName, [String typeExtension]) {
-    if (typeExtension == null) {
-      return _createElementNS_2(namespaceURI, qualifiedName);
-    } else {
-      return _createElementNS(namespaceURI, qualifiedName, typeExtension);
-    }
+    return (typeExtension == null)
+        ? _createElementNS_2(namespaceURI, qualifiedName)
+        : _createElementNS(namespaceURI, qualifiedName, typeExtension);
   }
 
   @DomName('Document.createNodeIterator')
@@ -27430,7 +27446,26 @@
   @DomName('ServiceWorkerClient.postMessage')
   @DocsEditable()
   @Experimental() // untriaged
-  void postMessage(/*SerializedScriptValue*/ message, [List<MessagePort> transfer]) native;
+  void postMessage(/*SerializedScriptValue*/ message, [List<MessagePort> transfer]) {
+    if (transfer != null) {
+      var message_1 = convertDartToNative_SerializedScriptValue(message);
+      _postMessage_1(message_1, transfer);
+      return;
+    }
+    var message_1 = convertDartToNative_SerializedScriptValue(message);
+    _postMessage_2(message_1);
+    return;
+  }
+  @JSName('postMessage')
+  @DomName('ServiceWorkerClient.postMessage')
+  @DocsEditable()
+  @Experimental() // untriaged
+  void _postMessage_1(message, List<MessagePort> transfer) native;
+  @JSName('postMessage')
+  @DomName('ServiceWorkerClient.postMessage')
+  @DocsEditable()
+  @Experimental() // untriaged
+  void _postMessage_2(message) 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
@@ -31921,9 +31956,9 @@
    *
    * ## Other resources
    *
-   * * [Loading web pages]
-   * (http://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html)
-   * from WHATWG.
+   * * [Loading web
+   *   pages](https://html.spec.whatwg.org/multipage/browsers.html)
+   *   from WHATWG.
    */
   Document get document => JS('Document', '#.document', this);
 
@@ -31937,10 +31972,10 @@
    *
    * ## Other resources
    *
-   * * [Window.open]
-   * (https://developer.mozilla.org/en-US/docs/Web/API/Window.open) from MDN.
-   * * [Window open]
-   * (http://docs.webplatform.org/wiki/dom/methods/open) from WebPlatform.org.
+   * * [Window.open](https://developer.mozilla.org/en-US/docs/Web/API/Window.open)
+   *   from MDN.
+   * * [Window open](http://docs.webplatform.org/wiki/dom/methods/open)
+   *   from WebPlatform.org.
    */
   WindowBase open(String url, String name, [String options]) {
     if (options == null) {
@@ -32002,8 +32037,8 @@
    *
    * ## Other resources
    *
-   * * [Window.cancelAnimationFrame]
-   * (https://developer.mozilla.org/en-US/docs/Web/API/Window.cancelAnimationFrame) from MDN.
+   * * [Window.cancelAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/Window.cancelAnimationFrame)
+   *   from MDN.
    */
   void cancelAnimationFrame(int id) {
     _ensureRequestAnimationFrame();
@@ -33772,10 +33807,10 @@
    *
    * ## Other resources
    *
-   * * [Window.moveTo]
-   * (https://developer.mozilla.org/en-US/docs/Web/API/Window.moveTo) from MDN.
-   * * [Window.moveTo]
-   * (http://dev.w3.org/csswg/cssom-view/#dom-window-moveto) from W3C.
+   * * [Window.moveTo](https://developer.mozilla.org/en-US/docs/Web/API/Window.moveTo)
+   *   from MDN.
+   * * [Window.moveTo](http://dev.w3.org/csswg/cssom-view/#dom-window-moveto)
+   *   from W3C.
    */
   void moveTo(Point p) {
     _moveTo(p.x, p.y);
@@ -33794,10 +33829,10 @@
    *
    * ## Other resources
    *
-   * * [The Screen interface specification]
-   * (http://www.w3.org/TR/cssom-view/#screen) from W3C.
-   * * [scrollX]
-   * (https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollX) from MDN.
+   * * [The Screen interface
+   *   specification](http://www.w3.org/TR/cssom-view/#screen) from W3C.
+   * * [scrollX](https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollX)
+   *   from MDN.
    */
   @DomName('Window.scrollX')
   @DocsEditable()
@@ -33810,10 +33845,10 @@
    *
    * ## Other resources
    *
-   * * [The Screen interface specification]
-   * (http://www.w3.org/TR/cssom-view/#screen) from W3C.
-   * * [scrollY]
-   * (https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY) from MDN.
+   * * [The Screen interface
+   *   specification](http://www.w3.org/TR/cssom-view/#screen) from W3C.
+   * * [scrollY](https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY)
+   *   from MDN.
    */
   @DomName('Window.scrollY')
   @DocsEditable()
@@ -34020,7 +34055,24 @@
 
   @DomName('Worker.postMessage')
   @DocsEditable()
-  void postMessage(/*SerializedScriptValue*/ message, [List<MessagePort> transfer]) native;
+  void postMessage(/*SerializedScriptValue*/ message, [List<MessagePort> transfer]) {
+    if (transfer != null) {
+      var message_1 = convertDartToNative_SerializedScriptValue(message);
+      _postMessage_1(message_1, transfer);
+      return;
+    }
+    var message_1 = convertDartToNative_SerializedScriptValue(message);
+    _postMessage_2(message_1);
+    return;
+  }
+  @JSName('postMessage')
+  @DomName('Worker.postMessage')
+  @DocsEditable()
+  void _postMessage_1(message, List<MessagePort> transfer) native;
+  @JSName('postMessage')
+  @DomName('Worker.postMessage')
+  @DocsEditable()
+  void _postMessage_2(message) native;
 
   @DomName('Worker.terminate')
   @DocsEditable()
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index cc87949..6b1a7f7 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -9535,7 +9535,7 @@
   @DomName('DedicatedWorkerGlobalScope.postMessage')
   @DocsEditable()
   @Experimental() // untriaged
-  void postMessage(Object message, [List<MessagePort> transfer]) => _blink.BlinkDedicatedWorkerGlobalScope.instance.postMessage_Callback_2_(unwrap_jso(this), message, transfer);
+  void postMessage(Object message, [List<MessagePort> transfer]) => _blink.BlinkDedicatedWorkerGlobalScope.instance.postMessage_Callback_2_(unwrap_jso(this), convertDartToNative_SerializedScriptValue(message), transfer);
   
   /// Stream of `message` events handled by this [DedicatedWorkerGlobalScope].
   @DomName('DedicatedWorkerGlobalScope.onmessage')
@@ -33019,7 +33019,7 @@
   @DomName('ServiceWorkerClient.postMessage')
   @DocsEditable()
   @Experimental() // untriaged
-  void postMessage(/*SerializedScriptValue*/ message, [List<MessagePort> transfer]) => _blink.BlinkServiceWorkerClient.instance.postMessage_Callback_2_(unwrap_jso(this), message, transfer);
+  void postMessage(/*SerializedScriptValue*/ message, [List<MessagePort> transfer]) => _blink.BlinkServiceWorkerClient.instance.postMessage_Callback_2_(unwrap_jso(this), convertDartToNative_SerializedScriptValue(message), transfer);
   
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -40454,10 +40454,10 @@
    *
    * ## Other resources
    *
-   * * [Window.moveTo]
-   * (https://developer.mozilla.org/en-US/docs/Web/API/Window.moveTo) from MDN.
-   * * [Window.moveTo]
-   * (http://dev.w3.org/csswg/cssom-view/#dom-window-moveto) from W3C.
+   * * [Window.moveTo](https://developer.mozilla.org/en-US/docs/Web/API/Window.moveTo)
+   *   from MDN.
+   * * [Window.moveTo](http://dev.w3.org/csswg/cssom-view/#dom-window-moveto)
+   *   from W3C.
    */
   void moveTo(Point p) {
     _moveTo(p.x, p.y);
@@ -40677,7 +40677,7 @@
 
   @DomName('Worker.postMessage')
   @DocsEditable()
-  void postMessage(/*SerializedScriptValue*/ message, [List<MessagePort> transfer]) => _blink.BlinkWorker.instance.postMessage_Callback_2_(unwrap_jso(this), message, transfer);
+  void postMessage(/*SerializedScriptValue*/ message, [List<MessagePort> transfer]) => _blink.BlinkWorker.instance.postMessage_Callback_2_(unwrap_jso(this), convertDartToNative_SerializedScriptValue(message), transfer);
   
   @DomName('Worker.terminate')
   @DocsEditable()
diff --git a/sdk/lib/html/html_common/conversions_dart2js.dart b/sdk/lib/html/html_common/conversions_dart2js.dart
index 3b3a8ad..b7f3d7c 100644
--- a/sdk/lib/html/html_common/conversions_dart2js.dart
+++ b/sdk/lib/html/html_common/conversions_dart2js.dart
@@ -88,7 +88,7 @@
   var completer = new Completer();
   var then = convertDartClosureToJS((result) => completer.complete(result), 1);
   var error = convertDartClosureToJS((result) => completer.completeError(result), 1);
-  var newPromise = JS('', '#.then(#).catch(#)', promise, then, error);
+  var newPromise = JS('', '#.then(#)["catch"](#)', promise, then, error);
   return completer.future;
 }
 
diff --git a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
index 034b2ce..1f80c9d 100644
--- a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
+++ b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -380,7 +380,7 @@
     List storeNames_1 = convertDartToNative_StringArray(storeNames);
     return _transaction(storeNames_1, mode);
   }
-  
+
   Transaction transactionStores(DomStringList storeNames, String mode) {
     if (mode != 'readonly' && mode != 'readwrite') {
       throw new ArgumentError(mode);
diff --git a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
index c75130a..4ab3e30 100644
--- a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
+++ b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
@@ -292,6 +292,27 @@
     return _createObjectStore(name, options);
   }
 
+  Transaction transaction(storeName_OR_storeNames, String mode) {
+    if (mode != 'readonly' && mode != 'readwrite') {
+      throw new ArgumentError("Invalid transaction mode $mode");
+    }
+    var names;
+    if (storeName_OR_storeNames == null) {
+      throw new ArgumentError("stores may not be null in transaction");
+    } else if (storeName_OR_storeNames is String || storeName_OR_storeNames is DomStringList) {
+      names = unwrap_jso(storeName_OR_storeNames);
+    } else if (storeName_OR_storeNames is List<String>) {
+      names = convertDartToNative_List(storeName_OR_storeNames);
+    } else {
+      throw new ArgumentError("Invalid store(s) $store_Name_OR_storeNames");
+    }
+
+    return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_2_(unwrap_jso(this), names, mode));
+  }
+
+  Transaction transactionList(List<String> storeNames, String mode) => transaction(storeNames, mode);
+  Transaction transactionStores(List<String> storeNames, String mode) => transaction(storeNames, mode);
+  Transaction transactionStore(String storeName, String mode) => transaction(storeName, mode);
 
   // To suppress missing implicit constructor warnings.
   factory Database._() { throw new UnsupportedError("Not supported"); }
@@ -379,49 +400,6 @@
   @DocsEditable()
   void deleteObjectStore(String name) => _blink.BlinkIDBDatabase.instance.deleteObjectStore_Callback_1_(unwrap_jso(this), name);
   
-  Transaction transaction(storeName_OR_storeNames, [String mode]) {
-    if ((storeName_OR_storeNames is String || storeName_OR_storeNames == null) && mode == null) {
-      return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_1_(unwrap_jso(this), unwrap_jso(storeName_OR_storeNames)));
-    }
-    if ((mode is String || mode == null) && (storeName_OR_storeNames is String || storeName_OR_storeNames == null)) {
-      return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_2_(unwrap_jso(this), unwrap_jso(storeName_OR_storeNames), mode));
-    }
-    if ((storeName_OR_storeNames is List<String> || storeName_OR_storeNames == null) && mode == null) {
-      return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_1_(unwrap_jso(this), unwrap_jso(storeName_OR_storeNames)));
-    }
-    if ((mode is String || mode == null) && (storeName_OR_storeNames is List<String> || storeName_OR_storeNames == null)) {
-      return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_2_(unwrap_jso(this), unwrap_jso(storeName_OR_storeNames), mode));
-    }
-    if ((storeName_OR_storeNames is DomStringList || storeName_OR_storeNames == null) && mode == null) {
-      return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_1_(unwrap_jso(this), unwrap_jso(storeName_OR_storeNames)));
-    }
-    if ((mode is String || mode == null) && (storeName_OR_storeNames is DomStringList || storeName_OR_storeNames == null)) {
-      return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_2_(unwrap_jso(this), unwrap_jso(storeName_OR_storeNames), mode));
-    }
-    throw new ArgumentError("Incorrect number or type of arguments");
-  }
-
-  Transaction transactionList(List<String> storeNames, [String mode]) {
-    if (mode != null) {
-      return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_2_(unwrap_jso(this), convertDartToNative_StringArray(storeNames), mode));
-    }
-    return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_1_(unwrap_jso(this), convertDartToNative_StringArray(storeNames)));
-  }
-
-  Transaction transactionStore(String storeName, [String mode]) {
-    if (mode != null) {
-      return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_2_(unwrap_jso(this), storeName, mode));
-    }
-    return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_1_(unwrap_jso(this), storeName));
-  }
-
-  Transaction transactionStores(List<String> storeNames, [String mode]) {
-    if (mode != null) {
-      return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_2_(unwrap_jso(this), unwrap_jso(storeNames), mode));
-    }
-    return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_1_(unwrap_jso(this), unwrap_jso(storeNames)));
-  }
-
   /// Stream of `abort` events handled by this [Database].
   @DomName('IDBDatabase.onabort')
   @DocsEditable()
diff --git a/sdk/lib/math/math.dart b/sdk/lib/math/math.dart
index d167d80..9182442 100644
--- a/sdk/lib/math/math.dart
+++ b/sdk/lib/math/math.dart
@@ -63,7 +63,7 @@
   * same mathematical value) then it is unspecified which of the two arguments
   * is returned.
   */
-num min(num a, num b) {
+num/*=T*/ min/*<T extends num>*/(num/*=T*/ a, num/*=T*/ b) {
   // These partially redundant type checks improve code quality for dart2js.
   // Most of the improvement is at call sites from the inferred non-null num
   // return type.
@@ -98,7 +98,7 @@
   * otherwise equal (including int and doubles with the same mathematical value)
   * then it is unspecified which of the two arguments is returned.
   */
-num max(num a, num b) {
+num/*=T*/ max/*<T extends num>*/(num/*=T*/ a, num/*=T*/ b) {
   // These partially redundant type checks improve code quality for dart2js.
   // Most of the improvement is at call sites from the inferred non-null num
   // return type.
diff --git a/sdk/lib/vmservice/asset.dart b/sdk/lib/vmservice/asset.dart
index 7835e74..8155e8a 100644
--- a/sdk/lib/vmservice/asset.dart
+++ b/sdk/lib/vmservice/asset.dart
@@ -38,8 +38,8 @@
   }
 
   /// Call to request assets from the embedder.
-  static Map<String, Asset> request() {
-    Map<String, Asset> assets = new Map<String, Asset>();
+  static HashMap<String, Asset> request() {
+    HashMap<String, Asset> assets = new HashMap<String, Asset>();
     Uint8List tarBytes = _requestAssets();
     if (tarBytes == null) {
       return assets;
diff --git a/sdk/lib/vmservice/vmservice.dart b/sdk/lib/vmservice/vmservice.dart
index 6c9e8e5..fa7790f 100644
--- a/sdk/lib/vmservice/vmservice.dart
+++ b/sdk/lib/vmservice/vmservice.dart
@@ -5,6 +5,7 @@
 library dart._vmservice;
 
 import 'dart:async';
+import 'dart:collection';
 import 'dart:convert';
 import 'dart:isolate';
 import 'dart:typed_data';
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 7b463d9..56ccac3 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -628,6 +628,8 @@
 LayoutTests/fast/animation/request-animation-frame-timestamps_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/animation/request-animation-frame-within-callback_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/backgrounds/repeat/parsing-background-repeat_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/backgrounds/background-shorthand-with-backgroundSize-style_t01: RuntimeError # co19 issue 14
+LayoutTests/fast/backgrounds/multiple-backgrounds-computed-style_t01: RuntimeError # co19 issue 14
 LayoutTests/fast/borders/border-radius-child_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/2d.fillText.gradient_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/2d.text.draw.fill.maxWidth.gradient_t01: RuntimeError # Please triage this failure
@@ -747,6 +749,8 @@
 LayoutTests/fast/css/aspect-ratio-parsing-tests_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/css/auto-min-size_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/background-position-serialize_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/background-serialize_t01: RuntimeError # https://github.com/dart-lang/co19/issues/14
+LayoutTests/fast/css/css-escaped-identifier_t01: RuntimeError # co19 issue 14
 LayoutTests/fast/css/checked-pseudo-selector_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/collapsed-whitespace-reattach-in-style-recalc_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/content-language-case-insensitivity_t01: RuntimeError # Issue 23506
@@ -763,6 +767,8 @@
 LayoutTests/fast/css/css3-nth-tokens-style_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/cssText-shorthand_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/csstext-of-content-string_t01: Pass, RuntimeError # Please triage this failure
+LayoutTests/fast/css/cursor-parsing_t01: RuntimeError # co19 issue 14
+LayoutTests/fast/css/cursor-parsing-image-set_t01: RuntimeError # co19 issue 14
 LayoutTests/fast/css/cursor-parsing-quirks_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/deprecated-flexbox-auto-min-size_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/ex-unit-with-no-x-height_t01: Pass, RuntimeError # Please triage this failure
@@ -776,6 +782,8 @@
 LayoutTests/fast/css/font-shorthand-from-longhands_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/fontfaceset-events_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/css/fontfaceset-loadingdone_t01: Pass, RuntimeError # Please triage this failure
+LayoutTests/fast/css/getComputedStyle/computed-style-border-image_t01: RuntimeError # co19 issue 14
+LayoutTests/fast/css/getComputedStyle/computed-style-cross-fade_t01: RuntimeError # co19 issue 14
 LayoutTests/fast/css/getComputedStyle/computed-style-font_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/getComputedStyle/computed-style-properties_t01: RuntimeError # Issue 23506
 LayoutTests/fast/css/getComputedStyle/counterIncrement-without-counter_t01: RuntimeError # Please triage this failure
@@ -825,8 +833,7 @@
 LayoutTests/fast/css/transform-origin-parsing_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/css/webkit-keyframes-errors_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/word-break-user-modify-allowed-values_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/css3-text/css3-text-align-last/getComputedStyle/getComputedStyle-text-align-last-inherited_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/css3-text/css3-text-align-last/getComputedStyle/getComputedStyle-text-align-last_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/url-with-multi-byte-unicode-escape_t01: RuntimeError # co19 issue 14
 LayoutTests/fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-decoration-color_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-decoration-line_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-decoration-style_t01: RuntimeError # Please triage this failure
@@ -1030,6 +1037,7 @@
 LayoutTests/fast/forms/select-list-box-mouse-focus_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/forms/select-max-length_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/setrangetext_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/forms/submit-form-attributes_t01: RuntimeError # co19 issue 14
 LayoutTests/fast/forms/textarea-paste-newline_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/forms/textfield-focus-out_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/forms/validationMessage_t01: RuntimeError # Please triage this failure
@@ -1044,6 +1052,7 @@
 LayoutTests/fast/inline/parent-inline-element-padding-contributes-width_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/inline/positioned-element-padding-contributes-width_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/innerHTML/javascript-url_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/innerHTML/innerHTML-uri-resolution_t01: RuntimeError # co19 issue 14
 LayoutTests/fast/layers/normal-flow-hit-test_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/layers/zindex-hit-test_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/loader/about-blank-hash-change_t01: Skip # Times out. Please triage this failure
@@ -1053,6 +1062,7 @@
 LayoutTests/fast/loader/scroll-position-restored-on-back_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/loader/scroll-position-restored-on-reload-at-load-event_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/loader/stateobjects/replacestate-in-onunload_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/innerHTML/innerHTML-uri-resolution_t01: RuntimeError # co19 issue 14
 LayoutTests/fast/masking/parsing-clip-path-shape_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/masking/parsing-mask-source-type_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/masking/parsing-mask_t01: RuntimeError # Please triage this failure
@@ -1616,10 +1626,6 @@
 LayoutTests/fast/text/text-combine-shrink-to-fit_t01: RuntimeError # Please triage this failure
 
 [ $compiler == dart2js && $runtime == chrome && $system == windows ]
-LayoutTests/fast/canvas/canvas-blend-image_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-blend-solid_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-blending-clipping_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-blending-color-over-color_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-blending-color-over-gradient_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-blending-color-over-image_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-blending-color-over-pattern_t01: RuntimeError # Please triage this failure
@@ -1628,22 +1634,15 @@
 LayoutTests/fast/canvas/canvas-blending-gradient-over-color_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-blending-gradient-over-gradient_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-blending-gradient-over-image_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-blending-gradient-over-pattern_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-blending-image-over-color_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-blending-image-over-gradient_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-blending-image-over-image_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-blending-image-over-pattern_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-blending-pattern-over-color_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-blending-pattern-over-gradient_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-blending-pattern-over-image_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-blending-pattern-over-pattern_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-blending-shadow_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-blending-transforms_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-composite-alpha_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-composite-canvas_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-composite-image_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-composite-stroke-alpha_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-composite-text-alpha_t01: RuntimeError # Please triage this failure
 
 [ $compiler == dart2js && $runtime == chrome && $system != linux ]
 LayoutTests/fast/xpath/py-dom-xpath/abbreviations_t01: RuntimeError # Issue 24398
@@ -1684,7 +1683,6 @@
 LayoutTests/fast/canvas/canvas-blending-text_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-composite-canvas_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-composite-image_t01: Pass, RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-composite-text-alpha_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-css-crazy_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-currentColor_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-currentTransform_t01: RuntimeError # Feature is not implemented.
@@ -2480,7 +2478,6 @@
 LayoutTests/fast/forms/autofocus-readonly-attribute_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/forms/button/button-disabled-blur_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/forms/button-baseline-and-collapsing_t01: Pass, RuntimeError # Please triage this failure
-LayoutTests/fast/forms/change-form-element-document-crash_t01: RuntimeError # Dartium JSInterop failure, or else Firefox roll error. Issue 24409
 LayoutTests/fast/forms/checkValidity-001_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/forms/checkValidity-002_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/forms/checkValidity-004_t01: Pass, RuntimeError # Please triage this failure
diff --git a/tests/co19/co19-dartium.status b/tests/co19/co19-dartium.status
index 97e699d..4062b0e 100644
--- a/tests/co19/co19-dartium.status
+++ b/tests/co19/co19-dartium.status
@@ -827,24 +827,24 @@
 LibTest/isolate/Isolate/spawn_A01_t05: RuntimeError # co19-roll r667: Please triage this failure
 LibTest/isolate/RawReceivePort/RawReceivePort_A01_t01: RuntimeError # Issue 13921
 LibTest/isolate/RawReceivePort/RawReceivePort_A01_t02: RuntimeError # Issue 13921
-LibTest/isolate/RawReceivePort/close_A01_t01: RuntimeError # Issue 13921
+LibTest/isolate/RawReceivePort/close_A01_t01: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
 LibTest/isolate/RawReceivePort/handler_A01_t01: RuntimeError # Issue 13921
 LibTest/isolate/RawReceivePort/sendPort_A01_t01: RuntimeError # Issue 13921
 LibTest/isolate/ReceivePort/any_A01_t01: RuntimeError # Issue 13921
 LibTest/isolate/ReceivePort/any_A01_t02: RuntimeError # Issue 13921
 LibTest/isolate/ReceivePort/asBroadcastStream_A01_t01: RuntimeError # Issue 13921
-LibTest/isolate/ReceivePort/asBroadcastStream_A01_t02: RuntimeError # Issue 13921
+LibTest/isolate/ReceivePort/asBroadcastStream_A01_t02: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
 LibTest/isolate/ReceivePort/asBroadcastStream_A01_t03: RuntimeError # Issue 13921
 LibTest/isolate/ReceivePort/asBroadcastStream_A01_t04: RuntimeError # Issue 13921
 LibTest/isolate/ReceivePort/asBroadcastStream_A02_t01: RuntimeError # Issue 13921
-LibTest/isolate/ReceivePort/asBroadcastStream_A03_t01: RuntimeError # Issue 13921
-LibTest/isolate/ReceivePort/asBroadcastStream_A03_t02: RuntimeError # Issue 13921
-LibTest/isolate/ReceivePort/asBroadcastStream_A03_t03: RuntimeError # Issue 13921
+LibTest/isolate/ReceivePort/asBroadcastStream_A03_t01: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
+LibTest/isolate/ReceivePort/asBroadcastStream_A03_t02: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
+LibTest/isolate/ReceivePort/asBroadcastStream_A03_t03: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
 LibTest/isolate/ReceivePort/asBroadcastStream_A04_t01: RuntimeError # Issue 13921
 LibTest/isolate/ReceivePort/asBroadcastStream_A04_t02: RuntimeError # Issue 13921
 LibTest/isolate/ReceivePort/asBroadcastStream_A04_t03: RuntimeError # Issue 13921
-LibTest/isolate/ReceivePort/close_A01_t01: RuntimeError # Issue 13921
-LibTest/isolate/ReceivePort/close_A02_t01: RuntimeError # Issue 13921
+LibTest/isolate/ReceivePort/close_A01_t01: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
+LibTest/isolate/ReceivePort/close_A02_t01: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
 LibTest/isolate/ReceivePort/contains_A01_t01: RuntimeError # Issue 13921
 LibTest/isolate/ReceivePort/distinct_A01_t01: RuntimeError # Issue 13921
 LibTest/isolate/ReceivePort/distinct_A01_t02: RuntimeError # Issue 13921
diff --git a/tests/compiler/dart2js/compiler_helper.dart b/tests/compiler/dart2js/compiler_helper.dart
index e0a69f1..bef0984 100644
--- a/tests/compiler/dart2js/compiler_helper.dart
+++ b/tests/compiler/dart2js/compiler_helper.dart
@@ -43,7 +43,8 @@
 import 'output_collector.dart';
 export 'output_collector.dart';
 
-/// Compile [code] and returns the code for [entry].
+/// Compile [code] and returns either the code for [entry] or, if [returnAll] is
+/// true, the code for the entire program.
 ///
 /// If [check] is provided, it is executed on the code for [entry] before
 /// returning. If [useMock] is `true` the [MockCompiler] is used for
@@ -54,8 +55,11 @@
                         bool minify: false,
                         bool analyzeAll: false,
                         bool disableInlining: true,
+                        bool trustJSInteropTypeAnnotations: false,
                         bool useMock: false,
-                        void check(String generated)}) async {
+                        void check(String generatedEntry),
+                        bool returnAll: false}) async {
+  OutputCollector outputCollector = returnAll ? new OutputCollector() : null;
   if (useMock) {
     // TODO(johnniwinther): Remove this when no longer needed by
     // `arithmetic_simplication_test.dart`.
@@ -65,7 +69,9 @@
         // compiling a method.
         disableTypeInference: true,
         enableMinification: minify,
-        disableInlining: disableInlining);
+        disableInlining: disableInlining,
+        trustJSInteropTypeAnnotations: trustJSInteropTypeAnnotations,
+        outputProvider: outputCollector);
     await compiler.init();
     compiler.parseScript(code);
     lego.Element element = compiler.mainApp.find(entry);
@@ -89,7 +95,7 @@
     if (check != null) {
       check(generated);
     }
-    return generated;
+    return returnAll ? outputCollector.getOutput('', 'js') : generated;
   } else {
     List<String> options = <String>[
         Flags.disableTypeInference];
@@ -102,6 +108,9 @@
     if (analyzeAll) {
       options.add(Flags.analyzeAll);
     }
+    if (trustJSInteropTypeAnnotations) {
+      options.add(Flags.trustJSInteropTypeAnnotations);
+    }
 
     Map<String, String> source;
     if (entry != 'main') {
@@ -113,6 +122,7 @@
     CompilationResult result = await runCompiler(
         memorySourceFiles: source,
         options: options,
+        outputProvider: outputCollector,
         beforeRun: (compiler) {
           if (disableInlining) {
             compiler.disableInlining = true;
@@ -126,7 +136,7 @@
     if (check != null) {
       check(generated);
     }
-    return generated;
+    return returnAll ? outputCollector.getOutput('', 'js') : generated;
   }
 }
 
diff --git a/tests/compiler/dart2js/dart2js.status b/tests/compiler/dart2js/dart2js.status
index ed4cdeb..b7a65e8 100644
--- a/tests/compiler/dart2js/dart2js.status
+++ b/tests/compiler/dart2js/dart2js.status
@@ -56,14 +56,19 @@
 exit_code_test: Skip # This tests requires checked mode.
 
 [ $checked ]
+analyze_dart2js_helpers_test: Pass, Slow
 analyze_dart2js_test: Pass, Slow
 analyze_unused_dart2js_test: Pass, Slow
-uri_retention_test: Pass, Slow
+check_elements_invariants_test: Slow, Pass, Timeout
 deferred_mirrors_test: Pass, Slow
-mirror_final_field_inferrer2_test: Pass, Slow
-check_elements_invariants_test: Slow, Pass
-import_mirrors_test: Slow, Pass
+duplicate_library_test: Pass, Slow
 exit_code_test: Pass, Slow
+import_mirrors_test: Slow, Pass
+interop_anonymous_unreachable_test: Pass, Slow
+mirror_final_field_inferrer2_test: Pass, Slow
+source_map_pub_build_validity_test: Pass, Slow
+sourcemaps/source_mapping_operators_test: Pass, Slow
+uri_retention_test: Pass, Slow
 value_range_test: Pass, Slow
 
 [ $mode == debug ]
diff --git a/tests/compiler/dart2js/interop_anonymous_unreachable_test.dart b/tests/compiler/dart2js/interop_anonymous_unreachable_test.dart
new file mode 100644
index 0000000..3f38205
--- /dev/null
+++ b/tests/compiler/dart2js/interop_anonymous_unreachable_test.dart
@@ -0,0 +1,177 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library tests.dart2js.interop_anonymous_unreachable_test;
+
+import 'dart:async';
+
+import 'package:test/test.dart';
+import 'compiler_helper.dart';
+
+
+main() {
+  test("unreachable code doesn't crash the compiler", () async {
+    // This test is a regression for Issue #24974
+    String generated = await compile("""
+        import 'package:js/js.dart';
+
+        @JS() @anonymous
+        class UniqueLongNameForTesting_A {
+          external factory UniqueLongNameForTesting_A();
+        }
+        main() {}
+    """, returnAll: true);
+
+    // the code should not be included in the output either.
+    expect(generated, isNot(contains("UniqueLongNameForTesting_A")));
+  });
+
+  group('tree-shaking interop types', () {
+    String program = """
+        import 'package:js/js.dart';
+
+        // reachable and allocated
+        @JS() @anonymous
+        class UniqueLongNameForTesting_A {
+          external bool get x;
+          external UniqueLongNameForTesting_D get d;
+          external UniqueLongNameForTesting_E get e;
+          external factory UniqueLongNameForTesting_A(
+              {UniqueLongNameForTesting_B arg0});
+        }
+
+        // visible through the parameter above, but not used.
+        @JS() @anonymous
+        class UniqueLongNameForTesting_B {
+          external factory UniqueLongNameForTesting_B();
+        }
+
+        // unreachable
+        @JS() @anonymous
+        class UniqueLongNameForTesting_C {
+          external factory UniqueLongNameForTesting_C();
+        }
+
+        // visible and reached through `d`.
+        @JS() @anonymous
+        class UniqueLongNameForTesting_D {
+          external factory UniqueLongNameForTesting_D();
+        }
+
+        // visible through `e`, but not reached.
+        @JS() @anonymous
+        class UniqueLongNameForTesting_E {
+          external factory UniqueLongNameForTesting_E();
+        }
+
+        main() {
+          print(new UniqueLongNameForTesting_A().x);
+          print(new UniqueLongNameForTesting_A().d);
+        }
+    """;
+
+    test('no tree-shaking by default', () async {
+      String generated = await compile(program, returnAll: true);
+      expect(generated.contains("UniqueLongNameForTesting_A"), isTrue);
+      expect(generated.contains("UniqueLongNameForTesting_D"), isTrue);
+
+      expect(generated.contains("UniqueLongNameForTesting_B"), isTrue);
+      expect(generated.contains("UniqueLongNameForTesting_C"), isTrue);
+      expect(generated.contains("UniqueLongNameForTesting_E"), isTrue);
+    });
+
+    test('tree-shake when using flag', () async {
+      String generated = await compile(program,
+          trustJSInteropTypeAnnotations: true,
+          returnAll: true);
+      expect(generated.contains("UniqueLongNameForTesting_A"), isTrue);
+      expect(generated.contains("UniqueLongNameForTesting_D"), isTrue);
+
+      expect(generated.contains("UniqueLongNameForTesting_B"), isFalse);
+      expect(generated.contains("UniqueLongNameForTesting_C"), isFalse);
+      expect(generated.contains("UniqueLongNameForTesting_E"), isFalse);
+    });
+  });
+
+  group('tree-shaking other native types', () {
+    String program = """
+        import 'dart:html';
+        import 'package:js/js.dart';
+
+        @JS() @anonymous
+        class UniqueLongNameForTesting_A {
+          external dynamic get x;
+        }
+
+        @JS() @anonymous
+        class UniqueLongNameForTesting_B {
+          external dynamic get y;
+        }
+
+        main() {
+          print(new UniqueLongNameForTesting_A().x);
+        }
+    """;
+
+    test('allocation effect of dynamic excludes native types', () async {
+      String generated = await compile(program, returnAll: true);
+      expect(generated.contains("UniqueLongNameForTesting_A"), isTrue);
+      // any js-interop type could be allocated by `get x`
+      expect(generated.contains("UniqueLongNameForTesting_B"), isTrue);
+      // but we exclude other native types like HTMLAudioElement
+      expect(generated.contains("HTMLAudioElement"), isFalse);
+    });
+
+    test('allocation effect of dynamic excludes native types [flag]', () async {
+      // Trusting types doesn't make a difference.
+      String generated = await compile(program,
+          trustJSInteropTypeAnnotations: true,
+          returnAll: true);
+      expect(generated.contains("UniqueLongNameForTesting_A"), isTrue);
+      expect(generated.contains("UniqueLongNameForTesting_B"), isTrue);
+      expect(generated.contains("HTMLAudioElement"), isFalse);
+    });
+
+    test('declared native types are included in allocation effect', () async {
+      String program2 = """
+          import 'dart:html';
+          import 'package:js/js.dart';
+
+          @JS() @anonymous
+          class UniqueLongNameForTesting_A {
+            external AudioElement get x;
+          }
+
+          main() {
+            print(new UniqueLongNameForTesting_A().x is AudioElement);
+          }
+      """;
+
+      String generated = await compile(program2, returnAll: true);
+      expect(generated.contains("UniqueLongNameForTesting_A"), isTrue);
+      expect(generated.contains("HTMLAudioElement"), isTrue);
+
+      program2 = """
+          import 'dart:html';
+          import 'package:js/js.dart';
+
+          @JS() @anonymous
+          class UniqueLongNameForTesting_A {
+            external dynamic get x;
+          }
+
+          main() {
+            print(new UniqueLongNameForTesting_A().x is AudioElement);
+          }
+      """;
+
+      generated = await compile(program2, returnAll: true);
+      expect(generated.contains("UniqueLongNameForTesting_A"), isTrue);
+      // This extra check is to make sure that we don't include HTMLAudioElement
+      // just because of the is-check. It is optimized away in this case because
+      // we believe it was never instantiated.
+      expect(generated.contains("HTMLAudioElement"), isFalse);
+    });
+  });
+}
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_closures_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_closures_test.dart
index be1bd40..38608d0 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir_closures_test.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir_closures_test.dart
@@ -247,7 +247,7 @@
 """,
 r"""
 function(x) {
-  P.print(V.Foo$().getter$1(123));
+  P.print(V.Foo$().get$getter().call$1(123));
 }"""),
 ];
 
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_codeUnitAt_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_codeUnitAt_test.dart
new file mode 100644
index 0000000..b3f2808
--- /dev/null
+++ b/tests/compiler/dart2js/js_backend_cps_ir_codeUnitAt_test.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Tests for constant folding and lowering String.codeUnitAt.
+
+library basic_tests;
+
+import 'js_backend_cps_ir.dart';
+
+const List<TestEntry> tests = const [
+
+  // Constant folding.
+  const TestEntry(r"""
+main() {
+  print('A'.codeUnitAt(0));
+}""",r"""
+function() {
+  P.print(65);
+}"""),
+
+
+  // Bounds checking.
+  const TestEntry.forMethod('function(foo)',
+r"""
+foo(s) {
+  var sum = 0;
+  for (int i = 0; i < s.length; i++) sum += s.codeUnitAt(i);
+  return sum;
+}
+main() {
+  print(foo('ABC'));
+  print(foo('Hello'));
+}""",r"""
+function(s) {
+  var v0 = s.length, sum = 0, i = 0;
+  for (; i < v0; sum = sum + s.charCodeAt(i), i = i + 1)
+    ;
+  return sum;
+}"""),
+];
+
+
+void main() {
+  runTests(tests);
+}
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_gvn_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_gvn_test.dart
new file mode 100644
index 0000000..873afa8
--- /dev/null
+++ b/tests/compiler/dart2js/js_backend_cps_ir_gvn_test.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that the GVN optimization pass works as expected.
+
+library basic_tests;
+
+import 'js_backend_cps_ir.dart';
+
+const List<TestEntry> tests = const [
+  const TestEntry.forMethod('function(foo)', r"""
+foo(x, list) {
+  var sum = 0;
+  for (int k = 0; k < 10; k++) {
+    // Everything can be hoisted out, except the bounds check and sum += z.
+    var a = x.left.left;
+    var b = x.left.right;
+    var c = x.right.left;
+    var d = x.right.right;
+    var i = a.value + c.value;
+    var j = b.value + d.value;
+    var z = list[i * j] + i;
+    sum += z;
+  }
+  return sum;
+}
+// Use a different class for each level in the tree, so type inference
+// is not confused.
+class Root {
+  Branch left, right;
+  Root(this.left, this.right);
+}
+class Branch {
+  Leaf left, right;
+  Branch(this.left, this.right);
+}
+class Leaf {
+  int value;
+  Leaf(this.value);
+}
+main() {
+  var x1 = new Leaf(1);
+  var x2 = new Leaf(10);
+  var x3 = new Leaf(20);
+  var x4 = new Leaf(-10);
+  var y1 = new Branch(x1, x2);
+  var y2 = new Branch(x3, x4);
+  var z  = new Root(y1, y2);
+  print(foo(z, [1,2,3,4,5,6,7,8,9,10]));
+}
+""",r"""
+function(x, list) {
+  var v0 = x.left, a = v0.left, b = v0.right, sum = 0, k = 0, c = (v0 = x.right).left, d = v0.right, i = a.value + c.value, v1 = list[v0 = i * (b.value + d.value)];
+  for (; k < 10; sum = sum + (v1 + i), k = k + 1)
+    if (v0 < 0 || v0 >= 10)
+      return H.ioore(list, v0);
+  return sum;
+}"""),
+];
+
+void main() {
+  runTests(tests);
+}
diff --git a/tests/compiler/dart2js/js_spec_string_test.dart b/tests/compiler/dart2js/js_spec_string_test.dart
index 1481da4..01c9f64 100644
--- a/tests/compiler/dart2js/js_spec_string_test.dart
+++ b/tests/compiler/dart2js/js_spec_string_test.dart
@@ -64,10 +64,11 @@
         typesReturned: actualReturns, typesInstantiated: actualCreates,
         objectType: OBJECT, nullType: NULL);
   } catch (e) {
-    Expect.isTrue(expectError);
-    Expect.isNotNull(listener.errorMessage, 'Error expected.');
+    Expect.isTrue(expectError, 'Unexpected error "$specString"');
+    Expect.isNotNull(listener.errorMessage, 'Error message expected.');
     return;
   }
+  Expect.isFalse(expectError, 'Missing error for "$specString".');
   Expect.isNull(listener.errorMessage, 'Unexpected error.');
   if (returns != null) {
     Expect.listEquals(returns, actualReturns, 'Unexpected returns.');
@@ -217,17 +218,24 @@
   test('returns:void;', returns: [], creates: []);
   test('returns:;', returns: [OBJECT, NULL], creates: []);
   test('returns:var;', returns: [OBJECT, NULL], creates: []);
-  test('returns:A;', returns: ['A'], creates: []);
-  test('returns:A|B;', returns: ['A', 'B'], creates: []);
-  test('returns:A|B|C;', returns: ['A', 'B', 'C'], creates: []);
+  test('returns:A;', returns: ['A'], creates: ['A']);
+  test('returns:A|B;', returns: ['A', 'B'], creates: ['A', 'B']);
+  test('returns:A|B|C;', returns: ['A', 'B', 'C'], creates: ['A', 'B', 'C']);
 
   test('creates:void;', expectError: true);
-  test('creates:;', expectError: true);
-  test('creates:var;', expectError: true);
+  test('creates:;', creates: []);
+  test('creates:var;', creates: []);
   test('creates:A;', returns: [], creates: ['A']);
   test('creates:A|B;', returns: [], creates: ['A', 'B']);
   test('creates:A|B|C;', returns: [], creates: ['A', 'B', 'C']);
 
+  test('returns:void;creates:', returns: [], creates: []);
+  test('returns:;creates:', returns: [OBJECT, NULL], creates: []);
+  test('returns:var;creates:', returns: [OBJECT, NULL], creates: []);
+  test('returns:A;creates:', returns: ['A'], creates: []);
+  test('returns:A|B;creates:;', returns: ['A', 'B'], creates: []);
+  test('returns:A|B|C;creates:;', returns: ['A', 'B', 'C'], creates: []);
+
   test('returns:void;creates:A;', returns: [], creates: ['A']);
   test('returns:;creates:A|B;', returns: [OBJECT, NULL], creates: ['A', 'B']);
   test('returns:var;creates:A|B|C;',
@@ -242,19 +250,32 @@
   testWithSideEffects('returns:void;', returns: [], creates: []);
   testWithSideEffects('returns:;', returns: [OBJECT, NULL], creates: []);
   testWithSideEffects('returns:var;', returns: [OBJECT, NULL], creates: []);
-  testWithSideEffects('returns:A;', returns: ['A'], creates: []);
-  testWithSideEffects('returns:A|B;', returns: ['A', 'B'], creates: []);
-  testWithSideEffects('returns:A|B|C;', returns: ['A', 'B', 'C'], creates: []);
+  testWithSideEffects('returns:A;', returns: ['A'], creates: ['A']);
+  testWithSideEffects('returns:A|B;',
+      returns: ['A', 'B'], creates: ['A', 'B']);
+  testWithSideEffects('returns:A|B|C;',
+      returns: ['A', 'B', 'C'], creates: ['A', 'B', 'C']);
   testWithSideEffects('returns: A| B |C ;',
-      returns: ['A', 'B', 'C'], creates: []);
+      returns: ['A', 'B', 'C'], creates: ['A', 'B', 'C']);
 
   testWithSideEffects('creates:void;', expectError: true);
-  testWithSideEffects('creates:;', expectError: true);
-  testWithSideEffects('creates:var;', expectError: true);
+  testWithSideEffects('creates:;', creates: []);
+  testWithSideEffects('creates:var;', creates: []);
   testWithSideEffects('creates:A;', returns: [], creates: ['A']);
   testWithSideEffects('creates:A|B;', returns: [], creates: ['A', 'B']);
   testWithSideEffects('creates:A|B|C;', returns: [], creates: ['A', 'B', 'C']);
 
+  testWithSideEffects('returns:void;creates:;', returns: [], creates: []);
+  testWithSideEffects('returns:;creates:;',
+      returns: [OBJECT, NULL], creates: []);
+  testWithSideEffects('returns:var;creates:;',
+      returns: [OBJECT, NULL], creates: []);
+  testWithSideEffects('returns:A;creates:;', returns: ['A'], creates: []);
+  testWithSideEffects('returns:A|B;creates:;',
+      returns: ['A', 'B'], creates: []);
+  testWithSideEffects('returns:A|B|C;creates:;',
+      returns: ['A', 'B', 'C'], creates: []);
+
   testWithSideEffects('returns:void;creates:A;', returns: [], creates: ['A']);
   testWithSideEffects('returns:;creates:A|B;',
       returns: [OBJECT, NULL], creates: ['A', 'B']);
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index 9dde5bf..ae06d45 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -79,6 +79,7 @@
        // affected by inlining support.
        bool disableInlining: true,
        bool trustTypeAnnotations: false,
+       bool trustJSInteropTypeAnnotations: false,
        bool enableAsyncAwait: false,
        int this.expectedWarnings,
        int this.expectedErrors,
@@ -98,6 +99,7 @@
               emitJavaScript: emitJavaScript,
               preserveComments: preserveComments,
               trustTypeAnnotations: trustTypeAnnotations,
+              trustJSInteropTypeAnnotations: trustJSInteropTypeAnnotations,
               diagnosticOptions:
                   new DiagnosticOptions(showPackageWarnings: true),
               outputProvider: new LegacyCompilerOutput(outputProvider)) {
diff --git a/tests/compiler/dart2js/mock_libraries.dart b/tests/compiler/dart2js/mock_libraries.dart
index 9b89db0..1141416 100644
--- a/tests/compiler/dart2js/mock_libraries.dart
+++ b/tests/compiler/dart2js/mock_libraries.dart
@@ -64,10 +64,6 @@
       }''',
   'LinkedHashMap': r'''
       class LinkedHashMap<K, V> implements Map<K, V> {
-        factory LinkedHashMap._empty() => null;
-        factory LinkedHashMap._literal(elements) => null;
-        static _makeEmpty() => null;
-        static _makeLiteral(elements) => null;
       }''',
   'List': r'''
       class List<E> extends Iterable<E> {
@@ -113,6 +109,14 @@
 import 'dart:_interceptors';
 import 'dart:_isolate_helper';
 import 'dart:async';
+
+@patch
+class LinkedHashMap<K, V> {
+  factory LinkedHashMap._empty() => null;
+  factory LinkedHashMap._literal(elements) => null;
+  static _makeEmpty() => null;
+  static _makeLiteral(elements) => null;
+}
 ''';
 
 const Map<String, String> DEFAULT_JS_HELPER_LIBRARY = const <String, String>{
diff --git a/tests/compiler/dart2js/octagon_test.dart b/tests/compiler/dart2js/octagon_test.dart
index 2644c0e..59ea0c0 100644
--- a/tests/compiler/dart2js/octagon_test.dart
+++ b/tests/compiler/dart2js/octagon_test.dart
@@ -233,17 +233,35 @@
 }
 
 lower_bounds_check() {
+  setup();
   SignedVariable w = octagon.makeVariable(0, 1000);
   pushConstraint(w, w, -1);
   Expect.isTrue(octagon.isUnsolvable, 'Value in range 0..1000 is not <= -1');
 }
 
 upper_bounds_check() {
+  setup();
   SignedVariable w = octagon.makeVariable(0, 1000);
   pushConstraint(w.negated, w.negated, -5000);
   Expect.isTrue(octagon.isUnsolvable, 'Value in range 0..1000 is not >= 5000');
 }
 
+diamond_graph() {
+  setup();
+  pushConstraint(v1, v2.negated, 10);
+  pushConstraint(v1, v3.negated, 1);
+  pushConstraint(v2, v3.negated, 1);
+  pushConstraint(v2, v4.negated, 2);
+  pushConstraint(v3, v2.negated, 0);
+  pushConstraint(v3, v4.negated, 100);
+  Expect.isTrue(octagon.isSolvable, 'v1 <= v4 + 3');
+  var c = pushConstraint(v4, v1.negated, -4);
+  Expect.isTrue(octagon.isUnsolvable, 'v4 <= v1 - 4 should be a contradiction');
+  popConstraint(c);
+  pushConstraint(v1.negated, v4, -4); // Check converse constraint.
+  Expect.isTrue(octagon.isUnsolvable, 'v4 <= v1 - 4 should be a contradiction');
+}
+
 void main() {
   negative_loop1();
   negative_loop2();
@@ -261,4 +279,5 @@
   contradict2();
   lower_bounds_check();
   upper_bounds_check();
+  diamond_graph();
 }
diff --git a/tests/compiler/dart2js/simple_inferrer_test.dart b/tests/compiler/dart2js/simple_inferrer_test.dart
index f23b1f1..d552ccd 100644
--- a/tests/compiler/dart2js/simple_inferrer_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_test.dart
@@ -778,7 +778,7 @@
     checkReturn('testIsCheck17', intType);
     checkReturn('testIsCheck18', typesTask.dynamicType);
     checkReturn('testIsCheck19', typesTask.dynamicType);
-    checkReturn('testIsCheck20', typesTask.dynamicType.nonNullable());
+    checkReturn('testIsCheck20', interceptorType);
     checkReturn('testIsCheck21', typesTask.dynamicType);
     checkReturn('testIsCheck22', typesTask.dynamicType);
     checkReturn('testIsCheck23', intType);
diff --git a/tests/compiler/dart2js/size_test.dart b/tests/compiler/dart2js/size_test.dart
index c7604f7..48bf71b 100644
--- a/tests/compiler/dart2js/size_test.dart
+++ b/tests/compiler/dart2js/size_test.dart
@@ -9,9 +9,9 @@
 const String TEST = "main() => [];";
 
 const Map<String, String> DEFAULT_CORELIB_WITH_LIST = const <String, String>{
-  'Object': 'class Object { Object(); }',
+  'Object': 'class Object { const Object(); }',
   'bool': 'class bool {}',
-  'List': 'abstract class List {}',
+  'List': 'abstract class List<E> {}',
   'num': 'class num {}',
   'int': 'class int {}',
   'double': 'class double {}',
diff --git a/tests/compiler/dart2js_extra/consistent_codeUnitAt_error_test.dart b/tests/compiler/dart2js_extra/consistent_codeUnitAt_error_test.dart
new file mode 100644
index 0000000..8d3929f
--- /dev/null
+++ b/tests/compiler/dart2js_extra/consistent_codeUnitAt_error_test.dart
@@ -0,0 +1,132 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Test that optimized codeUnitAt and slow path codeUnitAt produce the same
+// error.
+
+@NoInline()
+@AssumeDynamic()
+confuse(x) => x;
+
+void check2(String name, name1, f1, name2, f2) {
+  Error trap(part, f) {
+    try {
+      f();
+    } catch (e) {
+      return e;
+    }
+    Expect.fail('should throw: $name.$part');
+  }
+  var e1 = trap(name1, f1);
+  var e2 = trap(name2, f2);
+  var s1 = '$e1';
+  var s2 = '$e2';
+  Expect.equals(s1, s2, '\n  $name.$name1: "$s1"\n  $name.$name2: "$s2"\n');
+}
+
+void check(String name, f1, f2, [f3, f4]) {
+  check2(name, 'f1', f1, 'f2', f2);
+  if (f3 != null) check2(name, 'f1', f1, 'f3', f3);
+  if (f4 != null) check2(name, 'f1', f1, 'f4', f4);
+}
+
+
+class TooHigh {
+  static f1() {
+    return confuse('AB').codeUnitAt(3);  // dynamic receiver.
+  }
+
+  static f2() {
+    var a = confuse(true) ? 'AB' : 'ABCDE';  // String with unknown length.
+    var i = confuse(3);
+    return a.codeUnitAt(i);
+  }
+
+  static f3() {
+    var a = confuse(true) ? 'AB' : 'ABCDE';  // String with unknown length.
+    return a.codeUnitAt(3);
+  }
+
+  static test() {
+    check('TooHigh', f1, f2, f3);
+  }
+}
+
+class Negative {
+  static f1() {
+    return confuse('AB').codeUnitAt(-3);  // dynamic receiver.
+  }
+
+  static f2() {
+    var a = confuse(true) ? 'AB' : 'ABCDE';  // String with unknown length.
+    var i = confuse(-3);
+    return a.codeUnitAt(i);
+  }
+
+  static f3() {
+    var a = confuse(true) ? 'AB' : 'ABCDE';  // String with unknown length.
+    var i = confuse(true) ? -3 : 0;
+    return a.codeUnitAt(i);
+  }
+
+  static f4() {
+    var a = confuse(true) ? 'AB' : 'ABCDE';  // String with unknown length.
+    return a.codeUnitAt(-3);
+  }
+
+  static test() {
+    check('Negative', f1, f2, f3, f4);
+  }
+}
+
+class Empty {
+  static f1() {
+    return confuse('').codeUnitAt(0);  // dynamic receiver.
+  }
+
+  static f2() {
+    var a = confuse(true) ? '' : 'ABCDE';  // Empty String with unknown length.
+    var i = confuse(true) ? 0 : 1;
+    return a.codeUnitAt(i);
+  }
+
+  static f3() {
+    var a = confuse(true) ? '' : 'ABCDE';  // Empty String with unknown length.
+    return a.codeUnitAt(0);
+  }
+
+  static test() {
+    check('Empty', f1, f2, f3);
+  }
+}
+
+class BadType {
+  static f1() {
+    return confuse('AB').codeUnitAt('a');  // dynamic receiver.
+  }
+
+  static f2() {
+    var a = confuse(true) ? 'AB' : 'ABCDE';  // String with unknown length.
+    var i = confuse('a');
+    return a.codeUnitAt(i);
+  }
+
+  static f3() {
+    var a = confuse(true) ? 'AB' : 'ABCDE';  // String with unknown length.
+    return a.codeUnitAt('a');
+  }
+
+  static test() {
+    check('BadType', f1, f2, f3);
+  }
+}
+
+main() {
+  TooHigh.test();
+  Negative.test();
+  Empty.test();
+  BadType.test();
+}
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index cd1f42d..9a04a94 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -10,7 +10,6 @@
 no_such_method_test: Fail # Wrong Invocation.memberName.
 constant_javascript_semantics4_test: Fail, OK
 mirrors_used_closure_test: Fail # Issue 17939
-interop_anonymous_unreachable_test: Crash # Issue 24974
 
 [ $compiler == dart2js && $runtime == jsshell ]
 mirror_printer_test: Pass, Slow # Issue 16473
diff --git a/tests/compiler/dart2js_extra/interop_anonymous_unreachable_test.dart b/tests/compiler/dart2js_extra/interop_anonymous_unreachable_test.dart
deleted file mode 100644
index b734491..0000000
--- a/tests/compiler/dart2js_extra/interop_anonymous_unreachable_test.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2015, Google Inc. 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:js/js.dart';
-
-@JS()
-@anonymous
-class A {
-  external bool get value;
-  external factory A({bool value});
-}
-
-void main() {}
diff --git a/tests/compiler/dart2js_native/dart2js_native.status b/tests/compiler/dart2js_native/dart2js_native.status
index 2066a92..e83f9d9 100644
--- a/tests/compiler/dart2js_native/dart2js_native.status
+++ b/tests/compiler/dart2js_native/dart2js_native.status
@@ -23,7 +23,6 @@
 [ $compiler == dart2js && $cps_ir ]
 native_exception_test: RuntimeError # Issue 24421
 native_method_inlining_test: RuntimeError # Please triage this failure.
-native_no_such_method_exception3_frog_test: RuntimeError # Please triage this failure.
 optimization_hints_test: RuntimeError # Please triage this failure.
 subclassing_constructor_1_test: RuntimeError # Please triage this failure.
 subclassing_constructor_2_test: RuntimeError # Please triage this failure.
diff --git a/tests/corelib/errors_test.dart b/tests/corelib/errors_test.dart
index edfa761..c980d44 100644
--- a/tests/corelib/errors_test.dart
+++ b/tests/corelib/errors_test.dart
@@ -25,9 +25,9 @@
                 new ArgumentError.value(42, "foo", "message").toString());
   Expect.equals("Invalid argument: message: 42",
                 new ArgumentError.value(42, null, "message").toString());
-  Expect.equals("Invalid argument: Must not be null: null",
+  Expect.equals("Invalid argument(s): Must not be null",
                 new ArgumentError.notNull().toString());
-  Expect.equals("Invalid argument (foo): Must not be null: null",
+  Expect.equals("Invalid argument(s) (foo): Must not be null",
                 new ArgumentError.notNull("foo").toString());
 
   Expect.equals("RangeError",
diff --git a/tests/corelib/stacktrace_current_test.dart b/tests/corelib/stacktrace_current_test.dart
new file mode 100644
index 0000000..f68ba32
--- /dev/null
+++ b/tests/corelib/stacktrace_current_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:convert" show LineSplitter;
+
+import "package:expect/expect.dart";
+
+void main() {
+  var st0;
+  var st1;
+  // Primitive way to get stack trace,.
+  try { throw 0; } catch (_, s) { st0 = s; }
+  st1 = StackTrace.current;
+
+  var st0s = findMain(st0);
+  var st1s = findMain(st1);
+  // Stack traces are not equal (contains at least a different line number,
+  // and possible different frame numbers).
+  // They are *similar*, so check that they agree on everything but numbers.
+  var digits = new RegExp(r"\d+");
+  Expect.equals(st0s.replaceAll(digits, "0"), st1s.replaceAll(digits, "0"));
+}
+
+String findMain(StackTrace stack) {
+  var string = "$stack";
+  var lines = LineSplitter.split(string).toList();
+  while (lines.isNotEmpty && !lines.first.contains("main")) {
+    lines.removeAt(0);
+  }
+  return lines.join("\n");
+}
diff --git a/tests/html/html.status b/tests/html/html.status
index 60180f9..b5f2cf3 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -9,8 +9,8 @@
 [ $compiler == none && ($runtime == dartium || $runtime == drt) ]
 
 js_array_test: Skip # Dartium JSInterop failure
-js_typed_interop_test: Skip # Dartium JSInterop failure
-mirrors_js_typed_interop_test: Skip # Dartium JSInterop failure
+mirrors_js_typed_interop_test: Fail # Missing expected failure (Issue 25044)
+js_typed_interop_side_cast_exp_test: Fail, OK # tests dart2js-specific behavior.
 
 cross_domain_iframe_test: RuntimeError # Dartium JSInterop failure
 indexeddb_2_test: Fail # Dartium JSInterop failure. Identity preservation on array deferred copy.
@@ -19,7 +19,6 @@
 native_gc_test: Skip # Dartium JSInterop failure
 transferables_test: RuntimeError # Dartium JSInterop failure
 
-
 [ $compiler == none && ($runtime == drt || $runtime == dartium ) ]
 worker_api_test: Fail # Issue 10223
 resource_http_test: Fail # Issue 24203
diff --git a/tests/html/js_dart_to_string_test.dart b/tests/html/js_dart_to_string_test.dart
index 5293053..d2c23f4 100644
--- a/tests/html/js_dart_to_string_test.dart
+++ b/tests/html/js_dart_to_string_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @JS()
-library js_typed_interop_test;
+library js_dart_to_string_test;
 
 import 'dart:html';
 
diff --git a/tests/html/js_typed_interop_anonymous2_exp_test.dart b/tests/html/js_typed_interop_anonymous2_exp_test.dart
new file mode 100644
index 0000000..baebd03
--- /dev/null
+++ b/tests/html/js_typed_interop_anonymous2_exp_test.dart
@@ -0,0 +1,52 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// SharedOptions=--experimental-trust-js-interop-type-annotations
+
+// Same test as js_typed_interop_anonymous2, but using the
+// --experimental-trust-js-interop-type-annotations flag.
+library js_typed_interop_anonymous2_exp_test;
+
+import 'dart:html';
+import 'dart:js' as js;
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+@JS() @anonymous
+class A {
+  external factory A({B b});
+
+  external B get b;
+}
+
+@JS() @anonymous
+class B {
+  external factory B({C c});
+
+  external C get c;
+}
+
+@JS() @anonymous
+class C {
+  external factory C();
+}
+
+// D is unreachable, and that is OK
+@JS() @anonymous
+class D {
+  external factory D();
+}
+
+main() {
+  useHtmlConfiguration();
+
+  test('simple', () {
+    var b = new B();
+    var a = new A(b: b);
+    expect(a.b, equals(b));
+    expect(b.c, isNull);
+  });
+}
diff --git a/tests/html/js_typed_interop_anonymous2_test.dart b/tests/html/js_typed_interop_anonymous2_test.dart
new file mode 100644
index 0000000..ed0e732
--- /dev/null
+++ b/tests/html/js_typed_interop_anonymous2_test.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library js_typed_interop_anonymous2_test;
+
+import 'dart:html';
+import 'dart:js' as js;
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+@JS() @anonymous
+class A {
+  external factory A({B b});
+
+  external B get b;
+}
+
+@JS() @anonymous
+class B {
+  external factory B({C c});
+
+  external C get c;
+}
+
+@JS() @anonymous
+class C {
+  external factory C();
+}
+
+// D is unreachable, and that is OK
+@JS() @anonymous
+class D {
+  external factory D();
+}
+
+main() {
+  useHtmlConfiguration();
+
+  test('simple', () {
+    var b = new B();
+    var a = new A(b: b);
+    expect(a.b, equals(b));
+    expect(b.c, isNull);
+  });
+}
diff --git a/tests/html/js_typed_interop_anonymous_exp_test.dart b/tests/html/js_typed_interop_anonymous_exp_test.dart
new file mode 100644
index 0000000..40a04aa
--- /dev/null
+++ b/tests/html/js_typed_interop_anonymous_exp_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// SharedOptions=--experimental-trust-js-interop-type-annotations
+
+// Same test as js_typed_interop_anonymous, but using the
+// --experimental-trust-js-interop-type-annotations flag.
+library js_typed_interop_anonymous_exp_test;
+
+import 'dart:html';
+import 'dart:js' as js;
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+@JS() @anonymous
+class Literal {
+  external factory Literal({int x, String y, num z});
+
+  external int get x;
+  external String get y;
+  external num get z;
+}
+
+main() {
+  useHtmlConfiguration();
+
+  test('simple', () {
+    var l = new Literal(x: 3, y: "foo");
+    expect(l.x, equals(3));
+    expect(l.y, equals("foo"));
+    expect(l.z, isNull);
+  });
+}
diff --git a/tests/html/js_typed_interop_anonymous_test.dart b/tests/html/js_typed_interop_anonymous_test.dart
new file mode 100644
index 0000000..b2d1593
--- /dev/null
+++ b/tests/html/js_typed_interop_anonymous_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library js_typed_interop_anonymous_test;
+
+import 'dart:html';
+import 'dart:js' as js;
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+@JS() @anonymous
+class Literal {
+  external factory Literal({int x, String y, num z});
+
+  external int get x;
+  external String get y;
+  external num get z;
+}
+
+main() {
+  useHtmlConfiguration();
+
+  test('simple', () {
+    var l = new Literal(x: 3, y: "foo");
+    expect(l.x, equals(3));
+    expect(l.y, equals("foo"));
+    expect(l.z, isNull);
+  });
+}
diff --git a/tests/html/js_typed_interop_anonymous_unreachable_exp_test.dart b/tests/html/js_typed_interop_anonymous_unreachable_exp_test.dart
new file mode 100644
index 0000000..a4e2c96
--- /dev/null
+++ b/tests/html/js_typed_interop_anonymous_unreachable_exp_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// SharedOptions=--experimental-trust-js-interop-type-annotations
+
+// Same test as js_typed_interop_anonymous_unreachable, but using the
+// --experimental-trust-js-interop-type-annotations flag.
+library js_typed_interop_anonymous_unreachable_exp_test;
+
+import 'dart:html';
+import 'dart:js' as js;
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+@JS() @anonymous
+class Literal {
+  external factory Literal({int x, String y, num z});
+
+  external int get x;
+  external String get y;
+  external num get z;
+}
+
+main() {
+  useHtmlConfiguration();
+  test('nothing to do', () {
+    // This test is empty, but it is a regression for Issue# 24974: dartjs
+    // would crash trying to compile code that used @anonymous and that was
+    // not reachable from main.
+  });
+}
diff --git a/tests/html/js_typed_interop_anonymous_unreachable_test.dart b/tests/html/js_typed_interop_anonymous_unreachable_test.dart
new file mode 100644
index 0000000..ba8758e
--- /dev/null
+++ b/tests/html/js_typed_interop_anonymous_unreachable_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library js_typed_interop_anonymous_unreachable_test;
+
+import 'dart:html';
+import 'dart:js' as js;
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+@JS() @anonymous
+class Literal {
+  external factory Literal({int x, String y, num z});
+
+  external int get x;
+  external String get y;
+  external num get z;
+}
+
+main() {
+  useHtmlConfiguration();
+  test('nothing to do', () {
+    // This test is empty, but it is a regression for Issue# 24974: dartjs
+    // would crash trying to compile code that used @anonymous and that was
+    // not reachable from main.
+  });
+}
diff --git a/tests/html/js_typed_interop_side_cast_exp_test.dart b/tests/html/js_typed_interop_side_cast_exp_test.dart
new file mode 100644
index 0000000..6fd929a
--- /dev/null
+++ b/tests/html/js_typed_interop_side_cast_exp_test.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// SharedOptions=--experimental-trust-js-interop-type-annotations
+
+// Similar test to js_typed_interop_side_cast, but because we are using the
+// --experimental-trust-js-interop-type-annotations flag, we test a slighly
+// different behavior.
+library js_typed_interop_side_cast_exp_test;
+
+import 'dart:html';
+import 'dart:js' as js;
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+@JS() @anonymous
+class A {
+  external int get x;
+  external factory A({int x});
+}
+
+@JS() @anonymous
+class B {
+  external int get x;
+  external factory B({int x});
+}
+
+@JS() @anonymous
+class C {
+  external int get x;
+  external factory C({int x});
+}
+
+main() {
+  useHtmlConfiguration();
+
+  test('side-casts work for reachable types', () {
+    new C(x: 3); // make C reachable
+    var a = new A(x: 3);
+    expect(a is C, isTrue);
+    C c = a;
+    expect(c.x, equals(3));
+  });
+
+  // Note: this test would fail without the experimental flag.
+  test('side-casts do not work for unreachable types', () {
+    var a = new A(x: 3);
+    expect(a is B, isFalse);
+  });
+}
diff --git a/tests/html/js_typed_interop_side_cast_test.dart b/tests/html/js_typed_interop_side_cast_test.dart
new file mode 100644
index 0000000..d50e1ac
--- /dev/null
+++ b/tests/html/js_typed_interop_side_cast_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library js_typed_interop_anonymous2_test;
+
+import 'dart:html';
+import 'dart:js' as js;
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+@JS() @anonymous
+class A {
+  external int get x;
+  external factory A({int x});
+}
+
+@JS() @anonymous
+class C {
+  external int get x;
+  external factory C({int x});
+}
+
+@JS() @anonymous
+class B {
+  external int get x;
+  external factory B({int x});
+}
+
+main() {
+  useHtmlConfiguration();
+
+  test('side-casts work for reachable types', () {
+    new C(x: 3); // make C reachable
+    var a = new A(x: 3);
+    expect(a is C, isTrue);
+    C c = a;
+    expect(c.x, equals(3));
+  });
+
+  test('side-casts work for otherwise unreachable types', () {
+    var a = new A(x: 3);
+    expect(a is B, isTrue);
+  });
+}
diff --git a/tests/isolate/isolate_import_test.dart b/tests/isolate/isolate_import_test.dart
index 5fa0f32..8d9f6a1 100644
--- a/tests/isolate/isolate_import_test.dart
+++ b/tests/isolate/isolate_import_test.dart
@@ -7,10 +7,11 @@
 /*  /// 01: runtime error, static type warning
 import 'dart:isolate';
 */  /// 01: continued
+import 'package:async_helper/async_helper.dart';
 
 void entry(msg) {}
 
 main() {
-  Isolate.spawn(entry, null);
+  asyncStart();
+  Isolate.spawn(entry, null).whenComplete(asyncEnd);
 }
-
diff --git a/tests/isolate/issue_21398_parent_isolate1_test.dart b/tests/isolate/issue_21398_parent_isolate1_test.dart
index 1c3aeb8..6f036bd 100644
--- a/tests/isolate/issue_21398_parent_isolate1_test.dart
+++ b/tests/isolate/issue_21398_parent_isolate1_test.dart
@@ -10,6 +10,7 @@
 import 'dart:isolate';
 import 'dart:async';
 import "package:expect/expect.dart";
+import 'package:async_helper/async_helper.dart';
 
 class FromMainIsolate {
   String toString() => 'from main isolate';
@@ -25,6 +26,7 @@
       Expect.isTrue(msg is FromMainIsolate);
       Expect.equals(10, msg.fld);
       receivePort.close();
+      sendPort.send("done");
     },
     onError: (e) => print('$e')
   );
@@ -57,37 +59,44 @@
   // create a receivePort and send it's sendPort back and then it will just
   // sit there listening for a message from the second isolate spawned
   // using spawnFunction.
-  Isolate.spawn(func1Child, [receive1.sendPort]).then(
+  asyncStart();
+  return Isolate.spawn(func1Child, [receive1.sendPort]).then(
     (isolate) {
       receive1.listen(
         (msg) {
-          Expect.isTrue(msg is SendPort);
-          spawnFunctionIsolate1SendPort = msg;
-          receive1.close();
+          if (msg is SendPort) {
+            spawnFunctionIsolate1SendPort = msg;
 
-          // Now spawn the second isolate using spawnFunction, this isolate
-          // will create a receivePort and send it's sendPort back and then
-          // wait for the third isolate spawned using spawnUri to send it
-          // a sendPort to which it will try and send a non "literal-like"
-          // object.
-          Isolate.spawn(func2Child, [receive2.sendPort]).then(
-            (isolate) {
-              receive2.listen(
-                (msg) {
-                  spawnFunctionIsolate2SendPort = msg;
-                  receive2.close();
+            // Now spawn the second isolate using spawnFunction, this isolate
+            // will create a receivePort and send it's sendPort back and then
+            // wait for the third isolate spawned using spawnUri to send it
+            // a sendPort to which it will try and send a non "literal-like"
+            // object.
+            Isolate.spawn(func2Child, [receive2.sendPort]).then(
+              (isolate) {
+                receive2.listen(
+                  (msg) {
+                    spawnFunctionIsolate2SendPort = msg;
+                    receive2.close();
 
-                  // Now spawn an isolate using spawnUri and send these send
-                  // ports over to it. This isolate will send one of the
-                  // sendports over to the other.
-                  Isolate.spawnUri(Uri.parse('issue_21398_child_isolate1.dart'),
-                                   [spawnFunctionIsolate1SendPort,
-                                    spawnFunctionIsolate2SendPort], "no-msg");
-                },
-                onError: (e) => print('$e')
-              );
-            }
-          );
+                    // Now spawn an isolate using spawnUri and send these send
+                    // ports over to it. This isolate will send one of the
+                    // sendports over to the other.
+                    Isolate
+                        .spawnUri(Uri.parse('issue_21398_child_isolate1.dart'),
+                                     [spawnFunctionIsolate1SendPort,
+                                       spawnFunctionIsolate2SendPort], "no-msg");
+                  },
+                  onError: (e) => print('$e')
+                );
+              }
+            );
+        } else  if (msg == "done") {
+            receive1.close();
+            asyncEnd();
+          } else {
+            Expect.fail("Invalid message received: $msg");
+          }
         },
         onError: (e) => print('$e')
       );
@@ -105,6 +114,7 @@
       Expect.isTrue(msg is String);
       Expect.equals("Invalid Argument(s).", msg);
       receivePort.close();
+      sendPort.send("done");
     },
     onError: (e) => print('$e')
   );
@@ -122,13 +132,13 @@
   // create a receivePort and send it's sendPort back and then it will just
   // sit there listening for a message from the second isolate spawned
   // using spawnFunction.
+  asyncStart();
   Isolate.spawn(uriChild, [receive1.sendPort]).then(
     (isolate) {
       receive1.listen(
         (msg) {
-          Expect.isTrue(msg is SendPort);
-          spawnFunctionIsolateSendPort = msg;
-          receive1.close();
+          if (msg is SendPort) {
+            spawnFunctionIsolateSendPort = msg;
 
           // Now spawn the second isolate using spawnUri, this isolate
           // will create a receivePort and send it's sendPort back and then
@@ -149,12 +159,18 @@
                   // sendports over to the other.
                   Isolate.spawnUri(Uri.parse('issue_21398_child_isolate1.dart'),
                                    [spawnFunctionIsolateSendPort,
-                                    spawnUriIsolateSendPort], "no-msg");
+                                     spawnUriIsolateSendPort], "no-msg");
                 },
                 onError: (e) => print('$e')
               );
             }
           );
+          } else if (msg == "done") {
+            receive1.close();
+            asyncEnd();
+          } else {
+            Expect.fail("Invalid message received: $msg");
+          }
         },
         onError: (e) => print('$e')
       );
diff --git a/tests/isolate/issue_21398_parent_isolate2_test.dart b/tests/isolate/issue_21398_parent_isolate2_test.dart
index 92754fd..da94b56 100644
--- a/tests/isolate/issue_21398_parent_isolate2_test.dart
+++ b/tests/isolate/issue_21398_parent_isolate2_test.dart
@@ -9,6 +9,7 @@
 import 'dart:isolate';
 import 'dart:async';
 import "package:expect/expect.dart";
+import 'package:async_helper/async_helper.dart';
 
 import "deferred_loaded_lib.dart" deferred as lib;
 
@@ -27,6 +28,7 @@
 
 void helperFunction() {
   var receivePort = new ReceivePort();
+  asyncStart();
 
   // Spawn an isolate using spawnFunction.
   Isolate.spawn(funcChild, [receivePort.sendPort]).then(
@@ -36,12 +38,14 @@
           // We don't expect to receive any valid messages.
           Expect.fail("We don't expect to receive any valid messages");
           receivePort.close();
+          asyncEnd();
         },
         onError: (e) {
           // We don't expect to receive any error messages, per spec listen
           // does not receive an error object.
           Expect.fail("We don't expect to receive any error messages");
           receivePort.close();
+          asyncEnd();
         }
       );
     }
diff --git a/tests/isolate/issue_21398_parent_isolate_test.dart b/tests/isolate/issue_21398_parent_isolate_test.dart
index fb4b0fb..76e7e0d 100644
--- a/tests/isolate/issue_21398_parent_isolate_test.dart
+++ b/tests/isolate/issue_21398_parent_isolate_test.dart
@@ -9,6 +9,7 @@
 import 'dart:isolate';
 import 'dart:async';
 import "package:expect/expect.dart";
+import 'package:async_helper/async_helper.dart';
 
 class FromMainIsolate {
   String toString() => 'from main isolate';
@@ -29,13 +30,16 @@
 
   // First spawn an isolate using spawnURI and have it
   // send back a "non-literal" like object.
+  asyncStart();
   Isolate.spawnUri(Uri.parse('issue_21398_child_isolate.dart'),
                    [],
                    [new FromMainIsolate(), receive1.sendPort]).catchError(
     (error) {
       Expect.isTrue(error is ArgumentError);
+      asyncEnd();
     }
   );
+  asyncStart();
   Isolate.spawnUri(Uri.parse('issue_21398_child_isolate.dart'),
                    [],
                    receive1.sendPort).then(
@@ -44,6 +48,7 @@
         (msg) {
           Expect.stringEquals(msg, "Invalid Argument(s).");
           receive1.close();
+          asyncEnd();
         },
         onError: (e) => print('$e')
       );
@@ -53,7 +58,8 @@
   // Now spawn an isolate using spawnFunction and send it a "non-literal"
   // like object and also have the child isolate send back a "non-literal"
   // like object.
-  Isolate.spawn(funcChild, 
+  asyncStart();
+  Isolate.spawn(funcChild,
                 [new FromMainIsolate(), receive2.sendPort]).then(
     (isolate) {
       receive2.listen(
@@ -61,6 +67,7 @@
           Expect.isTrue(msg is FromMainIsolate);
           Expect.equals(10, msg.fld);
           receive2.close();
+          asyncEnd();
         },
         onError: (e) => print('$e')
       );
diff --git a/tests/isolate/message_enum_test.dart b/tests/isolate/message_enum_test.dart
index 7dbaec3..b06dfc3 100644
--- a/tests/isolate/message_enum_test.dart
+++ b/tests/isolate/message_enum_test.dart
@@ -5,6 +5,7 @@
 // SharedOptions=--enable-enum
 
 import 'package:expect/expect.dart';
+import 'package:async_helper/async_helper.dart';
 import "dart:isolate";
 
 enum Foo { BAR, BAZ }
@@ -18,7 +19,8 @@
     Expect.equals(42, map[key]);
     p.close();
   });
-  Isolate.spawn(sendIt, p.sendPort);
+  asyncStart();
+  Isolate.spawn(sendIt, p.sendPort).whenComplete(asyncEnd);
 }
 
 void sendIt(port) {
diff --git a/tests/language/abstract_beats_arguments_test.dart b/tests/language/abstract_beats_arguments_test.dart
new file mode 100644
index 0000000..9fa33e2
--- /dev/null
+++ b/tests/language/abstract_beats_arguments_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// When an instantiation of an abstract class has the wrong arguments, an
+// AbstractClassInstantiationError is thrown, not a NoSuchMethodError.
+
+abstract class A {
+  A() { }
+}
+
+class B {
+  B() { }
+}
+
+bool isAbstractClassInstantiationError(e) =>
+    e is AbstractClassInstantiationError;
+
+bool isNoSuchMethodError(e) => e is NoSuchMethodError;
+
+void main() {
+  Expect.throws(() => new A(), isAbstractClassInstantiationError);
+
+  Expect.throws(() => new B(1), isNoSuchMethodError);
+  Expect.throws(() => new A(1), isAbstractClassInstantiationError);
+}
diff --git a/tests/language/issue23244_test.dart b/tests/language/issue23244_test.dart
index b155769..f8a3f32 100644
--- a/tests/language/issue23244_test.dart
+++ b/tests/language/issue23244_test.dart
@@ -5,6 +5,7 @@
 // Regression test case for http://dartbug.com/23244
 import 'dart:async';
 import 'dart:isolate';
+import 'package:async_helper/async_helper.dart';
 
 enum Fisk {
   torsk,
@@ -27,6 +28,7 @@
 
 main() async {
   var port = new ReceivePort();
+  asyncStart();
   await Isolate.spawn(isolate1, port.sendPort);
   Completer completer1 = new Completer();
   port.listen((message) {
@@ -53,6 +55,7 @@
     port.close();
     expectTorsk(message[0]);
     expectTorsk(message[1]);
+    asyncEnd();
   });
 }
 
@@ -61,4 +64,3 @@
     throw "$fisk isn't a ${Fisk.torsk}";
   }
 }
-
diff --git a/tests/language/language.status b/tests/language/language.status
index c2d3f88..8c5eb92 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -96,8 +96,8 @@
 [ $compiler == none && $runtime == vm && ( $arch == simarm || $arch == arm || $arch == simarmv5te || $arch == armv5te || $arch == simarm64 || $arch == arm64 || $arch == simmips || $arch == mips) ]
 vm/load_to_load_unaligned_forwarding_vm_test: Pass, Crash # Unaligned offset. Issue 22151
 
-[ $compiler == none && ( $runtime == dartium || $runtime == drt ) ]
-issue23244_test: Fail # Can't run spawnFunction on dartium.
+[ $compiler == none && $runtime == dartium ]
+issue23244_test: Fail # Issue 23244
 
 [ $compiler == none && ($runtime == vm || $runtime == drt || $runtime == dartium) && $arch == ia32 ]
 vm/regress_24517_test: Pass, Fail # Issue 24517.
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index a51dda3..27be7e0 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -187,6 +187,7 @@
 empty_block_case_test: StaticWarning # Test Issue 18701
 error_stacktrace_test: StaticWarning # Test Issue 18702
 
+abstract_beats_arguments_test: StaticWarning
 const_counter_negative_test: CompileTimeError
 const_optional_args_negative_test: CompileTimeError
 constructor_redirect1_negative_test: CompileTimeError
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 13c5598..1767b22 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -224,7 +224,7 @@
 generic_field_mixin5_test: Crash # Issue 18651
 many_method_calls_test: Crash # Stack overflow in HGraphVisitor.visitPostDominatorTree.visitBasicBlockAndSuccessors
 
-[ $compiler == dart2js && ($runtime == d8 || $runtime == jsshell) ]
+[ $compiler == dart2js ]
 issue23244_test: RuntimeError # 23244
 
 [ $compiler == dart2js && $cps_ir ]
@@ -273,6 +273,7 @@
 await_for_cancel_test: Crash # (await for(var x in controller.stream){for(int j=0;j<10;j++ ){if(j==5)continue outer;}}): await for
 await_for_test: Crash # (await for(var x in infiniteStream()){i++ ;if(i>10)break;t4.record(x);}): await for
 await_for_use_local_test: Crash # (await for(var v in s){accum+= v;}): await for
+call_closurization_test: RuntimeError # Bad type inference for ".call" tear-off.
 cha_deopt1_test: Crash # (d.make_u()): deferred access is not implemented
 cha_deopt2_test: Crash # (d.make_u()): deferred access is not implemented
 cha_deopt3_test: Crash # (d.make_u()): deferred access is not implemented
@@ -333,16 +334,12 @@
 infinite_switch_label_test: Crash # (switch (target){l0:...  continue to a labeled switch case
 instanceof2_test: RuntimeError # Please triage this failure.
 instanceof4_test/01: RuntimeError # Please triage this failure.
-invocation_mirror_invoke_on_test: RuntimeError # Please triage this failure.
 invocation_mirror_test: Crash # (super[37]=42): visitUnresolvedSuperIndexSet
 issue_1751477_test: RuntimeError # O.loadLibrary is not a function
 list_is_test: RuntimeError # Please triage this failure.
 list_test: RuntimeError # Please triage this failure.
 many_generic_instanceof_test: RuntimeError # Please triage this failure.
-many_overridden_no_such_method_test: RuntimeError # Please triage this failure.
 nested_switch_label_test: Crash # (switch (target){out...  continue to a labeled switch case
-no_such_method_test: RuntimeError # Please triage this failure.
-overridden_no_such_method_test: RuntimeError # Please triage this failure.
 regress_22443_test: RuntimeError # M.loadLibrary is not a function
 regress_23408_test: RuntimeError # G.loadLibrary is not a function
 regress_23500_test/01: Crash # (await for(var c in new Stream.fromIterable([] )){}): await for
diff --git a/tests/language/stacktrace_test.dart b/tests/language/stacktrace_test.dart
index e39f151..7ad6eee 100644
--- a/tests/language/stacktrace_test.dart
+++ b/tests/language/stacktrace_test.dart
@@ -1,4 +1,3 @@
-
 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
diff --git a/tests/language/vm/optimized_guarded_field_isolates_test.dart b/tests/language/vm/optimized_guarded_field_isolates_test.dart
index fc5e915..a150656 100644
--- a/tests/language/vm/optimized_guarded_field_isolates_test.dart
+++ b/tests/language/vm/optimized_guarded_field_isolates_test.dart
@@ -9,6 +9,7 @@
 import "dart:isolate";
 import "dart:async";
 import "package:expect/expect.dart";
+import 'package:async_helper/async_helper.dart';
 
 class A {
   A(this.a);
@@ -29,6 +30,7 @@
 
 test_field_type() {
   var receive_port = new ReceivePort();
+  asyncStart();
   Future<Isolate> isolate = Isolate.spawn(f1, receive_port.sendPort);
   B b = new B(1, 2);
   for (var i = 0; i < 200; i++) { test_b(b); }
@@ -37,6 +39,7 @@
   item.then((B value) {
       Expect.equals("foobar", test_b(value));
       receive_port.close();
+      asyncEnd();
   });
 }
 
@@ -53,6 +56,7 @@
 
 test_list_length() {
   var receive_port = new ReceivePort();
+  asyncStart();
   Future<Isolate> isolate = Isolate.spawn(f2, receive_port.sendPort);
   C c = new C(new List(10000));
   for (var i = 0; i < 200; i++) { test_c(c); }
@@ -61,6 +65,7 @@
   item.then((C value) {
       Expect.throws(() => test_c(value), (e) => e is RangeError);
       receive_port.close();
+      asyncEnd();
   });
 }
 
diff --git a/tests/language/vm/precompiled_static_initializer_test.dart b/tests/language/vm/precompiled_static_initializer_test.dart
new file mode 100644
index 0000000..195e07d
--- /dev/null
+++ b/tests/language/vm/precompiled_static_initializer_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Test optimizations with static fields with precompilation.
+// VMOptions=--inlining-hotness=0
+
+import 'package:expect/expect.dart';
+
+init() => 123;
+
+final a = init();
+
+main() {
+  var s = 0;
+  for (var i = 0; i < 10; i++) {
+    s += a;
+  }
+  Expect.equals(10 * 123, s);
+}
diff --git a/tests/language/vm/type_propagation_test.dart b/tests/language/vm/type_propagation_test.dart
new file mode 100644
index 0000000..2783654
--- /dev/null
+++ b/tests/language/vm/type_propagation_test.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--optimization-counter-threshold=1000 --max-polymorphic-checks=1
+
+// Test correct loop invariant code motion and type propagation from is-checks
+// and null-comparisons. 
+
+class B {
+  var b;
+  B(this.b);
+}
+
+class C {
+  final f0 = null;
+
+  final a;
+  C() : a = new B(0);
+}
+
+foo(x) {
+  for (var i = 0; i < 10; i++) {
+    i + i;
+    i + i;
+    if (x is C) {
+      x.a.b < 0;
+    }
+  }
+}
+
+class Y { var f = null; }
+
+bar(y) {
+  var x = y.f;
+  for (var i = 0; i < 10; i++) {
+    if (x != null) {
+      x.a.b < 0;
+    }
+  }
+}
+
+
+main () {
+  var o = new Y();
+  o.f = new C();
+  bar(o);
+  o.f = null;
+  bar(o);
+
+  for (var i = 0; i < 1000; i++) bar(o);
+
+  foo(new C());
+  foo(0);
+
+  for (var i = 0; i < 1000; i++) foo(0);
+}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 2c983c3..079fa14 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -347,8 +347,6 @@
 mirrors/deferred_mirrors_metadata_test: RuntimeError # U.loadLibrary is not a function
 mirrors/deferred_mirrors_metatarget_test: RuntimeError # X.loadLibrary is not a function
 mirrors/deferred_mirrors_update_test: RuntimeError # U.loadLibrary is not a function
-mirrors/delegate_call_through_getter_test: RuntimeError # Please triage this failure.
-mirrors/delegate_test: RuntimeError # Please triage this failure.
 mirrors/library_enumeration_deferred_loading_test: RuntimeError # L.loadLibrary is not a function
 mirrors/symbol_validation_test/none: RuntimeError # Please triage this failure.
 mirrors/typedef_deferred_library_test: RuntimeError # G.loadLibrary is not a function
diff --git a/tests/standalone/coverage_test.dart b/tests/standalone/coverage_test.dart
deleted file mode 100644
index 1ec4af4..0000000
--- a/tests/standalone/coverage_test.dart
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test forks a second vm process that runs the script tools/coverage.dart
-// and verifies that the coverage tool produces its expected output.
-// This test is mainly here to ensure that the coverage tool compiles and
-// runs.
-
-import "dart:async";
-import "dart:convert";
-import "dart:io";
-
-import "package:path/path.dart";
-
-// Coverage tool script relative to the path of this test.
-var coverageToolScript = "../../tools/coverage.dart";
-
-// Coverage target script relative to this test.
-var coverageTargetScript = "../language/hello_dart_test.dart";
-var targPath;
-
-Process coverageToolProcess;
-List sourceLines;
-int nextLineToMatch = 0;
-
-void onCoverageOutput(String line) {
-  print("COV: $line");
-  if (nextLineToMatch < sourceLines.length) {
-    if (line.endsWith("|" + sourceLines[nextLineToMatch])) {
-      nextLineToMatch++;
-    }
-  }
-}
-
-bool checkExitCode(exitCode) {
-  var pid = coverageToolProcess.pid;
-  print("Coverage tool process (pid $pid) terminated with "
-        "exit code $exitCode.");
-  return exitCode == 0;
-}
-
-void checkSuccess() {
-  if (nextLineToMatch == sourceLines.length) {
-    print("Successfully matched all lines of '$targPath'");
-  } else {
-    print("Error: could not match all source code lines of '$targPath'");
-    exit(-1);
-  }
-}
-
-void main() {
-  // Compute paths for coverage tool and coverage target relative
-  // the the path of this script.
-  var scriptPath = dirname(Platform.script.toFilePath());
-  var toolPath = normalize(join(scriptPath, coverageToolScript));
-  targPath = normalize(join(scriptPath, coverageTargetScript));
-
-  sourceLines = new File(targPath).readAsLinesSync();
-  assert(sourceLines != null);
-
-  var processOpts = [ "--compile_all", toolPath, targPath ];
-
-  Process.start(Platform.executable, processOpts).then((Process process) {
-    coverageToolProcess = process;
-    coverageToolProcess.stdin.close();
-    var stdoutStringStream = coverageToolProcess.stdout
-        .transform(UTF8.decoder)
-        .transform(new LineSplitter());
-
-    var stderrStringStream = coverageToolProcess.stderr
-        .transform(UTF8.decoder)
-        .transform(new LineSplitter());
-
-    // Wait for 3 future events: stdout and stderr streams of the coverage
-    // tool process closed, and coverage tool process terminated.
-    var futures = [];
-    var subscription = stdoutStringStream.listen(onCoverageOutput);
-    futures.add(subscription.asFuture(true));
-    subscription = stderrStringStream.listen(onCoverageOutput);
-    futures.add(subscription.asFuture(true));
-    futures.add(coverageToolProcess.exitCode.then(checkExitCode));
-    Future.wait(futures).then((results) {
-      checkSuccess();
-      if (results.contains(false)) exit(-1);
-    });
-  });
-}
diff --git a/tests/standalone/debugger/basic_debugger_test.dart b/tests/standalone/debugger/basic_debugger_test.dart
deleted file mode 100644
index 9dfded6..0000000
--- a/tests/standalone/debugger/basic_debugger_test.dart
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test forks a second vm process that runs this dart script as
-// a debug target.
-// Run this test with option --wire to see the json messages sent
-// between the processes.
-// Run this test with option --verbose to see the stdout and stderr output
-// of the debug target process.
-
-import "debug_lib.dart";
-
-bar(x) {
-  var localStr = "foo";
-  int localInt = 1;
-  double localDouble = 1.1;
-
-  print(x);
-}
-
-bam(a) => bar(a);
-
-foo(i) {
-  bar("baz");
-  print(i);
-}
-
-main(List<String> arguments) {
-  if (RunScript(testScript, arguments)) return;
-  print("Hello from debuggee");
-  foo(42);
-  bam("bam");
-  print("Hello again");
-}
-
-
-// Expected debugger events and commands.
-var testScript = [
-  MatchFrame(0, "main"),  // Top frame in trace is function "main".
-  Step(),
-  MatchFrame(0, "main"),  // Should still be in "main".
-  SetBreakpoint(19),  // Set breakpoint a line 19, in function bar.
-  Resume(),
-  MatchFrames(["bar", "foo", "main"]),
-  MatchFrame(1, "foo"),
-  MatchLocals({"localStr": '"foo"', "localInt": "1", "localDouble": "1.1", 
-      "x": '"baz"'}),
-  SetBreakpoint(22),  // Set breakpoint a line 22, in function bam.
-  Resume(),
-  MatchFrames(["bam", "main"]),
-  Resume(),
-  MatchFrames(["bar", "bam", "main"]),
-  Resume(),
-];
diff --git a/tests/standalone/debugger/break_at_equals_test.dart b/tests/standalone/debugger/break_at_equals_test.dart
deleted file mode 100644
index 5000e6d..0000000
--- a/tests/standalone/debugger/break_at_equals_test.dart
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "debug_lib.dart";
-
-class MyClass {
-  operator ==(other) {
-    print(other);
-    return true;  // Breakpoint #3.
-  }
-}
-
-main(List<String> arguments) {
-  if (RunScript(testScript, arguments)) return;
-  var a = new MyClass();
-  var b = null;
-  a == b;  // Breakpoint #1.
-  print("after 1");
-  b = 123;
-  a == b;  // Breakpoint #2.
-  print("after 2");
-  a == null;  // Breakpoint #4.
-  print("after 4");
-  if (null == a) {
-    throw "unreachable";
-  }
-  print("ok");
-}
-
-// Checks that debugger can stop at calls to == even if one
-// of the operands is null.
-
-var testScript = [
-  MatchFrames(["main"]),
-  MatchLine(14),
-  SetBreakpoint(18),
-  SetBreakpoint(21),
-  SetBreakpoint(10),
-  SetBreakpoint(23),
-  Resume(),
-  MatchFrames(["main"]),
-  MatchLine(18),  // At breakpoint #1.
-  Resume(),
-  MatchLine(21),  // At breakpoint #2; didn't hit breakpoint in MyClass.==.
-  Resume(),
-  MatchFrames(["MyClass.==", "main"]),
-  MatchLine(10),  // At breakpoint #3 in MyClass.==.
-  Resume(),
-  MatchLine(23),  // At breakpoint #4.
-  Resume()
-];
diff --git a/tests/standalone/debugger/breakpoint_resolved_test.dart b/tests/standalone/debugger/breakpoint_resolved_test.dart
deleted file mode 100644
index 14c2827..0000000
--- a/tests/standalone/debugger/breakpoint_resolved_test.dart
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "debug_lib.dart";
-
-main(List<String> arguments) {
-  if (RunScript(testScript, arguments)) return;
-
-  bar();
-
-  print("Hello from debuggee");
-}
-
-bar() {
-  // Attempt to set breakpoint in this empty line does not
-  // result in a resolved breakpoint.
-  print("bar");
-}
-
-var testScript = [
-  MatchFrame(0, "main"),
-  SetBreakpoint(10),
-  SetBreakpoint(12),
-  SetBreakpoint(16),
-  Resume(),
-  MatchFrame(0, "main"),
-  Resume(),  // Next breakpoint expected in main, when bar() returns.
-  MatchFrame(0, "main"),
-  // Only two breakpoint resolved events expected.
-  ExpectEvent("breakpointResolved", {"breakpointId": 2}),
-  ExpectEvent("breakpointResolved", {"breakpointId": 3}),
-  Resume(),
-];
diff --git a/tests/standalone/debugger/closure_bp_test.dart b/tests/standalone/debugger/closure_bp_test.dart
deleted file mode 100644
index 2eb2bfd..0000000
--- a/tests/standalone/debugger/closure_bp_test.dart
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test forks a second vm process that runs this dart script as
-// a debug target.
-// Run this test with option --wire to see the json messages sent
-// between the processes.
-// Run this test with option --verbose to see the stdout and stderr output
-// of the debug target process.
-
-import "debug_lib.dart";
-
-bar(x) {
-  print(x);
-}
-
-main(List<String> arguments) {
-  if (RunScript(testScript, arguments)) return;
-  print("Hello from debuggee");
-  [1,2].forEach(bar);  // Causes implicit closure of bar to be compiled.
-  print("stop here");  // Stop here and set breakpoint in bar.
-  [3,4].forEach(bar);  // Call bar closure and observe breakpoints being hit.
-  print("done");
-}
-
-
-// Expected debugger events and commands.
-var testScript = [
-  MatchFrame(0, "main"),  // Top frame in trace is function "main".
-  SetBreakpoint(22),      // Set breakpoint a line 22, after bar closure is compiled.
-  Resume(),
-  MatchFrame(0, "main"),  // Should be at line 22 in main.
-  MatchLine(22),
-  SetBreakpoint(15),      // Set breakpoint in function bar. Bar has not been called
-                          // through a regular function call at this point, only
-                          // through a closure from forEach().
-  Resume(),
-  MatchFrames(["bar", "forEach", "main"]),  // Should be in closure function now.
-  MatchLine(15),
-  MatchLocals({"x": "3"}),
-  Resume(),
-  MatchFrames(["bar", "forEach", "main"]),  // Should be in closure function now.
-  MatchLine(15),
-  MatchLocals({"x": "4"}),
-  Resume(),
-];
diff --git a/tests/standalone/debugger/closure_debugger_test.dart b/tests/standalone/debugger/closure_debugger_test.dart
deleted file mode 100644
index 7562a8c..0000000
--- a/tests/standalone/debugger/closure_debugger_test.dart
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test forks a second vm process that runs this dart script as
-// a debug target.
-// Run this test with option --wire to see the json messages sent
-// between the processes.
-// Run this test with option --verbose to see the stdout and stderr output
-// of the debug target process.
-
-import "debug_lib.dart";
-
-bar(x) {
-  print(x);
-}
-
-main(List<String> arguments) {
-  if (RunScript(testScript, arguments)) return;
-  print("Hello from debuggee");
-  var f = bar;
-  f("closure call");
-  bar(12);
-  var a = new A();
-  for (var i = 0; i < 2; ++i) {
-    a.foo(i);
-  }
-}
-
-class A {
-  A() {
-    foo =
-      (x) => print(x);
-  }
-  var foo;
-}
-
-// Expected debugger events and commands.
-var testScript = [
-  MatchFrame(0, "main"),  // Top frame in trace is function "main".
-  SetBreakpoint(22),      // Set breakpoint a line 22, at the closure call.
-  Resume(),
-  MatchFrame(0, "main"),  // Should be at closure call.
-  StepInto(),
-  MatchFrames(["bar", "main"]),  // Should be in closure function now.
-  StepOut(),
-  MatchFrame(0, "main"),  // Back in main, before static call to bar().
-  SetBreakpoint(15),      // Breakpoint in bar();
-  Resume(),
-  MatchFrames(["bar", "main"]),
-  SetBreakpoint(26),      // Breakpoint in main() at a.field(i).
-  SetBreakpoint(33),      // Breakpoint in closure.
-  Resume(),
-  MatchFrame(0, "main"),  // Should be in main().
-  MatchLocals({"i": "0"}),
-  StepInto(),
-  StepInto(),
-  MatchFrames(["A.<anonymous closure>", "main"]),  // In closure function.
-  Resume(),
-  MatchFrame(0, "main"),  // Back in main().
-  MatchLocals({"i": "1"}),
-  Resume(),
-  MatchFrames(["A.<anonymous closure>", "main"]),  // In closure function.
-  Resume()
-];
diff --git a/tests/standalone/debugger/debug_lib.dart b/tests/standalone/debugger/debug_lib.dart
deleted file mode 100644
index 92a0d10..0000000
--- a/tests/standalone/debugger/debug_lib.dart
+++ /dev/null
@@ -1,749 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// Library used by debugger wire protocol tests (standalone VM debugging).
-
-library DartDebugger;
-
-import "dart:async";
-import "dart:convert";
-import "dart:io";
-import "dart:math";
-
-// Whether or not to print the debugger wire messages on the console.
-var verboseWire = false;
-
-// Class to buffer wire protocol data from debug target and
-// break it down to individual json messages.
-class JsonBuffer {
-  String buffer = null;
-
-  append(String s) {
-    if (buffer == null || buffer.length == 0) {
-      buffer = s;
-    } else {
-      buffer += s;
-    }
-  }
-
-  String getNextMessage() {
-    if (buffer == null) return null;
-    int msgLen = objectLength();
-    if (msgLen == 0) return null;
-    String msg = null;
-    if (msgLen == buffer.length) {
-      msg = buffer;
-      buffer = null;
-    } else {
-      assert(msgLen < buffer.length);
-      msg = buffer.substring(0, msgLen);
-      buffer = buffer.substring(msgLen);
-    }
-    return msg;
-  }
-
-  bool haveGarbage() {
-    if (buffer == null || buffer.length == 0) return false;
-    var i = 0, char = " ";
-    while (i < buffer.length) {
-      char = buffer[i];
-      if (char != " " && char != "\n" && char != "\r" && char != "\t") break;
-      i++;
-    }
-    if (i >= buffer.length) {
-      return false;
-    } else {
-      return char != "{";
-    }
-  }
-
-  // Returns the character length of the next json message in the
-  // buffer, or 0 if there is only a partial message in the buffer.
-  // The object value must start with '{' and continues to the
-  // matching '}'. No attempt is made to otherwise validate the contents
-  // as JSON. If it is invalid, a later JSON.decode() will fail.
-  int objectLength() {
-    int skipWhitespace(int index) {
-      while (index < buffer.length) {
-        String char = buffer[index];
-        if (char != " " && char != "\n" && char != "\r" && char != "\t") break;
-        index++;
-      }
-      return index;
-    }
-    int skipString(int index) {
-      assert(buffer[index - 1] == '"');
-      while (index < buffer.length) {
-        String char = buffer[index];
-        if (char == '"') return index + 1;
-        if (char == r'\') index++;
-        if (index == buffer.length) return index;
-        index++;
-      }
-      return index;
-    }
-    int index = 0;
-    index = skipWhitespace(index);
-    // Bail out if the first non-whitespace character isn't '{'.
-    if (index == buffer.length || buffer[index] != '{') return 0;
-    int nesting = 0;
-    while (index < buffer.length) {
-      String char = buffer[index++];
-      if (char == '{') {
-        nesting++;
-      } else if (char == '}') {
-        nesting--;
-        if (nesting == 0) return index;
-      } else if (char == '"') {
-        // Strings can contain braces. Skip their content.
-        index = skipString(index);
-      }
-    }
-    return 0;
-  }
-}
-
-
-getJsonValue(Map jsonMsg, String path) {
-  List properties = path.split(new RegExp(":"));
-  assert(properties.length >= 1);
-  var node = jsonMsg;
-  for (int i = 0; i < properties.length; i++) {
-    if (node == null) return null;
-    String property = properties[i];
-    var index = null;
-    if (property.endsWith("]")) {
-      var bracketPos = property.lastIndexOf("[");
-      if (bracketPos <= 0) return null;
-      var indexStr = property.substring(bracketPos + 1, property.length - 1);
-      try {
-        index = int.parse(indexStr);
-      } on FormatException {
-        print("$indexStr is not a valid array index");
-        return null;
-      }
-      property = property.substring(0, bracketPos);
-    }
-    if (node is Map) {
-      node = node[property];
-    } else {
-      return null;
-    }
-    if (index != null) {
-      if (node is List && node.length > index) {
-        node = node[index];
-      } else {
-        return null;
-      }
-    }
-  }
-  return node;
-}
-
-
-// Returns true if [template] is a subset of [map].
-bool matchMaps(Map template, Map msg) {
-  bool isMatch = true;
-  template.forEach((k, v) {
-    if (msg.containsKey(k)) {
-      var receivedValue = msg[k];
-      if ((v is Map) && (receivedValue is Map)) {
-        if (!matchMaps(v, receivedValue)) isMatch = false;
-      } else if (v == null) {
-        // null in the template matches everything.
-      } else if (v != receivedValue) {
-        isMatch = false;
-      }
-    } else {
-      isMatch = false;
-    }
-  });
-  return isMatch;
-}
-
-
-class Command {
-  var template;
-
-  void send(Debugger debugger) {
-    debugger.sendMessage(template);
-  }
-
-  void matchResponse(Debugger debugger) {
-    Map response = debugger.currentMessage;
-    var id = template["id"];
-    assert(id != null && id >= 0);
-    if (response["id"] != id) {
-      debugger.error("Error: expected messaged id $id but got ${response["id"]}.");
-    }
-  }
-}
-
-class GetLineTableCmd extends Command {
-  GetLineTableCmd() {
-    template = {"id": 0,
-                "command": "getLineNumberTable",
-                "params": {"isolateId": 0, "libraryId": 0, "url": ""}};
-  }
-
-  void send(Debugger debugger) {
-    assert(debugger.scriptUrl != null);
-    template["params"]["url"] = debugger.scriptUrl;
-    template["params"]["libraryId"] = debugger.libraryId;
-    debugger.sendMessage(template);
-  }
-
-  void matchResponse(Debugger debugger) {
-    super.matchResponse(debugger);
-    List<List<int>> table = getJsonValue(debugger.currentMessage, "result:lines");
-    debugger.tokenToLine = {};
-    for (var line in table) {
-      // Each entry begins with a line number...
-      var lineNumber = line[0];
-      for (var pos = 1; pos < line.length; pos += 2) {
-        // ...and is followed by (token offset, col number) pairs.
-        var tokenOffset = line[pos];
-        debugger.tokenToLine[tokenOffset] = lineNumber;
-      }
-    }
-  }
-}
-
-
-class LineMatcher extends Command {
-  int expectedLineNumber;
-
-  LineMatcher(this.expectedLineNumber) {
-    template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}};
-  }
-
-  void matchResponse(Debugger debugger) {
-    assert(debugger.tokenToLine != null);
-    super.matchResponse(debugger);
-    var msg = debugger.currentMessage;
-    List frames = getJsonValue(msg, "result:callFrames");
-    assert(frames != null);
-    var tokenOffset = frames[0]["location"]["tokenOffset"];
-    assert(tokenOffset != null);
-    var lineNumber = debugger.tokenToLine[tokenOffset];
-    assert(lineNumber != null);
-    if (expectedLineNumber != lineNumber) {
-      debugger.error("Error: expected pause at line $expectedLineNumber "
-                     "but reported line is $lineNumber.");
-      return;
-    }
-    print("Matched line number $lineNumber");
-  }
-}
-
-MatchLine(lineNumber) {
-  return new LineMatcher(lineNumber);
-}
-
-
-class FrameMatcher extends Command {
-  int frameIndex;
-  List<String> functionNames;
-  bool exactMatch;
-
-  FrameMatcher(this.frameIndex, this.functionNames, this.exactMatch) {
-    template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}};
-  }
-
-  void matchResponse(Debugger debugger) {
-    super.matchResponse(debugger);
-    var msg = debugger.currentMessage;
-    List frames = getJsonValue(msg, "result:callFrames");
-    assert(frames != null);
-    if (debugger.scriptUrl == null) {
-      var name = frames[0]["functionName"];
-      if (name == "main") {
-        // Extract script url of debugged script.
-        debugger.scriptUrl = frames[0]["location"]["url"];
-        assert(debugger.scriptUrl != null);
-        debugger.libraryId = frames[0]["location"]["libraryId"];
-        assert(debugger.libraryId != null);
-      }
-    }
-    if (frames.length < functionNames.length) {
-      debugger.error("Error: stack trace not long enough "
-                     "to match ${functionNames.length} frames");
-      return;
-    }
-    for (int i = 0; i < functionNames.length; i++) {
-      var idx = i + frameIndex;
-      var name = frames[idx]["functionName"];
-      assert(name != null);
-      bool isMatch = exactMatch ? name == functionNames[i]
-                                : name.contains(functionNames[i]);
-      if (!isMatch) {
-        debugger.error("Error: call frame $idx: "
-          "expected function name '${functionNames[i]}' but found '$name'");
-        return;
-      }
-    }
-    print("Matched frames: $functionNames");
-  }
-}
-
-
-MatchFrame(int frameIndex, String functionName, {exactMatch: false}) {
-  return new FrameMatcher(frameIndex, [functionName], exactMatch);
-}
-
-MatchFrames(List<String> functionNames, {exactMatch: false}) {
-  return new FrameMatcher(0, functionNames, exactMatch);
-}
-
-
-class LocalsMatcher extends Command {
-  Map locals = {};
-
-  LocalsMatcher(this.locals) {
-    template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}};
-  }
-
-  void matchResponse(Debugger debugger) {
-    super.matchResponse(debugger);
-
-    List frames = getJsonValue(debugger.currentMessage, "result:callFrames");
-    assert(frames != null);
-
-    String functionName = frames[0]['functionName'];
-    List localsList = frames[0]['locals'];
-    Map reportedLocals = {};
-    localsList.forEach((local) => reportedLocals[local['name']] = local['value']);
-    for (String key in locals.keys) {
-      if (reportedLocals[key] == null) {
-        debugger.error("Error in $functionName(): no value reported for local "
-            "variable $key");
-        return;
-      }
-      String expected = locals[key];
-      String actual = reportedLocals[key]['text'];
-      if (expected != actual) {
-        debugger.error("Error in $functionName(): got '$actual' for local "
-            "variable $key, but expected '$expected'");
-        return;
-      }
-    }
-    print("Matched locals ${locals.keys}");
-  }
-}
-
-
-MatchLocals(Map localValues) {
-  return new LocalsMatcher(localValues);
-}
-
-
-// Used to check if local variables are visible.
-class AssertLocalsNotVisibleMatcher extends Command {
-  List<String> locals;
-  int frame_index;
-
-  AssertLocalsNotVisibleMatcher(this.locals, this.frame_index) {
-    template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}};
-  }
-
-  void matchResponse(Debugger debugger) {
-    super.matchResponse(debugger);
-
-    List frames = getJsonValue(debugger.currentMessage, "result:callFrames");
-    assert(frames != null);
-
-    String functionName = frames[frame_index]['functionName'];
-    List localsList = frames[frame_index]['locals'];
-    Map reportedLocals = {};
-    localsList.forEach((local) => reportedLocals[local['name']] = local['value']);
-    for (String key in locals) {
-      if (reportedLocals[key] != null) {
-        debugger.error("Error in $functionName(): local variable $key not "
-                       "expected in scope (reported value "
-                       "${reportedLocals[key]['text']})");
-        return;
-      }
-    }
-    print("Matched locals $locals");
-  }
-}
-
-
-AssertLocalsNotVisible(List<String> locals, [int frame_index = 0]) {
-  return new AssertLocalsNotVisibleMatcher(locals, frame_index);
-}
-
-
-class EventMatcher {
-  String eventName;
-  Map params;
-
-  EventMatcher(this.eventName, this.params);
-
-  void matchEvent(Debugger debugger) {
-    for (Event event in debugger.events) {
-      if (event.name == eventName) {
-        if (params == null || matchMaps(params, event.params)) {
-          // Remove the matched event, so we don't match against it in the future.
-          debugger.events.remove(event);
-          return;
-        }
-      }
-    }
-
-    String msg = params == null ? '' : params.toString();
-    debugger.error("Error: could not match event $eventName $msg");
-  }
-}
-
-
-ExpectEvent(String eventName, [Map params]) {
-  return new EventMatcher(eventName, params);
-}
-
-
-class RunCommand extends Command {
-  RunCommand.resume() {
-    template = {"id": 0, "command": "resume", "params": {"isolateId": 0}};
-  }
-  RunCommand.step() {
-    template = {"id": 0, "command": "stepOver", "params": {"isolateId": 0}};
-  }
-  RunCommand.stepInto() {
-    template = {"id": 0, "command": "stepInto", "params": {"isolateId": 0}};
-  }
-  RunCommand.stepOut() {
-    template = {"id": 0, "command": "stepOut", "params": {"isolateId": 0}};
-  }
-  void send(Debugger debugger) {
-    debugger.sendMessage(template);
-    debugger.isPaused = false;
-  }
-  void matchResponse(Debugger debugger) {
-    super.matchResponse(debugger);
-    print("Command: ${template['command']}");
-  }
-}
-
-
-Resume() => new RunCommand.resume();
-Step() => new RunCommand.step();
-StepInto() => new RunCommand.stepInto();
-StepOut() => new RunCommand.stepOut();
-
-class SetBreakpointCommand extends Command {
-  int line;
-  String url;
-  SetBreakpointCommand(this.line, this.url) {
-    template = {"id": 0,
-                "command": "setBreakpoint",
-                "params": { "isolateId": 0,
-                            "url": null,
-                            "line": null }};
-  }
-
-  void send(Debugger debugger) {
-    assert(debugger.scriptUrl != null);
-    if (url == null) {
-      url = debugger.scriptUrl;
-    }
-    template["params"]["url"] = url;
-    template["params"]["line"] = line;
-    debugger.sendMessage(template);
-  }
-
-  void matchResponse(Debugger debugger) {
-    super.matchResponse(debugger);
-    print("Set breakpoint at line $line in $url");
-  }
-}
-
-SetBreakpoint(int line, {String url}) => new SetBreakpointCommand(line, url);
-
-class Event {
-  String name;
-  Map params;
-
-  Event(Map json) {
-    name = json['event'];
-    params = json['params'];
-  }
-}
-
-
-// A debug script is a list of Command objects.
-class DebugScript {
-  List entries;
-  DebugScript(List scriptEntries) {
-    entries = new List.from(scriptEntries.reversed);
-    entries.add(new GetLineTableCmd());
-    entries.add(MatchFrame(0, "main"));
-  }
-  bool get isEmpty => entries.isEmpty;
-  bool get isNextEventMatcher => !isEmpty && currentEntry is EventMatcher;
-  get currentEntry => entries.last;
-  advance() => entries.removeLast();
-  add(entry) => entries.add(entry);
-}
-
-
-class Debugger {
-  // Debug target process properties.
-  Process targetProcess;
-  Socket socket;
-  JsonBuffer responses = new JsonBuffer();
-
-  DebugScript script;
-  int seqNr = 0;  // Sequence number of next debugger command message.
-  Command lastCommand = null;  // Most recent command sent to target.
-  List<String> errors = new List();
-  List<Event> events = new List();
-  bool cleanupDone = false;
-
-  // Data collected from debug target.
-  Map currentMessage = null;  // Currently handled message sent by target.
-  String scriptUrl = null;
-  int libraryId = null;
-  Map<int,int> tokenToLine = null;
-  bool shutdownEventSeen = false;
-  int isolateId = 0;
-  bool isPaused = false;
-
-  Debugger(this.targetProcess, this.script) {
-    var stdoutStringStream = targetProcess.stdout
-        .transform(UTF8.decoder)
-        .transform(new LineSplitter());
-    stdoutStringStream.listen((line) {
-      print("TARG: $line");
-      if (line.startsWith("Debugger listening")) {
-        RegExp portExpr = new RegExp(r"\d+");
-        var port = portExpr.stringMatch(line);
-        print("Debug target found listening at port '$port'");
-        openConnection(int.parse(port));
-      }
-    });
-
-    var stderrStringStream = targetProcess.stderr
-        .transform(UTF8.decoder)
-        .transform(new LineSplitter());
-    stderrStringStream.listen((line) {
-      print("TARG: $line");
-    });
-  }
-
-  // Handle debugger events, updating the debugger state.
-  void handleEvent(Map<String,dynamic> msg) {
-    events.add(new Event(msg));
-
-    if (msg["event"] == "isolate") {
-      if (msg["params"]["reason"] == "created") {
-        isolateId = msg["params"]["id"];
-        assert(isolateId != null);
-        print("Debuggee isolate id $isolateId created.");
-      } else if (msg["params"]["reason"] == "shutdown") {
-        print("Debuggee isolate id ${msg["params"]["id"]} shut down.");
-        shutdownEventSeen = true;
-        if (!script.isEmpty) {
-          error("Error: premature isolate shutdown event seen.");
-          error("Next expected event: ${script.currentEntry}");
-        }
-      }
-    } else if (msg["event"] == "breakpointResolved") {
-      var bpId = msg["params"]["breakpointId"];
-      assert(bpId != null);
-      var isolateId = msg["params"]["isolateId"];
-      assert(isolateId != null);
-      var location = msg["params"]["location"];
-      assert(location != null);
-      print("Isolate $isolateId: breakpoint $bpId resolved"
-            " at location $location");
-      // We may want to maintain a table of breakpoints in the future.
-    } else if (msg["event"] == "paused") {
-      isPaused = true;
-    } else {
-      error("Error: unknown debugger event received");
-    }
-  }
-
-  // Handle one JSON message object and match it to the
-  // expected events and responses in the debugging script.
-  void handleMessage(Map<String,dynamic> receivedMsg) {
-    currentMessage = receivedMsg;
-    if (receivedMsg["event"] != null) {
-      handleEvent(receivedMsg);
-      if (errorsDetected) {
-        error("Error while handling debugger event");
-        error("Event received from debug target: $receivedMsg");
-      }
-    } else if (receivedMsg["id"] != null) {
-      // This is a response to the last command we sent.
-      assert(lastCommand != null);
-      lastCommand.matchResponse(this);
-      lastCommand = null;
-      if (errorsDetected) {
-        error("Error while matching response to debugger command");
-        error("Response received from debug target: $receivedMsg");
-      }
-    }
-  }
-
-  // Send next debugger command in the script, if a response
-  // from the last command has been received and processed.
-  void sendNextCommand() {
-    while (script.isNextEventMatcher) {
-      EventMatcher matcher = script.currentEntry;
-      script.advance();
-      matcher.matchEvent(this);
-    }
-
-    if (lastCommand == null) {
-      if (script.currentEntry is Command) {
-        script.currentEntry.send(this);
-        lastCommand = script.currentEntry;
-        seqNr++;
-        script.advance();
-      }
-    }
-  }
-
-  // Handle data received over the wire from the debug target
-  // process. Split input from JSON wire format into individual
-  // message objects (maps).
-  void handleMessages() {
-    var msg = responses.getNextMessage();
-    while (msg != null) {
-      if (verboseWire) print("RECV: $msg");
-      if (responses.haveGarbage()) {
-        error("Error: leftover text after message: '${responses.buffer}'");
-        error("Previous message may be malformed, was: '$msg'");
-        cleanup();
-        return;
-      }
-      var msgObj = JSON.decode(msg);
-      handleMessage(msgObj);
-      if (errorsDetected) {
-        error("Error while handling script entry");
-        error("Message received from debug target: $msg");
-        cleanup();
-        return;
-      }
-      if (shutdownEventSeen) {
-        cleanup();
-        return;
-      }
-      if (isPaused) sendNextCommand();
-      msg = responses.getNextMessage();
-    }
-  }
-
-  // Send a debugger command to the target VM.
-  void sendMessage(Map<String,dynamic> msg) {
-    if (msg["id"] != null) {
-      msg["id"] = seqNr;
-    }
-    if (msg["params"] != null && msg["params"]["isolateId"] != null) {
-      msg["params"]["isolateId"] = isolateId;
-    }
-    String jsonMsg = JSON.encode(msg);
-    if (verboseWire) print("SEND: $jsonMsg");
-    socket.write(jsonMsg);
-  }
-
-  bool get errorsDetected => errors.length > 0;
-
-  // Record error message.
-  void error(String s) {
-    errors.add(s);
-  }
-
-  void openConnection(int portNumber) {
-    Socket.connect("127.0.0.1", portNumber).then((s) {
-        s.setOption(SocketOption.TCP_NODELAY, true);
-        this.socket = s;
-        var stringStream = socket.transform(UTF8.decoder);
-        stringStream.listen((str) {
-            try {
-              responses.append(str);
-              handleMessages();
-            } catch(e, trace) {
-              print("Unexpected exception:\n$e\n$trace");
-              cleanup();
-            }
-          },
-          onDone: () {
-            print("Connection closed by debug target");
-            cleanup();
-          },
-          onError: (e, trace) {
-            print("Error '$e' detected in input stream from debug target");
-            if (trace != null) print("StackTrace: $trace");
-            cleanup();
-          });
-      },
-      onError: (e, trace) {
-        String msg = "Error while connecting to debugee: $e";
-        if (trace != null) msg += "\nStackTrace: $trace";
-        error(msg);
-        cleanup();
-      });
-  }
-
-  void cleanup() {
-    if (cleanupDone) return;
-    if (socket != null) {
-      socket.close().catchError((error) {
-        // Print this directly in addition to adding it to the
-        // error message queue, in case the error message queue
-        // gets printed before this error handler is called.
-        print("Error occurred while closing socket: $error");
-        error("Error while closing socket: $error");
-      });
-    }
-    var targetPid = targetProcess.pid;
-    if (errorsDetected || !shutdownEventSeen) {
-      print("Sending kill signal to process $targetPid...");
-      targetProcess.kill();
-    }
-    // If the process was already dead, exitCode is
-    // available and we call exit() in the next event loop cycle.
-    // Otherwise this will wait for the process to exit.
-    targetProcess.exitCode.then((exitCode) {
-      print("process $targetPid terminated with exit code $exitCode.");
-      if (exitCode != 0) {
-        error("Error: target process died with exit code $exitCode");
-      }
-      if (errorsDetected) {
-        print("\n===== Errors detected: =====");
-        for (int i = 0; i < errors.length; i++) print(errors[i]);
-        print("============================\n");
-      }
-      exit(errors.length);
-    });
-    cleanupDone = true;
-  }
-}
-
-
-bool RunScript(List script, List<String> arguments) {
-  if (arguments.contains("--debuggee")) {
-    return false;
-  }
-  verboseWire = arguments.contains("--wire");
-
-  // Port number 0 means debug target picks a free port dynamically.
-  var targetOpts = [ "--debug:0" ];
-  if (arguments.contains("--verbose")) {
-    targetOpts.add("--verbose_debug");
-  }
-  targetOpts.add(Platform.script.toFilePath());
-  targetOpts.add("--debuggee");
-  print('args: ${targetOpts.join(" ")}');
-
-  Process.start(Platform.executable, targetOpts).then((Process process) {
-    print("Debug target process started, pid ${process.pid}.");
-    process.stdin.close();
-    var debugger = new Debugger(process, new DebugScript(script));
-  });
-  return true;
-}
diff --git a/tests/standalone/debugger/deferred_code_lib.dart b/tests/standalone/debugger/deferred_code_lib.dart
deleted file mode 100644
index 4506217..0000000
--- a/tests/standalone/debugger/deferred_code_lib.dart
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library lazyCode;
-
-void stopTheBuck() {
-  // Line number of print call must match breakpoint request
-  // in deferred_code_test.dart.
-  print("The debugger stops here.");
-}
diff --git a/tests/standalone/debugger/deferred_code_test.dart b/tests/standalone/debugger/deferred_code_test.dart
deleted file mode 100644
index c4578ab..0000000
--- a/tests/standalone/debugger/deferred_code_test.dart
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// Test to verify that a breakpoint can be set in code that is not yet
-// loaded, i.e. in a deferred library.
-//
-// This test forks a second vm process that runs this dart script as
-// a debug target.
-// Run this test with option --wire to see the json messages sent
-// between the processes.
-// Run this test with option --verbose to see the stdout and stderr output
-// of the debug target process.
-
-import "debug_lib.dart";
-import "deferred_code_lib.dart" deferred as D;
-
-
-main(List<String> arguments) {
-  if (RunScript(testScript, arguments)) return;
-  var loaded = false;
-  print("Hello from debuggee");
-  D.loadLibrary().then((_) {
-    loaded = true;
-    print("Done loading deferred library");
-    D.stopTheBuck();
-  });
-  print("main terminates");
-}
-
-
-// Expected debugger events and commands.
-var testScript = [
-  MatchFrame(0, "main"),  // Top frame in trace is function "main".
-  SetBreakpoint(22),  // Breakpoint just before call to loadLibrary().
-  Resume(),
-  // Set BP in deferred library code before the loadLibrary() call is executed.
-  MatchFrame(0, "main"),
-  MatchLine(22),
-  MatchLocals({"loaded": "false"}),
-  SetBreakpoint(10, url: "deferred_code_lib.dart"),
-  // Regression test: we used to have a bug that hung the debugger when
-  // processing latent brakepoints for urls that have no match.
-  // The BP below will not match any loaded file.
-  SetBreakpoint(10, url: "non_existing_file.dart"),
-  Resume(),
-  MatchFrame(0, "stopTheBuck"),  // Expect to be stopped in deferred library code.
-  // MatchLine(10), // Line matching only works for the main script.
-  Resume(),
-];
diff --git a/tests/standalone/debugger/local_function_test.dart b/tests/standalone/debugger/local_function_test.dart
deleted file mode 100644
index 98df8fe..0000000
--- a/tests/standalone/debugger/local_function_test.dart
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test forks a second vm process that runs this dart script as
-// a debug target.
-// Run this test with option --wire to see the json messages sent
-// between the processes.
-// Run this test with option --verbose to see the stdout and stderr output
-// of the debug target process.
-
-import "debug_lib.dart";
-
-// Check that if a breakpoint is requested on the line containing the
-// one-liner with a local function below, the breakpoint gets set in
-// the outer function.
-foo(x) => (n) => x * n;  // Breakpoint 1 on this line.
-
-// Check that if a breakpoint is requested on the line "return n*x"
-// below, the breakpoint is set in the local function (closure).
-bar(x) {
-  return (n) {
-    return n * x;  // Breakpoint 2 on this line.
-  };
-}
-
-// Check that setting a breakpoint works in the case where the
-// class has not been parsed yet.
-// No reference to class C must appear in main(), so that the class is not
-// yet parsed when the breakpoint in the closure nested in the constructor
-// is set.
-class C {
-  var closure;
-  C() {
-    closure = () {
-      var z = 10;  // Breakpoint 3 on this line.
-      z = z * 2;
-      return z;
-    };
-  }
-}
-
-checkBpInLazilyParsedClass() {
-  var c = new C();
-  c.closure(); // Expected to hit breakpoint.
-}
-
-
-main(List<String> arguments) {
-  if (RunScript(testScript, arguments)) return;
-  print("Hello from debuggee");
-  var f = foo(10);  // Hits breakpoint.
-  print(f(5));
-  var b = bar(10);
-  print(b(10)); // Hits breakpoint.
-  checkBpInLazilyParsedClass();
-}
-
-// Expected debugger events and commands.
-var testScript = [
-  MatchFrame(0, "main"),  // Top frame in trace is function "main".
-  SetBreakpoint(17),      // Breakpoint 1 in function foo.
-  SetBreakpoint(23),      // Breakpoint 2 in local function inside bar.
-  SetBreakpoint(36),      // Breakpoint 3 in local function inside constructor C.
-  Resume(),
-  MatchFrames(["foo", "main"]),
-  Resume(),
-  MatchFrames(["<anonymous closure>", "main"]),
-  Resume(),
-  MatchFrames(["C.<anonymous closure>", "checkBpInLazilyParsedClass"]),
-  Resume(),
-];
diff --git a/tests/standalone/debugger/local_variables_test.dart b/tests/standalone/debugger/local_variables_test.dart
deleted file mode 100644
index b7871d4..0000000
--- a/tests/standalone/debugger/local_variables_test.dart
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test forks a second vm process that runs this dart script as
-// a debug target.
-// Run this test with option --wire to see the json messages sent
-// between the processes.
-// Run this test with option --verbose to see the stdout and stderr output
-// of the debug target process.
-
-import "debug_lib.dart";
-
-foo() {
-  var y;  // Breakpoint
-  return 123;
-}
-
-test() {
-  if (true) {
-    var temp = 777;
-  }
-  if (true) {
-    var a = foo();  // Breakpoint
-    if (true) {
-      var s = 456;
-      print(s);
-    }
-  }
-}
-
-test_no_init() {
-  if (true) {
-    var temp = 777;
-  }
-  if (true) {
-    var a;  // Breakpoint
-    if (true) {
-      var s = 456;
-      print(s);
-    }
-  }
-}
-
-
-main(List<String> arguments) {
-  if (RunScript(testScript, arguments)) return;
-  print("Hello from debuggee");
-  test();
-  test_no_init();
-  print("Hello again");
-}
-
-
-// Expected debugger events and commands.
-var testScript = [
-  MatchFrame(0, "main"),  // Top frame in trace is function "main".
-  Step(),
-  MatchFrame(0, "main"),  // Should still be in "main".
-  SetBreakpoint(15),  // Set breakpoint in function foo.
-  SetBreakpoint(24),  // Set breakpoint in function test.
-  SetBreakpoint(37),  // Set breakpoint in function test_no_init.
-  Resume(),
-  MatchFrames(["test", "main"]),
-  AssertLocalsNotVisible(["a"]),  // Here, a is not in scope yet.
-  Resume(),
-  MatchFrames(["foo", "test", "main"]),
-  AssertLocalsNotVisible(["a"], 1),  // In the caller, a is not in scope.
-  Step(),
-  MatchLocals({"y": "null"}),  // Expect y initialized to null.
-  Resume(),
-  MatchFrames(["test_no_init", "main"]),
-  AssertLocalsNotVisible(["a"]),  // a is not in scope.
-  Step(),
-  MatchLocals({"a": "null"}),
-  Resume()
-];
diff --git a/tests/standalone/debugger/mixin_closure_debugger_test.dart b/tests/standalone/debugger/mixin_closure_debugger_test.dart
deleted file mode 100644
index 5e6fd5e..0000000
--- a/tests/standalone/debugger/mixin_closure_debugger_test.dart
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test forks a second vm process that runs this dart script as
-// a debug target.
-// Run this test with option --wire to see the json messages sent
-// between the processes.
-// Run this test with option --verbose to see the stdout and stderr output
-// of the debug target process.
-
-// This test checks that a breakpoint can be set and is hit in a closure
-// inside a mixin function. Regression test for issue 15325.
-
-import "debug_lib.dart";
-
-class S { }
-
-class M {
-  m()  {
-    var sum = 0;
-    [1,2,3].forEach((e) {
-      sum += e;  // Breakpoint here.
-    });
-    return sum;
-  }
-}
-
-class A = S with M;
-
-main(List<String> arguments) {
-  if (RunScript(testScript, arguments)) return;
-  var a = new A();
-  print(a.m());
-}
-
-// Expected debugger events and commands.
-var testScript = [
-  MatchFrame(0, "main"),  // Top frame in trace is function "main".
-  SetBreakpoint(23),      // Set breakpoint inside the forEach closure.
-  Resume(),
-  MatchFrames(["S&M.<anonymous closure>", "forEach", "S&M.m"],
-              exactMatch: false),  // First iteration.
-  MatchLocals({"e": "1"}),
-  Resume(),
-  MatchFrames(["S&M.<anonymous closure>", "forEach", "S&M.m"],
-              exactMatch: false),  // Second iteration.
-  MatchLocals({"e": "2"}),
-  Resume(),
-  MatchFrames(["S&M.<anonymous closure>", "forEach", "S&M.m"],
-              exactMatch: false),  // Third iteration.
-  MatchLocals({"e": "3"}),
-  Resume(),
-];
diff --git a/tests/standalone/debugger/nosuchmethod_debugger_test.dart b/tests/standalone/debugger/nosuchmethod_debugger_test.dart
deleted file mode 100644
index 10b6855..0000000
--- a/tests/standalone/debugger/nosuchmethod_debugger_test.dart
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test forks a second vm process that runs this dart script as
-// a debug target.
-// Run this test with option --wire to see the json messages sent
-// between the processes.
-// Run this test with option --verbose to see the stdout and stderr output
-// of the debug target process.
-
-import "debug_lib.dart";
-
-main(List<String> arguments) {
-  if (RunScript(testScript, arguments)) return;
-  print("Hello from debuggee");
-  var a = new A();
-  for (var i = 0; i < 2; ++i) {
-    a.foo(i);
-  }
-}
-
-class A {
-  noSuchMethod(m) {
-    print(m.positionalArguments[0]);
-  }
-}
-
-// Expected debugger events and commands.
-var testScript = [
-  MatchFrame(0, "main"),  // Top frame in trace is function "main".
-  SetBreakpoint(19),      // Set breakpoint at a.foo(i).
-  Resume(),
-  MatchFrame(0, "main"),  // Should be at closure call.
-  MatchLocals({"i": "0"}),
-  StepInto(),
-  StepInto(),
-  MatchFrames(["A.noSuchMethod", "main"]),
-  StepOut(),
-  MatchFrame(0, "main"),  // Back in main.
-  Resume(),
-  MatchFrame(0, "main"),  // Still in main back at a.foo(i).
-  MatchLocals({"i": "1"}),
-  StepInto(),
-  StepInto(),
-  MatchFrames(["A.noSuchMethod", "main"]),  // Second invocation.
-  Resume()
-];
diff --git a/tests/standalone/debugger/step_inout_test.dart b/tests/standalone/debugger/step_inout_test.dart
deleted file mode 100644
index 421c212..0000000
--- a/tests/standalone/debugger/step_inout_test.dart
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "debug_lib.dart";
-
-main(List<String> arguments) {
-  if (RunScript(testScript, arguments)) return;
-
-  foo('foo1');
-  foo('foo2');
-  foo('foo3');
-}
-
-void foo(String str) {
-  print(str);
-}
-
-/**
- * Set a breakpoint, resume to that breakpoint, step into a method, step out,
- * step over the next line, and resume execution.
- */
-var testScript = [
-  MatchFrames(["main"]),
-  SetBreakpoint(10),
-  Resume(),
-  MatchFrames(["main"]),
-  StepInto(),
-  MatchFrames(["foo", "main"]),
-  StepOut(),
-  MatchFrames(["main"]),
-  Step(),
-  MatchFrames(["main"]),
-  Resume(),
-];
diff --git a/tests/standalone/debugger/stepping_test.dart b/tests/standalone/debugger/stepping_test.dart
deleted file mode 100644
index d8f37d2..0000000
--- a/tests/standalone/debugger/stepping_test.dart
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "debug_lib.dart";
-
-main(List<String> arguments) {
-  if (RunScript(testScript, arguments)) return;
-
-  bar();
-}
-
-void bar() {
-  print('foo1');
-  print('foo2');
-  print('foo3');
-}
-
-/**
- * Set a breakpoint, resume to that breakpoint, step once, and verify that the
- * step worked.
- */
-var testScript = [
-  MatchFrames(["main"]),
-  SetBreakpoint(15),
-  Resume(),
-  MatchFrames(["bar"]),
-  Step(),
-  MatchFrames(["bar"]),
-  Resume(),
-];
diff --git a/tests/standalone/debugger/tostring_throws_test.dart b/tests/standalone/debugger/tostring_throws_test.dart
deleted file mode 100644
index 7214bb2..0000000
--- a/tests/standalone/debugger/tostring_throws_test.dart
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "debug_lib.dart";
-
-main(List<String> arguments) {
-  if (RunScript(testScript, arguments)) return;
-
-  Foo foo = new Foo();
-
-  print("Hello from debuggee");
-}
-
-class Foo {
-  String toString() {
-    throw 'I always throw';
-  }
-}
-
-// Make sure Foo.toString() does not get called.
-var testScript = [
-  MatchFrame(0, "main"),
-  SetBreakpoint(12),
-  Resume(),
-  MatchFrame(0, "main"),
-  MatchLocals({"foo": "object of type Foo"}),
-  Resume(),
-];
diff --git a/tests/standalone/precompilation_dart2js_test.dart b/tests/standalone/precompilation_dart2js_test.dart
index c961a5e..52957d7 100644
--- a/tests/standalone/precompilation_dart2js_test.dart
+++ b/tests/standalone/precompilation_dart2js_test.dart
@@ -87,7 +87,7 @@
 
     var ld_library_path = new String.fromEnvironment("LD_LIBRARY_PATH");
     ld_library_path = "${ld_library_path}:${tmp.path}";
-    exec = "${dart_executable}";
+    exec = "${dart_executable}_precompiled";
     args = ["--run-precompiled-snapshot", "ignored_script", "--version"];
     print("LD_LIBRARY_PATH=$ld_library_path $exec ${args.join(' ')}");
     result = Process.runSync(exec, args,
diff --git a/tests/standalone/precompilation_test.dart b/tests/standalone/precompilation_test.dart
index 047ac0d..751682e 100644
--- a/tests/standalone/precompilation_test.dart
+++ b/tests/standalone/precompilation_test.dart
@@ -86,7 +86,7 @@
     ld_library_path = "${ld_library_path}:${tmp.path}";
 
     result = Process.runSync(
-       "${dart_executable}",
+       "${dart_executable}_precompiled",
        ["--run-precompiled-snapshot", "ignored_script", "--hello"],
        workingDirectory: tmp.path,
        environment: {"LD_LIBRARY_PATH": ld_library_path});
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index b136d43..5891105 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -50,8 +50,6 @@
 typed_data_isolate_test: SkipByDesign # This test uses dart:io
 io/*: SkipByDesign # Don't run tests using dart:io in the browser
 package/*: Skip # Do not run those in Dartium.
-debugger/*: SkipByDesign # Do not run standalone debugger tests in browser.
-coverage_test: Skip
 full_coverage_test: Skip
 http_launch_test: Skip
 vmservice/*: SkipByDesign # Do not run standalone vm service tests in browser.
@@ -91,7 +89,6 @@
 package/package_isolate_test: Skip # spawnUri does not work in dart2js. See issue 3051
 package/package_test: Fail, OK # dart2js does not support 'package:foo.dart' imports
 package/package1_test: Fail, OK # dart2js does not support 'package:foo.dart' imports
-debugger/*: Skip # Do not run standalone vm debugger tests with dart2js.
 full_coverage_test: Skip
 left_shift_bit_and_op_test: Skip # Integers exceed dart2js precision.
 pow_test: Skip # Precision > 53 bits.
@@ -110,16 +107,19 @@
 precompilation_dart2js_test: Skip # Standalone only test.
 noopt_test: Skip # Standalone only test.
 
-[ $runtime == vm && $arch == ia32]
+[ $runtime == vm && $mode == debug ]
+precompilation_dart2js_test: Pass, Slow
+
+[ $runtime == vm && $arch == ia32 ]
 precompilation_test: Skip # Not expected to pass on ia32.
 precompilation_dart2js_test: Skip # Not expected to pass on ia32.
 noopt_test: Skip # Not expected to pass on ia32.
 
-[ $runtime == vm && $arch == arm]
+[ $runtime == vm && $arch == arm ]
 precompilation_test: Skip # Issue 24427
 precompilation_dart2js_test: Skip # Issue 24427
 
-[ $runtime == vm && $arch == mips]
+[ $runtime == vm && $arch == mips ]
 precompilation_dart2js_test: SkipSlow
 
 [ $compiler == dart2js && $jscl ]
@@ -136,7 +136,7 @@
 [ $compiler == dart2js && $browser ]
 *: Skip
 
-[ $arch == simarm || $arch == simarmv5te || $arch == simmips]
+[ $arch == simarm || $arch == simarmv5te || $arch == simmips ]
 out_of_memory_test: Skip # passes on Mac, crashes on Linux
 oom_error_stacktrace_test: Skip # Fails on Linux
 
@@ -200,6 +200,7 @@
 io/skipping_dart2js_compilations_test: Fail # Issue 19551.
 verbose_gc_to_bmu_test: Skip
 io/platform_resolved_executable_test/06: RuntimeError  # Issue 23641
+io/process_sync_test: Pass, Timeout  # Issue 24596
 
 [ $arch != ia32 && $arch != x64 && $arch != simarm && $arch != simarmv5te && $mode == debug ]
 verified_mem_test: Skip  # Not yet implemented.
diff --git a/tests/standalone/typed_array_int64_uint64_test.dart b/tests/standalone/typed_array_int64_uint64_test.dart
index 3decb92..f62ab53 100644
--- a/tests/standalone/typed_array_int64_uint64_test.dart
+++ b/tests/standalone/typed_array_int64_uint64_test.dart
@@ -7,12 +7,19 @@
 // Library tag to be able to run in html test framework.
 library TypedArray;
 import "package:expect/expect.dart";
+import 'package:async_helper/async_helper.dart';
+import 'dart:async';
 import 'dart:isolate';
 import 'dart:typed_data';
 
-void main() {
-  int64_receiver();
-  uint64_receiver();
+main() {
+  test(int64_receiver);
+  test(uint64_receiver);
+}
+
+test(f) {
+  asyncStart();
+  return f().whenComplete(asyncEnd);
 }
 
 // Int64 array.
@@ -24,15 +31,17 @@
 }
 Int64List int64 = initInt64();
 
-void int64_receiver() {
+int64_receiver() {
   var response = new ReceivePort();
   var remote = Isolate.spawn(int64_sender, [int64.length, response.sendPort]);
-  response.first.then((a) {
+  asyncStart();
+  return response.first.then((a) {
     Expect.equals(int64.length, a.length);
     for (int i = 0; i < a.length; i++) {
       Expect.equals(int64[i], a[i]);
     }
     print("int64_receiver");
+    asyncEnd();
   });
 }
 
@@ -57,15 +66,17 @@
 }
 Uint64List uint64 = initUint64();
 
-void uint64_receiver() {
+uint64_receiver() {
   var response = new ReceivePort();
   var remote = Isolate.spawn(uint64_sender, [uint64.length, response.sendPort]);
-  response.first.then((a) {
+  asyncStart();
+  return response.first.then((a) {
     Expect.equals(uint64.length, a.length);
     for (int i = 0; i < a.length; i++) {
       Expect.equals(uint64[i], a[i]);
     }
     print("uint64_receiver");
+    asyncEnd();
   });
 }
 
diff --git a/tests/standalone/typed_array_test.dart b/tests/standalone/typed_array_test.dart
index 9643e13e..0c4c2b1 100644
--- a/tests/standalone/typed_array_test.dart
+++ b/tests/standalone/typed_array_test.dart
@@ -8,19 +8,25 @@
 // Library tag to be able to run in html test framework.
 library TypedArray;
 import "package:expect/expect.dart";
+import 'package:async_helper/async_helper.dart';
 import 'dart:isolate';
 import 'dart:typed_data';
 
 void main() {
-  int8_receiver();
-  uint8_receiver();
-  int16_receiver();
-  uint16_receiver();
-  int32_receiver();
-  uint32_receiver();
+  test(int8_receiver);
+  test(uint8_receiver);
+  test(int16_receiver);
+  test(uint16_receiver);
+  test(int32_receiver);
+  test(uint32_receiver);
   // int64 and uint64 in separate test.
-  float32_receiver();
-  float64_receiver();
+  test(float32_receiver);
+  test(float64_receiver);
+}
+
+test(f) {
+  asyncStart();
+  return f().whenComplete(asyncEnd);
 }
 
 // Int8 array.
@@ -32,15 +38,17 @@
 }
 Int8List int8 = initInt8();
 
-void int8_receiver() {
+int8_receiver() {
   var response = new ReceivePort();
   var remote = Isolate.spawn(int8_sender, [int8.length, response.sendPort]);
-  response.first.then((a) {
+  asyncStart();
+  return response.first.then((a) {
     Expect.equals(int8.length, a.length);
     for (int i = 0; i < a.length; i++) {
       Expect.equals(int8[i], a[i]);
     }
     print("int8_receiver");
+    asyncEnd();
   });
 }
 
@@ -65,15 +73,17 @@
 }
 Uint8List uint8 = initUint8();
 
-void uint8_receiver() {
+uint8_receiver() {
   var response = new ReceivePort();
   var remote = Isolate.spawn(uint8_sender, [uint8.length, response.sendPort]);
-  response.first.then((a) {
+  asyncStart();
+  return response.first.then((a) {
     Expect.equals(uint8.length, a.length);
     for (int i = 0; i < a.length; i++) {
       Expect.equals(uint8[i], a[i]);
     }
     print("uint8_receiver");
+    asyncEnd();
   });
 }
 
@@ -98,15 +108,17 @@
 }
 Int16List int16 = initInt16();
 
-void int16_receiver() {
+int16_receiver() {
   var response = new ReceivePort();
   var remote = Isolate.spawn(int16_sender, [int16.length, response.sendPort]);
-  response.first.then((a) {
+  asyncStart();
+  return response.first.then((a) {
     Expect.equals(int16.length, a.length);
     for (int i = 0; i < a.length; i++) {
       Expect.equals(int16[i], a[i]);
     }
     print("int16_receiver");
+    asyncEnd();
   });
 }
 
@@ -131,15 +143,17 @@
 }
 Uint16List uint16 = initUint16();
 
-void uint16_receiver() {
+uint16_receiver() {
   var response = new ReceivePort();
   var remote = Isolate.spawn(uint16_sender, [uint16.length, response.sendPort]);
-  response.first.then((a) {
+  asyncStart();
+  return response.first.then((a) {
     Expect.equals(uint16.length, a.length);
     for (int i = 0; i < a.length; i++) {
       Expect.equals(uint16[i], a[i]);
     }
     print("uint16_receiver");
+    asyncEnd();
   });
 }
 
@@ -164,15 +178,17 @@
 }
 Int32List int32 = initInt32();
 
-void int32_receiver() {
+int32_receiver() {
   var response = new ReceivePort();
   var remote = Isolate.spawn(int32_sender, [int32.length, response.sendPort]);
-  response.first.then((a) {
+  asyncStart();
+  return response.first.then((a) {
     Expect.equals(int32.length, a.length);
     for (int i = 0; i < a.length; i++) {
       Expect.equals(int32[i], a[i]);
     }
     print("int32_receiver");
+    asyncEnd();
   });
 }
 
@@ -197,15 +213,17 @@
 }
 Uint32List uint32 = initUint32();
 
-void uint32_receiver() {
+uint32_receiver() {
   var response = new ReceivePort();
   var remote = Isolate.spawn(uint32_sender, [uint32.length, response.sendPort]);
-  response.first.then((a) {
+  asyncStart();
+  return response.first.then((a) {
     Expect.equals(uint32.length, a.length);
     for (int i = 0; i < a.length; i++) {
       Expect.equals(uint32[i], a[i]);
     }
     print("uint32_receiver");
+    asyncEnd();
   });
 }
 
@@ -230,16 +248,18 @@
 }
 Float32List float32 = initFloat32();
 
-void float32_receiver() {
+float32_receiver() {
   var response = new ReceivePort();
   var remote =
       Isolate.spawn(float32_sender, [float32.length, response.sendPort]);
-  response.first.then((a) {
+  asyncStart();
+  return response.first.then((a) {
     Expect.equals(float32.length, a.length);
     for (int i = 0; i < a.length; i++) {
       Expect.equals(float32[i], a[i]);
     }
     print("float32_receiver");
+    asyncEnd();
   });
 }
 
@@ -264,16 +284,18 @@
 }
 Float64List float64 = initFloat64();
 
-void float64_receiver() {
+float64_receiver() {
   var response = new ReceivePort();
   var remote =
       Isolate.spawn(float64_sender, [float64.length, response.sendPort]);
-  response.first.then((a) {
+  asyncStart();
+  return response.first.then((a) {
     Expect.equals(float64.length, a.length);
     for (int i = 0; i < a.length; i++) {
       Expect.equals(float64[i], a[i]);
     }
     print("float64_receiver");
+    asyncEnd();
   });
 }
 
diff --git a/tools/FAKE_COMMITS b/tools/FAKE_COMMITS
index 59a3d33..709ba90 100644
--- a/tools/FAKE_COMMITS
+++ b/tools/FAKE_COMMITS
@@ -14,3 +14,4 @@
 Trigger bots on github pull
 Trigger bots 
 Purple is the new green.
+googlecode back up
diff --git a/tools/VERSION b/tools/VERSION
index c50dfe1..1998c0e 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 1
 MINOR 14
 PATCH 0
-PRERELEASE 1
+PRERELEASE 2
 PRERELEASE_PATCH 0
diff --git a/tools/coverage.dart b/tools/coverage.dart
deleted file mode 100644
index b5cc618..0000000
--- a/tools/coverage.dart
+++ /dev/null
@@ -1,545 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test forks a second vm process that runs a dart script as
-// a debug target, single stepping through the entire program, and
-// recording each breakpoint. At the end, a coverage map of the source
-// is printed.
-//
-// Usage: dart coverage.dart [--wire] [--verbose] target_script.dart
-//
-//   --wire      see json messages sent between the processes.
-//   --verbose   see the stdout and stderr output of the debug
-//               target process.
-
-import "dart:convert";
-import "dart:io";
-
-
-// Whether or not to print debug target process on the console.
-var showDebuggeeOutput = false;
-
-// Whether or not to print the debugger wire messages on the console.
-var verboseWire = false;
-
-var debugger = null;
-
-class Program {
-  static int numBps = 0;
-
-  // Maps source code url to source.
-  static var sources = new Map<String, Source>();
-
-  // Takes a JSON Debugger response and increments the count for
-  // the source position.
-  static void recordBp(Map<String,dynamic> msg) {
-    // Progress indicator.
-    if (++numBps % 1000 == 0) print(numBps);
-    var location = msg["params"]["location"];
-    if (location == null) return;
-    String url = location["url"];
-    assert(url != null);
-    int libId = location["libraryId"];
-    assert(libId != null);
-    int tokenPos = location["tokenOffset"];;
-    Source s = sources[url];
-    if (s == null) {
-      debugger.getLineNumberTable(url, libId);
-      s = new Source(url);
-      sources[url] = s;
-    }
-    s.recordBp(tokenPos);
-  }
-
-  // Prints the annotated source code.
-  static void printCoverage() {
-    print("Coverage info collected from $numBps breakpoints:");
-    for(Source s in sources.values) s.printCoverage();
-  }
-}
-
-
-class Source {
-  final String url;
-
-  // Maps token position to breakpoint count.
-  final tokenCounts = new Map<int,int>();
-
-  // Maps token position to line number.
-  final tokenPosToLine = new Map<int,int>();
-
-  Source(this.url);
-
-  void recordBp(int tokenPos) {
-    var count = tokenCounts[tokenPos];
-    tokenCounts[tokenPos] = count == null ? 1 : count + 1;
-  }
-
-  void SetLineInfo(List lineInfoTable) {
-    // Each line is encoded as an array with first element being the line
-    // number, followed by pairs of (tokenPosition, columnNumber).
-    lineInfoTable.forEach((List<int> line) {
-      int lineNumber = line[0];
-      for (int t = 1; t < line.length; t += 2) {
-        assert(tokenPosToLine[line[t]] == null);
-        tokenPosToLine[line[t]] = lineNumber;
-      }
-    });
-  }
-
-  // Print out the annotated source code. For each line that has seen
-  // a breakpoint, print out the maximum breakpoint count for all
-  // tokens in the line.
-  void printCoverage() {
-    var lineCounts = new Map<int,int>();  // BP counts for each line.
-    print(url);
-    tokenCounts.forEach((tp, bpCount) {
-      int lineNumber = tokenPosToLine[tp];
-      var lineCount = lineCounts[lineNumber];
-      // Remember maximum breakpoint count of all tokens in this line.
-      if (lineCount == null || lineCount < bpCount) {
-        lineCounts[lineNumber] = bpCount;
-      }
-    });
-
-    String srcPath = Uri.parse(url).toFilePath();
-    List lines = new File(srcPath).readAsLinesSync();
-    for (int line = 1; line <= lines.length; line++) {
-      String prefix = "      ";
-      if (lineCounts.containsKey(line)) {
-        prefix = lineCounts[line].toString();
-        StringBuffer b = new StringBuffer();
-        for (int i = prefix.length; i < 6; i++) b.write(" ");
-        b.write(prefix);
-        prefix = b.toString();
-      }
-      print("${prefix}|${lines[line-1]}");
-    }
-  }
-}
-
-
-class StepCmd {
-  Map msg;
-  StepCmd(int isolateId) {
-    msg = {"id": 0, "command": "stepInto", "params": {"isolateId": isolateId}};
-  }
-  void handleResponse(Map response) {}
-}
-
-
-class GetLineTableCmd {
-  Map msg;
-  GetLineTableCmd(int isolateId, int libraryId, String url) {
-    msg = { "id": 0,
-            "command":  "getLineNumberTable",
-            "params": { "isolateId" : isolateId,
-                        "libraryId": libraryId,
-                        "url": url } };
-  }
-
-  void handleResponse(Map response) {
-    var url = msg["params"]["url"];
-    Source s = Program.sources[url];
-    assert(s != null);
-    s.SetLineInfo(response["result"]["lines"]);
-  }
-}
-
-
-class GetLibrariesCmd {
-  Map msg;
-  GetLibrariesCmd(int isolateId) {
-    msg = { "id": 0,
-            "command":  "getLibraries",
-            "params": { "isolateId" : isolateId } };
-  }
-
-  void handleResponse(Map response) {
-    List libs = response["result"]["libraries"];
-    for (var lib in libs) {
-      String url = lib["url"];
-      int libraryId = lib["id"];
-      bool enable = !url.startsWith("dart:") && !url.startsWith("package:");
-      if (enable) {
-        print("Enable stepping for '$url'");
-        debugger.enableDebugging(libraryId, true);
-      }
-    }
-  }
-}
-
-
-class SetLibraryPropertiesCmd {
-  Map msg;
-  SetLibraryPropertiesCmd(int isolateId, int libraryId, bool enableDebugging) {
-    // Note that in the debugger protocol, boolean values true and false
-    // must be sent as string literals.
-    msg = { "id": 0,
-            "command":  "setLibraryProperties",
-            "params": { "isolateId" : isolateId,
-                        "libraryId": libraryId,
-                        "debuggingEnabled": "$enableDebugging" } };
-  }
-
-  void handleResponse(Map response) {
-    // Nothing to do.
-  }
-}
-
-
-class Debugger {
-  // Debug target process properties.
-  Process targetProcess;
-  Socket socket;
-  bool cleanupDone = false;
-  JsonBuffer responses = new JsonBuffer();
-  List<String> errors = new List();
-
-  // Data collected from debug target.
-  Map currentMessage = null;  // Currently handled message sent by target.
-  var outstandingCommand = null;
-  var queuedCommands = new List();
-  String scriptUrl = null;
-  bool shutdownEventSeen = false;
-  int isolateId = 0;
-  int libraryId = null;
-
-  int nextMessageId = 0;
-  bool isPaused = false;
-  bool pendingAck = false;
-
-  Debugger(this.targetProcess) {
-    var stdoutStringStream = targetProcess.stdout
-        .transform(UTF8.decoder)
-        .transform(new LineSplitter());
-    stdoutStringStream.listen((line) {
-      if (showDebuggeeOutput) {
-        print("TARG: $line");
-      }
-      if (line.startsWith("Debugger listening")) {
-        RegExp portExpr = new RegExp(r"\d+");
-        var port = portExpr.stringMatch(line);
-        var pid = targetProcess.pid;
-        print("Coverage target process (pid $pid) found "
-              "listening on port $port.");
-        openConnection(int.parse(port));
-      }
-    });
-
-    var stderrStringStream = targetProcess.stderr
-        .transform(UTF8.decoder)
-        .transform(new LineSplitter());
-    stderrStringStream.listen((line) {
-      if (showDebuggeeOutput) {
-        print("TARG: $line");
-      }
-    });
-  }
-
-  // Handle debugger events, updating the debugger state.
-  void handleEvent(Map<String,dynamic> msg) {
-    if (msg["event"] == "isolate") {
-      if (msg["params"]["reason"] == "created") {
-        isolateId = msg["params"]["id"];
-        assert(isolateId != null);
-        print("Debuggee isolate id $isolateId created.");
-      } else if (msg["params"]["reason"] == "shutdown") {
-        print("Debuggee isolate id ${msg["params"]["id"]} shut down.");
-        shutdownEventSeen = true;
-      }
-    } else if (msg["event"] == "breakpointResolved") {
-      var bpId = msg["params"]["breakpointId"];
-      assert(bpId != null);
-      var isolateId = msg["params"]["isolateId"];
-      assert(isolateId != null);
-      var location = msg["params"]["location"];
-      assert(location != null);
-      print("Isolate $isolateId: breakpoint $bpId resolved"
-            " at location $location");
-      // We may want to maintain a table of breakpoints in the future.
-    } else if (msg["event"] == "paused") {
-      isPaused = true;
-      if (libraryId == null) {
-        libraryId = msg["params"]["location"]["libraryId"];
-        assert(libraryId != null);
-        // This is the first paused event we got. Get all libraries from
-        // the debugger so we can turn on debugging events for them.
-        getLibraries();
-      }
-      if (msg["params"]["reason"] == "breakpoint") {
-        Program.recordBp(msg);
-      }
-    } else {
-      error("Error: unknown debugger event received");
-    }
-  }
-
-  // Handle one JSON message object.
-  void handleMessage(Map<String,dynamic> receivedMsg) {
-    currentMessage = receivedMsg;
-    if (receivedMsg["event"] != null) {
-      handleEvent(receivedMsg);
-      if (errorsDetected) {
-        error("Error while handling event message");
-        error("Event received from coverage target: $receivedMsg");
-      }
-    } else if (receivedMsg["id"] != null) {
-      // This is a response to the last command we sent.
-      int id = receivedMsg["id"];
-      assert(outstandingCommand != null);
-      assert(outstandingCommand.msg["id"] == id);
-      outstandingCommand.handleResponse(receivedMsg);
-      outstandingCommand = null;
-    } else {
-      error("Unexpected message from target");
-    }
-  }
-
-  // Handle data received over the wire from the coverage target
-  // process. Split input from JSON wire format into individual
-  // message objects (maps).
-  void handleMessages() {
-    var msg = responses.getNextMessage();
-    while (msg != null) {
-      if (verboseWire) print("RECV: $msg");
-      if (responses.haveGarbage()) {
-        error("Error: leftover text after message: '${responses.buffer}'");
-        error("Previous message may be malformed, was: '$msg'");
-        cleanup();
-        return;
-      }
-      var msgObj = JSON.decode(msg);
-      handleMessage(msgObj);
-      if (errorsDetected) {
-        error("Error while handling message from coverage target");
-        error("Message received from coverage target: $msg");
-        cleanup();
-        return;
-      }
-      if (shutdownEventSeen) {
-        if (outstandingCommand != null) {
-          error("Error: outstanding command when shutdown received");
-        }
-        cleanup();
-        return;
-      }
-      if (isPaused && (outstandingCommand == null)) {
-        var cmd = queuedCommands.length > 0 ? queuedCommands.removeAt(0) : null;
-        if (cmd == null) {
-          cmd = new StepCmd(isolateId);
-          isPaused = false;
-        }
-        sendMessage(cmd.msg);
-        outstandingCommand = cmd;
-      }
-      msg = responses.getNextMessage();
-    }
-  }
-
-  // Send a debugger command to the target VM.
-  void sendMessage(Map<String,dynamic> msg) {
-    assert(msg["id"] != null);
-    msg["id"] = nextMessageId++;
-    String jsonMsg = JSON.encode(msg);
-    if (verboseWire) print("SEND: $jsonMsg");
-    socket.write(jsonMsg);
-  }
-
-  void getLineNumberTable(String url, int libId) {
-    queuedCommands.add(new GetLineTableCmd(isolateId, libId, url));
-  }
-
-  void getLibraries() {
-    queuedCommands.add(new GetLibrariesCmd(isolateId));
-  }
-
-  void enableDebugging(libraryId, enable) {
-    queuedCommands.add(new SetLibraryPropertiesCmd(isolateId, libraryId, enable));
-  }
-
-  bool get errorsDetected => errors.length > 0;
-
-  // Record error message.
-  void error(String s) {
-    errors.add(s);
-  }
-
-  void openConnection(int portNumber) {
-    Socket.connect("127.0.0.1", portNumber).then((s) {
-      socket = s;
-      socket.setOption(SocketOption.TCP_NODELAY, true);
-      var stringStream = socket.transform(UTF8.decoder);
-      stringStream.listen(
-          (str) {
-            try {
-              responses.append(str);
-              handleMessages();
-            } catch(e, trace) {
-              print("Unexpected exception:\n$e\n$trace");
-              cleanup();
-            }
-          },
-          onDone: () {
-            print("Connection closed by coverage target");
-            cleanup();
-          },
-          onError: (e) {
-            print("Error '$e' detected in input stream from coverage target");
-            cleanup();
-          });
-      },
-      onError: (e, trace) {
-        String msg = "Error while connecting to coverage target: $e";
-        if (trace != null) msg += "\nStackTrace: $trace";
-        error(msg);
-        cleanup();
-     });
-  }
-
-  void cleanup() {
-    if (cleanupDone) return;
-    if (socket != null) {
-      socket.close().catchError((error) {
-        // Print this directly in addition to adding it to the
-        // error message queue, in case the error message queue
-        // gets printed before this error handler is called.
-        print("Error occurred while closing socket: $error");
-        error("Error while closing socket: $error");
-      });
-    }
-    var targetPid = targetProcess.pid;
-    print("Sending kill signal to process $targetPid.");
-    targetProcess.kill();
-    // If the process was already dead exitCode is already
-    // available and we call exit() in the next event loop cycle.
-    // Otherwise this will wait for the process to exit.
-
-    targetProcess.exitCode.then((exitCode) {
-      print("Process $targetPid terminated with exit code $exitCode.");
-      if (errorsDetected) {
-        print("\n===== Errors detected: =====");
-        for (int i = 0; i < errors.length; i++) print(errors[i]);
-        print("============================\n");
-      }
-      Program.printCoverage();
-      exit(errors.length);
-    });
-    cleanupDone = true;
-  }
-}
-
-
-// Class to buffer wire protocol data from coverage target and
-// break it down to individual json messages.
-class JsonBuffer {
-  String buffer = null;
-
-  append(String s) {
-    if (buffer == null || buffer.length == 0) {
-      buffer = s;
-    } else {
-      buffer = buffer + s;
-    }
-  }
-
-  String getNextMessage() {
-    if (buffer == null) return null;
-    int msgLen = objectLength();
-    if (msgLen == 0) return null;
-    String msg = null;
-    if (msgLen == buffer.length) {
-      msg = buffer;
-      buffer = null;
-    } else {
-      assert(msgLen < buffer.length);
-      msg = buffer.substring(0, msgLen);
-      buffer = buffer.substring(msgLen);
-    }
-    return msg;
-  }
-
-  bool haveGarbage() {
-    if (buffer == null || buffer.length == 0) return false;
-    var i = 0, char = " ";
-    while (i < buffer.length) {
-      char = buffer[i];
-      if (char != " " && char != "\n" && char != "\r" && char != "\t") break;
-      i++;
-    }
-    if (i >= buffer.length) {
-      return false;
-    } else {
-      return char != "{";
-    }
-  }
-
-  // Returns the character length of the next json message in the
-  // buffer, or 0 if there is only a partial message in the buffer.
-  // The object value must start with '{' and continues to the
-  // matching '}'. No attempt is made to otherwise validate the contents
-  // as JSON. If it is invalid, a later JSON.decode() will fail.
-  int objectLength() {
-    int skipWhitespace(int index) {
-      while (index < buffer.length) {
-        String char = buffer[index];
-        if (char != " " && char != "\n" && char != "\r" && char != "\t") break;
-        index++;
-      }
-      return index;
-    }
-    int skipString(int index) {
-      assert(buffer[index - 1] == '"');
-      while (index < buffer.length) {
-        String char = buffer[index];
-        if (char == '"') return index + 1;
-        if (char == r'\') index++;
-        if (index == buffer.length) return index;
-        index++;
-      }
-      return index;
-    }
-    int index = 0;
-    index = skipWhitespace(index);
-    // Bail out if the first non-whitespace character isn't '{'.
-    if (index == buffer.length || buffer[index] != '{') return 0;
-    int nesting = 0;
-    while (index < buffer.length) {
-      String char = buffer[index++];
-      if (char == '{') {
-        nesting++;
-      } else if (char == '}') {
-        nesting--;
-        if (nesting == 0) return index;
-      } else if (char == '"') {
-        // Strings can contain braces. Skip their content.
-        index = skipString(index);
-      }
-    }
-    return 0;
-  }
-}
-
-
-void main(List<String> arguments) {
-  var targetOpts = [ "--debug:0" ];
-  for (String str in arguments) {
-    switch (str) {
-      case "--verbose":
-        showDebuggeeOutput = true;
-        break;
-      case "--wire":
-        verboseWire = true;
-        break;
-      default:
-        targetOpts.add(str);
-        break;
-    }
-  }
-
-  Process.start(Platform.executable, targetOpts).then((Process process) {
-    process.stdin.close();
-    debugger = new Debugger(process);
-  });
-}
diff --git a/tools/dart2js/angular2_testing_deps/CURRENT_ANGULAR_DEPS b/tools/dart2js/angular2_testing_deps/CURRENT_ANGULAR_DEPS
index 586e643..b797e77 100644
--- a/tools/dart2js/angular2_testing_deps/CURRENT_ANGULAR_DEPS
+++ b/tools/dart2js/angular2_testing_deps/CURRENT_ANGULAR_DEPS
@@ -1 +1 @@
-64bd9639a14afd83bf3f03ffe82825be2c8e940c
+e1d7bdcfe7f25156c8a462452db5367b68a02df6
diff --git a/tools/ddbg.dart b/tools/ddbg.dart
deleted file mode 100644
index f14a017..0000000
--- a/tools/ddbg.dart
+++ /dev/null
@@ -1,1496 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// Simple interactive debugger shell that connects to the Dart VM's debugger
-// connection port.
-
-import "dart:convert";
-import "dart:io";
-import "dart:async";
-import "dart:math";
-
-import "ddbg/lib/commando.dart";
-
-class TargetScript {
-  // The text of a script.
-  String source = null;
-
-  // A mapping from line number to source text.
-  List<String> lineToSource = null;
-
-  // A mapping from token offset to line number.
-  Map<int,int> tokenToLine = null;
-}
-
-const UnknownLocation = const {};
-
-class TargetIsolate {
-  int id;
-  // The location of the last paused event.
-  Map pausedLocation = null;
-
-  TargetIsolate(this.id);
-  bool get isPaused => pausedLocation != null;
-  String get pausedUrl => pausedLocation != null ? pausedLocation["url"] : null;
-
-  Map<String, TargetScript> scripts = {};
-}
-
-Map<int, TargetIsolate> targetIsolates= new Map<int, TargetIsolate>();
-
-Map<int, Completer> outstandingCommands;
-
-Socket vmSock;
-String vmData;
-var cmdSubscription;
-Commando cmdo;
-var vmSubscription;
-int seqNum = 0;
-
-bool isDebugging = false;
-Process targetProcess = null;
-bool suppressNextExitCode = false;
-
-final verbose = false;
-final printMessages = false;
-
-TargetIsolate currentIsolate;
-TargetIsolate mainIsolate;
-
-int debugPort = 5858;
-
-String formatLocation(Map location) {
-  if (location == null) return "";
-  var fileName = location["url"].split("/").last;
-  return "file: $fileName lib: ${location['libraryId']} token: ${location['tokenOffset']}";
-}
-
-
-Future sendCmd(Map<String, dynamic> cmd) {
-  var completer = new Completer.sync();
-  int id = cmd["id"];
-  outstandingCommands[id] = completer;
-  if (verbose) {
-    print("sending: '${JSON.encode(cmd)}'");
-  }
-  vmSock.write(JSON.encode(cmd));
-  return completer.future;
-}
-
-
-bool checkCurrentIsolate() {
-  if (vmSock == null) {
-    print("There is no active script.  Try 'help run'.");
-    return false;
-  }
-  if (currentIsolate == null) {
-    print('There is no current isolate.');
-    return false;
-  }
-  return true;
-}
-
-
-void setCurrentIsolate(TargetIsolate isolate) {
-  if (isolate != currentIsolate) {
-    currentIsolate = isolate;
-    if (mainIsolate == null) {
-      print("Main isolate is ${isolate.id}");
-      mainIsolate = isolate;
-    }
-    print("Current isolate is now ${isolate.id}");
-  }
-}
-
-
-bool checkPaused() {
-  if (!checkCurrentIsolate()) return false;
-  if (currentIsolate.isPaused) return true;
-  print("Current isolate must be paused");
-  return false;
-}
-
-// These settings are allowed in the 'set' and 'show' debugger commands.
-var validSettings = ['vm', 'vmargs', 'script', 'args'];
-
-// The current values for all settings.
-var settings = new Map();
-
-String _leftJustify(text, int width) {
-  StringBuffer buffer = new StringBuffer();
-  buffer.write(text);
-  while (buffer.length < width) {
-    buffer.write(' ');
-  }
-  return buffer.toString();
-}
-
-// TODO(turnidge): Move all commands here.
-List<Command> commandList =
-    [ new HelpCommand(),
-      new QuitCommand(),
-      new RunCommand(),
-      new KillCommand(),
-      new ConnectCommand(),
-      new DisconnectCommand(),
-      new SetCommand(),
-      new ShowCommand() ];
-
-
-List<Command> matchCommand(String commandName, bool exactMatchWins) {
-  List matches = [];
-  for (var command in commandList) {
-    if (command.name.startsWith(commandName)) {
-      if (exactMatchWins && command.name == commandName) {
-        // Exact match
-        return [command];
-      } else {
-        matches.add(command);
-      }
-    }
-  }
-  return matches;
-}
-
-abstract class Command {
-  String get name;
-  Future run(List<String> args);
-}
-
-class HelpCommand extends Command {
-  final name = 'help';
-  final helpShort = 'Show a list of debugger commands';
-  final helpLong ="""
-Show a list of debugger commands or get more information about a
-particular command.
-
-Usage:
-  help
-  help <command>
-""";
-
-  Future run(List<String> args) {
-    if (args.length == 1) {
-      print("Debugger commands:\n");
-      for (var command in commandList) {
-        print('  ${_leftJustify(command.name, 11)} ${command.helpShort}');
-      }
-
-      // TODO(turnidge): Convert all commands to use the Command class.
-      print("""
-  bt          Show backtrace
-  r           Resume execution
-  s           Single step
-  so          Step over
-  si          Step into
-  sbp [<file>] <line> Set breakpoint
-  rbp <id>    Remove breakpoint with given id
-  po <id>     Print object info for given id
-  eval fr  <n> <expr> Evaluate expr on stack frame index n
-  eval obj <id> <expr> Evaluate expr on object id
-  eval cls <id> <expr> Evaluate expr on class id
-  eval lib <id> <expr> Evaluate expr in toplevel of library id
-  pl <id> <idx> [<len>] Print list element/slice
-  pc <id>     Print class info for given id
-  ll          List loaded libraries
-  plib <id>   Print library info for given library id
-  slib <id> <true|false> Set library id debuggable
-  pg <id>     Print all global variables visible within given library id
-  ls <lib_id> List loaded scripts in library
-  gs <lib_id> <script_url> Get source text of script in library
-  tok <lib_id> <script_url> Get line and token table of script in library
-  epi <none|all|unhandled>  Set exception pause info
-  li          List ids of all isolates in the VM
-  sci <id>    Set current target isolate
-  i <id>      Interrupt execution of given isolate id
-""");
-
-      print("For more information about a particular command, type:\n\n"
-            "  help <command>\n");
-
-      print("Commands may be abbreviated: e.g. type 'h' for 'help.\n");
-    } else if (args.length == 2) {
-      var commandName = args[1];
-      var matches = matchCommand(commandName, true);
-      if (matches.length == 0) {
-        print("Command '$commandName' not recognized.  "
-              "Try 'help' for a list of commands.");
-      } else {
-        for (var command in matches) {
-          print("---- ${command.name} ----\n${command.helpLong}");
-        }
-      }
-    } else {
-      print("Command '$command' not recognized.  "
-            "Try 'help' for a list of commands.");
-    }
-
-    return new Future.value();
-  }
-}
-
-
-class QuitCommand extends Command {
-  final name = 'quit';
-  final helpShort = 'Quit the debugger.';
-  final helpLong ="""
-Quit the debugger.
-
-Usage:
-  quit
-""";
-
-  Future run(List<String> args) {
-    if (args.length > 1) {
-      print("Unexpected arguments to $name command.");
-      return new Future.value();
-    }
-    return debuggerQuit();
-  }
-}
-
-class SetCommand extends Command {
-  final name = 'set';
-  final helpShort = 'Change the value of a debugger setting.';
-  final helpLong ="""
-Change the value of a debugger setting.
-
-Usage:
-  set <setting> <value>
-
-Valid settings are:
-  ${validSettings.join('\n  ')}.
-
-See also 'help show'.
-""";
-
-  Future run(List<String> args) {
-    if (args.length < 3 || !validSettings.contains(args[1])) {
-      print("Undefined $name command.  Try 'help $name'.");
-      return new Future.value();
-    }
-    var option = args[1];
-    var value = args.getRange(2, args.length).join(' ');
-    settings[option] = value;
-    return new Future.value();
-  }
-}
-
-class ShowCommand extends Command {
-  final name = 'show';
-  final helpShort = 'Show the current value of a debugger setting.';
-  final helpLong ="""
-Show the current value of a debugger setting.
-
-Usage:
-  show
-  show <setting>
-
-If no <setting> is specified, all current settings are shown.
-
-Valid settings are:
-  ${validSettings.join('\n  ')}.
-
-See also 'help set'.
-""";
-
-  Future run(List<String> args) {
-    if (args.length == 1) {
-      for (var option in validSettings) {
-        var value = settings[option];
-        print("$option = '$value'");
-      }
-    } else if (args.length == 2 && validSettings.contains(args[1])) {
-      var option = args[1];
-      var value = settings[option];
-      if (value == null) {
-        print('$option has not been set.');
-      } else {
-        print("$option = '$value'");
-      }
-      return new Future.value();
-    } else {
-      print("Undefined $name command.  Try 'help $name'.");
-    }
-    return new Future.value();
-  }
-}
-
-class RunCommand extends Command {
-  final name = 'run';
-  final helpShort = "Run the currrent script.";
-  final helpLong ="""
-Runs the current script.
-
-Usage:
-  run
-  run <args>
-
-The current script will be run on the current vm.  The 'vm' and
-'vmargs' settings are used to specify the current vm and vm arguments.
-The 'script' and 'args' settings are used to specify the current
-script and script arguments.
-
-For more information on settings type 'help show' or 'help set'.
-
-If <args> are provided to the run command, it is the same as typing
-'set args <args>' followed by 'run'.
-""";
-
-  Future run(List<String> cmdArgs) {
-    if (isDebugging) {
-      // TODO(turnidge): Implement modal y/n dialog to stop running script.
-      print("There is already a running dart process.  "
-            "Try 'kill'.");
-      return new Future.value();
-    }
-    assert(targetProcess == null);
-    if (settings['script'] == null) {
-      print("There is no script specified.  "
-            "Use 'set script' to set the current script.");
-      return new Future.value();
-    }
-    if (cmdArgs.length > 1) {
-      settings['args'] = cmdArgs.getRange(1, cmdArgs.length);
-    }
-
-    // Build the process arguments.
-    var processArgs = ['--debug:$debugPort'];
-    if (verbose) {
-      processArgs.add('--verbose_debug');
-    }
-    if (settings['vmargs'] != null) {
-      processArgs.addAll(settings['vmargs'].split(' '));
-    }
-    processArgs.add(settings['script']);
-    if (settings['args'] != null) {
-      processArgs.addAll(settings['args'].split(' '));
-    }
-    String vm = settings['vm'];
-
-    isDebugging = true;
-    cmdo.hide();
-    return Process.start(vm, processArgs).then((process) {
-        print("Started process ${process.pid} '$vm ${processArgs.join(' ')}'");
-        targetProcess = process;
-        process.stdin.close();
-
-        // TODO(turnidge): For now we only show full lines of output
-        // from the debugged process.  Should show each character.
-        process.stdout
-            .transform(UTF8.decoder)
-            .transform(new LineSplitter())
-            .listen((String line) {
-                cmdo.hide();
-                // TODO(turnidge): Escape output in any way?
-                print(line);
-                cmdo.show();
-              });
-
-        process.stderr
-            .transform(UTF8.decoder)
-            .transform(new LineSplitter())
-            .listen((String line) {
-                cmdo.hide();
-                print(line);
-                cmdo.show();
-              });
-
-        process.exitCode.then((int exitCode) {
-            cmdo.hide();
-            if (suppressNextExitCode) {
-              suppressNextExitCode = false;
-            } else {
-              if (exitCode == 0) {
-                print('Process exited normally.');
-              } else {
-                print('Process exited with code $exitCode.');
-              }
-            }
-            targetProcess = null;
-            cmdo.show();
-          });
-
-        // Wait for the vm to open the debugging port.
-        return openVmSocket(0);
-      });
-  }
-}
-
-class KillCommand extends Command {
-  final name = 'kill';
-  final helpShort = 'Kill the currently executing script.';
-  final helpLong ="""
-Kill the currently executing script.
-
-Usage:
-  kill
-""";
-
-  Future run(List<String> cmdArgs) {
-    if (!isDebugging) {
-      print('There is no running script.');
-      return new Future.value();
-    }
-    if (targetProcess == null) {
-      print("The active dart process was not started with 'run'. "
-            "Try 'disconnect' instead.");
-      return new Future.value();
-    }
-    assert(targetProcess != null);
-    bool result = targetProcess.kill();
-    if (result) {
-      print('Process killed.');
-      suppressNextExitCode = true;
-    } else {
-      print('Unable to kill process ${targetProcess.pid}');
-    }
-    return new Future.value();
-  }
-}
-
-class ConnectCommand extends Command {
-  final name = 'connect';
-  final helpShort = "Connect to a running dart script.";
-  final helpLong ="""
-Connect to a running dart script.
-
-Usage:
-  connect
-  connect <port>
-
-The debugger will connect to a dart script which has already been
-started with the --debug option.  If no port is provided, the debugger
-will attempt to connect on the default debugger port.
-""";
-
-  Future run(List<String> cmdArgs) {
-    if (cmdArgs.length > 2) {
-      print("Too many arguments to 'connect'.");
-    }
-    if (isDebugging) {
-      // TODO(turnidge): Implement modal y/n dialog to stop running script.
-      print("There is already a running dart process.  "
-            "Try 'kill'.");
-      return new Future.value();
-    }
-    assert(targetProcess == null);
-    if (cmdArgs.length == 2) {
-      debugPort = int.parse(cmdArgs[1]);
-    }
-
-    isDebugging = true;
-    cmdo.hide();
-    return openVmSocket(0);
-  }
-}
-
-class DisconnectCommand extends Command {
-  final name = 'disconnect';
-  final helpShort = "Disconnect from a running dart script.";
-  final helpLong ="""
-Disconnect from a running dart script.
-
-Usage:
-  disconnect
-
-The debugger will disconnect from a dart script's debugging port.  The
-script must have been connected to earlier with the 'connect' command.
-""";
-
-  Future run(List<String> cmdArgs) {
-    if (cmdArgs.length > 1) {
-      print("Too many arguments to 'disconnect'.");
-    }
-    if (!isDebugging) {
-      // TODO(turnidge): Implement modal y/n dialog to stop running script.
-      print("There is no active dart process.  "
-            "Try 'connect'.");
-      return new Future.value();
-    }
-    if (targetProcess != null) {
-      print("The active dart process was started with 'run'.  "
-            "Try 'kill'.");
-    }
-
-    cmdo.hide();
-    return closeVmSocket();
-  }
-}
-
-typedef void HandlerType(Map response);
-
-HandlerType showPromptAfter(void handler(Map response)) {
-  return (response) {
-    handler(response);
-    cmdo.show();
-  };
-}
-
-void processCommand(String cmdLine) {
-  void huh() {
-    print("'$cmdLine' not understood, try 'help' for help.");
-  }
-
-  cmdo.hide();
-  seqNum++;
-  cmdLine = cmdLine.trim();
-  var args = cmdLine.split(' ');
-  if (args.length == 0) {
-    return;
-  }
-  var command = args[0];
-
-  var resume_commands =
-      { 'r':'resume', 's':'stepOver', 'si':'stepInto', 'so':'stepOut'};
-  if (resume_commands[command] != null) {
-    if (!checkPaused()) {
-      cmdo.show();
-      return;
-    }
-    var cmd = { "id": seqNum,
-                "command": resume_commands[command],
-                "params": { "isolateId" : currentIsolate.id } };
-    sendCmd(cmd).then(showPromptAfter(handleResumedResponse));
-  } else if (command == "bt") {
-    if (!checkCurrentIsolate()) {
-      cmdo.show();
-      return;
-    }
-    var cmd = { "id": seqNum,
-                "command": "getStackTrace",
-                "params": { "isolateId" : currentIsolate.id } };
-    sendCmd(cmd).then(showPromptAfter(handleStackTraceResponse));
-  } else if (command == "ll") {
-    if (!checkCurrentIsolate()) {
-      cmdo.show();
-      return;
-    }
-    var cmd = { "id": seqNum,
-                "command": "getLibraries",
-                "params": { "isolateId" : currentIsolate.id } };
-    sendCmd(cmd).then(showPromptAfter(handleGetLibraryResponse));
-  } else if (command == "sbp" && args.length >= 2) {
-    if (!checkCurrentIsolate()) {
-      cmdo.show();
-      return;
-    }
-    var url, line;
-    if (args.length == 2 && currentIsolate.pausedUrl != null) {
-      url = currentIsolate.pausedUrl;
-      line = int.parse(args[1]);
-    } else {
-      url = args[1];
-      line = int.parse(args[2]);
-    }
-    var cmd = { "id": seqNum,
-                "command": "setBreakpoint",
-                "params": { "isolateId" : currentIsolate.id,
-                            "url": url,
-                            "line": line }};
-    sendCmd(cmd).then(showPromptAfter(handleSetBpResponse));
-  } else if (command == "rbp" && args.length == 2) {
-    if (!checkCurrentIsolate()) {
-      cmdo.show();
-      return;
-    }
-    var cmd = { "id": seqNum,
-                "command": "removeBreakpoint",
-                "params": { "isolateId" : currentIsolate.id,
-                            "breakpointId": int.parse(args[1]) } };
-    sendCmd(cmd).then(showPromptAfter(handleGenericResponse));
-  } else if (command == "ls" && args.length == 2) {
-    if (!checkCurrentIsolate()) {
-      cmdo.show();
-      return;
-    }
-    var cmd = { "id": seqNum,
-                "command": "getScriptURLs",
-                "params": { "isolateId" : currentIsolate.id,
-                            "libraryId": int.parse(args[1]) } };
-    sendCmd(cmd).then(showPromptAfter(handleGetScriptsResponse));
-  } else if (command == "eval" && args.length > 3) {
-    if (!checkCurrentIsolate()) {
-      cmdo.show();
-      return;
-    }
-    var expr = args.getRange(3, args.length).join(" ");
-    var target = args[1];
-    if (target == "obj") {
-      target = "objectId";
-    } else if (target == "cls") {
-      target = "classId";
-    } else if (target == "lib") {
-      target = "libraryId";
-    } else if (target == "fr") {
-      target = "frameId";
-    } else {
-      huh();
-      return;
-    }
-    var cmd = { "id": seqNum,
-                "command": "evaluateExpr",
-                "params": { "isolateId": currentIsolate.id,
-                            target: int.parse(args[2]),
-                            "expression": expr } };
-    sendCmd(cmd).then(showPromptAfter(handleEvalResponse));
-  } else if (command == "po" && args.length == 2) {
-    if (!checkCurrentIsolate()) {
-      cmdo.show();
-      return;
-    }
-    var cmd = { "id": seqNum,
-                "command": "getObjectProperties",
-                "params": { "isolateId" : currentIsolate.id,
-                            "objectId": int.parse(args[1]) } };
-    sendCmd(cmd).then(showPromptAfter(handleGetObjPropsResponse));
-  } else if (command == "pl" && args.length >= 3) {
-    if (!checkCurrentIsolate()) {
-      cmdo.show();
-      return;
-    }
-    var cmd;
-    if (args.length == 3) {
-      cmd = { "id": seqNum,
-              "command": "getListElements",
-              "params": { "isolateId" : currentIsolate.id,
-                          "objectId": int.parse(args[1]),
-                          "index": int.parse(args[2]) } };
-    } else {
-      cmd = { "id": seqNum,
-              "command": "getListElements",
-              "params": { "isolateId" : currentIsolate.id,
-                          "objectId": int.parse(args[1]),
-                          "index": int.parse(args[2]),
-                          "length": int.parse(args[3]) } };
-    }
-    sendCmd(cmd).then(showPromptAfter(handleGetListResponse));
-  } else if (command == "pc" && args.length == 2) {
-    if (!checkCurrentIsolate()) {
-      cmdo.show();
-      return;
-    }
-    var cmd = { "id": seqNum,
-                "command": "getClassProperties",
-                "params": { "isolateId" : currentIsolate.id,
-                            "classId": int.parse(args[1]) } };
-    sendCmd(cmd).then(showPromptAfter(handleGetClassPropsResponse));
-  } else if (command == "plib" && args.length == 2) {
-    if (!checkCurrentIsolate()) {
-      cmdo.show();
-      return;
-    }
-    var cmd = { "id": seqNum,
-                "command": "getLibraryProperties",
-                "params": {"isolateId" : currentIsolate.id,
-                           "libraryId": int.parse(args[1]) } };
-    sendCmd(cmd).then(showPromptAfter(handleGetLibraryPropsResponse));
-  } else if (command == "slib" && args.length == 3) {
-    if (!checkCurrentIsolate()) {
-      cmdo.show();
-      return;
-    }
-    var cmd = { "id": seqNum,
-                "command": "setLibraryProperties",
-                "params": {"isolateId" : currentIsolate.id,
-                           "libraryId": int.parse(args[1]),
-                           "debuggingEnabled": args[2] } };
-    sendCmd(cmd).then(showPromptAfter(handleSetLibraryPropsResponse));
-  } else if (command == "pg" && args.length == 2) {
-    if (!checkCurrentIsolate()) {
-      cmdo.show();
-      return;
-    }
-    var cmd = { "id": seqNum,
-                "command": "getGlobalVariables",
-                "params": { "isolateId" : currentIsolate.id,
-                            "libraryId": int.parse(args[1]) } };
-    sendCmd(cmd).then(showPromptAfter(handleGetGlobalVarsResponse));
-  } else if (command == "gs" && args.length == 3) {
-    if (!checkCurrentIsolate()) {
-      cmdo.show();
-      return;
-    }
-    var cmd = { "id": seqNum,
-                "command":  "getScriptSource",
-                "params": { "isolateId" : currentIsolate.id,
-                            "libraryId": int.parse(args[1]),
-                            "url": args[2] } };
-    sendCmd(cmd).then(showPromptAfter(handleGetSourceResponse));
-  } else if (command == "tok" && args.length == 3) {
-    if (!checkCurrentIsolate()) {
-      cmdo.show();
-      return;
-    }
-    var cmd = { "id": seqNum,
-                "command":  "getLineNumberTable",
-                "params": { "isolateId" : currentIsolate.id,
-                            "libraryId": int.parse(args[1]),
-                            "url": args[2] } };
-    sendCmd(cmd).then(showPromptAfter(handleGetLineTableResponse));
-  } else if (command == "epi" && args.length == 2) {
-    if (!checkCurrentIsolate()) {
-      cmdo.show();
-      return;
-    }
-    var cmd = { "id": seqNum,
-                "command":  "setPauseOnException",
-                "params": { "isolateId" : currentIsolate.id,
-                            "exceptions": args[1] } };
-    sendCmd(cmd).then(showPromptAfter(handleGenericResponse));
-  } else if (command == "li") {
-    if (!checkCurrentIsolate()) {
-      cmdo.show();
-      return;
-    }
-    var cmd = { "id": seqNum, "command": "getIsolateIds" };
-    sendCmd(cmd).then(showPromptAfter(handleGetIsolatesResponse));
-  } else if (command == "sci" && args.length == 2) {
-    var id = int.parse(args[1]);
-    if (targetIsolates[id] != null) {
-      setCurrentIsolate(targetIsolates[id]);
-    } else {
-      print("$id is not a valid isolate id");
-    }
-    cmdo.show();
-  } else if (command == "i" && args.length == 2) {
-    var cmd = { "id": seqNum,
-                "command": "interrupt",
-                "params": { "isolateId": int.parse(args[1]) } };
-    sendCmd(cmd).then(showPromptAfter(handleGenericResponse));
-  } else if (command.length == 0) {
-    huh();
-    cmdo.show();
-  } else {
-    // TODO(turnidge): Use this for all commands.
-    var matches = matchCommand(command, true);
-    if (matches.length == 0) {
-      huh();
-      cmdo.show();
-    } else if (matches.length == 1) {
-      matches[0].run(args).then((_) {
-          cmdo.show();
-        });
-    } else {
-      var matchNames = matches.map((handler) => handler.name);
-      print("Ambiguous command '$command' : ${matchNames.toList()}");
-      cmdo.show();
-    }
-  }
-}
-
-
-void processError(error, trace) {
-  cmdo.hide();
-  print("\nInternal error:\n$error\n$trace");
-  cmdo.show();
-}
-
-
-void processDone() {
-  debuggerQuit();
-}
-
-
-String remoteObject(value) {
-  var kind = value["kind"];
-  var text = value["text"];
-  var id = value["objectId"];
-  if (kind == "string") {
-    return "(string, id $id) '$text'";
-  } else if (kind == "list") {
-    var len = value["length"];
-    return "(list, id $id, len $len) $text";
-  } else if (kind == "object") {
-    return "(obj, id $id) $text";
-  } else if (kind == "function") {
-    var location = formatLocation(value['location']);
-    var name = value['name'];
-    var signature = value['signature'];
-    return "(closure ${name}${signature} $location)";
-  } else {
-    return "$text";
-  }
-}
-
-
-printNamedObject(obj) {
-  var name = obj["name"];
-  var value = obj["value"];
-  print("  $name = ${remoteObject(value)}");
-}
-
-
-handleGetObjPropsResponse(Map response) {
-  Map props = response["result"];
-  int class_id = props["classId"];
-  if (class_id == -1) {
-    print("  null");
-    return;
-  }
-  List fields = props["fields"];
-  print("  class id: $class_id");
-  for (int i = 0; i < fields.length; i++) {
-    printNamedObject(fields[i]);
-  }
-}
-
-handleGetListResponse(Map response) {
-  Map result = response["result"];
-  if (result["elements"] != null) {
-    // List slice.
-    var index = result["index"];
-    var length = result["length"];
-    List elements = result["elements"];
-    assert(length == elements.length);
-    for (int i = 0; i < length; i++) {
-      var kind = elements[i]["kind"];
-      var text = elements[i]["text"];
-      print("  ${index + i}: ($kind) $text");
-    }
-  } else {
-    // One element, a remote object.
-    print(result);
-    print("  ${remoteObject(result)}");
-  }
-}
-
-
-handleGetClassPropsResponse(Map response) {
-  Map props = response["result"];
-  assert(props["name"] != null);
-  int libId = props["libraryId"];
-  assert(libId != null);
-  print("  class ${props["name"]} (library id: $libId)");
-  List fields = props["fields"];
-  if (fields.length > 0) {
-    print("  static fields:");
-    for (int i = 0; i < fields.length; i++) {
-      printNamedObject(fields[i]);
-    }
-  }
-}
-
-
-handleGetLibraryPropsResponse(Map response) {
-  Map props = response["result"];
-  assert(props["url"] != null);
-  print("  library url: ${props["url"]}");
-  assert(props["debuggingEnabled"] != null);
-  print("  debugging enabled: ${props["debuggingEnabled"]}");
-  List imports = props["imports"];
-  assert(imports != null);
-  if (imports.length > 0) {
-    print("  imports:");
-    for (int i = 0; i < imports.length; i++) {
-      print("    id ${imports[i]["libraryId"]} prefix ${imports[i]["prefix"]}");
-    }
-  }
-  List globals = props["globals"];
-  assert(globals != null);
-  if (globals.length > 0) {
-    print("  global variables:");
-    for (int i = 0; i < globals.length; i++) {
-      printNamedObject(globals[i]);
-    }
-  }
-}
-
-
-handleSetLibraryPropsResponse(Map response) {
-  Map props = response["result"];
-  assert(props["debuggingEnabled"] != null);
-  print("  debugging enabled: ${props["debuggingEnabled"]}");
-}
-
-
-handleGetGlobalVarsResponse(Map response) {
-  List globals = response["result"]["globals"];
-  for (int i = 0; i < globals.length; i++) {
-    printNamedObject(globals[i]);
-  }
-}
-
-
-handleGetSourceResponse(Map response) {
-  Map result = response["result"];
-  String source = result["text"];
-  print("Source text:\n$source\n--------");
-}
-
-
-handleGetLineTableResponse(Map response) {
-  Map result = response["result"];
-  var info = result["lines"];
-  print("Line info table:\n$info");
-}
-
-
-void handleGetIsolatesResponse(Map response) {
-  Map result = response["result"];
-  List ids = result["isolateIds"];
-  assert(ids != null);
-  print("List of isolates:");
-  for (int id in ids) {
-    TargetIsolate isolate = targetIsolates[id];
-    var state = (isolate != null) ? "running" : "<unknown isolate>";
-    if (isolate != null && isolate.isPaused) {
-      var loc = formatLocation(isolate.pausedLocation);
-      state = "paused at $loc";
-    }
-    var marker = " ";
-    if (currentIsolate != null && id == currentIsolate.id) {
-      marker = "*";
-    }
-    print("$marker $id $state");
-  }
-}
-
-
-void handleGetLibraryResponse(Map response) {
-  Map result = response["result"];
-  List libs = result["libraries"];
-  print("Loaded libraries:");
-  print(libs);
-  for (int i = 0; i < libs.length; i++) {
-    print("  ${libs[i]["id"]} ${libs[i]["url"]}");
-  }
-}
-
-
-void handleGetScriptsResponse(Map response) {
-  Map result = response["result"];
-  List urls = result["urls"];
-  print("Loaded scripts:");
-  for (int i = 0; i < urls.length; i++) {
-    print("  $i ${urls[i]}");
-  }
-}
-
-
-void handleEvalResponse(Map response) {
-  Map result = response["result"];
-  print(remoteObject(result));
-}
-
-
-void handleSetBpResponse(Map response) {
-  Map result = response["result"];
-  var id = result["breakpointId"];
-  assert(id != null);
-  print("Set BP $id");
-}
-
-
-void handleGenericResponse(Map response) {
-  if (response["error"] != null) {
-    print("Error: ${response["error"]}");
-  }
-}
-
-void handleResumedResponse(Map response) {
-  if (response["error"] != null) {
-    print("Error: ${response["error"]}");
-    return;
-  }
-  assert(currentIsolate != null);
-  currentIsolate.pausedLocation = null;
-}
-
-
-void handleStackTraceResponse(Map response) {
-  Map result = response["result"];
-  List callFrames = result["callFrames"];
-  assert(callFrames != null);
-  printStackTrace(callFrames);
-}
-
-
-void printStackFrame(frame_num, Map frame) {
-  var fname = frame["functionName"];
-  var loc = formatLocation(frame["location"]);
-  print("#${_leftJustify(frame_num,2)} $fname at $loc");
-  List locals = frame["locals"];
-  for (int i = 0; i < locals.length; i++) {
-    printNamedObject(locals[i]);
-  }
-}
-
-
-void printStackTrace(List frames) {
-  for (int i = 0; i < frames.length; i++) {
-    printStackFrame(i, frames[i]);
-  }
-}
-
-
-Map<int, int> parseLineNumberTable(List<List<int>> table) {
-  Map tokenToLine = {};
-  for (var line in table) {
-    // Each entry begins with a line number...
-    var lineNumber = line[0];
-    for (var pos = 1; pos < line.length; pos += 2) {
-      // ...and is followed by (token offset, col number) pairs.
-      // We ignore the column numbers.
-      var tokenOffset = line[pos];
-      tokenToLine[tokenOffset] = lineNumber;
-    }
-  }
-  return tokenToLine;
-}
-
-
-Future<TargetScript> getTargetScript(Map location) {
-  var isolate = targetIsolates[currentIsolate.id];
-  var url = location['url'];
-  var script = isolate.scripts[url];
-  if (script != null) {
-    return new Future.value(script);
-  }
-  script = new TargetScript();
-
-  // Ask the vm for the source and line number table.
-  var sourceCmd = {
-    "id": seqNum++,
-    "command":  "getScriptSource",
-    "params": { "isolateId": currentIsolate.id,
-                "libraryId": location['libraryId'],
-                "url": url } };
-
-  var lineNumberCmd = {
-    "id": seqNum++,
-    "command":  "getLineNumberTable",
-    "params": { "isolateId": currentIsolate.id,
-                "libraryId": location['libraryId'],
-                "url": url } };
-
-  // Send the source command
-  var sourceResponse = sendCmd(sourceCmd).then((response) {
-      Map result = response["result"];
-      script.source = result['text'];
-      // Line numbers are 1-based so add a dummy for line 0.
-      script.lineToSource = [''];
-      script.lineToSource.addAll(script.source.split('\n'));
-    });
-
-  // Send the line numbers command
-  var lineNumberResponse = sendCmd(lineNumberCmd).then((response) {
-      Map result = response["result"];
-      script.tokenToLine = parseLineNumberTable(result['lines']);
-    });
-
-  return Future.wait([sourceResponse, lineNumberResponse]).then((_) {
-      // When both commands complete, cache the result.
-      isolate.scripts[url] = script;
-      return script;
-    });
-}
-
-
-Future printLocation(String label, Map location) {
-  // Figure out the line number.
-  return getTargetScript(location).then((script) {
-      var lineNumber = script.tokenToLine[location['tokenOffset']];
-      var text = script.lineToSource[lineNumber];
-      if (label != null) {
-        var fileName = location['url'].split("/").last;
-        print("$label \n"
-              "    at $fileName:$lineNumber");
-      }
-      print("${_leftJustify(lineNumber, 8)}$text");
-    });
-}
-
-
-Future handlePausedEvent(msg) {
-  assert(msg["params"] != null);
-  var reason = msg["params"]["reason"];
-  int isolateId = msg["params"]["isolateId"];
-  assert(isolateId != null);
-  var isolate = targetIsolates[isolateId];
-  assert(isolate != null);
-  assert(!isolate.isPaused);
-  var location = msg["params"]["location"];;
-  setCurrentIsolate(isolate);
-  isolate.pausedLocation = (location == null) ? UnknownLocation : location;
-  if (reason == "breakpoint") {
-    assert(location != null);
-    var bpId = (msg["params"]["breakpointId"]);
-    var label = (bpId != null) ? "Breakpoint $bpId" : null;
-    return printLocation(label, location);
-  } else if (reason == "interrupted") {
-    assert(location != null);
-    return printLocation("Interrupted", location);
-  } else {
-    assert(reason == "exception");
-    var excObj = msg["params"]["exception"];
-    print("Isolate $isolateId paused on exception");
-    print(remoteObject(excObj));
-    return new Future.value();
-  }
-}
-
-void handleIsolateEvent(msg) {
-  Map params = msg["params"];
-  assert(params != null);
-  var isolateId = params["id"];
-  var reason = params["reason"];
-  if (reason == "created") {
-    print("Isolate $isolateId has been created.");
-    assert(targetIsolates[isolateId] == null);
-    targetIsolates[isolateId] = new TargetIsolate(isolateId);
-  } else {
-    assert(reason == "shutdown");
-    var isolate = targetIsolates.remove(isolateId);
-    assert(isolate != null);
-    if (isolate == mainIsolate) {
-      mainIsolate = null;
-      print("Main isolate ${isolate.id} has terminated.");
-    } else {
-      print("Isolate ${isolate.id} has terminated.");
-    }
-    if (isolate == currentIsolate) {
-      currentIsolate = mainIsolate;
-      if (currentIsolate == null && !targetIsolates.isEmpty) {
-        currentIsolate = targetIsolates.values.first;
-      }
-      if (currentIsolate != null) {
-        print("Setting current isolate to ${currentIsolate.id}.");
-      } else {
-        print("All isolates have terminated.");
-      }
-    }
-  }
-}
-
-void processVmMessage(String jsonString) {
-  var msg = JSON.decode(jsonString);
-  if (msg == null) {
-    return;
-  }
-  var event = msg["event"];
-  if (event == "isolate") {
-    cmdo.hide();
-    handleIsolateEvent(msg);
-    cmdo.show();
-    return;
-  }
-  if (event == "paused") {
-    cmdo.hide();
-    handlePausedEvent(msg).then((_) {
-        cmdo.show();
-      });
-    return;
-  }
-  if (event == "breakpointResolved") {
-    Map params = msg["params"];
-    assert(params != null);
-    var isolateId = params["isolateId"];
-    var location = formatLocation(params["location"]);
-    cmdo.hide();
-    print("Breakpoint ${params["breakpointId"]} resolved in isolate $isolateId"
-          " at $location.");
-    cmdo.show();
-    return;
-  }
-  if (msg["id"] != null) {
-    var id = msg["id"];
-    if (outstandingCommands.containsKey(id)) {
-      var completer = outstandingCommands.remove(id);
-      if (msg["error"] != null) {
-        print("VM says: ${msg["error"]}");
-        // TODO(turnidge): Rework how hide/show happens.  For now we
-        // show here explicitly.
-        cmdo.show();
-      } else {
-        completer.complete(msg);
-      }
-    }
-  }
-}
-
-bool haveGarbageVmData() {
-  if (vmData == null || vmData.length == 0) return false;
-  var i = 0, char = " ";
-  while (i < vmData.length) {
-    char = vmData[i];
-    if (char != " " && char != "\n" && char != "\r" && char != "\t") break;
-    i++;
-  }
-  if (i >= vmData.length) {
-    return false;
-  } else {
-    return char != "{";
-  }
-}
-
-
-void processVmData(String data) {
-  if (vmData == null || vmData.length == 0) {
-    vmData = data;
-  } else {
-    vmData = vmData + data;
-  }
-  if (haveGarbageVmData()) {
-    print("Error: have garbage data from VM: '$vmData'");
-    return;
-  }
-  int msg_len = jsonObjectLength(vmData);
-  if (printMessages && msg_len == 0) {
-    print("have partial or illegal json message"
-          " of ${vmData.length} chars:\n'$vmData'");
-    return;
-  }
-  while (msg_len > 0 && msg_len <= vmData.length) {
-    if (msg_len == vmData.length) {
-      if (printMessages) { print("have one full message:\n$vmData"); }
-      processVmMessage(vmData);
-      vmData = null;
-      return;
-    }
-    if (printMessages) { print("at least one message: '$vmData'"); }
-    var msg = vmData.substring(0, msg_len);
-    if (printMessages) { print("first message: $msg"); }
-    vmData = vmData.substring(msg_len);
-    if (haveGarbageVmData()) {
-      print("Error: garbage data after previous message: '$vmData'");
-      print("Previous message was: '$msg'");
-      return;
-    }
-    processVmMessage(msg);
-    msg_len = jsonObjectLength(vmData);
-  }
-  if (printMessages) { print("leftover vm data '$vmData'"); }
-}
-
-/**
- * Skip past a JSON object value.
- * The object value must start with '{' and continues to the
- * matching '}'. No attempt is made to otherwise validate the contents
- * as JSON. If it is invalid, a later [parseJson] will fail.
- */
-int jsonObjectLength(String string) {
-  int skipWhitespace(int index) {
-    while (index < string.length) {
-      String char = string[index];
-      if (char != " " && char != "\n" && char != "\r" && char != "\t") break;
-      index++;
-    }
-    return index;
-  }
-  int skipString(int index) {
-    assert(string[index - 1] == '"');
-    while (index < string.length) {
-      String char = string[index];
-      if (char == '"') return index + 1;
-      if (char == r'\') index++;
-      if (index == string.length) return index;
-      index++;
-    }
-    return index;
-  }
-  int index = 0;
-  index = skipWhitespace(index);
-  // Bail out if the first non-whitespace character isn't '{'.
-  if (index == string.length || string[index] != '{') return 0;
-  int nesting = 0;
-  while (index < string.length) {
-    String char = string[index++];
-    if (char == '{') {
-      nesting++;
-    } else if (char == '}') {
-      nesting--;
-      if (nesting == 0) return index;
-    } else if (char == '"') {
-      // Strings can contain braces. Skip their content.
-      index = skipString(index);
-    }
-  }
-  return 0;
-}
-
-List<String> debuggerCommandCompleter(List<String> commandParts) {
-  List<String> completions = new List<String>();
-
-  // TODO(turnidge): Have a global command table and use it to for
-  // help messages, command completion, and command dispatching.  For now
-  // we hardcode the list here.
-  //
-  // TODO(turnidge): Implement completion for arguments as well.
-  List<String> oldCommands = ['bt', 'r', 's', 'so', 'si', 'sbp', 'rbp',
-                              'po', 'eval', 'pl', 'pc', 'll', 'plib', 'slib',
-                              'pg', 'ls', 'gs', 'tok', 'epi', 'li', 'i' ];
-
-  // Completion of first word in the command.
-  if (commandParts.length == 1) {
-    String prefix = commandParts.last;
-    for (var command in oldCommands) {
-      if (command.startsWith(prefix)) {
-        completions.add(command);
-      }
-    }
-    for (var command in commandList) {
-      if (command.name.startsWith(prefix)) {
-        completions.add(command.name);
-      }
-    }
-  }
-
-  return completions;
-}
-
-Future closeCommando() {
-  var subscription = cmdSubscription;
-  cmdSubscription = null;
-  cmdo = null;
-
-  var future = subscription.cancel();
-  if (future != null) {
-    return future;
-  } else {
-    return new Future.value();
-  }
-}
-
-
-Future openVmSocket(int attempt) {
-  return Socket.connect("127.0.0.1", debugPort).then(
-      setupVmSocket,
-      onError: (e) {
-        // We were unable to connect to the debugger's port.  Try again.
-        retryOpenVmSocket(e, attempt);
-      });
-}
-
-
-void setupVmSocket(Socket s) {
-  vmSock = s;
-  vmSock.setOption(SocketOption.TCP_NODELAY, true);
-  var stringStream = vmSock.transform(UTF8.decoder);
-  outstandingCommands = new Map<int, Completer>();
-  vmSubscription = stringStream.listen(
-      (String data) {
-        processVmData(data);
-      },
-      onDone: () {
-        cmdo.hide();
-        if (verbose) {
-          print("VM debugger connection closed");
-        }
-        closeVmSocket().then((_) {
-            cmdo.show();
-          });
-      },
-      onError: (err) {
-        cmdo.hide();
-        // TODO(floitsch): do we want to print the stack trace?
-        print("Error in debug connection: $err");
-
-        // TODO(turnidge): Kill the debugged process here?
-        closeVmSocket().then((_) {
-            cmdo.show();
-          });
-      });
-}
-
-
-Future retryOpenVmSocket(error, int attempt) {
-  var delay;
-  if (attempt < 10) {
-    delay = new Duration(milliseconds:10);
-  } else if (attempt < 20) {
-    delay = new Duration(seconds:1);
-  } else {
-    // Too many retries.  Give up.
-    //
-    // TODO(turnidge): Kill the debugged process here?
-    print('Timed out waiting for debugger to start.\nError: $e');
-    return closeVmSocket();
-  }
-  // Wait and retry.
-  return new Future.delayed(delay, () {
-      openVmSocket(attempt + 1);
-    });
-}
-
-
-Future closeVmSocket() {
-  if (vmSubscription == null) {
-    // Already closed, nothing to do.
-    assert(vmSock == null);
-    return new Future.value();
-  }
-
-  isDebugging = false;
-  var subscription = vmSubscription;
-  var sock = vmSock;
-
-  // Wait for the socket to close and the subscription to be
-  // cancelled.  Perhaps overkill, but it means we know these will be
-  // done.
-  //
-  // This is uglier than it needs to be since cancel can return null.
-  var cleanupFutures = [sock.close()];
-  var future = subscription.cancel();
-  if (future != null) {
-    cleanupFutures.add(future);
-  }
-
-  vmSubscription = null;
-  vmSock = null;
-  outstandingCommands = null;
-  return Future.wait(cleanupFutures);
-}
-
-void debuggerError(self, parent, zone, error, StackTrace trace) {
-  print('\n--------\nExiting due to unexpected error:\n'
-        '  $error\n$trace\n');
-  debuggerQuit();
-}
-
-Future debuggerQuit() {
-  // Kill target process, if any.
-  if (targetProcess != null) {
-    if (!targetProcess.kill()) {
-      print('Unable to kill process ${targetProcess.pid}');
-    }
-  }
-
-  // Restore terminal settings, close connections.
-  return Future.wait([closeCommando(), closeVmSocket()]).then((_) {
-      exit(0);
-
-      // Unreachable.
-      return new Future.value();
-    });
-}
-
-
-void parseArgs(List<String> args) {
-  int pos = 0;
-  settings['vm'] = Platform.executable;
-  while (pos < args.length && args[pos].startsWith('-')) {
-    pos++;
-  }
-  if (pos < args.length) {
-    settings['vmargs'] = args.getRange(0, pos).join(' ');
-    settings['script'] = args[pos];
-    settings['args'] = args.getRange(pos + 1, args.length).join(' ');
-  }
-}
-
-void main(List<String> args) {
-  // Setup a zone which will exit the debugger cleanly on any uncaught
-  // exception.
-  var zone = Zone.ROOT.fork(specification:new ZoneSpecification(
-      handleUncaughtError: debuggerError));
-
-  zone.run(() {
-      parseArgs(args);
-      cmdo = new Commando(completer: debuggerCommandCompleter);
-      cmdSubscription = cmdo.commands.listen(processCommand,
-                                             onError: processError,
-                                             onDone: processDone);
-    });
-}
diff --git a/tools/ddbg/lib/commando.dart b/tools/ddbg/lib/commando.dart
deleted file mode 100644
index f3ff3ea..0000000
--- a/tools/ddbg/lib/commando.dart
+++ /dev/null
@@ -1,731 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:convert';
-import 'dart:io';
-import 'dart:math';
-
-import 'terminfo.dart';
-
-typedef List<String> CommandCompleter(List<String> commandParts);
-
-class Commando {
-  // Ctrl keys
-  static const runeCtrlA   = 0x01;
-  static const runeCtrlB   = 0x02;
-  static const runeCtrlD   = 0x04;
-  static const runeCtrlE   = 0x05;
-  static const runeCtrlF   = 0x06;
-  static const runeTAB     = 0x09;
-  static const runeNewline = 0x0a;
-  static const runeCtrlK   = 0x0b;
-  static const runeCtrlL   = 0x0c;
-  static const runeCtrlN   = 0x0e;
-  static const runeCtrlP   = 0x10;
-  static const runeCtrlU   = 0x15;
-  static const runeCtrlY   = 0x19;
-  static const runeESC     = 0x1b;
-  static const runeSpace   = 0x20;
-  static const runeDEL     = 0x7F;
-
-  StreamController<String> _commandController;
-
-  Stream get commands => _commandController.stream;
-
-  Commando({consoleIn,
-            consoleOut,
-            this.prompt : '> ',
-          this.completer : null}) {
-    _stdin = (consoleIn != null ? consoleIn : stdin);
-    _stdout = (consoleOut != null ? consoleOut : stdout);
-    _commandController = new StreamController<String>(
-        onCancel: _onCancel);
-    _stdin.echoMode = false;
-    _stdin.lineMode = false;
-    _screenWidth = _term.cols - 1;
-    _writePrompt();
-    // TODO(turnidge): Handle errors in _stdin here.
-    _stdinSubscription =
-        _stdin.transform(UTF8.decoder).listen(_handleText, onDone:_done);
-  }
-
-  Future _onCancel() {
-    _stdin.echoMode = true;
-    _stdin.lineMode = true;
-    var future = _stdinSubscription.cancel();
-    if (future != null) {
-      return future;
-    } else {
-      return new Future.value();
-    }
-  }
-
-  // Before terminating, call close() to restore terminal settings.
-  void _done() {
-    _onCancel().then((_) {
-        _commandController.close();
-      });
-  }
-  
-  void _handleText(String text) {
-    try {
-      if (!_promptShown) {
-        _bufferedInput.write(text);
-        return;
-      }
-
-      var runes = text.runes.toList();
-      var pos = 0;
-      while (pos < runes.length) {
-        if (!_promptShown) {
-          // A command was processed which hid the prompt.  Buffer
-          // the rest of the input.
-          //
-          // TODO(turnidge): Here and elsewhere in the file I pass
-          // runes to String.fromCharCodes.  Does this work?
-          _bufferedInput.write(
-              new String.fromCharCodes(runes.skip(pos)));
-          return;
-        }
-
-        var rune = runes[pos];
-
-        // Count consecutive tabs because double-tab is meaningful.
-        if (rune == runeTAB) {
-          _tabCount++;
-        } else {
-          _tabCount = 0;
-        }
-
-        if (_isControlRune(rune)) {
-          pos += _handleControlSequence(runes, pos);
-        } else {
-          pos += _handleRegularSequence(runes, pos);
-        }
-      }
-    } catch(e, trace) {
-      _commandController.addError(e, trace);
-    }
-  }
-
-  int _handleControlSequence(List<int> runes, int pos) {
-    var runesConsumed = 1;  // Most common result.
-    var char = runes[pos];
-    switch (char) {
-      case runeCtrlA:
-        _home();
-        break;
-           
-      case runeCtrlB:
-        _leftArrow();
-        break;
-
-      case runeCtrlD:
-        if (_currentLine.length == 0) {
-          // ^D on an empty line means quit.
-          _stdout.writeln("^D");
-          _done();
-        } else {
-          _delete();
-        }
-        break;
-           
-      case runeCtrlE:
-        _end();
-        break;
-           
-      case runeCtrlF:
-        _rightArrow();
-        break;
-
-      case runeTAB:
-        if (_complete(_tabCount > 1)) {
-          _tabCount = 0;
-        }
-        break;
-      
-      case runeNewline:
-        _newline();
-        break;
-      
-      case runeCtrlK:
-        _kill();
-        break;
-           
-      case runeCtrlL:
-        _clearScreen();
-        break;
-           
-      case runeCtrlN:
-        _historyNext();
-        break;
-
-      case runeCtrlP:
-        _historyPrevious();
-        break;
-
-      case runeCtrlU:
-        _clearLine();
-        break;
-           
-      case runeCtrlY:
-        _yank();
-        break;
-           
-      case runeESC:
-        // Check to see if this is an arrow key.
-        if (pos + 2 < runes.length &&  // must be a 3 char sequence.
-            runes[pos + 1] == 0x5b) {  // second char must be '['.
-          switch (runes[pos + 2]) {
-            case 0x41:  // ^[[A = up arrow
-              _historyPrevious();
-              runesConsumed = 3;
-              break;
-
-            case 0x42:  // ^[[B = down arrow
-              _historyNext();
-              runesConsumed = 3;
-              break;
-
-            case 0x43:  // ^[[C = right arrow
-              _rightArrow();
-              runesConsumed = 3;
-              break;
-        
-            case 0x44:  // ^[[D = left arrow
-              _leftArrow();
-              runesConsumed = 3;
-              break;
-
-            default:
-              // Ignore the escape character.
-              break;
-          }
-        }
-        break;
-
-      case runeDEL:
-        _backspace();
-        break;
-
-      default:
-        // Ignore the escape character.
-        break;
-    }
-    return runesConsumed;
-  }
-
-  int _handleRegularSequence(List<int> runes, int pos) {
-    var len = pos + 1;
-    while (len < runes.length && !_isControlRune(runes[len])) {
-      len++;
-    }
-    _addChars(runes.getRange(pos, len));
-    return len;
-  }
-
-  bool _isControlRune(int char) {
-    return (char >= 0x00 && char < 0x20) || (char == 0x7f);
-  }
-
-  void _writePromptAndLine() {
-    _writePrompt();
-    var pos = _writeRange(_currentLine, 0, _currentLine.length);
-    _cursorPos = _move(pos, _cursorPos);
-  }
-
-  void _writePrompt() {
-    _stdout.write(prompt);
-  }
-
-  void _addChars(Iterable<int> chars) {
-    var newLine = [];
-    newLine..addAll(_currentLine.take(_cursorPos))
-           ..addAll(chars)
-           ..addAll(_currentLine.skip(_cursorPos));
-    _update(newLine, (_cursorPos + chars.length));
-  }
-
-  void _backspace() {
-    if (_cursorPos == 0) {
-      return;
-    }
-
-    var newLine = [];
-    newLine..addAll(_currentLine.take(_cursorPos - 1))
-           ..addAll(_currentLine.skip(_cursorPos));
-    _update(newLine, (_cursorPos - 1));
-  }
-
-  void _delete() {
-    if (_cursorPos == _currentLine.length) {
-      return;
-    }
-
-    var newLine = [];
-    newLine..addAll(_currentLine.take(_cursorPos))
-           ..addAll(_currentLine.skip(_cursorPos + 1));
-    _update(newLine, _cursorPos);
-  }
-
-  void _home() {
-    _updatePos(0);
-  }
-
-  void _end() {
-    _updatePos(_currentLine.length);
-  }
-
-  void _clearScreen() {
-    _stdout.write(_term.clear);
-    _term.resize();
-    _screenWidth = _term.cols - 1;
-    _writePromptAndLine();
-  }
-
-  void _kill() {
-    var newLine = [];
-    newLine.addAll(_currentLine.take(_cursorPos));
-    _killBuffer = _currentLine.skip(_cursorPos).toList();
-    _update(newLine, _cursorPos);
-  }
-
-  void _clearLine() {
-    _update([], 0);
-  }
-
-  void _yank() {
-    var newLine = [];
-    newLine..addAll(_currentLine.take(_cursorPos))
-           ..addAll(_killBuffer)
-           ..addAll(_currentLine.skip(_cursorPos));
-    _update(newLine, (_cursorPos + _killBuffer.length));
-  }
-
-  static String _trimLeadingSpaces(String line) {
-    bool _isSpace(int rune) {
-      return rune == runeSpace;
-    }
-    return new String.fromCharCodes(line.runes.skipWhile(_isSpace));
-  }
-
-  static String _sharedPrefix(String one, String two) {
-    var len = min(one.length, two.length);
-    var runesOne = one.runes.toList();
-    var runesTwo = two.runes.toList();
-    var pos;
-    for (pos = 0; pos < len; pos++) {
-      if (runesOne[pos] != runesTwo[pos]) {
-        break;
-      }
-    }
-    var shared =  new String.fromCharCodes(runesOne.take(pos));
-    return shared;
-  }
-
-  bool _complete(bool showCompletions) {
-    if (completer == null) {
-      return false;
-    }
-
-    var linePrefix = _currentLine.take(_cursorPos).toList();
-    List<String> commandParts =
-        _trimLeadingSpaces(new String.fromCharCodes(linePrefix)).split(' ');
-    List<String> completionList = completer(commandParts);
-    var completion = '';
-
-    if (completionList.length == 0) {
-      // The current line admits no possible completion.
-      return false;
-
-    } else if (completionList.length == 1) {
-      // There is a single, non-ambiguous completion for the current line.
-      completion = completionList[0];
-
-      // If we are at the end of the line, add a space to signal that
-      // the completion is unambiguous.
-      if (_currentLine.length == _cursorPos) {
-        completion = completion + ' ';
-      }
-    } else {
-      // There are ambiguous completions. Find the longest common
-      // shared prefix of all of the completions.
-      completion = completionList.fold(completionList[0], _sharedPrefix);
-    }
-
-    var lastWord = commandParts.last;
-    if (completion == lastWord) {
-      // The completion does not add anything.
-      if (showCompletions) {
-        // User hit double-TAB.  Show them all possible completions.
-        _move(_cursorPos, _currentLine.length);
-        _stdout.writeln();
-        _stdout.writeln(completionList);
-        _writePromptAndLine();
-      }
-      return false;
-    } else {
-      // Apply the current completion.
-      var completionRunes = completion.runes.toList();
-
-      var newLine = [];
-      newLine..addAll(linePrefix)
-             ..addAll(completionRunes.skip(lastWord.length))
-             ..addAll(_currentLine.skip(_cursorPos));
-      _update(newLine, _cursorPos + completionRunes.length - lastWord.length);
-      return true;
-    }
-  }
-
-  void _newline() {
-    _addLineToHistory(_currentLine);
-    _linePos = _lines.length;
-
-    _end();
-    _stdout.writeln();
-
-    // Call the user's command handler.
-    _commandController.add(new String.fromCharCodes(_currentLine));
-    
-    _currentLine = [];
-    _cursorPos = 0;
-    if (_promptShown) {
-      _writePrompt();
-    }
-  }
-
-  void _leftArrow() {
-    _updatePos(_cursorPos - 1);
-  }
-
-  void _rightArrow() {
-    _updatePos(_cursorPos + 1);
-  }
-
-  void _addLineToHistory(List<int> line) {
-    if (_tempLineAdded) {
-      _lines.removeLast();
-      _tempLineAdded = false;
-    }
-    if (line.length > 0) {
-      _lines.add(line);
-    }
-  }
-
-  void _addTempLineToHistory(List<int> line) {
-    _lines.add(line);
-    _tempLineAdded = true;
-  }
-
-  void _replaceHistory(List<int> line, int linePos) {
-    _lines[linePos] = line;
-  }
-
-  void _historyPrevious() {
-    if (_linePos == 0) {
-      return;
-    }
-
-    if (_linePos == _lines.length) {
-      // The current in-progress line gets temporarily stored in history.
-      _addTempLineToHistory(_currentLine);
-    } else {
-      // Any edits get committed to history.
-      _replaceHistory(_currentLine, _linePos);
-    }
-
-    _linePos -= 1;
-    var line = _lines[_linePos];
-    _update(line, line.length);
-  }
-
-  void _historyNext() {
-    // For the very first command, _linePos (0) will exceed
-    // (_lines.length - 1) (-1) so we use a ">=" here instead of an "==".
-    if (_linePos >= (_lines.length - 1)) {
-      return;
-    }
-
-    // Any edits get committed to history.
-    _replaceHistory(_currentLine, _linePos);
-
-    _linePos += 1;
-    var line = _lines[_linePos];
-    _update(line, line.length);
-  }
-
-  void _updatePos(int newCursorPos) {
-    if (newCursorPos < 0) {
-      return;
-    }
-    if (newCursorPos > _currentLine.length) {
-      return;
-    }
-
-    _cursorPos = _move(_cursorPos, newCursorPos);
-  }
-
-  void _update(List<int> newLine, int newCursorPos) {
-    var pos = _cursorPos;
-    var diffPos;
-    var sharedLen = min(_currentLine.length, newLine.length);
-
-    // Find first difference.
-    for (diffPos = 0; diffPos < sharedLen; diffPos++) {
-      if (_currentLine[diffPos] != newLine[diffPos]) {
-        break;
-      }
-    }
-
-    // Move the cursor to where the difference begins.
-    pos = _move(pos, diffPos);
-
-    // Write the new text.
-    pos = _writeRange(newLine, pos, newLine.length);
-
-    // Clear any extra characters at the end.
-    pos = _clearRange(pos, _currentLine.length);
-
-    // Move the cursor back to the input point.
-    _cursorPos = _move(pos, newCursorPos);
-    _currentLine = newLine;    
-  }
-  
-  void hide() {
-    if (!_promptShown) {
-      return;
-    }
-    _promptShown = false;
-    // We need to erase everything, including the prompt.
-    var curLine = _getLine(_cursorPos);
-    var lastLine = _getLine(_currentLine.length);
-
-    // Go to last line.
-    if (curLine < lastLine) {
-      for (var i = 0; i < (lastLine - curLine); i++) {
-        // This moves us to column 0.
-        _stdout.write(_term.cursorDown);
-      }
-      curLine = lastLine;
-    } else {
-      // Move to column 0.
-      _stdout.write('\r');
-    }
-
-    // Work our way up, clearing lines.
-    while (true) {
-      _stdout.write(_term.clrEOL);
-      if (curLine > 0) {
-        _stdout.write(_term.cursorUp);
-      } else {
-        break;
-      }
-    }
-  }
-
-  void show() {
-    if (_promptShown) {
-      return;
-    }
-    _promptShown = true;
-    _writePromptAndLine();
-
-    // If input was buffered while the prompt was hidden, process it
-    // now.
-    if (!_bufferedInput.isEmpty) {
-      var input = _bufferedInput.toString();
-      _bufferedInput.clear();
-      _handleText(input);
-    }
-  }
-
-  int _writeRange(List<int> text, int pos, int writeToPos) {
-    if (pos >= writeToPos) {
-      return pos;
-    }
-    while (pos < writeToPos) {
-      var margin = _nextMargin(pos);
-      var limit = min(writeToPos, margin);
-      _stdout.write(new String.fromCharCodes(text.getRange(pos, limit)));
-      pos = limit;
-      if (pos == margin) {
-        _stdout.write('\n');
-      }
-    }
-    return pos;
-  }
-
-  int _clearRange(int pos, int clearToPos) {
-    if (pos >= clearToPos) {
-      return pos;
-    }
-    while (true) {
-      var limit = _nextMargin(pos);
-      _stdout.write(_term.clrEOL);
-      if (limit >= clearToPos) {
-        return pos;
-      }
-      _stdout.write('\n');
-      pos = limit;
-    }
-  }
-
-  int _move(int pos, int newPos) {
-    if (pos == newPos) {
-      return pos;
-    }
-
-    var curCol = _getCol(pos);
-    var curLine = _getLine(pos);
-    var newCol = _getCol(newPos);
-    var newLine = _getLine(newPos);
-
-    if (curLine > newLine) {
-      for (var i = 0; i < (curLine - newLine); i++) {
-        _stdout.write(_term.cursorUp);
-      }
-    }
-    if (curLine < newLine) {
-      for (var i = 0; i < (newLine - curLine); i++) {
-        _stdout.write(_term.cursorDown);
-      }
-
-      // Moving down resets column to zero, oddly.
-      curCol = 0;
-    }
-    if (curCol > newCol) {
-      for (var i = 0; i < (curCol - newCol); i++) {
-        _stdout.write(_term.cursorBack);
-      }
-    }
-    if (curCol < newCol) {
-      for (var i = 0; i < (newCol - curCol); i++) {
-        _stdout.write(_term.cursorForward);
-      }
-    }
-
-    return newPos;
-  }
-        
-  int _nextMargin(int pos) {
-    var truePos = pos + prompt.length;
-    return ((truePos ~/ _screenWidth) + 1) * _screenWidth - prompt.length;
-  }
-
-  int _getLine(int pos) {
-    var truePos = pos + prompt.length;
-    return truePos ~/ _screenWidth;
-  }
-
-  int _getCol(int pos) {
-    var truePos = pos + prompt.length;
-    return truePos % _screenWidth;
-  }
-
-  Stdin _stdin;
-  StreamSubscription _stdinSubscription;
-  IOSink _stdout;
-  final String prompt;
-  bool _promptShown = true;
-  final CommandCompleter completer;
-  TermInfo _term = new TermInfo();
-
-  // TODO(turnidge): See if we can get screen resize events.
-  int _screenWidth;
-  List<int> _currentLine = [];  // A list of runes.
-  StringBuffer _bufferedInput = new StringBuffer();
-  List<List<int>> _lines = [];
-
-  // When using the command history, the current line is temporarily
-  // added to the history to allow the user to return to it.  This
-  // values tracks whether the history has a temporary line at the end.
-  bool _tempLineAdded = false;
-  int _linePos = 0;
-  int _cursorPos = 0;
-  int _tabCount = 0;
-  List<int> _killBuffer = [];
-}
-
-
-// Demo code.
-
-
-List<String> _myCompleter(List<String> commandTokens) {
-  List<String> completions = new List<String>();
-
-  // First word completions.
-  if (commandTokens.length <= 1) {
-    String prefix = '';
-    if (commandTokens.length == 1) {
-      prefix = commandTokens.first;
-    }
-    if ('quit'.startsWith(prefix)) {
-      completions.add('quit');
-    }
-    if ('help'.startsWith(prefix)) {
-      completions.add('help');
-    }
-    if ('happyface'.startsWith(prefix)) {
-      completions.add('happyface');
-    }
-  }
-
-  // Complete 'foobar' or 'gondola' anywhere in string.
-  String lastWord = commandTokens.last;
-  if ('foobar'.startsWith(lastWord)) {
-    completions.add('foobar');
-  }
-  if ('gondola'.startsWith(lastWord)) {
-    completions.add('gondola');
-  }
-
-  return completions;
-}
-
-
-int _helpCount = 0;
-Commando cmdo;
-
-
-void _handleCommand(String rawCommand) {
-  String command = rawCommand.trim();
-  cmdo.hide();
-  if (command == 'quit') {
-    cmdo.close().then((_) {
-        print('Exiting');
-      });
-  } else if (command == 'help') {
-    switch (_helpCount) {
-      case 0:
-        print('I will not help you.');
-        break;
-      case 1:
-        print('I mean it.');
-        break;
-      case 2:
-        print('Seriously.');
-        break;
-      case 100:
-        print('Well now.');
-        break;
-      default:
-        print("Okay.  Type 'quit' to quit");
-        break;
-    }
-    _helpCount++;
-  } else if (command == 'happyface') {
-    print(':-)');
-  } else {
-    print('Received command($command)');
-  }
-  cmdo.show();
-}
-
-
-void main() {
-  print('[Commando demo]');
-  cmdo = new Commando(completer:_myCompleter);
-  cmdo.commands.listen(_handleCommand);
-}
diff --git a/tools/ddbg/lib/terminfo.dart b/tools/ddbg/lib/terminfo.dart
deleted file mode 100644
index 4521031..0000000
--- a/tools/ddbg/lib/terminfo.dart
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:convert';
-import 'dart:io';
-
-int _tputGetInteger(String capName) {
-  var result = Process.runSync('tput',  ['$capName'], stdoutEncoding:UTF8);
-  if (result.exitCode != 0) {
-    return 0;
-  }
-  return int.parse(result.stdout);
-}
-
-String _tputGetSequence(String capName) {
-  var result = Process.runSync('tput',  ['$capName'], stdoutEncoding:UTF8);
-  if (result.exitCode != 0) {
-    return '';
-  }
-  return result.stdout;
-}
-
-class TermInfo {
-  TermInfo() {
-    resize();
-  }
-
-  int get lines => _lines;
-  int get cols => _cols;
-
-  int _lines;
-  int _cols;
-
-  void resize() {
-    _lines = _tputGetInteger('lines');
-    _cols = _tputGetInteger('cols');
-  }
-
-  // Back one character.
-  final String cursorBack = _tputGetSequence('cub1');
-
-  // Forward one character.
-  final String cursorForward = _tputGetSequence('cuf1');
-
-  // Up one character.
-  final String cursorUp = _tputGetSequence('cuu1');
-
-  // Down one character.
-  final String cursorDown = _tputGetSequence('cud1');
-
-  // Clear to end of line.
-  final String clrEOL = _tputGetSequence('el');
-
-  // Clear screen and home cursor.
-  final String clear = _tputGetSequence('clear');
-}
diff --git a/tools/ddbg_service/HACKING.txt b/tools/ddbg_service/HACKING.txt
deleted file mode 100644
index 27c47d7..0000000
--- a/tools/ddbg_service/HACKING.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-ddbg_service
----
-
-ddbg_service is a command line debugger for the Dart VM implemented
-using the Dart VM Service.  It is still being written and is not ready
-for use.
-
-Assumptions:
-You are running pub from the latest dev channel release of Dart Editor.
-
-Before running ddbg_service, you will need to run get packages from pub:
-
-    pub upgrade
-
-Then launch ddbg_service:
-
-    dart bin/ddbg_service.dart
diff --git a/tools/ddbg_service/bin/ddbg_service.dart b/tools/ddbg_service/bin/ddbg_service.dart
deleted file mode 100644
index 0023ba3..0000000
--- a/tools/ddbg_service/bin/ddbg_service.dart
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// A command line debugger implemented using the VM Service protocol.
-
-library ddbg2;
-
-import "dart:async";
-
-import 'package:ddbg/debugger.dart';
-
-Debugger debugger;
-
-void onError(self, parent, zone, error, StackTrace trace) {
-  if (debugger != null) {
-    debugger.onUncaughtError(error, trace);
-  } else {
-    print('\n--------\nExiting due to unexpected error:\n'
-          '  $error\n$trace\n');
-    exit();
-  }
-}
-
-void main(List<String> args) {
-  // Setup a zone which will exit the debugger cleanly on any uncaught
-  // exception.
-  var zone = Zone.ROOT.fork(specification:new ZoneSpecification(
-      handleUncaughtError: onError));
-  
-  zone.run(() {
-      debugger = new Debugger();
-  });
-}
diff --git a/tools/ddbg_service/lib/commando.dart b/tools/ddbg_service/lib/commando.dart
deleted file mode 100644
index 3996880..0000000
--- a/tools/ddbg_service/lib/commando.dart
+++ /dev/null
@@ -1,750 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library commando;
-
-import 'dart:async';
-import 'dart:convert';
-import 'dart:io';
-import 'dart:math';
-
-import 'package:ddbg/terminfo.dart';
-
-typedef List<String> CommandCompleter(List<String> commandParts);
-
-class Commando {
-  // Ctrl keys
-  static const runeCtrlA   = 0x01;
-  static const runeCtrlB   = 0x02;
-  static const runeCtrlD   = 0x04;
-  static const runeCtrlE   = 0x05;
-  static const runeCtrlF   = 0x06;
-  static const runeTAB     = 0x09;
-  static const runeNewline = 0x0a;
-  static const runeCtrlK   = 0x0b;
-  static const runeCtrlL   = 0x0c;
-  static const runeCtrlN   = 0x0e;
-  static const runeCtrlP   = 0x10;
-  static const runeCtrlU   = 0x15;
-  static const runeCtrlY   = 0x19;
-  static const runeESC     = 0x1b;
-  static const runeSpace   = 0x20;
-  static const runeDEL     = 0x7F;
-
-  StreamController<String> _commandController;
-
-  Stream get commands => _commandController.stream;
-
-  Commando({consoleIn,
-            consoleOut,
-            this.prompt : '> ',
-          this.completer : null}) {
-    _stdin = (consoleIn != null ? consoleIn : stdin);
-    _stdout = (consoleOut != null ? consoleOut : stdout);
-    _commandController = new StreamController<String>(
-        onCancel: _onCancel);
-    _stdin.echoMode = false;
-    _stdin.lineMode = false;
-    _screenWidth = _term.cols - 1;
-    _writePrompt();
-    // TODO(turnidge): Handle errors in _stdin here.
-    _stdinSubscription =
-        _stdin.transform(UTF8.decoder).listen(_handleText, onDone:_done);
-  }
-
-  Future _onCancel() {
-    _stdin.echoMode = true;
-    _stdin.lineMode = true;
-    var future = _stdinSubscription.cancel();
-    if (future != null) {
-      return future;
-    } else {
-      return new Future.value();
-    }
-  }
-
-  // Before terminating, call close() to restore terminal settings.
-  void _done() {
-    _onCancel().then((_) {
-        _commandController.close();
-      });
-  }
-  
-  void _handleText(String text) {
-    try {
-      if (!_promptShown) {
-        _bufferedInput.write(text);
-        return;
-      }
-
-      var runes = text.runes.toList();
-      var pos = 0;
-      while (pos < runes.length) {
-        if (!_promptShown) {
-          // A command was processed which hid the prompt.  Buffer
-          // the rest of the input.
-          //
-          // TODO(turnidge): Here and elsewhere in the file I pass
-          // runes to String.fromCharCodes.  Does this work?
-          _bufferedInput.write(
-              new String.fromCharCodes(runes.skip(pos)));
-          return;
-        }
-
-        var rune = runes[pos];
-
-        // Count consecutive tabs because double-tab is meaningful.
-        if (rune == runeTAB) {
-          _tabCount++;
-        } else {
-          _tabCount = 0;
-        }
-
-        if (_isControlRune(rune)) {
-          pos += _handleControlSequence(runes, pos);
-        } else {
-          pos += _handleRegularSequence(runes, pos);
-        }
-      }
-    } catch(e, trace) {
-      _commandController.addError(e, trace);
-    }
-  }
-
-  int _handleControlSequence(List<int> runes, int pos) {
-    var runesConsumed = 1;  // Most common result.
-    var char = runes[pos];
-    switch (char) {
-      case runeCtrlA:
-        _home();
-        break;
-           
-      case runeCtrlB:
-        _leftArrow();
-        break;
-
-      case runeCtrlD:
-        if (_currentLine.length == 0) {
-          // ^D on an empty line means quit.
-          _stdout.writeln("^D");
-          _done();
-        } else {
-          _delete();
-        }
-        break;
-           
-      case runeCtrlE:
-        _end();
-        break;
-           
-      case runeCtrlF:
-        _rightArrow();
-        break;
-
-      case runeTAB:
-        _complete(_tabCount > 1);
-        break;
-      
-      case runeNewline:
-        _newline();
-        break;
-      
-      case runeCtrlK:
-        _kill();
-        break;
-           
-      case runeCtrlL:
-        _clearScreen();
-        break;
-           
-      case runeCtrlN:
-        _historyNext();
-        break;
-
-      case runeCtrlP:
-        _historyPrevious();
-        break;
-
-      case runeCtrlU:
-        _clearLine();
-        break;
-           
-      case runeCtrlY:
-        _yank();
-        break;
-           
-      case runeESC:
-        // Check to see if this is an arrow key.
-        if (pos + 2 < runes.length &&  // must be a 3 char sequence.
-            runes[pos + 1] == 0x5b) {  // second char must be '['.
-          switch (runes[pos + 2]) {
-            case 0x41:  // ^[[A = up arrow
-              _historyPrevious();
-              runesConsumed = 3;
-              break;
-
-            case 0x42:  // ^[[B = down arrow
-              _historyNext();
-              runesConsumed = 3;
-              break;
-
-            case 0x43:  // ^[[C = right arrow
-              _rightArrow();
-              runesConsumed = 3;
-              break;
-        
-            case 0x44:  // ^[[D = left arrow
-              _leftArrow();
-              runesConsumed = 3;
-              break;
-
-            default:
-              // Ignore the escape character.
-              break;
-          }
-        }
-        break;
-
-      case runeDEL:
-        _backspace();
-        break;
-
-      default:
-        // Ignore the escape character.
-        break;
-    }
-    return runesConsumed;
-  }
-
-  int _handleRegularSequence(List<int> runes, int pos) {
-    var len = pos + 1;
-    while (len < runes.length && !_isControlRune(runes[len])) {
-      len++;
-    }
-    _addChars(runes.getRange(pos, len));
-    return len;
-  }
-
-  bool _isControlRune(int char) {
-    return (char >= 0x00 && char < 0x20) || (char == 0x7f);
-  }
-
-  void _writePromptAndLine() {
-    _writePrompt();
-    var pos = _writeRange(_currentLine, 0, _currentLine.length);
-    _cursorPos = _move(pos, _cursorPos);
-  }
-
-  void _writePrompt() {
-    _stdout.write(prompt);
-  }
-
-  void _addChars(Iterable<int> chars) {
-    var newLine = [];
-    newLine..addAll(_currentLine.take(_cursorPos))
-           ..addAll(chars)
-           ..addAll(_currentLine.skip(_cursorPos));
-    _update(newLine, (_cursorPos + chars.length));
-  }
-
-  void _backspace() {
-    if (_cursorPos == 0) {
-      return;
-    }
-
-    var newLine = [];
-    newLine..addAll(_currentLine.take(_cursorPos - 1))
-           ..addAll(_currentLine.skip(_cursorPos));
-    _update(newLine, (_cursorPos - 1));
-  }
-
-  void _delete() {
-    if (_cursorPos == _currentLine.length) {
-      return;
-    }
-
-    var newLine = [];
-    newLine..addAll(_currentLine.take(_cursorPos))
-           ..addAll(_currentLine.skip(_cursorPos + 1));
-    _update(newLine, _cursorPos);
-  }
-
-  void _home() {
-    _updatePos(0);
-  }
-
-  void _end() {
-    _updatePos(_currentLine.length);
-  }
-
-  void _clearScreen() {
-    _stdout.write(_term.clear);
-    _term.resize();
-    _screenWidth = _term.cols - 1;
-    _writePromptAndLine();
-  }
-
-  void _kill() {
-    var newLine = [];
-    newLine.addAll(_currentLine.take(_cursorPos));
-    _killBuffer = _currentLine.skip(_cursorPos).toList();
-    _update(newLine, _cursorPos);
-  }
-
-  void _clearLine() {
-    _update([], 0);
-  }
-
-  void _yank() {
-    var newLine = [];
-    newLine..addAll(_currentLine.take(_cursorPos))
-           ..addAll(_killBuffer)
-           ..addAll(_currentLine.skip(_cursorPos));
-    _update(newLine, (_cursorPos + _killBuffer.length));
-  }
-
-  static String _trimLeadingSpaces(String line) {
-    bool _isSpace(int rune) {
-      return rune == runeSpace;
-    }
-    return new String.fromCharCodes(line.runes.skipWhile(_isSpace));
-  }
-
-  static String _sharedPrefix(String one, String two) {
-    var len = min(one.length, two.length);
-    var runesOne = one.runes.toList();
-    var runesTwo = two.runes.toList();
-    var pos;
-    for (pos = 0; pos < len; pos++) {
-      if (runesOne[pos] != runesTwo[pos]) {
-        break;
-      }
-    }
-    var shared =  new String.fromCharCodes(runesOne.take(pos));
-    return shared;
-  }
-
-  void _complete(bool showCompletions) {
-    if (completer == null) {
-      return;
-    }
-
-    var linePrefix = _currentLine.take(_cursorPos).toList();
-    var lineAsString = new String.fromCharCodes(linePrefix);
-    var commandParts = new List.from(lineAsString.split(' ').where((line) {
-          return line != ' ' && line != '';
-        }));
-    if (lineAsString.endsWith(' ')) {
-      // If the current line ends with a space, they are hoping to
-      // complete the next word in the command.  Add an empty string
-      // to the commandParts to signal this to the completer.
-      commandParts.add('');
-    }
-    List<String> completionList = completer(commandParts);
-    var completion = null;
-
-    if (completionList.length == 0) {
-      // The current line admits no possible completion.
-      return;
-
-    } else if (completionList.length == 1) {
-      // There is a single, non-ambiguous completion for the current line.
-      completion = completionList[0];
-
-    } else {
-      // There are ambiguous completions. Find the longest common
-      // shared prefix of all of the completions.
-      completion = completionList.fold(completionList[0], _sharedPrefix);
-    }
-
-    if (showCompletions) {
-      // User hit double-TAB.  Show them all possible completions.
-      completionList.sort((a,b) => a.compareTo(b));
-      _move(_cursorPos, _currentLine.length);
-      _stdout.writeln();
-      _stdout.writeln(completionList);
-      _writePromptAndLine();
-      return;
-
-    } else {
-      // Apply the current completion.
-      var completionRunes = completion.runes.toList();
-
-      var newLine = [];
-      newLine..addAll(completionRunes)
-             ..addAll(_currentLine.skip(_cursorPos));
-      _update(newLine, completionRunes.length);
-      return;
-    }
-  }
-
-  void _newline() {
-    _addLineToHistory(_currentLine);
-    _linePos = _lines.length;
-
-    _end();
-    _stdout.writeln();
-
-    // Call the user's command handler.
-    _commandController.add(new String.fromCharCodes(_currentLine));
-    
-    _currentLine = [];
-    _cursorPos = 0;
-    if (_promptShown) {
-      _writePrompt();
-    }
-  }
-
-  void _leftArrow() {
-    _updatePos(_cursorPos - 1);
-  }
-
-  void _rightArrow() {
-    _updatePos(_cursorPos + 1);
-  }
-
-  void _addLineToHistory(List<int> line) {
-    if (_tempLineAdded) {
-      _lines.removeLast();
-      _tempLineAdded = false;
-    }
-    if (line.length > 0) {
-      _lines.add(line);
-    }
-  }
-
-  void _addTempLineToHistory(List<int> line) {
-    _lines.add(line);
-    _tempLineAdded = true;
-  }
-
-  void _replaceHistory(List<int> line, int linePos) {
-    _lines[linePos] = line;
-  }
-
-  void _historyPrevious() {
-    if (_linePos == 0) {
-      return;
-    }
-
-    if (_linePos == _lines.length) {
-      // The current in-progress line gets temporarily stored in history.
-      _addTempLineToHistory(_currentLine);
-    } else {
-      // Any edits get committed to history.
-      _replaceHistory(_currentLine, _linePos);
-    }
-
-    _linePos -= 1;
-    var line = _lines[_linePos];
-    _update(line, line.length);
-  }
-
-  void _historyNext() {
-    // For the very first command, _linePos (0) will exceed
-    // (_lines.length - 1) (-1) so we use a ">=" here instead of an "==".
-    if (_linePos >= (_lines.length - 1)) {
-      return;
-    }
-
-    // Any edits get committed to history.
-    _replaceHistory(_currentLine, _linePos);
-
-    _linePos += 1;
-    var line = _lines[_linePos];
-    _update(line, line.length);
-  }
-
-  void _updatePos(int newCursorPos) {
-    if (newCursorPos < 0) {
-      return;
-    }
-    if (newCursorPos > _currentLine.length) {
-      return;
-    }
-
-    _cursorPos = _move(_cursorPos, newCursorPos);
-  }
-
-  void _update(List<int> newLine, int newCursorPos) {
-    var pos = _cursorPos;
-    var diffPos;
-    var sharedLen = min(_currentLine.length, newLine.length);
-
-    // Find first difference.
-    for (diffPos = 0; diffPos < sharedLen; diffPos++) {
-      if (_currentLine[diffPos] != newLine[diffPos]) {
-        break;
-      }
-    }
-
-    // Move the cursor to where the difference begins.
-    pos = _move(pos, diffPos);
-
-    // Write the new text.
-    pos = _writeRange(newLine, pos, newLine.length);
-
-    // Clear any extra characters at the end.
-    pos = _clearRange(pos, _currentLine.length);
-
-    // Move the cursor back to the input point.
-    _cursorPos = _move(pos, newCursorPos);
-    _currentLine = newLine;    
-  }
-
-  void print(String text) {
-    bool togglePrompt = _promptShown;
-    if (togglePrompt) {
-      hide();
-    }
-    _stdout.writeln(text);
-    if (togglePrompt) {
-      show();
-    }
-  }
-  
-  void hide() {
-    if (!_promptShown) {
-      return;
-    }
-    _promptShown = false;
-    // We need to erase everything, including the prompt.
-    var curLine = _getLine(_cursorPos);
-    var lastLine = _getLine(_currentLine.length);
-
-    // Go to last line.
-    if (curLine < lastLine) {
-      for (var i = 0; i < (lastLine - curLine); i++) {
-        // This moves us to column 0.
-        _stdout.write(_term.cursorDown);
-      }
-      curLine = lastLine;
-    } else {
-      // Move to column 0.
-      _stdout.write('\r');
-    }
-
-    // Work our way up, clearing lines.
-    while (true) {
-      _stdout.write(_term.clrEOL);
-      if (curLine > 0) {
-        _stdout.write(_term.cursorUp);
-      } else {
-        break;
-      }
-    }
-  }
-
-  void show() {
-    if (_promptShown) {
-      return;
-    }
-    _promptShown = true;
-    _writePromptAndLine();
-
-    // If input was buffered while the prompt was hidden, process it
-    // now.
-    if (!_bufferedInput.isEmpty) {
-      var input = _bufferedInput.toString();
-      _bufferedInput.clear();
-      _handleText(input);
-    }
-  }
-
-  int _writeRange(List<int> text, int pos, int writeToPos) {
-    if (pos >= writeToPos) {
-      return pos;
-    }
-    while (pos < writeToPos) {
-      var margin = _nextMargin(pos);
-      var limit = min(writeToPos, margin);
-      _stdout.write(new String.fromCharCodes(text.getRange(pos, limit)));
-      pos = limit;
-      if (pos == margin) {
-        _stdout.write('\n');
-      }
-    }
-    return pos;
-  }
-
-  int _clearRange(int pos, int clearToPos) {
-    if (pos >= clearToPos) {
-      return pos;
-    }
-    while (true) {
-      var limit = _nextMargin(pos);
-      _stdout.write(_term.clrEOL);
-      if (limit >= clearToPos) {
-        return pos;
-      }
-      _stdout.write('\n');
-      pos = limit;
-    }
-  }
-
-  int _move(int pos, int newPos) {
-    if (pos == newPos) {
-      return pos;
-    }
-
-    var curCol = _getCol(pos);
-    var curLine = _getLine(pos);
-    var newCol = _getCol(newPos);
-    var newLine = _getLine(newPos);
-
-    if (curLine > newLine) {
-      for (var i = 0; i < (curLine - newLine); i++) {
-        _stdout.write(_term.cursorUp);
-      }
-    }
-    if (curLine < newLine) {
-      for (var i = 0; i < (newLine - curLine); i++) {
-        _stdout.write(_term.cursorDown);
-      }
-
-      // Moving down resets column to zero, oddly.
-      curCol = 0;
-    }
-    if (curCol > newCol) {
-      for (var i = 0; i < (curCol - newCol); i++) {
-        _stdout.write(_term.cursorBack);
-      }
-    }
-    if (curCol < newCol) {
-      for (var i = 0; i < (newCol - curCol); i++) {
-        _stdout.write(_term.cursorForward);
-      }
-    }
-
-    return newPos;
-  }
-        
-  int _nextMargin(int pos) {
-    var truePos = pos + prompt.length;
-    return ((truePos ~/ _screenWidth) + 1) * _screenWidth - prompt.length;
-  }
-
-  int _getLine(int pos) {
-    var truePos = pos + prompt.length;
-    return truePos ~/ _screenWidth;
-  }
-
-  int _getCol(int pos) {
-    var truePos = pos + prompt.length;
-    return truePos % _screenWidth;
-  }
-
-  Stdin _stdin;
-  StreamSubscription _stdinSubscription;
-  IOSink _stdout;
-  final String prompt;
-  bool _promptShown = true;
-  final CommandCompleter completer;
-  TermInfo _term = new TermInfo();
-
-  // TODO(turnidge): See if we can get screen resize events.
-  int _screenWidth;
-  List<int> _currentLine = [];  // A list of runes.
-  StringBuffer _bufferedInput = new StringBuffer();
-  List<List<int>> _lines = [];
-
-  // When using the command history, the current line is temporarily
-  // added to the history to allow the user to return to it.  This
-  // values tracks whether the history has a temporary line at the end.
-  bool _tempLineAdded = false;
-  int _linePos = 0;
-  int _cursorPos = 0;
-  int _tabCount = 0;
-  List<int> _killBuffer = [];
-}
-
-
-// Demo code.
-
-
-List<String> _myCompleter(List<String> commandTokens) {
-  List<String> completions = new List<String>();
-
-  // First word completions.
-  if (commandTokens.length <= 1) {
-    String prefix = '';
-    if (commandTokens.length == 1) {
-      prefix = commandTokens.first;
-    }
-    if ('quit'.startsWith(prefix)) {
-      completions.add('quit');
-    }
-    if ('help'.startsWith(prefix)) {
-      completions.add('help');
-    }
-    if ('happyface'.startsWith(prefix)) {
-      completions.add('happyface');
-    }
-  }
-
-  // Complete 'foobar' or 'gondola' anywhere in string.
-  String lastWord = commandTokens.last;
-  if ('foobar'.startsWith(lastWord)) {
-    completions.add('foobar');
-  }
-  if ('gondola'.startsWith(lastWord)) {
-    completions.add('gondola');
-  }
-
-  return completions;
-}
-
-
-int _helpCount = 0;
-Commando cmdo;
-var cmdoSubscription;
-
-
-void _handleCommand(String rawCommand) {
-  String command = rawCommand.trim();
-  cmdo.hide();
-  if (command == 'quit') {
-    var future = cmdoSubscription.cancel();
-    if (future != null) {
-      future.then((_) {
-          print('Exiting');
-          exit(0);
-        });
-    } else {
-      print('Exiting');
-      exit(0);
-    }
-  } else if (command == 'help') {
-    switch (_helpCount) {
-      case 0:
-        print('I will not help you.');
-        break;
-      case 1:
-        print('I mean it.');
-        break;
-      case 2:
-        print('Seriously.');
-        break;
-      case 100:
-        print('Well now.');
-        break;
-      default:
-        print("Okay.  Type 'quit' to quit");
-        break;
-    }
-    _helpCount++;
-  } else if (command == 'happyface') {
-    print(':-)');
-  } else {
-    print('Received command($command)');
-  }
-  cmdo.show();
-}
-
-
-void main() {
-  print('[Commando demo]');
-  cmdo = new Commando(completer:_myCompleter);
-  cmdoSubscription = cmdo.commands.listen(_handleCommand);
-}
diff --git a/tools/ddbg_service/lib/debugger.dart b/tools/ddbg_service/lib/debugger.dart
deleted file mode 100644
index 0a04161..0000000
--- a/tools/ddbg_service/lib/debugger.dart
+++ /dev/null
@@ -1,478 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library debugger;
-
-import "dart:async";
-import "dart:io";
-
-import "package:ddbg/commando.dart";
-import "package:observatory/service_io.dart";
-
-class Debugger {
-  Commando cmdo;
-  var _cmdoSubscription;
-
-  CommandList _commands;
-
-  VM _vm;
-  VM get vm => _vm;
-  set vm(VM vm) {
-    if (_vm == vm) {
-      // Do nothing.
-      return;
-    }
-    if (_vm != null) {
-      _vm.disconnect();
-    }
-    if (vm != null) {
-      vm.onConnect.then(_vmConnected);
-      vm.onDisconnect.then(_vmDisconnected);
-      vm.errors.stream.listen(_onServiceError);
-      vm.exceptions.stream.listen(_onServiceException);
-      vm.events.stream.listen(_onServiceEvent);
-    }
-    _vm = vm;
-  }
-
-  _vmConnected(VM vm) {
-    cmdo.print('Connected to vm');
-  }
-
-  _vmDisconnected(VM vm) {
-    cmdo.print('Disconnected from vm');
-  }
-
-  _onServiceError(ServiceError error) {
-    cmdo.print('error $error');
-  }
-
-  _onServiceException(ServiceException exception) {
-    cmdo.print('${exception.message}');
-  }
-
-  _onServiceEvent(ServiceEvent event) {
-    switch (event.eventType) {
-      case 'GC':
-        // Ignore GC events for now.
-        break;
-      default:
-        cmdo.print('event $event');
-        break;
-    }
-  }
-
-  VM _isolate;
-  VM get isolate => _isolate;
-  set isolate(Isolate isolate) {
-    _isolate = isolate;
-    cmdo.print('Current isolate is now isolate ${getIsolateIndex(_isolate)}');
-  }
-
-  Map _isolateIndexMap = new Map();
-  int _nextIsolateIndex = 0;
-  int getIsolateIndex(Isolate isolate) {
-    var index = _isolateIndexMap[isolate.id];
-    if (index == null) {
-      index = _nextIsolateIndex++;
-      _isolateIndexMap[isolate.id] = index;
-    }
-    return index;
-  }
-
-  void onUncaughtError(error, StackTrace trace) {
-    if (error is ServiceException ||
-        error is ServiceError) {
-      // These are handled elsewhere.  Ignore.
-      return;
-    }
-    cmdo.print('\n--------\nExiting due to unexpected error:\n'
-                '  $error\n$trace\n');
-    quit();
-  }
-
-  Debugger() {
-    cmdo = new Commando(completer: _completeCommand);
-    _cmdoSubscription = cmdo.commands.listen(_processCommand,
-                                             onError: _cmdoError,
-                                             onDone: _cmdoDone);
-    _commands = new CommandList();
-    _commands.register(new AttachCommand());
-    _commands.register(new DetachCommand());
-    _commands.register(new HelpCommand(_commands));
-    _commands.register(new IsolateCommand());
-    _commands.register(new QuitCommand());
-  }
-
-  Future _closeCmdo() {
-    var sub = _cmdoSubscription;
-    _cmdoSubscription = null;
-    cmdo = null;
-
-    var future = sub.cancel();
-    if (future != null) {
-      return future;
-    } else {
-      return new Future.value();
-    }
-  }
-
-  Future quit() {
-    return Future.wait([_closeCmdo()]).then((_) {
-        exit(0);
-      });
-  }
-
-  void _cmdoError(error, StackTrace trace) {
-    cmdo.print('\n--------\nExiting due to unexpected error:\n'
-               '  $error\n$trace\n');
-    quit();
-  }
-
-  void _cmdoDone() {
-    quit();
-  }
-
-  List<String> _completeCommand(List<String> commandParts) {
-    return _commands.complete(commandParts);
-  }
-
-  void _processCommand(String cmdLine) {
-    void huh() {
-      cmdo.print("'$cmdLine' not understood, try 'help' for help.");
-    }
-
-    cmdo.hide();
-    cmdLine = cmdLine.trim();
-    var args = cmdLine.split(' ');
-    if (args.length == 0) {
-      return;
-    }
-    var command = args[0];
-    var matches  = _commands.match(command, true);
-    if (matches.length == 0) {
-      huh();
-      cmdo.show();
-    } else if (matches.length == 1) {
-      matches[0].run(this, args).then((_) {
-          cmdo.show();
-        });
-    } else {
-      var matchNames = matches.map((handler) => handler.name);
-      cmdo.print("Ambiguous command '$command' : ${matchNames.toList()}");
-      cmdo.show();
-    }
-  }
-
-}
-
-// Every debugger command extends this base class.
-abstract class Command {
-  String get name;
-  String get helpShort;
-  void printHelp(Debugger debugger, List<String> args);
-  Future run(Debugger debugger, List<String> args);
-  List<String> complete(List<String> commandParts) {
-    return ["$name ${commandParts.join(' ')}"];
-
-  }
-}
-
-class AttachCommand extends Command {
-  final name = 'attach';
-  final helpShort = 'Attach to a running Dart VM';
-  void printHelp(Debugger debugger, List<String> args) {
-    debugger.cmdo.print('''
------ attach -----
-
-Attach to the Dart VM running at the indicated host:port. If no
-host:port is provided, attach to the VM running on the default port.
-
-Usage:
-  attach
-  attach <host:port>
-''');
-  }
-
-  Future run(Debugger debugger, List<String> args) {
-    var cmdo = debugger.cmdo;
-    if (args.length > 2) {
-      cmdo.print('$name expects 0 or 1 arguments');
-      return new Future.value();
-    }
-    String hostPort = 'localhost:8181';
-    if (args.length > 1) {
-      hostPort = args[1];
-    }
-
-    debugger.vm = new WebSocketVM(new WebSocketVMTarget('ws://${hostPort}/ws'));
-    return debugger.vm.load().then((vm) {
-        if (debugger.isolate == null) {
-          for (var isolate in vm.isolates) {
-            if (isolate.name == 'root') {
-              debugger.isolate = isolate;
-            }
-          }
-        }
-      });
-  }
-}
-
-class CommandList {
-  List _commands = new List<Command>();
-
-  void register(Command cmd) {
-    _commands.add(cmd);
-  }
-
-  List<Command> match(String commandName, bool exactMatchWins) {
-    var matches = [];
-    for (var command in _commands) {
-      if (command.name.startsWith(commandName)) {
-        if (exactMatchWins && command.name == commandName) {
-          // Exact match
-          return [command];
-        } else {
-          matches.add(command);
-        }
-      }
-    }
-    return matches;
-  }
-
-  List<String> complete(List<String> commandParts) {
-    var completions = new List<String>();
-    String prefix = commandParts[0];
-    for (var command in _commands) {
-      if (command.name.startsWith(prefix)) {
-        completions.addAll(command.complete(commandParts.sublist(1)));
-      }
-    }
-    return completions;
-  }
-
-  void printHelp(Debugger debugger, List<String> args) {
-    var cmdo = debugger.cmdo;
-    if (args.length <= 1) {
-      cmdo.print("\nDebugger commands:\n");
-      for (var command in _commands) {
-        cmdo.print('  ${command.name.padRight(11)} ${command.helpShort}');
-      }
-      cmdo.print("For more information about a particular command, type:\n\n"
-                  "  help <command>\n");
-
-      cmdo.print("Commands may be abbreviated: e.g. type 'h' for 'help.\n");
-    } else {
-      var commandName = args[1];
-      var matches =match(commandName, true);
-      if (matches.length == 0) {
-        cmdo.print("Command '$commandName' not recognized.  "
-                    "Try 'help' for a list of commands.");
-      } else {
-        for (var command in matches) {
-          command.printHelp(debugger, args);
-        }
-      }
-    }
-  }
-}
-
-class DetachCommand extends Command {
-  final name = 'detach';
-  final helpShort = 'Detach from a running Dart VM';
-  void printHelp(Debugger debugger, List<String> args) {
-    debugger.cmdo.print('''
------ detach -----
-
-Detach from the Dart VM.
-
-Usage:
-  detach
-''');
-  }
-
-  Future run(Debugger debugger, List<String> args) {
-    var cmdo = debugger.cmdo;
-    if (args.length > 1) {
-      cmdo.print('$name expects no arguments');
-      return new Future.value();
-    }
-    if (debugger.vm == null) {
-      cmdo.print('No VM is attached');
-    } else {
-      debugger.vm = null;
-    }
-    return new Future.value();
-  }
-}
-
-class HelpCommand extends Command {
-  HelpCommand(this._commands);
-  final CommandList _commands;
-
-  final name = 'help';
-  final helpShort = 'Show a list of debugger commands';
-  void printHelp(Debugger debugger, List<String> args) {
-    debugger.cmdo.print('''
------ help -----
-
-Show a list of debugger commands or get more information about a
-particular command.
-
-Usage:
-  help
-  help <command>
-''');
-  }
-
-  Future run(Debugger debugger, List<String> args) {
-    _commands.printHelp(debugger, args);
-    return new Future.value();
-  }
-
-  List<String> complete(List<String> commandParts) {
-    if (commandParts.isEmpty) {
-      return ['$name '];
-    }
-    return _commands.complete(commandParts).map((value) {
-        return '$name $value';
-      });
-  }
-}
-
-class IsolateCommand extends Command {
-  final name = 'isolate';
-  final helpShort = 'Isolate control';
-  void printHelp(Debugger debugger, List<String> args) {
-    debugger.cmdo.print('''
------ isolate -----
-
-List all isolates.
-
-Usage:
-  isolate
-  isolate list
-
-Set current isolate.
-
-Usage:
-  isolate <id>
-''');
-  }
-
-  Future run(Debugger debugger, List<String> args) {
-    var cmdo = debugger.cmdo;
-    if (args.length == 1 ||
-        (args.length == 2 && args[1] == 'list')) {
-      return _listIsolates(debugger);
-    } else if (args.length == 2) {
-      cmdo.print('UNIMPLEMENTED');
-      return new Future.value();
-    } else {
-      if (args.length > 1) {
-        cmdo.print('Unrecognized isolate command');
-        printHelp(debugger, []);
-        return new Future.value();
-      }
-    }
-  }
-    
-  Future _listIsolates(Debugger debugger) {
-    var cmdo = debugger.cmdo;
-    if (debugger.vm == null) {
-      cmdo.print('No VM is attached');
-      return new Future.value();
-    }
-    return debugger.vm.reload().then((vm) {
-        // Sort the isolates by their indices.
-        var isolates = vm.isolates.toList();
-        isolates.sort((iso1, iso2) {
-            return (debugger.getIsolateIndex(iso1) -
-                    debugger.getIsolateIndex(iso2));
-          });
-
-        StringBuffer sb = new StringBuffer();
-        cmdo.print('  ID       NAME         STATE');
-        cmdo.print('-----------------------------------------------');
-        for (var isolate in isolates) {
-          if (isolate == debugger.isolate) {
-            sb.write('* ');
-          } else {
-            sb.write('  ');
-          }
-          sb.write(debugger.getIsolateIndex(isolate).toString().padRight(8));
-          sb.write(' ');
-          sb.write(isolate.name.padRight(12));
-          sb.write(' ');
-          if (isolate.pauseEvent != null) {
-            switch (isolate.pauseEvent.eventType) {
-              case 'IsolateCreated':
-                sb.write('paused at isolate start');
-                break;
-              case 'IsolateShutdown':
-                sb.write('paused at isolate exit');
-                break;
-              case 'IsolateInterrupted':
-                sb.write('paused');
-                break;
-              case 'BreakpointReached':
-                sb.write('paused by breakpoint');
-                break;
-              case 'ExceptionThrown':
-                sb.write('paused by exception');
-                break;
-              default:
-                sb.write('paused by unknown cause');
-                break;
-            }
-          } else if (isolate.running) {
-            sb.write('running');
-          } else if (isolate.idle) {
-            sb.write('idle');
-          } else if (isolate.loading) {
-            // TODO(turnidge): This is weird in a command line debugger.
-            sb.write('(not available)');
-          }
-          sb.write('\n');
-        }
-        cmdo.print(sb);
-      });
-    return new Future.value();
-  }
-
-  List<String> complete(List<String> commandParts) {
-    if (commandParts.isEmpty) {
-      return ['$name ${commandParts.join(" ")}'];
-    } else {
-      var completions =  _commands.complete(commandParts);
-      return completions.map((completion) {
-          return '$name $completion';
-        });
-    }
-  }
-}
-
-class QuitCommand extends Command {
-  final name = 'quit';
-  final helpShort = 'Quit the debugger.';
-  void printHelp(Debugger debugger, List<String> args) {
-    debugger.cmdo.print('''
------ quit -----
-
-Quit the debugger.
-
-Usage:
-  quit
-''');
-  }
-
-  Future run(Debugger debugger, List<String> args) {
-    var cmdo = debugger.cmdo;
-    if (args.length > 1) {
-      cmdo.print("Unexpected arguments to $name command.");
-      return new Future.value();
-    }
-    return debugger.quit();
-  }
-}
diff --git a/tools/ddbg_service/lib/terminfo.dart b/tools/ddbg_service/lib/terminfo.dart
deleted file mode 100644
index 0ec8860..0000000
--- a/tools/ddbg_service/lib/terminfo.dart
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library terminfo;
-
-import 'dart:convert';
-import 'dart:io';
-
-int _tputGetInteger(String capName) {
-  var result = Process.runSync('tput',  ['$capName'], stdoutEncoding:UTF8);
-  if (result.exitCode != 0) {
-    return 0;
-  }
-  return int.parse(result.stdout);
-}
-
-String _tputGetSequence(String capName) {
-  var result = Process.runSync('tput',  ['$capName'], stdoutEncoding:UTF8);
-  if (result.exitCode != 0) {
-    return '';
-  }
-  return result.stdout;
-}
-
-class TermInfo {
-  TermInfo() {
-    resize();
-  }
-
-  int get lines => _lines;
-  int get cols => _cols;
-
-  int _lines;
-  int _cols;
-
-  void resize() {
-    _lines = _tputGetInteger('lines');
-    _cols = _tputGetInteger('cols');
-  }
-
-  // Back one character.
-  final String cursorBack = _tputGetSequence('cub1');
-
-  // Forward one character.
-  final String cursorForward = _tputGetSequence('cuf1');
-
-  // Up one character.
-  final String cursorUp = _tputGetSequence('cuu1');
-
-  // Down one character.
-  final String cursorDown = _tputGetSequence('cud1');
-
-  // Clear to end of line.
-  final String clrEOL = _tputGetSequence('el');
-
-  // Clear screen and home cursor.
-  final String clear = _tputGetSequence('clear');
-}
diff --git a/tools/ddbg_service/pubspec.yaml b/tools/ddbg_service/pubspec.yaml
deleted file mode 100644
index f6b93de..0000000
--- a/tools/ddbg_service/pubspec.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-name: ddbg
-description: A command-line Dart debugger
-dependencies:
-  logging: any
-  observatory:
-    path: /Users/turnidge/ws/dart-repo/dart/runtime/bin/vmservice/observatory
-#dev_dependencies:
-#  unittest: any
diff --git a/tools/deps/dartium.deps/DEPS b/tools/deps/dartium.deps/DEPS
index 25978fa..fb3f166 100644
--- a/tools/deps/dartium.deps/DEPS
+++ b/tools/deps/dartium.deps/DEPS
@@ -14,7 +14,7 @@
   "dartium_chromium_commit": "62a7524d4f71c9e0858d24b0aa1bbff3a2d09bff",
   "chromium_base_revision": "297060",
   "dartium_webkit_branch": "/blink/branches/dart/dartium",
-  "dartium_webkit_revision": "202699",
+  "dartium_webkit_revision": "202728",
 
   # We use mirrors of all github repos to guarantee reproducibility and
   # consistency between what users see and what the bots see.
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index 0f8867d..92a5ed0 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -722,6 +722,9 @@
     # postMessage
     'any set MessagePort.postMessage': _serialize_SSV,
     'SerializedScriptValue set Window.postMessage': _serialize_SSV,
+    'SerializedScriptValue set Worker.postMessage': _serialize_SSV,
+    'any set DedicatedWorkerGlobalScope.postMessage' : _serialize_SSV,
+    'SerializedScriptValue set ServiceWorkerClient.postMessage': _serialize_SSV,
 
     '* get CustomEvent.detail':
       Conversion('convertNativeToDart_SerializedScriptValue',
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index e207e79..78193a5 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -439,12 +439,6 @@
   'DataTransferItemList.add(DOMString data, DOMString type)': 'addData',
   'FormData.append(DOMString name, Blob value, DOMString filename)':
       'appendBlob',
-  'IDBDatabase.transaction(DOMStringList storeNames, IDBTransactionMode mode)':
-      'transactionStores',
-  'IDBDatabase.transaction(sequence<DOMString> storeNames, IDBTransactionMode mode)':
-      'transactionList',
-  'IDBDatabase.transaction(DOMString storeName, IDBTransactionMode mode)':
-      'transactionStore',
   'RTCDataChannel.send(ArrayBuffer data)': 'sendByteBuffer',
   'RTCDataChannel.send(ArrayBufferView data)': 'sendTypedData',
   'RTCDataChannel.send(Blob data)': 'sendBlob',
@@ -777,6 +771,7 @@
     'HTMLTitleElement.text',
     'HTMLUListElement.compact',
     'HTMLUListElement.type',
+    'IDBDatabase.transaction', # We do this in a template without the generated implementation at all.
     'Location.valueOf',
     'MessageEvent.ports',
     'MessageEvent.webkitInitMessageEvent',
diff --git a/tools/dom/templates/html/impl/impl_Document.darttemplate b/tools/dom/templates/html/impl/impl_Document.darttemplate
index 2060813..ca0705a 100644
--- a/tools/dom/templates/html/impl/impl_Document.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Document.darttemplate
@@ -64,11 +64,9 @@
   @DomName('Document.createElement')
   Element createElement(String tagName, [String typeExtension]) {
 $if DART2JS
-    if (typeExtension == null) {
-      return _createElement_2(tagName);
-    } else {
-      return _createElement(tagName, typeExtension);
-    }
+    return (typeExtension == null)
+        ? _createElement_2(tagName)
+        : _createElement(tagName, typeExtension);
 $else
     var newElement = (typeExtension == null) ?
       _blink.BlinkDocument.instance.createElement_Callback_1_(unwrap_jso(this), tagName) :
@@ -94,24 +92,23 @@
   // The two-argument version of this is automatically generated, but we need to
   // omit the typeExtension if it's null on Firefox or we get an is="null" attribute.
   @DomName('Document.createElement')
-  _createElement_2(String tagName) => JS('', '#.createElement(#)', this, tagName);
+  _createElement_2(String tagName) =>
+      JS('Element', '#.createElement(#)', this, tagName);
 
   // The three-argument version of this is automatically generated, but we need to
   // omit the typeExtension if it's null on Firefox or we get an is="null" attribute.
   @DomName('Document.createElementNS')
   _createElementNS_2(String namespaceURI, String qualifiedName) =>
-      JS('', '#.createElementNS(#, #)', this, namespaceURI, qualifiedName);
+      JS('Element', '#.createElementNS(#, #)', this, namespaceURI, qualifiedName);
 
 $endif
   @DomName('Document.createElementNS')
   @DocsEditable()
   Element createElementNS(String namespaceURI, String qualifiedName, [String typeExtension]) {
 $if DART2JS
-    if (typeExtension == null) {
-      return _createElementNS_2(namespaceURI, qualifiedName);
-    } else {
-      return _createElementNS(namespaceURI, qualifiedName, typeExtension);
-    }
+    return (typeExtension == null)
+        ? _createElementNS_2(namespaceURI, qualifiedName)
+        : _createElementNS(namespaceURI, qualifiedName, typeExtension);
 $else
     var newElement = (typeExtension == null) ?
       _blink.BlinkDocument.instance.createElementNS_Callback_2_(unwrap_jso(this), namespaceURI, qualifiedName) :
diff --git a/tools/dom/templates/html/impl/impl_IDBDatabase.darttemplate b/tools/dom/templates/html/impl/impl_IDBDatabase.darttemplate
index c89c29a..8a74ad3 100644
--- a/tools/dom/templates/html/impl/impl_IDBDatabase.darttemplate
+++ b/tools/dom/templates/html/impl/impl_IDBDatabase.darttemplate
@@ -53,7 +53,7 @@
     List storeNames_1 = convertDartToNative_StringArray(storeNames);
     return _transaction(storeNames_1, mode);
   }
-  
+
   Transaction transactionStores(DomStringList storeNames, String mode) {
     if (mode != 'readonly' && mode != 'readwrite') {
       throw new ArgumentError(mode);
@@ -63,6 +63,28 @@
 
   @JSName('transaction')
   Transaction _transaction(stores, mode) native;
+$else
+  Transaction transaction(storeName_OR_storeNames, String mode) {
+    if (mode != 'readonly' && mode != 'readwrite') {
+      throw new ArgumentError("Invalid transaction mode $mode");
+    }
+    var names;
+    if (storeName_OR_storeNames == null) {
+      throw new ArgumentError("stores may not be null in transaction");
+    } else if (storeName_OR_storeNames is String || storeName_OR_storeNames is DomStringList) {
+      names = unwrap_jso(storeName_OR_storeNames);
+    } else if (storeName_OR_storeNames is List<String>) {
+      names = convertDartToNative_List(storeName_OR_storeNames);
+    } else {
+      throw new ArgumentError("Invalid store(s) $store_Name_OR_storeNames");
+    }
+
+    return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_2_(unwrap_jso(this), names, mode));
+  }
+
+  Transaction transactionList(List<String> storeNames, String mode) => transaction(storeNames, mode);
+  Transaction transactionStores(List<String> storeNames, String mode) => transaction(storeNames, mode);
+  Transaction transactionStore(String storeName, String mode) => transaction(storeName, mode);
 $endif
 
 $!MEMBERS}
diff --git a/tools/gyp/configurations_make.gypi b/tools/gyp/configurations_make.gypi
index 683ca51..ebaf935 100644
--- a/tools/gyp/configurations_make.gypi
+++ b/tools/gyp/configurations_make.gypi
@@ -29,9 +29,10 @@
           # '-fvisibility=hidden',
           # '-fvisibility-inlines-hidden',
           '-fstack-protector',
+          '-Wa,--noexecstack',
         ],
         'ldflags': [
-          '-Wa,--noexecstack',
+          '-Wl,-z,noexecstack',
           '-Wl,-z,now',
           '-Wl,-z,relro',
         ],
@@ -236,6 +237,10 @@
         ],
         'cflags': [
           '-O3',
+          '-ffunction-sections',
+        ],
+        'ldflags': [
+          '-Wl,--gc-sections',
         ],
       },
     },
diff --git a/tools/gyp/configurations_xcode.gypi b/tools/gyp/configurations_xcode.gypi
index 3f22df5..f709727 100644
--- a/tools/gyp/configurations_xcode.gypi
+++ b/tools/gyp/configurations_xcode.gypi
@@ -25,6 +25,7 @@
           'GCC_ENABLE_CPP_RTTI': 'NO', # -fno-rtti
           'GCC_DEBUGGING_SYMBOLS': 'default', # -g
           'GCC_GENERATE_DEBUGGING_SYMBOLS': 'YES', # Do not strip symbols
+          'DEAD_CODE_STRIPPING': 'YES',  # -Wl,-dead_strip
           'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden
           'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES', # -fvisibility-inlines-hidden
           'GCC_WARN_NON_VIRTUAL_DESTRUCTOR': 'YES', # -Wnon-virtual-dtor
diff --git a/tools/make_links.py b/tools/make_links.py
index 58bc9cb..157008a 100644
--- a/tools/make_links.py
+++ b/tools/make_links.py
@@ -29,8 +29,9 @@
 import utils
 
 # Useful messages when we find orphaned checkouts.
-old_directories = {'package_config':
-  'Please remove third_party/pkg/package_config.'}
+old_directories = {
+    'package_config': 'Please remove third_party/pkg/package_config.',
+    'analyzer_cli': 'Please remove third_party/pkg/analyzer_cli.'}
 
 def get_options():
   result = optparse.OptionParser()
diff --git a/tools/precompilation/test_linux.sh b/tools/precompilation/test_linux.sh
index d6263b1..f5b1865 100755
--- a/tools/precompilation/test_linux.sh
+++ b/tools/precompilation/test_linux.sh
@@ -6,8 +6,8 @@
 
 ./tools/build.py -mdebug -ax64 runtime
 
-./out/DebugX64/dart_no_snapshot --gen-precompiled-snapshot "$1"
+./out/DebugX64/dart_no_snapshot --gen-precompiled-snapshot --package-root=out/DebugX64/packages/ "$1"
 
 gcc -m64 -shared -Wl,-soname,libprecompiled.so -o libprecompiled.so precompiled.S
 
-LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" gdb -ex run --args ./out/DebugX64/dart --run-precompiled-snapshot --observe --profile-vm not_used.dart
+LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" gdb -ex run --args ./out/DebugX64/dart_precompiled --run-precompiled-snapshot not_used.dart
diff --git a/tools/precompilation/test_linux_simarm.sh b/tools/precompilation/test_linux_simarm.sh
index 5f477f6..f87c6a5 100755
--- a/tools/precompilation/test_linux_simarm.sh
+++ b/tools/precompilation/test_linux_simarm.sh
@@ -6,8 +6,8 @@
 
 ./tools/build.py -mdebug -asimarm runtime
 
-./out/DebugSIMARM/dart_no_snapshot --gen-precompiled-snapshot "$1"
+./out/DebugSIMARM/dart_no_snapshot --gen-precompiled-snapshot --package-root=out/DebugX64/packages/ "$1"
 
 gcc -m32 -shared -Wl,-soname,libprecompiled.so -o libprecompiled.so precompiled.S
 
-LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" gdb -ex run --args ./out/DebugSIMARM/dart --run-precompiled-snapshot --observe not_used.dart
+LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" gdb -ex run --args ./out/DebugSIMARM/dart_precompiled --run-precompiled-snapshot not_used.dart
diff --git a/tools/precompilation/test_macos.sh b/tools/precompilation/test_macos.sh
index 4dbf51c..510478f 100755
--- a/tools/precompilation/test_macos.sh
+++ b/tools/precompilation/test_macos.sh
@@ -6,8 +6,8 @@
 
 ./tools/build.py -mdebug -ax64 runtime
 
-./xcodebuild/DebugX64/dart_no_snapshot --gen-precompiled-snapshot "$1"
+./xcodebuild/DebugX64/dart_no_snapshot --gen-precompiled-snapshot --package-root=xcodebuild/DebugX64/packages/ "$1"
 
 clang -m64 -dynamiclib -o libprecompiled.dylib precompiled.S
 
-LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" lldb -- ./xcodebuild/DebugX64/dart --run-precompiled-snapshot --observe not_used.dart
+LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" lldb -- ./xcodebuild/DebugX64/dart_precompiled --run-precompiled-snapshot not_used.dart
diff --git a/utils/dartanalyzer/dartanalyzer.gyp b/utils/dartanalyzer/dartanalyzer.gyp
index 93dc15f..9617f05 100644
--- a/utils/dartanalyzer/dartanalyzer.gyp
+++ b/utils/dartanalyzer/dartanalyzer.gyp
@@ -18,7 +18,7 @@
             '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart<(EXECUTABLE_SUFFIX)',
             '../../sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart',
             '<(SHARED_INTERMEDIATE_DIR)/packages.stamp',
-            '<!@(["python", "../../tools/list_files.py", "\\.dart$", "../../third_party/pkg/analyzer_cli"])',
+            '<!@(["python", "../../tools/list_files.py", "\\.dart$", "../../pkg/analyzer_cli"])',
           ],
           'outputs': [
             '<(SHARED_INTERMEDIATE_DIR)/dartanalyzer.dart.snapshot',
@@ -27,7 +27,7 @@
             '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart<(EXECUTABLE_SUFFIX)',
             '--snapshot=<(SHARED_INTERMEDIATE_DIR)/dartanalyzer.dart.snapshot',
             '--package-root=<(PRODUCT_DIR)/packages/',
-            '../../third_party/pkg/analyzer_cli/bin/analyzer.dart',
+            '../../pkg/analyzer_cli/bin/analyzer.dart',
           ],
         },
       ],