Version 1.13.0-dev.6.0

Merge commit '3abd6ad7583fa0e87158fddbdc7668c851874e5f' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e6e2695..2f9aadf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,26 +1,40 @@
 ## 1.13.0
 
+### Core library changes
+* `dart:async`
+  * `StreamTransformer` instances created with `fromHandlers` with no
+    `handleError` callback now forward stack traces along with errors to the
+    resulting streams.
+
 * `dart:core`
   * `Uri` added `removeFragment` method.
   * `String.allMatches` (implementing `Pattern.allMatches`) is now lazy,
     as all `allMatches` implementations are intended to be.
+  * `Resource` is deprecated in favor of the resource package.
+    See https://pub.dartlang.org/packages/resource to learn more. This is
+    the last release to contain the Resource class.
 
 * `dart:io`
   * `HttpClient` no longer sends URI fragments in the request. This is not
     allowed by the HTTP protocol.
     The `HttpServer` still gracefully receives fragments, but discards them
     before delivering the request.
-
-* `dart:async`
-  * `StreamTransformer`s created with `fromHandlers` with no `handleError`
-    callback now forward stack traces along with errors to the resulting
-    streams.
+  * Removed server socket references. The use of server socket references
+    was deprecated back in 1.9. Use the `shared` flag when creating listening
+    sockets and `HttpServer` to distribute accepted sockets between isolates.
 
 ### Tool changes
 
 * `docgen` and 'dartdocgen' no longer ship in the sdk. The `docgen` sources have
    been removed from the repository.
 
+* This is the last release to ship the VM's "legacy debug protocol".
+  We intend to remove the legacy debug protocol in Dart VM 1.14.
+
+* The VM's Service Protocol has been updated to version 3.0 to take care
+  of a number of issues uncovered by the first few non-observatory
+  clients.  This is a potentially breaking change for clients.
+
 ## 1.12.0
 
 ### Language changes
diff --git a/DEPS b/DEPS
index 9cb65e6..ac30916 100644
--- a/DEPS
+++ b/DEPS
@@ -38,7 +38,7 @@
 
   # Revisions of /third_party/* dependencies.
   "7zip_rev" : "@19997",
-  "analyzer_cli_rev" : "@0b89a16c0566f36676fa8f2016eb2c332178f616",
+  "analyzer_cli_rev" : "@c8a60be821be07df64cde2efb8f87b462a91a521",
   "args_tag": "@0.13.0",
   "async_tag": "@1.2.0",
   "barback_tag" : "@0.15.2+7",
@@ -50,8 +50,8 @@
   "collection_rev": "@1da9a07f32efa2ba0c391b289e2037391e31da0e",
   "crypto_rev" : "@2df57a1e26dd88e8d0614207d4b062c73209917d",
   "csslib_tag" : "@0.12.0",
-  "dart2js_info_rev" : "@bad01369f1f605ab688d505c135db54de927318f",
-  "dartdoc_rev" : "@786426c4bbea96729d5eab2add744def41a5a690",
+  "dart2js_info_rev" : "@ffd03ee45f7459efd3039ff565b4d0aa2e7cd9e7",
+  "dartdoc_rev" : "@d51211b7c0a30862a691aa6dc0631009bd926004",
   "dart_services_rev" : "@7aea2574e6f3924bf409a80afb8ad52aa2be4f97",
   "dart_style_tag": "@0.2.0",
   "dev_compiler_rev": "@0.1.8",
diff --git a/codereview.settings b/codereview.settings
index 3e78887..ada9e3c 100644
--- a/codereview.settings
+++ b/codereview.settings
@@ -1,4 +1,4 @@
 # This file is used by gcl to get repository specific information.
-CODE_REVIEW_SERVER: http://codereview.chromium.org/
+CODE_REVIEW_SERVER: http://codereview.chromium.org
 VIEW_VC: https://github.com/dart-lang/sdk/commit/
 CC_LIST: reviews@dartlang.org
diff --git a/pkg/analysis_server/benchmark/perf/analysis_timing_tests.dart b/pkg/analysis_server/benchmark/perf/analysis_timing_tests.dart
index fd50e13..6f7a3c6 100644
--- a/pkg/analysis_server/benchmark/perf/analysis_timing_tests.dart
+++ b/pkg/analysis_server/benchmark/perf/analysis_timing_tests.dart
@@ -7,43 +7,82 @@
 import 'dart:async';
 import 'dart:io';
 
+import 'package:analysis_server/src/protocol.dart';
 import 'package:args/args.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart';
 
 import '../../test/utils.dart';
 import 'performance_tests.dart';
 
-const String SOURCE_OPTION = 'source';
-
 /**
- * Pass in the directory of the source to be analyzed as option --source
+ * Pass in the directory of the source to be analyzed as option `--source`,
+ * optionally specify a priority file with `--priority` and the specific
+ * test to run with `--test`.  If no test is specified, the default is
+ * `analysis`.
  */
-main(List<String> arguements) {
+main(List<String> arguments) {
   initializeTestEnvironment();
   ArgParser parser = _createArgParser();
-  var args = parser.parse(arguements);
+  var args = parser.parse(arguments);
   if (args[SOURCE_OPTION] == null) {
     print('path to source directory must be specified');
     exit(1);
   }
   source = args[SOURCE_OPTION];
-  defineReflectiveTests(AnalysisTimingIntegrationTest);
+  priorityFile = args[PRIORITY_FILE_OPTION];
+  testName = args[TEST_NAME_OPTION] ?? DEFAULT_TEST;
+
+  switch (testName) {
+    case 'analysis':
+      defineReflectiveTests(AnalysisTimingIntegrationTest);
+      break;
+    case 'highlighting':
+      defineReflectiveTests(HighlightingTimingIntegrationTest);
+      break;
+    case 'navigation':
+      defineReflectiveTests(NavigationTimingIntegrationTest);
+      break;
+    case 'outline':
+      defineReflectiveTests(OutlineTimingIntegrationTest);
+      break;
+    default:
+      print('unrecognized test name $testName');
+      exit(1);
+  }
 }
 
+const DEFAULT_TEST = 'analysis';
+const PRIORITY_FILE_OPTION = 'priority';
+const SOURCE_OPTION = 'source';
+const TEST_NAME_OPTION = 'test';
+
+String priorityFile;
 String source;
+String testName;
+
+ArgParser _createArgParser() => new ArgParser()
+  ..addOption(TEST_NAME_OPTION, help: 'test name (defaults to `analysis`)')
+  ..addOption(SOURCE_OPTION, help: 'full path to source directory for analysis')
+  ..addOption(PRIORITY_FILE_OPTION,
+      help: '(optional) full path to a priority file');
+
+class AbstractTimingTest extends AbstractAnalysisServerPerformanceTest {
+  @override
+  Future setUp() => super.setUp().then((_) {
+        sourceDirectory = new Directory(source);
+        subscribeToStatusNotifications();
+      });
+}
 
 @reflectiveTest
-class AnalysisTimingIntegrationTest
-    extends AbstractAnalysisServerPerformanceTest {
+class AnalysisTimingIntegrationTest extends AbstractTimingTest {
   test_detect_analysis_done() {
-    sourceDirectory = new Directory(source);
-    subscribeToStatusNotifications();
-    return _runAndTimeAnalysis();
-  }
-
-  Future _runAndTimeAnalysis() {
     stopwatch.start();
     setAnalysisRoot();
+    if (priorityFile != null) {
+      sendAnalysisSetPriorityFiles([priorityFile]);
+    }
     return analysisFinished.then((_) {
       print('analysis completed in ${stopwatch.elapsed}');
       stopwatch.reset();
@@ -51,9 +90,67 @@
   }
 }
 
-ArgParser _createArgParser() {
-  ArgParser parser = new ArgParser();
-  parser.addOption('source',
-      help: 'full path to source directory for analysis');
-  return parser;
+@reflectiveTest
+class HighlightingTimingIntegrationTest extends PriorityFileTimer {
+  @override
+  String get description => 'highlighting';
+
+  @override
+  Stream get eventStream => onAnalysisHighlights;
+
+  @override
+  AnalysisService get service => AnalysisService.HIGHLIGHTS;
+}
+
+@reflectiveTest
+class NavigationTimingIntegrationTest extends PriorityFileTimer {
+  @override
+  String get description => 'navigation';
+
+  @override
+  Stream get eventStream => onAnalysisNavigation;
+
+  @override
+  AnalysisService get service => AnalysisService.NAVIGATION;
+}
+
+@reflectiveTest
+class OutlineTimingIntegrationTest extends PriorityFileTimer {
+  @override
+  String get description => 'outline';
+
+  @override
+  Stream get eventStream => onAnalysisOutline;
+
+  @override
+  AnalysisService get service => AnalysisService.OUTLINE;
+}
+
+abstract class PriorityFileTimer extends AbstractTimingTest {
+  String get description;
+  Stream get eventStream;
+  AnalysisService get service;
+
+  Future test_timing() {
+    expect(priorityFile, isNotNull,
+        reason: 'A priority file must be specified for $description testing.');
+    stopwatch.start();
+
+    Duration elapsed;
+    eventStream.listen((_) {
+      elapsed = stopwatch.elapsed;
+    });
+
+    setAnalysisRoot();
+    sendAnalysisSetSubscriptions({
+      service: [priorityFile]
+    });
+
+    sendAnalysisSetPriorityFiles([priorityFile]);
+
+    return analysisFinished.then((_) {
+      print('$description completed in ${elapsed}');
+      stopwatch.reset();
+    });
+  }
 }
diff --git a/pkg/analysis_server/benchmark/perf/performance_tests.dart b/pkg/analysis_server/benchmark/perf/performance_tests.dart
index a926e33..3dd1842 100644
--- a/pkg/analysis_server/benchmark/perf/performance_tests.dart
+++ b/pkg/analysis_server/benchmark/perf/performance_tests.dart
@@ -25,9 +25,8 @@
    * Send the server an 'analysis.setAnalysisRoots' command directing it to
    * analyze [sourceDirectory].
    */
-  Future setAnalysisRoot() {
-    return sendAnalysisSetAnalysisRoots([sourceDirectory.path], []);
-  }
+  Future setAnalysisRoot() =>
+      sendAnalysisSetAnalysisRoots([sourceDirectory.path], []);
 
   /**
    * Enable [SERVER_STATUS] notifications so that [analysisFinished]
@@ -69,7 +68,5 @@
    * After every test, the server is stopped.
    */
   @override
-  Future tearDown() {
-    return shutdownIfNeeded();
-  }
+  Future tearDown() => shutdownIfNeeded();
 }
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 52b4419..69a9f87 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.9.0</h1>
+    <h1 style="color:#999999">Version 1.12.0</h1>
     <p>
       This document contains a specification of the API provided by the
       analysis server.  The API in this document is currently under
@@ -1200,6 +1200,8 @@
   "event": "analysis.outline"
   "params": {
     "<b>file</b>": <a href="#type_FilePath">FilePath</a>
+    "<b>kind</b>": <a href="#type_FileKind">FileKind</a>
+    "<b>libraryName</b>": <span style="color:#999999">optional</span> String
     "<b>outline</b>": <a href="#type_Outline">Outline</a>
   }
 }</pre></div>
@@ -1218,6 +1220,21 @@
             <p>
               The file with which the outline is associated.
             </p>
+          </dd><dt class="field"><b><i>kind ( <a href="#type_FileKind">FileKind</a> )</i></b></dt><dd>
+            
+            <p>
+              The kind of the file.
+            </p>
+          </dd><dt class="field"><b><i>libraryName ( <span style="color:#999999">optional</span> String )</i></b></dt><dd>
+            
+            <p>
+              The name of the library defined by the file using a "library"
+              directive, or referenced by a "part of" directive. If both
+              "library" and "part of" directives are present, then the
+              "library" directive takes precedence.
+              This field will be omitted if the file has neither "library"
+              nor "part of" directives.
+            </p>
           </dd><dt class="field"><b><i>outline ( <a href="#type_Outline">Outline</a> )</i></b></dt><dd>
             
             <p>
@@ -2309,6 +2326,7 @@
       
       
       
+      
     <dl><dt class="typeDefinition"><a name="type_AddContentOverlay">AddContentOverlay: object</a></dt><dd>
         <p>
           A directive to begin overlaying the contents of a file.  The
@@ -2362,6 +2380,20 @@
               the error. The field is omitted if there is no correction
               message associated with the error code.
             </p>
+          </dd><dt class="field"><b><i>hasFix ( <span style="color:#999999">optional</span> bool )</i></b></dt><dd>
+            
+            <p>
+              A hint to indicate to interested clients that this error has
+              an associated fix (or fixes).  The absence of this field implies
+              there are not known to be fixes.  Note that since the operation
+              to calculate whether fixes apply needs to be performant it is
+              possible that complicated tests will be skipped and a false
+              negative returned.  For this reason, this attribute should be
+              treated as a "hint".  Despite the possibility of false negatives,
+              no false positives should be returned.  If a client sees this
+              flag set they can proceed with the confidence that there are in
+              fact associated fixes.
+            </p>
           </dd></dl></dd><dt class="typeDefinition"><a name="type_AnalysisErrorFixes">AnalysisErrorFixes: object</a></dt><dd>
         <p>
           A list of fixes associated with a specific error
@@ -2775,7 +2807,12 @@
           domain.
         </p>
         
-      <dl><dt class="value">LAUNCH_DATA</dt></dl></dd><dt class="typeDefinition"><a name="type_FilePath">FilePath: String</a></dt><dd>
+      <dl><dt class="value">LAUNCH_DATA</dt></dl></dd><dt class="typeDefinition"><a name="type_FileKind">FileKind: String</a></dt><dd>
+        <p>
+          An enumeration of the kinds of files.
+        </p>
+        
+      <dl><dt class="value">LIBRARY</dt><dt class="value">PART</dt></dl></dd><dt class="typeDefinition"><a name="type_FilePath">FilePath: String</a></dt><dd>
         
         <p>
           The absolute path of a file.
@@ -3918,16 +3955,28 @@
         </p>
       <h4>Feedback</h4><p>none</p><h4>Options</h4><p>none</p></dd><dt class="refactoring">EXTRACT_LOCAL_VARIABLE</dt><dd>
         <p>
-          Create a local variable initialized by a specified
-          expression.
+          Create a local variable initialized by the expression that covers
+          the specified selection.
         </p>
         <p>
-          It is an error if the range contains anything other than a
-          complete expression (no partial expressions are allowed).
+          It is an error if the selection range is not covered by a
+          complete expression.
         </p>
         
         
-      <h4>Feedback</h4><dl><dt class="field"><b><i>names ( List&lt;String&gt; )</i></b></dt><dd>
+      <h4>Feedback</h4><dl><dt class="field"><b><i>coveringExpressionOffsets ( List&lt;int&gt; )</i></b></dt><dd>
+            
+            <p>
+              The offsets of the expressions that cover the specified
+              selection, from the down most to the up most.
+            </p>
+          </dd><dt class="field"><b><i>coveringExpressionLengths ( List&lt;int&gt; )</i></b></dt><dd>
+            
+            <p>
+              The lengths of the expressions that cover the specified
+              selection, from the down most to the up most.
+            </p>
+          </dd><dt class="field"><b><i>names ( List&lt;String&gt; )</i></b></dt><dd>
             
             <p>
               The proposed names for the local variable.
@@ -4202,7 +4251,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_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.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/analysis/index_core.dart b/pkg/analysis_server/lib/analysis/index_core.dart
index aac9d8a..58e996e 100644
--- a/pkg/analysis_server/lib/analysis/index_core.dart
+++ b/pkg/analysis_server/lib/analysis/index_core.dart
@@ -12,6 +12,16 @@
 import 'package:analyzer/src/generated/source.dart';
 
 /**
+ * Return the integer value that corresponds to the given [string]. The value of
+ * [string] may be `null`.
+ *
+ * Clients are not expected to implement this signature. A function of this type
+ * is provided by the framework to clients in order to implement the method
+ * [IndexableObjectKind.encodeHash].
+ */
+typedef int StringToInt(String string);
+
+/**
  * An object that can have a [Relationship] with various [Location]s in a code
  * base. The object is abstractly represented by a [kind] and an [offset] within
  * a [source].
@@ -29,17 +39,6 @@
   IndexableObjectKind get kind;
 
   /**
-   * Return the length of the indexable object within its source.
-   */
-  int get length;
-
-  /**
-   * Return the name of this element.
-   */
-  // TODO(brianwilkerson) Remove the need for this getter.
-  String get name;
-
-  /**
    * Return the offset of the indexable object within its source.
    */
   int get offset;
@@ -88,6 +87,27 @@
   IndexableObject decode(AnalysisContext context, String filePath, int offset);
 
   /**
+   * Returns the hash value that corresponds to the given [indexable].
+   *
+   * This hash is used to remember buckets with relations of the given
+   * [indexable]. Usually the name of the indexable object is encoded
+   * using [stringToInt] and mixed with other information to produce the final
+   * result.
+   *
+   * Clients must ensure that the same value is returned for the same object.
+   *
+   * Returned values must have good selectivity, e.g. if it is possible that
+   * there are many different objects with the same name, then additional
+   * information should be mixed in, for example the hash of the source that
+   * declares the given [indexable].
+   *
+   * Clients don't have to use name to compute this result, so if an indexable
+   * object does not have a name, some other value may be returned, but it still
+   * must be always the same for the same object and have good selectivity.
+   */
+  int encodeHash(StringToInt stringToInt, IndexableObject indexable);
+
+  /**
    * Return the object kind with the given [index].
    */
   static IndexableObjectKind getKind(int index) {
@@ -121,20 +141,6 @@
   void contributeTo(IndexStore store, AnalysisContext context, Object object);
 }
 
-// A sketch of what the driver routine might look like:
-//
-//void buildIndexForSource(AnalysisContext context, Source source) {
-//  IndexStoreImpl store;
-//  store.aboutToIndex(context, source);
-//  try {
-//    for (IndexContributor contributor in contributors) {
-//      contributor.contributeTo(store, context, source);
-//    }
-//  } finally {
-//    store.doneIndexing();
-//  }
-//}
-
 /**
  * An object that stores information about the relationships between locations
  * in a code base.
diff --git a/pkg/analysis_server/lib/analysis/navigation_core.dart b/pkg/analysis_server/lib/analysis/navigation_core.dart
index e2f56f8..2e2623d 100644
--- a/pkg/analysis_server/lib/analysis/navigation_core.dart
+++ b/pkg/analysis_server/lib/analysis/navigation_core.dart
@@ -25,8 +25,7 @@
 }
 
 /**
- * An object that [NavigationContributor]s use to record navigation regions
- * into.
+ * An object that [NavigationContributor]s use to record navigation regions.
  *
  * Clients are not expected to subtype this class.
  */
diff --git a/pkg/analysis_server/lib/plugin/occurrences.dart b/pkg/analysis_server/lib/plugin/occurrences.dart
index 5339ccc..eaabc26 100644
--- a/pkg/analysis_server/lib/plugin/occurrences.dart
+++ b/pkg/analysis_server/lib/plugin/occurrences.dart
@@ -5,6 +5,23 @@
 /**
  * Support for client code that extends the analysis server by adding new
  * occurrences contributors.
+ *
+ * Plugins can register occurrences contributors. The registered contributors
+ * will be used to get occurrence information any time the server is about to
+ * send an 'analysis.occurrences' notification.
+ *
+ * If a plugin wants to add occurrence information, it should implement the
+ * class [OccurrencesContributor] and then register the contributor by including
+ * code like the following in the plugin's registerExtensions method:
+ *
+ *     @override
+ *     void registerExtensions(RegisterExtension registerExtension) {
+ *       ...
+ *       registerExtension(
+ *           OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT_ID,
+ *           new MyOccurrencesContributor());
+ *       ...
+ *     }
  */
 library analysis_server.plugin.occurrences;
 
@@ -14,8 +31,8 @@
 
 /**
  * The identifier of the extension point that allows plugins to register
- * element occurrences. The object used as an extension must be
- * a [OccurrencesContributor].
+ * occurrence information. The object used as an extension must be an
+ * [OccurrencesContributor].
  */
 final String OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT_ID = Plugin.join(
     ServerPlugin.UNIQUE_IDENTIFIER,
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index cee3508..8cb08b0 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -70,7 +70,7 @@
    * The version of the analysis server. The value should be replaced
    * automatically during the build.
    */
-  static final String VERSION = '1.9.0';
+  static final String VERSION = '1.12.0';
 
   /**
    * The number of milliseconds to perform operations before inserting
@@ -1002,7 +1002,9 @@
               case AnalysisService.OUTLINE:
                 AnalysisContext context = dartUnit.element.context;
                 LineInfo lineInfo = context.getLineInfo(source);
-                sendAnalysisNotificationOutline(this, file, lineInfo, dartUnit);
+                SourceKind kind = context.getKindOf(source);
+                sendAnalysisNotificationOutline(
+                    this, file, lineInfo, kind, dartUnit);
                 break;
               case AnalysisService.OVERRIDES:
                 sendAnalysisNotificationOverrides(this, file, dartUnit);
@@ -1221,8 +1223,15 @@
               if (dartUnits != null) {
                 AnalysisErrorInfo errorInfo = context.getErrors(source);
                 for (var dartUnit in dartUnits) {
-                  scheduleNotificationOperations(this, file, errorInfo.lineInfo,
-                      context, null, dartUnit, errorInfo.errors);
+                  scheduleNotificationOperations(
+                      this,
+                      source,
+                      file,
+                      errorInfo.lineInfo,
+                      context,
+                      null,
+                      dartUnit,
+                      errorInfo.errors);
                   scheduleIndexOperation(this, file, context, dartUnit);
                 }
               } else {
diff --git a/pkg/analysis_server/lib/src/computer/computer_hover.dart b/pkg/analysis_server/lib/src/computer/computer_hover.dart
index c09668b..8d870c0 100644
--- a/pkg/analysis_server/lib/src/computer/computer_hover.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_hover.dart
@@ -111,9 +111,7 @@
           }
         }
         // documentation
-        String dartDoc = element.computeDocumentationComment();
-        dartDoc = _removeDartDocDelimiters(dartDoc);
-        hover.dartdoc = dartDoc;
+        hover.dartdoc = _computeDocumentation(element);
       }
       // parameter
       hover.parameter = _safeToString(expression.bestParameterElement);
@@ -127,5 +125,13 @@
     return null;
   }
 
+  String _computeDocumentation(Element element) {
+    if (element is ParameterElement) {
+      element = element.enclosingElement;
+    }
+    String dartDoc = element.computeDocumentationComment();
+    return _removeDartDocDelimiters(dartDoc);
+  }
+
   static _safeToString(obj) => obj != null ? obj.toString() : null;
 }
diff --git a/pkg/analysis_server/lib/src/constants.dart b/pkg/analysis_server/lib/src/constants.dart
index 391e41c..a32ad98 100644
--- a/pkg/analysis_server/lib/src/constants.dart
+++ b/pkg/analysis_server/lib/src/constants.dart
@@ -137,6 +137,7 @@
 const String FILES = 'files';
 const String FIXES = 'fixes';
 const String FLAGS = 'flags';
+const String HAS_FIX = 'hasFix';
 const String HIERARCHY_ITEMS = 'hierarchyItems';
 const String HOVERS = 'hovers';
 const String ID = 'id';
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index 81d7bf2..970e189 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -6,12 +6,12 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/completion/completion_core.dart'
-    show CompletionRequest, CompletionResult;
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/context_manager.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart'
+    show CompletionRequest, CompletionResult;
 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';
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 0891156..f96f42f 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
@@ -22,6 +22,15 @@
 
   compute() async {
     for (ClassElement type in unitElement.types) {
+      // always include Object and its members
+      if (type.supertype == null) {
+        _addImplementedClass(type);
+        type.accessors.forEach(_addImplementedMember);
+        type.fields.forEach(_addImplementedMember);
+        type.methods.forEach(_addImplementedMember);
+        continue;
+      }
+      // analyze ancestors
       subtypes = await getSubClasses(searchEngine, type);
       if (subtypes.isNotEmpty) {
         _addImplementedClass(type);
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 8b87629..f1b9100 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
@@ -74,6 +74,9 @@
   }
 
   void _addRegionForNode(AstNode node, Element element) {
+    if (node == null) {
+      return;
+    }
     int offset = node.offset;
     int length = node.length;
     _addRegion(offset, length, element);
@@ -92,6 +95,30 @@
   _DartNavigationComputerVisitor(this.computer);
 
   @override
+  visitAnnotation(Annotation node) {
+    Element element = node.element;
+    if (element is ConstructorElement && element.isSynthetic) {
+      element = element.enclosingElement;
+    }
+    Identifier name = node.name;
+    if (name is PrefixedIdentifier) {
+      // use constructor in: @PrefixClass.constructorName
+      Element prefixElement = name.prefix.staticElement;
+      if (prefixElement is ClassElement) {
+        prefixElement = element;
+      }
+      computer._addRegionForNode(name.prefix, prefixElement);
+      // always constructor
+      computer._addRegionForNode(name.identifier, element);
+    } else {
+      computer._addRegionForNode(name, element);
+    }
+    computer._addRegionForNode(node.constructorName, element);
+    // arguments
+    _safelyVisit(node.arguments);
+  }
+
+  @override
   visitAssignmentExpression(AssignmentExpression node) {
     _safelyVisit(node.leftHandSide);
     computer._addRegionForToken(node.operator, node.bestElement);
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index cb7b513..f6c298d 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -557,7 +557,8 @@
       List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
       if (units.isNotEmpty) {
         refactoring = new ExtractLocalRefactoring(units[0], offset, length);
-        feedback = new ExtractLocalVariableFeedback([], [], []);
+        feedback = new ExtractLocalVariableFeedback(
+            <int>[], <int>[], <String>[], <int>[], <int>[]);
       }
     }
     if (kind == RefactoringKind.EXTRACT_METHOD) {
@@ -565,8 +566,8 @@
       if (units.isNotEmpty) {
         refactoring = new ExtractMethodRefactoring(
             searchEngine, units[0], offset, length);
-        feedback = new ExtractMethodFeedback(
-            offset, length, '', [], false, [], [], []);
+        feedback = new ExtractMethodFeedback(offset, length, '', <String>[],
+            false, <RefactoringMethodParameter>[], <int>[], <int>[]);
       }
     }
     if (kind == RefactoringKind.INLINE_LOCAL_VARIABLE) {
diff --git a/pkg/analysis_server/lib/src/generated_protocol.dart b/pkg/analysis_server/lib/src/generated_protocol.dart
index c396864..4c95b37e 100644
--- a/pkg/analysis_server/lib/src/generated_protocol.dart
+++ b/pkg/analysis_server/lib/src/generated_protocol.dart
@@ -3158,12 +3158,18 @@
  *
  * {
  *   "file": FilePath
+ *   "kind": FileKind
+ *   "libraryName": optional String
  *   "outline": Outline
  * }
  */
 class AnalysisOutlineParams implements HasToJson {
   String _file;
 
+  FileKind _kind;
+
+  String _libraryName;
+
   Outline _outline;
 
   /**
@@ -3180,6 +3186,39 @@
   }
 
   /**
+   * The kind of the file.
+   */
+  FileKind get kind => _kind;
+
+  /**
+   * The kind of the file.
+   */
+  void set kind(FileKind value) {
+    assert(value != null);
+    this._kind = value;
+  }
+
+  /**
+   * The name of the library defined by the file using a "library" directive,
+   * or referenced by a "part of" directive. If both "library" and "part of"
+   * directives are present, then the "library" directive takes precedence.
+   * This field will be omitted if the file has neither "library" nor "part of"
+   * directives.
+   */
+  String get libraryName => _libraryName;
+
+  /**
+   * The name of the library defined by the file using a "library" directive,
+   * or referenced by a "part of" directive. If both "library" and "part of"
+   * directives are present, then the "library" directive takes precedence.
+   * This field will be omitted if the file has neither "library" nor "part of"
+   * directives.
+   */
+  void set libraryName(String value) {
+    this._libraryName = value;
+  }
+
+  /**
    * The outline associated with the file.
    */
   Outline get outline => _outline;
@@ -3192,8 +3231,10 @@
     this._outline = value;
   }
 
-  AnalysisOutlineParams(String file, Outline outline) {
+  AnalysisOutlineParams(String file, FileKind kind, Outline outline, {String libraryName}) {
     this.file = file;
+    this.kind = kind;
+    this.libraryName = libraryName;
     this.outline = outline;
   }
 
@@ -3208,13 +3249,23 @@
       } else {
         throw jsonDecoder.missingKey(jsonPath, "file");
       }
+      FileKind kind;
+      if (json.containsKey("kind")) {
+        kind = new FileKind.fromJson(jsonDecoder, jsonPath + ".kind", json["kind"]);
+      } else {
+        throw jsonDecoder.missingKey(jsonPath, "kind");
+      }
+      String libraryName;
+      if (json.containsKey("libraryName")) {
+        libraryName = jsonDecoder._decodeString(jsonPath + ".libraryName", json["libraryName"]);
+      }
       Outline outline;
       if (json.containsKey("outline")) {
         outline = new Outline.fromJson(jsonDecoder, jsonPath + ".outline", json["outline"]);
       } else {
         throw jsonDecoder.missingKey(jsonPath, "outline");
       }
-      return new AnalysisOutlineParams(file, outline);
+      return new AnalysisOutlineParams(file, kind, outline, libraryName: libraryName);
     } else {
       throw jsonDecoder.mismatch(jsonPath, "analysis.outline params", json);
     }
@@ -3228,6 +3279,10 @@
   Map<String, dynamic> toJson() {
     Map<String, dynamic> result = {};
     result["file"] = file;
+    result["kind"] = kind.toJson();
+    if (libraryName != null) {
+      result["libraryName"] = libraryName;
+    }
     result["outline"] = outline.toJson();
     return result;
   }
@@ -3243,6 +3298,8 @@
   bool operator==(other) {
     if (other is AnalysisOutlineParams) {
       return file == other.file &&
+          kind == other.kind &&
+          libraryName == other.libraryName &&
           outline == other.outline;
     }
     return false;
@@ -3252,6 +3309,8 @@
   int get hashCode {
     int hash = 0;
     hash = _JenkinsSmiHash.combine(hash, file.hashCode);
+    hash = _JenkinsSmiHash.combine(hash, kind.hashCode);
+    hash = _JenkinsSmiHash.combine(hash, libraryName.hashCode);
     hash = _JenkinsSmiHash.combine(hash, outline.hashCode);
     return _JenkinsSmiHash.finish(hash);
   }
@@ -7288,6 +7347,7 @@
  *   "location": Location
  *   "message": String
  *   "correction": optional String
+ *   "hasFix": optional bool
  * }
  */
 class AnalysisError implements HasToJson {
@@ -7301,6 +7361,8 @@
 
   String _correction;
 
+  bool _hasFix;
+
   /**
    * The severity of the error.
    */
@@ -7371,12 +7433,39 @@
     this._correction = value;
   }
 
-  AnalysisError(AnalysisErrorSeverity severity, AnalysisErrorType type, Location location, String message, {String correction}) {
+  /**
+   * A hint to indicate to interested clients that this error has an associated
+   * fix (or fixes). The absence of this field implies there are not known to
+   * be fixes. Note that since the operation to calculate whether fixes apply
+   * needs to be performant it is possible that complicated tests will be
+   * skipped and a false negative returned. For this reason, this attribute
+   * should be treated as a "hint". Despite the possibility of false negatives,
+   * no false positives should be returned. If a client sees this flag set they
+   * can proceed with the confidence that there are in fact associated fixes.
+   */
+  bool get hasFix => _hasFix;
+
+  /**
+   * A hint to indicate to interested clients that this error has an associated
+   * fix (or fixes). The absence of this field implies there are not known to
+   * be fixes. Note that since the operation to calculate whether fixes apply
+   * needs to be performant it is possible that complicated tests will be
+   * skipped and a false negative returned. For this reason, this attribute
+   * should be treated as a "hint". Despite the possibility of false negatives,
+   * no false positives should be returned. If a client sees this flag set they
+   * can proceed with the confidence that there are in fact associated fixes.
+   */
+  void set hasFix(bool value) {
+    this._hasFix = value;
+  }
+
+  AnalysisError(AnalysisErrorSeverity severity, AnalysisErrorType type, Location location, String message, {String correction, bool hasFix}) {
     this.severity = severity;
     this.type = type;
     this.location = location;
     this.message = message;
     this.correction = correction;
+    this.hasFix = hasFix;
   }
 
   factory AnalysisError.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
@@ -7412,7 +7501,11 @@
       if (json.containsKey("correction")) {
         correction = jsonDecoder._decodeString(jsonPath + ".correction", json["correction"]);
       }
-      return new AnalysisError(severity, type, location, message, correction: correction);
+      bool hasFix;
+      if (json.containsKey("hasFix")) {
+        hasFix = jsonDecoder._decodeBool(jsonPath + ".hasFix", json["hasFix"]);
+      }
+      return new AnalysisError(severity, type, location, message, correction: correction, hasFix: hasFix);
     } else {
       throw jsonDecoder.mismatch(jsonPath, "AnalysisError", json);
     }
@@ -7427,6 +7520,9 @@
     if (correction != null) {
       result["correction"] = correction;
     }
+    if (hasFix != null) {
+      result["hasFix"] = hasFix;
+    }
     return result;
   }
 
@@ -7440,7 +7536,8 @@
           type == other.type &&
           location == other.location &&
           message == other.message &&
-          correction == other.correction;
+          correction == other.correction &&
+          hasFix == other.hasFix;
     }
     return false;
   }
@@ -7453,6 +7550,7 @@
     hash = _JenkinsSmiHash.combine(hash, location.hashCode);
     hash = _JenkinsSmiHash.combine(hash, message.hashCode);
     hash = _JenkinsSmiHash.combine(hash, correction.hashCode);
+    hash = _JenkinsSmiHash.combine(hash, hasFix.hashCode);
     return _JenkinsSmiHash.finish(hash);
   }
 }
@@ -9511,6 +9609,55 @@
 }
 
 /**
+ * FileKind
+ *
+ * enum {
+ *   LIBRARY
+ *   PART
+ * }
+ */
+class FileKind implements Enum {
+  static const LIBRARY = const FileKind._("LIBRARY");
+
+  static const PART = const FileKind._("PART");
+
+  /**
+   * A list containing all of the enum values that are defined.
+   */
+  static const List<FileKind> VALUES = const <FileKind>[LIBRARY, PART];
+
+  final String name;
+
+  const FileKind._(this.name);
+
+  factory FileKind(String name) {
+    switch (name) {
+      case "LIBRARY":
+        return LIBRARY;
+      case "PART":
+        return PART;
+    }
+    throw new Exception('Illegal enum value: $name');
+  }
+
+  factory FileKind.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json is String) {
+      try {
+        return new FileKind(json);
+      } catch(_) {
+        // Fall through
+      }
+    }
+    throw jsonDecoder.mismatch(jsonPath, "FileKind", json);
+  }
+
+  @override
+  String toString() => "FileKind.$name";
+
+  String toJson() => name;
+}
+
+/**
  * FoldingKind
  *
  * enum {
@@ -14573,12 +14720,18 @@
  * extractLocalVariable feedback
  *
  * {
+ *   "coveringExpressionOffsets": List<int>
+ *   "coveringExpressionLengths": List<int>
  *   "names": List<String>
  *   "offsets": List<int>
  *   "lengths": List<int>
  * }
  */
 class ExtractLocalVariableFeedback extends RefactoringFeedback implements HasToJson {
+  List<int> _coveringExpressionOffsets;
+
+  List<int> _coveringExpressionLengths;
+
   List<String> _names;
 
   List<int> _offsets;
@@ -14586,6 +14739,36 @@
   List<int> _lengths;
 
   /**
+   * The offsets of the expressions that cover the specified selection, from
+   * the down most to the up most.
+   */
+  List<int> get coveringExpressionOffsets => _coveringExpressionOffsets;
+
+  /**
+   * The offsets of the expressions that cover the specified selection, from
+   * the down most to the up most.
+   */
+  void set coveringExpressionOffsets(List<int> value) {
+    assert(value != null);
+    this._coveringExpressionOffsets = value;
+  }
+
+  /**
+   * The lengths of the expressions that cover the specified selection, from
+   * the down most to the up most.
+   */
+  List<int> get coveringExpressionLengths => _coveringExpressionLengths;
+
+  /**
+   * The lengths of the expressions that cover the specified selection, from
+   * the down most to the up most.
+   */
+  void set coveringExpressionLengths(List<int> value) {
+    assert(value != null);
+    this._coveringExpressionLengths = value;
+  }
+
+  /**
    * The proposed names for the local variable.
    */
   List<String> get names => _names;
@@ -14632,7 +14815,9 @@
     this._lengths = value;
   }
 
-  ExtractLocalVariableFeedback(List<String> names, List<int> offsets, List<int> lengths) {
+  ExtractLocalVariableFeedback(List<int> coveringExpressionOffsets, List<int> coveringExpressionLengths, List<String> names, List<int> offsets, List<int> lengths) {
+    this.coveringExpressionOffsets = coveringExpressionOffsets;
+    this.coveringExpressionLengths = coveringExpressionLengths;
     this.names = names;
     this.offsets = offsets;
     this.lengths = lengths;
@@ -14643,6 +14828,18 @@
       json = {};
     }
     if (json is Map) {
+      List<int> coveringExpressionOffsets;
+      if (json.containsKey("coveringExpressionOffsets")) {
+        coveringExpressionOffsets = jsonDecoder._decodeList(jsonPath + ".coveringExpressionOffsets", json["coveringExpressionOffsets"], jsonDecoder._decodeInt);
+      } else {
+        throw jsonDecoder.missingKey(jsonPath, "coveringExpressionOffsets");
+      }
+      List<int> coveringExpressionLengths;
+      if (json.containsKey("coveringExpressionLengths")) {
+        coveringExpressionLengths = jsonDecoder._decodeList(jsonPath + ".coveringExpressionLengths", json["coveringExpressionLengths"], jsonDecoder._decodeInt);
+      } else {
+        throw jsonDecoder.missingKey(jsonPath, "coveringExpressionLengths");
+      }
       List<String> names;
       if (json.containsKey("names")) {
         names = jsonDecoder._decodeList(jsonPath + ".names", json["names"], jsonDecoder._decodeString);
@@ -14661,7 +14858,7 @@
       } else {
         throw jsonDecoder.missingKey(jsonPath, "lengths");
       }
-      return new ExtractLocalVariableFeedback(names, offsets, lengths);
+      return new ExtractLocalVariableFeedback(coveringExpressionOffsets, coveringExpressionLengths, names, offsets, lengths);
     } else {
       throw jsonDecoder.mismatch(jsonPath, "extractLocalVariable feedback", json);
     }
@@ -14669,6 +14866,8 @@
 
   Map<String, dynamic> toJson() {
     Map<String, dynamic> result = {};
+    result["coveringExpressionOffsets"] = coveringExpressionOffsets;
+    result["coveringExpressionLengths"] = coveringExpressionLengths;
     result["names"] = names;
     result["offsets"] = offsets;
     result["lengths"] = lengths;
@@ -14681,7 +14880,9 @@
   @override
   bool operator==(other) {
     if (other is ExtractLocalVariableFeedback) {
-      return _listEqual(names, other.names, (String a, String b) => a == b) &&
+      return _listEqual(coveringExpressionOffsets, other.coveringExpressionOffsets, (int a, int b) => a == b) &&
+          _listEqual(coveringExpressionLengths, other.coveringExpressionLengths, (int a, int b) => a == b) &&
+          _listEqual(names, other.names, (String a, String b) => a == b) &&
           _listEqual(offsets, other.offsets, (int a, int b) => a == b) &&
           _listEqual(lengths, other.lengths, (int a, int b) => a == b);
     }
@@ -14691,6 +14892,8 @@
   @override
   int get hashCode {
     int hash = 0;
+    hash = _JenkinsSmiHash.combine(hash, coveringExpressionOffsets.hashCode);
+    hash = _JenkinsSmiHash.combine(hash, coveringExpressionLengths.hashCode);
     hash = _JenkinsSmiHash.combine(hash, names.hashCode);
     hash = _JenkinsSmiHash.combine(hash, offsets.hashCode);
     hash = _JenkinsSmiHash.combine(hash, lengths.hashCode);
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index 198955c..973b831 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -77,6 +77,7 @@
  */
 void scheduleNotificationOperations(
     AnalysisServer server,
+    Source source,
     String file,
     LineInfo lineInfo,
     AnalysisContext context,
@@ -99,12 +100,10 @@
     }
     if (server.hasAnalysisSubscription(
         protocol.AnalysisService.NAVIGATION, file)) {
-      Source source = resolvedDartUnit.element.source;
       server.scheduleOperation(new NavigationOperation(context, source));
     }
     if (server.hasAnalysisSubscription(
         protocol.AnalysisService.OCCURRENCES, file)) {
-      Source source = resolvedDartUnit.element.source;
       server.scheduleOperation(new OccurrencesOperation(context, source));
     }
     if (server.hasAnalysisSubscription(
@@ -116,8 +115,9 @@
   if (dartUnit != null) {
     if (server.hasAnalysisSubscription(
         protocol.AnalysisService.OUTLINE, file)) {
-      server.scheduleOperation(
-          new _DartOutlineOperation(context, file, lineInfo, dartUnit));
+      SourceKind sourceKind = context.getKindOf(source);
+      server.scheduleOperation(new _DartOutlineOperation(
+          context, file, lineInfo, sourceKind, dartUnit));
     }
   }
   // errors
@@ -213,11 +213,23 @@
 }
 
 void sendAnalysisNotificationOutline(AnalysisServer server, String file,
-    LineInfo lineInfo, CompilationUnit dartUnit) {
+    LineInfo lineInfo, SourceKind sourceKind, CompilationUnit dartUnit) {
   _sendNotification(server, () {
+    // compute FileKind
+    protocol.FileKind fileKind = protocol.FileKind.LIBRARY;
+    if (sourceKind == SourceKind.LIBRARY) {
+      fileKind = protocol.FileKind.LIBRARY;
+    } else if (sourceKind == SourceKind.PART) {
+      fileKind = protocol.FileKind.PART;
+    }
+    // compute library name
+    String libraryName = _computeLibraryName(dartUnit);
+    // compute Outline
     var computer = new DartUnitOutlineComputer(file, lineInfo, dartUnit);
-    var outline = computer.compute();
-    var params = new protocol.AnalysisOutlineParams(file, outline);
+    protocol.Outline outline = computer.compute();
+    // send notification
+    var params = new protocol.AnalysisOutlineParams(file, fileKind, outline,
+        libraryName: libraryName);
     server.sendNotification(params.toNotification());
   });
 }
@@ -241,6 +253,20 @@
   context.analysisOptions = options;
 }
 
+String _computeLibraryName(CompilationUnit unit) {
+  for (Directive directive in unit.directives) {
+    if (directive is LibraryDirective && directive.name != null) {
+      return directive.name.name;
+    }
+  }
+  for (Directive directive in unit.directives) {
+    if (directive is PartOfDirective && directive.libraryName != null) {
+      return directive.libraryName.name;
+    }
+  }
+  return null;
+}
+
 /**
  * Runs the given notification producing function [f], catching exceptions.
  */
@@ -371,8 +397,8 @@
       // Dart
       CompilationUnit parsedDartUnit = notice.parsedDartUnit;
       CompilationUnit resolvedDartUnit = notice.resolvedDartUnit;
-      scheduleNotificationOperations(server, file, notice.lineInfo, context,
-          parsedDartUnit, resolvedDartUnit, notice.errors);
+      scheduleNotificationOperations(server, source, file, notice.lineInfo,
+          context, parsedDartUnit, resolvedDartUnit, notice.errors);
       // done
       server.fileAnalyzed(notice);
     }
@@ -455,14 +481,15 @@
 
 class _DartOutlineOperation extends _DartNotificationOperation {
   final LineInfo lineInfo;
+  final SourceKind sourceKind;
 
-  _DartOutlineOperation(
-      AnalysisContext context, String file, this.lineInfo, CompilationUnit unit)
+  _DartOutlineOperation(AnalysisContext context, String file, this.lineInfo,
+      this.sourceKind, CompilationUnit unit)
       : super(context, file, unit);
 
   @override
   void perform(AnalysisServer server) {
-    sendAnalysisNotificationOutline(server, file, lineInfo, unit);
+    sendAnalysisNotificationOutline(server, file, lineInfo, sourceKind, unit);
   }
 }
 
diff --git a/pkg/analysis_server/lib/src/plugin/server_plugin.dart b/pkg/analysis_server/lib/src/plugin/server_plugin.dart
index b88d009..4e227b4 100644
--- a/pkg/analysis_server/lib/src/plugin/server_plugin.dart
+++ b/pkg/analysis_server/lib/src/plugin/server_plugin.dart
@@ -8,7 +8,6 @@
 import 'package:analysis_server/analysis/index_core.dart';
 import 'package:analysis_server/analysis/navigation_core.dart';
 import 'package:analysis_server/analysis/occurrences_core.dart';
-import 'package:analysis_server/completion/completion_core.dart';
 import 'package:analysis_server/edit/assist/assist_core.dart';
 import 'package:analysis_server/edit/fix/fix_core.dart';
 import 'package:analysis_server/plugin/analyzed_files.dart';
@@ -26,6 +25,7 @@
 import 'package:analysis_server/src/domains/analysis/occurrences_dart.dart';
 import 'package:analysis_server/src/edit/edit_domain.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_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';
diff --git a/pkg/analysis_server/lib/src/protocol_server.dart b/pkg/analysis_server/lib/src/protocol_server.dart
index a9dd5dd..705b7aa 100644
--- a/pkg/analysis_server/lib/src/protocol_server.dart
+++ b/pkg/analysis_server/lib/src/protocol_server.dart
@@ -5,6 +5,7 @@
 library protocol.server;
 
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart'
     as engine;
 import 'package:analyzer/src/generated/ast.dart' as engine;
@@ -92,8 +93,9 @@
   var type = new AnalysisErrorType(errorCode.type.name);
   String message = error.message;
   String correction = error.correction;
+  bool fix = hasFix(error.errorCode);
   return new AnalysisError(severity, type, location, message,
-      correction: correction);
+      correction: correction, hasFix: fix);
 }
 
 /**
diff --git a/pkg/analysis_server/lib/plugin/completion.dart b/pkg/analysis_server/lib/src/provisional/completion/completion.dart
similarity index 90%
rename from pkg/analysis_server/lib/plugin/completion.dart
rename to pkg/analysis_server/lib/src/provisional/completion/completion.dart
index 9b1c4b5..9a71bc0 100644
--- a/pkg/analysis_server/lib/plugin/completion.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/completion.dart
@@ -23,10 +23,10 @@
  *       ...
  *     }
  */
-library analysis_server.plugin.completion;
+library analysis_server.src.provisional.completion.completion;
 
-import 'package:analysis_server/completion/completion_core.dart';
 import 'package:analysis_server/src/plugin/server_plugin.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart';
 import 'package:plugin/plugin.dart';
 
 /**
diff --git a/pkg/analysis_server/lib/completion/completion_core.dart b/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
similarity index 97%
rename from pkg/analysis_server/lib/completion/completion_core.dart
rename to pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
index 5003faf..f38d541 100644
--- a/pkg/analysis_server/lib/completion/completion_core.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library analysis_server.completion.completion_core;
+library analysis_server.src.provisional.completion.completion_core;
 
 import 'package:analysis_server/src/protocol.dart';
 import 'package:analyzer/file_system/file_system.dart';
diff --git a/pkg/analysis_server/lib/completion/completion_dart.dart b/pkg/analysis_server/lib/src/provisional/completion/completion_dart.dart
similarity index 91%
rename from pkg/analysis_server/lib/completion/completion_dart.dart
rename to pkg/analysis_server/lib/src/provisional/completion/completion_dart.dart
index 1ddd5a0..488f30d 100644
--- a/pkg/analysis_server/lib/completion/completion_dart.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/completion_dart.dart
@@ -2,14 +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.
 
-library analysis_server.completion.completion_dart;
+library analysis_server.src.provisional.completion.completion_dart;
 
-import 'package:analysis_server/completion/completion_core.dart';
 import 'package:analysis_server/src/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';
-import 'package:analysis_server/completion/dart/completion_target.dart';
 
 /**
  * An object used to produce completions for a specific error within a Dart
@@ -66,9 +66,10 @@
   bool get isResolved;
 
   /**
-   * Return the compilation unit in which the completion was requested.
+   * Return the completion target.  This determines what part of the parse tree
+   * will receive the newly inserted text.
    */
-  CompilationUnit get unit;
+  CompletionTarget get target;
 
   /**
    * Cached information from a prior code completion operation.
@@ -76,10 +77,9 @@
   //DartCompletionCache get cache;
 
   /**
-   * Return the completion target.  This determines what part of the parse tree
-   * will receive the newly inserted text.
+   * Return the compilation unit in which the completion was requested.
    */
-  CompletionTarget get target;
+  CompilationUnit get unit;
 
   /**
    * Information about the types of suggestions that should be included.
diff --git a/pkg/analysis_server/lib/completion/dart/completion_target.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
similarity index 97%
rename from pkg/analysis_server/lib/completion/dart/completion_target.dart
rename to pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
index a1f315b..b24c610 100644
--- a/pkg/analysis_server/lib/completion/dart/completion_target.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
@@ -1,3 +1,9 @@
+// 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.completion_target;
+
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
 import 'package:analyzer/src/generated/scanner.dart';
diff --git a/pkg/analysis_server/lib/src/provisional/refactoring/refactoring_core.dart b/pkg/analysis_server/lib/src/provisional/refactoring/refactoring_core.dart
new file mode 100644
index 0000000..f1c9f94
--- /dev/null
+++ b/pkg/analysis_server/lib/src/provisional/refactoring/refactoring_core.dart
@@ -0,0 +1,102 @@
+// 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.edit.refactoring.refactoring_core;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/protocol.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+/**
+ * Abstract interface for all refactorings.
+ */
+abstract class Refactoring {
+  /**
+   * Return the ids of source edits that are not known to be valid.
+   *
+   * An edit is not known to be valid if there was insufficient type information
+   * for the server to be able to determine whether or not the code needs to be
+   * modified, such as when a member is being renamed and there is a reference
+   * to a member from an unknown type. This field will be omitted if the change
+   * field is omitted or if there are no potential edits for the refactoring.
+   */
+  List<String> get potentialEditIds;
+
+  /**
+   * Return the human readable name of this refactoring.
+   */
+  String get refactoringName;
+
+  /**
+   * Checks all conditions - [checkInitialConditions] and
+   * [checkFinalConditions] to decide if refactoring can be performed.
+   */
+  Future<RefactoringStatus> checkAllConditions();
+
+  /**
+   * Validates environment to check if this refactoring can be performed.
+   *
+   * This check may be slow, because many refactorings use search engine.
+   */
+  Future<RefactoringStatus> checkFinalConditions();
+
+  /**
+   * Validates arguments to check if this refactoring can be performed.
+   *
+   * This check should be quick because it is used often as arguments change.
+   */
+  Future<RefactoringStatus> checkInitialConditions();
+
+  /**
+   * Return the [Change] to apply to perform this refactoring.
+   */
+  Future<SourceChange> createChange();
+
+  /**
+   * Return `true` if the [Change] created by refactoring may be unsafe,
+   * so we want user to review the [Change] to ensure that he understands it.
+   */
+  bool requiresPreview();
+}
+
+/**
+ *
+ *
+ * Clients are expected to subtype this class when implementing plugins.
+ */
+abstract class RefactoringContributor {
+  /**
+   *
+   */
+  Refactoring createRefactoring(AnalysisContext context, RefactoringKind kind,
+      Source source, int offset, int length);
+
+  /**
+   *
+   */
+  List<RefactoringKind> getAvailableRefactorings(
+      AnalysisContext context, Source source, int offset, int length);
+}
+
+/**
+ *
+ *
+ * Clients are not expected to subtype this class.
+ */
+abstract class RefactoringKind {
+  factory RefactoringKind(String name, bool requiresOptions) {
+  } // TODO(brianwilkerson) Redirect to impl class.
+  bool get requiresOptions;
+}
+
+/**
+ *
+ *
+ * Clients are not expected to subtype this class.
+ */
+abstract class RefactoringStatus {
+  // TODO(brianwilkerson) Fill this in.
+}
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index c5eb6bf..883f50c4e 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -206,6 +206,11 @@
   static const String CLIENT_VERSION = "client-version";
 
   /**
+   * The name of the option used to disable the use of the new task model.
+   */
+  static const String DISABLE_NEW_TASK_MODEL = "disable-new-task-model";
+
+  /**
    * The name of the option used to enable incremental resolution of API
    * changes.
    */
@@ -218,11 +223,6 @@
   static const String ENABLE_INSTRUMENTATION_OPTION = "enable-instrumentation";
 
   /**
-   * The name of the option used to enable the use of the new task model.
-   */
-  static const String ENABLE_NEW_TASK_MODEL = "enable-new-task-model";
-
-  /**
    * The name of the option used to set the file read mode.
    */
   static const String FILE_READ_MODE = "file-read-mode";
@@ -395,9 +395,7 @@
     //
     // Enable the new task model, if appropriate.
     //
-    if (results[ENABLE_NEW_TASK_MODEL]) {
-      AnalysisEngine.instance.useTaskModel = true;
-    }
+    AnalysisEngine.instance.useTaskModel = !results[DISABLE_NEW_TASK_MODEL];
     //
     // Process all of the plugins so that extensions are registered.
     //
@@ -470,6 +468,11 @@
     parser.addOption(CLIENT_ID,
         help: "an identifier used to identify the client");
     parser.addOption(CLIENT_VERSION, help: "the version of the client");
+    parser.addFlag(DISABLE_NEW_TASK_MODEL,
+        help: "disable the use of the new task model",
+        defaultsTo: false,
+        hide: true,
+        negatable: false);
     parser.addFlag(ENABLE_INCREMENTAL_RESOLUTION_API,
         help: "enable using incremental resolution for API changes",
         defaultsTo: false,
@@ -478,11 +481,6 @@
         help: "enable sending instrumentation information to a server",
         defaultsTo: false,
         negatable: false);
-    parser.addFlag(ENABLE_NEW_TASK_MODEL,
-        help: "enable the use of the new task model",
-        defaultsTo: false,
-        hide: true,
-        negatable: false);
     parser.addFlag(HELP_OPTION,
         help: "print this help message without starting a server",
         defaultsTo: false,
diff --git a/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart
index 61194fc..4f7780d 100644
--- a/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart
@@ -141,23 +141,20 @@
           }
         }
       }
-      if (parent is InstanceCreationExpression) {
-        ConstructorName constructorName = parent.constructorName;
-        if (constructorName != null) {
-          String name = constructorName.toSource();
-          if (name.length > 0) {
-            /*
-             * 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;
-            }
-            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;
diff --git a/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart b/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart
index 2b391ca..e3c44ce 100644
--- a/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart
@@ -4,10 +4,10 @@
 
 library services.completion.computer.dart.relevance;
 
-import 'package:analysis_server/completion/completion_dart.dart';
 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/services/completion/dart_completion_manager.dart'
     show DART_RELEVANCE_COMMON_USAGE;
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 a8ed44b..68fa732 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_core.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_core.dart
@@ -4,7 +4,7 @@
 
 library analysis_server.src.services.completion.completion_dart;
 
-import 'package:analysis_server/completion/completion_core.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_dart.dart b/pkg/analysis_server/lib/src/services/completion/completion_dart.dart
index 4304295..1cfff04 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_dart.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_dart.dart
@@ -4,9 +4,9 @@
 
 library analysis_server.src.services.completion.completion_dart;
 
-import 'package:analysis_server/completion/completion_core.dart';
-import 'package:analysis_server/completion/completion_dart.dart';
-import 'package:analysis_server/completion/dart/completion_target.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';
 
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 ebc5054..178d76c 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
@@ -6,10 +6,10 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/completion/completion_core.dart'
-    show CompletionRequest, CompletionResult;
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart'
+    show 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';
@@ -273,11 +273,9 @@
   CompletionResultImpl(this.replacementOffset, this.replacementLength,
       this.suggestions, this.last);
 
-  @override
-  // TODO(brianwilkerson) Figure out whether this is correct.
-  bool get hasNewSuggestions => suggestions.isNotEmpty;
-
-  @override
+  /**
+   * Return `true` if this is the last completion result that will be produced.
+   */
   bool get isLast => last;
 }
 
diff --git a/pkg/analysis_server/lib/src/services/completion/contribution_sorter.dart b/pkg/analysis_server/lib/src/services/completion/contribution_sorter.dart
index 737a837..3a5217b 100644
--- a/pkg/analysis_server/lib/src/services/completion/contribution_sorter.dart
+++ b/pkg/analysis_server/lib/src/services/completion/contribution_sorter.dart
@@ -4,8 +4,8 @@
 
 library services.completion.sorter;
 
-import 'package:analysis_server/completion/completion_dart.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_dart.dart';
 
 /**
  * The abstract class `ContributionSorter` defines the behavior of objects
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 ae177f2..2f19c64 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
@@ -6,12 +6,13 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/completion/completion_core.dart'
-    show CompletionRequest;
-import 'package:analysis_server/completion/completion_dart.dart' as newApi;
-import 'package:analysis_server/completion/dart/completion_target.dart';
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart'
+    show CompletionRequest;
+import 'package:analysis_server/src/provisional/completion/completion_dart.dart'
+    as newApi;
+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';
@@ -182,7 +183,10 @@
       });
       contributionSorter.sort(
           new OldRequestWrapper(request), request.suggestions);
-      sendResults(request, todo.isEmpty);
+
+      if (todo.isEmpty) {
+        sendResults(request, todo.isEmpty);
+      }
       return todo;
     });
   }
diff --git a/pkg/analysis_server/lib/src/services/completion/inherited_contributor.dart b/pkg/analysis_server/lib/src/services/completion/inherited_contributor.dart
index 11d0631..410eb81 100644
--- a/pkg/analysis_server/lib/src/services/completion/inherited_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/inherited_contributor.dart
@@ -4,11 +4,11 @@
 
 library services.completion.computer.dart.invocation;
 
-import 'package:analysis_server/completion/completion_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:analysis_server/utilities/change_builder_dart.dart';
diff --git a/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart b/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart
index 6aa3536..fe9ef14 100644
--- a/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart
@@ -1,4 +1,5 @@
 // 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.
 
@@ -70,6 +71,9 @@
       }
     }
     _addStatementKeywords(node);
+    if (_inCatchClause(node)) {
+      _addSuggestion(Keyword.RETHROW, DART_RELEVANCE_KEYWORD - 1);
+    }
   }
 
   @override
@@ -446,7 +450,6 @@
       Keyword.VOID,
       Keyword.WHILE
     ]);
-    _addSuggestion(Keyword.RETHROW, DART_RELEVANCE_KEYWORD - 1);
   }
 
   void _addSuggestion(Keyword keyword,
@@ -481,6 +484,9 @@
     return body != null && body.isAsynchronous;
   }
 
+  bool _inCatchClause(Block node) =>
+      node.getAncestor((p) => p is CatchClause) != null;
+
   bool _inClassMemberBody(AstNode node) {
     while (true) {
       AstNode body = node.getAncestor((n) => n is FunctionBody);
diff --git a/pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart
index 6fdb2b6..181f259 100644
--- a/pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart
@@ -351,9 +351,20 @@
 class _LocalVisitor extends LocalDeclarationVisitor {
   final DartCompletionRequest request;
   final OpType optype;
+  int privateMemberRelevance = DART_RELEVANCE_DEFAULT;
 
   _LocalVisitor(this.request, int offset, this.optype) : super(offset) {
     includeLocalInheritedTypes = !optype.inStaticMethodBody;
+    if (request.replacementLength > 0) {
+      var contents = request.context.getContents(request.source);
+      if (contents != null &&
+          contents.data != null &&
+          contents.data.startsWith('_', request.replacementOffset)) {
+        // If user typed identifier starting with '_'
+        // then do not suppress the relevance of private members
+        privateMemberRelevance = null;
+      }
+    }
   }
 
   @override
@@ -554,6 +565,10 @@
         id, isDeprecated, relevance, typeName,
         classDecl: classDecl);
     if (suggestion != null) {
+      if (privateMemberRelevance != null &&
+          suggestion.completion.startsWith('_')) {
+        suggestion.relevance = privateMemberRelevance;
+      }
       request.addSuggestion(suggestion);
       suggestion.element = createElement(request.source, elemKind, id,
           isAbstract: isAbstract,
diff --git a/pkg/analysis_server/lib/src/services/completion/optype.dart b/pkg/analysis_server/lib/src/services/completion/optype.dart
index 5a04322..dc38919 100644
--- a/pkg/analysis_server/lib/src/services/completion/optype.dart
+++ b/pkg/analysis_server/lib/src/services/completion/optype.dart
@@ -4,7 +4,7 @@
 
 library services.completion.dart.optype;
 
-import 'package:analysis_server/completion/dart/completion_target.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/scanner.dart';
 
@@ -295,6 +295,16 @@
   }
 
   @override
+  void visitFieldFormalParameter(FieldFormalParameter node) {
+    if (entity == node.identifier) {
+      optype.isPrefixed = true;
+    } else {
+      optype.includeReturnValueSuggestions = true;
+      optype.includeTypeNameSuggestions = true;
+    }
+  }
+
+  @override
   void visitForEachStatement(ForEachStatement node) {
     if (identical(entity, node.identifier)) {
       optype.includeTypeNameSuggestions = true;
@@ -449,16 +459,6 @@
   }
 
   @override
-  void visitFieldFormalParameter(FieldFormalParameter node) {
-    if (entity == node.identifier) {
-      optype.isPrefixed = true;
-    } else {
-      optype.includeReturnValueSuggestions = true;
-      optype.includeTypeNameSuggestions = true;
-    }
-  }
-
-  @override
   void visitNormalFormalParameter(NormalFormalParameter node) {
     optype.includeReturnValueSuggestions = true;
     optype.includeTypeNameSuggestions = true;
diff --git a/pkg/analysis_server/lib/src/services/completion/uri_contributor.dart b/pkg/analysis_server/lib/src/services/completion/uri_contributor.dart
index cb32012..6d19260 100644
--- a/pkg/analysis_server/lib/src/services/completion/uri_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/uri_contributor.dart
@@ -48,13 +48,22 @@
   }
 
   @override
+  visitExportDirective(ExportDirective node) {
+    visitNamespaceDirective(node);
+  }
+
+  @override
   visitImportDirective(ImportDirective node) {
+    visitNamespaceDirective(node);
+  }
+
+  visitNamespaceDirective(NamespaceDirective node) {
     StringLiteral uri = node.uri;
     if (uri is SimpleStringLiteral) {
       int offset = request.offset;
       if (uri.offset < offset &&
           (offset < uri.end || offset == uri.offset + 1)) {
-        // Handle degenerate case where import is only line in file
+        // Handle degenerate case where import or export is only line in file
         // and there is no semicolon
         visitSimpleStringLiteral(uri);
       }
@@ -64,7 +73,7 @@
   @override
   visitSimpleStringLiteral(SimpleStringLiteral node) {
     AstNode parent = node.parent;
-    if (parent is ImportDirective && parent.uri == node) {
+    if (parent is NamespaceDirective && parent.uri == node) {
       String partial = node.literal.lexeme.substring(
           node.contentsOffset - node.offset, request.offset - node.offset);
       request.replacementOffset = node.contentsOffset;
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index e1f81f6..d00a24f 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -10,6 +10,7 @@
 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/parser.dart';
 
 /**
  * Compute and return the fixes available for the given [error]. The error was
@@ -38,6 +39,63 @@
 }
 
 /**
+ * Return true if this [errorCode] is likely to have a fix associated with it.
+ */
+bool hasFix(ErrorCode errorCode) => errorCode ==
+        StaticWarningCode.UNDEFINED_CLASS_BOOLEAN ||
+    errorCode == StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER ||
+    errorCode == StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS ||
+    errorCode == StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR ||
+    errorCode ==
+        StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE ||
+    errorCode ==
+        StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO ||
+    errorCode ==
+        StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE ||
+    errorCode ==
+        StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR ||
+    errorCode ==
+        StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS ||
+    errorCode == StaticWarningCode.CAST_TO_NON_TYPE ||
+    errorCode == StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME ||
+    errorCode == StaticWarningCode.UNDEFINED_CLASS ||
+    errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED ||
+    errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1 ||
+    errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2 ||
+    errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS ||
+    errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER ||
+    errorCode ==
+        CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE ||
+    errorCode == CompileTimeErrorCode.INVALID_ANNOTATION ||
+    errorCode == CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT ||
+    errorCode == CompileTimeErrorCode.PART_OF_NON_PART ||
+    errorCode ==
+        CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT ||
+    errorCode == CompileTimeErrorCode.URI_DOES_NOT_EXIST ||
+    errorCode == HintCode.DEAD_CODE ||
+    errorCode == HintCode.DIVISION_OPTIMIZATION ||
+    errorCode == HintCode.TYPE_CHECK_IS_NOT_NULL ||
+    errorCode == HintCode.TYPE_CHECK_IS_NULL ||
+    errorCode == HintCode.UNDEFINED_GETTER ||
+    errorCode == HintCode.UNDEFINED_SETTER ||
+    errorCode == HintCode.UNNECESSARY_CAST ||
+    errorCode == HintCode.UNUSED_CATCH_CLAUSE ||
+    errorCode == HintCode.UNUSED_CATCH_STACK ||
+    errorCode == HintCode.UNUSED_IMPORT ||
+    errorCode == HintCode.UNDEFINED_METHOD ||
+    errorCode == ParserErrorCode.EXPECTED_TOKEN ||
+    errorCode == ParserErrorCode.GETTER_WITH_PARAMETERS ||
+    errorCode == ParserErrorCode.VAR_AS_TYPE_NAME ||
+    errorCode == StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE ||
+    errorCode == StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER ||
+    errorCode == StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION ||
+    errorCode == StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT ||
+    errorCode == StaticTypeWarningCode.UNDEFINED_FUNCTION ||
+    errorCode == StaticTypeWarningCode.UNDEFINED_GETTER ||
+    errorCode == StaticTypeWarningCode.UNDEFINED_METHOD ||
+    errorCode == StaticTypeWarningCode.UNDEFINED_SETTER;
+
+/**
  * An enumeration of possible quick fix kinds.
  */
 class DartFixKind {
diff --git a/pkg/analysis_server/lib/src/services/index/index.dart b/pkg/analysis_server/lib/src/services/index/index.dart
index 3a44b4f..5767b4c 100644
--- a/pkg/analysis_server/lib/src/services/index/index.dart
+++ b/pkg/analysis_server/lib/src/services/index/index.dart
@@ -82,9 +82,6 @@
   IndexableObjectKind get kind => IndexableNameKind.INSTANCE;
 
   @override
-  int get length => 0;
-
-  @override
   int get offset {
     return -1;
   }
@@ -127,6 +124,12 @@
     throw new UnsupportedError(
         'Indexable names cannot be decoded through their kind');
   }
+
+  @override
+  int encodeHash(StringToInt stringToInt, IndexableObject indexable) {
+    String name = (indexable as IndexableName).name;
+    return stringToInt(name);
+  }
 }
 
 /**
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 ae1ec69..44ce967 100644
--- a/pkg/analysis_server/lib/src/services/index/index_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/index/index_contributor.dart
@@ -778,8 +778,8 @@
   void _recordTopLevelElementDefinition(Element element) {
     if (element != null) {
       IndexableElement indexable = new IndexableElement(element);
-      int offset = indexable.offset;
-      int length = indexable.length;
+      int offset = element.nameOffset;
+      int length = element.nameLength;
       LocationImpl location = new LocationImpl(indexable, offset, length);
       recordRelationshipElement(
           _libraryElement, IndexConstants.DEFINES, location);
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 8df94c0..a2d3d64 100644
--- a/pkg/analysis_server/lib/src/services/index/indexable_element.dart
+++ b/pkg/analysis_server/lib/src/services/index/indexable_element.dart
@@ -10,6 +10,7 @@
 import 'package:analyzer/src/generated/element.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_general.dart';
 
 /**
  * A wrapper around an [Element] that implements the [IndexableObject] interface.
@@ -36,12 +37,6 @@
   IndexableObjectKind get kind => IndexableElementKind.forElement(element);
 
   @override
-  int get length => element.nameLength;
-
-  @override
-  String get name => element.displayName;
-
-  @override
   int get offset {
     if (element is ConstructorElement) {
       return element.enclosingElement.nameOffset;
@@ -67,7 +62,7 @@
   /**
    * A table mapping element kinds to the corresponding indexable element kind.
    */
-  static Map<ElementKind, IndexableElementKind> _kindMap =
+  static final Map<ElementKind, IndexableElementKind> _kindMap =
       new HashMap<ElementKind, IndexableElementKind>();
 
   /**
@@ -75,7 +70,7 @@
    * of constructors associated with a class) to the indexable element kind used
    * to represent it.
    */
-  static Map<int, IndexableElementKind> _constructorKinds =
+  static final Map<int, IndexableElementKind> _constructorKinds =
       new HashMap<int, IndexableElementKind>();
 
   @override
@@ -145,6 +140,22 @@
     return null;
   }
 
+  @override
+  int encodeHash(StringToInt stringToInt, IndexableObject indexable) {
+    Element element = (indexable as IndexableElement).element;
+    String elementName = element.displayName;
+    int elementNameId = stringToInt(elementName);
+    if (indexable is IndexableElement) {
+      LibraryElement libraryElement = indexable.element.library;
+      if (libraryElement != null) {
+        String libraryPath = libraryElement.source.fullName;
+        int libraryPathId = stringToInt(libraryPath);
+        return JenkinsSmiHash.combine(libraryPathId, elementNameId);
+      }
+    }
+    return elementNameId;
+  }
+
   /**
    * Return the indexable element kind representing the given [element].
    */
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 07925f3..c865aa4 100644
--- a/pkg/analysis_server/lib/src/services/index/store/codec.dart
+++ b/pkg/analysis_server/lib/src/services/index/store/codec.dart
@@ -8,11 +8,8 @@
 
 import 'package:analysis_server/analysis/index_core.dart';
 import 'package:analysis_server/src/services/index/index.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';
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_general.dart';
 
 /**
  * A helper that encodes/decodes [AnalysisContext]s from/to integers.
@@ -79,7 +76,6 @@
    */
   IndexableObject decode(
       AnalysisContext context, int fileId, int offset, int kindId) {
-    String filePath = _stringCodec.decode(fileId);
     IndexableObjectKind kind = IndexableObjectKind.getKind(kindId);
     if (kind == null) {
       return null;
@@ -87,6 +83,7 @@
       String name = _stringCodec.decode(offset);
       return new IndexableName(name);
     }
+    String filePath = _stringCodec.decode(fileId);
     return kind.decode(context, filePath, offset);
   }
 
@@ -113,11 +110,7 @@
       String name = indexable.name;
       return _stringCodec.encode(name);
     }
-    int offset = indexable.offset;
-    if (offset < 0) {
-      return _stringCodec.encode(indexable.name);
-    }
-    return offset;
+    return indexable.offset;
   }
 
   /**
@@ -132,19 +125,7 @@
    * Returns an integer that corresponds to the name of [indexable].
    */
   int encodeHash(IndexableObject indexable) {
-    // TODO(brianwilkerson) Consider moving this to IndexableObjectKind so that
-    // we don't have to break encapsulation.
-    String elementName = indexable.name; // was: indexable.displayName;
-    int elementNameId = _stringCodec.encode(elementName);
-    if (indexable is IndexableElement) {
-      LibraryElement libraryElement = indexable.element.library;
-      if (libraryElement != null) {
-        String libraryPath = libraryElement.source.fullName;
-        int libraryPathId = _stringCodec.encode(libraryPath);
-        return JenkinsSmiHash.combine(libraryPathId, elementNameId);
-      }
-    }
-    return elementNameId;
+    return indexable.kind.encodeHash(_stringCodec.encode, indexable);
   }
 }
 
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 9c51d6a..57b1734 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
@@ -1005,8 +1005,8 @@
       nodeDeclarations[_currentNodeNameId] = declarations;
     }
     // record LocationData
-    declarations
-        .add(new _TopElementData(_elementCodec, new IndexableElement(element)));
+    declarations.add(new _TopElementData(
+        _elementCodec, element.displayName, new IndexableElement(element)));
   }
 
   @override
@@ -1154,12 +1154,9 @@
   final int elementId3;
 
   factory _TopElementData(
-      ElementCodec elementCodec, IndexableObject indexable) {
-    return new _TopElementData._(
-        indexable.name,
-        elementCodec.encode1(indexable),
-        elementCodec.encode2(indexable),
-        elementCodec.encode3(indexable));
+      ElementCodec elementCodec, String name, IndexableObject indexable) {
+    return new _TopElementData._(name, elementCodec.encode1(indexable),
+        elementCodec.encode2(indexable), elementCodec.encode3(indexable));
   }
 
   _TopElementData._(
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename.dart b/pkg/analysis_server/lib/src/services/refactoring/rename.dart
index bd97527..a9bdb74 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename.dart
@@ -17,6 +17,7 @@
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:path/path.dart' as pathos;
 
 /**
  * Returns `true` if two given [Element]s are [LocalElement]s and have
@@ -52,6 +53,18 @@
   return librarySourcesOfSource.contains(librarySourceOfElement);
 }
 
+bool isElementInPubCache(Element element) {
+  Source source = element.source;
+  String path = source.fullName;
+  return isPathInPubCache(path);
+}
+
+bool isElementInSdkOrPubCache(Element element) {
+  Source source = element.source;
+  String path = source.fullName;
+  return source.isInSystemLibrary || isPathInPubCache(path);
+}
+
 /**
  * Checks if the given [Element] is in the given [AnalysisContext].
  */
@@ -59,6 +72,23 @@
   return element.context == context;
 }
 
+bool isPathInPubCache(String path) {
+  List<String> parts = pathos.split(path);
+  if (parts.contains('.pub-cache')) {
+    return true;
+  }
+  for (int i = 0; i < parts.length - 1; i++) {
+    if (parts[i] == 'Pub' && parts[i + 1] == 'Cache') {
+      return true;
+    }
+    if (parts[i] == 'third_party' &&
+        (parts[i + 1] == 'pkg' || parts[i + 1] == 'pkg_tested')) {
+      return true;
+    }
+  }
+  return false;
+}
+
 /**
  * Checks if the given unqualified [SearchMatch] intersects with visibility
  * range of [localElement].
@@ -145,6 +175,13 @@
           getElementQualifiedName(element));
       result.addFatalError(message);
     }
+    if (isElementInPubCache(element)) {
+      String message = format(
+          "The {0} '{1}' is defined in a pub package, so cannot be renamed.",
+          getElementKindName(element),
+          getElementQualifiedName(element));
+      result.addFatalError(message);
+    }
     return new Future.value(result);
   }
 
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
index e0f9a77..4d70e06 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
@@ -100,6 +100,11 @@
       if (reference.isResolved) {
         continue;
       }
+      // ignore references from SDK and pub cache
+      if (isElementInSdkOrPubCache(reference.element)) {
+        print('ignore: $reference');
+        continue;
+      }
       // check the element being renamed is accessible
       {
         LibraryElement whereLibrary = reference.element.library;
diff --git a/pkg/analysis_server/lib/src/status/get_handler.dart b/pkg/analysis_server/lib/src/status/get_handler.dart
index abf8f00..c85db7b 100644
--- a/pkg/analysis_server/lib/src/status/get_handler.dart
+++ b/pkg/analysis_server/lib/src/status/get_handler.dart
@@ -323,6 +323,7 @@
       results.add(COMPILATION_UNIT_CONSTANTS);
       results.add(COMPILATION_UNIT_ELEMENT);
       results.add(HINTS);
+      results.add(LINTS);
       results.add(INFER_STATIC_VARIABLE_TYPES_ERRORS);
       results.add(INFERABLE_STATIC_VARIABLES_IN_UNIT);
       results.add(LIBRARY_UNIT_ERRORS);
diff --git a/pkg/analysis_server/pubspec.yaml b/pkg/analysis_server/pubspec.yaml
index 0029437..95fcbe5 100644
--- a/pkg/analysis_server/pubspec.yaml
+++ b/pkg/analysis_server/pubspec.yaml
@@ -6,7 +6,7 @@
 environment:
   sdk: '>=1.9.0 <2.0.0'
 dependencies:
-  analyzer: '>=0.26.1+3 <0.27.0'
+  analyzer: '>=0.26.1+7 <0.27.0'
   args: '>=0.13.0 <0.14.0'
   dart_style: '>=0.2.0 <0.3.0'
   logging: any
diff --git a/pkg/analysis_server/test/analysis/get_hover_test.dart b/pkg/analysis_server/test/analysis/get_hover_test.dart
index bda7c91..61520dc 100644
--- a/pkg/analysis_server/test/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/analysis/get_hover_test.dart
@@ -168,6 +168,31 @@
     });
   }
 
+  test_expression_parameter() {
+    addTestFile('''
+library my.library;
+class A {
+  /// The method documentation.
+  m(int p) {
+  }
+}
+''');
+    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);
+    });
+  }
+
   test_expression_syntheticGetter() {
     addTestFile('''
 library my.library;
diff --git a/pkg/analysis_server/test/analysis/notification_errors_test.dart b/pkg/analysis_server/test/analysis/notification_errors_test.dart
index e03a380..aa841e3 100644
--- a/pkg/analysis_server/test/analysis/notification_errors_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_errors_test.dart
@@ -7,6 +7,7 @@
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/domain_analysis.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 import 'package:unittest/unittest.dart';
 
@@ -35,6 +36,24 @@
     server.handlers = [new AnalysisDomainHandler(server),];
   }
 
+  test_importError() {
+    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'));
+    });
+  }
+
   test_notInAnalysisRoot() {
     createProject();
     String otherFile = '/other.dart';
diff --git a/pkg/analysis_server/test/analysis/notification_implemented_test.dart b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
index a26ff56..fc72b72 100644
--- a/pkg/analysis_server/test/analysis/notification_implemented_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
@@ -37,6 +37,9 @@
     if (length == -1) {
       length = findIdentifierLength(search);
     }
+    if (implementedClasses == null) {
+      fail('No notification of impemented classes was received');
+    }
     for (ImplementedClass clazz in implementedClasses) {
       if (clazz.offset == offset && clazz.length == length) {
         return;
@@ -57,6 +60,9 @@
     if (length == -1) {
       length = findIdentifierLength(search);
     }
+    if (implementedMembers == null) {
+      fail('No notification of impemented members was received');
+    }
     for (ImplementedMember member in implementedMembers) {
       if (member.offset == offset && member.length == length) {
         return;
@@ -77,6 +83,9 @@
     if (length == -1) {
       length = findIdentifierLength(search);
     }
+    if (implementedMembers == null) {
+      fail('No notification of impemented members was received');
+    }
     for (ImplementedMember member in implementedMembers) {
       if (member.offset == offset) {
         fail('Unexpected implemented member at $offset'
@@ -90,16 +99,12 @@
     return createLocalMemoryIndex();
   }
 
+  /**
+   * Subscribe for `IMPLEMENTED` and wait for the notification.
+   */
   Future prepareImplementedElements() {
-    addAnalysisSubscription(AnalysisService.IMPLEMENTED, testFile);
-    Future waitForNotification(int times) {
-      if (times == 0 || implementedClasses != null) {
-        return new Future.value();
-      }
-      return new Future.delayed(
-          Duration.ZERO, () => waitForNotification(times - 1));
-    }
-    return waitForNotification(100);
+    subscribeForImplemented();
+    return waitForImplementedElements();
   }
 
   void processNotification(Notification notification) {
@@ -117,6 +122,10 @@
     createProject();
   }
 
+  void subscribeForImplemented() {
+    addAnalysisSubscription(AnalysisService.IMPLEMENTED, testFile);
+  }
+
   test_afterAnalysis() async {
     addTestFile('''
 class A {}
@@ -127,6 +136,25 @@
     assertHasImplementedClass('A {');
   }
 
+  test_afterIncrementalResolution() async {
+    subscribeForImplemented();
+    addTestFile('''
+class A {}
+class B extends A {}
+''');
+    await prepareImplementedElements();
+    assertHasImplementedClass('A {');
+    // add a space
+    implementedClasses = null;
+    testCode = '''
+class A  {}
+class B extends A {}
+''';
+    server.updateContent('1', {testFile: new AddContentOverlay(testCode)});
+    await waitForImplementedElements();
+    assertHasImplementedClass('A  {');
+  }
+
   test_class_extended() async {
     addTestFile('''
 class A {}
@@ -286,4 +314,15 @@
     await prepareImplementedElements();
     assertHasImplementedMember('f(_) {} // A');
   }
+
+  Future waitForImplementedElements() {
+    Future waitForNotification(int times) {
+      if (times == 0 || implementedClasses != null) {
+        return new Future.value();
+      }
+      return new Future.delayed(
+          new Duration(milliseconds:1), () => waitForNotification(times - 1));
+    }
+    return waitForNotification(30000);
+  }
 }
diff --git a/pkg/analysis_server/test/analysis/notification_navigation_test.dart b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
index fee0d6f..6ef6b57 100644
--- a/pkg/analysis_server/test/analysis/notification_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
@@ -215,6 +215,113 @@
     });
   }
 
+  test_annotationConstructor_implicit() async {
+    addTestFile('''
+class A {
+}
+@A()
+main() {
+}
+''');
+    await prepareNavigation();
+    assertHasRegionString('A()', 'A'.length);
+    assertHasTarget('A {');
+  }
+
+  test_annotationConstructor_importPrefix() async {
+    addFile(
+        '$testFolder/my_annotation.dart',
+        r'''
+library an;
+class MyAnnotation {
+  const MyAnnotation();
+  const MyAnnotation.named();
+}
+''');
+    addTestFile('''
+import 'my_annotation.dart' as man;
+@man.MyAnnotation()
+@man.MyAnnotation.named()
+main() {
+}
+''');
+    await prepareNavigation();
+    assertHasRegion('MyAnnotation()');
+    assertHasRegion('MyAnnotation.named()');
+    assertHasRegion('named()');
+    {
+      assertHasRegion('man.MyAnnotation()');
+      assertHasTarget('man;');
+    }
+    {
+      assertHasRegion('man.MyAnnotation.named()');
+      assertHasTarget('man;');
+    }
+  }
+
+  test_annotationConstructor_named() async {
+    addTestFile('''
+class A {
+  const A.named(p);
+}
+@A.named(0)
+main() {
+}
+''');
+    await prepareNavigation();
+    {
+      assertHasRegion('A.named(0)');
+      assertHasTarget('named(p);');
+    }
+    {
+      assertHasRegion('named(0)');
+      assertHasTarget('named(p);');
+    }
+  }
+
+  test_annotationConstructor_unnamed() async {
+    addTestFile('''
+class A {
+  const A();
+}
+@A()
+main() {
+}
+''');
+    await prepareNavigation();
+    assertHasRegionString('A()', 'A'.length);
+    assertHasTarget('A();', 0);
+  }
+
+  test_annotationField() async {
+    addTestFile('''
+const myan = new Object();
+@myan // ref
+main() {
+}
+''');
+    await prepareNavigation();
+    assertHasRegion('myan // ref');
+    assertHasTarget('myan = new Object();');
+  }
+
+  test_annotationField_importPrefix() async {
+    addFile(
+        '$testFolder/mayn.dart',
+        r'''
+library an;
+const myan = new Object();
+''');
+    addTestFile('''
+import 'mayn.dart' as man;
+@man.myan // ref
+main() {
+}
+''');
+    await prepareNavigation();
+    assertHasRegion('myan // ref');
+  }
+
   test_class_fromSDK() {
     addTestFile('''
 int V = 42;
diff --git a/pkg/analysis_server/test/analysis/notification_outline_test.dart b/pkg/analysis_server/test/analysis/notification_outline_test.dart
index fdac6b5..4840a2e 100644
--- a/pkg/analysis_server/test/analysis/notification_outline_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_outline_test.dart
@@ -21,6 +21,8 @@
 
 @reflectiveTest
 class _AnalysisNotificationOutlineTest extends AbstractAnalysisTest {
+  FileKind fileKind;
+  String libraryName;
   Outline outline;
 
   Future prepareOutline() {
@@ -32,6 +34,8 @@
     if (notification.event == ANALYSIS_OUTLINE) {
       var params = new AnalysisOutlineParams.fromNotification(notification);
       if (params.file == testFile) {
+        fileKind = params.kind;
+        libraryName = params.libraryName;
         outline = params.outline;
       }
     }
@@ -311,6 +315,43 @@
     });
   }
 
+  test_libraryName_hasLibraryDirective() async {
+    addTestFile('''
+library my.lib;
+''');
+    await prepareOutline();
+    expect(fileKind, FileKind.LIBRARY);
+    expect(libraryName, 'my.lib');
+  }
+
+  test_libraryName_hasLibraryPartOfDirectives() async {
+    addTestFile('''
+part of lib.in.part.of;
+library my.lib;
+''');
+    await prepareOutline();
+    expect(fileKind, FileKind.LIBRARY);
+    expect(libraryName, 'my.lib');
+  }
+
+  test_libraryName_hasPartOfDirective() async {
+    addTestFile('''
+part of my.lib;
+''');
+    await prepareOutline();
+    expect(fileKind, FileKind.PART);
+    expect(libraryName, 'my.lib');
+  }
+
+  test_libraryName_noDirectives() async {
+    addTestFile('''
+class A {}
+''');
+    await prepareOutline();
+    expect(fileKind, FileKind.LIBRARY);
+    expect(libraryName, isNull);
+  }
+
   test_localFunctions() {
     addTestFile('''
 class A {
diff --git a/pkg/analysis_server/test/analysis/test_all.dart b/pkg/analysis_server/test/analysis/test_all.dart
index a14781f..468d420 100644
--- a/pkg/analysis_server/test/analysis/test_all.dart
+++ b/pkg/analysis_server/test/analysis/test_all.dart
@@ -27,7 +27,7 @@
  */
 main() {
   initializeTestEnvironment();
-  group('search', () {
+  group('analysis', () {
     get_errors_test.main();
     get_hover_test.main();
     get_navigation_test.main();
diff --git a/pkg/analysis_server/test/completion_test.dart b/pkg/analysis_server/test/completion_test.dart
index d602bde..7fc8d23 100644
--- a/pkg/analysis_server/test/completion_test.dart
+++ b/pkg/analysis_server/test/completion_test.dart
@@ -2851,7 +2851,7 @@
 
     // test analysis of untyped fields and top-level vars
     buildTests('test035', '''class Y {final x='hi';mth() {x.!1length;}}''',
-        <String>["1+length"]);
+        <String>["1+length"], failingTests: '1');
 
     // TODO(scheglov) decide what to do with Type for untyped field (not
     // supported by the new store)
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 1202ef3..c1ccc99 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -6,9 +6,6 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/completion/completion_core.dart'
-    show CompletionRequest, CompletionResult;
-import 'package:analysis_server/completion/completion_dart.dart' as newApi;
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/channel/channel.dart';
 import 'package:analysis_server/src/constants.dart';
@@ -17,6 +14,10 @@
 import 'package:analysis_server/src/domain_completion.dart';
 import 'package:analysis_server/src/plugin/server_plugin.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart'
+    show 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_completion_manager.dart';
diff --git a/pkg/analysis_server/test/edit/organize_directives_test.dart b/pkg/analysis_server/test/edit/organize_directives_test.dart
index deb4ed9..821e4a4 100644
--- a/pkg/analysis_server/test/edit/organize_directives_test.dart
+++ b/pkg/analysis_server/test/edit/organize_directives_test.dart
@@ -65,6 +65,28 @@
         response, isResponseFailure('0', RequestErrorCode.FILE_NOT_ANALYZED));
   }
 
+  Future test_OK_remove_duplicateImports_withSamePrefix() {
+    addTestFile('''
+library lib;
+
+import 'dart:async' as async;
+import 'dart:async' as async;
+
+main() {
+  async.Future f;
+}
+''');
+    return _assertOrganized(r'''
+library lib;
+
+import 'dart:async' as async;
+
+main() {
+  async.Future f;
+}
+''');
+  }
+
   Future test_OK_remove_unresolvedDirectives() {
     addFile('$testFolder/existing_part1.dart', 'part of lib;');
     addFile('$testFolder/existing_part2.dart', 'part of lib;');
diff --git a/pkg/analysis_server/test/integration/integration_test_methods.dart b/pkg/analysis_server/test/integration/integration_test_methods.dart
index 836f884..8ab5dca 100644
--- a/pkg/analysis_server/test/integration/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/integration_test_methods.dart
@@ -829,6 +829,18 @@
    *
    *   The file with which the outline is associated.
    *
+   * kind ( FileKind )
+   *
+   *   The kind of the file.
+   *
+   * libraryName ( optional String )
+   *
+   *   The name of the library defined by the file using a "library" directive,
+   *   or referenced by a "part of" directive. If both "library" and "part of"
+   *   directives are present, then the "library" directive takes precedence.
+   *   This field will be omitted if the file has neither "library" nor "part
+   *   of" directives.
+   *
    * outline ( Outline )
    *
    *   The outline associated with the file.
diff --git a/pkg/analysis_server/test/integration/integration_tests.dart b/pkg/analysis_server/test/integration/integration_tests.dart
index ed2d62a..6e7273e 100644
--- a/pkg/analysis_server/test/integration/integration_tests.dart
+++ b/pkg/analysis_server/test/integration/integration_tests.dart
@@ -597,7 +597,7 @@
       {bool debugServer: false,
       int diagnosticPort,
       bool profileServer: false,
-      bool newTaskModel: false,
+      bool newTaskModel: true,
       bool useAnalysisHighlight2: false}) {
     if (_process != null) {
       throw new Exception('Process already started');
@@ -627,9 +627,11 @@
     if (useAnalysisHighlight2) {
       arguments.add('--useAnalysisHighlight2');
     }
-    if (newTaskModel) {
-      arguments.add('--${analysisServer.Driver.ENABLE_NEW_TASK_MODEL}');
+    if (!newTaskModel) {
+      arguments.add('--${analysisServer.Driver.DISABLE_NEW_TASK_MODEL}');
     }
+    print('Launching $serverPath');
+    print('$dartBinary ${arguments.join(' ')}');
     return Process.start(dartBinary, arguments).then((Process process) {
       _process = process;
       process.exitCode.then((int code) {
diff --git a/pkg/analysis_server/test/integration/protocol_matchers.dart b/pkg/analysis_server/test/integration/protocol_matchers.dart
index 4d2bc54..347976e 100644
--- a/pkg/analysis_server/test/integration/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/protocol_matchers.dart
@@ -468,13 +468,18 @@
  *
  * {
  *   "file": FilePath
+ *   "kind": FileKind
+ *   "libraryName": optional String
  *   "outline": Outline
  * }
  */
 final Matcher isAnalysisOutlineParams = new LazyMatcher(() => new MatchesJsonObject(
   "analysis.outline params", {
     "file": isFilePath,
+    "kind": isFileKind,
     "outline": isOutline
+  }, optionalFields: {
+    "libraryName": isString
   }));
 
 /**
@@ -1024,6 +1029,7 @@
  *   "location": Location
  *   "message": String
  *   "correction": optional String
+ *   "hasFix": optional bool
  * }
  */
 final Matcher isAnalysisError = new LazyMatcher(() => new MatchesJsonObject(
@@ -1033,7 +1039,8 @@
     "location": isLocation,
     "message": isString
   }, optionalFields: {
-    "correction": isString
+    "correction": isString,
+    "hasFix": isBool
   }));
 
 /**
@@ -1379,6 +1386,19 @@
 ]);
 
 /**
+ * FileKind
+ *
+ * enum {
+ *   LIBRARY
+ *   PART
+ * }
+ */
+final Matcher isFileKind = new MatchesEnum("FileKind", [
+  "LIBRARY",
+  "PART"
+]);
+
+/**
  * FilePath
  *
  * String
@@ -2221,6 +2241,8 @@
  * extractLocalVariable feedback
  *
  * {
+ *   "coveringExpressionOffsets": List<int>
+ *   "coveringExpressionLengths": List<int>
  *   "names": List<String>
  *   "offsets": List<int>
  *   "lengths": List<int>
@@ -2228,6 +2250,8 @@
  */
 final Matcher isExtractLocalVariableFeedback = new LazyMatcher(() => new MatchesJsonObject(
   "extractLocalVariable feedback", {
+    "coveringExpressionOffsets": isListOf(isInt),
+    "coveringExpressionLengths": isListOf(isInt),
     "names": isListOf(isString),
     "offsets": isListOf(isInt),
     "lengths": isListOf(isInt)
diff --git a/pkg/analysis_server/test/protocol_server_test.dart b/pkg/analysis_server/test/protocol_server_test.dart
index 7abbe3f..d770e35 100644
--- a/pkg/analysis_server/test/protocol_server_test.dart
+++ b/pkg/analysis_server/test/protocol_server_test.dart
@@ -72,7 +72,8 @@
         START_COLUMN: 2
       },
       MESSAGE: 'my message',
-      CORRECTION: 'my correction'
+      CORRECTION: 'my correction',
+      HAS_FIX : false
     });
   }
 
@@ -89,7 +90,8 @@
         START_LINE: 3,
         START_COLUMN: 2
       },
-      MESSAGE: 'my message'
+      MESSAGE: 'my message',
+      HAS_FIX : false
     });
   }
 
@@ -106,7 +108,8 @@
         START_LINE: -1,
         START_COLUMN: -1
       },
-      MESSAGE: 'my message'
+      MESSAGE: 'my message',
+      HAS_FIX : false
     });
   }
 }
diff --git a/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart b/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart
index 433448b..959b027 100644
--- a/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart
@@ -90,6 +90,17 @@
     contributor = new ArgListContributor();
   }
 
+  test_Annotation_local_constructor_named_param() {
+    //
+    addTestSource('''
+class A { A({int one, String two: 'defaultValue'}) { } }
+@A(^) main() { }''');
+    computeFast();
+    return computeFull((bool result) {
+      assertSuggestArguments(namedArguments: ['one', 'two']);
+    });
+  }
+
   test_ArgumentList_getter() {
     addTestSource('class A {int get foo => 7; main() {foo(^)}');
     computeFast();
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 0cdeff9..dddf75e 100644
--- a/pkg/analysis_server/test/services/completion/completion_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_computer_test.dart
@@ -6,10 +6,10 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/completion/completion_core.dart'
-    show CompletionRequest, CompletionResult;
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart'
+    show CompletionRequest, CompletionResult;
 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';
@@ -94,26 +94,24 @@
       switch (++count) {
         case 1:
           contributor1.assertCalls(context, source, 0, searchEngine);
+          expect(contributor1.fastCount, equals(1));
+          expect(contributor1.fullCount, equals(0));
           contributor2.assertCalls(context, source, 0, searchEngine);
-          expect(isLast, isFalse);
-          expect(r.suggestions, hasLength(1));
-          expect(r.suggestions, contains(suggestion1));
-          resolveLibrary();
-          break;
-        case 2:
-          contributor1.assertFull(0);
-          contributor2.assertFull(1);
+          expect(contributor2.fastCount, equals(1));
+          expect(contributor2.fullCount, equals(1));
           expect(isLast, isTrue);
           expect(r.suggestions, hasLength(2));
           expect(r.suggestions, contains(suggestion1));
           expect(r.suggestions, contains(suggestion2));
+          resolveLibrary();
           break;
         default:
           fail('unexpected');
       }
     }, onDone: () {
       done = true;
-      expect(count, equals(2));
+      // There is only one notification
+      expect(count, equals(1));
     });
     return pumpEventQueue().then((_) {
       expect(done, isTrue);
@@ -134,7 +132,11 @@
       switch (++count) {
         case 1:
           contributor1.assertCalls(context, source, 0, searchEngine);
+          expect(contributor1.fastCount, equals(1));
+          expect(contributor1.fullCount, equals(0));
           contributor2.assertCalls(context, source, 0, searchEngine);
+          expect(contributor2.fastCount, equals(1));
+          expect(contributor2.fullCount, equals(0));
           expect(isLast, isTrue);
           expect(r.suggestions, hasLength(2));
           expect(r.suggestions, contains(suggestion1));
@@ -170,14 +172,11 @@
 
   MockCompletionContributor(this.fastSuggestion, this.fullSuggestion);
 
-  assertCalls(AnalysisContext context, Source source, int offset,
-      SearchEngine searchEngine) {
+  assertCalls(AnalysisContext context, Source source, int offset, SearchEngine searchEngine) {
     expect(request.context, equals(context));
     expect(request.source, equals(source));
     expect(request.offset, equals(offset));
     expect(request.searchEngine, equals(searchEngine));
-    expect(this.fastCount, equals(1));
-    expect(this.fullCount, equals(0));
   }
 
   assertFull(int fullCount) {
diff --git a/pkg/analysis_server/test/services/completion/completion_target_test.dart b/pkg/analysis_server/test/services/completion/completion_target_test.dart
index 6d0e52f..169874b 100644
--- a/pkg/analysis_server/test/services/completion/completion_target_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_target_test.dart
@@ -4,7 +4,7 @@
 
 library test.services.completion.target;
 
-import 'package:analysis_server/completion/dart/completion_target.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
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 94d9058..e9b24b4 100644
--- a/pkg/analysis_server/test/services/completion/completion_test_util.dart
+++ b/pkg/analysis_server/test/services/completion/completion_test_util.dart
@@ -10,9 +10,9 @@
 import 'package:analysis_server/src/protocol.dart' as protocol
     show Element, ElementKind;
 import 'package:analysis_server/src/protocol.dart' hide Element, ElementKind;
+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/completion/dart/completion_target.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';
@@ -1357,7 +1357,8 @@
       //assertSuggestImportedTopLevelVar('T3', 'int', COMPLETION_RELEVANCE_LOW);
       assertNotSuggested('_T4');
       assertSuggestLocalTopLevelVar('T5', 'int');
-      assertSuggestLocalTopLevelVar('_T6', null);
+      assertSuggestLocalTopLevelVar('_T6', null,
+          relevance: DART_RELEVANCE_DEFAULT);
       assertNotSuggested('==');
       assertSuggestLocalGetter('T7', 'String');
       assertSuggestLocalSetter('T8');
@@ -3473,7 +3474,8 @@
         expect(getterF.element.isDeprecated, isTrue);
         expect(getterF.element.isPrivate, isFalse);
       }
-      CompletionSuggestion getterG = assertSuggestLocalGetter('_g', null);
+      CompletionSuggestion getterG = assertSuggestLocalGetter('_g', null,
+          relevance: DART_RELEVANCE_DEFAULT);
       if (getterG != null) {
         expect(getterG.element.isDeprecated, isFalse);
         expect(getterG.element.isPrivate, isTrue);
@@ -3528,7 +3530,8 @@
     return computeFull((bool result) {
       expect(request.replacementOffset, completionOffset);
       expect(request.replacementLength, 0);
-      CompletionSuggestion methodA = assertSuggestLocalMethod('_a', 'A', 'Z');
+      CompletionSuggestion methodA = assertSuggestLocalMethod('_a', 'A', 'Z',
+          relevance: DART_RELEVANCE_DEFAULT);
       if (methodA != null) {
         expect(methodA.element.isDeprecated, isFalse);
         expect(methodA.element.isPrivate, isTrue);
diff --git a/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart b/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
index bf3c027..882efd9 100644
--- a/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
@@ -85,7 +85,6 @@
     Keyword.FOR,
     Keyword.IF,
     Keyword.NEW,
-    Keyword.RETHROW,
     Keyword.RETURN,
     Keyword.SUPER,
     Keyword.SWITCH,
@@ -107,7 +106,6 @@
     Keyword.FOR,
     Keyword.IF,
     Keyword.NEW,
-    Keyword.RETHROW,
     Keyword.RETURN,
     Keyword.SUPER,
     Keyword.SWITCH,
@@ -130,7 +128,6 @@
     Keyword.FOR,
     Keyword.IF,
     Keyword.NEW,
-    Keyword.RETHROW,
     Keyword.RETURN,
     Keyword.SUPER,
     Keyword.SWITCH,
@@ -153,7 +150,6 @@
     Keyword.FOR,
     Keyword.IF,
     Keyword.NEW,
-    Keyword.RETHROW,
     Keyword.RETURN,
     Keyword.SWITCH,
     Keyword.THROW,
@@ -171,7 +167,6 @@
     Keyword.FOR,
     Keyword.IF,
     Keyword.NEW,
-    Keyword.RETHROW,
     Keyword.RETURN,
     Keyword.SWITCH,
     Keyword.THROW,
@@ -191,7 +186,6 @@
     Keyword.FOR,
     Keyword.IF,
     Keyword.NEW,
-    Keyword.RETHROW,
     Keyword.RETURN,
     Keyword.SWITCH,
     Keyword.THROW,
@@ -613,6 +607,16 @@
         relevance: DART_RELEVANCE_KEYWORD);
   }
 
+  test_catch() {
+    addTestSource('main() {try {} catch (e) {^}}}');
+    expect(computeFast(), isTrue);
+    var keywords = <Keyword>[];
+    keywords.addAll(STMT_START_OUTSIDE_CLASS);
+    keywords.add(Keyword.RETHROW);
+    assertSuggestKeywords(keywords,
+        relevance: DART_RELEVANCE_KEYWORD);
+  }
+
   test_for_break_continue2() {
     addTestSource('class A {foo() {for (int x in myList) {^}}}');
     expect(computeFast(), isTrue);
diff --git a/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart
index cb29f97..94c0717 100644
--- a/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart
@@ -793,6 +793,20 @@
     assertSuggestMethod('m', 'B', null, relevance: DART_RELEVANCE_LOCAL_METHOD);
   }
 
+  test_prioritization_private() {
+    addTestSource('main() {var ab; var _ab; _^}');
+    expect(computeFast(), isTrue);
+    assertSuggestLocalVariable('ab', null);
+    assertSuggestLocalVariable('_ab', null);
+  }
+
+  test_prioritization_public() {
+    addTestSource('main() {var ab; var _ab; a^}');
+    expect(computeFast(), isTrue);
+    assertSuggestLocalVariable('ab', null);
+    assertSuggestLocalVariable('_ab', null, relevance: DART_RELEVANCE_DEFAULT);
+  }
+
   test_shadowed_name() {
     addTestSource('var a; class A { var a; m() { ^ } }');
     expect(computeFast(), isTrue);
diff --git a/pkg/analysis_server/test/services/completion/optype_test.dart b/pkg/analysis_server/test/services/completion/optype_test.dart
index e2c654c..a2bf5c8 100644
--- a/pkg/analysis_server/test/services/completion/optype_test.dart
+++ b/pkg/analysis_server/test/services/completion/optype_test.dart
@@ -4,7 +4,7 @@
 
 library test.services.completion.contributor.dart.optype;
 
-import 'package:analysis_server/completion/dart/completion_target.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
 import 'package:analysis_server/src/services/completion/optype.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart';
diff --git a/pkg/analysis_server/test/services/completion/uri_contributor_test.dart b/pkg/analysis_server/test/services/completion/uri_contributor_test.dart
index 9742dbd..4a046a1 100644
--- a/pkg/analysis_server/test/services/completion/uri_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/uri_contributor_test.dart
@@ -186,6 +186,16 @@
         csKind: CompletionSuggestionKind.IMPORT);
   }
 
+  test_export_package2() {
+    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();
+    assertSuggest('package:foo/baz/too.dart',
+        csKind: CompletionSuggestionKind.IMPORT);
+  }
+
   test_import_package_missing_lib() {
     var pkgSrc = addPackageSource('bar', 'bar.dart', 'library bar;');
     provider.deleteFolder(dirname(pkgSrc.fullName));
diff --git a/pkg/analysis_server/test/services/correction/organize_directives_test.dart b/pkg/analysis_server/test/services/correction/organize_directives_test.dart
index 6c817b5..833cc49 100644
--- a/pkg/analysis_server/test/services/correction/organize_directives_test.dart
+++ b/pkg/analysis_server/test/services/correction/organize_directives_test.dart
@@ -22,6 +22,29 @@
 class OrganizeDirectivesTest extends AbstractSingleUnitTest {
   List<AnalysisError> testErrors;
 
+  void test_keep_duplicateImports_withDifferentPrefix() {
+    _computeUnitAndErrors(r'''
+import 'dart:async' as async1;
+import 'dart:async' as async2;
+
+main() {
+  async1.Future f;
+  async2.Stream s;
+}''');
+    // validate change
+    _assertOrganize(
+        r'''
+import 'dart:async' as async1;
+import 'dart:async' as async2;
+
+main() {
+  async1.Future f;
+  async2.Stream s;
+}''',
+        removeUnresolved: true,
+        removeUnused: true);
+  }
+
   void test_remove_duplicateImports() {
     _computeUnitAndErrors(r'''
 import 'dart:async';
@@ -42,6 +65,46 @@
         removeUnused: true);
   }
 
+  void test_remove_duplicateImports_differentText_uri() {
+    _computeUnitAndErrors(r'''
+import 'dart:async' as async;
+import "dart:async" as async;
+
+main() {
+  async.Future f;
+}''');
+    // validate change
+    _assertOrganize(
+        r'''
+import 'dart:async' as async;
+
+main() {
+  async.Future f;
+}''',
+        removeUnresolved: true,
+        removeUnused: true);
+  }
+
+  void test_remove_duplicateImports_withSamePrefix() {
+    _computeUnitAndErrors(r'''
+import 'dart:async' as async;
+import 'dart:async' as async;
+
+main() {
+  async.Future f;
+}''');
+    // validate change
+    _assertOrganize(
+        r'''
+import 'dart:async' as async;
+
+main() {
+  async.Future f;
+}''',
+        removeUnresolved: true,
+        removeUnused: true);
+  }
+
   void test_remove_unresolvedDirectives() {
     addSource('/existing_part1.dart', 'part of lib;');
     addSource('/existing_part2.dart', 'part of lib;');
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 43dbe33..5e6d180 100644
--- a/pkg/analysis_server/test/services/index/store/codec_test.dart
+++ b/pkg/analysis_server/test/services/index/store/codec_test.dart
@@ -93,7 +93,7 @@
       int id2 = codec.encode2(indexable);
       int id3 = codec.encode3(indexable);
       expect(id1, isNonNegative);
-      expect(id2, isNonNegative);
+      expect(id2, -1);
       expect(id3, IndexableElementKind.forElement(element).index);
       validateDecode(id1, id2, id3, element);
     }
@@ -106,7 +106,7 @@
       int id2 = codec.encode2(indexable);
       int id3 = codec.encode3(indexable);
       expect(id1, isNonNegative);
-      expect(id2, isNonNegative);
+      expect(id2, -1);
       expect(id3, IndexableElementKind.forElement(element).index);
       validateDecode(id1, id2, id3, element);
     }
@@ -260,6 +260,7 @@
     expect(id1, -1);
     expect(id2, isNonNegative);
     expect(id3, IndexableNameKind.INSTANCE.index);
+    expect(codec.decode(context, id1, id2, id3), indexable);
   }
 
   void test_encode_LibraryElement() {
@@ -274,7 +275,7 @@
     int id2 = codec.encode2(indexable);
     int id3 = codec.encode3(indexable);
     expect(id1, isNonNegative);
-    expect(id2, isNonNegative);
+    expect(id2, -1);
     expect(id3, IndexableElementKind.forElement(element).index);
     validateDecode(id1, id2, id3, element);
   }
diff --git a/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart b/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
index 3f0ee70..d0b312b 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
@@ -582,6 +582,43 @@
     assertPotentialEdits(['test(); // 1', 'test(); // 2']);
   }
 
+  test_createChange_MethodElement_potential_inPubCache() async {
+    String pkgLib = '/.pub-cache/lib.dart';
+    indexUnit(
+        pkgLib,
+        r'''
+processObj(p) {
+  p.test();
+}
+''');
+    indexTestUnit('''
+import '$pkgLib';
+class A {
+  test() {}
+}
+main(var a) {
+  a.test();
+}
+''');
+    // configure refactoring
+    createRenameRefactoringAtString('test() {}');
+    expect(refactoring.refactoringName, 'Rename Method');
+    expect(refactoring.oldName, 'test');
+    refactoring.newName = 'newName';
+    // validate change
+    await assertSuccessfulRefactoring('''
+import '/.pub-cache/lib.dart';
+class A {
+  newName() {}
+}
+main(var a) {
+  a.newName();
+}
+''');
+    SourceFileEdit fileEdit = refactoringChange.getFileEdit(pkgLib);
+    expect(fileEdit, isNull);
+  }
+
   test_createChange_MethodElement_potential_private_otherLibrary() async {
     indexUnit(
         '/lib.dart',
diff --git a/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart b/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
index 4c799d1..8e38f8f 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
@@ -224,6 +224,48 @@
     assertRefactoringStatusOK(status);
   }
 
+  test_checkInitialConditions_inPubCache_posix() async {
+    addSource(
+        '/.pub-cache/lib.dart',
+        r'''
+class A {}
+''');
+    indexTestUnit('''
+import '/.pub-cache/lib.dart';
+main() {
+  A a;
+}
+''');
+    createRenameRefactoringAtString('A a');
+    // check status
+    refactoring.newName = 'NewName';
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL,
+        expectedMessage:
+            "The class 'A' is defined in a pub package, so cannot be renamed.");
+  }
+
+  test_checkInitialConditions_inPubCache_windows() async {
+    addSource(
+        '/Pub/Cache/lib.dart',
+        r'''
+class A {}
+''');
+    indexTestUnit('''
+import '/Pub/Cache/lib.dart';
+main() {
+  A a;
+}
+''');
+    createRenameRefactoringAtString('A a');
+    // check status
+    refactoring.newName = 'NewName';
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL,
+        expectedMessage:
+            "The class 'A' is defined in a pub package, so cannot be renamed.");
+  }
+
   test_checkInitialConditions_inSDK() async {
     indexTestUnit('''
 main() {
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/AnalysisError.java b/pkg/analysis_server/tool/spec/generated/java/types/AnalysisError.java
index c85d882..baf27c0 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/AnalysisError.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/AnalysisError.java
@@ -72,14 +72,26 @@
   private final String correction;
 
   /**
+   * A hint to indicate to interested clients that this error has an associated fix (or fixes). The
+   * absence of this field implies there are not known to be fixes. Note that since the operation to
+   * calculate whether fixes apply needs to be performant it is possible that complicated tests will
+   * be skipped and a false negative returned. For this reason, this attribute should be treated as a
+   * "hint". Despite the possibility of false negatives, no false positives should be returned. If a
+   * client sees this flag set they can proceed with the confidence that there are in fact associated
+   * fixes.
+   */
+  private final Boolean hasFix;
+
+  /**
    * Constructor for {@link AnalysisError}.
    */
-  public AnalysisError(String severity, String type, Location location, String message, String correction) {
+  public AnalysisError(String severity, String type, Location location, String message, String correction, Boolean hasFix) {
     this.severity = severity;
     this.type = type;
     this.location = location;
     this.message = message;
     this.correction = correction;
+    this.hasFix = hasFix;
   }
 
   @Override
@@ -91,7 +103,8 @@
         ObjectUtilities.equals(other.type, type) &&
         ObjectUtilities.equals(other.location, location) &&
         ObjectUtilities.equals(other.message, message) &&
-        ObjectUtilities.equals(other.correction, correction);
+        ObjectUtilities.equals(other.correction, correction) &&
+        ObjectUtilities.equals(other.hasFix, hasFix);
     }
     return false;
   }
@@ -102,7 +115,8 @@
     Location location = Location.fromJson(jsonObject.get("location").getAsJsonObject());
     String message = jsonObject.get("message").getAsString();
     String correction = jsonObject.get("correction") == null ? null : jsonObject.get("correction").getAsString();
-    return new AnalysisError(severity, type, location, message, correction);
+    Boolean hasFix = jsonObject.get("hasFix") == null ? null : jsonObject.get("hasFix").getAsBoolean();
+    return new AnalysisError(severity, type, location, message, correction, hasFix);
   }
 
   public static List<AnalysisError> fromJsonArray(JsonArray jsonArray) {
@@ -127,6 +141,19 @@
   }
 
   /**
+   * A hint to indicate to interested clients that this error has an associated fix (or fixes). The
+   * absence of this field implies there are not known to be fixes. Note that since the operation to
+   * calculate whether fixes apply needs to be performant it is possible that complicated tests will
+   * be skipped and a false negative returned. For this reason, this attribute should be treated as a
+   * "hint". Despite the possibility of false negatives, no false positives should be returned. If a
+   * client sees this flag set they can proceed with the confidence that there are in fact associated
+   * fixes.
+   */
+  public Boolean getHasFix() {
+    return hasFix;
+  }
+
+  /**
    * The location associated with the error.
    */
   public Location getLocation() {
@@ -163,6 +190,7 @@
     builder.append(location);
     builder.append(message);
     builder.append(correction);
+    builder.append(hasFix);
     return builder.toHashCode();
   }
 
@@ -175,6 +203,9 @@
     if (correction != null) {
       jsonObject.addProperty("correction", correction);
     }
+    if (hasFix != null) {
+      jsonObject.addProperty("hasFix", hasFix);
+    }
     return jsonObject;
   }
 
@@ -191,7 +222,9 @@
     builder.append("message=");
     builder.append(message + ", ");
     builder.append("correction=");
-    builder.append(correction);
+    builder.append(correction + ", ");
+    builder.append("hasFix=");
+    builder.append(hasFix);
     builder.append("]");
     return builder.toString();
   }
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/ExtractLocalVariableFeedback.java b/pkg/analysis_server/tool/spec/generated/java/types/ExtractLocalVariableFeedback.java
index c329329..e00506d 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/ExtractLocalVariableFeedback.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/ExtractLocalVariableFeedback.java
@@ -42,6 +42,18 @@
   public static final List<ExtractLocalVariableFeedback> EMPTY_LIST = Lists.newArrayList();
 
   /**
+   * The offsets of the expressions that cover the specified selection, from the down most to the up
+   * most.
+   */
+  private final int[] coveringExpressionOffsets;
+
+  /**
+   * The lengths of the expressions that cover the specified selection, from the down most to the up
+   * most.
+   */
+  private final int[] coveringExpressionLengths;
+
+  /**
    * The proposed names for the local variable.
    */
   private final List<String> names;
@@ -61,7 +73,9 @@
   /**
    * Constructor for {@link ExtractLocalVariableFeedback}.
    */
-  public ExtractLocalVariableFeedback(List<String> names, int[] offsets, int[] lengths) {
+  public ExtractLocalVariableFeedback(int[] coveringExpressionOffsets, int[] coveringExpressionLengths, List<String> names, int[] offsets, int[] lengths) {
+    this.coveringExpressionOffsets = coveringExpressionOffsets;
+    this.coveringExpressionLengths = coveringExpressionLengths;
     this.names = names;
     this.offsets = offsets;
     this.lengths = lengths;
@@ -72,6 +86,8 @@
     if (obj instanceof ExtractLocalVariableFeedback) {
       ExtractLocalVariableFeedback other = (ExtractLocalVariableFeedback) obj;
       return
+        Arrays.equals(other.coveringExpressionOffsets, coveringExpressionOffsets) &&
+        Arrays.equals(other.coveringExpressionLengths, coveringExpressionLengths) &&
         ObjectUtilities.equals(other.names, names) &&
         Arrays.equals(other.offsets, offsets) &&
         Arrays.equals(other.lengths, lengths);
@@ -80,10 +96,12 @@
   }
 
   public static ExtractLocalVariableFeedback fromJson(JsonObject jsonObject) {
+    int[] coveringExpressionOffsets = JsonUtilities.decodeIntArray(jsonObject.get("coveringExpressionOffsets").getAsJsonArray());
+    int[] coveringExpressionLengths = JsonUtilities.decodeIntArray(jsonObject.get("coveringExpressionLengths").getAsJsonArray());
     List<String> names = JsonUtilities.decodeStringList(jsonObject.get("names").getAsJsonArray());
     int[] offsets = JsonUtilities.decodeIntArray(jsonObject.get("offsets").getAsJsonArray());
     int[] lengths = JsonUtilities.decodeIntArray(jsonObject.get("lengths").getAsJsonArray());
-    return new ExtractLocalVariableFeedback(names, offsets, lengths);
+    return new ExtractLocalVariableFeedback(coveringExpressionOffsets, coveringExpressionLengths, names, offsets, lengths);
   }
 
   public static List<ExtractLocalVariableFeedback> fromJsonArray(JsonArray jsonArray) {
@@ -99,6 +117,22 @@
   }
 
   /**
+   * The lengths of the expressions that cover the specified selection, from the down most to the up
+   * most.
+   */
+  public int[] getCoveringExpressionLengths() {
+    return coveringExpressionLengths;
+  }
+
+  /**
+   * The offsets of the expressions that cover the specified selection, from the down most to the up
+   * most.
+   */
+  public int[] getCoveringExpressionOffsets() {
+    return coveringExpressionOffsets;
+  }
+
+  /**
    * The lengths of the expressions that would be replaced by a reference to the variable. The
    * lengths correspond to the offsets. In other words, for a given expression, if the offset of that
    * expression is offsets[i], then the length of that expression is lengths[i].
@@ -124,6 +158,8 @@
   @Override
   public int hashCode() {
     HashCodeBuilder builder = new HashCodeBuilder();
+    builder.append(coveringExpressionOffsets);
+    builder.append(coveringExpressionLengths);
     builder.append(names);
     builder.append(offsets);
     builder.append(lengths);
@@ -132,6 +168,16 @@
 
   public JsonObject toJson() {
     JsonObject jsonObject = new JsonObject();
+    JsonArray jsonArrayCoveringExpressionOffsets = new JsonArray();
+    for (int elt : coveringExpressionOffsets) {
+      jsonArrayCoveringExpressionOffsets.add(new JsonPrimitive(elt));
+    }
+    jsonObject.add("coveringExpressionOffsets", jsonArrayCoveringExpressionOffsets);
+    JsonArray jsonArrayCoveringExpressionLengths = new JsonArray();
+    for (int elt : coveringExpressionLengths) {
+      jsonArrayCoveringExpressionLengths.add(new JsonPrimitive(elt));
+    }
+    jsonObject.add("coveringExpressionLengths", jsonArrayCoveringExpressionLengths);
     JsonArray jsonArrayNames = new JsonArray();
     for (String elt : names) {
       jsonArrayNames.add(new JsonPrimitive(elt));
@@ -154,6 +200,10 @@
   public String toString() {
     StringBuilder builder = new StringBuilder();
     builder.append("[");
+    builder.append("coveringExpressionOffsets=");
+    builder.append(StringUtils.join(coveringExpressionOffsets, ", ") + ", ");
+    builder.append("coveringExpressionLengths=");
+    builder.append(StringUtils.join(coveringExpressionLengths, ", ") + ", ");
     builder.append("names=");
     builder.append(StringUtils.join(names, ", ") + ", ");
     builder.append("offsets=");
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/FileKind.java b/pkg/analysis_server/tool/spec/generated/java/types/FileKind.java
new file mode 100644
index 0000000..d9ba7bb
--- /dev/null
+++ b/pkg/analysis_server/tool/spec/generated/java/types/FileKind.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, the Dart project authors.
+ *
+ * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ *
+ * This file has been automatically generated.  Please do not edit it manually.
+ * To regenerate the file, use the script "pkg/analysis_server/tool/spec/generate_files".
+ */
+package org.dartlang.analysis.server.protocol;
+
+/**
+ * An enumeration of the kinds of files.
+ *
+ * @coverage dart.server.generated.types
+ */
+public class FileKind {
+
+  public static final String LIBRARY = "LIBRARY";
+
+  public static final String PART = "PART";
+
+}
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index c913011..a48d987 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.9.0</version></h1>
+    <h1 style="color:#999999">Version <version>1.12.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
@@ -1044,6 +1044,23 @@
               The file with which the outline is associated.
             </p>
           </field>
+          <field name="kind">
+            <ref>FileKind</ref>
+            <p>
+              The kind of the file.
+            </p>
+          </field>
+          <field name="libraryName" optional="true">
+            <ref>String</ref>
+            <p>
+              The name of the library defined by the file using a "library"
+              directive, or referenced by a "part of" directive. If both
+              "library" and "part of" directives are present, then the
+              "library" directive takes precedence.
+              This field will be omitted if the file has neither "library"
+              nor "part of" directives.
+            </p>
+          </field>
           <field name="outline">
             <ref>Outline</ref>
             <p>
@@ -2010,6 +2027,21 @@
               message associated with the error code.
             </p>
           </field>
+          <field name="hasFix" optional="true">
+            <ref>bool</ref>
+            <p>
+              A hint to indicate to interested clients that this error has
+              an associated fix (or fixes).  The absence of this field implies
+              there are not known to be fixes.  Note that since the operation
+              to calculate whether fixes apply needs to be performant it is
+              possible that complicated tests will be skipped and a false
+              negative returned.  For this reason, this attribute should be
+              treated as a "hint".  Despite the possibility of false negatives,
+              no false positives should be returned.  If a client sees this
+              flag set they can proceed with the confidence that there are in
+              fact associated fixes.
+            </p>
+          </field>
         </object>
       </type>
       <type name="AnalysisErrorFixes">
@@ -2551,6 +2583,15 @@
           <value><code>LAUNCH_DATA</code></value>
         </enum>
       </type>
+      <type name="FileKind">
+        <p>
+          An enumeration of the kinds of files.
+        </p>
+        <enum>
+          <value><code>LIBRARY</code></value>
+          <value><code>PART</code></value>
+        </enum>
+      </type>
       <type name="FilePath">
         <ref>String</ref>
         <p>
@@ -3985,14 +4026,28 @@
       </refactoring>
       <refactoring kind="EXTRACT_LOCAL_VARIABLE">
         <p>
-          Create a local variable initialized by a specified
-          expression.
+          Create a local variable initialized by the expression that covers
+          the specified selection.
         </p>
         <p>
-          It is an error if the range contains anything other than a
-          complete expression (no partial expressions are allowed).
+          It is an error if the selection range is not covered by a
+          complete expression.
         </p>
         <feedback>
+          <field name="coveringExpressionOffsets">
+            <list><ref>int</ref></list>
+            <p>
+              The offsets of the expressions that cover the specified
+              selection, from the down most to the up most.
+            </p>
+          </field>
+          <field name="coveringExpressionLengths">
+            <list><ref>int</ref></list>
+            <p>
+              The lengths of the expressions that cover the specified
+              selection, from the down most to the up most.
+            </p>
+          </field>
           <field name="names">
             <list><ref>String</ref></list>
             <p>
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index b39f429..c555f1b 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -27,7 +27,6 @@
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_collection.dart';
@@ -572,31 +571,13 @@
     if (source == null) {
       return null;
     }
-    CompilationUnit unit = parseCompilationUnit(source);
-    if (unit == null) {
+    SourceRange docRange = element.docRange;
+    if (docRange == null) {
       return null;
     }
-    NodeLocator locator = new NodeLocator(element.nameOffset);
-    AstNode nameNode = locator.searchWithin(unit);
-    while (nameNode != null) {
-      if (nameNode is AnnotatedNode) {
-        Comment comment = nameNode.documentationComment;
-        if (comment == null) {
-          return null;
-        }
-        StringBuffer buffer = new StringBuffer();
-        List<Token> tokens = comment.tokens;
-        for (int i = 0; i < tokens.length; i++) {
-          if (i > 0) {
-            buffer.write("\n");
-          }
-          buffer.write(tokens[i].lexeme);
-        }
-        return buffer.toString();
-      }
-      nameNode = nameNode.parent;
-    }
-    return null;
+    String code = getContents(source).data;
+    String comment = code.substring(docRange.offset, docRange.end);
+    return comment.replaceAll('\r\n', '\n');
   }
 
   @override
@@ -1157,7 +1138,7 @@
           new LibrarySpecificUnit(librarySource, librarySource);
       entry = getCacheEntry(unit);
       setValue(HINTS, AnalysisError.NO_ERRORS);
-      // dartEntry.setValue(LINTS, AnalysisError.NO_ERRORS);
+      setValue(LINTS, AnalysisError.NO_ERRORS);
       setValue(INFER_STATIC_VARIABLE_TYPES_ERRORS, AnalysisError.NO_ERRORS);
       setValue(LIBRARY_UNIT_ERRORS, AnalysisError.NO_ERRORS);
       setValue(PARTIALLY_RESOLVE_REFERENCES_ERRORS, AnalysisError.NO_ERRORS);
@@ -1654,16 +1635,16 @@
               return;
             }
           }
-//          if (lintsEnabled) {
-//            state = unitEntry.getState(LINTS);
-//            if (state == CacheState.INVALID ||
-//                (isPriority && state == CacheState.FLUSHED)) {
-//              sources.add(source);
-//              return;
-//            } else if (state == CacheState.ERROR) {
-//              return;
-//            }
-//          }
+          if (lintsEnabled) {
+            state = unitEntry.getState(LINTS);
+            if (state == CacheState.INVALID ||
+                (isPriority && state == CacheState.FLUSHED)) {
+              sources.add(source);
+              return;
+            } else if (state == CacheState.ERROR) {
+              return;
+            }
+          }
         }
       }
 //    } else if (kind == SourceKind.HTML) {
@@ -1896,8 +1877,7 @@
           sourceEntry,
           unitEntry,
           oldUnit,
-          analysisOptions.incrementalApi,
-          analysisOptions);
+          analysisOptions.incrementalApi);
       bool success = resolver.resolve(newCode);
       AnalysisEngine.instance.instrumentationService.logPerformance(
           AnalysisPerformanceKind.INCREMENTAL,
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index bff8b4e..30aa17e 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -2462,6 +2462,12 @@
   String get displayName;
 
   /**
+   * Return the source range of the documentation comment for this element,
+   * or `null` if this element does not or cannot have a documentation.
+   */
+  SourceRange get docRange;
+
+  /**
    * Return the element that either physically or logically encloses this
    * element. This will be `null` if this element is a library because libraries
    * are the top-level elements in the model.
@@ -2828,6 +2834,17 @@
   ElementLocation _cachedLocation;
 
   /**
+   * The offset to the beginning of the documentation comment,
+   * or `null` if this element does not have a documentation comment.
+   */
+  int _docRangeOffset;
+
+  /**
+   * The length of the documentation comment range for this element.
+   */
+  int _docRangeLength;
+
+  /**
    * Initialize a newly created element to have the given [name] at the given
    * [_nameOffset].
    */
@@ -2853,6 +2870,14 @@
   String get displayName => _name;
 
   @override
+  SourceRange get docRange {
+    if (_docRangeOffset != null && _docRangeLength != null) {
+      return new SourceRange(_docRangeOffset, _docRangeLength);
+    }
+    return null;
+  }
+
+  @override
   Element get enclosingElement => _enclosingElement;
 
   /**
@@ -3102,6 +3127,14 @@
   }
 
   /**
+   * Set the documentation comment source range for this element.
+   */
+  void setDocRange(int offset, int length) {
+    _docRangeOffset = offset;
+    _docRangeLength = length;
+  }
+
+  /**
    * Set whether the given [modifier] is associated with this element to
    * correspond to the given [value].
    */
@@ -7917,6 +7950,9 @@
   @override
   String get displayName => _baseElement.displayName;
 
+  @override
+  SourceRange get docRange => _baseElement.docRange;
+
   int get id => _baseElement.id;
 
   @override
@@ -8427,6 +8463,9 @@
   String get displayName => _name;
 
   @override
+  SourceRange get docRange => null;
+
+  @override
   Element get enclosingElement => null;
 
   @override
diff --git a/pkg/analyzer/lib/src/generated/element_handle.dart b/pkg/analyzer/lib/src/generated/element_handle.dart
index 35af627..338a279 100644
--- a/pkg/analyzer/lib/src/generated/element_handle.dart
+++ b/pkg/analyzer/lib/src/generated/element_handle.dart
@@ -337,6 +337,9 @@
   String get displayName => actualElement.displayName;
 
   @override
+  SourceRange get docRange => actualElement.docRange;
+
+  @override
   Element get enclosingElement => actualElement.enclosingElement;
 
   @override
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index a57cc05..9560bff 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -1641,31 +1641,13 @@
     if (source == null) {
       return null;
     }
-    CompilationUnit unit = parseCompilationUnit(source);
-    if (unit == null) {
+    SourceRange docRange = element.docRange;
+    if (docRange == null) {
       return null;
     }
-    NodeLocator locator = new NodeLocator(element.nameOffset);
-    AstNode nameNode = locator.searchWithin(unit);
-    while (nameNode != null) {
-      if (nameNode is AnnotatedNode) {
-        Comment comment = nameNode.documentationComment;
-        if (comment == null) {
-          return null;
-        }
-        StringBuffer buffer = new StringBuffer();
-        List<Token> tokens = comment.tokens;
-        for (int i = 0; i < tokens.length; i++) {
-          if (i > 0) {
-            buffer.write("\n");
-          }
-          buffer.write(tokens[i].lexeme);
-        }
-        return buffer.toString();
-      }
-      nameNode = nameNode.parent;
-    }
-    return null;
+    String code = getContents(source).data;
+    String comment = code.substring(docRange.offset, docRange.end);
+    return comment.replaceAll('\r\n', '\n');
   }
 
   @override
@@ -4886,8 +4868,7 @@
           null,
           null,
           oldUnit,
-          analysisOptions.incrementalApi,
-          analysisOptions);
+          analysisOptions.incrementalApi);
       bool success = resolver.resolve(newCode);
       AnalysisEngine.instance.instrumentationService.logPerformance(
           AnalysisPerformanceKind.INCREMENTAL,
@@ -8792,8 +8773,10 @@
       AnalysisEngine.instance.instrumentationService
           .logFileRead(source.fullName, _modificationTime, _content);
     } catch (exception, stackTrace) {
-      errors.add(new AnalysisError(
-          source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [exception]));
+      if (source.exists()) {
+        errors.add(new AnalysisError(
+            source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [exception]));
+      }
       throw new AnalysisException("Could not get contents of $source",
           new CaughtException(exception, stackTrace));
     }
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 832bb00..7c8516e 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -943,7 +943,6 @@
 
   @override
   Object visitPropertyAccess(PropertyAccess node) {
-    bool isConditional = node.operator.type == sc.TokenType.QUESTION_PERIOD;
     ClassElement typeReference =
         ElementResolver.getTypeReference(node.realTarget);
     SimpleIdentifier propertyName = node.propertyName;
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 46cd677..15bbec9 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -493,6 +493,24 @@
       _assertCompatibleParameter(node.parameter, element);
     } else if (node is FieldFormalParameter) {
       _assertTrue(element.isInitializingFormal);
+      DartType parameterType = element.type;
+      if (node.type == null && node.parameters == null) {
+        FieldFormalParameterElement parameterElement = element;
+        if (!parameterElement.hasImplicitType) {
+          _assertTrue(parameterType == null || parameterType.isDynamic);
+        }
+        if (parameterElement.field != null) {
+          _assertEquals(node.identifier.name, element.name);
+        }
+      } else {
+        if (node.parameters != null) {
+          _assertTrue(parameterType is FunctionType);
+          FunctionType parameterFunctionType = parameterType;
+          _assertSameType(node.type, parameterFunctionType.returnType);
+        } else {
+          _assertSameType(node.type, parameterType);
+        }
+      }
       _assertCompatibleParameters(node.parameters, element.parameters);
     } else if (node is FunctionTypedFormalParameter) {
       _assertFalse(element.isInitializingFormal);
@@ -1044,8 +1062,6 @@
       _context.invalidateLibraryHints(_librarySource);
       // update entry errors
       _updateEntry();
-      // notify unit
-      _definingUnit.afterIncrementalResolution();
       // OK
       return true;
     } finally {
@@ -1223,6 +1239,7 @@
 
   void _shiftEntryErrors_NEW() {
     _shiftErrors_NEW(HINTS);
+    _shiftErrors_NEW(LINTS);
     _shiftErrors_NEW(INFER_STATIC_VARIABLE_TYPES_ERRORS);
     _shiftErrors_NEW(LIBRARY_UNIT_ERRORS);
     _shiftErrors_NEW(PARTIALLY_RESOLVE_REFERENCES_ERRORS);
@@ -1279,6 +1296,7 @@
     try {
       _definingUnit
           .accept(new _ElementNameOffsetUpdater(_updateOffset, _updateDelta));
+      _definingUnit.afterIncrementalResolution();
     } finally {
       timer.stop('update element offsets');
     }
@@ -1303,6 +1321,7 @@
     newUnitEntry.setState(USED_IMPORTED_ELEMENTS, CacheState.INVALID);
     newUnitEntry.setState(USED_LOCAL_ELEMENTS, CacheState.INVALID);
     newUnitEntry.setState(HINTS, CacheState.INVALID);
+    newUnitEntry.setState(LINTS, CacheState.INVALID);
   }
 
   void _updateEntry_OLD() {
@@ -1392,7 +1411,6 @@
   CacheEntry _newUnitEntry;
 
   final CompilationUnit _oldUnit;
-  final AnalysisOptions _options;
   CompilationUnitElement _unitElement;
 
   int _updateOffset;
@@ -1411,8 +1429,7 @@
       this._newSourceEntry,
       this._newUnitEntry,
       this._oldUnit,
-      bool resolveApiChanges,
-      this._options) {
+      bool resolveApiChanges) {
     _resolveApiChanges = resolveApiChanges;
   }
 
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 0a197f5..908c297 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -44,6 +44,10 @@
 
 typedef void VoidFunction();
 
+typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited);
+
+typedef bool _SubtypeChecker<T>(T t1, T t2);
+
 /**
  * Instances of the class `BestPracticesVerifier` traverse an AST structure looking for
  * violations of Dart best practices.
@@ -2511,6 +2515,7 @@
       //
       constructors = _createDefaultConstructors(interfaceType);
     }
+    _setDocRange(element, node);
     element.abstract = node.isAbstract;
     element.accessors = holder.accessors;
     element.constructors = constructors;
@@ -2584,6 +2589,7 @@
     SimpleIdentifier constructorName = node.name;
     ConstructorElementImpl element =
         new ConstructorElementImpl.forNode(constructorName);
+    _setDocRange(element, node);
     if (node.externalKeyword != null) {
       element.external = true;
     }
@@ -2688,6 +2694,7 @@
     SimpleIdentifier enumName = node.name;
     ClassElementImpl enumElement = new ClassElementImpl.forNode(enumName);
     enumElement.enum2 = true;
+    _setDocRange(enumElement, node);
     InterfaceTypeImpl enumType = new InterfaceTypeImpl(enumElement);
     enumElement.type = enumType;
     // The equivalent code for enums in the spec shows a single constructor,
@@ -2760,6 +2767,7 @@
         SimpleIdentifier functionName = node.name;
         FunctionElementImpl element =
             new FunctionElementImpl.forNode(functionName);
+        _setDocRange(element, node);
         if (node.externalKeyword != null) {
           element.external = true;
         }
@@ -2806,6 +2814,7 @@
         if (node.isGetter) {
           PropertyAccessorElementImpl getter =
               new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          _setDocRange(getter, node);
           if (node.externalKeyword != null) {
             getter.external = true;
           }
@@ -2831,6 +2840,7 @@
         } else {
           PropertyAccessorElementImpl setter =
               new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          _setDocRange(setter, node);
           if (node.externalKeyword != null) {
             setter.external = true;
           }
@@ -2917,6 +2927,7 @@
     List<TypeParameterElement> typeParameters = holder.typeParameters;
     FunctionTypeAliasElementImpl element =
         new FunctionTypeAliasElementImpl.forNode(aliasName);
+    _setDocRange(element, node);
     element.parameters = parameters;
     element.typeParameters = typeParameters;
     FunctionTypeImpl type = new FunctionTypeImpl.forTypedef(element);
@@ -2988,6 +2999,7 @@
         }
         MethodElementImpl element =
             new MethodElementImpl(nameOfMethod, methodName.offset);
+        _setDocRange(element, node);
         element.abstract = node.isAbstract;
         if (node.externalKeyword != null) {
           element.external = true;
@@ -3024,6 +3036,7 @@
         if (node.isGetter) {
           PropertyAccessorElementImpl getter =
               new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          _setDocRange(getter, node);
           if (node.externalKeyword != null) {
             getter.external = true;
           }
@@ -3049,6 +3062,7 @@
         } else {
           PropertyAccessorElementImpl setter =
               new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          _setDocRange(setter, node);
           if (node.externalKeyword != null) {
             setter.external = true;
           }
@@ -3185,6 +3199,9 @@
         field = new FieldElementImpl.forNode(fieldName);
       }
       element = field;
+      if (node.parent.parent is FieldDeclaration) {
+        _setDocRange(element, node.parent.parent);
+      }
       if ((node.parent as VariableDeclarationList).type == null) {
         field.hasImplicitType = true;
       }
@@ -3350,6 +3367,17 @@
   }
 
   /**
+   * If the given [node] has a documentation comment, remember its range
+   * into the given [element].
+   */
+  void _setDocRange(ElementImpl element, AnnotatedNode node) {
+    Comment comment = node.documentationComment;
+    if (comment != null && comment.isDocumentation) {
+      element.setDocRange(comment.offset, comment.length);
+    }
+  }
+
+  /**
    * Sets the visible source range for formal parameter.
    */
   void _setParameterVisibleRange(
@@ -7060,6 +7088,7 @@
         .buildCompilationUnit(
             librarySource, definingCompilationUnit, librarySource);
     NodeList<Directive> directives = definingCompilationUnit.directives;
+    LibraryDirective libraryDirective = null;
     LibraryIdentifier libraryNameNode = null;
     bool hasPartDirective = false;
     FunctionElement entryPoint =
@@ -7077,6 +7106,7 @@
       //
       if (directive is LibraryDirective) {
         if (libraryNameNode == null) {
+          libraryDirective = directive;
           libraryNameNode = directive.name;
           directivesToResolve.add(directive);
         }
@@ -7135,6 +7165,7 @@
     //
     LibraryElementImpl libraryElement = new LibraryElementImpl.forNode(
         _analysisContext.getContextFor(librarySource), libraryNameNode);
+    _setDocRange(libraryElement, libraryDirective);
     libraryElement.definingCompilationUnit = definingCompilationUnitElement;
     if (entryPoint != null) {
       libraryElement.entryPoint = entryPoint;
@@ -7166,6 +7197,7 @@
         .buildCompilationUnit(
             librarySource, definingCompilationUnit, librarySource);
     NodeList<Directive> directives = definingCompilationUnit.directives;
+    LibraryDirective libraryDirective = null;
     LibraryIdentifier libraryNameNode = null;
     bool hasPartDirective = false;
     FunctionElement entryPoint =
@@ -7183,6 +7215,7 @@
       //
       if (directive is LibraryDirective) {
         if (libraryNameNode == null) {
+          libraryDirective = directive;
           libraryNameNode = directive.name;
           directivesToResolve.add(directive);
         }
@@ -7243,6 +7276,7 @@
     //
     LibraryElementImpl libraryElement = new LibraryElementImpl.forNode(
         _analysisContext.getContextFor(librarySource), libraryNameNode);
+    _setDocRange(libraryElement, libraryDirective);
     libraryElement.definingCompilationUnit = definingCompilationUnitElement;
     if (entryPoint != null) {
       libraryElement.entryPoint = entryPoint;
@@ -7346,6 +7380,19 @@
       }
     }
   }
+
+  /**
+   * If the given [node] has a documentation comment, remember its range
+   * into the given [element].
+   */
+  void _setDocRange(ElementImpl element, LibraryDirective node) {
+    if (node != null) {
+      Comment comment = node.documentationComment;
+      if (comment != null && comment.isDocumentation) {
+        element.setDocRange(comment.offset, comment.length);
+      }
+    }
+  }
 }
 
 /**
@@ -8928,46 +8975,6 @@
 }
 
 /**
- * Instances of the class `TypeAliasInfo` hold information about a [TypeAlias].
- */
-class LibraryResolver2_TypeAliasInfo {
-  final ResolvableLibrary _library;
-
-  final Source _source;
-
-  final FunctionTypeAlias _typeAlias;
-
-  /**
-   * Initialize a newly created information holder with the given information.
-   *
-   * @param library the library containing the type alias
-   * @param source the source of the file containing the type alias
-   * @param typeAlias the type alias being remembered
-   */
-  LibraryResolver2_TypeAliasInfo(this._library, this._source, this._typeAlias);
-}
-
-/**
- * Instances of the class `TypeAliasInfo` hold information about a [TypeAlias].
- */
-class LibraryResolver_TypeAliasInfo {
-  final Library _library;
-
-  final Source _source;
-
-  final FunctionTypeAlias _typeAlias;
-
-  /**
-   * Initialize a newly created information holder with the given information.
-   *
-   * @param library the library containing the type alias
-   * @param source the source of the file containing the type alias
-   * @param typeAlias the type alias being remembered
-   */
-  LibraryResolver_TypeAliasInfo(this._library, this._source, this._typeAlias);
-}
-
-/**
  * Instances of the class `LibraryScope` implement a scope containing all of the names defined
  * in a given library.
  */
@@ -9261,8 +9268,7 @@
    *
    * @return a table containing the same mappings as those defined by this namespace
    */
-  Map<String, Element> get definedNames =>
-      new HashMap<String, Element>.from(_definedNames);
+  Map<String, Element> get definedNames => _definedNames;
 
   /**
    * Return the element in this namespace that is available to the containing scope using the given
@@ -9412,7 +9418,7 @@
       List<NamespaceCombinator> combinators) {
     for (NamespaceCombinator combinator in combinators) {
       if (combinator is HideElementCombinator) {
-        _hide(definedNames, combinator.hiddenNames);
+        definedNames = _hide(definedNames, combinator.hiddenNames);
       } else if (combinator is ShowElementCombinator) {
         definedNames = _show(definedNames, combinator.shownNames);
       } else {
@@ -9491,24 +9497,22 @@
   }
 
   /**
-   * Hide all of the given names by removing them from the given collection of defined names.
-   *
-   * @param definedNames the names that were defined before this operation
-   * @param hiddenNames the names to be hidden
+   * Return a new map of names which has all the names from [definedNames]
+   * with exception of [hiddenNames].
    */
-  void _hide(HashMap<String, Element> definedNames, List<String> hiddenNames) {
+  Map<String, Element> _hide(
+      HashMap<String, Element> definedNames, List<String> hiddenNames) {
+    HashMap<String, Element> newNames =
+        new HashMap<String, Element>.from(definedNames);
     for (String name in hiddenNames) {
-      definedNames.remove(name);
-      definedNames.remove("$name=");
+      newNames.remove(name);
+      newNames.remove("$name=");
     }
+    return newNames;
   }
 
   /**
-   * Show only the given names by removing all other names from the given collection of defined
-   * names.
-   *
-   * @param definedNames the names that were defined before this operation
-   * @param shownNames the names to be shown
+   * Return a new map of names which has only [shownNames] from [definedNames].
    */
   HashMap<String, Element> _show(
       HashMap<String, Element> definedNames, List<String> shownNames) {
@@ -10544,6 +10548,14 @@
    */
   DartType overrideVariable(VariableElement element, DartType potentialType,
       bool allowPrecisionLoss) {
+    // TODO(scheglov) type propagation for instance/top-level fields
+    // was disabled because it depends on the order or visiting.
+    // If both field and its client are in the same unit, and we visit
+    // the client before the field, then propagated type is not set yet.
+    if (element is PropertyInducingElement) {
+      return null;
+    }
+
     if (potentialType == null || potentialType.isBottom) {
       return null;
     }
@@ -10576,18 +10588,6 @@
         allowPrecisionLoss ||
         !currentType.isMoreSpecificThan(potentialType) ||
         potentialType.isMoreSpecificThan(currentType)) {
-      // TODO(scheglov) type propagation for instance/top-level fields
-      // was disabled because it depends on the order or visiting.
-      // If both field and its client are in the same unit, and we visit
-      // the client before the field, then propagated type is not set yet.
-//      if (element is PropertyInducingElement) {
-//        PropertyInducingElement variable = element;
-//        if (!variable.isConst && !variable.isFinal) {
-//          return;
-//        }
-//        (variable as PropertyInducingElementImpl).propagatedType =
-//            potentialType;
-//      }
       _overrideManager.setType(element, potentialType);
       return potentialType;
     }
@@ -12723,6 +12723,310 @@
 }
 
 /**
+ * Implementation of [TypeSystem] using the strong mode rules.
+ * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md
+ */
+class StrongTypeSystemImpl implements TypeSystem {
+  final _specTypeSystem = new TypeSystemImpl();
+
+  StrongTypeSystemImpl();
+
+  @override
+  DartType getLeastUpperBound(
+      TypeProvider typeProvider, DartType type1, DartType type2) {
+    // TODO(leafp): Implement a strong mode version of this.
+    return _specTypeSystem.getLeastUpperBound(typeProvider, type1, type2);
+  }
+
+  // TODO(leafp): Document the rules in play here
+  @override
+  bool isAssignableTo(DartType fromType, DartType toType) {
+    // An actual subtype
+    if (isSubtypeOf(fromType, toType)) {
+      return true;
+    }
+
+    // Don't allow implicit downcasts between function types
+    // and call method objects, as these will almost always fail.
+    if ((fromType is FunctionType && _getCallMethodType(toType) != null) ||
+        (toType is FunctionType && _getCallMethodType(fromType) != null)) {
+      return false;
+    }
+
+    // If the subtype relation goes the other way, allow the implicit downcast.
+    // TODO(leafp): Emit warnings and hints for these in some way.
+    // TODO(leafp): Consider adding a flag to disable these?  Or just rely on
+    //   --warnings-as-errors?
+    if (isSubtypeOf(toType, fromType) ||
+        _specTypeSystem.isAssignableTo(toType, fromType)) {
+      // TODO(leafp): error if type is known to be exact (literal,
+      //  instance creation).
+      // TODO(leafp): Warn on composite downcast.
+      // TODO(leafp): hint on object/dynamic downcast.
+      // TODO(leafp): Consider allowing assignment casts.
+      return true;
+    }
+
+    return false;
+  }
+
+  @override
+  bool isSubtypeOf(DartType leftType, DartType rightType) {
+    return _isSubtypeOf(leftType, rightType, null);
+  }
+
+  FunctionType _getCallMethodType(DartType t) {
+    if (t is InterfaceType) {
+      ClassElement element = t.element;
+      InheritanceManager manager = new InheritanceManager(element.library);
+      FunctionType callType = manager.lookupMemberType(t, "call");
+      return callType;
+    }
+    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) {
+      Element element = t1.element;
+      if (visited == null) {
+        visited = new HashSet<Element>();
+      }
+      if (element == null || !visited.add(element)) {
+        return false;
+      }
+      try {
+        return check(t1, t2, visited);
+      } finally {
+        visited.remove(element);
+      }
+    };
+  }
+
+  bool _isBottom(DartType t, {bool dynamicIsBottom: false}) {
+    return (t.isDynamic && dynamicIsBottom) || t.isBottom;
+  }
+
+  // Guard against loops in the class hierarchy
+  /**
+   * Check that [f1] is a subtype of [f2].
+   * [fuzzyArrows] indicates whether or not the f1 and f2 should be
+   * treated as fuzzy arrow types (and hence dynamic parameters to f2 treated
+   * as bottom).
+   */
+  bool _isFunctionSubtypeOf(FunctionType f1, FunctionType f2,
+      {bool fuzzyArrows: true}) {
+    final r1s = f1.normalParameterTypes;
+    final o1s = f1.optionalParameterTypes;
+    final n1s = f1.namedParameterTypes;
+    final r2s = f2.normalParameterTypes;
+    final o2s = f2.optionalParameterTypes;
+    final n2s = f2.namedParameterTypes;
+    final ret1 = f1.returnType;
+    final ret2 = f2.returnType;
+
+    // A -> B <: C -> D if C <: A and
+    // either D is void or B <: D
+    if (!ret2.isVoid && !isSubtypeOf(ret1, ret2)) {
+      return false;
+    }
+
+    // Reject if one has named and the other has optional
+    if (n1s.length > 0 && o2s.length > 0) {
+      return false;
+    }
+    if (n2s.length > 0 && o1s.length > 0) {
+      return false;
+    }
+
+    // Rebind _isSubtypeOf for convenience
+    _SubtypeChecker<DartType> parameterSubtype = (DartType t1, DartType t2) =>
+        _isSubtypeOf(t1, t2, null, dynamicIsBottom: fuzzyArrows);
+
+    // f2 has named parameters
+    if (n2s.length > 0) {
+      // Check that every named parameter in f2 has a match in f1
+      for (String k2 in n2s.keys) {
+        if (!n1s.containsKey(k2)) {
+          return false;
+        }
+        if (!parameterSubtype(n2s[k2], n1s[k2])) {
+          return false;
+        }
+      }
+    }
+    // If we get here, we either have no named parameters,
+    // or else the named parameters match and we have no optional
+    // parameters
+
+    // If f1 has more required parameters, reject
+    if (r1s.length > r2s.length) {
+      return false;
+    }
+
+    // If f2 has more required + optional parameters, reject
+    if (r2s.length + o2s.length > r1s.length + o1s.length) {
+      return false;
+    }
+
+    // The parameter lists must look like the following at this point
+    // where rrr is a region of required, and ooo is a region of optionals.
+    // f1: rrr ooo ooo ooo
+    // f2: rrr rrr ooo
+    int rr = r1s.length; // required in both
+    int or = r2s.length - r1s.length; // optional in f1, required in f2
+    int oo = o2s.length; // optional in both
+
+    for (int i = 0; i < rr; ++i) {
+      if (!parameterSubtype(r2s[i], r1s[i])) {
+        return false;
+      }
+    }
+    for (int i = 0, j = rr; i < or; ++i, ++j) {
+      if (!parameterSubtype(r2s[j], o1s[i])) {
+        return false;
+      }
+    }
+    for (int i = or, j = 0; i < oo; ++i, ++j) {
+      if (!parameterSubtype(o2s[j], o1s[i])) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  bool _isInterfaceSubtypeOf(
+      InterfaceType i1, InterfaceType i2, Set<Element> visited) {
+    // Guard recursive calls
+    _GuardedSubtypeChecker<InterfaceType> guardedInterfaceSubtype =
+        _guard(_isInterfaceSubtypeOf);
+
+    if (i1 == i2) {
+      return true;
+    }
+
+    if (i1.element == i2.element) {
+      List<DartType> tArgs1 = i1.typeArguments;
+      List<DartType> tArgs2 = i2.typeArguments;
+
+      assert(tArgs1.length == tArgs2.length);
+
+      for (int i = 0; i < tArgs1.length; i++) {
+        DartType t1 = tArgs1[i];
+        DartType t2 = tArgs2[i];
+        if (!isSubtypeOf(t1, t2)) {
+          return false;
+        }
+      }
+      return true;
+    }
+
+    if (i2.isDartCoreFunction && i1.element.getMethod("call") != null) {
+      return true;
+    }
+
+    if (i1.isObject) {
+      return false;
+    }
+
+    if (guardedInterfaceSubtype(i1.superclass, i2, visited)) {
+      return true;
+    }
+
+    for (final parent in i1.interfaces) {
+      if (guardedInterfaceSubtype(parent, i2, visited)) {
+        return true;
+      }
+    }
+
+    for (final parent in i1.mixins) {
+      if (guardedInterfaceSubtype(parent, i2, visited)) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited,
+      {bool dynamicIsBottom: false}) {
+    // Guard recursive calls
+    _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf);
+
+    if (t1 == t2) {
+      return true;
+    }
+
+    // The types are void, dynamic, bottom, interface types, function types
+    // and type parameters.  We proceed by eliminating these different classes
+    // from consideration.
+
+    // Trivially true.
+    if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) ||
+        _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) {
+      return true;
+    }
+
+    // Trivially false.
+    if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) ||
+        _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) {
+      return false;
+    }
+
+    // S <: T where S is a type variable
+    //  T is not dynamic or object (handled above)
+    //  S != T (handled above)
+    //  So only true if bound of S is S' and
+    //  S' <: T
+    if (t1 is TypeParameterType) {
+      DartType bound = t1.element.bound;
+      if (bound == null) return false;
+      return guardedSubtype(bound, t2, visited);
+    }
+
+    if (t2 is TypeParameterType) {
+      return false;
+    }
+
+    if (t1.isVoid || t2.isVoid) {
+      return false;
+    }
+
+    // We've eliminated void, dynamic, bottom, and type parameters.  The only
+    // cases are the combinations of interface type and function type.
+
+    // A function type can only subtype an interface type if
+    // the interface type is Function
+    if (t1 is FunctionType && t2 is InterfaceType) {
+      return t2.isDartCoreFunction;
+    }
+
+    // An interface type can only subtype a function type if
+    // the interface type declares a call method with a type
+    // which is a super type of the function type.
+    if (t1 is InterfaceType && t2 is FunctionType) {
+      var callType = _getCallMethodType(t1);
+      return (callType != null) && _isFunctionSubtypeOf(callType, t2);
+    }
+
+    // Two interface types
+    if (t1 is InterfaceType && t2 is InterfaceType) {
+      return _isInterfaceSubtypeOf(t1, t2, visited);
+    }
+
+    return _isFunctionSubtypeOf(t1 as FunctionType, t2 as FunctionType);
+  }
+
+  // TODO(leafp): Document the rules in play here
+  bool _isTop(DartType t, {bool dynamicIsBottom: false}) {
+    return (t.isDynamic && !dynamicIsBottom) || t.isObject;
+  }
+}
+
+/**
  * Instances of this class manage the knowledge of what the set of subtypes are for a given type.
  */
 class SubtypeManager {
@@ -14956,15 +15260,6 @@
  */
 abstract class TypeSystem {
   /**
-   * Create either a strong mode or regular type system based on context.
-   */
-  static TypeSystem create(AnalysisContext context) {
-    return (context.analysisOptions.strongMode)
-        ? new StrongTypeSystemImpl()
-        : new TypeSystemImpl();
-  }
-
-  /**
    * Compute the least upper bound of two types.
    */
   DartType getLeastUpperBound(
@@ -14981,6 +15276,15 @@
    * if leftType <: rightType).
    */
   bool isSubtypeOf(DartType leftType, DartType rightType);
+
+  /**
+   * Create either a strong mode or regular type system based on context.
+   */
+  static TypeSystem create(AnalysisContext context) {
+    return (context.analysisOptions.strongMode)
+        ? new StrongTypeSystemImpl()
+        : new TypeSystemImpl();
+  }
 }
 
 /**
@@ -15080,313 +15384,6 @@
   }
 }
 
-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
- */
-class StrongTypeSystemImpl implements TypeSystem {
-  StrongTypeSystemImpl();
-
-  final _specTypeSystem = new TypeSystemImpl();
-
-  @override
-  DartType getLeastUpperBound(
-      TypeProvider typeProvider, DartType type1, DartType type2) {
-    // TODO(leafp): Implement a strong mode version of this.
-    return _specTypeSystem.getLeastUpperBound(typeProvider, type1, type2);
-  }
-
-  // TODO(leafp): Document the rules in play here
-  @override
-  bool isAssignableTo(DartType toType, DartType fromType) {
-    // An actual subtype
-    if (isSubtypeOf(fromType, toType)) {
-      return true;
-    }
-
-    // Don't allow implicit downcasts between function types
-    // and call method objects, as these will almost always fail.
-    if ((fromType is FunctionType && _getCallMethodType(toType) != null) ||
-        (toType is FunctionType && _getCallMethodType(fromType) != null)) {
-      return false;
-    }
-
-    // If the subtype relation goes the other way, allow the implicit downcast.
-    // TODO(leafp): Emit warnings and hints for these in some way.
-    // TODO(leafp): Consider adding a flag to disable these?  Or just rely on
-    //   --warnings-as-errors?
-    if (isSubtypeOf(toType, fromType) ||
-        _specTypeSystem.isAssignableTo(toType, fromType)) {
-      // TODO(leafp): error if type is known to be exact (literal,
-      //  instance creation).
-      // TODO(leafp): Warn on composite downcast.
-      // TODO(leafp): hint on object/dynamic downcast.
-      // TODO(leafp): Consider allowing assignment casts.
-      return true;
-    }
-
-    return false;
-  }
-
-  bool _isBottom(DartType t, {bool dynamicIsBottom: false}) {
-    return (t.isDynamic && dynamicIsBottom) || t.isBottom;
-  }
-
-  bool _isTop(DartType t, {bool dynamicIsBottom: false}) {
-    return (t.isDynamic && !dynamicIsBottom) || t.isObject;
-  }
-
-  // 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) {
-      ClassElement element = t.element;
-      InheritanceManager manager = new InheritanceManager(element.library);
-      FunctionType callType = manager.lookupMemberType(t, "call");
-      return callType;
-    }
-    return null;
-  }
-
-  /**
-   * Check that [f1] is a subtype of [f2].
-   * [fuzzyArrows] indicates whether or not the f1 and f2 should be
-   * treated as fuzzy arrow types (and hence dynamic parameters to f2 treated
-   * as bottom).
-   */
-  bool _isFunctionSubtypeOf(FunctionType f1, FunctionType f2,
-      {bool fuzzyArrows: true}) {
-    final r1s = f1.normalParameterTypes;
-    final o1s = f1.optionalParameterTypes;
-    final n1s = f1.namedParameterTypes;
-    final r2s = f2.normalParameterTypes;
-    final o2s = f2.optionalParameterTypes;
-    final n2s = f2.namedParameterTypes;
-    final ret1 = f1.returnType;
-    final ret2 = f2.returnType;
-
-    // A -> B <: C -> D if C <: A and
-    // either D is void or B <: D
-    if (!ret2.isVoid && !isSubtypeOf(ret1, ret2)) {
-      return false;
-    }
-
-    // Reject if one has named and the other has optional
-    if (n1s.length > 0 && o2s.length > 0) {
-      return false;
-    }
-    if (n2s.length > 0 && o1s.length > 0) {
-      return false;
-    }
-
-    // Rebind _isSubtypeOf for convenience
-    _SubtypeChecker<DartType> parameterSubtype = (DartType t1, DartType t2) =>
-        _isSubtypeOf(t1, t2, null, dynamicIsBottom: fuzzyArrows);
-
-    // f2 has named parameters
-    if (n2s.length > 0) {
-      // Check that every named parameter in f2 has a match in f1
-      for (String k2 in n2s.keys) {
-        if (!n1s.containsKey(k2)) {
-          return false;
-        }
-        if (!parameterSubtype(n2s[k2], n1s[k2])) {
-          return false;
-        }
-      }
-    }
-    // If we get here, we either have no named parameters,
-    // or else the named parameters match and we have no optional
-    // parameters
-
-    // If f1 has more required parameters, reject
-    if (r1s.length > r2s.length) {
-      return false;
-    }
-
-    // If f2 has more required + optional parameters, reject
-    if (r2s.length + o2s.length > r1s.length + o1s.length) {
-      return false;
-    }
-
-    // The parameter lists must look like the following at this point
-    // where rrr is a region of required, and ooo is a region of optionals.
-    // f1: rrr ooo ooo ooo
-    // f2: rrr rrr ooo
-    int rr = r1s.length; // required in both
-    int or = r2s.length - r1s.length; // optional in f1, required in f2
-    int oo = o2s.length; // optional in both
-
-    for (int i = 0; i < rr; ++i) {
-      if (!parameterSubtype(r2s[i], r1s[i])) {
-        return false;
-      }
-    }
-    for (int i = 0, j = rr; i < or; ++i, ++j) {
-      if (!parameterSubtype(r2s[j], o1s[i])) {
-        return false;
-      }
-    }
-    for (int i = or, j = 0; i < oo; ++i, ++j) {
-      if (!parameterSubtype(o2s[j], o1s[i])) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  // Guard against loops in the class hierarchy
-  _GuardedSubtypeChecker<DartType> _guard(
-      _GuardedSubtypeChecker<DartType> check) {
-    return (DartType t1, DartType t2, Set<Element> visited) {
-      Element element = t1.element;
-      if (visited == null) {
-        visited = new HashSet<Element>();
-      }
-      if (element == null || !visited.add(element)) {
-        return false;
-      }
-      try {
-        return check(t1, t2, visited);
-      } finally {
-        visited.remove(element);
-      }
-    };
-  }
-
-  bool _isInterfaceSubtypeOf(
-      InterfaceType i1, InterfaceType i2, Set<Element> visited) {
-    // Guard recursive calls
-    _GuardedSubtypeChecker<InterfaceType> guardedInterfaceSubtype =
-        _guard(_isInterfaceSubtypeOf);
-
-    if (i1 == i2) {
-      return true;
-    }
-
-    if (i1.element == i2.element) {
-      List<DartType> tArgs1 = i1.typeArguments;
-      List<DartType> tArgs2 = i2.typeArguments;
-
-      assert(tArgs1.length == tArgs2.length);
-
-      for (int i = 0; i < tArgs1.length; i++) {
-        DartType t1 = tArgs1[i];
-        DartType t2 = tArgs2[i];
-        if (!isSubtypeOf(t1, t2)) {
-          return false;
-        }
-      }
-      return true;
-    }
-
-    if (i2.isDartCoreFunction && i1.element.getMethod("call") != null) {
-      return true;
-    }
-
-    if (i1.isObject) {
-      return false;
-    }
-
-    if (guardedInterfaceSubtype(i1.superclass, i2, visited)) {
-      return true;
-    }
-
-    for (final parent in i1.interfaces) {
-      if (guardedInterfaceSubtype(parent, i2, visited)) {
-        return true;
-      }
-    }
-
-    for (final parent in i1.mixins) {
-      if (guardedInterfaceSubtype(parent, i2, visited)) {
-        return true;
-      }
-    }
-
-    return false;
-  }
-
-  bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited,
-      {bool dynamicIsBottom: false}) {
-    // Guard recursive calls
-    _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf);
-
-    if (t1 == t2) {
-      return true;
-    }
-
-    // The types are void, dynamic, bottom, interface types, function types
-    // and type parameters.  We proceed by eliminating these different classes
-    // from consideration.
-
-    // Trivially true.
-    if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) ||
-        _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) {
-      return true;
-    }
-
-    // Trivially false.
-    if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) ||
-        _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) {
-      return false;
-    }
-
-    // S <: T where S is a type variable
-    //  T is not dynamic or object (handled above)
-    //  S != T (handled above)
-    //  So only true if bound of S is S' and
-    //  S' <: T
-    if (t1 is TypeParameterType) {
-      DartType bound = t1.element.bound;
-      if (bound == null) return false;
-      return guardedSubtype(bound, t2, visited);
-    }
-
-    if (t2 is TypeParameterType) {
-      return false;
-    }
-
-    if (t1.isVoid || t2.isVoid) {
-      return false;
-    }
-
-    // We've eliminated void, dynamic, bottom, and type parameters.  The only
-    // cases are the combinations of interface type and function type.
-
-    // A function type can only subtype an interface type if
-    // the interface type is Function
-    if (t1 is FunctionType && t2 is InterfaceType) {
-      return t2.isDartCoreFunction;
-    }
-
-    // An interface type can only subtype a function type if
-    // the interface type declares a call method with a type
-    // which is a super type of the function type.
-    if (t1 is InterfaceType && t2 is FunctionType) {
-      var callType = _getCallMethodType(t1);
-      return (callType != null) && _isFunctionSubtypeOf(callType, t2);
-    }
-
-    // Two interface types
-    if (t1 is InterfaceType && t2 is InterfaceType) {
-      return _isInterfaceSubtypeOf(t1, t2, visited);
-    }
-
-    return _isFunctionSubtypeOf(t1 as FunctionType, t2 as FunctionType);
-  }
-
-  // TODO(leafp): Document the rules in play here
-  @override
-  bool isSubtypeOf(DartType leftType, DartType rightType) {
-    return _isSubtypeOf(leftType, rightType, null);
-  }
-}
-
 /**
  * Instances of the class [UnusedLocalElementsVerifier] traverse an element
  * structure looking for cases of [HintCode.UNUSED_ELEMENT],
diff --git a/pkg/analyzer/lib/src/generated/testing/ast_factory.dart b/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
index 86f1e04..bb758b3 100644
--- a/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
@@ -377,6 +377,11 @@
           TypeName type, String identifier) =>
       declaredIdentifier2(null, type, identifier);
 
+  static Comment documentationComment(
+      List<Token> tokens, List<CommentReference> references) {
+    return new Comment(tokens, CommentType.DOCUMENTATION, references);
+  }
+
   static DoStatement doStatement(Statement body, Expression condition) =>
       new DoStatement(
           TokenFactory.tokenFromKeyword(Keyword.DO),
diff --git a/pkg/analyzer/lib/src/plugin/engine_plugin.dart b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
index 75debaa..f720367 100644
--- a/pkg/analyzer/lib/src/plugin/engine_plugin.dart
+++ b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
@@ -159,8 +159,6 @@
 
   void _registerDartErrorsForSource(RegisterExtension registerExtension) {
     String id = DART_ERRORS_FOR_SOURCE_EXTENSION_POINT_ID;
-    registerExtension(id, BUILD_DIRECTIVES_ERRORS);
-    registerExtension(id, BUILD_LIBRARY_ERRORS);
     registerExtension(id, PARSE_ERRORS);
     registerExtension(id, SCAN_ERRORS);
   }
@@ -203,6 +201,7 @@
     registerExtension(taskId, GatherUsedImportedElementsTask.DESCRIPTOR);
     registerExtension(taskId, GatherUsedLocalElementsTask.DESCRIPTOR);
     registerExtension(taskId, GenerateHintsTask.DESCRIPTOR);
+    registerExtension(taskId, GenerateLintsTask.DESCRIPTOR);
     registerExtension(taskId, InferInstanceMembersInUnitTask.DESCRIPTOR);
     registerExtension(taskId, InferStaticVariableTypesInUnitTask.DESCRIPTOR);
     registerExtension(taskId, InferStaticVariableTypeTask.DESCRIPTOR);
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index 8ce9084..2091fdc 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -21,7 +21,9 @@
 import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/visitors.dart';
 import 'package:analyzer/src/plugin/engine_plugin.dart';
+import 'package:analyzer/src/services/lint.dart';
 import 'package:analyzer/src/task/driver.dart';
 import 'package:analyzer/src/task/general.dart';
 import 'package:analyzer/src/task/html.dart';
@@ -291,6 +293,17 @@
         'LIBRARY_UNIT_ERRORS', AnalysisError.NO_ERRORS);
 
 /**
+ * The errors produced while generating lints for a compilation unit.
+ *
+ * The list will be empty if there were no errors, but will not be `null`.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<AnalysisError> LINTS =
+    new ListResultDescriptor<AnalysisError>(
+        'LINT_ERRORS', AnalysisError.NO_ERRORS);
+
+/**
  * The errors produced while parsing a compilation unit.
  *
  * The list will be empty if there were no errors, but will not be `null`.
@@ -537,7 +550,7 @@
     //
     // Build or reuse CompilationUnitElement.
     //
-    unit = AstCloner.clone(unit);
+//    unit = AstCloner.clone(unit);
     AnalysisCache analysisCache =
         (context as InternalAnalysisContext).analysisCache;
     CompilationUnitElement element =
@@ -573,7 +586,7 @@
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
     LibrarySpecificUnit unit = target;
     return <String, TaskInput>{
-      PARSED_UNIT_INPUT_NAME: PARSED_UNIT.of(unit.unit)
+      PARSED_UNIT_INPUT_NAME: PARSED_UNIT.of(unit.unit, flushOnAccess: true)
     };
   }
 
@@ -2419,6 +2432,92 @@
 }
 
 /**
+ * A task that generates [LINTS] for a unit.
+ */
+class GenerateLintsTask extends SourceBasedAnalysisTask {
+  /**
+   * The name of the [RESOLVED_UNIT8] input.
+   */
+  static const String RESOLVED_UNIT_INPUT = 'RESOLVED_UNIT';
+
+  /**
+   * The name of a list of [USED_LOCAL_ELEMENTS] for each library unit input.
+   */
+  static const String USED_LOCAL_ELEMENTS_INPUT = 'USED_LOCAL_ELEMENTS';
+
+  /**
+   * The name of a list of [USED_IMPORTED_ELEMENTS] for each library unit input.
+   */
+  static const String USED_IMPORTED_ELEMENTS_INPUT = 'USED_IMPORTED_ELEMENTS';
+
+  /**
+   * The name of the [TYPE_PROVIDER] input.
+   */
+  static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
+
+  /**
+   * The task descriptor describing this kind of task.
+   */
+  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+      'GenerateLintsTask', createTask, buildInputs, <ResultDescriptor>[LINTS]);
+
+  GenerateLintsTask(InternalAnalysisContext context, AnalysisTarget target)
+      : super(context, target);
+
+  @override
+  TaskDescriptor get descriptor => DESCRIPTOR;
+
+  @override
+  void internalPerform() {
+    AnalysisOptions analysisOptions = context.analysisOptions;
+    if (!analysisOptions.lint) {
+      outputs[LINTS] = AnalysisError.NO_ERRORS;
+      return;
+    }
+    //
+    // Prepare collectors.
+    //
+    RecordingErrorListener errorListener = new RecordingErrorListener();
+    Source source = getRequiredSource();
+    ErrorReporter errorReporter = new ErrorReporter(errorListener, source);
+    //
+    // Prepare inputs.
+    //
+    CompilationUnit unit = getRequiredInput(RESOLVED_UNIT_INPUT);
+
+    //
+    // Generate lints.
+    //
+    LintGenerator.LINTERS.forEach((l) => l.reporter = errorReporter);
+    Iterable<AstVisitor> visitors =
+        LintGenerator.LINTERS.map((l) => l.getVisitor()).toList();
+    unit.accept(new DelegatingAstVisitor(visitors.where((v) => v != null)));
+
+    //
+    // Record outputs.
+    //
+    outputs[LINTS] = errorListener.errors;
+  }
+
+  /**
+   * 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) =>
+      <String, TaskInput>{RESOLVED_UNIT_INPUT: RESOLVED_UNIT.of(target)};
+
+  /**
+   * Create a [GenerateLintsTask] based on the given [target] in
+   * the given [context].
+   */
+  static GenerateLintsTask createTask(
+      AnalysisContext context, AnalysisTarget target) {
+    return new GenerateLintsTask(context, target);
+  }
+}
+
+/**
  * A task that ensures that all of the inferrable instance members in a
  * compilation unit have had their type inferred.
  */
@@ -2804,11 +2903,26 @@
  */
 class LibraryUnitErrorsTask extends SourceBasedAnalysisTask {
   /**
+   * The name of the [BUILD_DIRECTIVES_ERRORS] input.
+   */
+  static const String BUILD_DIRECTIVES_ERRORS_INPUT = 'BUILD_DIRECTIVES_ERRORS';
+
+  /**
+   * The name of the [BUILD_LIBRARY_ERRORS] input.
+   */
+  static const String BUILD_LIBRARY_ERRORS_INPUT = 'BUILD_LIBRARY_ERRORS';
+
+  /**
    * The name of the [HINTS] input.
    */
   static const String HINTS_INPUT = 'HINTS';
 
   /**
+   * The name of the [LINTS] input.
+   */
+  static const String LINTS_INPUT = 'LINTS';
+
+  /**
    * The name of the [INFER_STATIC_VARIABLE_TYPES_ERRORS] input.
    */
   static const String INFER_STATIC_VARIABLE_TYPES_ERRORS_INPUT =
@@ -2864,7 +2978,10 @@
     // Prepare inputs.
     //
     List<List<AnalysisError>> errorLists = <List<AnalysisError>>[];
+    errorLists.add(getRequiredInput(BUILD_DIRECTIVES_ERRORS_INPUT));
+    errorLists.add(getRequiredInput(BUILD_LIBRARY_ERRORS_INPUT));
     errorLists.add(getRequiredInput(HINTS_INPUT));
+    errorLists.add(getRequiredInput(LINTS_INPUT));
     errorLists.add(getRequiredInput(INFER_STATIC_VARIABLE_TYPES_ERRORS_INPUT));
     errorLists.add(getRequiredInput(PARTIALLY_RESOLVE_REFERENCES_ERRORS_INPUT));
     errorLists.add(getRequiredInput(RESOLVE_FUNCTION_BODIES_ERRORS_INPUT));
@@ -2884,8 +3001,9 @@
    */
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
     LibrarySpecificUnit unit = target;
-    return <String, TaskInput>{
+    Map<String, TaskInput> inputs = <String, TaskInput>{
       HINTS_INPUT: HINTS.of(unit),
+      LINTS_INPUT: LINTS.of(unit),
       INFER_STATIC_VARIABLE_TYPES_ERRORS_INPUT:
           INFER_STATIC_VARIABLE_TYPES_ERRORS.of(unit),
       PARTIALLY_RESOLVE_REFERENCES_ERRORS_INPUT:
@@ -2896,6 +3014,18 @@
       VARIABLE_REFERENCE_ERRORS_INPUT: VARIABLE_REFERENCE_ERRORS.of(unit),
       VERIFY_ERRORS_INPUT: VERIFY_ERRORS.of(unit)
     };
+    Source source = unit.source;
+    if (unit.library == source) {
+      inputs[BUILD_DIRECTIVES_ERRORS_INPUT] =
+          BUILD_DIRECTIVES_ERRORS.of(source);
+      inputs[BUILD_LIBRARY_ERRORS_INPUT] = BUILD_LIBRARY_ERRORS.of(source);
+    } else {
+      inputs[BUILD_DIRECTIVES_ERRORS_INPUT] =
+          new ConstantTaskInput(AnalysisError.NO_ERRORS);
+      inputs[BUILD_LIBRARY_ERRORS_INPUT] =
+          new ConstantTaskInput(AnalysisError.NO_ERRORS);
+    }
+    return inputs;
   }
 
   /**
@@ -3730,7 +3860,7 @@
     LibrarySpecificUnit unit = target;
     return <String, TaskInput>{
       LIBRARY_INPUT: LIBRARY_ELEMENT1.of(unit.library),
-      UNIT_INPUT: RESOLVED_UNIT1.of(unit),
+      UNIT_INPUT: RESOLVED_UNIT3.of(unit),
       TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
     };
   }
@@ -3788,8 +3918,10 @@
           message = exception.toString();
         }
       }
-      errorListener.onError(new AnalysisError(
-          source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [message]));
+      if (source.exists()) {
+        errorListener.onError(new AnalysisError(
+            source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [message]));
+      }
     }
     if (target is DartScript) {
       DartScript script = target;
@@ -4087,6 +4219,9 @@
   }
 
   @override
+  bool get flushOnAccess => false;
+
+  @override
   List<Source> get inputValue {
     return _libraries.map((LibraryElement library) => library.source).toList();
   }
diff --git a/pkg/analyzer/lib/src/task/dart_work_manager.dart b/pkg/analyzer/lib/src/task/dart_work_manager.dart
index 77c4a0a..cc4d4e6 100644
--- a/pkg/analyzer/lib/src/task/dart_work_manager.dart
+++ b/pkg/analyzer/lib/src/task/dart_work_manager.dart
@@ -42,6 +42,7 @@
    */
   static final List<ResultDescriptor> _UNIT_ERRORS = <ResultDescriptor>[
     HINTS,
+    LINTS,
     INFER_STATIC_VARIABLE_TYPES_ERRORS,
     LIBRARY_UNIT_ERRORS,
     PARTIALLY_RESOLVE_REFERENCES_ERRORS,
diff --git a/pkg/analyzer/lib/src/task/driver.dart b/pkg/analyzer/lib/src/task/driver.dart
index 8daa5cf..3231454 100644
--- a/pkg/analyzer/lib/src/task/driver.dart
+++ b/pkg/analyzer/lib/src/task/driver.dart
@@ -667,6 +667,9 @@
         }
       } else {
         builder.currentValue = inputEntry.getValue(inputResult);
+        if (builder.flushOnAccess) {
+          inputEntry.setState(inputResult, CacheState.FLUSHED);
+        }
       }
       if (!builder.moveNext()) {
         inputs = builder.inputValue;
diff --git a/pkg/analyzer/lib/src/task/inputs.dart b/pkg/analyzer/lib/src/task/inputs.dart
index c93a127..468f313 100644
--- a/pkg/analyzer/lib/src/task/inputs.dart
+++ b/pkg/analyzer/lib/src/task/inputs.dart
@@ -24,6 +24,55 @@
  * An input to an [AnalysisTask] that is computed by accessing a single result
  * defined on a single target.
  */
+class ConstantTaskInput<V> extends TaskInputImpl<V> {
+  final V value;
+
+  ConstantTaskInput(this.value);
+
+  @override
+  TaskInputBuilder<V> createBuilder() {
+    return new ConstantTaskInputBuilder<V>(this);
+  }
+}
+
+/**
+ * A [TaskInputBuilder] used to build an input based on a [ConstantTaskInput].
+ */
+class ConstantTaskInputBuilder<V> implements TaskInputBuilder<V> {
+  final ConstantTaskInput input;
+
+  ConstantTaskInputBuilder(this.input);
+
+  @override
+  ResultDescriptor get currentResult => null;
+
+  @override
+  AnalysisTarget get currentTarget => null;
+
+  @override
+  void set currentValue(Object value) {
+    throw new StateError('Only supported after moveNext() returns true');
+  }
+
+  @override
+  bool get flushOnAccess => false;
+
+  @override
+  V get inputValue => input.value;
+
+  @override
+  void currentValueNotAvailable() {
+    throw new StateError('Only supported after moveNext() returns true');
+  }
+
+  @override
+  bool moveNext() => false;
+}
+
+/**
+ * An input to an [AnalysisTask] that is computed by accessing a single result
+ * defined on a single target.
+ */
 class ListTaskInputImpl<E> extends SimpleTaskInput<List<E>>
     with ListTaskInputMixin<E>
     implements ListTaskInput<E> {
@@ -32,7 +81,7 @@
    * the given [result] associated with the given [target].
    */
   ListTaskInputImpl(AnalysisTarget target, ResultDescriptor<List<E>> result)
-      : super(target, result);
+      : super._unflushable(target, result);
 }
 
 /**
@@ -243,6 +292,9 @@
   }
 
   @override
+  bool get flushOnAccess => currentBuilder.flushOnAccess;
+
+  @override
   void currentValueNotAvailable() {
     if (currentBuilder == null) {
       throw new StateError(
@@ -394,6 +446,9 @@
   }
 
   @override
+  bool get flushOnAccess => builder.flushOnAccess;
+
+  @override
   List<E> get inputValue {
     if (builder != null) {
       throw new StateError('Result value has not been created');
@@ -445,10 +500,23 @@
   final ResultDescriptor<V> result;
 
   /**
+   * Return `true` if the value accessed by this input builder should be flushed
+   * from the cache at the time it is retrieved.
+   */
+  final bool flushOnAccess;
+
+  /**
    * Initialize a newly created task input that computes the input by accessing
    * the given [result] associated with the given [target].
    */
-  SimpleTaskInput(this.target, this.result);
+  SimpleTaskInput(this.target, this.result, {this.flushOnAccess: false});
+
+  /**
+   * Initialize a newly created task input that computes the input by accessing
+   * the given [result] associated with the given [target].
+   */
+  SimpleTaskInput._unflushable(this.target, this.result)
+      : flushOnAccess = false;
 
   @override
   TaskInputBuilder<V> createBuilder() => new SimpleTaskInputBuilder<V>(this);
@@ -520,6 +588,9 @@
   }
 
   @override
+  bool get flushOnAccess => input.flushOnAccess;
+
+  @override
   V get inputValue {
     if (_state != _AFTER) {
       throw new StateError('Result value has not been created');
@@ -628,6 +699,9 @@
   }
 
   @override
+  bool get flushOnAccess => currentBuilder.flushOnAccess;
+
+  @override
   Map<String, Object> get inputValue {
     if (nameIndex < inputNames.length) {
       throw new StateError('Result value has not been created');
@@ -675,11 +749,18 @@
       return false;
     }
     currentBuilder = inputDescriptors[_currentName].createBuilder();
-    // NOTE: This assumes that every builder will require at least one result
-    // value to be created. If that assumption is every broken, this method will
-    // need to be changed to advance until we find a builder that does require
-    // a result to be computed (or run out of builders).
-    return currentBuilder.moveNext();
+    while (!currentBuilder.moveNext()) {
+      if (currentBuilder.inputValue != null) {
+        inputs[_currentName] = currentBuilder.inputValue;
+      }
+      nameIndex++;
+      if (nameIndex >= inputNames.length) {
+        // There is no next value, so we're done.
+        return false;
+      }
+      currentBuilder = inputDescriptors[_currentName].createBuilder();
+    }
+    return true;
   }
 }
 
@@ -774,6 +855,9 @@
   }
 
   @override
+  bool get flushOnAccess => currentBuilder.flushOnAccess;
+
+  @override
   C get inputValue {
     if (currentBuilder != null || _resultValue == null) {
       throw new StateError('Result value has not been created');
diff --git a/pkg/analyzer/lib/src/task/model.dart b/pkg/analyzer/lib/src/task/model.dart
index 9ef568e..50c05ee 100644
--- a/pkg/analyzer/lib/src/task/model.dart
+++ b/pkg/analyzer/lib/src/task/model.dart
@@ -29,8 +29,12 @@
       : super(name, defaultValue, cachingPolicy: cachingPolicy);
 
   @override
-  ListTaskInput<E> of(AnalysisTarget target) =>
-      new ListTaskInputImpl<E>(target, this);
+  ListTaskInput<E> of(AnalysisTarget target, {bool flushOnAccess: false}) {
+    if (flushOnAccess) {
+      throw new StateError('Cannot flush a list of values');
+    }
+    return new ListTaskInputImpl<E>(target, this);
+  }
 }
 
 /**
@@ -71,8 +75,8 @@
   }
 
   @override
-  TaskInput<V> of(AnalysisTarget target) =>
-      new SimpleTaskInput<V>(target, this);
+  TaskInput<V> of(AnalysisTarget target, {bool flushOnAccess: false}) =>
+      new SimpleTaskInput<V>(target, this, flushOnAccess: flushOnAccess);
 
   @override
   String toString() => name;
diff --git a/pkg/analyzer/lib/task/model.dart b/pkg/analyzer/lib/task/model.dart
index 018b349..9d949c3 100644
--- a/pkg/analyzer/lib/task/model.dart
+++ b/pkg/analyzer/lib/task/model.dart
@@ -5,6 +5,7 @@
 library analyzer.task.model;
 
 import 'dart:collection';
+import 'dart:developer';
 
 import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask;
 import 'package:analyzer/src/generated/error.dart' show AnalysisError;
@@ -84,6 +85,12 @@
   static final Map<Type, int> countMap = new HashMap<Type, int>();
 
   /**
+   * A table mapping the types of analysis tasks to user tags used to collect
+   * timing data for the Observatory.
+   */
+  static Map<Type, UserTag> tagMap = new HashMap<Type, UserTag>();
+
+  /**
    * A table mapping the types of analysis tasks to stopwatches used to compute
    * how much time was spent executing each kind of task.
    */
@@ -228,11 +235,15 @@
       //
       int count = countMap[runtimeType];
       countMap[runtimeType] = count == null ? 1 : count + 1;
+//      UserTag tag = tagMap.putIfAbsent(
+//          runtimeType, () => new UserTag(runtimeType.toString()));
       Stopwatch stopwatch = stopwatchMap[runtimeType];
       if (stopwatch == null) {
         stopwatch = new Stopwatch();
         stopwatchMap[runtimeType] = stopwatch;
       }
+//      UserTag previousTag = tag.makeCurrent();
+//      try {
       stopwatch.start();
       //
       // Actually perform the task.
@@ -245,6 +256,9 @@
       } finally {
         stopwatch.stop();
       }
+//      } finally {
+//        previousTag.makeCurrent();
+//      }
     } on AnalysisException {
       rethrow;
     } catch (exception, stackTrace) {
@@ -272,7 +286,7 @@
       E>;
 
   @override
-  ListTaskInput<E> of(AnalysisTarget target);
+  ListTaskInput<E> of(AnalysisTarget target, {bool flushOnAccess: false});
 }
 
 /**
@@ -387,9 +401,10 @@
 
   /**
    * Return a task input that can be used to compute this result for the given
-   * [target].
+   * [target]. If [flushOnAccess] is `true` then the value of this result that
+   * is associated with the [target] will be flushed when it is accessed.
    */
-  TaskInput<V> of(AnalysisTarget target);
+  TaskInput<V> of(AnalysisTarget target, {bool flushOnAccess: false});
 }
 
 /**
@@ -530,6 +545,12 @@
   void set currentValue(Object value);
 
   /**
+   * Return `true` if the value accessed by this input builder should be flushed
+   * from the cache at the time it is retrieved.
+   */
+  bool get flushOnAccess;
+
+  /**
    * Return the [value] that was computed by this builder.
    *
    * Throws a [StateError] if [moveNext] has not been invoked or if the last
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 056ec55..022f3f8 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 0.26.1+6
+version: 0.26.1+7
 author: Dart Team <misc@dartlang.org>
 description: Static analyzer for Dart.
 homepage: http://www.dartlang.org
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index 0b878f5..cabe5d7 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -5052,6 +5052,8 @@
     String className = "C";
     ClassDeclaration classDeclaration =
         AstFactory.classDeclaration(null, className, null, null, null, null);
+    classDeclaration.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     classDeclaration.accept(builder);
     List<ClassElement> types = holder.types;
     expect(types, hasLength(1));
@@ -5063,6 +5065,7 @@
     expect(type.isAbstract, isFalse);
     expect(type.isMixinApplication, isFalse);
     expect(type.isSynthetic, isFalse);
+    _assertHasDocRange(type, 50, 7);
   }
 
   void test_visitClassDeclaration_parameterized() {
@@ -5296,11 +5299,16 @@
             AstFactory.formalParameterList(),
             null,
             AstFactory.blockFunctionBody2());
+    constructorDeclaration.documentationComment = AstFactory
+        .documentationComment(
+            [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     constructorDeclaration.accept(builder);
+
     List<ConstructorElement> constructors = holder.constructors;
     expect(constructors, hasLength(1));
     ConstructorElement constructor = constructors[0];
     expect(constructor, isNotNull);
+    _assertHasDocRange(constructor, 50, 7);
     expect(constructor.isExternal, isFalse);
     expect(constructor.isFactory, isFalse);
     expect(constructor.name, "");
@@ -5478,11 +5486,14 @@
     String enumName = "E";
     EnumDeclaration enumDeclaration =
         AstFactory.enumDeclaration2(enumName, ["ONE"]);
+    enumDeclaration.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     enumDeclaration.accept(builder);
     List<ClassElement> enums = holder.enums;
     expect(enums, hasLength(1));
     ClassElement enumElement = enums[0];
     expect(enumElement, isNotNull);
+    _assertHasDocRange(enumElement, 50, 7);
     expect(enumElement.name, enumName);
   }
 
@@ -5496,18 +5507,25 @@
       AstFactory.variableDeclaration(firstFieldName),
       AstFactory.variableDeclaration(secondFieldName)
     ]);
+    fieldDeclaration.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     fieldDeclaration.accept(builder);
+
     List<FieldElement> fields = holder.fields;
     expect(fields, hasLength(2));
+
     FieldElement firstField = fields[0];
     expect(firstField, isNotNull);
+    _assertHasDocRange(firstField, 50, 7);
     expect(firstField.name, firstFieldName);
     expect(firstField.initializer, isNull);
     expect(firstField.isConst, isFalse);
     expect(firstField.isFinal, isFalse);
     expect(firstField.isSynthetic, isFalse);
+
     FieldElement secondField = fields[1];
     expect(secondField, isNotNull);
+    _assertHasDocRange(secondField, 50, 7);
     expect(secondField.name, secondFieldName);
     expect(secondField.initializer, isNull);
     expect(secondField.isConst, isFalse);
@@ -5614,12 +5632,15 @@
         functionName,
         AstFactory.functionExpression2(
             AstFactory.formalParameterList(), AstFactory.blockFunctionBody2()));
+    declaration.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     declaration.accept(builder);
 
     List<PropertyAccessorElement> accessors = holder.accessors;
     expect(accessors, hasLength(1));
     PropertyAccessorElement accessor = accessors[0];
     expect(accessor, isNotNull);
+    _assertHasDocRange(accessor, 50, 7);
     expect(accessor.name, functionName);
     expect(declaration.element, same(accessor));
     expect(declaration.functionExpression.element, same(accessor));
@@ -5646,12 +5667,15 @@
         functionName,
         AstFactory.functionExpression2(
             AstFactory.formalParameterList(), AstFactory.blockFunctionBody2()));
+    declaration.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     declaration.accept(builder);
 
     List<FunctionElement> functions = holder.functions;
     expect(functions, hasLength(1));
     FunctionElement function = functions[0];
     expect(function, isNotNull);
+    _assertHasDocRange(function, 50, 7);
     expect(function.hasImplicitReturnType, isFalse);
     expect(function.name, functionName);
     expect(declaration.element, same(function));
@@ -5672,12 +5696,15 @@
         functionName,
         AstFactory.functionExpression2(
             AstFactory.formalParameterList(), AstFactory.blockFunctionBody2()));
+    declaration.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     declaration.accept(builder);
 
     List<PropertyAccessorElement> accessors = holder.accessors;
     expect(accessors, hasLength(1));
     PropertyAccessorElement accessor = accessors[0];
     expect(accessor, isNotNull);
+    _assertHasDocRange(accessor, 50, 7);
     expect(accessor.hasImplicitReturnType, isFalse);
     expect(accessor.name, "$functionName=");
     expect(declaration.element, same(accessor));
@@ -5747,11 +5774,15 @@
     String parameterName = "E";
     FunctionTypeAlias aliasNode = AstFactory.typeAlias(
         null, aliasName, AstFactory.typeParameterList([parameterName]), null);
+    aliasNode.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     aliasNode.accept(builder);
+
     List<FunctionTypeAliasElement> aliases = holder.typeAliases;
     expect(aliases, hasLength(1));
     FunctionTypeAliasElement alias = aliases[0];
     expect(alias, isNotNull);
+    _assertHasDocRange(alias, 50, 7);
     expect(alias.name, aliasName);
     expect(alias.parameters, hasLength(0));
     List<TypeParameterElement> typeParameters = alias.typeParameters;
@@ -5903,6 +5934,8 @@
         AstFactory.identifier3(methodName),
         AstFactory.formalParameterList(),
         AstFactory.blockFunctionBody2());
+    methodDeclaration.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     methodDeclaration.accept(builder);
 
     List<FieldElement> fields = holder.fields;
@@ -5914,6 +5947,7 @@
     expect(field.setter, isNull);
     PropertyAccessorElement getter = field.getter;
     expect(getter, isNotNull);
+    _assertHasDocRange(getter, 50, 7);
     expect(getter.hasImplicitReturnType, isTrue);
     expect(getter.isAbstract, isFalse);
     expect(getter.isExternal, isFalse);
@@ -6015,11 +6049,15 @@
         AstFactory.identifier3(methodName),
         AstFactory.formalParameterList(),
         AstFactory.blockFunctionBody2());
+    methodDeclaration.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     methodDeclaration.accept(builder);
+
     List<MethodElement> methods = holder.methods;
     expect(methods, hasLength(1));
     MethodElement method = methods[0];
     expect(method, isNotNull);
+    _assertHasDocRange(method, 50, 7);
     expect(method.hasImplicitReturnType, isFalse);
     expect(method.name, methodName);
     expect(method.functions, hasLength(0));
@@ -6079,6 +6117,8 @@
         AstFactory.identifier3(methodName),
         AstFactory.formalParameterList(),
         AstFactory.blockFunctionBody2());
+    methodDeclaration.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     methodDeclaration.accept(builder);
 
     List<FieldElement> fields = holder.fields;
@@ -6088,8 +6128,10 @@
     expect(field.name, methodName);
     expect(field.isSynthetic, isTrue);
     expect(field.getter, isNull);
+
     PropertyAccessorElement setter = field.setter;
     expect(setter, isNotNull);
+    _assertHasDocRange(setter, 50, 7);
     expect(setter.hasImplicitReturnType, isFalse);
     expect(setter.isAbstract, isFalse);
     expect(setter.isExternal, isFalse);
@@ -6654,6 +6696,14 @@
     expect(variable.setter, isNull);
   }
 
+  void _assertHasDocRange(
+      Element element, int expectedOffset, int expectedLength) {
+    SourceRange docRange = element.docRange;
+    expect(docRange, isNotNull);
+    expect(docRange.offset, expectedOffset);
+    expect(docRange.length, expectedLength);
+  }
+
   void _useParameterInMethod(
       FormalParameter formalParameter, int blockOffset, int blockEnd) {
     Block block = AstFactory.block();
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index 18a45f6..eaef165 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -834,6 +834,24 @@
 ''');
   }
 
+  void test_false_fieldFormalParameter_differentField() {
+    _assertDoesNotMatch(
+        r'''
+class A {
+  final aaa;
+  final bbb;
+  A(this.aaa, this.bbb);
+}
+''',
+        r'''
+class A {
+  final aaa;
+  final bbb;
+  A(this.bbb, this.aaa);
+}
+''');
+  }
+
   void test_false_fieldFormalParameter_parameters_add() {
     _assertDoesNotMatch(
         r'''
@@ -930,6 +948,54 @@
 ''');
   }
 
+  void test_false_fieldFormalParameter_typeAdd() {
+    _assertDoesNotMatch(
+        r'''
+class A {
+  final fff;
+  A(this.fff);
+}
+''',
+        r'''
+class A {
+  final fff;
+  A(int this.fff);
+}
+''');
+  }
+
+  void test_false_fieldFormalParameter_typeEdit() {
+    _assertDoesNotMatch(
+        r'''
+class A {
+  final fff;
+  A(int this.fff);
+}
+''',
+        r'''
+class A {
+  final fff;
+  A(String this.fff);
+}
+''');
+  }
+
+  void test_false_fieldFormalParameter_typeRemove() {
+    _assertDoesNotMatch(
+        r'''
+class A {
+  final fff;
+  A(int this.fff);
+}
+''',
+        r'''
+class A {
+  final fff;
+  A(this.fff);
+}
+''');
+  }
+
   void test_false_fieldFormalParameterElement_wasSimple() {
     _assertDoesNotMatch(
         r'''
@@ -2383,6 +2449,22 @@
 ''');
   }
 
+  void test_true_fieldFormalParameter_changeName_wasUnresolvedField() {
+    _assertMatches(
+        r'''
+class A {
+  final fff;
+  A(this.unresolved);
+}
+''',
+        r'''
+class A {
+  final fff;
+  A(this.fff);
+}
+''');
+  }
+
   void test_true_fieldFormalParameter_function() {
     _assertMatches(
         r'''
@@ -2987,15 +3069,6 @@
     _resolve(_editString('+', '*'), _isFunctionBody);
   }
 
-  void test_constructor_fieldFormalParameter() {
-    _resolveUnit(r'''
-class A {
-  int xy;
-  A(this.x);
-}''');
-    _resolve(_editString('this.x', 'this.xy'), _isDeclaration);
-  }
-
   void test_constructor_fieldInitializer_add() {
     _resolveUnit(r'''
 class A {
@@ -3050,6 +3123,15 @@
     _resolve(_editString('+', '*'), _isExpression);
   }
 
+  void test_fieldFormalParameter() {
+    _resolveUnit(r'''
+class A {
+  int xy;
+  A(this.x);
+}''');
+    _resolve(_editString('this.x', 'this.xy'), _isDeclaration);
+  }
+
   void test_function_localFunction_add() {
     _resolveUnit(r'''
 int main() {
@@ -4091,6 +4173,28 @@
 ''');
   }
 
+  void test_true_todoHint() {
+    _resolveUnit(r'''
+main() {
+  print(1);
+}
+foo() {
+ // TODO
+}
+''');
+    List<AnalysisError> oldErrors = analysisContext.computeErrors(source);
+    _updateAndValidate(r'''
+main() {
+  print(2);
+}
+foo() {
+ // TODO
+}
+''');
+    List<AnalysisError> newErrors = analysisContext.computeErrors(source);
+    _assertEqualErrors(newErrors, oldErrors);
+  }
+
   void test_true_wholeConstructor() {
     _resolveUnit(r'''
 class A {
@@ -4168,28 +4272,6 @@
 ''');
   }
 
-  void test_true_todoHint() {
-    _resolveUnit(r'''
-main() {
-  print(1);
-}
-foo() {
- // TODO
-}
-''');
-    List<AnalysisError> oldErrors = analysisContext.computeErrors(source);
-    _updateAndValidate(r'''
-main() {
-  print(2);
-}
-foo() {
- // TODO
-}
-''');
-    List<AnalysisError> newErrors = analysisContext.computeErrors(source);
-    _assertEqualErrors(newErrors, oldErrors);
-  }
-
   void test_unusedHint_add_wasUsedOnlyInPart() {
     Source partSource = addNamedSource(
         '/my_unit.dart',
@@ -4440,6 +4522,36 @@
 ''');
   }
 
+  void test_whitespace_getElementAt() {
+    _resolveUnit(r'''
+class A {}
+class B extends A {}
+''');
+    {
+      ClassElement typeA = oldUnitElement.getType('A');
+      expect(oldUnitElement.getElementAt(typeA.nameOffset), typeA);
+    }
+    {
+      ClassElement typeB = oldUnitElement.getType('B');
+      expect(oldUnitElement.getElementAt(typeB.nameOffset), typeB);
+    }
+    _updateAndValidate(r'''
+class A {}
+
+class B extends A {}
+''');
+    // getElementAt() caches results, it should be notified when offset
+    // are changed.
+    {
+      ClassElement typeA = oldUnitElement.getType('A');
+      expect(oldUnitElement.getElementAt(typeA.nameOffset), typeA);
+    }
+    {
+      ClassElement typeB = oldUnitElement.getType('B');
+      expect(oldUnitElement.getElementAt(typeB.nameOffset), typeB);
+    }
+  }
+
   void _assertEqualLineInfo(LineInfo incrLineInfo, LineInfo fullLineInfo) {
     for (int offset = 0; offset < 1000; offset++) {
       LineInfo_Location incrLocation = incrLineInfo.getLocation(offset);
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 307c41c..1339162 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -995,13 +995,13 @@
   final T x = y;
   const C();
 }
-const y = 1;
+const int y = 1;
 var v = const C<String>();
 ''');
     computeLibrarySourceErrors(source);
     assertErrors(source, [
       CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH,
-      HintCode.INVALID_ASSIGNMENT
+      StaticTypeWarningCode.INVALID_ASSIGNMENT
     ]);
     verify([source]);
   }
@@ -1027,11 +1027,11 @@
   final T x = y;
   const C();
 }
-const y = 1;
+const int y = 1;
 var v = const C<int>();
 ''');
     computeLibrarySourceErrors(source);
-    assertErrors(source, [HintCode.INVALID_ASSIGNMENT]);
+    assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
     verify([source]);
   }
 
@@ -5931,6 +5931,21 @@
     expect(unit.topLevelVariables, hasLength(0));
   }
 
+  void test_libraryElement_docRange() {
+    String code = r'''
+/// My dart doc.
+library lib;
+
+class A {}''';
+    Source librarySource = addSource("/lib.dart", code);
+    LibraryElement element = _buildLibrary(librarySource);
+    expect(element, isNotNull);
+    SourceRange docRange = element.docRange;
+    expect(docRange, isNotNull);
+    expect(docRange.offset, code.indexOf('/// My dart doc.'));
+    expect(docRange.length, '/// My dart doc.'.length);
+  }
+
   void test_missingLibraryDirectiveWithPart() {
     addSource("/a.dart", "part of lib;");
     Source librarySource = addSource("/lib.dart", "part 'a.dart';");
@@ -5989,6 +6004,7 @@
     Source librarySource = addSource(
         "/lib.dart",
         r'''
+/// My dart doc.
 library lib;
 
 class A {}''');
@@ -9974,31 +9990,6 @@
 }
 
 /**
- * Shared infrastructure for [StaticTypeAnalyzer2Test] and
- * [StrongModeStaticTypeAnalyzer2Test].
- */
-class _StaticTypeAnalyzer2TestShared extends ResolverTestCase {
-  String testCode;
-  Source testSource;
-  CompilationUnit testUnit;
-
-  SimpleIdentifier _findIdentifier(String search) {
-    SimpleIdentifier identifier = EngineTestCase.findNode(
-        testUnit, testCode, search, (node) => node is SimpleIdentifier);
-    return identifier;
-  }
-
-  void _resolveTestUnit(String code) {
-    testCode = code;
-    testSource = addSource(testCode);
-    LibraryElement library = resolve2(testSource);
-    assertNoErrors(testSource);
-    verify([testSource]);
-    testUnit = resolveCompilationUnit(testSource, library);
-  }
-}
-
-/**
  * Like [StaticTypeAnalyzerTest], but as end-to-end tests.
  */
 @reflectiveTest
@@ -11915,25 +11906,11 @@
     resetWithOptions(options);
   }
 
-  void test_ternaryOperator_null_right() {
+  void test_dynamicObjectGetter_hashCode() {
     String code = r'''
 main() {
-  var foo = (true) ? 3 : null;
-}
-''';
-    _resolveTestUnit(code);
-
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'int');
-    expect(declaration.initializer.propagatedType, isNull);
-  }
-
-  void test_ternaryOperator_null_left() {
-    String code = r'''
-main() {
-  var foo = (true) ? null : 3;
+  dynamic a = null;
+  var foo = a.hashCode;
 }
 ''';
     _resolveTestUnit(code);
@@ -11961,38 +11938,6 @@
     expect(declaration.initializer.propagatedType, isNull);
   }
 
-  void test_dynamicObjectGetter_hashCode() {
-    String code = r'''
-main() {
-  dynamic a = null;
-  var foo = a.hashCode;
-}
-''';
-    _resolveTestUnit(code);
-
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'int');
-    expect(declaration.initializer.propagatedType, isNull);
-  }
-
-  void test_pseudoGeneric_max_intInt() {
-    String code = r'''
-import 'dart:math';
-main() {
-  var foo = max(1, 2);
-}
-''';
-    _resolveTestUnit(code);
-
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'int');
-    expect(declaration.initializer.propagatedType, isNull);
-  }
-
   void test_pseudoGeneric_max_doubleDouble() {
     String code = r'''
 import 'dart:math';
@@ -12009,22 +11954,6 @@
     expect(declaration.initializer.propagatedType, isNull);
   }
 
-  void test_pseudoGeneric_max_intDouble() {
-    String code = r'''
-import 'dart:math';
-main() {
-  var foo = max(1, 2.0);
-}
-''';
-    _resolveTestUnit(code);
-
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'num');
-    expect(declaration.initializer.propagatedType, isNull);
-  }
-
   void test_pseudoGeneric_max_doubleInt() {
     String code = r'''
 import 'dart:math';
@@ -12041,6 +11970,38 @@
     expect(declaration.initializer.propagatedType, isNull);
   }
 
+  void test_pseudoGeneric_max_intDouble() {
+    String code = r'''
+import 'dart:math';
+main() {
+  var foo = max(1, 2.0);
+}
+''';
+    _resolveTestUnit(code);
+
+    SimpleIdentifier identifier = _findIdentifier('foo');
+    VariableDeclaration declaration =
+        identifier.getAncestor((node) => node is VariableDeclaration);
+    expect(declaration.initializer.staticType.name, 'num');
+    expect(declaration.initializer.propagatedType, isNull);
+  }
+
+  void test_pseudoGeneric_max_intInt() {
+    String code = r'''
+import 'dart:math';
+main() {
+  var foo = max(1, 2);
+}
+''';
+    _resolveTestUnit(code);
+
+    SimpleIdentifier identifier = _findIdentifier('foo');
+    VariableDeclaration declaration =
+        identifier.getAncestor((node) => node is VariableDeclaration);
+    expect(declaration.initializer.staticType.name, 'int');
+    expect(declaration.initializer.propagatedType, isNull);
+  }
+
   void test_pseudoGeneric_then() {
     String code = r'''
 import 'dart:async';
@@ -12055,14 +12016,40 @@
     SimpleIdentifier identifier = _findIdentifier('foo');
     VariableDeclaration declaration =
         identifier.getAncestor((node) => node is VariableDeclaration);
-    InterfaceType stringType = typeProvider.stringType;
-    InterfaceType futureType = typeProvider.futureType;
-    InterfaceType futureOfStringType =
-        futureType.substitute4(<DartType>[stringType]);
 
     expect(declaration.initializer.staticType.toString(), "Future<String>");
     expect(declaration.initializer.propagatedType, isNull);
   }
+
+  void test_ternaryOperator_null_left() {
+    String code = r'''
+main() {
+  var foo = (true) ? null : 3;
+}
+''';
+    _resolveTestUnit(code);
+
+    SimpleIdentifier identifier = _findIdentifier('foo');
+    VariableDeclaration declaration =
+        identifier.getAncestor((node) => node is VariableDeclaration);
+    expect(declaration.initializer.staticType.name, 'int');
+    expect(declaration.initializer.propagatedType, isNull);
+  }
+
+  void test_ternaryOperator_null_right() {
+    String code = r'''
+main() {
+  var foo = (true) ? 3 : null;
+}
+''';
+    _resolveTestUnit(code);
+
+    SimpleIdentifier identifier = _findIdentifier('foo');
+    VariableDeclaration declaration =
+        identifier.getAncestor((node) => node is VariableDeclaration);
+    expect(declaration.initializer.staticType.name, 'int');
+    expect(declaration.initializer.propagatedType, isNull);
+  }
 }
 
 @reflectiveTest
@@ -12559,6 +12546,18 @@
         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",
@@ -13853,6 +13852,99 @@
     assertNoErrors(source);
   }
 
+  void test_objectAccessInference_disabled_for_library_prefix() {
+    String name = 'hashCode';
+    addNamedSource(
+        '/helper.dart',
+        '''
+library helper;
+dynamic get $name => 42;
+''');
+    String code = '''
+import 'helper.dart' as helper;
+main() {
+  helper.$name; // marker
+}''';
+
+    SimpleIdentifier id = _findMarkedIdentifier(code, "; // marker");
+    PrefixedIdentifier prefixedId = id.parent;
+    expect(id.staticType, typeProvider.dynamicType);
+    expect(prefixedId.staticType, typeProvider.dynamicType);
+  }
+
+  void test_objectAccessInference_disabled_for_local_getter() {
+    String name = 'hashCode';
+    String code = '''
+dynamic get $name => null;
+main() {
+  $name; // marker
+}''';
+
+    SimpleIdentifier getter = _findMarkedIdentifier(code, "; // marker");
+    expect(getter.staticType, typeProvider.dynamicType);
+  }
+
+  void test_objectAccessInference_enabled_for_cascades() {
+    String name = 'hashCode';
+    String code = '''
+main() {
+  dynamic obj;
+  obj..$name..$name; // marker
+}''';
+    PropertyAccess access = _findMarkedIdentifier(code, "; // marker").parent;
+    expect(access.staticType, typeProvider.dynamicType);
+    expect(access.realTarget.staticType, typeProvider.dynamicType);
+  }
+
+  void test_objectMethodInference_disabled_for_library_prefix() {
+    String name = 'toString';
+    addNamedSource(
+        '/helper.dart',
+        '''
+library helper;
+dynamic $name = (int x) => x + 42');
+''');
+    String code = '''
+import 'helper.dart' as helper;
+main() {
+  helper.$name(); // marker
+}''';
+    SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
+    MethodInvocation methodInvoke = methodName.parent;
+    expect(methodName.staticType, null, reason: 'library prefix has no type');
+    expect(methodInvoke.staticType, typeProvider.dynamicType);
+  }
+
+  void test_objectMethodInference_disabled_for_local_function() {
+    String name = 'toString';
+    String code = '''
+main() {
+  dynamic $name = () => null;
+  $name(); // marker
+}''';
+    SimpleIdentifier identifier = _findMarkedIdentifier(code, "$name = ");
+    expect(identifier.staticType, typeProvider.dynamicType);
+
+    SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
+    MethodInvocation methodInvoke = methodName.parent;
+    expect(methodName.staticType, typeProvider.dynamicType);
+    expect(methodInvoke.staticType, typeProvider.dynamicType);
+  }
+
+  void test_objectMethodInference_enabled_for_cascades() {
+    String name = 'toString';
+    String code = '''
+main() {
+  dynamic obj;
+  obj..$name()..$name(); // marker
+}''';
+    SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
+    MethodInvocation methodInvoke = methodName.parent;
+
+    expect(methodInvoke.staticType, typeProvider.dynamicType);
+    expect(methodInvoke.realTarget.staticType, typeProvider.dynamicType);
+  }
+
   void test_objectMethodOnDynamicExpression_doubleEquals() {
     // https://code.google.com/p/dart/issues/detail?id=20342
     //
@@ -13906,96 +13998,6 @@
         typeProvider.stringType);
   }
 
-  void test_objectMethodInference_disabled_for_local_function() {
-    String name = 'toString';
-    String code = '''
-main() {
-  dynamic $name = () => null;
-  $name(); // marker
-}''';
-    SimpleIdentifier identifier = _findMarkedIdentifier(code, "$name = ");
-    expect(identifier.staticType, typeProvider.dynamicType);
-
-    SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
-    MethodInvocation methodInvoke = methodName.parent;
-    expect(methodName.staticType, typeProvider.dynamicType);
-    expect(methodInvoke.staticType, typeProvider.dynamicType);
-  }
-
-  void test_objectMethodInference_disabled_for_library_prefix() {
-    String name = 'toString';
-    addNamedSource('/helper.dart', '''
-library helper;
-dynamic $name = (int x) => x + 42');
-''');
-    String code = '''
-import 'helper.dart' as helper;
-main() {
-  helper.$name(); // marker
-}''';
-    SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
-    MethodInvocation methodInvoke = methodName.parent;
-    expect(methodName.staticType, null, reason: 'library prefix has no type');
-    expect(methodInvoke.staticType, typeProvider.dynamicType);
-  }
-
-  void test_objectMethodInference_enabled_for_cascades() {
-    String name = 'toString';
-    String code = '''
-main() {
-  dynamic obj;
-  obj..$name()..$name(); // marker
-}''';
-    SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
-    MethodInvocation methodInvoke = methodName.parent;
-
-    expect(methodInvoke.staticType, typeProvider.dynamicType);
-    expect(methodInvoke.realTarget.staticType, typeProvider.dynamicType);
-  }
-
-
-  void test_objectAccessInference_disabled_for_local_getter() {
-    String name = 'hashCode';
-    String code = '''
-dynamic get $name => null;
-main() {
-  $name; // marker
-}''';
-
-    SimpleIdentifier getter = _findMarkedIdentifier(code, "; // marker");
-    expect(getter.staticType, typeProvider.dynamicType);
-  }
-
-  void test_objectAccessInference_disabled_for_library_prefix() {
-    String name = 'hashCode';
-    addNamedSource('/helper.dart', '''
-library helper;
-dynamic get $name => 42;
-''');
-    String code = '''
-import 'helper.dart' as helper;
-main() {
-  helper.$name; // marker
-}''';
-
-    SimpleIdentifier id = _findMarkedIdentifier(code, "; // marker");
-    PrefixedIdentifier prefixedId = id.parent;
-    expect(id.staticType, typeProvider.dynamicType);
-    expect(prefixedId.staticType, typeProvider.dynamicType);
-  }
-
-  void test_objectAccessInference_enabled_for_cascades() {
-    String name = 'hashCode';
-    String code = '''
-main() {
-  dynamic obj;
-  obj..$name..$name; // marker
-}''';
-    PropertyAccess access = _findMarkedIdentifier(code, "; // marker").parent;
-    expect(access.staticType, typeProvider.dynamicType);
-    expect(access.realTarget.staticType, typeProvider.dynamicType);
-  }
-
   void test_propagatedReturnType_localFunction() {
     String code = r'''
 main() {
@@ -14833,3 +14835,28 @@
     return null;
   }
 }
+
+/**
+ * Shared infrastructure for [StaticTypeAnalyzer2Test] and
+ * [StrongModeStaticTypeAnalyzer2Test].
+ */
+class _StaticTypeAnalyzer2TestShared extends ResolverTestCase {
+  String testCode;
+  Source testSource;
+  CompilationUnit testUnit;
+
+  SimpleIdentifier _findIdentifier(String search) {
+    SimpleIdentifier identifier = EngineTestCase.findNode(
+        testUnit, testCode, search, (node) => node is SimpleIdentifier);
+    return identifier;
+  }
+
+  void _resolveTestUnit(String code) {
+    testCode = code;
+    testSource = addSource(testCode);
+    LibraryElement library = resolve2(testSource);
+    assertNoErrors(testSource);
+    verify([testSource]);
+    testUnit = resolveCompilationUnit(testSource, library);
+  }
+}
diff --git a/pkg/analyzer/test/generated/type_system_test.dart b/pkg/analyzer/test/generated/type_system_test.dart
index a6c552a..d49c75c 100644
--- a/pkg/analyzer/test/generated/type_system_test.dart
+++ b/pkg/analyzer/test/generated/type_system_test.dart
@@ -791,7 +791,7 @@
     DartType top = TypeBuilder.functionType(<DartType>[intType], objectType);
     InterfaceType bottom = classBottom.type;
 
-    _checkIsAssignableTo(top, bottom);
+    _checkIsStrictAssignableTo(bottom, top);
   }
 
   void test_isAssignableTo_fuzzy_arrows() {
diff --git a/pkg/analyzer/test/source/analysis_options_provider_test.dart b/pkg/analyzer/test/source/analysis_options_provider_test.dart
index 80bf2ad..a251770 100644
--- a/pkg/analyzer/test/source/analysis_options_provider_test.dart
+++ b/pkg/analyzer/test/source/analysis_options_provider_test.dart
@@ -52,6 +52,7 @@
       var optionsProvider = new AnalysisOptionsProvider();
       Map<String, YamlNode> options =
           optionsProvider.getOptions(resourceProvider.getFolder('/'));
+      expect(options, isNotNull);
     });
   });
   group('AnalysisOptionsProvider', () {
@@ -67,7 +68,8 @@
       try {
         Map<String, YamlNode> options =
             optionsProvider.getOptions(resourceProvider.getFolder('/'));
-      } catch (e, st) {
+        expect(options, isNotNull);
+      } catch (e) {
         exceptionCaught = true;
       }
       expect(exceptionCaught, isTrue);
diff --git a/pkg/analyzer/test/src/context/context_test.dart b/pkg/analyzer/test/src/context/context_test.dart
index 734c1b2..0544bf5 100644
--- a/pkg/analyzer/test/src/context/context_test.dart
+++ b/pkg/analyzer/test/src/context/context_test.dart
@@ -1500,7 +1500,7 @@
         reason: "part changed 3");
     _analyzeAll_assertFinished();
     expect(context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
-        reason: "library resolved 2");
+        reason: "library resolved 3");
     expect(
         context.getResolvedCompilationUnit2(partSource, libSource), isNotNull,
         reason: "part resolved 3");
diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart
index 51a86fb..1c94faf 100644
--- a/pkg/analyzer/test/src/task/dart_test.dart
+++ b/pkg/analyzer/test/src/task/dart_test.dart
@@ -15,6 +15,7 @@
 import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/services/lint.dart';
 import 'package:analyzer/src/task/dart.dart';
 import 'package:analyzer/src/task/html.dart';
 import 'package:analyzer/task/dart.dart';
@@ -48,6 +49,7 @@
   runReflectiveTests(GatherUsedImportedElementsTaskTest);
   runReflectiveTests(GatherUsedLocalElementsTaskTest);
   runReflectiveTests(GenerateHintsTaskTest);
+  runReflectiveTests(GenerateLintsTaskTest);
   runReflectiveTests(InferInstanceMembersInUnitTaskTest);
   runReflectiveTests(InferStaticVariableTypesInUnitTaskTest);
   runReflectiveTests(InferStaticVariableTypeTaskTest);
@@ -98,6 +100,7 @@
 isInstanceOf isGatherUsedLocalElementsTask =
     new isInstanceOf<GatherUsedLocalElementsTask>();
 isInstanceOf isGenerateHintsTask = new isInstanceOf<GenerateHintsTask>();
+isInstanceOf isGenerateLintsTask = new isInstanceOf<GenerateLintsTask>();
 isInstanceOf isInferInstanceMembersInUnitTask =
     new isInstanceOf<InferInstanceMembersInUnitTask>();
 isInstanceOf isInferStaticVariableTypesInUnitTask =
@@ -122,6 +125,8 @@
 isInstanceOf isScanDartTask = new isInstanceOf<ScanDartTask>();
 isInstanceOf isVerifyUnitTask = new isInstanceOf<VerifyUnitTask>();
 
+final LintCode _testLintCode = new LintCode('test lint', 'test lint code');
+
 @reflectiveTest
 class BuildCompilationUnitElementTaskTest extends _AbstractDartTaskTest {
   Source source;
@@ -1876,6 +1881,62 @@
 }
 
 @reflectiveTest
+class GenerateLintsTaskTest extends _AbstractDartTaskTest {
+  void enableLints() {
+    AnalysisOptionsImpl options = context.analysisOptions;
+    options.lint = true;
+    context.analysisOptions = options;
+  }
+
+  @override
+  void setUp() {
+    super.setUp();
+    enableLints();
+  }
+
+  @override
+  void tearDown() {
+    LintGenerator.LINTERS.clear();
+    super.tearDown();
+  }
+
+  test_camel_case_types() {
+    Source source = newSource(
+        '/test.dart',
+        '''
+class a { }
+''');
+
+    LintGenerator.LINTERS.clear();
+    LintGenerator.LINTERS.add(new GenerateLintsTaskTest_TestLinter());
+
+    LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+    computeResult(target, LINTS, matcher: isGenerateLintsTask);
+    // validate
+    _fillErrorListener(LINTS);
+    errorListener.assertErrorsWithCodes(<ErrorCode>[_testLintCode]);
+  }
+}
+
+class GenerateLintsTaskTest_AstVisitor extends SimpleAstVisitor {
+  Linter linter;
+  GenerateLintsTaskTest_AstVisitor(this.linter);
+
+  @override
+  visitClassDeclaration(ClassDeclaration node) {
+    if (!new RegExp(r'^([_]*)([A-Z]+[a-z0-9]*)+$')
+        .hasMatch(node.name.toString())) {
+      linter.reporter.reportErrorForNode(_testLintCode, node, []);
+    }
+  }
+}
+
+class GenerateLintsTaskTest_TestLinter extends Linter {
+  @override
+  AstVisitor getVisitor() => new GenerateLintsTaskTest_AstVisitor(this);
+}
+
+@reflectiveTest
 class InferInstanceMembersInUnitTaskTest extends _AbstractDartTaskTest {
   void test_perform() {
     enableStrongMode();
@@ -1973,6 +2034,23 @@
 
 @reflectiveTest
 class InferStaticVariableTypesInUnitTaskTest extends _AbstractDartTaskTest {
+  void test_perform_const_field() {
+    enableStrongMode();
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+class M {
+  static const X = "";
+}
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6,
+        matcher: isInferStaticVariableTypesInUnitTask);
+    CompilationUnit unit = outputs[RESOLVED_UNIT6];
+    VariableDeclaration declaration = getFieldInClass(unit, 'M', 'X');
+    InterfaceType stringType = context.typeProvider.stringType;
+    expect(declaration.element.type, stringType);
+  }
+
   void test_perform_nestedDeclarations() {
     enableStrongMode();
     AnalysisTarget source = newSource(
@@ -2050,23 +2128,6 @@
     InterfaceType intType = context.typeProvider.intType;
     expect(expression.staticType, intType);
   }
-
-  void test_perform_const_field() {
-    enableStrongMode();
-    AnalysisTarget source = newSource(
-        '/test.dart',
-        '''
-class M {
-  static const X = "";
-}
-''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6,
-        matcher: isInferStaticVariableTypesInUnitTask);
-    CompilationUnit unit = outputs[RESOLVED_UNIT6];
-    VariableDeclaration declaration = getFieldInClass(unit, 'M', 'X');
-    InterfaceType stringType = context.typeProvider.stringType;
-    expect(declaration.element.type, stringType);
-  }
 }
 
 @reflectiveTest
@@ -2128,31 +2189,6 @@
     expect(outputs[INFER_STATIC_VARIABLE_ERRORS], hasLength(0));
   }
 
-  void test_perform_reresolution() {
-    AnalysisTarget source = newSource(
-        '/test.dart',
-        '''
-const topLevel = '';
-class C {
-  String field = topLevel;
-}
-''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
-    CompilationUnit unit = outputs[RESOLVED_UNIT5];
-    VariableDeclaration topLevelDecl = getTopLevelVariable(unit, 'topLevel');
-    VariableDeclaration fieldDecl = getFieldInClass(unit, 'C', 'field');
-    VariableElement topLevel = topLevelDecl.name.staticElement;
-    VariableElement field = fieldDecl.name.staticElement;
-
-    computeResult(field, INFERRED_STATIC_VARIABLE,
-        matcher: isInferStaticVariableTypeTask);
-    InterfaceType stringType = context.typeProvider.stringType;
-    expect(topLevel.type, stringType);
-    expect(field.type, stringType);
-    expect(fieldDecl.initializer.staticType, stringType);
-    expect(outputs[INFER_STATIC_VARIABLE_ERRORS], hasLength(0));
-  }
-
   void test_perform_const() {
     AnalysisTarget source = newSource(
         '/test.dart',
@@ -2231,6 +2267,31 @@
     expect(a.type.isDynamic, isTrue);
     expect(outputs[INFER_STATIC_VARIABLE_ERRORS], hasLength(0));
   }
+
+  void test_perform_reresolution() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+const topLevel = '';
+class C {
+  String field = topLevel;
+}
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
+    CompilationUnit unit = outputs[RESOLVED_UNIT5];
+    VariableDeclaration topLevelDecl = getTopLevelVariable(unit, 'topLevel');
+    VariableDeclaration fieldDecl = getFieldInClass(unit, 'C', 'field');
+    VariableElement topLevel = topLevelDecl.name.staticElement;
+    VariableElement field = fieldDecl.name.staticElement;
+
+    computeResult(field, INFERRED_STATIC_VARIABLE,
+        matcher: isInferStaticVariableTypeTask);
+    InterfaceType stringType = context.typeProvider.stringType;
+    expect(topLevel.type, stringType);
+    expect(field.type, stringType);
+    expect(fieldDecl.initializer.staticType, stringType);
+    expect(outputs[INFER_STATIC_VARIABLE_ERRORS], hasLength(0));
+  }
 }
 
 @reflectiveTest
@@ -2594,472 +2655,6 @@
 }
 
 @reflectiveTest
-class StrongModeInferenceTest extends _AbstractDartTaskTest {
-
-  @override
-  void setUp() {
-    super.setUp();
-    enableStrongMode();
-  }
-
-  // Check that even within a static variable cycle, inferred
-  // types get propagated to the members of the cycle.
-  void test_perform_cycle() {
-    AnalysisTarget source = newSource(
-        '/test.dart',
-        '''
-var piFirst = true;
-var pi = piFirst ? 3.14 : tau / 2;
-var tau = piFirst ? pi * 2 : 6.28;
-''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
-    CompilationUnit unit = outputs[RESOLVED_UNIT8];
-    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;
-
-    expect(piFirstUse.staticType, context.typeProvider.boolType);
-    expect(piFirst.type, context.typeProvider.boolType);
-    expect(pi.type.isDynamic, isTrue);
-    expect(tau.type.isDynamic, isTrue);
-  }
-
-  void test_perform_local_explicit_disabled() {
-    AnalysisTarget source = newSource(
-        '/test.dart',
-        '''
-      test() {
-        int x = 3;
-        x = "hi";
-      }
-''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
-    CompilationUnit unit = outputs[RESOLVED_UNIT8];
-
-    InterfaceType intType = context.typeProvider.intType;
-    InterfaceType stringType = context.typeProvider.stringType;
-
-    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
-    VariableDeclaration decl =
-        (statements[0] as VariableDeclarationStatement).variables.variables[0];
-    expect(decl.element.type, intType);
-    expect(decl.initializer.staticType, intType);
-
-    ExpressionStatement statement = statements[1];
-    AssignmentExpression assgn = statement.expression;
-    expect(assgn.leftHandSide.staticType, intType);
-    expect(assgn.rightHandSide.staticType, stringType);
-  }
-
-  void assertVariableDeclarationTypes(
-      VariableDeclaration decl, DartType varType, DartType initializerType) {
-    expect(decl.element.type, varType);
-    expect(decl.initializer.staticType, initializerType);
-  }
-
-  void assertVariableDeclarationStatementTypes(
-      Statement stmt, DartType varType, DartType initializerType) {
-    VariableDeclaration decl =
-        (stmt as VariableDeclarationStatement).variables.variables[0];
-    assertVariableDeclarationTypes(decl, varType, initializerType);
-  }
-
-  void assertAssignmentStatementTypes(
-      Statement stmt, DartType leftType, DartType rightType) {
-    AssignmentExpression assgn = (stmt as ExpressionStatement).expression;
-    expect(assgn.leftHandSide.staticType, leftType);
-    expect(assgn.rightHandSide.staticType, rightType);
-  }
-
-  // Test that local variables in method bodies are inferred appropriately
-  void test_perform_inference_local_variables() {
-    AnalysisTarget source = newSource(
-        '/test.dart',
-        '''
-      test() {
-        int x = 3;
-        x = "hi";
-        var y = 3;
-        y = "hi";
-      }
-''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
-    CompilationUnit unit = outputs[RESOLVED_UNIT8];
-
-    InterfaceType intType = context.typeProvider.intType;
-    InterfaceType stringType = context.typeProvider.stringType;
-
-    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
-
-    assertVariableDeclarationStatementTypes(statements[0], intType, intType);
-    assertAssignmentStatementTypes(statements[1], intType, stringType);
-    assertVariableDeclarationStatementTypes(statements[2], intType, intType);
-    assertAssignmentStatementTypes(statements[3], intType, stringType);
-  }
-
-  // Test inference interactions between local variables and fields
-  void test_perform_inference_local_variables_fields() {
-    AnalysisTarget source = newSource(
-        '/test.dart',
-        '''
-      class A {
-        int x = 0;
-
-        test1() {
-          var a = x;
-          a = "hi";
-          a = 3;
-          var b = y;
-          b = "hi";
-          b = 4;
-          var c = z;
-          c = "hi";
-          c = 4;
-        }
-
-        int y; // field def after use
-        final z = 42; // should infer `int`
-      }
-''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
-    CompilationUnit unit = outputs[RESOLVED_UNIT8];
-
-    InterfaceType intType = context.typeProvider.intType;
-    InterfaceType stringType = context.typeProvider.stringType;
-
-    List<Statement> statements = getStatementsInMethod(unit, "A", "test1");
-
-    assertVariableDeclarationStatementTypes(statements[0], intType, intType);
-    assertAssignmentStatementTypes(statements[1], intType, stringType);
-    assertAssignmentStatementTypes(statements[2], intType, intType);
-
-    assertVariableDeclarationStatementTypes(statements[3], intType, intType);
-    assertAssignmentStatementTypes(statements[4], intType, stringType);
-    assertAssignmentStatementTypes(statements[5], intType, intType);
-
-    assertVariableDeclarationStatementTypes(statements[6], intType, intType);
-    assertAssignmentStatementTypes(statements[7], intType, stringType);
-    assertAssignmentStatementTypes(statements[8], intType, intType);
-
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit, "A", "x"), intType, intType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit, "A", "z"), intType, intType);
-  }
-
-  // Test inference interactions between local variables and top level
-  // variables
-  void test_perform_inference_local_variables_topLevel() {
-    AnalysisTarget source = newSource(
-        '/test.dart',
-        '''
-      int x = 0;
-
-      test1() {
-        var a = x;
-        a = /*severe:StaticTypeError*/"hi";
-        a = 3;
-        var b = y;
-        b = /*severe:StaticTypeError*/"hi";
-        b = 4;
-        var c = z;
-        c = /*severe:StaticTypeError*/"hi";
-        c = 4;
-      }
-
-      int y = 0; // field def after use
-      final z = 42; // should infer `int`
-''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
-    CompilationUnit unit = outputs[RESOLVED_UNIT8];
-
-    InterfaceType intType = context.typeProvider.intType;
-    InterfaceType stringType = context.typeProvider.stringType;
-
-    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test1");
-
-    assertVariableDeclarationStatementTypes(statements[0], intType, intType);
-    assertAssignmentStatementTypes(statements[1], intType, stringType);
-    assertAssignmentStatementTypes(statements[2], intType, intType);
-
-    assertVariableDeclarationStatementTypes(statements[3], intType, intType);
-    assertAssignmentStatementTypes(statements[4], intType, stringType);
-    assertAssignmentStatementTypes(statements[5], intType, intType);
-
-    assertVariableDeclarationStatementTypes(statements[6], intType, intType);
-    assertAssignmentStatementTypes(statements[7], intType, stringType);
-    assertAssignmentStatementTypes(statements[8], intType, intType);
-
-    assertVariableDeclarationTypes(
-        getTopLevelVariable(unit, "x"), intType, intType);
-    assertVariableDeclarationTypes(
-        getTopLevelVariable(unit, "y"), intType, intType);
-    assertVariableDeclarationTypes(
-        getTopLevelVariable(unit, "z"), intType, intType);
-  }
-
-  // Test that inference does not propagate from null
-  void test_perform_inference_null() {
-    AnalysisTarget source = newSource(
-        '/test.dart',
-        '''
-      var x = null;
-      var y = 3;
-      class A {
-        static var x = null;
-        static var y = 3;
-
-        var x2 = null;
-        var y2 = 3;
-      }
-
-      test() {
-        x = "hi";
-        y = /*severe:StaticTypeError*/"hi";
-        A.x = "hi";
-        A.y = /*severe:StaticTypeError*/"hi";
-        new A().x2 = "hi";
-        new A().y2 = /*severe:StaticTypeError*/"hi";
-      }
-''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
-    CompilationUnit unit = outputs[RESOLVED_UNIT8];
-
-    InterfaceType intType = context.typeProvider.intType;
-    InterfaceType stringType = context.typeProvider.stringType;
-    DartType bottomType = context.typeProvider.bottomType;
-    DartType dynamicType = context.typeProvider.dynamicType;
-
-    assertVariableDeclarationTypes(
-        getTopLevelVariable(unit, "x"), dynamicType, bottomType);
-    assertVariableDeclarationTypes(
-        getTopLevelVariable(unit, "y"), intType, intType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit, "A", "x"), dynamicType, bottomType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit, "A", "y"), intType, intType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit, "A", "x2"), dynamicType, bottomType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit, "A", "y2"), intType, intType);
-
-    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
-
-    assertAssignmentStatementTypes(statements[0], dynamicType, stringType);
-    assertAssignmentStatementTypes(statements[1], intType, stringType);
-    assertAssignmentStatementTypes(statements[2], dynamicType, stringType);
-    assertAssignmentStatementTypes(statements[3], intType, stringType);
-    assertAssignmentStatementTypes(statements[4], dynamicType, stringType);
-    assertAssignmentStatementTypes(statements[5], intType, stringType);
-  }
-
-  // Test inference across units (non-cyclic)
-  void test_perform_inference_cross_unit_non_cyclic() {
-    AnalysisTarget firstSource = newSource(
-        '/a.dart',
-        '''
-          var x = 2;
-          class A { static var x = 2; }
-''');
-    AnalysisTarget secondSource = newSource(
-        '/test.dart',
-        '''
-          import 'a.dart';
-          var y = x;
-          class B { static var y = A.x; }
-
-          test1() {
-            x = /*severe:StaticTypeError*/"hi";
-            y = /*severe:StaticTypeError*/"hi";
-            A.x = /*severe:StaticTypeError*/"hi";
-            B.y = /*severe:StaticTypeError*/"hi";
-          }
-''');
-    computeResult(
-        new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT8);
-    CompilationUnit unit1 = outputs[RESOLVED_UNIT8];
-    computeResult(
-        new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT8);
-    CompilationUnit unit2 = outputs[RESOLVED_UNIT8];
-
-    InterfaceType intType = context.typeProvider.intType;
-    InterfaceType stringType = context.typeProvider.stringType;
-    DartType dynamicType = context.typeProvider.dynamicType;
-
-    assertVariableDeclarationTypes(
-        getTopLevelVariable(unit1, "x"), intType, intType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "A", "x"), intType, intType);
-
-    assertVariableDeclarationTypes(
-        getTopLevelVariable(unit2, "y"), intType, intType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit2, "B", "y"), intType, intType);
-
-    List<Statement> statements =
-        getStatementsInTopLevelFunction(unit2, "test1");
-
-    assertAssignmentStatementTypes(statements[0], intType, stringType);
-    assertAssignmentStatementTypes(statements[1], intType, stringType);
-  }
-
-  // Test inference across units (cyclic)
-  void test_perform_inference_cross_unit_cyclic() {
-    AnalysisTarget firstSource = newSource(
-        '/a.dart',
-        '''
-          import 'test.dart';
-          var x = 2;
-          class A { static var x = 2; }
-''');
-    AnalysisTarget secondSource = newSource(
-        '/test.dart',
-        '''
-          import 'a.dart';
-          var y = x;
-          class B { static var y = A.x; }
-
-          test1() {
-            int t = 3;
-            t = x;
-            t = y;
-            t = A.x;
-            t = B.y;
-          }
-''');
-    computeResult(
-        new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT8);
-    CompilationUnit unit1 = outputs[RESOLVED_UNIT8];
-    computeResult(
-        new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT8);
-    CompilationUnit unit2 = outputs[RESOLVED_UNIT8];
-
-    InterfaceType intType = context.typeProvider.intType;
-    InterfaceType stringType = context.typeProvider.stringType;
-
-    assertVariableDeclarationTypes(
-        getTopLevelVariable(unit1, "x"), intType, intType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "A", "x"), intType, intType);
-
-    assertVariableDeclarationTypes(
-        getTopLevelVariable(unit2, "y"), intType, intType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit2, "B", "y"), intType, intType);
-
-    List<Statement> statements =
-        getStatementsInTopLevelFunction(unit2, "test1");
-
-    assertAssignmentStatementTypes(statements[1], intType, intType);
-    assertAssignmentStatementTypes(statements[2], intType, intType);
-    assertAssignmentStatementTypes(statements[3], intType, intType);
-    assertAssignmentStatementTypes(statements[4], intType, intType);
-  }
-
-  // Test inference of instance fields across units
-  // TODO(leafp): Fix this
-  // https://github.com/dart-lang/dev_compiler/issues/354
-  void fail_perform_inference_cross_unit_instance() {
-    List<Source> sources = newSources({
-      '/a7.dart': '''
-          import 'b7.dart';
-          class A {
-            final a2 = new B().b2;
-          }
-      ''',
-      '/b7.dart': '''
-          class B {
-            final b2 = 1;
-          }
-      ''',
-      '/main7.dart': '''
-          import "a7.dart";
-
-          test1() {
-            int x = 0;
-            x = new A().a2;
-          }
-    '''
-    });
-    List<dynamic> units =
-        computeLibraryResults(sources, RESOLVED_UNIT8).toList();
-    CompilationUnit unit0 = units[0];
-    CompilationUnit unit1 = units[1];
-    CompilationUnit unit2 = units[2];
-
-    InterfaceType intType = context.typeProvider.intType;
-
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a2"), intType, intType);
-
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "B", "b2"), intType, intType);
-
-    List<Statement> statements =
-        getStatementsInTopLevelFunction(unit2, "test1");
-
-    assertAssignmentStatementTypes(statements[1], intType, intType);
-  }
-
-  // Test inference between static and instance fields
-  // TODO(leafp): Fix this
-  // https://github.com/dart-lang/dev_compiler/issues/354
-  void fail_perform_inference_cross_unit_static_instance() {
-    List<Source> sources = newSources({
-      '/a.dart': '''
-          import 'b.dart';
-          class A {
-            static final a1 = B.b1;
-            final a2 = new B().b2;
-          }
-      ''',
-      '/b.dart': '''
-          class B {
-            static final b1 = 1;
-            final b2 = 1;
-          }
-      ''',
-      '/main.dart': '''
-          import "a.dart";
-
-          test1() {
-            int x = 0;
-            // inference in A now works.
-            x = A.a1;
-            x = new A().a2;
-          }
-    '''
-    });
-    List<dynamic> units =
-        computeLibraryResults(sources, RESOLVED_UNIT8).toList();
-    CompilationUnit unit0 = units[0];
-    CompilationUnit unit1 = units[1];
-    CompilationUnit unit2 = units[2];
-
-    InterfaceType intType = context.typeProvider.intType;
-
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a1"), intType, intType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a2"), intType, intType);
-
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "B", "b1"), intType, intType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "B", "b2"), intType, intType);
-
-    List<Statement> statements =
-        getStatementsInTopLevelFunction(unit2, "test1");
-
-    assertAssignmentStatementTypes(statements[1], intType, intType);
-    assertAssignmentStatementTypes(statements[2], intType, intType);
-  }
-}
-
-@reflectiveTest
 class ResolveLibraryTypeNamesTaskTest extends _AbstractDartTaskTest {
   test_perform() {
     Source sourceLib = newSource(
@@ -3338,6 +2933,469 @@
 }
 
 @reflectiveTest
+class StrongModeInferenceTest extends _AbstractDartTaskTest {
+  void assertAssignmentStatementTypes(
+      Statement stmt, DartType leftType, DartType rightType) {
+    AssignmentExpression assgn = (stmt as ExpressionStatement).expression;
+    expect(assgn.leftHandSide.staticType, leftType);
+    expect(assgn.rightHandSide.staticType, rightType);
+  }
+
+  // Check that even within a static variable cycle, inferred
+  // types get propagated to the members of the cycle.
+  void assertVariableDeclarationStatementTypes(
+      Statement stmt, DartType varType, DartType initializerType) {
+    VariableDeclaration decl =
+        (stmt as VariableDeclarationStatement).variables.variables[0];
+    assertVariableDeclarationTypes(decl, varType, initializerType);
+  }
+
+  void assertVariableDeclarationTypes(
+      VariableDeclaration decl, DartType varType, DartType initializerType) {
+    expect(decl.element.type, varType);
+    expect(decl.initializer.staticType, initializerType);
+  }
+
+  void fail_perform_inference_cross_unit_instance() {
+    List<Source> sources = newSources({
+      '/a7.dart': '''
+          import 'b7.dart';
+          class A {
+            final a2 = new B().b2;
+          }
+      ''',
+      '/b7.dart': '''
+          class B {
+            final b2 = 1;
+          }
+      ''',
+      '/main7.dart': '''
+          import "a7.dart";
+
+          test1() {
+            int x = 0;
+            x = new A().a2;
+          }
+    '''
+    });
+    List<dynamic> units =
+        computeLibraryResults(sources, RESOLVED_UNIT8).toList();
+    CompilationUnit unit0 = units[0];
+    CompilationUnit unit1 = units[1];
+    CompilationUnit unit2 = units[2];
+
+    InterfaceType intType = context.typeProvider.intType;
+
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit0, "A", "a2"), intType, intType);
+
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit1, "B", "b2"), intType, intType);
+
+    List<Statement> statements =
+        getStatementsInTopLevelFunction(unit2, "test1");
+
+    assertAssignmentStatementTypes(statements[1], intType, intType);
+  }
+
+  void fail_perform_inference_cross_unit_static_instance() {
+    List<Source> sources = newSources({
+      '/a.dart': '''
+          import 'b.dart';
+          class A {
+            static final a1 = B.b1;
+            final a2 = new B().b2;
+          }
+      ''',
+      '/b.dart': '''
+          class B {
+            static final b1 = 1;
+            final b2 = 1;
+          }
+      ''',
+      '/main.dart': '''
+          import "a.dart";
+
+          test1() {
+            int x = 0;
+            // inference in A now works.
+            x = A.a1;
+            x = new A().a2;
+          }
+    '''
+    });
+    List<dynamic> units =
+        computeLibraryResults(sources, RESOLVED_UNIT8).toList();
+    CompilationUnit unit0 = units[0];
+    CompilationUnit unit1 = units[1];
+    CompilationUnit unit2 = units[2];
+
+    InterfaceType intType = context.typeProvider.intType;
+
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit0, "A", "a1"), intType, intType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit0, "A", "a2"), intType, intType);
+
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit1, "B", "b1"), intType, intType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit1, "B", "b2"), intType, intType);
+
+    List<Statement> statements =
+        getStatementsInTopLevelFunction(unit2, "test1");
+
+    assertAssignmentStatementTypes(statements[1], intType, intType);
+    assertAssignmentStatementTypes(statements[2], intType, intType);
+  }
+
+  @override
+  void setUp() {
+    super.setUp();
+    enableStrongMode();
+  }
+
+  // Test that local variables in method bodies are inferred appropriately
+  void test_perform_cycle() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+var piFirst = true;
+var pi = piFirst ? 3.14 : tau / 2;
+var tau = piFirst ? pi * 2 : 6.28;
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
+    CompilationUnit unit = outputs[RESOLVED_UNIT8];
+    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;
+
+    expect(piFirstUse.staticType, context.typeProvider.boolType);
+    expect(piFirst.type, context.typeProvider.boolType);
+    expect(pi.type.isDynamic, isTrue);
+    expect(tau.type.isDynamic, isTrue);
+  }
+
+  // Test inference interactions between local variables and fields
+  void test_perform_inference_cross_unit_cyclic() {
+    AnalysisTarget firstSource = newSource(
+        '/a.dart',
+        '''
+          import 'test.dart';
+          var x = 2;
+          class A { static var x = 2; }
+''');
+    AnalysisTarget secondSource = newSource(
+        '/test.dart',
+        '''
+          import 'a.dart';
+          var y = x;
+          class B { static var y = A.x; }
+
+          test1() {
+            int t = 3;
+            t = x;
+            t = y;
+            t = A.x;
+            t = B.y;
+          }
+''');
+    computeResult(
+        new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT8);
+    CompilationUnit unit1 = outputs[RESOLVED_UNIT8];
+    computeResult(
+        new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT8);
+    CompilationUnit unit2 = outputs[RESOLVED_UNIT8];
+
+    InterfaceType intType = context.typeProvider.intType;
+
+    assertVariableDeclarationTypes(
+        getTopLevelVariable(unit1, "x"), intType, intType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit1, "A", "x"), intType, intType);
+
+    assertVariableDeclarationTypes(
+        getTopLevelVariable(unit2, "y"), intType, intType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit2, "B", "y"), intType, intType);
+
+    List<Statement> statements =
+        getStatementsInTopLevelFunction(unit2, "test1");
+
+    assertAssignmentStatementTypes(statements[1], intType, intType);
+    assertAssignmentStatementTypes(statements[2], intType, intType);
+    assertAssignmentStatementTypes(statements[3], intType, intType);
+    assertAssignmentStatementTypes(statements[4], intType, intType);
+  }
+
+  // Test inference interactions between local variables and top level
+  // variables
+  void test_perform_inference_cross_unit_non_cyclic() {
+    AnalysisTarget firstSource = newSource(
+        '/a.dart',
+        '''
+          var x = 2;
+          class A { static var x = 2; }
+''');
+    AnalysisTarget secondSource = newSource(
+        '/test.dart',
+        '''
+          import 'a.dart';
+          var y = x;
+          class B { static var y = A.x; }
+
+          test1() {
+            x = /*severe:StaticTypeError*/"hi";
+            y = /*severe:StaticTypeError*/"hi";
+            A.x = /*severe:StaticTypeError*/"hi";
+            B.y = /*severe:StaticTypeError*/"hi";
+          }
+''');
+    computeResult(
+        new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT8);
+    CompilationUnit unit1 = outputs[RESOLVED_UNIT8];
+    computeResult(
+        new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT8);
+    CompilationUnit unit2 = outputs[RESOLVED_UNIT8];
+
+    InterfaceType intType = context.typeProvider.intType;
+    InterfaceType stringType = context.typeProvider.stringType;
+
+    assertVariableDeclarationTypes(
+        getTopLevelVariable(unit1, "x"), intType, intType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit1, "A", "x"), intType, intType);
+
+    assertVariableDeclarationTypes(
+        getTopLevelVariable(unit2, "y"), intType, intType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit2, "B", "y"), intType, intType);
+
+    List<Statement> statements =
+        getStatementsInTopLevelFunction(unit2, "test1");
+
+    assertAssignmentStatementTypes(statements[0], intType, stringType);
+    assertAssignmentStatementTypes(statements[1], intType, stringType);
+  }
+
+  // Test that inference does not propagate from null
+  void test_perform_inference_local_variables() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+      test() {
+        int x = 3;
+        x = "hi";
+        var y = 3;
+        y = "hi";
+      }
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
+    CompilationUnit unit = outputs[RESOLVED_UNIT8];
+
+    InterfaceType intType = context.typeProvider.intType;
+    InterfaceType stringType = context.typeProvider.stringType;
+
+    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
+
+    assertVariableDeclarationStatementTypes(statements[0], intType, intType);
+    assertAssignmentStatementTypes(statements[1], intType, stringType);
+    assertVariableDeclarationStatementTypes(statements[2], intType, intType);
+    assertAssignmentStatementTypes(statements[3], intType, stringType);
+  }
+
+  // Test inference across units (non-cyclic)
+  void test_perform_inference_local_variables_fields() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+      class A {
+        int x = 0;
+
+        test1() {
+          var a = x;
+          a = "hi";
+          a = 3;
+          var b = y;
+          b = "hi";
+          b = 4;
+          var c = z;
+          c = "hi";
+          c = 4;
+        }
+
+        int y; // field def after use
+        final z = 42; // should infer `int`
+      }
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
+    CompilationUnit unit = outputs[RESOLVED_UNIT8];
+
+    InterfaceType intType = context.typeProvider.intType;
+    InterfaceType stringType = context.typeProvider.stringType;
+
+    List<Statement> statements = getStatementsInMethod(unit, "A", "test1");
+
+    assertVariableDeclarationStatementTypes(statements[0], intType, intType);
+    assertAssignmentStatementTypes(statements[1], intType, stringType);
+    assertAssignmentStatementTypes(statements[2], intType, intType);
+
+    assertVariableDeclarationStatementTypes(statements[3], intType, intType);
+    assertAssignmentStatementTypes(statements[4], intType, stringType);
+    assertAssignmentStatementTypes(statements[5], intType, intType);
+
+    assertVariableDeclarationStatementTypes(statements[6], intType, intType);
+    assertAssignmentStatementTypes(statements[7], intType, stringType);
+    assertAssignmentStatementTypes(statements[8], intType, intType);
+
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit, "A", "x"), intType, intType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit, "A", "z"), intType, intType);
+  }
+
+  // Test inference across units (cyclic)
+  void test_perform_inference_local_variables_topLevel() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+      int x = 0;
+
+      test1() {
+        var a = x;
+        a = /*severe:StaticTypeError*/"hi";
+        a = 3;
+        var b = y;
+        b = /*severe:StaticTypeError*/"hi";
+        b = 4;
+        var c = z;
+        c = /*severe:StaticTypeError*/"hi";
+        c = 4;
+      }
+
+      int y = 0; // field def after use
+      final z = 42; // should infer `int`
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
+    CompilationUnit unit = outputs[RESOLVED_UNIT8];
+
+    InterfaceType intType = context.typeProvider.intType;
+    InterfaceType stringType = context.typeProvider.stringType;
+
+    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test1");
+
+    assertVariableDeclarationStatementTypes(statements[0], intType, intType);
+    assertAssignmentStatementTypes(statements[1], intType, stringType);
+    assertAssignmentStatementTypes(statements[2], intType, intType);
+
+    assertVariableDeclarationStatementTypes(statements[3], intType, intType);
+    assertAssignmentStatementTypes(statements[4], intType, stringType);
+    assertAssignmentStatementTypes(statements[5], intType, intType);
+
+    assertVariableDeclarationStatementTypes(statements[6], intType, intType);
+    assertAssignmentStatementTypes(statements[7], intType, stringType);
+    assertAssignmentStatementTypes(statements[8], intType, intType);
+
+    assertVariableDeclarationTypes(
+        getTopLevelVariable(unit, "x"), intType, intType);
+    assertVariableDeclarationTypes(
+        getTopLevelVariable(unit, "y"), intType, intType);
+    assertVariableDeclarationTypes(
+        getTopLevelVariable(unit, "z"), intType, intType);
+  }
+
+  // Test inference of instance fields across units
+  // TODO(leafp): Fix this
+  // https://github.com/dart-lang/dev_compiler/issues/354
+  void test_perform_inference_null() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+      var x = null;
+      var y = 3;
+      class A {
+        static var x = null;
+        static var y = 3;
+
+        var x2 = null;
+        var y2 = 3;
+      }
+
+      test() {
+        x = "hi";
+        y = /*severe:StaticTypeError*/"hi";
+        A.x = "hi";
+        A.y = /*severe:StaticTypeError*/"hi";
+        new A().x2 = "hi";
+        new A().y2 = /*severe:StaticTypeError*/"hi";
+      }
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
+    CompilationUnit unit = outputs[RESOLVED_UNIT8];
+
+    InterfaceType intType = context.typeProvider.intType;
+    InterfaceType stringType = context.typeProvider.stringType;
+    DartType bottomType = context.typeProvider.bottomType;
+    DartType dynamicType = context.typeProvider.dynamicType;
+
+    assertVariableDeclarationTypes(
+        getTopLevelVariable(unit, "x"), dynamicType, bottomType);
+    assertVariableDeclarationTypes(
+        getTopLevelVariable(unit, "y"), intType, intType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit, "A", "x"), dynamicType, bottomType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit, "A", "y"), intType, intType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit, "A", "x2"), dynamicType, bottomType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit, "A", "y2"), intType, intType);
+
+    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
+
+    assertAssignmentStatementTypes(statements[0], dynamicType, stringType);
+    assertAssignmentStatementTypes(statements[1], intType, stringType);
+    assertAssignmentStatementTypes(statements[2], dynamicType, stringType);
+    assertAssignmentStatementTypes(statements[3], intType, stringType);
+    assertAssignmentStatementTypes(statements[4], dynamicType, stringType);
+    assertAssignmentStatementTypes(statements[5], intType, stringType);
+  }
+
+  // Test inference between static and instance fields
+  // TODO(leafp): Fix this
+  // https://github.com/dart-lang/dev_compiler/issues/354
+  void test_perform_local_explicit_disabled() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+      test() {
+        int x = 3;
+        x = "hi";
+      }
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
+    CompilationUnit unit = outputs[RESOLVED_UNIT8];
+
+    InterfaceType intType = context.typeProvider.intType;
+    InterfaceType stringType = context.typeProvider.stringType;
+
+    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
+    VariableDeclaration decl =
+        (statements[0] as VariableDeclarationStatement).variables.variables[0];
+    expect(decl.element.type, intType);
+    expect(decl.initializer.staticType, intType);
+
+    ExpressionStatement statement = statements[1];
+    AssignmentExpression assgn = statement.expression;
+    expect(assgn.leftHandSide.staticType, intType);
+    expect(assgn.rightHandSide.staticType, stringType);
+  }
+}
+
+@reflectiveTest
 class VerifyUnitTaskTest extends _AbstractDartTaskTest {
   test_perform_constantError() {
     Source source = newSource(
@@ -3370,6 +3428,23 @@
         <ErrorCode>[CompileTimeErrorCode.URI_DOES_NOT_EXIST]);
   }
 
+  void test_perform_reresolution() {
+    enableStrongMode();
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+const topLevel = 3;
+class C {
+  String field = topLevel;
+}
+''');
+    computeResult(new LibrarySpecificUnit(source, source), VERIFY_ERRORS);
+    // validate
+    _fillErrorListener(VERIFY_ERRORS);
+    errorListener.assertErrorsWithCodes(
+        <ErrorCode>[StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+  }
+
   test_perform_verifyError() {
     Source source = newSource(
         '/test.dart',
@@ -3387,23 +3462,6 @@
     errorListener.assertErrorsWithCodes(
         <ErrorCode>[StaticTypeWarningCode.NON_BOOL_CONDITION]);
   }
-
-  void test_perform_reresolution() {
-    enableStrongMode();
-    AnalysisTarget source = newSource(
-        '/test.dart',
-        '''
-const topLevel = 3;
-class C {
-  String field = topLevel;
-}
-''');
-    computeResult(new LibrarySpecificUnit(source, source), VERIFY_ERRORS);
-    // validate
-    _fillErrorListener(VERIFY_ERRORS);
-    errorListener.assertErrorsWithCodes(
-        <ErrorCode>[StaticTypeWarningCode.INVALID_ASSIGNMENT]);
-  }
 }
 
 class _AbstractDartTaskTest extends AbstractContextTest {
@@ -3540,6 +3598,23 @@
   }
 
   /**
+   * 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].
    */
@@ -3560,23 +3635,6 @@
     return null;
   }
 
-  /**
-   * 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;
-  }
-
   void setUp() {
     super.setUp();
     emptySource = newSource('/test.dart');
diff --git a/pkg/analyzer/test/src/task/inputs_test.dart b/pkg/analyzer/test/src/task/inputs_test.dart
index 35e4660..3943a99 100644
--- a/pkg/analyzer/test/src/task/inputs_test.dart
+++ b/pkg/analyzer/test/src/task/inputs_test.dart
@@ -15,6 +15,8 @@
 
 main() {
   initializeTestEnvironment();
+  runReflectiveTests(ConstantTaskInputBuilderTest);
+  runReflectiveTests(ConstantTaskInputTest);
   runReflectiveTests(ListTaskInputImplTest);
   runReflectiveTests(ListToListTaskInputTest);
   runReflectiveTests(ListToListTaskInputBuilderTest);
@@ -28,6 +30,96 @@
 }
 
 @reflectiveTest
+class ConstantTaskInputBuilderTest extends EngineTestCase {
+  static final int value = 7;
+  static final ConstantTaskInput<int> input = new ConstantTaskInput<int>(value);
+
+  ConstantTaskInputBuilder builder;
+
+  void setUp() {
+    builder = new ConstantTaskInputBuilder(input);
+  }
+
+  test_create() {
+    expect(builder, isNotNull);
+    expect(builder.input, input);
+  }
+
+  test_currentResult_afterOneMoveNext() {
+    builder.moveNext();
+    expect(builder.currentResult, null);
+  }
+
+  test_currentResult_beforeMoveNext() {
+    expect(builder.currentResult, null);
+  }
+
+  test_currentTarget_afterOneMoveNext() {
+    builder.moveNext();
+    expect(builder.currentTarget, null);
+  }
+
+  test_currentTarget_beforeMoveNext() {
+    expect(builder.currentTarget, null);
+  }
+
+  test_currentValue_afterOneMoveNext() {
+    builder.moveNext();
+    expect(() {
+      builder.currentValue = 'value';
+    }, throwsStateError);
+  }
+
+  test_currentValue_beforeMoveNext() {
+    expect(() {
+      builder.currentValue = 'value';
+    }, throwsStateError);
+  }
+
+  test_currentValueNotAvailable_afterOneMoveNext() {
+    builder.moveNext();
+    expect(() {
+      builder.currentValueNotAvailable();
+    }, throwsStateError);
+  }
+
+  test_currentValueNotAvailable_beforeMoveNext() {
+    expect(() {
+      builder.currentValueNotAvailable();
+    }, throwsStateError);
+  }
+
+  test_inputValue_afterOneMoveNext() {
+    builder.moveNext();
+    expect(builder.inputValue, value);
+  }
+
+  test_inputValue_beforeMoveNext() {
+    expect(builder.inputValue, value);
+  }
+
+  test_moveNext() {
+    expect(builder.moveNext(), false);
+    expect(builder.moveNext(), false);
+  }
+}
+
+@reflectiveTest
+class ConstantTaskInputTest extends EngineTestCase {
+  test_create() {
+    int value = 3;
+    ConstantTaskInput<int> input = new ConstantTaskInput<int>(value);
+    expect(input, isNotNull);
+    expect(input.value, value);
+  }
+
+  test_createBuilder() {
+    ConstantTaskInput<int> input = new ConstantTaskInput<int>(5);
+    expect(input.createBuilder(), new isInstanceOf<ConstantTaskInputBuilder>());
+  }
+}
+
+@reflectiveTest
 class ListTaskInputImplTest extends EngineTestCase {
   static final AnalysisTarget target = new TestSource();
   static final result1 =
@@ -800,6 +892,21 @@
     expect(builder.currentResult, result1);
   }
 
+  test_currentResult_afterTwoMoveNext_withConstantInput() {
+    ConstantTaskInput<int> constantInput = new ConstantTaskInput<int>(11);
+    Map<String, TaskInput> inputDescriptors = {
+      'one': input1,
+      'constant': constantInput,
+      'two': input2
+    };
+    TopLevelTaskInputBuilder builder =
+        new TopLevelTaskInputBuilder(inputDescriptors);
+    builder.moveNext();
+    builder.currentValue = 'value1';
+    builder.moveNext();
+    expect(builder.currentResult, result2);
+  }
+
   test_currentResult_beforeMoveNext() {
     Map<String, TaskInput> inputDescriptors = {};
     TopLevelTaskInputBuilder builder =
@@ -835,6 +942,21 @@
     expect(builder.currentTarget, target);
   }
 
+  test_currentTarget_afterTwoMoveNext_withConstantInput() {
+    ConstantTaskInput<int> constantInput = new ConstantTaskInput<int>(11);
+    Map<String, TaskInput> inputDescriptors = {
+      'one': input1,
+      'constant': constantInput,
+      'two': input2
+    };
+    TopLevelTaskInputBuilder builder =
+        new TopLevelTaskInputBuilder(inputDescriptors);
+    builder.moveNext();
+    builder.currentValue = 'value1';
+    builder.moveNext();
+    expect(builder.currentTarget, target);
+  }
+
   test_currentTarget_beforeMoveNext() {
     Map<String, TaskInput> inputDescriptors = {};
     TopLevelTaskInputBuilder builder =
diff --git a/pkg/analyzer/test/src/task/strong_mode_test.dart b/pkg/analyzer/test/src/task/strong_mode_test.dart
index fbbbae6..ff87d92 100644
--- a/pkg/analyzer/test/src/task/strong_mode_test.dart
+++ b/pkg/analyzer/test/src/task/strong_mode_test.dart
@@ -252,9 +252,6 @@
   final $fieldName = 0;
 }
 ''');
-    ClassElement classA = unit.getType('A');
-    FieldElement fieldA = classA.getField(fieldName);
-    PropertyAccessorElement getterA = classA.getGetter(fieldName);
     ClassElement classB = unit.getType('B');
     FieldElement fieldB = classB.getField(fieldName);
     PropertyAccessorElement getterB = classB.getGetter(fieldName);
@@ -564,7 +561,6 @@
 }
 ''');
     ClassElement classA = unit.getType('A');
-    FieldElement fieldA = classA.getField(getterName);
     PropertyAccessorElement setterA = classA.getSetter(getterName);
     ClassElement classB = unit.getType('B');
     FieldElement fieldB = classB.getField(getterName);
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index 7f5ce65..e515631 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -24,7 +24,8 @@
     GenericTask;
 import 'compiler.dart' as leg;
 import 'diagnostics/diagnostic_listener.dart' show
-    DiagnosticMessage;
+    DiagnosticMessage,
+    DiagnosticOptions;
 import 'diagnostics/messages.dart';
 import 'diagnostics/source_span.dart' show
     SourceSpan;
@@ -90,8 +91,6 @@
             analyzeSignaturesOnly:
                 hasOption(options, Flags.analyzeSignaturesOnly),
             strips: extractCsvOption(options, '--force-strip='),
-            enableConcreteTypeInference:
-                hasOption(options, Flags.enableConcreteTypeInference),
             disableTypeInferenceFlag:
                 hasOption(options, Flags.disableTypeInference),
             preserveComments: hasOption(options, Flags.preserveComments),
@@ -99,22 +98,24 @@
             verbose: hasOption(options, Flags.verbose),
             sourceMapUri: extractUriOption(options, '--source-map='),
             outputUri: extractUriOption(options, '--out='),
-            terseDiagnostics: hasOption(options, Flags.terse),
             deferredMapUri: extractUriOption(options, '--deferred-map='),
             dumpInfo: hasOption(options, Flags.dumpInfo),
             buildId: extractStringOption(
                 options, '--build-id=',
                 "build number could not be determined"),
-            showPackageWarnings:
-                hasOption(options, Flags.showPackageWarnings),
             useContentSecurityPolicy:
               hasOption(options, Flags.useContentSecurityPolicy),
             useStartupEmitter: hasOption(options, Flags.fastStartup),
             hasIncrementalSupport:
                 forceIncrementalSupport ||
                 hasOption(options, Flags.incrementalSupport),
-            suppressWarnings: hasOption(options, Flags.suppressWarnings),
-            fatalWarnings: hasOption(options, Flags.fatalWarnings),
+            diagnosticOptions: new DiagnosticOptions(
+                suppressWarnings: hasOption(options, Flags.suppressWarnings),
+                fatalWarnings: hasOption(options, Flags.fatalWarnings),
+                suppressHints: hasOption(options, Flags.suppressHints),
+                terseDiagnostics: hasOption(options, Flags.terse),
+                showPackageWarnings:
+                    hasOption(options, Flags.showPackageWarnings)),
             enableExperimentalMirrors:
                 hasOption(options, Flags.enableExperimentalMirrors),
             enableAssertMessage:
@@ -237,7 +238,7 @@
   Future<Script> readScript(Spannable node, Uri readableUri) {
     if (!readableUri.isAbsolute) {
       if (node == null) node = NO_LOCATION_SPANNABLE;
-      internalError(node,
+      reporter.internalError(node,
           'Relative uri $readableUri provided to readScript(Uri).');
     }
 
@@ -247,13 +248,13 @@
     elements.Element element = currentElement;
     void reportReadError(exception) {
       if (element == null || node == null) {
-        reportErrorMessage(
+        reporter.reportErrorMessage(
             new SourceSpan(readableUri, 0, 0),
             MessageKind.READ_SELF_ERROR,
             {'uri': readableUri, 'exception': exception});
       } else {
-        withCurrentElement(element, () {
-          reportErrorMessage(
+        reporter.withCurrentElement(element, () {
+          reporter.reportErrorMessage(
               node,
               MessageKind.READ_SCRIPT_ERROR,
               {'uri': readableUri, 'exception': exception});
@@ -265,8 +266,8 @@
     if (resourceUri == null) return synthesizeScript(node, readableUri);
     if (resourceUri.scheme == 'dart-ext') {
       if (!allowNativeExtensions) {
-        withCurrentElement(element, () {
-          reportErrorMessage(
+        reporter.withCurrentElement(element, () {
+          reporter.reportErrorMessage(
               node, MessageKind.DART_EXT_NOT_SUPPORTED);
         });
       }
@@ -337,13 +338,13 @@
       }
       if (!allowInternalLibraryAccess) {
         if (importingLibrary != null) {
-          reportErrorMessage(
+          reporter.reportErrorMessage(
               spannable,
               MessageKind.INTERNAL_LIBRARY_FROM,
               {'resolvedUri': resolvedUri,
                'importingUri': importingLibrary.canonicalUri});
         } else {
-          reportErrorMessage(
+          reporter.reportErrorMessage(
               spannable,
               MessageKind.INTERNAL_LIBRARY,
               {'resolvedUri': resolvedUri});
@@ -352,12 +353,12 @@
     }
     if (path == null) {
       if (libraryInfo == null) {
-        reportErrorMessage(
+        reporter.reportErrorMessage(
             spannable,
             MessageKind.LIBRARY_NOT_FOUND,
             {'resolvedUri': resolvedUri});
       } else {
-        reportErrorMessage(
+        reporter.reportErrorMessage(
             spannable,
             MessageKind.LIBRARY_NOT_SUPPORTED,
             {'resolvedUri': resolvedUri});
@@ -385,7 +386,7 @@
     try {
       checkValidPackageUri(uri);
     } on ArgumentError catch (e) {
-      reportErrorMessage(
+      reporter.reportErrorMessage(
           node,
           MessageKind.INVALID_PACKAGE_URI,
           {'uri': uri, 'exception': e.message});
@@ -393,7 +394,7 @@
     }
     return packages.resolve(uri,
         notFound: (Uri notFound) {
-          reportErrorMessage(
+          reporter.reportErrorMessage(
               node,
               MessageKind.LIBRARY_NOT_FOUND,
               {'resolvedUri': uri});
@@ -431,7 +432,7 @@
         packages =
             new MapPackages(pkgs.parse(packageConfigContents, packageConfig));
       }).catchError((error) {
-        reportErrorMessage(
+        reporter.reportErrorMessage(
             NO_LOCATION_SPANNABLE,
             MessageKind.INVALID_PACKAGE_CONFIG,
             {'uri': packageConfig, 'exception': error});
@@ -479,9 +480,11 @@
   void reportDiagnostic(DiagnosticMessage message,
                         List<DiagnosticMessage> infos,
                         api.Diagnostic kind) {
+    // TODO(johnniwinther): Move this to the [DiagnosticReporter]?
     if (kind == api.Diagnostic.ERROR ||
         kind == api.Diagnostic.CRASH ||
-        (fatalWarnings && kind == api.Diagnostic.WARNING)) {
+        (reporter.options.fatalWarnings &&
+         kind == api.Diagnostic.WARNING)) {
       compilationFailed = true;
     }
     _reportDiagnosticMessage(message, kind);
@@ -541,11 +544,6 @@
     }
   }
 
-  void diagnoseCrashInUserCode(String message, exception, stackTrace) {
-    hasCrashed = true;
-    print('$message: ${tryToString(exception)}');
-    print(tryToString(stackTrace));
-  }
 
   fromEnvironment(String name) => environment[name];
 
diff --git a/pkg/compiler/lib/src/closure.dart b/pkg/compiler/lib/src/closure.dart
index 0f8f218..b0fff43 100644
--- a/pkg/compiler/lib/src/closure.dart
+++ b/pkg/compiler/lib/src/closure.dart
@@ -6,6 +6,9 @@
 
 import 'common/names.dart' show
     Identifiers;
+import 'common/resolution.dart' show
+    Parsing,
+    Resolution;
 import 'common/tasks.dart' show
     CompilerTask;
 import 'compiler.dart' show
@@ -75,7 +78,7 @@
     return measure(() {
       ClosureClassMap nestedClosureData = closureMappingCache[node];
       if (nestedClosureData == null) {
-        compiler.internalError(node, "No closure cache.");
+        reporter.internalError(node, "No closure cache.");
       }
       return nestedClosureData;
     });
@@ -140,7 +143,7 @@
   bool get isInstanceMember => true;
   bool get isAssignable => false;
 
-  DartType computeType(Compiler compiler) => type;
+  DartType computeType(Resolution resolution) => type;
 
   DartType get type {
     if (local is LocalElement) {
@@ -197,7 +200,7 @@
     ClassElement superclass = methodElement.isInstanceMember
         ? backend.boundClosureClass
         : backend.closureClass;
-    superclass.ensureResolved(compiler);
+    superclass.ensureResolved(compiler.resolution);
     supertype = superclass.thisType;
     interfaces = const Link<DartType>();
     thisType = rawType = new InterfaceType(this);
@@ -208,7 +211,7 @@
 
   Iterable<ClosureFieldElement> get closureFields => _closureFields;
 
-  void addField(ClosureFieldElement field, DiagnosticListener listener) {
+  void addField(ClosureFieldElement field, DiagnosticReporter listener) {
     _closureFields.add(field);
     addMember(field, listener);
   }
@@ -219,7 +222,7 @@
 
   Token get position => node.getBeginToken();
 
-  Node parseNode(DiagnosticListener listener) => node;
+  Node parseNode(Parsing parsing) => node;
 
   // A [ClosureClassElement] is nested inside a function or initializer in terms
   // of [enclosingElement], but still has to be treated as a top-level
@@ -252,7 +255,7 @@
       : this.box = box,
         super(name, ElementKind.FIELD, box.executableContext);
 
-  DartType computeType(Compiler compiler) => type;
+  DartType computeType(Resolution resolution) => type;
 
   DartType get type => variableElement.type;
 
@@ -315,7 +318,7 @@
       : expression = other,
         super(name, other.kind, other.modifiers, enclosing) {
     asyncMarker = other.asyncMarker;
-    functionSignatureCache = other.functionSignature;
+    functionSignature = other.functionSignature;
   }
 
   /// Use [closureClass] instead.
@@ -332,7 +335,7 @@
 
   FunctionExpression get node => expression.node;
 
-  FunctionExpression parseNode(DiagnosticListener listener) => node;
+  FunctionExpression parseNode(Parsing parsing) => node;
 
   ResolvedAst get resolvedAst {
     return new ResolvedAst(this, node, treeElements);
@@ -507,6 +510,8 @@
                     this.elements,
                     this.closureMappingCache);
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   /// Generate a unique name for the [id]th closure field, with proposed name
   /// [name].
   ///
@@ -539,7 +544,7 @@
 
   void addCapturedVariable(Node node, Local variable) {
     if (_capturedVariableMapping[variable] != null) {
-      compiler.internalError(node, 'In closure analyzer.');
+      reporter.internalError(node, 'In closure analyzer.');
     }
     _capturedVariableMapping[variable] = null;
   }
@@ -609,7 +614,7 @@
       void addClosureField(Local local, String name) {
         ClosureFieldElement closureField =
             new ClosureFieldElement(name, local, closureClass);
-        closureClass.addField(closureField, compiler);
+        closureClass.addField(closureField, reporter);
         data.freeVariableMap[local] = closureField;
       }
 
@@ -999,7 +1004,7 @@
         globalizedElement, callElement, element);
     MemberElement enclosing = element.memberContext;
     enclosing.nestedClosures.add(callElement);
-    globalizedElement.addMember(callElement, compiler);
+    globalizedElement.addMember(callElement, reporter);
     globalizedElement.computeAllClassMembers(compiler);
     // The nested function's 'this' is the same as the one for the outer
     // function. It could be [null] if we are inside a static method.
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 204bb2a..668cb28 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -19,8 +19,6 @@
   static const String dumpInfo = '--dump-info';
   static const String enableAssertMessage = '--assert-message';
   static const String enableCheckedMode = '--enable-checked-mode';
-  static const String enableConcreteTypeInference =
-      '--enable-concrete-type-inference';
   static const String enableDiagnosticColors = '--enable-diagnostic-colors';
   static const String enableExperimentalMirrors =
       '--enable-experimental-mirrors';
diff --git a/pkg/compiler/lib/src/common/backend_api.dart b/pkg/compiler/lib/src/common/backend_api.dart
index 487f01d..948fdba 100644
--- a/pkg/compiler/lib/src/common/backend_api.dart
+++ b/pkg/compiler/lib/src/common/backend_api.dart
@@ -11,6 +11,8 @@
 import '../compile_time_constants.dart' show
     BackendConstantEnvironment,
     ConstantCompilerTask;
+import '../constants/expressions.dart' show
+    ConstantExpression;
 import '../constants/constant_system.dart' show
     ConstantSystem;
 import '../constants/values.dart' show
@@ -48,6 +50,11 @@
     checkNativeAnnotation;
 import '../resolution/tree_elements.dart' show
     TreeElements;
+import '../tree/tree.dart' show
+    Node,
+    Send;
+import '../universe/call_structure.dart' show
+    CallStructure;
 
 import 'codegen.dart' show
     CodegenWorkItem;
@@ -220,7 +227,7 @@
   /// Call this method to enable support for isolates.
   void enableIsolateSupport(Enqueuer enqueuer) {}
 
-  void registerRequiredType(DartType type, Element enclosingElement) {}
+  void registerRequiredType(DartType type) {}
 
   void registerConstSymbol(String name, Registry registry) {}
   void registerNewSymbol(Registry registry) {}
@@ -375,5 +382,23 @@
   void registerAsyncMarker(FunctionElement element,
                            Enqueuer enqueuer,
                            Registry registry) {}
+
+  /// Called when resolving a call to a foreign function.
+  void registerForeignCall(Send node,
+                           Element element,
+                           CallStructure callStructure,
+                           ForeignResolver resolver) {}
 }
 
+/// Interface for resolving calls to foreign functions.
+abstract class ForeignResolver {
+  /// Returns the constant expression of [node], or `null` if [node] is not
+  /// a constant expression.
+  ConstantExpression getConstant(Node node);
+
+  /// Registers [type] as instantiated.
+  void registerInstantiatedType(InterfaceType type);
+
+  /// Resolves [typeName] to a type in the context of [node].
+  DartType resolveTypeFromString(Node node, String typeName);
+}
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index e220aab..e5554c9 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -191,7 +191,7 @@
     // generation could spuriously be adding dependencies on things we know we
     // don't need.
     assert(invariant(element,
-        compiler.enqueuer.resolution.hasBeenResolved(element),
+        compiler.enqueuer.resolution.hasBeenProcessed(element),
         message: "$element has not been resolved."));
     assert(invariant(element, element.resolvedAst.elements != null,
         message: 'Resolution tree is null for $element in codegen work item'));
diff --git a/pkg/compiler/lib/src/common/resolution.dart b/pkg/compiler/lib/src/common/resolution.dart
index 86a21bd..474b10e 100644
--- a/pkg/compiler/lib/src/common/resolution.dart
+++ b/pkg/compiler/lib/src/common/resolution.dart
@@ -1,3 +1,4 @@
+
 // 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.
@@ -6,18 +7,36 @@
 
 import '../compiler.dart' show
     Compiler;
+import '../core_types.dart' show
+    CoreTypes;
 import '../dart_types.dart' show
-    DartType;
+    DartType,
+    InterfaceType;
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import '../elements/elements.dart' show
     AstElement,
+    ClassElement,
+    Element,
     ErroneousElement,
+    FunctionElement,
+    FunctionSignature,
+    LocalFunctionElement,
+    MetadataAnnotation,
+    MethodElement,
+    TypedefElement,
     TypeVariableElement;
 import '../enqueue.dart' show
     ResolutionEnqueuer,
     WorldImpact;
 import '../tree/tree.dart' show
     AsyncForIn,
-    Send;
+    Send,
+    TypeAnnotation;
+import '../universe/universe.dart' show
+    UniverseSelector;
+import '../util/util.dart' show
+    Setlet;
 import 'registry.dart' show
     Registry;
 import 'work.dart' show
@@ -34,6 +53,7 @@
 
   WorldImpact run(Compiler compiler, ResolutionEnqueuer world) {
     WorldImpact impact = compiler.analyze(this, world);
+    impact = compiler.backend.resolutionCallbacks.transformImpact(impact);
     _isAnalyzed = true;
     return impact;
   }
@@ -41,8 +61,13 @@
   bool get isAnalyzed => _isAnalyzed;
 }
 
+// TODO(johnniwinther): Rename this to something like  `BackendResolutionApi`
+// and clean up the interface.
 /// Backend callbacks function specific to the resolution phase.
 class ResolutionCallbacks {
+  ///
+  WorldImpact transformImpact(ResolutionWorldImpact worldImpact) => worldImpact;
+
   /// Register that an assert has been seen.
   void onAssert(bool hasMessage, Registry registry) {}
 
@@ -120,3 +145,279 @@
   /// Called when resolving a prefix or postfix expression.
   void onIncDecOperation(Registry registry) {}
 }
+
+class ResolutionWorldImpact extends WorldImpact {
+  const ResolutionWorldImpact();
+
+  // TODO(johnniwinther): Remove this.
+  void registerDependency(Element element) {}
+
+  Iterable<Feature> get features => const <Feature>[];
+  Iterable<DartType> get requiredTypes => const <DartType>[];
+  Iterable<MapLiteralUse> get mapLiterals => const <MapLiteralUse>[];
+  Iterable<ListLiteralUse> get listLiterals => const <ListLiteralUse>[];
+  Iterable<DartType> get typeLiterals => const <DartType>[];
+  Iterable<String> get constSymbolNames => const <String>[];
+}
+
+/// A language feature seen during resolution.
+// TODO(johnniwinther): Should mirror usage be part of this?
+enum Feature {
+  /// Invocation of a generative construction on an abstract class.
+  ABSTRACT_CLASS_INSTANTIATION,
+  /// An assert statement with no message.
+  ASSERT,
+  /// An assert statement with a message.
+  ASSERT_WITH_MESSAGE,
+  /// A method with an `async` body modifier.
+  ASYNC,
+  /// An asynchronous for in statement like `await for (var e in i) {}`.
+  ASYNC_FOR_IN,
+  /// A method with an `async*` body modifier.
+  ASYNC_STAR,
+  /// A catch statement.
+  CATCH_STATEMENT,
+  /// A compile time error.
+  COMPILE_TIME_ERROR,
+  /// A fall through in a switch case.
+  FALL_THROUGH_ERROR,
+  /// A ++/-- operation.
+  INC_DEC_OPERATION,
+  /// A field whose initialization is not a constant.
+  LAZY_FIELD,
+  /// A call to `new Symbol`.
+  NEW_SYMBOL,
+  /// A catch clause with a variable for the stack trace.
+  STACK_TRACE_IN_CATCH,
+  /// String interpolation.
+  STRING_INTERPOLATION,
+  /// An implicit call to `super.noSuchMethod`, like calling an unresolved
+  /// super method.
+  SUPER_NO_SUCH_METHOD,
+  /// A redirection to the `Symbol` constructor.
+  SYMBOL_CONSTRUCTOR,
+  /// An synchronous for in statement, like `for (var e in i) {}`.
+  SYNC_FOR_IN,
+  /// A method with a `sync*` body modifier.
+  SYNC_STAR,
+  /// A throw expression.
+  THROW_EXPRESSION,
+  /// An implicit throw of a `NoSuchMethodError`, like calling an unresolved
+  /// static method.
+  THROW_NO_SUCH_METHOD,
+  /// An implicit throw of a runtime error, like
+  THROW_RUNTIME_ERROR,
+  /// The need for a type variable bound check, like instantiation of a generic
+  /// type whose type variable have non-trivial bounds.
+  TYPE_VARIABLE_BOUNDS_CHECK,
+}
+
+/// A use of a map literal seen during resolution.
+class MapLiteralUse {
+  final InterfaceType type;
+  final bool isConstant;
+  final bool isEmpty;
+
+  MapLiteralUse(this.type, {this.isConstant: false, this.isEmpty: false});
+
+  int get hashCode {
+    return
+        type.hashCode * 13 +
+        isConstant.hashCode * 17 +
+        isEmpty.hashCode * 19;
+  }
+
+  bool operator ==(other) {
+    if (identical(this, other)) return true;
+    if (other is! MapLiteralUse) return false;
+    return
+        type == other.type &&
+        isConstant == other.isConstant &&
+        isEmpty == other.isEmpty;
+  }
+}
+
+/// A use of a list literal seen during resolution.
+class ListLiteralUse {
+  final InterfaceType type;
+  final bool isConstant;
+  final bool isEmpty;
+
+  ListLiteralUse(this.type, {this.isConstant: false, this.isEmpty: false});
+
+  int get hashCode {
+    return
+        type.hashCode * 13 +
+        isConstant.hashCode * 17 +
+        isEmpty.hashCode * 19;
+  }
+
+  bool operator ==(other) {
+    if (identical(this, other)) return true;
+    if (other is! ListLiteralUse) return false;
+    return
+        type == other.type &&
+        isConstant == other.isConstant &&
+        isEmpty == other.isEmpty;
+  }
+}
+
+/// Mutable implementation of [WorldImpact] used to transform
+/// [ResolutionWorldImpact] to [WorldImpact].
+// TODO(johnniwinther): Remove [Registry] when dependency is tracked directly
+// on [WorldImpact].
+class TransformedWorldImpact implements WorldImpact, Registry {
+  final ResolutionWorldImpact worldImpact;
+
+  Setlet<Element> _staticUses;
+  Setlet<InterfaceType> _instantiatedTypes;
+  Setlet<UniverseSelector> _dynamicGetters;
+  Setlet<UniverseSelector> _dynamicInvocations;
+  Setlet<UniverseSelector> _dynamicSetters;
+
+  TransformedWorldImpact(this.worldImpact);
+
+  @override
+  Iterable<DartType> get asCasts => worldImpact.asCasts;
+
+  @override
+  Iterable<DartType> get checkedModeChecks => worldImpact.checkedModeChecks;
+
+  @override
+  Iterable<MethodElement> get closurizedFunctions {
+    return worldImpact.closurizedFunctions;
+  }
+
+  @override
+  Iterable<UniverseSelector> get dynamicGetters {
+    return _dynamicGetters != null
+        ? _dynamicGetters : worldImpact.dynamicGetters;
+  }
+
+  @override
+  Iterable<UniverseSelector> get dynamicInvocations {
+    return _dynamicInvocations != null
+        ? _dynamicInvocations : worldImpact.dynamicInvocations;
+  }
+
+  @override
+  Iterable<UniverseSelector> get dynamicSetters {
+    return _dynamicSetters != null
+        ? _dynamicSetters : worldImpact.dynamicSetters;
+  }
+
+  @override
+  Iterable<DartType> get isChecks => worldImpact.isChecks;
+
+  @override
+  Iterable<Element> get staticUses {
+    if (_staticUses == null) {
+      return worldImpact.staticUses;
+    }
+    return _staticUses;
+  }
+
+  @override
+  bool get isForResolution => true;
+
+  _unsupported(String message) => throw new UnsupportedError(message);
+
+  @override
+  Iterable<Element> get otherDependencies => _unsupported('otherDependencies');
+
+  // TODO(johnniwinther): Remove this.
+  @override
+  void registerAssert(bool hasMessage) => _unsupported('registerAssert');
+
+  @override
+  void registerDependency(Element element) {
+    worldImpact.registerDependency(element);
+  }
+
+  @override
+  void registerDynamicGetter(UniverseSelector selector) {
+    if (_dynamicGetters == null) {
+      _dynamicGetters = new Setlet<UniverseSelector>();
+      _dynamicGetters.addAll(worldImpact.dynamicGetters);
+    }
+    _dynamicGetters.add(selector);
+  }
+
+  @override
+  void registerDynamicInvocation(UniverseSelector selector) {
+    if (_dynamicInvocations == null) {
+      _dynamicInvocations = new Setlet<UniverseSelector>();
+      _dynamicInvocations.addAll(worldImpact.dynamicInvocations);
+    }
+    _dynamicInvocations.add(selector);
+  }
+
+  @override
+  void registerDynamicSetter(UniverseSelector selector) {
+    if (_dynamicSetters == null) {
+      _dynamicSetters = new Setlet<UniverseSelector>();
+      _dynamicSetters.addAll(worldImpact.dynamicSetters);
+    }
+    _dynamicSetters.add(selector);
+  }
+
+  @override
+  void registerGetOfStaticFunction(FunctionElement element) {
+    _unsupported('registerGetOfStaticFunction($element)');
+  }
+
+  @override
+  void registerInstantiation(InterfaceType type) {
+    // TODO(johnniwinther): Remove this when dependency tracking is done on
+    // the world impact itself.
+    registerDependency(type.element);
+    if (_instantiatedTypes == null) {
+      _instantiatedTypes = new Setlet<InterfaceType>();
+    }
+    _instantiatedTypes.add(type);
+  }
+
+  @override
+  Iterable<InterfaceType> get instantiatedTypes {
+    return _instantiatedTypes != null
+        ? _instantiatedTypes : const <InterfaceType>[];
+  }
+
+  @override
+  void registerStaticInvocation(Element element) {
+    // TODO(johnniwinther): Remove this when dependency tracking is done on
+    // the world impact itself.
+    registerDependency(element);
+    if (_staticUses == null) {
+      _staticUses = new Setlet<Element>();
+    }
+    _staticUses.add(element);
+  }
+
+  @override
+  Iterable<LocalFunctionElement> get closures => worldImpact.closures;
+}
+
+// TODO(johnniwinther): Rename to `Resolver` or `ResolverContext`.
+abstract class Resolution {
+  Parsing get parsing;
+  DiagnosticReporter get reporter;
+  CoreTypes get coreTypes;
+
+  void resolveTypedef(TypedefElement typdef);
+  void resolveClass(ClassElement cls);
+  void registerClass(ClassElement cls);
+  void resolveMetadataAnnotation(MetadataAnnotation metadataAnnotation);
+  FunctionSignature resolveSignature(FunctionElement function);
+  DartType resolveTypeAnnotation(Element element, TypeAnnotation node);
+
+  bool hasBeenResolved(Element element);
+  ResolutionWorldImpact analyzeElement(Element element);
+}
+
+// TODO(johnniwinther): Rename to `Parser` or `ParsingContext`.
+abstract class Parsing {
+  DiagnosticReporter get reporter;
+  void parsePatchClass(ClassElement cls);
+  measure(f());
+}
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/common/tasks.dart b/pkg/compiler/lib/src/common/tasks.dart
index 32966df..56253db 100644
--- a/pkg/compiler/lib/src/common/tasks.dart
+++ b/pkg/compiler/lib/src/common/tasks.dart
@@ -8,6 +8,8 @@
     UserTag;
 import '../compiler.dart' show
     Compiler;
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import '../elements/elements.dart' show
     Element;
 
@@ -30,6 +32,8 @@
       : this.compiler = compiler,
         watch = (compiler.verbose) ? new Stopwatch() : null;
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   String get name => "Unknown task '${this.runtimeType}'";
 
   int get timing {
@@ -66,7 +70,7 @@
   }
 
   measureElement(Element element, action()) {
-    compiler.withCurrentElement(element, () => measure(action));
+    reporter.withCurrentElement(element, () => measure(action));
   }
 
   /// Measure the time spent in [action] (if in verbose mode) and accumulate it
diff --git a/pkg/compiler/lib/src/compile_time_constants.dart b/pkg/compiler/lib/src/compile_time_constants.dart
index dba9976..59166a0 100644
--- a/pkg/compiler/lib/src/compile_time_constants.dart
+++ b/pkg/compiler/lib/src/compile_time_constants.dart
@@ -4,6 +4,8 @@
 
 library dart2js.compile_time_constant_evaluator;
 
+import 'common/resolution.dart' show
+    Resolution;
 import 'common/tasks.dart' show
     CompilerTask;
 import 'compiler.dart' show
@@ -14,6 +16,8 @@
 import 'constants/expressions.dart';
 import 'constants/values.dart';
 import 'dart_types.dart';
+import 'diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import 'diagnostics/invariant.dart' show
     invariant;
 import 'diagnostics/messages.dart' show
@@ -161,6 +165,8 @@
 
   ConstantCompilerBase(this.compiler, this.constantSystem);
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   @override
   ConstantValue getConstantValueForVariable(VariableElement element) {
     return getConstantValue(initialVariableValues[element.declaration]);
@@ -198,7 +204,7 @@
       return result;
     }
     AstElement currentElement = element.analyzableElement;
-    return compiler.withCurrentElement(currentElement, () {
+    return reporter.withCurrentElement(currentElement, () {
       // TODO(johnniwinther): Avoid this eager analysis.
       _analyzeElementEagerly(compiler, currentElement);
 
@@ -221,7 +227,7 @@
     Node node = element.node;
     if (pendingVariables.contains(element)) {
       if (isConst) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS);
         ConstantExpression expression = new ErroneousConstantExpression();
         constantValueMap[expression] = constantSystem.createNull();
@@ -249,7 +255,7 @@
         if (elementType.isMalformed && !value.isNull) {
           if (isConst) {
             ErroneousElement element = elementType.element;
-            compiler.reportErrorMessage(
+            reporter.reportErrorMessage(
                 node, element.messageKind, element.messageArguments);
           } else {
             // We need to throw an exception at runtime.
@@ -260,7 +266,7 @@
           if (!constantSystem.isSubtype(
               compiler.types, constantType, elementType)) {
             if (isConst) {
-              compiler.reportErrorMessage(
+              reporter.reportErrorMessage(
                   node,
                   MessageKind.NOT_ASSIGNABLE,
                   {'fromType': constantType,
@@ -366,6 +372,9 @@
       : this.isEvaluatingConstant = isConst;
 
   ConstantSystem get constantSystem => handler.constantSystem;
+  Resolution get resolution => compiler.resolution;
+
+  DiagnosticReporter get reporter => compiler.reporter;
 
   AstConstant evaluate(Node node) {
     // TODO(johnniwinther): should there be a visitErrorNode?
@@ -448,7 +457,7 @@
       if (!map.containsKey(key.value)) {
         keyValues.add(key.value);
       } else {
-        compiler.reportWarningMessage(
+        reporter.reportWarningMessage(
             entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY);
       }
       keyExpressions.add(key.expression);
@@ -573,7 +582,7 @@
       AstConstant result;
       if (Elements.isStaticOrTopLevelFunction(element)) {
         FunctionElementX function = element;
-        function.computeType(compiler);
+        function.computeType(resolution);
         result = new AstConstant(context, send,
             new FunctionConstantExpression(function),
             new FunctionConstantValue(function));
@@ -623,7 +632,7 @@
       }
       if (isDeferredUse(send)) {
         if (isEvaluatingConstant) {
-          compiler.reportErrorMessage(
+          reporter.reportErrorMessage(
               send, MessageKind.DEFERRED_COMPILE_TIME_CONSTANT);
         }
         PrefixElement prefix =
@@ -660,7 +669,7 @@
       UnaryOperator operator = UnaryOperator.parse(node.source);
       UnaryOperation operation = constantSystem.lookupUnary(operator);
       if (operation == null) {
-        compiler.internalError(send.selector, "Unexpected operator.");
+        reporter.internalError(send.selector, "Unexpected operator.");
       }
       ConstantValue folded = operation.fold(receiverConstant.value);
       if (folded == null) {
@@ -723,7 +732,7 @@
     } else if (!condition.value.isBool) {
       DartType conditionType = condition.value.getType(compiler.coreTypes);
       if (isEvaluatingConstant) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node.condition,
             MessageKind.NOT_ASSIGNABLE,
             {'fromType': conditionType,
@@ -766,13 +775,13 @@
       return new AstConstant.fromDefaultValue(
           element, constant, handler.getConstantValue(constant));
     }
-    target.computeType(compiler);
+    target.computeType(resolution);
 
     FunctionSignature signature = target.functionSignature;
     if (!callStructure.signatureApplies(signature)) {
       String name = Elements.constructorNameForDiagnostics(
           target.enclosingClass.name, target.name);
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node, MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS,
           {'constructorName': name});
 
@@ -876,14 +885,14 @@
     ConstantValue defaultValue = normalizedArguments[1].value;
 
     if (firstArgument.isNull) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           normalizedArguments[0].node, MessageKind.NULL_NOT_ALLOWED);
       return null;
     }
 
     if (!firstArgument.isString) {
       DartType type = defaultValue.getType(compiler.coreTypes);
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           normalizedArguments[0].node,
           MessageKind.NOT_ASSIGNABLE,
           {'fromType': type,
@@ -894,7 +903,7 @@
     if (constructor == compiler.intEnvironment &&
         !(defaultValue.isNull || defaultValue.isInt)) {
       DartType type = defaultValue.getType(compiler.coreTypes);
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           normalizedArguments[1].node,
           MessageKind.NOT_ASSIGNABLE,
           {'fromType': type,
@@ -905,7 +914,7 @@
     if (constructor == compiler.boolEnvironment &&
         !(defaultValue.isNull || defaultValue.isBool)) {
       DartType type = defaultValue.getType(compiler.coreTypes);
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           normalizedArguments[1].node,
           MessageKind.NOT_ASSIGNABLE,
           {'fromType': type,
@@ -916,7 +925,7 @@
     if (constructor == compiler.stringEnvironment &&
         !(defaultValue.isNull || defaultValue.isString)) {
       DartType type = defaultValue.getType(compiler.coreTypes);
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           normalizedArguments[1].node,
           MessageKind.NOT_ASSIGNABLE,
           {'fromType': type,
@@ -1010,7 +1019,7 @@
   AstConstant signalNotCompileTimeConstant(Node node,
       {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) {
     if (isEvaluatingConstant) {
-      compiler.reportErrorMessage(node, message);
+      reporter.reportErrorMessage(node, message);
 
       return new AstConstant(context, node, new ErroneousConstantExpression(),
           new NullConstantValue());
@@ -1050,7 +1059,7 @@
     if (Elements.isLocal(element)) {
       AstConstant constant = definitions[element];
       if (constant == null) {
-        compiler.internalError(send, "Local variable without value.");
+        reporter.internalError(send, "Local variable without value.");
       }
       return constant;
     }
@@ -1063,8 +1072,8 @@
       DartType constantType = constant.value.getType(compiler.coreTypes);
       if (!constantSystem.isSubtype(
           compiler.types, constantType, elementType)) {
-        compiler.withCurrentElement(constant.element, () {
-          compiler.reportErrorMessage(
+        reporter.withCurrentElement(constant.element, () {
+          reporter.reportErrorMessage(
               constant.node,
               MessageKind.NOT_ASSIGNABLE,
               {'fromType': constantType,
@@ -1190,7 +1199,7 @@
    */
   void evaluateConstructorFieldValues(List<AstConstant> arguments) {
     if (constructor.isErroneous) return;
-    compiler.withCurrentElement(constructor, () {
+    reporter.withCurrentElement(constructor, () {
       assignArgumentsToParameters(arguments);
       evaluateConstructorInitializers();
     });
@@ -1256,10 +1265,9 @@
           new ErroneousConstantExpression(), new NullConstantValue());
 }
 
-// TODO(johnniwinther): Avoid the need for this hack.
+// TODO(johnniwinther): Clean this up.
 TreeElements _analyzeElementEagerly(Compiler compiler, AstElement element) {
-  WorldImpact worldImpact = compiler.analyzeElement(element.declaration);
-  compiler.enqueuer.resolution.applyImpact(element.declaration, worldImpact);
+  compiler.resolution.analyzeElement(element.declaration);
   return element.resolvedAst.elements;
 }
 
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 86a87f3..e3105d7 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -24,7 +24,10 @@
 import 'common/registry.dart' show
     Registry;
 import 'common/resolution.dart' show
-    ResolutionWorkItem;
+    Parsing,
+    Resolution,
+    ResolutionWorkItem,
+    ResolutionWorldImpact;
 import 'common/tasks.dart' show
     CompilerTask,
     GenericTask;
@@ -42,7 +45,10 @@
     Types;
 import 'deferred_load.dart' show DeferredLoadTask, OutputUnit;
 import 'diagnostics/code_location.dart';
-import 'diagnostics/diagnostic_listener.dart';
+import 'diagnostics/diagnostic_listener.dart' show
+    DiagnosticMessage,
+    DiagnosticOptions,
+    DiagnosticReporter;
 import 'diagnostics/invariant.dart' show
     invariant,
     REPORT_EXCESS_RESOLUTION;
@@ -120,7 +126,8 @@
 import 'tokens/token_map.dart' show
     TokenMap;
 import 'tree/tree.dart' show
-    Node;
+    Node,
+    TypeAnnotation;
 import 'typechecker.dart' show
     TypeCheckerTask;
 import 'types/types.dart' as ti;
@@ -136,13 +143,16 @@
 import 'world.dart' show
     World;
 
-abstract class Compiler extends DiagnosticListener {
+abstract class Compiler {
 
   final Stopwatch totalCompileTime = new Stopwatch();
   int nextFreeClassId = 0;
   World world;
   Types types;
   _CompilerCoreTypes _coreTypes;
+  _CompilerDiagnosticReporter _reporter;
+  _CompilerResolution _resolution;
+  _CompilerParsing _parsing;
 
   final CacheStrategy cacheStrategy;
 
@@ -181,7 +191,6 @@
   final bool enableUserAssertions;
   final bool trustTypeAnnotations;
   final bool trustPrimitives;
-  final bool enableConcreteTypeInference;
   final bool disableTypeInferenceFlag;
   final Uri deferredMapUri;
   final bool dumpInfo;
@@ -238,23 +247,6 @@
    */
   final Uri outputUri;
 
-  /// Emit terse diagnostics without howToFix.
-  final bool terseDiagnostics;
-
-  /// If `true`, warnings and hints not from user code are reported.
-  final bool showPackageWarnings;
-
-  /// `true` if the last diagnostic was filtered, in which case the
-  /// accompanying info message should be filtered as well.
-  bool lastDiagnosticWasFiltered = false;
-
-  /// Map containing information about the warnings and hints that have been
-  /// suppressed for each library.
-  Map<Uri, SuppressionInfo> suppressedWarnings = <Uri, SuppressionInfo>{};
-
-  final bool suppressWarnings;
-  final bool fatalWarnings;
-
   /// If `true`, some values are cached for reuse in incremental compilation.
   /// Incremental compilation is basically calling [run] more than once.
   final bool hasIncrementalSupport;
@@ -283,7 +275,6 @@
   Tracer tracer;
 
   CompilerTask measuredTask;
-  Element _currentElement;
   LibraryElement coreLibrary;
   LibraryElement asyncLibrary;
 
@@ -314,7 +305,10 @@
   ClassElement get iterableClass => _coreTypes.iterableClass;
   ClassElement get streamClass => _coreTypes.streamClass;
 
+  DiagnosticReporter get reporter => _reporter;
   CoreTypes get coreTypes => _coreTypes;
+  Resolution get resolution => _resolution;
+  Parsing get parsing => _parsing;
 
   ClassElement typedDataClass;
 
@@ -372,49 +366,7 @@
 
   fromEnvironment(String name) => null;
 
-  Element get currentElement => _currentElement;
-
-  String tryToString(object) {
-    try {
-      return object.toString();
-    } catch (_) {
-      return '<exception in toString()>';
-    }
-  }
-
-  /**
-   * Perform an operation, [f], returning the return value from [f].  If an
-   * error occurs then report it as having occurred during compilation of
-   * [element].  Can be nested.
-   */
-  withCurrentElement(Element element, f()) {
-    Element old = currentElement;
-    _currentElement = element;
-    try {
-      return f();
-    } on SpannableAssertionFailure catch (ex) {
-      if (!hasCrashed) {
-        reportAssertionFailure(ex);
-        pleaseReportCrash();
-      }
-      hasCrashed = true;
-      rethrow;
-    } on StackOverflowError {
-      // We cannot report anything useful in this case, because we
-      // do not have enough stack space.
-      rethrow;
-    } catch (ex) {
-      if (hasCrashed) rethrow;
-      try {
-        unhandledExceptionOnElement(element);
-      } catch (doubleFault) {
-        // Ignoring exceptions in exception handling.
-      }
-      rethrow;
-    } finally {
-      _currentElement = old;
-    }
-  }
+  Element get currentElement => _reporter.currentElement;
 
   List<CompilerTask> tasks;
   ScannerTask scanner;
@@ -458,6 +410,8 @@
   bool enabledInvokeOn = false;
   bool hasIsolateSupport = false;
 
+  bool get hasCrashed => _reporter.hasCrashed;
+
   Stopwatch progress;
 
   bool get shouldPrintProgress {
@@ -481,8 +435,6 @@
     compilationFailedInternal = value;
   }
 
-  bool hasCrashed = false;
-
   /// Set by the backend if real reflection is detected in use of dart:mirrors.
   bool disableTypeInferenceForMirrors = false;
 
@@ -490,7 +442,6 @@
             this.enableUserAssertions: false,
             this.trustTypeAnnotations: false,
             this.trustPrimitives: false,
-            this.enableConcreteTypeInference: false,
             bool disableTypeInferenceFlag: false,
             this.maxConcreteTypeSize: 5,
             this.enableMinification: false,
@@ -510,20 +461,17 @@
             this.sourceMapUri: null,
             this.outputUri: null,
             this.buildId: UNDETERMINED_BUILD_ID,
-            this.terseDiagnostics: false,
             this.deferredMapUri: null,
             this.dumpInfo: false,
-            this.showPackageWarnings: false,
             bool useStartupEmitter: false,
             this.useContentSecurityPolicy: false,
-            this.suppressWarnings: false,
-            this.fatalWarnings: false,
             bool hasIncrementalSupport: false,
             this.enableExperimentalMirrors: false,
             this.enableAssertMessage: false,
             this.allowNativeExtensions: false,
             this.generateCodeWithCompileTimeErrors: false,
             this.testMode: false,
+            DiagnosticOptions diagnosticOptions,
             api.CompilerOutput outputProvider,
             List<String> strips: const []})
       : this.disableTypeInferenceFlag =
@@ -544,7 +492,10 @@
     world = new World(this);
     // TODO(johnniwinther): Initialize core types in [initializeCoreClasses] and
     // make its field final.
-    _coreTypes = new _CompilerCoreTypes(this);
+    _reporter = new _CompilerDiagnosticReporter(this, diagnosticOptions);
+    _parsing = new _CompilerParsing(this);
+    _resolution = new _CompilerResolution(this);
+    _coreTypes = new _CompilerCoreTypes(_resolution);
     types = new Types(this);
     tracer = new Tracer(this, this.outputProvider);
 
@@ -609,118 +560,15 @@
   int getNextFreeClassId() => nextFreeClassId++;
 
   void unimplemented(Spannable spannable, String methodName) {
-    internalError(spannable, "$methodName not implemented.");
-  }
-
-  internalError(Spannable node, reason) {
-    String message = tryToString(reason);
-    reportDiagnosticInternal(
-        createMessage(node, MessageKind.GENERIC, {'text': message}),
-        const <DiagnosticMessage>[],
-        api.Diagnostic.CRASH);
-    throw 'Internal Error: $message';
-  }
-
-  void unhandledExceptionOnElement(Element element) {
-    if (hasCrashed) return;
-    hasCrashed = true;
-    reportDiagnostic(
-        createMessage(element, MessageKind.COMPILER_CRASHED),
-        const <DiagnosticMessage>[],
-        api.Diagnostic.CRASH);
-    pleaseReportCrash();
-  }
-
-  void pleaseReportCrash() {
-    print(
-        MessageTemplate.TEMPLATES[MessageKind.PLEASE_REPORT_THE_CRASH]
-            .message({'buildId': buildId}));
-  }
-
-  SourceSpan spanFromSpannable(Spannable node) {
-    // TODO(johnniwinther): Disallow `node == null` ?
-    if (node == null) return null;
-    if (node == CURRENT_ELEMENT_SPANNABLE) {
-      node = currentElement;
-    } else if (node == NO_LOCATION_SPANNABLE) {
-      if (currentElement == null) return null;
-      node = currentElement;
-    }
-    if (node is SourceSpan) {
-      return node;
-    } else if (node is Node) {
-      return spanFromNode(node);
-    } else if (node is TokenPair) {
-      return spanFromTokens(node.begin, node.end);
-    } else if (node is Token) {
-      return spanFromTokens(node, node);
-    } else if (node is HInstruction) {
-      return spanFromHInstruction(node);
-    } else if (node is Element) {
-      return spanFromElement(node);
-    } else if (node is MetadataAnnotation) {
-      Uri uri = node.annotatedElement.compilationUnit.script.resourceUri;
-      return spanFromTokens(node.beginToken, node.endToken, uri);
-    } else if (node is Local) {
-      Local local = node;
-      return spanFromElement(local.executableContext);
-    } else {
-      throw 'No error location.';
-    }
-  }
-
-  Element _elementFromHInstruction(HInstruction instruction) {
-    return instruction.sourceElement is Element
-        ? instruction.sourceElement : null;
-  }
-
-  /// Finds the approximate [Element] for [node]. [currentElement] is used as
-  /// the default value.
-  Element elementFromSpannable(Spannable node) {
-    Element element;
-    if (node is Element) {
-      element = node;
-    } else if (node is HInstruction) {
-      element = _elementFromHInstruction(node);
-    } else if (node is MetadataAnnotation) {
-      element = node.annotatedElement;
-    }
-    return element != null ? element : currentElement;
-  }
-
-  void log(message) {
-    Message msg = MessageTemplate.TEMPLATES[MessageKind.GENERIC]
-        .message({'text': '$message'});
-    reportDiagnostic(
-        new DiagnosticMessage(null, null, msg),
-        const <DiagnosticMessage>[],
-        api.Diagnostic.VERBOSE_INFO);
+    reporter.internalError(spannable, "$methodName not implemented.");
   }
 
   Future<bool> run(Uri uri) {
     totalCompileTime.start();
 
-    return new Future.sync(() => runCompiler(uri)).catchError((error) {
-      try {
-        if (!hasCrashed) {
-          hasCrashed = true;
-          if (error is SpannableAssertionFailure) {
-            reportAssertionFailure(error);
-          } else {
-            reportDiagnostic(
-                createMessage(
-                    new SourceSpan(uri, 0, 0),
-                    MessageKind.COMPILER_CRASHED),
-                const <DiagnosticMessage>[],
-                api.Diagnostic.CRASH);
-          }
-          pleaseReportCrash();
-        }
-      } catch (doubleFault) {
-        // Ignoring exceptions in exception handling.
-      }
-      throw error;
-    }).whenComplete(() {
+    return new Future.sync(() => runCompiler(uri))
+        .catchError((error) => _reporter.onError(uri, error))
+        .whenComplete(() {
       tracer.close();
       totalCompileTime.stop();
     }).then((_) {
@@ -859,7 +707,7 @@
         if (loadedLibraries.containsLibrary(uri)) {
           Set<String> importChains =
               computeImportChainsFor(loadedLibraries, Uri.parse('dart:io'));
-          reportInfo(NO_LOCATION_SPANNABLE,
+          reporter.reportInfo(NO_LOCATION_SPANNABLE,
              MessageKind.DISALLOWED_LIBRARY_IMPORT,
               {'uri': uri,
                'importChain': importChains.join(
@@ -871,24 +719,27 @@
         return null;
       }
 
-      if (!enableExperimentalMirrors &&
-          loadedLibraries.containsLibrary(Uris.dart_mirrors)) {
+      bool importsMirrorsLibrary =
+          loadedLibraries.containsLibrary(Uris.dart_mirrors);
+      if (importsMirrorsLibrary && !backend.supportsReflection) {
         Set<String> importChains =
             computeImportChainsFor(loadedLibraries, Uris.dart_mirrors);
-        if (!backend.supportsReflection) {
-          reportErrorMessage(
-              NO_LOCATION_SPANNABLE,
-              MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND);
-        } else {
-          reportWarningMessage(
-              NO_LOCATION_SPANNABLE,
-              MessageKind.IMPORT_EXPERIMENTAL_MIRRORS,
-              {'importChain': importChains.join(
-                   MessageTemplate.IMPORT_EXPERIMENTAL_MIRRORS_PADDING)});
-        }
+        reporter.reportErrorMessage(
+            NO_LOCATION_SPANNABLE,
+            MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND,
+            {'importChain': importChains.join(
+                MessageTemplate.MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING)});
+      } else if (importsMirrorsLibrary && !enableExperimentalMirrors) {
+        Set<String> importChains =
+            computeImportChainsFor(loadedLibraries, Uris.dart_mirrors);
+        reporter.reportWarningMessage(
+            NO_LOCATION_SPANNABLE,
+            MessageKind.IMPORT_EXPERIMENTAL_MIRRORS,
+            {'importChain': importChains.join(
+                 MessageTemplate.IMPORT_EXPERIMENTAL_MIRRORS_PADDING)});
       }
 
-      functionClass.ensureResolved(this);
+      functionClass.ensureResolved(resolution);
       functionApplyMethod = functionClass.lookupLocalMember('apply');
 
       if (preserveComments) {
@@ -903,7 +754,7 @@
   bool isProxyConstant(ConstantValue value) {
     FieldElement field = coreLibrary.find('proxy');
     if (field == null) return false;
-    if (!enqueuer.resolution.hasBeenResolved(field)) return false;
+    if (!resolution.hasBeenResolved(field)) return false;
     if (proxyConstant == null) {
       proxyConstant =
           constants.getConstantValue(
@@ -915,10 +766,10 @@
   Element findRequiredElement(LibraryElement library, String name) {
     var element = library.find(name);
     if (element == null) {
-      internalError(library,
+      reporter.internalError(library,
           "The library '${library.canonicalUri}' does not contain required "
           "element: '$name'.");
-      }
+    }
     return element;
   }
 
@@ -973,7 +824,7 @@
     _coreTypes.iterableClass = lookupCoreClass('Iterable');
     _coreTypes.symbolClass = lookupCoreClass('Symbol');
     if (!missingCoreClasses.isEmpty) {
-      internalError(
+      reporter.internalError(
           coreLibrary,
           'dart:core library does not contain required classes: '
           '$missingCoreClasses');
@@ -1010,16 +861,16 @@
     return new Future.sync(() {
       if (librariesToAnalyzeWhenRun != null) {
         return Future.forEach(librariesToAnalyzeWhenRun, (libraryUri) {
-          log('Analyzing $libraryUri ($buildId)');
+          reporter.log('Analyzing $libraryUri ($buildId)');
           return libraryLoader.loadLibrary(libraryUri);
         });
       }
     }).then((_) {
       if (uri != null) {
         if (analyzeOnly) {
-          log('Analyzing $uri ($buildId)');
+          reporter.log('Analyzing $uri ($buildId)');
         } else {
-          log('Compiling $uri ($buildId)');
+          reporter.log('Compiling $uri ($buildId)');
         }
         return libraryLoader.loadLibrary(uri).then((LibraryElement library) {
           mainApp = library;
@@ -1053,7 +904,7 @@
       if (main is ErroneousElement) {
         errorElement = main;
       } else {
-        internalError(main, 'Problem with ${Identifiers.main}.');
+        reporter.internalError(main, 'Problem with ${Identifiers.main}.');
       }
       mainFunction = backend.helperForBadMain();
     } else if (!main.isFunction) {
@@ -1063,7 +914,7 @@
       mainFunction = backend.helperForBadMain();
     } else {
       mainFunction = main;
-      mainFunction.computeType(this);
+      mainFunction.computeType(resolution);
       FunctionSignature parameters = mainFunction.functionSignature;
       if (parameters.requiredParameterCount > 2) {
         int index = 0;
@@ -1081,7 +932,7 @@
     }
     if (mainFunction == null) {
       if (errorElement == null && !analyzeOnly && !analyzeAll) {
-        internalError(mainApp, "Problem with '${Identifiers.main}'.");
+        reporter.internalError(mainApp, "Problem with '${Identifiers.main}'.");
       } else {
         mainFunction = errorElement;
       }
@@ -1089,7 +940,7 @@
     if (errorElement != null &&
         errorElement.isSynthesized &&
         !mainApp.isSynthesized) {
-      reportWarningMessage(
+      reporter.reportWarningMessage(
           errorElement, errorElement.messageKind,
           errorElement.messageArguments);
     }
@@ -1106,7 +957,7 @@
       Uri libraryUri,
       {bool skipLibraryWithPartOfTag: true}) {
     assert(analyzeMain);
-    log('Analyzing $libraryUri ($buildId)');
+    reporter.log('Analyzing $libraryUri ($buildId)');
     return libraryLoader.loadLibrary(libraryUri).then((LibraryElement library) {
       var compilationUnit = library.compilationUnit;
       if (skipLibraryWithPartOfTag && compilationUnit.partTag != null) {
@@ -1114,7 +965,7 @@
       }
       fullyEnqueueLibrary(library, enqueuer.resolution);
       emptyQueue(enqueuer.resolution);
-      enqueuer.resolution.logSummary(log);
+      enqueuer.resolution.logSummary(reporter.log);
       return library;
     });
   }
@@ -1134,7 +985,7 @@
     phase = PHASE_RESOLVING;
     if (analyzeAll) {
       libraryLoader.libraries.forEach((LibraryElement library) {
-        log('Enqueuing ${library.canonicalUri}');
+      reporter.log('Enqueuing ${library.canonicalUri}');
         fullyEnqueueLibrary(library, enqueuer.resolution);
       });
     } else if (analyzeMain && mainApp != null) {
@@ -1144,30 +995,11 @@
     // that are not pulled in by a particular element.
     backend.enqueueHelpers(enqueuer.resolution, globalDependencies);
     resolveLibraryMetadata();
-    log('Resolving...');
+    reporter.log('Resolving...');
     processQueue(enqueuer.resolution, mainFunction);
-    enqueuer.resolution.logSummary(log);
+    enqueuer.resolution.logSummary(reporter.log);
 
-    if (!showPackageWarnings && !suppressWarnings) {
-      suppressedWarnings.forEach((Uri uri, SuppressionInfo info) {
-        MessageKind kind = MessageKind.HIDDEN_WARNINGS_HINTS;
-        if (info.warnings == 0) {
-          kind = MessageKind.HIDDEN_HINTS;
-        } else if (info.hints == 0) {
-          kind = MessageKind.HIDDEN_WARNINGS;
-        }
-        MessageTemplate template = MessageTemplate.TEMPLATES[kind];
-        Message message = template.message(
-            {'warnings': info.warnings,
-             'hints': info.hints,
-             'uri': uri},
-            terseDiagnostics);
-        reportDiagnostic(
-            new DiagnosticMessage(null, null, message),
-            const <DiagnosticMessage>[],
-            api.Diagnostic.HINT);
-      });
-    }
+    _reporter.reportSuppressedMessagesSummary();
 
     if (compilationFailed){
       if (!generateCodeWithCompileTimeErrors) return;
@@ -1198,14 +1030,14 @@
 
     deferredLoadTask.onResolutionComplete(mainFunction);
 
-    log('Inferring types...');
+    reporter.log('Inferring types...');
     typesTask.onResolutionComplete(mainFunction);
 
     if (stopAfterTypeInference) return;
 
     backend.onTypeInferenceComplete();
 
-    log('Compiling...');
+    reporter.log('Compiling...');
     phase = PHASE_COMPILING;
     backend.onCodegenStart();
     // TODO(johnniwinther): Move these to [CodegenEnqueuer].
@@ -1218,7 +1050,7 @@
       });
     }
     processQueue(enqueuer.codegen, mainFunction);
-    enqueuer.codegen.logSummary(log);
+    enqueuer.codegen.logSummary(reporter.log);
 
     int programSize = backend.assembleProgram();
 
@@ -1240,7 +1072,7 @@
   void fullyEnqueueTopLevelElement(Element element, Enqueuer world) {
     if (element.isClass) {
       ClassElement cls = element;
-      cls.ensureResolved(this);
+      cls.ensureResolved(resolution);
       cls.forEachLocalMember(enqueuer.resolution.addToWorkList);
       backend.registerInstantiatedType(
           cls.rawType, world, globalDependencies);
@@ -1256,7 +1088,7 @@
     for (LibraryElement library in libraryLoader.libraries) {
       if (library.metadata != null) {
         for (MetadataAnnotation metadata in library.metadata) {
-          metadata.ensureResolved(this);
+          metadata.ensureResolved(resolution);
         }
       }
     }
@@ -1267,7 +1099,7 @@
    */
   void emptyQueue(Enqueuer world) {
     world.forEach((WorkItem work) {
-      withCurrentElement(work.element, () {
+    reporter.withCurrentElement(work.element, () {
         world.applyImpact(work.element, work.run(this, world));
       });
     });
@@ -1277,13 +1109,13 @@
     world.nativeEnqueuer.processNativeClasses(libraryLoader.libraries);
     if (main != null && !main.isErroneous) {
       FunctionElement mainMethod = main;
-      mainMethod.computeType(this);
+      mainMethod.computeType(resolution);
       if (mainMethod.functionSignature.parameterCount != 0) {
         // The first argument could be a list of strings.
-        backend.listImplementation.ensureResolved(this);
+        backend.listImplementation.ensureResolved(resolution);
         backend.registerInstantiatedType(
             backend.listImplementation.rawType, world, globalDependencies);
-        backend.stringImplementation.ensureResolved(this);
+        backend.stringImplementation.ensureResolved(resolution);
         backend.registerInstantiatedType(
             backend.stringImplementation.rawType, world, globalDependencies);
 
@@ -1309,11 +1141,11 @@
   checkQueues() {
     for (Enqueuer world in [enqueuer.resolution, enqueuer.codegen]) {
       world.forEach((WorkItem work) {
-        internalError(work.element, "Work list is not empty.");
+        reporter.internalError(work.element, "Work list is not empty.");
       });
     }
     if (!REPORT_EXCESS_RESOLUTION) return;
-    var resolved = new Set.from(enqueuer.resolution.resolvedElements);
+    var resolved = new Set.from(enqueuer.resolution.processedElements);
     for (Element e in enqueuer.codegen.generatedCode.keys) {
       resolved.remove(e);
     }
@@ -1332,15 +1164,15 @@
         resolved.remove(e);
       }
     }
-    log('Excess resolution work: ${resolved.length}.');
+    reporter.log('Excess resolution work: ${resolved.length}.');
     for (Element e in resolved) {
-      reportWarningMessage(e,
+      reporter.reportWarningMessage(e,
           MessageKind.GENERIC,
           {'text': 'Warning: $e resolved but not compiled.'});
     }
   }
 
-  WorldImpact analyzeElement(Element element) {
+  ResolutionWorldImpact analyzeElement(Element element) {
     assert(invariant(element,
            element.impliesType ||
            element.isField ||
@@ -1352,23 +1184,11 @@
     assert(invariant(element, element is AnalyzableElement,
         message: 'Element $element is not analyzable.'));
     assert(invariant(element, element.isDeclaration));
-    ResolutionEnqueuer world = enqueuer.resolution;
-    if (world.hasBeenResolved(element)) {
-      return const WorldImpact();
-    }
-    assert(parser != null);
-    Node tree = parser.parse(element);
-    assert(invariant(element, !element.isSynthesized || tree == null));
-    WorldImpact worldImpact = resolver.resolve(element);
-    if (tree != null && !analyzeSignaturesOnly && !suppressWarnings) {
-      // Only analyze nodes with a corresponding [TreeElements].
-      checker.check(element);
-    }
-    world.registerResolvedElement(element);
-    return worldImpact;
+    return resolution.analyzeElement(element);
   }
 
-  WorldImpact analyze(ResolutionWorkItem work, ResolutionEnqueuer world) {
+  ResolutionWorldImpact analyze(ResolutionWorkItem work,
+                                ResolutionEnqueuer world) {
     assert(invariant(work.element, identical(world, enqueuer.resolution)));
     assert(invariant(work.element, !work.isAnalyzed,
         message: 'Element ${work.element} has already been analyzed'));
@@ -1376,17 +1196,19 @@
       // TODO(ahe): Add structured diagnostics to the compiler API and
       // use it to separate this from the --verbose option.
       if (phase == PHASE_RESOLVING) {
-        log('Resolved ${enqueuer.resolution.resolvedElements.length} '
+        reporter.log(
+            'Resolved ${enqueuer.resolution.processedElements.length} '
             'elements.');
         progress.reset();
       }
     }
     AstElement element = work.element;
-    if (world.hasBeenResolved(element)) {
-      return const WorldImpact();
+    if (world.hasBeenProcessed(element)) {
+      return const ResolutionWorldImpact();
     }
-    WorldImpact worldImpact = analyzeElement(element);
+    ResolutionWorldImpact worldImpact = analyzeElement(element);
     backend.onElementResolved(element, element.resolvedAst.elements);
+    world.registerProcessedElement(element);
     return worldImpact;
   }
 
@@ -1395,153 +1217,19 @@
     if (shouldPrintProgress) {
       // TODO(ahe): Add structured diagnostics to the compiler API and
       // use it to separate this from the --verbose option.
-      log('Compiled ${enqueuer.codegen.generatedCode.length} methods.');
+      reporter.log(
+          'Compiled ${enqueuer.codegen.generatedCode.length} methods.');
       progress.reset();
     }
     return backend.codegen(work);
   }
 
-  DiagnosticMessage createMessage(
-      Spannable spannable,
-      MessageKind messageKind,
-      [Map arguments = const {}]) {
-    SourceSpan span = spanFromSpannable(spannable);
-    MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
-    Message message = template.message(arguments, terseDiagnostics);
-    return new DiagnosticMessage(span, spannable, message);
-  }
-
-  void reportError(
-      DiagnosticMessage message,
-      [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
-    reportDiagnosticInternal(message, infos, api.Diagnostic.ERROR);
-  }
-
-  void reportWarning(
-      DiagnosticMessage message,
-      [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
-    reportDiagnosticInternal(message, infos, api.Diagnostic.WARNING);
-  }
-
-  void reportHint(
-      DiagnosticMessage message,
-      [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
-    reportDiagnosticInternal(message, infos, api.Diagnostic.HINT);
-  }
-
-  @deprecated
-  void reportInfo(Spannable node, MessageKind messageKind,
-                  [Map arguments = const {}]) {
-    reportDiagnosticInternal(
-        createMessage(node, messageKind, arguments),
-        const <DiagnosticMessage>[],
-        api.Diagnostic.INFO);
-  }
-
-  void reportDiagnosticInternal(DiagnosticMessage message,
-                                List<DiagnosticMessage> infos,
-                                api.Diagnostic kind) {
-    if (!showPackageWarnings && message.spannable != NO_LOCATION_SPANNABLE) {
-      switch (kind) {
-      case api.Diagnostic.WARNING:
-      case api.Diagnostic.HINT:
-        Element element = elementFromSpannable(message.spannable);
-        if (!inUserCode(element, assumeInUserCode: true)) {
-          Uri uri = getCanonicalUri(element);
-          SuppressionInfo info =
-              suppressedWarnings.putIfAbsent(uri, () => new SuppressionInfo());
-          if (kind == api.Diagnostic.WARNING) {
-            info.warnings++;
-          } else {
-            info.hints++;
-          }
-          lastDiagnosticWasFiltered = true;
-          return;
-        }
-        break;
-      case api.Diagnostic.INFO:
-        if (lastDiagnosticWasFiltered) {
-          return;
-        }
-        break;
-      }
-    }
-    lastDiagnosticWasFiltered = false;
-    reportDiagnostic(message, infos, kind);
-  }
-
   void reportDiagnostic(DiagnosticMessage message,
                         List<DiagnosticMessage> infos,
                         api.Diagnostic kind);
 
-  void reportAssertionFailure(SpannableAssertionFailure ex) {
-    String message = (ex.message != null) ? tryToString(ex.message)
-                                          : tryToString(ex);
-    reportDiagnosticInternal(
-        createMessage(ex.node, MessageKind.GENERIC, {'text': message}),
-        const <DiagnosticMessage>[],
-        api.Diagnostic.CRASH);
-  }
-
-  SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) {
-    if (begin == null || end == null) {
-      // TODO(ahe): We can almost always do better. Often it is only
-      // end that is null. Otherwise, we probably know the current
-      // URI.
-      throw 'Cannot find tokens to produce error message.';
-    }
-    if (uri == null && currentElement != null) {
-      uri = currentElement.compilationUnit.script.resourceUri;
-    }
-    return new SourceSpan.fromTokens(uri, begin, end);
-  }
-
-  SourceSpan spanFromNode(Node node) {
-    return spanFromTokens(node.getBeginToken(), node.getEndToken());
-  }
-
-  SourceSpan spanFromElement(Element element) {
-    if (element != null && element.sourcePosition != null) {
-      return element.sourcePosition;
-    }
-    while (element != null && element.isSynthesized) {
-      element = element.enclosingElement;
-    }
-    if (element != null &&
-        element.sourcePosition == null &&
-        !element.isLibrary &&
-        !element.isCompilationUnit) {
-      // Sometimes, the backend fakes up elements that have no
-      // position. So we use the enclosing element instead. It is
-      // not a good error location, but cancel really is "internal
-      // error" or "not implemented yet", so the vicinity is good
-      // enough for now.
-      element = element.enclosingElement;
-      // TODO(ahe): I plan to overhaul this infrastructure anyways.
-    }
-    if (element == null) {
-      element = currentElement;
-    }
-    if (element == null) {
-      return null;
-    }
-
-    if (element.sourcePosition != null) {
-      return element.sourcePosition;
-    }
-    Token position = element.position;
-    Uri uri = element.compilationUnit.script.resourceUri;
-    return (position == null)
-        ? new SourceSpan(uri, 0, 0)
-        : spanFromTokens(position, position, uri);
-  }
-
-  SourceSpan spanFromHInstruction(HInstruction instruction) {
-    Element element = _elementFromHInstruction(instruction);
-    if (element == null) element = currentElement;
-    SourceInformation position = instruction.sourceInformation;
-    if (position == null) return spanFromElement(element);
-    return position.sourceSpan;
+  void reportCrashInUserCode(String message, exception, stackTrace) {
+    _reporter.onCrashInUserCode(message, exception, stackTrace);
   }
 
   /**
@@ -1616,20 +1304,20 @@
     void checkLive(member) {
       if (member.isErroneous) return;
       if (member.isFunction) {
-        if (!enqueuer.resolution.hasBeenResolved(member)) {
-          reportHintMessage(
+        if (!enqueuer.resolution.hasBeenProcessed(member)) {
+          reporter.reportHintMessage(
               member, MessageKind.UNUSED_METHOD, {'name': member.name});
         }
       } else if (member.isClass) {
         if (!member.isResolved) {
-          reportHintMessage(
+          reporter.reportHintMessage(
               member, MessageKind.UNUSED_CLASS, {'name': member.name});
         } else {
           member.forEachLocalMember(checkLive);
         }
       } else if (member.isTypedef) {
         if (!member.isResolved) {
-          reportHintMessage(
+          reporter.reportHintMessage(
               member, MessageKind.UNUSED_TYPEDEF, {'name': member.name});
         }
       }
@@ -1753,7 +1441,7 @@
 }
 
 class _CompilerCoreTypes implements CoreTypes {
-  final Compiler compiler;
+  final Resolution resolution;
 
   ClassElement objectClass;
   ClassElement boolClass;
@@ -1773,31 +1461,50 @@
   ClassElement streamClass;
   ClassElement resourceClass;
 
-  _CompilerCoreTypes(this.compiler);
+  _CompilerCoreTypes(this.resolution);
 
   @override
-  InterfaceType get objectType => objectClass.computeType(compiler);
+  InterfaceType get objectType {
+    objectClass.ensureResolved(resolution);
+    return objectClass.rawType;
+  }
 
   @override
-  InterfaceType get boolType => boolClass.computeType(compiler);
+  InterfaceType get boolType {
+    boolClass.ensureResolved(resolution);
+    return boolClass.rawType;
+  }
 
   @override
-  InterfaceType get doubleType => doubleClass.computeType(compiler);
+  InterfaceType get doubleType {
+    doubleClass.ensureResolved(resolution);
+    return doubleClass.rawType;
+  }
 
   @override
-  InterfaceType get functionType => functionClass.computeType(compiler);
+  InterfaceType get functionType {
+    functionClass.ensureResolved(resolution);
+    return functionClass.rawType;
+  }
 
   @override
-  InterfaceType get intType => intClass.computeType(compiler);
+  InterfaceType get intType {
+    intClass.ensureResolved(resolution);
+    return intClass.rawType;
+  }
 
   @override
-  InterfaceType get resourceType => resourceClass.computeType(compiler);
+  InterfaceType get resourceType {
+    resourceClass.ensureResolved(resolution);
+    return resourceClass.rawType;
+  }
 
   @override
   InterfaceType listType([DartType elementType]) {
-    InterfaceType type = listClass.computeType(compiler);
+    listClass.ensureResolved(resolution);
+    InterfaceType type = listClass.rawType;
     if (elementType == null) {
-      return listClass.rawType;
+      return type;
     }
     return type.createInstantiation([elementType]);
   }
@@ -1805,9 +1512,10 @@
   @override
   InterfaceType mapType([DartType keyType,
                          DartType valueType]) {
-    InterfaceType type = mapClass.computeType(compiler);
+    mapClass.ensureResolved(resolution);
+    InterfaceType type = mapClass.rawType;
     if (keyType == null && valueType == null) {
-      return mapClass.rawType;
+      return type;
     } else if (keyType == null) {
       keyType = const DynamicType();
     } else if (valueType == null) {
@@ -1817,44 +1525,498 @@
   }
 
   @override
-  InterfaceType get nullType => nullClass.computeType(compiler);
+  InterfaceType get nullType {
+    nullClass.ensureResolved(resolution);
+    return nullClass.rawType;
+  }
 
   @override
-  InterfaceType get numType => numClass.computeType(compiler);
+  InterfaceType get numType {
+    numClass.ensureResolved(resolution);
+    return numClass.rawType;
+  }
 
   @override
-  InterfaceType get stringType => stringClass.computeType(compiler);
+  InterfaceType get stringType {
+    stringClass.ensureResolved(resolution);
+    return stringClass.rawType;
+  }
 
   @override
-  InterfaceType get symbolType => symbolClass.computeType(compiler);
+  InterfaceType get symbolType {
+    symbolClass.ensureResolved(resolution);
+    return symbolClass.rawType;
+  }
 
   @override
-  InterfaceType get typeType => typeClass.computeType(compiler);
+  InterfaceType get typeType {
+    typeClass.ensureResolved(resolution);
+    return typeClass.rawType;
+  }
 
   @override
   InterfaceType iterableType([DartType elementType]) {
-    InterfaceType type = iterableClass.computeType(compiler);
+    iterableClass.ensureResolved(resolution);
+    InterfaceType type = iterableClass.rawType;
     if (elementType == null) {
-      return iterableClass.rawType;
+      return type;
     }
     return type.createInstantiation([elementType]);
   }
 
   @override
   InterfaceType futureType([DartType elementType]) {
-    InterfaceType type = futureClass.computeType(compiler);
+    futureClass.ensureResolved(resolution);
+    InterfaceType type = futureClass.rawType;
     if (elementType == null) {
-      return futureClass.rawType;
+      return type;
     }
     return type.createInstantiation([elementType]);
   }
 
   @override
   InterfaceType streamType([DartType elementType]) {
-    InterfaceType type = streamClass.computeType(compiler);
+    streamClass.ensureResolved(resolution);
+    InterfaceType type = streamClass.rawType;
     if (elementType == null) {
-      return streamClass.rawType;
+      return type;
     }
     return type.createInstantiation([elementType]);
   }
 }
+
+class _CompilerDiagnosticReporter extends DiagnosticReporter {
+  final Compiler compiler;
+  final DiagnosticOptions options;
+
+  Element _currentElement;
+  bool hasCrashed = false;
+
+  /// `true` if the last diagnostic was filtered, in which case the
+  /// accompanying info message should be filtered as well.
+  bool lastDiagnosticWasFiltered = false;
+
+  /// Map containing information about the warnings and hints that have been
+  /// suppressed for each library.
+  Map<Uri, SuppressionInfo> suppressedWarnings = <Uri, SuppressionInfo>{};
+
+  _CompilerDiagnosticReporter(this.compiler, this.options);
+
+  Element get currentElement => _currentElement;
+
+  DiagnosticMessage createMessage(
+      Spannable spannable,
+      MessageKind messageKind,
+      [Map arguments = const {}]) {
+    SourceSpan span = spanFromSpannable(spannable);
+    MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
+    Message message = template.message(arguments, options.terseDiagnostics);
+    return new DiagnosticMessage(span, spannable, message);
+  }
+
+  void reportError(
+      DiagnosticMessage message,
+      [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
+    reportDiagnosticInternal(message, infos, api.Diagnostic.ERROR);
+  }
+
+  void reportWarning(
+      DiagnosticMessage message,
+      [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
+    reportDiagnosticInternal(message, infos, api.Diagnostic.WARNING);
+  }
+
+  void reportHint(
+      DiagnosticMessage message,
+      [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
+    reportDiagnosticInternal(message, infos, api.Diagnostic.HINT);
+  }
+
+  @deprecated
+  void reportInfo(Spannable node, MessageKind messageKind,
+                  [Map arguments = const {}]) {
+    reportDiagnosticInternal(
+        createMessage(node, messageKind, arguments),
+        const <DiagnosticMessage>[],
+        api.Diagnostic.INFO);
+  }
+
+  void reportDiagnosticInternal(DiagnosticMessage message,
+                                List<DiagnosticMessage> infos,
+                                api.Diagnostic kind) {
+    if (!options.showPackageWarnings &&
+        message.spannable != NO_LOCATION_SPANNABLE) {
+      switch (kind) {
+      case api.Diagnostic.WARNING:
+      case api.Diagnostic.HINT:
+        Element element = elementFromSpannable(message.spannable);
+        if (!compiler.inUserCode(element, assumeInUserCode: true)) {
+          Uri uri = compiler.getCanonicalUri(element);
+          SuppressionInfo info =
+              suppressedWarnings.putIfAbsent(uri, () => new SuppressionInfo());
+          if (kind == api.Diagnostic.WARNING) {
+            info.warnings++;
+          } else {
+            info.hints++;
+          }
+          lastDiagnosticWasFiltered = true;
+          return;
+        }
+        break;
+      case api.Diagnostic.INFO:
+        if (lastDiagnosticWasFiltered) {
+          return;
+        }
+        break;
+      }
+    }
+    lastDiagnosticWasFiltered = false;
+    reportDiagnostic(message, infos, kind);
+  }
+
+  void reportDiagnostic(DiagnosticMessage message,
+                        List<DiagnosticMessage> infos,
+                        api.Diagnostic kind) {
+    compiler.reportDiagnostic(message, infos, kind);
+  }
+
+  /**
+   * Perform an operation, [f], returning the return value from [f].  If an
+   * error occurs then report it as having occurred during compilation of
+   * [element].  Can be nested.
+   */
+  withCurrentElement(Element element, f()) {
+    Element old = currentElement;
+    _currentElement = element;
+    try {
+      return f();
+    } on SpannableAssertionFailure catch (ex) {
+      if (!hasCrashed) {
+        reportAssertionFailure(ex);
+        pleaseReportCrash();
+      }
+      hasCrashed = true;
+      rethrow;
+    } on StackOverflowError {
+      // We cannot report anything useful in this case, because we
+      // do not have enough stack space.
+      rethrow;
+    } catch (ex) {
+      if (hasCrashed) rethrow;
+      try {
+        unhandledExceptionOnElement(element);
+      } catch (doubleFault) {
+        // Ignoring exceptions in exception handling.
+      }
+      rethrow;
+    } finally {
+      _currentElement = old;
+    }
+  }
+
+  void reportAssertionFailure(SpannableAssertionFailure ex) {
+    String message = (ex.message != null) ? tryToString(ex.message)
+                                          : tryToString(ex);
+    reportDiagnosticInternal(
+        createMessage(ex.node, MessageKind.GENERIC, {'text': message}),
+        const <DiagnosticMessage>[],
+        api.Diagnostic.CRASH);
+  }
+
+  SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) {
+    if (begin == null || end == null) {
+      // TODO(ahe): We can almost always do better. Often it is only
+      // end that is null. Otherwise, we probably know the current
+      // URI.
+      throw 'Cannot find tokens to produce error message.';
+    }
+    if (uri == null && currentElement != null) {
+      uri = currentElement.compilationUnit.script.resourceUri;
+    }
+    return new SourceSpan.fromTokens(uri, begin, end);
+  }
+
+  SourceSpan spanFromNode(Node node) {
+    return spanFromTokens(node.getBeginToken(), node.getEndToken());
+  }
+
+  SourceSpan spanFromElement(Element element) {
+    if (element != null && element.sourcePosition != null) {
+      return element.sourcePosition;
+    }
+    while (element != null && element.isSynthesized) {
+      element = element.enclosingElement;
+    }
+    if (element != null &&
+        element.sourcePosition == null &&
+        !element.isLibrary &&
+        !element.isCompilationUnit) {
+      // Sometimes, the backend fakes up elements that have no
+      // position. So we use the enclosing element instead. It is
+      // not a good error location, but cancel really is "internal
+      // error" or "not implemented yet", so the vicinity is good
+      // enough for now.
+      element = element.enclosingElement;
+      // TODO(ahe): I plan to overhaul this infrastructure anyways.
+    }
+    if (element == null) {
+      element = currentElement;
+    }
+    if (element == null) {
+      return null;
+    }
+
+    if (element.sourcePosition != null) {
+      return element.sourcePosition;
+    }
+    Token position = element.position;
+    Uri uri = element.compilationUnit.script.resourceUri;
+    return (position == null)
+        ? new SourceSpan(uri, 0, 0)
+        : spanFromTokens(position, position, uri);
+  }
+
+  SourceSpan spanFromHInstruction(HInstruction instruction) {
+    Element element = _elementFromHInstruction(instruction);
+    if (element == null) element = currentElement;
+    SourceInformation position = instruction.sourceInformation;
+    if (position == null) return spanFromElement(element);
+    return position.sourceSpan;
+  }
+
+  SourceSpan spanFromSpannable(Spannable node) {
+    // TODO(johnniwinther): Disallow `node == null` ?
+    if (node == null) return null;
+    if (node == CURRENT_ELEMENT_SPANNABLE) {
+      node = currentElement;
+    } else if (node == NO_LOCATION_SPANNABLE) {
+      if (currentElement == null) return null;
+      node = currentElement;
+    }
+    if (node is SourceSpan) {
+      return node;
+    } else if (node is Node) {
+      return spanFromNode(node);
+    } else if (node is TokenPair) {
+      return spanFromTokens(node.begin, node.end);
+    } else if (node is Token) {
+      return spanFromTokens(node, node);
+    } else if (node is HInstruction) {
+      return spanFromHInstruction(node);
+    } else if (node is Element) {
+      return spanFromElement(node);
+    } else if (node is MetadataAnnotation) {
+      Uri uri = node.annotatedElement.compilationUnit.script.resourceUri;
+      return spanFromTokens(node.beginToken, node.endToken, uri);
+    } else if (node is Local) {
+      Local local = node;
+      return spanFromElement(local.executableContext);
+    } else {
+      throw 'No error location.';
+    }
+  }
+
+  Element _elementFromHInstruction(HInstruction instruction) {
+    return instruction.sourceElement is Element
+        ? instruction.sourceElement : null;
+  }
+
+  internalError(Spannable node, reason) {
+    String message = tryToString(reason);
+    reportDiagnosticInternal(
+        createMessage(node, MessageKind.GENERIC, {'text': message}),
+        const <DiagnosticMessage>[],
+        api.Diagnostic.CRASH);
+    throw 'Internal Error: $message';
+  }
+
+  void unhandledExceptionOnElement(Element element) {
+    if (hasCrashed) return;
+    hasCrashed = true;
+    reportDiagnostic(
+        createMessage(element, MessageKind.COMPILER_CRASHED),
+        const <DiagnosticMessage>[],
+        api.Diagnostic.CRASH);
+    pleaseReportCrash();
+  }
+
+  void pleaseReportCrash() {
+    print(
+        MessageTemplate.TEMPLATES[MessageKind.PLEASE_REPORT_THE_CRASH]
+            .message({'buildId': compiler.buildId}));
+  }
+
+  /// Finds the approximate [Element] for [node]. [currentElement] is used as
+  /// the default value.
+  Element elementFromSpannable(Spannable node) {
+    Element element;
+    if (node is Element) {
+      element = node;
+    } else if (node is HInstruction) {
+      element = _elementFromHInstruction(node);
+    } else if (node is MetadataAnnotation) {
+      element = node.annotatedElement;
+    }
+    return element != null ? element : currentElement;
+  }
+
+  void log(message) {
+    Message msg = MessageTemplate.TEMPLATES[MessageKind.GENERIC]
+        .message({'text': '$message'});
+    reportDiagnostic(
+        new DiagnosticMessage(null, null, msg),
+        const <DiagnosticMessage>[],
+        api.Diagnostic.VERBOSE_INFO);
+  }
+
+  String tryToString(object) {
+    try {
+      return object.toString();
+    } catch (_) {
+      return '<exception in toString()>';
+    }
+  }
+
+  onError(Uri uri, error) {
+    try {
+      if (!hasCrashed) {
+        hasCrashed = true;
+        if (error is SpannableAssertionFailure) {
+          reportAssertionFailure(error);
+        } else {
+          reportDiagnostic(
+              createMessage(
+                  new SourceSpan(uri, 0, 0),
+                  MessageKind.COMPILER_CRASHED),
+              const <DiagnosticMessage>[],
+              api.Diagnostic.CRASH);
+        }
+        pleaseReportCrash();
+      }
+    } catch (doubleFault) {
+      // Ignoring exceptions in exception handling.
+    }
+    throw error;
+  }
+
+  void onCrashInUserCode(String message, exception, stackTrace) {
+    hasCrashed = true;
+    print('$message: ${tryToString(exception)}');
+    print(tryToString(stackTrace));
+  }
+
+  void reportSuppressedMessagesSummary() {
+    if (!options.showPackageWarnings && !options.suppressWarnings) {
+      suppressedWarnings.forEach((Uri uri, SuppressionInfo info) {
+        MessageKind kind = MessageKind.HIDDEN_WARNINGS_HINTS;
+        if (info.warnings == 0) {
+          kind = MessageKind.HIDDEN_HINTS;
+        } else if (info.hints == 0) {
+          kind = MessageKind.HIDDEN_WARNINGS;
+        }
+        MessageTemplate template = MessageTemplate.TEMPLATES[kind];
+        Message message = template.message(
+            {'warnings': info.warnings,
+             'hints': info.hints,
+             'uri': uri},
+             options.terseDiagnostics);
+        reportDiagnostic(
+            new DiagnosticMessage(null, null, message),
+            const <DiagnosticMessage>[],
+            api.Diagnostic.HINT);
+      });
+    }
+  }
+}
+
+// TODO(johnniwinther): Move [ResolverTask] here.
+class _CompilerResolution implements Resolution {
+  final Compiler compiler;
+  final Map<Element, ResolutionWorldImpact> _worldImpactCache =
+      <Element, ResolutionWorldImpact>{};
+
+  _CompilerResolution(this.compiler);
+
+  @override
+  DiagnosticReporter get reporter => compiler.reporter;
+
+  @override
+  Parsing get parsing => compiler.parsing;
+
+  @override
+  CoreTypes get coreTypes => compiler.coreTypes;
+
+  @override
+  void registerClass(ClassElement cls) {
+    compiler.world.registerClass(cls);
+  }
+
+  @override
+  void resolveClass(ClassElement cls) {
+    compiler.resolver.resolveClass(cls);
+  }
+
+  @override
+  void resolveTypedef(TypedefElement typdef) {
+    compiler.resolver.resolve(typdef);
+  }
+
+  @override
+  void resolveMetadataAnnotation(MetadataAnnotation metadataAnnotation) {
+    compiler.resolver.resolveMetadataAnnotation(metadataAnnotation);
+  }
+
+  @override
+  FunctionSignature resolveSignature(FunctionElement function) {
+    return compiler.resolver.resolveSignature(function);
+  }
+
+  @override
+  DartType resolveTypeAnnotation(Element element, TypeAnnotation node) {
+    return compiler.resolver.resolveTypeAnnotation(element, node);
+  }
+
+  ResolutionWorldImpact analyzeElement(Element element) {
+    return _worldImpactCache.putIfAbsent(element, () {
+      assert(compiler.parser != null);
+      Node tree = compiler.parser.parse(element);
+      assert(invariant(element, !element.isSynthesized || tree == null));
+      ResolutionWorldImpact worldImpact = compiler.resolver.resolve(element);
+      if (tree != null &&
+          !compiler.analyzeSignaturesOnly &&
+          !reporter.options.suppressWarnings) {
+        // Only analyze nodes with a corresponding [TreeElements].
+        compiler.checker.check(element);
+      }
+      return worldImpact;
+    });
+  }
+
+  @override
+  bool hasBeenResolved(Element element) {
+    return _worldImpactCache.containsKey(element);
+  }
+}
+
+// TODO(johnniwinther): Move [ParserTask], [PatchParserTask], [DietParserTask]
+// and [ScannerTask] here.
+class _CompilerParsing implements Parsing {
+  final Compiler compiler;
+
+  _CompilerParsing(this.compiler);
+
+  @override
+  DiagnosticReporter get reporter => compiler.reporter;
+
+  @override
+  measure(f()) => compiler.parser.measure(f);
+
+  @override
+  void parsePatchClass(ClassElement cls) {
+    compiler.patchParser.measure(() {
+      if (cls.isPatch) {
+        compiler.patchParser.parsePatchClassNode(cls);
+      }
+    });
+  }
+}
diff --git a/pkg/compiler/lib/src/constant_system_dart.dart b/pkg/compiler/lib/src/constant_system_dart.dart
index 940e764..4a15ac9 100644
--- a/pkg/compiler/lib/src/constant_system_dart.dart
+++ b/pkg/compiler/lib/src/constant_system_dart.dart
@@ -434,7 +434,7 @@
     // `compiler.coreTypes.typeType` and check the backend specific value in
     // [checkConstMapKeysDontOverrideEquals] in 'members.dart'.
     return new TypeConstantValue(type,
-        compiler.backend.typeImplementation.computeType(compiler));
+        compiler.backend.typeImplementation.computeType(compiler.resolution));
   }
 
   bool isInt(ConstantValue constant) => constant.isInt;
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 09c6b0d..3d168d3 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
@@ -15,6 +15,8 @@
     Compiler;
 import '../constants/expressions.dart';
 import '../dart_types.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import '../diagnostics/invariant.dart' show
     invariant;
 import '../elements/elements.dart';
@@ -83,7 +85,7 @@
 
       TreeElements elementsMapping = element.resolvedAst.elements;
       element = element.implementation;
-      return compiler.withCurrentElement(element, () {
+      return reporter.withCurrentElement(element, () {
         SourceInformationBuilder sourceInformationBuilder =
             sourceInformationStrategy.createBuilderForContext(element);
 
@@ -160,6 +162,8 @@
                    this.compiler,
                    this.sourceInformationBuilder);
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   String bailoutMessage = null;
 
   @override
@@ -235,14 +239,14 @@
 
   ir.Primitive visitBreakStatement(ast.BreakStatement node) {
     if (!irBuilder.buildBreak(elements.getTargetOf(node))) {
-      compiler.internalError(node, "'break' target not found");
+      reporter.internalError(node, "'break' target not found");
     }
     return null;
   }
 
   ir.Primitive visitContinueStatement(ast.ContinueStatement node) {
     if (!irBuilder.buildContinue(elements.getTargetOf(node))) {
-      compiler.internalError(node, "'continue' target not found");
+      reporter.internalError(node, "'continue' target not found");
     }
     return null;
   }
@@ -2065,8 +2069,7 @@
   }
 
   @override
-  ir.Primitive bulkHandleError(ast.Send node, ErroneousElement error, _) {
-    assert(compiler.compilationFailed);
+  ir.Primitive bulkHandleError(ast.Node node, ErroneousElement error, _) {
     return irBuilder.buildNullConstant();
   }
 
@@ -2259,7 +2262,7 @@
   }
 
   internalError(ast.Node node, String message) {
-    compiler.internalError(node, message);
+    reporter.internalError(node, message);
   }
 
   @override
@@ -2496,7 +2499,7 @@
 
   ClassElement get nullClass => _compiler.nullClass;
 
-  DartType unaliasType(DartType type) => type.unalias(_compiler);
+  DartType unaliasType(DartType type) => type.unalias(_compiler.resolution);
 
   TypeMask getTypeMaskForForeign(NativeBehavior behavior) {
     if (behavior == null) {
@@ -2647,7 +2650,7 @@
           break;
 
         default:
-          compiler.internalError(element, "Unexpected element type $element");
+          reporter.internalError(element, "Unexpected element type $element");
       }
       return root;
     });
@@ -2906,7 +2909,7 @@
               fieldValues);
           hasConstructorCall = true;
         } else {
-          compiler.internalError(initializer,
+          reporter.internalError(initializer,
                                  "Unexpected initializer type $initializer");
         }
       }
@@ -2916,7 +2919,7 @@
       ClassElement superClass = enclosingClass.superclass;
       FunctionElement target = superClass.lookupDefaultConstructor();
       if (target == null) {
-        compiler.internalError(superClass, "No default constructor available.");
+        reporter.internalError(superClass, "No default constructor available.");
       }
       target = target.implementation;
       evaluateConstructorCallFromInitializer(
@@ -3372,7 +3375,7 @@
                                               CallStructure callStructure) {
       Element element = backend.isolateHelperLibrary.find(helperName);
       if (element == null) {
-        compiler.internalError(node,
+        reporter.internalError(node,
             'Isolate library and compiler mismatch.');
       }
       List<ir.Primitive> arguments = translateStaticArguments(argumentList,
diff --git a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
index b9b6b09..4de0cab 100644
--- a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
+++ b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
@@ -43,7 +43,7 @@
   final World _classWorld;
 
   ScalarReplacer(dart2js.Compiler compiler)
-      : _internalError = compiler.internalError,
+      : _internalError = compiler.reporter.internalError,
         _classWorld = compiler.world;
 
   @override
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 893113f..a84d28d 100644
--- a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
@@ -133,10 +133,7 @@
     if (!mask.isValue) return null;
     if (mask.isNullable) return null;  // e.g. 'true or null'.
     ValueTypeMask valueMask = mask;
-    var value = valueMask.value;
-    // TODO(sra): Why is ValueTypeMask.value not a ConstantValue?
-    if (value == false) return new FalseConstantValue();
-    if (value == true) return new TrueConstantValue();
+    if (valueMask.value.isBool) return valueMask.value;
     // TODO(sra): Consider other values. Be careful with large strings.
     return null;
   }
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index 383b39f..ecf555d 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -355,7 +355,7 @@
                  TypeMaskSystem typeSystem,
                  this._functionCompiler)
       : _compiler = compiler,
-        _internalError = compiler.internalError,
+        _internalError = compiler.reporter.internalError,
         _typeSystem = typeSystem,
         _lattice = new ConstantPropagationLattice(
             typeSystem,
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index c250be1..bc511e4 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -329,9 +329,6 @@
                       (_) => diagnosticHandler.enableColors = true),
     new OptionHandler('--enable[_-]checked[_-]mode|--checked',
                       (_) => setCheckedMode(Flags.enableCheckedMode)),
-    new OptionHandler(Flags.enableConcreteTypeInference,
-                      (_) => implyCompilation(
-                          Flags.enableConcreteTypeInference)),
     new OptionHandler(Flags.trustTypeAnnotations,
                       (_) => setTrustTypeAnnotations(
                           Flags.trustTypeAnnotations)),
diff --git a/pkg/compiler/lib/src/dart_backend/backend.dart b/pkg/compiler/lib/src/dart_backend/backend.dart
index c29ae0e..85427b1 100644
--- a/pkg/compiler/lib/src/dart_backend/backend.dart
+++ b/pkg/compiler/lib/src/dart_backend/backend.dart
@@ -52,7 +52,7 @@
       new Set<ClassElement>();
 
   bool enableCodegenWithErrorsIfSupported(Spannable node) {
-    compiler.reportHintMessage(
+    reporter.reportHintMessage(
         node,
         MessageKind.GENERIC,
         {'text': "Generation of code with compile time errors is not "
@@ -108,7 +108,7 @@
         stripAsserts = strips.indexOf('asserts') != -1,
         constantCompilerTask = new DartConstantTask(compiler),
         outputter = new DartOutputter(
-            compiler, compiler.outputProvider,
+            compiler.reporter, compiler.outputProvider,
             forceStripTypes: strips.indexOf('types') != -1,
             multiFile: multiFile,
             enableMinification: compiler.enableMinification),
@@ -116,6 +116,11 @@
     resolutionCallbacks = new DartResolutionCallbacks(this);
   }
 
+
+  DiagnosticReporter get reporter => compiler.reporter;
+
+  Resolution get resolution => compiler.resolution;
+
   bool classNeedsRti(ClassElement cls) => false;
   bool methodNeedsRti(FunctionElement function) => false;
 
@@ -128,7 +133,7 @@
     final coreLibrary = compiler.coreLibrary;
     for (final name in LITERAL_TYPE_NAMES) {
       ClassElement classElement = coreLibrary.findLocal(name);
-      classElement.ensureResolved(compiler);
+      classElement.ensureResolved(resolution);
     }
     // Enqueue the methods that the VM might invoke on user objects because
     // we don't trust the resolution to always get these included.
@@ -167,7 +172,7 @@
         newTypedefElementCallback,
         newClassElementCallback) {
       ReferencedElementCollector collector =
-          new ReferencedElementCollector(compiler,
+          new ReferencedElementCollector(reporter,
                                          element,
                                          elementAst,
                                          newTypedefElementCallback,
@@ -178,7 +183,7 @@
     int totalSize = outputter.assembleProgram(
         libraries: compiler.libraryLoader.libraries,
         instantiatedClasses: compiler.resolverWorld.directlyInstantiatedClasses,
-        resolvedElements: compiler.enqueuer.resolution.resolvedElements,
+        resolvedElements: compiler.enqueuer.resolution.processedElements,
         usedTypeLiterals: usedTypeLiterals,
         postProcessElementAst: postProcessElementAst,
         computeElementAst: computeElementAst,
@@ -214,7 +219,7 @@
         'Output total size: $totalOutputSize bytes (${percentage}%)');
   }
 
-  log(String message) => compiler.log('[DartBackend] $message');
+  log(String message) => reporter.log('[DartBackend] $message');
 
   @override
   Future onLibrariesLoaded(LoadedLibraries loadedLibraries) {
@@ -225,7 +230,7 @@
         library.forEachLocalMember((Element element) {
           if (element.isClass) {
             ClassElement classElement = element;
-            classElement.ensureResolved(compiler);
+            classElement.ensureResolved(resolution);
           }
         });
       }
@@ -306,7 +311,7 @@
               if (element.isConstructor || element.isStatic) return;
 
               FunctionElement function = element.asFunctionElement();
-              element.computeType(compiler);
+              element.computeType(resolution);
               Selector selector = new Selector.fromElement(element);
               if (selector.isGetter) {
                 registry.registerDynamicGetter(
@@ -330,7 +335,7 @@
   @override
   bool enableDeferredLoadingIfSupported(Spannable node, Registry registry) {
     // TODO(sigurdm): Implement deferred loading for dart2dart.
-    compiler.reportWarningMessage(
+    reporter.reportWarningMessage(
         node, MessageKind.DEFERRED_LIBRARY_DART_2_DART);
     return false;
   }
@@ -341,6 +346,24 @@
 
   DartResolutionCallbacks(this.backend);
 
+  @override
+  WorldImpact transformImpact(ResolutionWorldImpact worldImpact) {
+    TransformedWorldImpact transformed =
+        new TransformedWorldImpact(worldImpact);
+    for (DartType typeLiteral in worldImpact.typeLiterals) {
+      onTypeLiteral(typeLiteral, transformed);
+    }
+    for (InterfaceType instantiatedType in worldImpact.instantiatedTypes) {
+      // TODO(johnniwinther): Remove this when dependency tracking is done on
+      // the world impact itself.
+      transformed.registerInstantiation(instantiatedType);
+      backend.registerInstantiatedType(
+          instantiatedType, backend.compiler.enqueuer.resolution, transformed);
+    }
+    return transformed;
+  }
+
+  @override
   void onTypeLiteral(DartType type, Registry registry) {
     if (type.isInterfaceType) {
       backend.usedTypeLiterals.add(type.element);
@@ -385,13 +408,13 @@
  * (just to name a few).  Retraverse AST to pick those up.
  */
 class ReferencedElementCollector extends Visitor {
-  final Compiler compiler;
+  final DiagnosticReporter reporter;
   final Element element;
   final ElementAst elementAst;
   final newTypedefElementCallback;
   final newClassElementCallback;
 
-  ReferencedElementCollector(this.compiler,
+  ReferencedElementCollector(this.reporter,
                              this.element,
                              this.elementAst,
                              this.newTypedefElementCallback,
@@ -412,7 +435,7 @@
   }
 
   void collect() {
-    compiler.withCurrentElement(element, () {
+    reporter.withCurrentElement(element, () {
       elementAst.ast.accept(this);
     });
   }
diff --git a/pkg/compiler/lib/src/dart_backend/dart_backend.dart b/pkg/compiler/lib/src/dart_backend/dart_backend.dart
index 9c42e1d..fcfc0c8 100644
--- a/pkg/compiler/lib/src/dart_backend/dart_backend.dart
+++ b/pkg/compiler/lib/src/dart_backend/dart_backend.dart
@@ -19,7 +19,10 @@
 import '../common/registry.dart' show
     Registry;
 import '../common/resolution.dart' show
-    ResolutionCallbacks;
+    Resolution,
+    ResolutionCallbacks,
+    ResolutionWorldImpact,
+    TransformedWorldImpact;
 import '../common/tasks.dart' show
     CompilerTask;
 import '../compiler.dart' show
diff --git a/pkg/compiler/lib/src/dart_backend/outputter.dart b/pkg/compiler/lib/src/dart_backend/outputter.dart
index a8240ad..3e6f564 100644
--- a/pkg/compiler/lib/src/dart_backend/outputter.dart
+++ b/pkg/compiler/lib/src/dart_backend/outputter.dart
@@ -18,7 +18,7 @@
 /// Output engine for dart2dart that is shared between the dart2js and the
 /// analyzer implementations of dart2dart.
 class DartOutputter {
-  final DiagnosticListener listener;
+  final DiagnosticReporter reporter;
   final CompilerOutputProvider outputProvider;
   final bool forceStripTypes;
 
@@ -37,7 +37,7 @@
   ElementInfo elementInfo;
 
   // TODO(johnniwinther): Support recompilation.
-  DartOutputter(this.listener, this.outputProvider,
+  DartOutputter(this.reporter, this.outputProvider,
                 {bool this.forceStripTypes: false,
                  bool this.enableMinification: false,
                  bool this.multiFile: false});
@@ -97,7 +97,7 @@
     }
 
     libraryInfo = LibraryInfo.processLibraries(
-        listener, libraries, resolvedElements);
+        reporter, libraries, resolvedElements);
 
     elementInfo = ElementInfoProcessor.createElementInfo(
         instantiatedClasses,
@@ -109,7 +109,7 @@
         sortElements: sortElements);
 
     PlaceholderCollector collector = collectPlaceholders(
-        listener,
+        reporter,
         mirrorRenamer,
         mainFunction,
         libraryInfo,
@@ -124,7 +124,7 @@
         isSafeToRemoveTypeDeclarations: isSafeToRemoveTypeDeclarations);
 
     if (outputAst) {
-      String code = astOutput(listener, elementInfo);
+      String code = astOutput(reporter, elementInfo);
       outputProvider("", "dart")
                  ..add(code)
                  ..close();
@@ -147,14 +147,14 @@
   }
 
   static PlaceholderCollector collectPlaceholders(
-      DiagnosticListener listener,
+      DiagnosticReporter reporter,
       MirrorRenamer mirrorRenamer,
       FunctionElement mainFunction,
       LibraryInfo libraryInfo,
       ElementInfo elementInfo) {
     // Create all necessary placeholders.
     PlaceholderCollector collector = new PlaceholderCollector(
-        listener,
+        reporter,
         mirrorRenamer,
         libraryInfo.fixedDynamicNames,
         elementInfo.elementAsts,
@@ -194,13 +194,13 @@
     return placeholderRenamer;
   }
 
-  static String astOutput(DiagnosticListener listener,
+  static String astOutput(DiagnosticReporter reporter,
                           ElementInfo elementInfo) {
     // TODO(antonm): Ideally XML should be a separate backend.
     // TODO(antonm): obey renames and minification, at least as an option.
     StringBuffer sb = new StringBuffer();
     outputElement(element) {
-      sb.write(element.parseNode(listener).toDebugString());
+      sb.write(element.parseNode(reporter).toDebugString());
     }
 
     // Emit XML for AST instead of the program.
@@ -229,7 +229,7 @@
               this.userLibraries);
 
   static LibraryInfo processLibraries(
-      DiagnosticListener listener,
+      DiagnosticReporter reporter,
       Iterable<LibraryElement> libraries,
       Iterable<AstElement> resolvedElements) {
     Set<String> fixedStaticNames = new Set<String>();
@@ -299,14 +299,14 @@
         ClassElement existingEnumClass =
             enumClassMap.putIfAbsent(cls.name, () => cls);
         if (existingEnumClass != cls) {
-          listener.reportError(
-              listener.createMessage(
+          reporter.reportError(
+              reporter.createMessage(
                   cls,
                   MessageKind.GENERIC,
                   {'text': "Duplicate enum names are not supported "
                            "in dart2dart."}),
           <DiagnosticMessage>[
-              listener.createMessage(
+              reporter.createMessage(
                   existingEnumClass,
                   MessageKind.GENERIC,
                   {'text': "This is the other declaration of '${cls.name}'."}),
diff --git a/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart b/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart
index b15e76a..42c15f9 100644
--- a/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart
+++ b/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart
@@ -170,7 +170,7 @@
 }
 
 class PlaceholderCollector extends Visitor {
-  final DiagnosticListener listener;
+  final DiagnosticReporter reporter;
   final MirrorRenamer mirrorRenamer;
   final FunctionElement mainFunction;
   final Set<String> fixedMemberNames; // member names which cannot be renamed.
@@ -196,7 +196,7 @@
   get currentFunctionScope => functionScopes.putIfAbsent(
       topmostEnclosingFunction, () => new FunctionScope());
 
-  PlaceholderCollector(this.listener, this.mirrorRenamer,
+  PlaceholderCollector(this.reporter, this.mirrorRenamer,
                        this.fixedMemberNames, this.elementAsts,
                        this.mainFunction);
 
@@ -258,7 +258,7 @@
     currentLocalPlaceholders = new Map<String, LocalPlaceholder>();
     if (!(element is ConstructorElement && element.isRedirectingFactory)) {
       // Do not visit the body of redirecting factories.
-      listener.withCurrentElement(element, () {
+      reporter.withCurrentElement(element, () {
         elementNode.accept(this);
       });
     }
@@ -475,7 +475,7 @@
   }
 
   void internalError(String reason, {Node node}) {
-    listener.internalError(node, reason);
+    reporter.internalError(node, reason);
   }
 
   visit(Node node) => (node == null) ? null : node.accept(this);
diff --git a/pkg/compiler/lib/src/dart_types.dart b/pkg/compiler/lib/src/dart_types.dart
index 1686c5a..353c00a 100644
--- a/pkg/compiler/lib/src/dart_types.dart
+++ b/pkg/compiler/lib/src/dart_types.dart
@@ -6,9 +6,13 @@
 
 import 'dart:math' show min;
 
-import 'core_types.dart';
+import 'common/resolution.dart' show
+    Resolution;
 import 'compiler.dart' show
     Compiler;
+import 'core_types.dart';
+import 'diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import 'diagnostics/invariant.dart' show
     invariant;
 import 'diagnostics/spannable.dart' show
@@ -82,7 +86,7 @@
    * function type [: (B) -> A :] and the unaliased type of
    * [: Func<int,String> :] is the function type [: (String) -> int :].
    */
-  DartType unalias(Compiler compiler);
+  DartType unalias(Resolution resolution);
 
   /**
    * If this type is malformed or a generic type created with the wrong number
@@ -215,7 +219,7 @@
     return this;
   }
 
-  DartType unalias(Compiler compiler) => this;
+  DartType unalias(Resolution resolution) => this;
 
   TypeVariableType get typeVariableOccurrence => this;
 
@@ -249,7 +253,7 @@
 
   DartType subst(List<DartType> arguments, List<DartType> parameters) => this;
 
-  DartType unalias(Compiler compiler) => this;
+  DartType unalias(Resolution resolution) => this;
 
   accept(DartTypeVisitor visitor, var argument) {
     return visitor.visitStatementType(this, argument);
@@ -270,7 +274,7 @@
     return this;
   }
 
-  DartType unalias(Compiler compiler) => this;
+  DartType unalias(Resolution resolution) => this;
 
   accept(DartTypeVisitor visitor, var argument) {
     return visitor.visitVoidType(this, argument);
@@ -320,7 +324,7 @@
   // Malformed types are treated as dynamic.
   bool get treatAsDynamic => true;
 
-  DartType unalias(Compiler compiler) => this;
+  DartType unalias(Resolution resolution) => this;
 
   accept(DartTypeVisitor visitor, var argument) {
     return visitor.visitMalformedType(this, argument);
@@ -487,7 +491,7 @@
     return null;
   }
 
-  DartType unalias(Compiler compiler) => this;
+  DartType unalias(Resolution resolution) => this;
 
   MemberSignature lookupInterfaceMember(Name name) {
     MemberSignature member = element.lookupInterfaceMember(name);
@@ -613,8 +617,6 @@
     assert(namedParameters.length == namedParameterTypes.length);
   }
 
-
-
   TypeKind get kind => TypeKind.FUNCTION;
 
   DartType getNamedParameterType(String name) {
@@ -658,7 +660,7 @@
     return this;
   }
 
-  DartType unalias(Compiler compiler) => this;
+  DartType unalias(Resolution resolution) => this;
 
   TypeVariableType get typeVariableOccurrence {
     TypeVariableType typeVariableType = returnType.typeVariableOccurrence;
@@ -783,10 +785,10 @@
     return new TypedefType(element, newTypeArguments);
   }
 
-  DartType unalias(Compiler compiler) {
-    element.ensureResolved(compiler);
-    element.checkCyclicReference(compiler);
-    DartType definition = element.alias.unalias(compiler);
+  DartType unalias(Resolution resolution) {
+    element.ensureResolved(resolution);
+    element.checkCyclicReference(resolution);
+    DartType definition = element.alias.unalias(resolution);
     return definition.substByContext(this);
   }
 
@@ -811,7 +813,7 @@
         message: 'Alias must be non-null on $element.'));
   }
 
-  FunctionType unalias(Compiler compiler) => alias;
+  FunctionType unalias(Resolution resolution) => alias;
 }
 
 /**
@@ -828,7 +830,7 @@
 
   TypeKind get kind => TypeKind.DYNAMIC;
 
-  DartType unalias(Compiler compiler) => this;
+  DartType unalias(Resolution resolution) => this;
 
   DartType subst(List<DartType> arguments, List<DartType> parameters) => this;
 
@@ -949,6 +951,7 @@
     extends BaseDartTypeVisitor<bool, DartType> {
   final Compiler compiler;
   CoreTypes get coreTypes => compiler.coreTypes;
+  Resolution get resolution => compiler.resolution;
 
   AbstractTypeRelation(this.compiler);
 
@@ -977,7 +980,7 @@
 
     // TODO(johnniwinther): Currently needed since literal types like int,
     // double, bool etc. might not have been resolved yet.
-    t.element.ensureResolved(compiler);
+    t.element.ensureResolved(resolution);
 
     bool checkTypeArguments(InterfaceType instance, InterfaceType other) {
       List<DartType> tTypeArgs = instance.typeArguments;
@@ -1142,8 +1145,8 @@
     if (s == coreTypes.objectType) {
       return true;
     }
-    t = t.unalias(compiler);
-    s = s.unalias(compiler);
+    t = t.unalias(resolution);
+    s = s.unalias(resolution);
 
     return t.accept(this, s);
   }
@@ -1242,6 +1245,10 @@
 
   CoreTypes get coreTypes => compiler.coreTypes;
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
+  Resolution get resolution => compiler.resolution;
+
   Types(Compiler compiler)
       : this.compiler = compiler,
         this.moreSpecificVisitor = new MoreSpecificVisitor(compiler),
@@ -1541,7 +1548,7 @@
       }
     }
 
-    compiler.internalError(CURRENT_ELEMENT_SPANNABLE,
+    reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
         'No least upper bound computed for $a and $b.');
     return null;
   }
@@ -1642,8 +1649,8 @@
       return computeLeastUpperBoundTypeVariableTypes(a, b);
     }
 
-    a = a.unalias(compiler);
-    b = b.unalias(compiler);
+    a = a.unalias(resolution);
+    b = b.unalias(resolution);
 
     if (a.treatAsDynamic || b.treatAsDynamic) return const DynamicType();
     if (a.isVoid || b.isVoid) return const VoidType();
@@ -1704,7 +1711,7 @@
     if (type.isMalformed) {
       return const DynamicType();
     }
-    return type.unalias(compiler);
+    return type.unalias(compiler.resolution);
   }
 
   /// Computes the interface type of [type], which is the type that defines
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 9615406..d0f3120 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -6,6 +6,8 @@
 
 import 'common/backend_api.dart' show
     Backend;
+import 'common/resolution.dart' show
+    Resolution;
 import 'common/tasks.dart' show
     CompilerTask;
 import 'compiler.dart' show
@@ -201,7 +203,7 @@
     String name =
         _importDeferName[new _DeclaredDeferredImport(prefix.deferredImport)];
     if (name == null) {
-      compiler.internalError(node, "No deferred name for $prefix.");
+      reporter.internalError(node, "No deferred name for $prefix.");
     }
     return name;
   }
@@ -283,7 +285,7 @@
         collectTypeDependencies(type.returnType);
       } else if (type is TypedefType) {
         elements.add(type.element);
-        collectTypeDependencies(type.unalias(compiler));
+        collectTypeDependencies(type.unalias(compiler.resolution));
       } else if (type is InterfaceType) {
         elements.add(type.element);
       }
@@ -302,7 +304,7 @@
       // TODO(sigurdm): We want to be more specific about this - need a better
       // way to query "liveness".
       if (astElement is! TypedefElement &&
-          !compiler.enqueuer.resolution.hasBeenResolved(astElement)) {
+          !compiler.enqueuer.resolution.hasBeenProcessed(astElement)) {
         return;
       }
 
@@ -354,7 +356,7 @@
       // to.  Static members are not relevant, unless we are processing
       // extra dependencies due to mirrors.
       void addLiveInstanceMember(Element element) {
-        if (!compiler.enqueuer.resolution.hasBeenResolved(element)) return;
+        if (!compiler.enqueuer.resolution.hasBeenProcessed(element)) return;
         if (!isMirrorUsage && !element.isInstanceMember) return;
         collectDependencies(element.implementation);
       }
@@ -714,7 +716,7 @@
     Map<String, ImportElement> prefixDeferredImport =
         new Map<String, ImportElement>();
     for (LibraryElement library in compiler.libraryLoader.libraries) {
-      compiler.withCurrentElement(library, () {
+      reporter.withCurrentElement(library, () {
         prefixDeferredImport.clear();
         usedPrefixes.clear();
         // TODO(sigurdm): Make helper getLibraryImportTags when tags is a List
@@ -724,12 +726,12 @@
           List<MetadataAnnotation> metadataList = import.metadata;
           if (metadataList != null) {
             for (MetadataAnnotation metadata in metadataList) {
-              metadata.ensureResolved(compiler);
+              metadata.ensureResolved(compiler.resolution);
               ConstantValue value =
                   compiler.constants.getConstantValue(metadata.constant);
               Element element = value.getType(compiler.coreTypes).element;
               if (element == deferredLibraryClass) {
-                 compiler.reportErrorMessage(
+                 reporter.reportErrorMessage(
                      import, MessageKind.DEFERRED_OLD_SYNTAX);
               }
             }
@@ -746,7 +748,7 @@
             _allDeferredImports[key] = importedLibrary;
 
             if (prefix == null) {
-              compiler.reportErrorMessage(
+              reporter.reportErrorMessage(
                   import,
                   MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX);
             } else {
@@ -763,7 +765,7 @@
               ImportElement failingImport = (previousDeferredImport != null)
                   ? previousDeferredImport
                   : import;
-              compiler.reportErrorMessage(
+              reporter.reportErrorMessage(
                   failingImport.prefix,
                   MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX);
             }
@@ -922,7 +924,7 @@
       List<MetadataAnnotation> metadatas = declaration.metadata;
       assert(metadatas != null);
       for (MetadataAnnotation metadata in metadatas) {
-        metadata.ensureResolved(compiler);
+        metadata.ensureResolved(compiler.resolution);
         ConstantValue value =
             compiler.constants.getConstantValue(metadata.constant);
         Element element = value.getType(compiler.coreTypes).element;
diff --git a/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart b/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart
index e2e4d1a..7d624b2 100644
--- a/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart
+++ b/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart
@@ -12,8 +12,35 @@
     Element;
 import 'messages.dart';
 
+class DiagnosticOptions {
+
+  /// Emit terse diagnostics without howToFix.
+  final bool terseDiagnostics;
+
+  /// If `true`, warnings and hints not from user code are reported.
+  final bool showPackageWarnings;
+
+  /// If `true`, warnings are not reported.
+  final bool suppressWarnings;
+
+  /// If `true`, warnings cause the compilation to fail.
+  final bool fatalWarnings;
+
+  /// If `true`, hints are not reported.
+  final bool suppressHints;
+
+  const DiagnosticOptions({
+    this.suppressWarnings: false,
+    this.fatalWarnings: false,
+    this.suppressHints: false,
+    this.terseDiagnostics: false,
+    this.showPackageWarnings: false});
+}
+
 // TODO(johnniwinther): Rename and cleanup this interface. Add severity enum.
-abstract class DiagnosticListener {
+abstract class DiagnosticReporter {
+  DiagnosticOptions get options => const DiagnosticOptions();
+
   // TODO(karlklose): rename log to something like reportInfo.
   void log(message);
 
diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart
index 33a6ba3..347b25b 100644
--- a/pkg/compiler/lib/src/diagnostics/messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/messages.dart
@@ -3352,7 +3352,11 @@
       MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND:
         const MessageTemplate(
           MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND,
-          "dart:mirrors library is not supported when using this backend."),
+          """
+dart:mirrors library is not supported when using this backend.
+
+Your app imports dart:mirrors via:""""""
+$MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING#{importChain}"""),
 
       MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS:
         const MessageTemplate(MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS,
@@ -3393,6 +3397,10 @@
   static const String IMPORT_EXPERIMENTAL_MIRRORS_PADDING = '\n*   ';
 
   /// Padding used before and between import chains in the message for
+  /// [MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND].
+  static const String MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING = '\n   ';
+
+  /// Padding used before and between import chains in the message for
   /// [MessageKind.DISALLOWED_LIBRARY_IMPORT].
   static const String DISALLOWED_LIBRARY_IMPORT_PADDING = '\n  ';
 
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 88d1be1..e9d7c05 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -31,6 +31,7 @@
 import 'js/js.dart' as jsAst;
 import 'universe/universe.dart' show
     UniverseSelector;
+import 'info/send_info.dart' show collectSendMeasurements;
 
 class ElementInfoCollector extends BaseElementVisitor<Info, dynamic> {
   final Compiler compiler;
@@ -226,6 +227,8 @@
 
   FunctionInfo visitFunctionElement(FunctionElement element, _) {
     int size = compiler.dumpInfoTask.sizeOf(element);
+    // TODO(sigmund): consider adding a small info to represent unreachable
+    // code here.
     if (size == 0 && !shouldKeep(element)) return null;
 
     String name = element.name;
@@ -317,6 +320,9 @@
     }
     info.closures = nestedClosures;
     result.functions.add(info);
+    if (const bool.fromEnvironment('send_stats')) {
+      info.measurements = collectSendMeasurements(element, compiler);
+    }
     return info;
   }
 
@@ -486,16 +492,9 @@
     return sb.toString();
   }
 
-  void collectInfo() {
-    infoCollector = new ElementInfoCollector(compiler)..run();
-  }
-
   void dumpInfo() {
     measure(() {
-      if (infoCollector == null) {
-        collectInfo();
-      }
-
+      infoCollector = new ElementInfoCollector(compiler)..run();
       StringBuffer jsonBuffer = new StringBuffer();
       dumpInfoJson(jsonBuffer);
       compiler.outputProvider('', 'info.json')
@@ -561,7 +560,7 @@
     ChunkedConversionSink<Object> sink = encoder.startChunkedConversion(
         new StringConversionSink.fromStringSink(buffer));
     sink.add(result.toJson());
-    compiler.reportInfo(NO_LOCATION_SPANNABLE, MessageKind.GENERIC, {
+    reporter.reportInfo(NO_LOCATION_SPANNABLE, MessageKind.GENERIC, {
       'text': "View the dumped .info.json file at "
           "https://dart-lang.github.io/dump-info-visualizer"
     });
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index d3e5d5d..d10bf45 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -4,6 +4,8 @@
 
 library elements;
 
+import '../common/resolution.dart' show
+    Resolution;
 import '../compiler.dart' show
     Compiler;
 import '../constants/constructors.dart';
@@ -425,7 +427,7 @@
 
   /// Unwraps [element] reporting any warnings attached to it, if any.
   static Element unwrap(Element element,
-                        DiagnosticListener listener,
+                        DiagnosticReporter listener,
                         Spannable spannable) {
     if (element != null && element.isWarnOnUse) {
       WarnOnUseElement wrappedElement = element;
@@ -804,7 +806,7 @@
   /// Reports the attached warning and returns the wrapped element.
   /// [usageSpannable] is used to report messages on the reference of
   /// [wrappedElement].
-  Element unwrap(DiagnosticListener listener, Spannable usageSpannable);
+  Element unwrap(DiagnosticReporter listener, Spannable usageSpannable);
 }
 
 /// An ambiguous element represents multiple elements accessible by the same
@@ -821,7 +823,7 @@
 
   /// Compute the info messages associated with an error/warning on [context].
   List<DiagnosticMessage> computeInfos(
-      Element context, DiagnosticListener listener);
+      Element context, DiagnosticReporter listener);
 }
 
 // TODO(kasperl): This probably shouldn't be called an element. It's
@@ -967,7 +969,7 @@
   /// For instance `(int)->void` for `typedef void F(int)`.
   DartType get alias;
 
-  void checkCyclicReference(Compiler compiler);
+  void checkCyclicReference(Resolution resolution);
 }
 
 /// An executable element is an element that can hold code.
@@ -1315,7 +1317,7 @@
   /// error and calling [computeType] covers that error.
   /// This method will go away!
   @deprecated
-  GenericType computeType(Compiler compiler);
+  GenericType computeType(Resolution resolution);
 
   /**
    * The `this type` for this type declaration.
@@ -1355,7 +1357,7 @@
 
   bool get isResolved;
 
-  void ensureResolved(Compiler compiler);
+  void ensureResolved(Resolution resolution);
 }
 
 abstract class ClassElement extends TypeDeclarationElement
@@ -1570,7 +1572,7 @@
   bool get hasNode;
   Node get node;
 
-  MetadataAnnotation ensureResolved(Compiler compiler);
+  MetadataAnnotation ensureResolved(Resolution resolution);
 }
 
 /// An [Element] that has a type.
@@ -1582,7 +1584,7 @@
   /// error and calling [computeType] covers that error.
   /// This method will go away!
   @deprecated
-  DartType computeType(Compiler compiler);
+  DartType computeType(Resolution resolution);
 
   DartType get type;
 }
diff --git a/pkg/compiler/lib/src/elements/modelx.dart b/pkg/compiler/lib/src/elements/modelx.dart
index c576f8d..488c7e1 100644
--- a/pkg/compiler/lib/src/elements/modelx.dart
+++ b/pkg/compiler/lib/src/elements/modelx.dart
@@ -4,6 +4,9 @@
 
 library elements.modelx;
 
+import '../common/resolution.dart' show
+    Resolution,
+    Parsing;
 import '../compiler.dart' show
     Compiler;
 import '../constants/constant_constructors.dart';
@@ -67,8 +70,8 @@
 
   Modifiers get modifiers => Modifiers.EMPTY;
 
-  Node parseNode(DiagnosticListener listener) {
-    listener.internalError(this,
+  Node parseNode(Parsing parsing) {
+    parsing.reporter.internalError(this,
         'parseNode not implemented on $this.');
     return null;
   }
@@ -312,8 +315,7 @@
   bool get isRedirectingGenerative => unsupported();
   bool get isRedirectingFactory => unsupported();
 
-  computeSignature(compiler) => unsupported();
-  computeType(compiler) => unsupported();
+  computeType(Resolution resolution) => unsupported();
 
   bool get hasFunctionSignature => false;
 
@@ -393,6 +395,10 @@
     throw new UnsupportedError("effectiveTargetType=");
   }
 
+  void _computeSignature(Resolution resolution) {
+    throw new UnsupportedError("_computeSignature");
+  }
+
   get typeCache {
     throw new UnsupportedError("typeCache");
   }
@@ -409,14 +415,18 @@
     throw new UnsupportedError("immediateRedirectionTarget=");
   }
 
-  get functionSignatureCache {
+  get _functionSignatureCache {
     throw new UnsupportedError("functionSignatureCache");
   }
 
-  set functionSignatureCache(_) {
+  set _functionSignatureCache(_) {
     throw new UnsupportedError("functionSignatureCache=");
   }
 
+  set functionSignature(_) {
+    throw new UnsupportedError("functionSignature=");
+  }
+
   get nestedClosures {
     throw new UnsupportedError("nestedClosures");
   }
@@ -468,24 +478,24 @@
       : this.wrappedElement = wrappedElement,
         super(wrappedElement.name, ElementKind.WARN_ON_USE, enclosingElement);
 
-  Element unwrap(DiagnosticListener listener, Spannable usageSpannable) {
+  Element unwrap(DiagnosticReporter reporter, Spannable usageSpannable) {
     var unwrapped = wrappedElement;
     if (warning != null) {
       Spannable spannable = warning.spannable;
       if (spannable == null) spannable = usageSpannable;
-      DiagnosticMessage warningMessage = listener.createMessage(
+      DiagnosticMessage warningMessage = reporter.createMessage(
           spannable, warning.messageKind, warning.messageArguments);
       List<DiagnosticMessage> infos = <DiagnosticMessage>[];
       if (info != null) {
         Spannable spannable = info.spannable;
         if (spannable == null) spannable = usageSpannable;
-        infos.add(listener.createMessage(
+        infos.add(reporter.createMessage(
             spannable, info.messageKind, info.messageArguments));
       }
-      listener.reportWarning(warningMessage, infos);
+      reporter.reportWarning(warningMessage, infos);
     }
     if (unwrapped.isWarnOnUse) {
-      unwrapped = unwrapped.unwrap(listener, usageSpannable);
+      unwrapped = unwrapped.unwrap(reporter, usageSpannable);
     }
     return unwrapped;
   }
@@ -535,7 +545,7 @@
   }
 
   List<DiagnosticMessage> computeInfos(Element context,
-                                   DiagnosticListener listener) {
+                                       DiagnosticReporter reporter) {
     return const <DiagnosticMessage>[];
   }
 
@@ -559,7 +569,7 @@
 
   List<DiagnosticMessage> computeInfos(
       Element context,
-      DiagnosticListener listener) {
+      DiagnosticReporter reporter) {
     List<DiagnosticMessage> infos = <DiagnosticMessage>[];
     Setlet ambiguousElements = flatten();
     MessageKind code = (ambiguousElements.length == 1)
@@ -567,10 +577,10 @@
     LibraryElementX importer = context.library;
     for (Element element in ambiguousElements) {
       Map arguments = {'name': element.name};
-      infos.add(listener.createMessage(element, code, arguments));
-      listener.withCurrentElement(importer, () {
+      infos.add(reporter.createMessage(element, code, arguments));
+      reporter.withCurrentElement(importer, () {
         for (ImportElement import in importer.importers.getImports(element)) {
-          infos.add(listener.createMessage(
+          infos.add(reporter.createMessage(
               import, MessageKind.IMPORTED_HERE, arguments));
         }
       });
@@ -601,20 +611,20 @@
     return contents[name];
   }
 
-  void add(Element element, DiagnosticListener listener) {
+  void add(Element element, DiagnosticReporter reporter) {
     String name = element.name;
     if (element.isAccessor) {
-      addAccessor(element, contents[name], listener);
+      addAccessor(element, contents[name], reporter);
     } else {
       Element existing = contents.putIfAbsent(name, () => element);
       if (!identical(existing, element)) {
-        listener.reportError(
-            listener.createMessage(
+        reporter.reportError(
+            reporter.createMessage(
                 element,
                 MessageKind.DUPLICATE_DEFINITION,
                 {'name': name}),
             <DiagnosticMessage>[
-                listener.createMessage(
+                reporter.createMessage(
                     existing,
                     MessageKind.EXISTING_DEFINITION,
                     {'name': name}),
@@ -638,15 +648,15 @@
    */
   void addAccessor(AccessorElementX accessor,
                    Element existing,
-                   DiagnosticListener listener) {
+                   DiagnosticReporter reporter) {
     void reportError(Element other) {
-      listener.reportError(
-          listener.createMessage(
+      reporter.reportError(
+          reporter.createMessage(
               accessor,
               MessageKind.DUPLICATE_DEFINITION,
               {'name': accessor.name}),
           <DiagnosticMessage>[
-              listener.createMessage(
+              reporter.createMessage(
                   other,
                   MessageKind.EXISTING_DEFINITION,
                   {'name': accessor.name}),
@@ -689,7 +699,7 @@
       } else {
         field.setter = accessor;
       }
-      add(field, listener);
+      add(field, reporter);
     }
   }
 }
@@ -729,32 +739,32 @@
     localMembers.forEach(f);
   }
 
-  void addMember(Element element, DiagnosticListener listener) {
+  void addMember(Element element, DiagnosticReporter reporter) {
     // Keep a list of top level members.
     localMembers = localMembers.prepend(element);
     // Provide the member to the library to build scope.
     if (enclosingElement.isPatch) {
-      implementationLibrary.addMember(element, listener);
+      implementationLibrary.addMember(element, reporter);
     } else {
-      library.addMember(element, listener);
+      library.addMember(element, reporter);
     }
   }
 
-  void setPartOf(PartOf tag, DiagnosticListener listener) {
+  void setPartOf(PartOf tag, DiagnosticReporter reporter) {
     LibraryElementX library = enclosingElement;
     if (library.entryCompilationUnit == this) {
       partTag = tag;
-      listener.reportErrorMessage(
+      reporter.reportErrorMessage(
           tag, MessageKind.IMPORT_PART_OF);
       return;
     }
     if (!localMembers.isEmpty) {
-      listener.reportErrorMessage(
+      reporter.reportErrorMessage(
           tag, MessageKind.BEFORE_TOP_LEVEL);
       return;
     }
     if (partTag != null) {
-      listener.reportWarningMessage(tag, MessageKind.DUPLICATED_PART_OF);
+      reporter.reportWarningMessage(tag, MessageKind.DUPLICATED_PART_OF);
       return;
     }
     partTag = tag;
@@ -763,19 +773,19 @@
     if (libraryTag != null) {
       String expectedName = libraryTag.name.toString();
       if (expectedName != actualName) {
-        listener.reportWarningMessage(
+        reporter.reportWarningMessage(
             tag.name,
             MessageKind.LIBRARY_NAME_MISMATCH,
             {'libraryName': expectedName});
       }
     } else {
-      listener.reportWarning(
-          listener.createMessage(
+      reporter.reportWarning(
+          reporter.createMessage(
               library,
               MessageKind.MISSING_LIBRARY_NAME,
               {'libraryName': actualName}),
           <DiagnosticMessage>[
-              listener.createMessage(
+              reporter.createMessage(
                   tag.name,
                   MessageKind.THIS_IS_THE_PART_OF_TAG),
           ]);
@@ -834,7 +844,7 @@
   void addImport(Element enclosingElement,
                  Element element,
                  ImportElement import,
-                 DiagnosticListener listener) {
+                 DiagnosticReporter reporter) {
     LibraryElementX library = enclosingElement.library;
     Importers importers = library.importers;
 
@@ -860,7 +870,7 @@
               messageKind,
               {'name': name, 'hiddenUri': hiddenUri, 'hidingUri': hidingUri}),
           new WrappedMessage(
-              listener.spanFromSpannable(import),
+              reporter.spanFromSpannable(import),
               MessageKind.IMPORTED_HERE,
               {'name': name}),
           enclosingElement, hidingElement);
@@ -1062,9 +1072,9 @@
     compilationUnits = compilationUnits.prepend(element);
   }
 
-  void addTag(LibraryTag tag, DiagnosticListener listener) {
+  void addTag(LibraryTag tag, DiagnosticReporter reporter) {
     if (tagsCache != null) {
-      listener.internalError(tag,
+      reporter.internalError(tag,
           "Library tags for $this have already been computed.");
     }
     tagsBuilder.addLast(tag);
@@ -1099,17 +1109,17 @@
    */
   void addImport(Element element,
                  ImportElement import,
-                 DiagnosticListener listener) {
-    importScope.addImport(this, element, import, listener);
+                 DiagnosticReporter reporter) {
+    importScope.addImport(this, element, import, reporter);
   }
 
-  void addMember(Element element, DiagnosticListener listener) {
+  void addMember(Element element, DiagnosticReporter reporter) {
     localMembers = localMembers.prepend(element);
-    addToScope(element, listener);
+    addToScope(element, reporter);
   }
 
-  void addToScope(Element element, DiagnosticListener listener) {
-    localScope.add(element, listener);
+  void addToScope(Element element, DiagnosticReporter reporter) {
+    localScope.add(element, reporter);
   }
 
   Element localLookup(String elementName) {
@@ -1281,14 +1291,14 @@
 
   Element lookupLocalMember(String memberName) => importScope[memberName];
 
-  DartType computeType(Compiler compiler) => const DynamicType();
+  DartType computeType(Resolution resolution) => const DynamicType();
 
   Token get position => firstPosition;
 
   void addImport(Element element,
                  ImportElement import,
-                 DiagnosticListener listener) {
-    importScope.addImport(this, element, import, listener);
+                 DiagnosticReporter reporter) {
+    importScope.addImport(this, element, import, reporter);
   }
 
   accept(ElementVisitor visitor, arg) {
@@ -1336,17 +1346,17 @@
    */
   FunctionSignature functionSignature;
 
-  TypedefType computeType(Compiler compiler) {
+  TypedefType computeType(Resolution resolution) {
     if (thisTypeCache != null) return thisTypeCache;
-    Typedef node = parseNode(compiler);
-    setThisAndRawTypes(compiler, createTypeVariables(node.typeParameters));
-    ensureResolved(compiler);
+    Typedef node = parseNode(resolution.parsing);
+    setThisAndRawTypes(createTypeVariables(node.typeParameters));
+    ensureResolved(resolution);
     return thisTypeCache;
   }
 
-  void ensureResolved(Compiler compiler) {
+  void ensureResolved(Resolution resolution) {
     if (resolutionState == STATE_NOT_STARTED) {
-      compiler.resolver.resolve(this);
+      resolution.resolveTypedef(this);
     }
   }
 
@@ -1358,10 +1368,11 @@
     return new TypeDeclarationScope(enclosingElement.buildScope(), this);
   }
 
-  void checkCyclicReference(Compiler compiler) {
+  void checkCyclicReference(Resolution resolution) {
     if (hasBeenCheckedForCycles) return;
-    var visitor = new TypedefCyclicVisitor(compiler, this);
-    computeType(compiler).accept(visitor, null);
+    TypedefCyclicVisitor visitor =
+        new TypedefCyclicVisitor(resolution.reporter, this);
+    computeType(resolution).accept(visitor, null);
     hasBeenCheckedForCycles = true;
   }
 
@@ -1409,11 +1420,11 @@
     metadataInternal = metadata;
   }
 
-  VariableDefinitions parseNode(Element element, DiagnosticListener listener) {
+  VariableDefinitions parseNode(Element element, Parsing parsing) {
     return definitions;
   }
 
-  DartType computeType(Element element, Compiler compiler) => type;
+  DartType computeType(Element element, Resolution resolution) => type;
 }
 
 abstract class ConstantVariableMixin implements VariableElement {
@@ -1492,10 +1503,10 @@
     return initializerCache;
   }
 
-  Node parseNode(DiagnosticListener listener) {
+  Node parseNode(Parsing parsing) {
     if (definitionsCache != null) return definitionsCache;
 
-    VariableDefinitions definitions = variables.parseNode(this, listener);
+    VariableDefinitions definitions = variables.parseNode(this, parsing);
     createDefinitions(definitions);
     return definitionsCache;
   }
@@ -1535,14 +1546,12 @@
     }
   }
 
-  DartType computeType(Compiler compiler) {
+  DartType computeType(Resolution resolution) {
     if (variables.type != null) return variables.type;
     // Call [parseNode] to ensure that [definitionsCache] and [initializerCache]
     // are set as a consequence of calling [computeType].
-    return compiler.withCurrentElement(this, () {
-      parseNode(compiler);
-      return variables.computeType(this, compiler);
-    });
+    parseNode(resolution.parsing);
+    return variables.computeType(this, resolution);
   }
 
   DartType get type {
@@ -1683,7 +1692,7 @@
     throw new UnsupportedError("copyWithEnclosing");
   }
 
-  DartType computeType(Compiler compiler) => type;
+  DartType computeType(Resolution resolution) => type;
 }
 
 /// [Element] for a parameter-like element.
@@ -1699,7 +1708,7 @@
    * kept to provide full information about parameter names through the mirror
    * system.
    */
-  FunctionSignature functionSignatureCache;
+  FunctionSignature _functionSignatureCache;
 
   FormalElementX(ElementKind elementKind,
                  FunctionTypedElement enclosingElement,
@@ -1714,9 +1723,9 @@
 
   Token get position => identifier.getBeginToken();
 
-  Node parseNode(DiagnosticListener listener) => definitions;
+  Node parseNode(Parsing parsing) => definitions;
 
-  DartType computeType(Compiler compiler) {
+  DartType computeType(Resolution resolution) {
     assert(invariant(this, type != null,
         message: "Parameter type has not been set for $this."));
     return type;
@@ -1729,9 +1738,16 @@
   }
 
   FunctionSignature get functionSignature {
-    assert(invariant(this, typeCache != null,
-            message: "Parameter signature has not been set for $this."));
-    return functionSignatureCache;
+    assert(invariant(this, _functionSignatureCache != null,
+        message: "Parameter signature has not been computed for $this."));
+    return _functionSignatureCache;
+  }
+
+  void set functionSignature(FunctionSignature value) {
+    assert(invariant(this, _functionSignatureCache == null,
+        message: "Parameter signature has already been computed for $this."));
+    _functionSignatureCache = value;
+    typeCache = _functionSignatureCache.type;
   }
 
   bool get hasNode => true;
@@ -1869,7 +1885,7 @@
     throw "internal error: AbstractFieldElement has no type";
   }
 
-  Node parseNode(DiagnosticListener listener) {
+  Node parseNode(Parsing parsing) {
     throw "internal error: AbstractFieldElement has no node";
   }
 
@@ -1951,7 +1967,7 @@
 
   List<FunctionElement> nestedClosures = new List<FunctionElement>();
 
-  FunctionSignature functionSignatureCache;
+  FunctionSignature _functionSignatureCache;
 
   AsyncMarker asyncMarker = AsyncMarker.SYNC;
 
@@ -1971,20 +1987,26 @@
            && !isStatic;
   }
 
-  bool get hasFunctionSignature => functionSignatureCache != null;
+  bool get hasFunctionSignature => _functionSignatureCache != null;
 
-  FunctionSignature computeSignature(Compiler compiler) {
-    if (functionSignatureCache != null) return functionSignatureCache;
-    compiler.withCurrentElement(this, () {
-      functionSignatureCache = compiler.resolver.resolveSignature(this);
-    });
-    return functionSignatureCache;
+  void _computeSignature(Resolution resolution) {
+    if (hasFunctionSignature) return;
+    functionSignature = resolution.resolveSignature(this);
   }
 
   FunctionSignature get functionSignature {
-    assert(invariant(this, functionSignatureCache != null,
+    assert(invariant(this, hasFunctionSignature,
         message: "Function signature has not been computed for $this."));
-    return functionSignatureCache;
+    return _functionSignatureCache;
+  }
+
+  void set functionSignature(FunctionSignature value) {
+    // TODO(johnniwinther): Strengthen the invariant to `!hasFunctionSignature`
+    // when checked mode checks are not enqueued eagerly.
+    assert(invariant(this, !hasFunctionSignature || type == value.type,
+        message: "Function signature has already been computed for $this."));
+    _functionSignatureCache = value;
+    typeCache = _functionSignatureCache.type;
   }
 
   List<ParameterElement> get parameters {
@@ -1995,9 +2017,11 @@
     return list;
   }
 
-  FunctionType computeType(Compiler compiler) {
+  FunctionType computeType(Resolution resolution) {
     if (typeCache != null) return typeCache;
-    typeCache = computeSignature(compiler).type;
+    _computeSignature(resolution);
+    assert(invariant(this, typeCache != null,
+        message: "Type cache expected to be set on $this."));
     return typeCache;
   }
 
@@ -2043,7 +2067,7 @@
   void reuseElement() {
     super.reuseElement();
     nestedClosures.clear();
-    functionSignatureCache = null;
+    _functionSignatureCache = null;
     typeCache = null;
   }
 }
@@ -2114,7 +2138,7 @@
 
   bool get hasNode => true;
 
-  FunctionExpression parseNode(DiagnosticListener listener) => node;
+  FunctionExpression parseNode(Parsing parsing) => node;
 
   Token get position {
     // Use the name as position if this is not an unnamed closure.
@@ -2233,15 +2257,8 @@
         super("loadLibrary",
               Modifiers.EMPTY,
               prefix,
-              false);
-
-  FunctionSignature computeSignature(Compiler compiler) {
-    if (functionSignatureCache != null) return functionSignature;
-    compiler.withCurrentElement(this, () {
-      DartType inner = new FunctionType(this);
-      functionSignatureCache = new FunctionSignatureX(type: inner);
-    });
-    return functionSignatureCache;
+              false) {
+    functionSignature = new FunctionSignatureX(type: new FunctionType(this));
   }
 
   bool get isClassMember => false;
@@ -2255,7 +2272,7 @@
   // error messages.
   Token get position => null;
 
-  FunctionExpression parseNode(DiagnosticListener listener) => null;
+  FunctionExpression parseNode(Parsing parsing) => null;
 
   bool get hasNode => false;
 
@@ -2275,7 +2292,7 @@
               ElementKind.GENERATIVE_CONSTRUCTOR_BODY,
               Modifiers.EMPTY,
               constructor.enclosingElement) {
-    functionSignatureCache = constructor.functionSignature;
+    functionSignature = constructor.functionSignature;
   }
 
   bool get hasNode => constructor.hasNode;
@@ -2286,8 +2303,9 @@
 
   bool get isInstanceMember => true;
 
-  FunctionType computeType(Compiler compiler) {
-    compiler.internalError(this, '$this.computeType.');
+  FunctionType computeType(Resolution resolution) {
+    DiagnosticReporter reporter = resolution.reporter;
+    reporter.internalError(this, '$this.computeType.');
     return null;
   }
 
@@ -2331,11 +2349,11 @@
               ElementKind.GENERATIVE_CONSTRUCTOR,
               Modifiers.EMPTY,
               enclosing) {
-    typeCache = new FunctionType.synthesized(enclosingClass.thisType);
-    functionSignatureCache = new FunctionSignatureX(type: type);
+    functionSignature = new FunctionSignatureX(
+        type: new FunctionType.synthesized(enclosingClass.thisType));
   }
 
-  FunctionExpression parseNode(DiagnosticListener listener) => null;
+  FunctionExpression parseNode(Parsing parsing) => null;
 
   bool get hasNode => false;
 
@@ -2355,18 +2373,16 @@
     }
   }
 
-  FunctionSignature computeSignature(compiler) {
-    if (functionSignatureCache != null) return functionSignatureCache;
+  void _computeSignature(Resolution resolution) {
+    if (hasFunctionSignature) return;
     if (definingConstructor.isErroneous) {
-      return functionSignatureCache =
-          compiler.objectClass.localLookup('').computeSignature(compiler);
+      functionSignature = new FunctionSignatureX(
+          type: new FunctionType.synthesized(enclosingClass.thisType));
     }
     // TODO(johnniwinther): Ensure that the function signature (and with it the
     // function type) substitutes type variables correctly.
-    definingConstructor.computeType(compiler);
-    functionSignatureCache = definingConstructor.functionSignature;
-    typeCache = definingConstructor.type;
-    return functionSignatureCache;
+    definingConstructor.computeType(resolution);
+    functionSignature = definingConstructor.functionSignature;
   }
 
   accept(ElementVisitor visitor, arg) {
@@ -2423,7 +2439,7 @@
 
   T createType(List<DartType> typeArguments);
 
-  void setThisAndRawTypes(Compiler compiler, List<DartType> typeParameters) {
+  void setThisAndRawTypes(List<DartType> typeParameters) {
     assert(invariant(this, thisTypeCache == null,
         message: "This type has already been set on $this."));
     assert(invariant(this, rawTypeCache == null,
@@ -2510,23 +2526,25 @@
   @override
   bool get isEnumClass => false;
 
-  InterfaceType computeType(Compiler compiler) {
+  InterfaceType computeType(Resolution resolution) {
     if (isPatch) {
-      origin.computeType(compiler);
+      origin.computeType(resolution);
       thisTypeCache = origin.thisType;
       rawTypeCache = origin.rawType;
     } else if (thisTypeCache == null) {
-      computeThisAndRawType(compiler, computeTypeParameters(compiler));
+      computeThisAndRawType(
+          resolution, computeTypeParameters(resolution.parsing));
     }
     return thisTypeCache;
   }
 
-  void computeThisAndRawType(Compiler compiler, List<DartType> typeVariables) {
+  void computeThisAndRawType(Resolution resolution,
+                             List<DartType> typeVariables) {
     if (thisTypeCache == null) {
       if (origin == null) {
-        setThisAndRawTypes(compiler, typeVariables);
+        setThisAndRawTypes(typeVariables);
       } else {
-        thisTypeCache = origin.computeType(compiler);
+        thisTypeCache = origin.computeType(resolution);
         rawTypeCache = origin.rawType;
       }
     }
@@ -2537,7 +2555,7 @@
     return new InterfaceType(this, typeArguments);
   }
 
-  List<DartType> computeTypeParameters(Compiler compiler);
+  List<DartType> computeTypeParameters(Parsing parsing);
 
   bool get isObject {
     assert(invariant(this, isResolved,
@@ -2545,14 +2563,15 @@
     return supertype == null;
   }
 
-  void ensureResolved(Compiler compiler) {
+  void ensureResolved(Resolution resolution) {
     if (resolutionState == STATE_NOT_STARTED) {
-      compiler.resolver.resolveClass(this);
-      compiler.world.registerClass(this);
+      resolution.resolveClass(this);
+      resolution.registerClass(this);
     }
   }
 
-  void setDefaultConstructor(FunctionElement constructor, Compiler compiler);
+  void setDefaultConstructor(FunctionElement constructor,
+                             DiagnosticReporter reporter);
 
   void addBackendMember(Element member) {
     // TODO(ngeoffray): Deprecate this method.
@@ -2593,7 +2612,8 @@
    * The returned element may not be resolved yet.
    */
   ClassElement get superclass {
-    assert(supertypeLoadState == STATE_DONE);
+    assert(invariant(this, supertypeLoadState == STATE_DONE,
+        message: "Superclass has not been computed for $this."));
     return supertype == null ? null : supertype.element;
   }
 
@@ -2645,18 +2665,18 @@
   bool get isMixinApplication => false;
   bool get hasLocalScopeMembers => !localScope.isEmpty;
 
-  void addMember(Element element, DiagnosticListener listener) {
+  void addMember(Element element, DiagnosticReporter reporter) {
     localMembersCache = null;
     localMembersReversed = localMembersReversed.prepend(element);
-    addToScope(element, listener);
+    addToScope(element, reporter);
   }
 
-  void addToScope(Element element, DiagnosticListener listener) {
+  void addToScope(Element element, DiagnosticReporter reporter) {
     if (element.isField && element.name == name) {
-      listener.reportErrorMessage(
+      reporter.reportErrorMessage(
           element, MessageKind.MEMBER_USES_CLASS_NAME);
     }
-    localScope.add(element, listener);
+    localScope.add(element, reporter);
   }
 
   Element localLookup(String elementName) {
@@ -2679,13 +2699,14 @@
     return false;
   }
 
-  void setDefaultConstructor(FunctionElement constructor, Compiler compiler) {
+  void setDefaultConstructor(FunctionElement constructor,
+                             DiagnosticReporter reporter) {
     // The default constructor, although synthetic, is part of a class' API.
-    addMember(constructor, compiler);
+    addMember(constructor, reporter);
   }
 
-  List<DartType> computeTypeParameters(Compiler compiler) {
-    ClassNode node = parseNode(compiler);
+  List<DartType> computeTypeParameters(Parsing parsing) {
+    ClassNode node = parseNode(parsing);
     return createTypeVariables(node.typeParameters);
   }
 
@@ -2719,14 +2740,14 @@
   bool get isEnumClass => true;
 
   @override
-  Node parseNode(Compiler compiler) => node;
+  Node parseNode(Parsing parsing) => node;
 
   @override
   accept(ElementVisitor visitor, arg) {
     return visitor.visitEnumClassElement(this, arg);
   }
 
-  List<DartType> computeTypeParameters(Compiler compiler) => const <DartType>[];
+  List<DartType> computeTypeParameters(Parsing parsing) => const <DartType>[];
 
   List<FieldElement> get enumValues {
     assert(invariant(this, _enumValues != null,
@@ -2756,7 +2777,7 @@
   bool get hasNode => true;
 
   @override
-  FunctionExpression parseNode(Compiler compiler) => node;
+  FunctionExpression parseNode(Parsing parsing) => node;
 }
 
 class EnumMethodElementX extends MethodElementX {
@@ -2772,7 +2793,7 @@
   bool get hasNode => true;
 
   @override
-  FunctionExpression parseNode(Compiler compiler) => node;
+  FunctionExpression parseNode(Parsing parsing) => node;
 }
 
 class EnumFormalElementX extends InitializingFormalElementX {
@@ -2826,7 +2847,7 @@
 
   Token get position => node.getBeginToken();
 
-  Node parseNode(DiagnosticListener listener) => node;
+  Node parseNode(Parsing parsing) => node;
 
   FunctionElement lookupLocalConstructor(String name) {
     for (Link<Element> link = constructors;
@@ -2853,24 +2874,25 @@
     });
   }
 
-  void addMember(Element element, DiagnosticListener listener) {
+  void addMember(Element element, DiagnosticReporter reporter) {
     throw new UnsupportedError("Cannot add member to $this.");
   }
 
-  void addToScope(Element element, DiagnosticListener listener) {
-    listener.internalError(this, 'Cannot add to scope of $this.');
+  void addToScope(Element element, DiagnosticReporter reporter) {
+    reporter.internalError(this, 'Cannot add to scope of $this.');
   }
 
   void addConstructor(FunctionElement constructor) {
     constructors = constructors.prepend(constructor);
   }
 
-  void setDefaultConstructor(FunctionElement constructor, Compiler compiler) {
+  void setDefaultConstructor(FunctionElement constructor,
+                             DiagnosticReporter reporter) {
     assert(!hasConstructor);
     addConstructor(constructor);
   }
 
-  List<DartType> computeTypeParameters(Compiler compiler) {
+  List<DartType> computeTypeParameters(Parsing parsing) {
     NamedMixinApplication named = node.asNamedMixinApplication();
     if (named == null) {
       throw new SpannableAssertionFailure(node,
@@ -2955,7 +2977,7 @@
 
   TypeDeclarationElement get typeDeclaration => enclosingElement;
 
-  TypeVariableType computeType(compiler) => type;
+  TypeVariableType computeType(Resolution resolution) => type;
 
   TypeVariableType get type {
     assert(invariant(this, typeCache != null,
@@ -2971,7 +2993,7 @@
 
   bool get hasNode => true;
 
-  Node parseNode(compiler) => node;
+  Node parseNode(Parsing parsing) => node;
 
   Token get position => node.getBeginToken();
 
@@ -3023,18 +3045,18 @@
 
   MetadataAnnotationX([this.resolutionState = STATE_NOT_STARTED]);
 
-  MetadataAnnotation ensureResolved(Compiler compiler) {
+  MetadataAnnotation ensureResolved(Resolution resolution) {
     if (annotatedElement.isClass || annotatedElement.isTypedef) {
       TypeDeclarationElement typeDeclaration = annotatedElement;
-      typeDeclaration.ensureResolved(compiler);
+      typeDeclaration.ensureResolved(resolution);
     }
     if (resolutionState == STATE_NOT_STARTED) {
-      compiler.resolver.resolveMetadataAnnotation(this);
+      resolution.resolveMetadataAnnotation(this);
     }
     return this;
   }
 
-  Node parseNode(DiagnosticListener listener);
+  Node parseNode(Parsing parsing);
 
   String toString() => 'MetadataAnnotation($constant, $resolutionState)';
 }
@@ -3045,7 +3067,7 @@
 
   ParameterMetadataAnnotation(Metadata this.metadata);
 
-  Node parseNode(DiagnosticListener listener) => metadata.expression;
+  Node parseNode(Parsing parsing) => metadata.expression;
 
   Token get beginToken => metadata.getBeginToken();
 
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index b6ecbad..212218d 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -9,6 +9,8 @@
 
 import 'common/names.dart' show
     Identifiers;
+import 'common/resolution.dart' show
+    Resolution;
 import 'common/work.dart' show
     ItemCompilationContext,
     WorkItem;
@@ -25,6 +27,8 @@
 import 'dart_types.dart' show
     DartType,
     InterfaceType;
+import 'diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import 'diagnostics/invariant.dart' show
     invariant;
 import 'diagnostics/spannable.dart' show
@@ -108,9 +112,15 @@
 
   // TODO(johnniwinther): Collect checked types for checked mode separately to
   // support serialization.
-  Iterable<DartType> get checkedTypes => const <DartType>[];
+  Iterable<DartType> get isChecks => const <DartType>[];
+
+  Iterable<DartType> get checkedModeChecks => const <DartType>[];
+
+  Iterable<DartType> get asCasts => const <DartType>[];
 
   Iterable<MethodElement> get closurizedFunctions => const <MethodElement>[];
+
+  Iterable<LocalFunctionElement> get closures => const <LocalFunctionElement>[];
 }
 
 abstract class Enqueuer {
@@ -141,6 +151,9 @@
            this.itemCompilationContextCreator,
            this.strategy);
 
+  // TODO(johnniwinther): Move this to [ResolutionEnqueuer].
+  Resolution get resolution => compiler.resolution;
+
   Queue<WorkItem> get queue;
   bool get queueIsEmpty => queue.isEmpty;
 
@@ -149,9 +162,15 @@
 
   QueueFilter get filter => compiler.enqueuerFilter;
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   /// Returns [:true:] if [member] has been processed by this enqueuer.
   bool isProcessed(Element member);
 
+  bool isClassProcessed(ClassElement cls) => _processedClasses.contains(cls);
+
+  Iterable<ClassElement> get processedClasses => _processedClasses;
+
   /**
    * Documentation wanted -- johnniwinther
    *
@@ -181,10 +200,14 @@
     worldImpact.dynamicGetters.forEach(registerDynamicGetter);
     worldImpact.dynamicSetters.forEach(registerDynamicSetter);
     worldImpact.staticUses.forEach(registerStaticUse);
-    // TODO(johnniwinther): Register [worldImpact.instantiatedTypes] when it
-    // doesn't require a [Registry].
-    worldImpact.checkedTypes.forEach(registerIsCheck);
+    worldImpact.instantiatedTypes.forEach(registerInstantiatedType);
+    worldImpact.isChecks.forEach(registerIsCheck);
+    worldImpact.asCasts.forEach(registerIsCheck);
+    if (compiler.enableTypeAssertions) {
+      worldImpact.checkedModeChecks.forEach(registerIsCheck);
+    }
     worldImpact.closurizedFunctions.forEach(registerGetOfStaticFunction);
+    worldImpact.closures.forEach(registerClosure);
   }
 
   // TODO(johnniwinther): Remove the need for passing the [registry].
@@ -192,7 +215,7 @@
                                 {bool mirrorUsage: false}) {
     task.measure(() {
       ClassElement cls = type.element;
-      cls.ensureResolved(compiler);
+      cls.ensureResolved(resolution);
       universe.registerTypeInstantiation(
           type,
           byMirrors: mirrorUsage,
@@ -261,7 +284,7 @@
       }
     } else if (member.isFunction) {
       FunctionElement function = member;
-      function.computeType(compiler);
+      function.computeType(resolution);
       if (function.name == Identifiers.noSuchMethod_) {
         registerNoSuchMethod(function);
       }
@@ -286,7 +309,7 @@
       }
     } else if (member.isGetter) {
       FunctionElement getter = member;
-      getter.computeType(compiler);
+      getter.computeType(resolution);
       if (universe.hasInvokedGetter(getter, compiler.world)) {
         addToWorkList(getter);
         return;
@@ -299,7 +322,7 @@
       }
     } else if (member.isSetter) {
       FunctionElement setter = member;
-      setter.computeType(compiler);
+      setter.computeType(resolution);
       if (universe.hasInvokedSetter(setter, compiler.world)) {
         addToWorkList(setter);
         return;
@@ -321,14 +344,23 @@
       if (_processedClasses.contains(cls)) return;
       // The class must be resolved to compute the set of all
       // supertypes.
-      cls.ensureResolved(compiler);
+      cls.ensureResolved(resolution);
 
       void processClass(ClassElement superclass) {
         if (_processedClasses.contains(superclass)) return;
+        // TODO(johnniwinther): Re-insert this invariant when unittests don't
+        // fail. There is already a similar invariant on the members.
+        /*if (!isResolutionQueue) {
+          assert(invariant(superclass,
+              superclass.isClosure ||
+              compiler.enqueuer.resolution.isClassProcessed(superclass),
+              message: "Class $superclass has not been "
+                       "processed in resolution."));
+        }*/
 
         _processedClasses.add(superclass);
         recentClasses.add(superclass);
-        superclass.ensureResolved(compiler);
+        superclass.ensureResolved(resolution);
         superclass.implementation.forEachMember(processInstantiatedClassMember);
         if (isResolutionQueue && !superclass.isSynthesized) {
           compiler.resolver.checkClass(superclass);
@@ -416,7 +448,7 @@
       logEnqueueReflectiveAction(element);
       if (element.isTypedef) {
         TypedefElement typedef = element;
-        typedef.ensureResolved(compiler);
+        typedef.ensureResolved(resolution);
         compiler.world.allTypedefs.add(element);
       } else if (Elements.isStaticOrTopLevel(element)) {
         registerStaticUse(element.declaration);
@@ -450,7 +482,7 @@
     if (includeClass) {
       logEnqueueReflectiveAction(cls, "register");
       ClassElement decl = cls.declaration;
-      decl.ensureResolved(compiler);
+      decl.ensureResolved(resolution);
       compiler.backend.registerInstantiatedType(
           decl.rawType,
           this,
@@ -484,7 +516,7 @@
     for (ClassElement cls in classes) {
       if (compiler.backend.referencedFromMirrorSystem(cls)) {
         logEnqueueReflectiveAction(cls);
-        cls.ensureResolved(compiler);
+        cls.ensureResolved(resolution);
         compiler.backend.registerInstantiatedType(
             cls.rawType,
             this,
@@ -521,7 +553,7 @@
       // have run before tree shaking is disabled and thus everything is
       // enqueued.
       recents = _processedClasses.toSet();
-      compiler.log('Enqueuing everything');
+      reporter.log('Enqueuing everything');
       for (LibraryElement lib in compiler.libraryLoader.libraries) {
         enqueueReflectiveElementsInLibrary(lib, recents);
       }
@@ -700,7 +732,7 @@
 
   void registerClosurizedMember(TypedElement element) {
     assert(element.isInstanceMember);
-    if (element.computeType(compiler).containsTypeVariables) {
+    if (element.computeType(resolution).containsTypeVariables) {
       compiler.backend.registerClosureWithFreeTypeVariables(
           element, this, compiler.globalDependencies);
     }
@@ -758,7 +790,7 @@
    *
    * Invariant: Key elements are declaration elements.
    */
-  final Set<AstElement> resolvedElements;
+  final Set<AstElement> processedElements;
 
   final Queue<ResolutionWorkItem> queue;
 
@@ -775,22 +807,22 @@
               compiler,
               itemCompilationContextCreator,
               strategy),
-        resolvedElements = new Set<AstElement>(),
+        processedElements = new Set<AstElement>(),
         queue = new Queue<ResolutionWorkItem>(),
         deferredTaskQueue = new Queue<DeferredTask>();
 
   bool get isResolutionQueue => true;
 
-  bool isProcessed(Element member) => resolvedElements.contains(member);
+  bool isProcessed(Element member) => processedElements.contains(member);
 
   /// Returns `true` if [element] has been processed by the resolution enqueuer.
-  bool hasBeenResolved(Element element) {
-    return resolvedElements.contains(element.analyzableElement.declaration);
+  bool hasBeenProcessed(Element element) {
+    return processedElements.contains(element.analyzableElement.declaration);
   }
 
-  /// Registers [element] as resolved for the resolution enqueuer.
-  void registerResolvedElement(AstElement element) {
-    resolvedElements.add(element);
+  /// Registers [element] as processed by the resolution enqueuer.
+  void registerProcessedElement(AstElement element) {
+    processedElements.add(element);
   }
 
   /**
@@ -811,7 +843,7 @@
 
     assert(invariant(element, element is AnalyzableElement,
         message: 'Element $element is not analyzable.'));
-    if (hasBeenResolved(element)) return false;
+    if (hasBeenProcessed(element)) return false;
     if (queueIsClosed) {
       throw new SpannableAssertionFailure(element,
           "Resolution work list is closed. Trying to add $element.");
@@ -898,29 +930,17 @@
   void emptyDeferredTaskQueue() {
     while (!deferredTaskQueue.isEmpty) {
       DeferredTask task = deferredTaskQueue.removeFirst();
-      compiler.withCurrentElement(task.element, task.action);
+      reporter.withCurrentElement(task.element, task.action);
     }
   }
 
-  void registerJsCall(Send node, ResolverVisitor resolver) {
-    nativeEnqueuer.registerJsCall(node, resolver);
-  }
-
-  void registerJsEmbeddedGlobalCall(Send node, ResolverVisitor resolver) {
-    nativeEnqueuer.registerJsEmbeddedGlobalCall(node, resolver);
-  }
-
-  void registerJsBuiltinCall(Send node, ResolverVisitor resolver) {
-    nativeEnqueuer.registerJsBuiltinCall(node, resolver);
-  }
-
   void _logSpecificSummary(log(message)) {
-    log('Resolved ${resolvedElements.length} elements.');
+    log('Resolved ${processedElements.length} elements.');
   }
 
   void forgetElement(Element element) {
     super.forgetElement(element);
-    resolvedElements.remove(element);
+    processedElements.remove(element);
   }
 }
 
diff --git a/pkg/compiler/lib/src/helpers/helpers.dart b/pkg/compiler/lib/src/helpers/helpers.dart
index 3a67978..6b3e787 100644
--- a/pkg/compiler/lib/src/helpers/helpers.dart
+++ b/pkg/compiler/lib/src/helpers/helpers.dart
@@ -15,6 +15,8 @@
 import '../../compiler.dart';
 import '../compiler.dart' show
     Compiler;
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import '../diagnostics/invariant.dart' show
     DEBUG_MODE;
 import '../diagnostics/messages.dart' show
@@ -88,7 +90,9 @@
 }
 
 /// Function signature of [reportHere].
-typedef ReportHere(Compiler compiler, Spannable node, String debugMessage);
+typedef ReportHere(DiagnosticReporter reporter,
+                   Spannable node,
+                   String debugMessage);
 
 /// Print a message with a source location.
 ReportHere get reportHere {
@@ -97,8 +101,8 @@
 }
 
 /// Implementation of [reportHere]
-_reportHere(Compiler compiler, Spannable node, String debugMessage) {
-  compiler.reportInfo(node,
+_reportHere(DiagnosticReporter reporter, Spannable node, String debugMessage) {
+  reporter.reportInfo(node,
       MessageKind.GENERIC, {'text': 'HERE: $debugMessage'});
 }
 
diff --git a/pkg/compiler/lib/src/helpers/trace.dart b/pkg/compiler/lib/src/helpers/trace.dart
index b928bb6..0889efd 100644
--- a/pkg/compiler/lib/src/helpers/trace.dart
+++ b/pkg/compiler/lib/src/helpers/trace.dart
@@ -60,8 +60,11 @@
 }
 
 /// Function signature of [traceAndReport].
-typedef void TraceAndReport(Compiler compiler, Spannable node, String message,
-                            {bool condition(String stackTrace), int limit,
+typedef void TraceAndReport(DiagnosticReporter reporter,
+                            Spannable node,
+                            String message,
+                            {bool condition(String stackTrace),
+                             int limit,
                              bool throwOnPrint});
 
 /// Calls [reportHere] and [trace] with the same message.
@@ -74,7 +77,9 @@
 TraceAndReport get reportAndTrace => traceAndReport;
 
 /// Implementation of [traceAndReport].
-void _traceAndReport(Compiler compiler, Spannable node, String message,
+void _traceAndReport(DiagnosticReporter reporter,
+                     Spannable node,
+                     String message,
                      {bool condition(String stackTrace), int limit,
                       bool throwOnPrint: false}) {
 
@@ -82,7 +87,7 @@
         condition: (String stackTrace) {
     bool result = condition != null ? condition(stackTrace) : true;
     if (result) {
-      reportHere(compiler, node, message);
+      reportHere(reporter, node, message);
     }
     return result;
   });
diff --git a/pkg/compiler/lib/src/inferrer/concrete_types_inferrer.dart b/pkg/compiler/lib/src/inferrer/concrete_types_inferrer.dart
deleted file mode 100644
index 7b0cf06..0000000
--- a/pkg/compiler/lib/src/inferrer/concrete_types_inferrer.dart
+++ /dev/null
@@ -1,2405 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library concrete_types_inferrer;
-
-import 'dart:collection' show
-    Queue,
-    IterableBase;
-
-import '../native/native.dart' as native;
-import '../closure.dart' show
-    BoxFieldElement;
-import '../compiler.dart' show
-    Compiler;
-import '../dart_types.dart' show
-    DartType,
-    TypeKind;
-import '../diagnostics/spannable.dart' show
-    Spannable;
-import '../elements/elements.dart';
-import '../tree/tree.dart';
-import '../types/types.dart' show
-    FlatTypeMask,
-    TypeMask,
-    TypesInferrer,
-    UnionTypeMask;
-import '../universe/selector.dart' show
-    Selector,
-    SelectorKind;
-import '../universe/side_effects.dart' show
-    SideEffects;
-import '../world.dart' show
-    ClassWorld;
-
-import 'inferrer_visitor.dart';
-import 'simple_types_inferrer.dart';
-
-/**
- * A singleton concrete type. More precisely, a [BaseType] is one of the
- * following:
- *
- *   - a non-asbtract class like [:int:] or [:Uri:] (but not [:List:])
- *   - the null base type
- *   - the unknown base type
- */
-abstract class BaseType {
-  bool isClass();
-  bool isUnknown();
-  bool isNull();
-}
-
-/**
- * A non-asbtract class like [:int:] or [:Uri:] (but not [:List:]).
- */
-class ClassBaseType implements BaseType {
-  final ClassElement element;
-
-  ClassBaseType(this.element);
-
-  bool operator ==(var other) {
-    if (identical(this, other)) return true;
-    if (other is! ClassBaseType) return false;
-    return element == other.element;
-  }
-  int get hashCode => element.hashCode;
-  String toString() {
-    return element == null ? 'toplevel' : element.name;
-  }
-  bool isClass() => true;
-  bool isUnknown() => false;
-  bool isNull() => false;
-}
-
-/**
- * The unknown base type.
- */
-class UnknownBaseType implements BaseType {
-  const UnknownBaseType();
-  bool operator ==(BaseType other) => other is UnknownBaseType;
-  int get hashCode => 0;
-  bool isClass() => false;
-  bool isUnknown() => true;
-  bool isNull() => false;
-  toString() => "unknown";
-}
-
-/**
- * The null base type.
- */
-class NullBaseType implements BaseType {
-  const NullBaseType();
-  bool operator ==(BaseType other) => identical(other, this);
-  int get hashCode => 1;
-  bool isClass() => false;
-  bool isUnknown() => false;
-  bool isNull() => true;
-  toString() => "null";
-}
-
-/**
- * An immutable set of base types like [:{int, bool}:], or the unknown concrete
- * type.
- */
-abstract class ConcreteType {
-  ConcreteType();
-
-  factory ConcreteType.empty(int maxConcreteTypeSize,
-                             BaseTypes classBaseTypes) {
-    return new UnionType(maxConcreteTypeSize, classBaseTypes,
-                         new Set<BaseType>());
-  }
-
-  /**
-   * The singleton constituted of the unknown base type is the unknown concrete
-   * type.
-   */
-  factory ConcreteType.singleton(int maxConcreteTypeSize,
-                                 BaseTypes classBaseTypes,
-                                 BaseType baseType) {
-    if (baseType.isUnknown() || maxConcreteTypeSize < 1) {
-      return const UnknownConcreteType();
-    }
-    Set<BaseType> singletonSet = new Set<BaseType>();
-    singletonSet.add(baseType);
-    return new UnionType(maxConcreteTypeSize, classBaseTypes, singletonSet);
-  }
-
-  factory ConcreteType.unknown() {
-    return const UnknownConcreteType();
-  }
-
-  ConcreteType union(ConcreteType other);
-  ConcreteType intersection(ConcreteType other);
-  ConcreteType refine(Selector selector, Compiler compiler);
-  bool isUnknown();
-  bool isEmpty();
-  Set<BaseType> get baseTypes;
-
-  /**
-   * Returns the unique element of [:this:] if [:this:] is a singleton, null
-   * otherwise.
-   */
-  ClassElement getUniqueType();
-}
-
-/**
- * The unkown concrete type: it is absorbing for the union.
- */
-class UnknownConcreteType implements ConcreteType {
-  const UnknownConcreteType();
-  bool isUnknown() => true;
-  bool isEmpty() => false;
-  bool operator ==(ConcreteType other) => identical(this, other);
-  Set<BaseType> get baseTypes =>
-      new Set<BaseType>.from([const UnknownBaseType()]);
-  int get hashCode => 0;
-  ConcreteType union(ConcreteType other) => this;
-  ConcreteType intersection(ConcreteType other) => other;
-  ConcreteType refine(Selector selector, Compiler compiler) => this;
-  ClassElement getUniqueType() => null;
-  toString() => "unknown";
-}
-
-/**
- * An immutable set of base types, like [: {int, bool} :].
- */
-class UnionType implements ConcreteType {
-  final int maxConcreteTypeSize;
-  final BaseTypes classBaseTypes;
-
-  final Set<BaseType> baseTypes;
-
-  /**
-   * The argument should NOT be mutated later. Do not call directly, use
-   * ConcreteType.singleton instead.
-   */
-  UnionType(this.maxConcreteTypeSize, this.classBaseTypes, this.baseTypes);
-
-  bool isUnknown() => false;
-  bool isEmpty() => baseTypes.isEmpty;
-
-  bool operator ==(ConcreteType other) {
-    if (other is! UnionType) return false;
-    if (baseTypes.length != other.baseTypes.length) return false;
-    return baseTypes.containsAll(other.baseTypes);
-  }
-
-  int get hashCode {
-    int result = 1;
-    for (final baseType in baseTypes) {
-      result = 31 * result + baseType.hashCode;
-    }
-    return result;
-  }
-
-  ConcreteType _simplify(Set<BaseType> baseTypes) {
-    // normalize all flavors of ints to int
-    // TODO(polux): handle different ints better
-    if (baseTypes.contains(classBaseTypes.uint31Type)) {
-      baseTypes.remove(classBaseTypes.uint31Type);
-      baseTypes.add(classBaseTypes.intBaseType);
-    }
-    if (baseTypes.contains(classBaseTypes.uint32Type)) {
-      baseTypes.remove(classBaseTypes.uint32Type);
-      baseTypes.add(classBaseTypes.intBaseType);
-    }
-    if (baseTypes.contains(classBaseTypes.positiveIntType)) {
-      baseTypes.remove(classBaseTypes.positiveIntType);
-      baseTypes.add(classBaseTypes.intBaseType);
-    }
-    // normalize {int, float}, {int, num} or {float, num} into num
-    // TODO(polux): generalize this to all types when we extend the concept of
-    //     "concrete type" to other abstract classes than num
-    if (baseTypes.contains(classBaseTypes.numBaseType) ||
-        (baseTypes.contains(classBaseTypes.intBaseType)
-            && baseTypes.contains(classBaseTypes.doubleBaseType))) {
-      baseTypes.remove(classBaseTypes.intBaseType);
-      baseTypes.remove(classBaseTypes.doubleBaseType);
-      baseTypes.add(classBaseTypes.numBaseType);
-    }
-
-    // widen big types to dynamic
-    return baseTypes.length > maxConcreteTypeSize
-        ? const UnknownConcreteType()
-        : new UnionType(maxConcreteTypeSize, classBaseTypes, baseTypes);
-  }
-
-  ConcreteType union(ConcreteType other) {
-    if (other.isUnknown()) {
-      return const UnknownConcreteType();
-    }
-    UnionType otherUnion = other;  // cast
-    Set<BaseType> newBaseTypes = new Set<BaseType>.from(baseTypes);
-    newBaseTypes.addAll(otherUnion.baseTypes);
-    return _simplify(newBaseTypes);
-  }
-
-  ConcreteType intersection(ConcreteType other) {
-    if (other.isUnknown()) {
-      return this;
-    }
-    Set<BaseType> thisBaseTypes = new Set<BaseType>.from(baseTypes);
-    Set<BaseType> otherBaseTypes = new Set<BaseType>.from(other.baseTypes);
-    return _simplify(thisBaseTypes.intersection(otherBaseTypes));
-  }
-
-  ConcreteType refine(Selector selector, Compiler compiler) {
-    Set<BaseType> newBaseTypes = new Set<BaseType>();
-    for (BaseType baseType in baseTypes) {
-      if (baseType.isClass()) {
-        ClassBaseType classBaseType = baseType;
-        if (classBaseType.element.lookupByName(selector.memberName) != null) {
-          newBaseTypes.add(baseType);
-        }
-      } else {
-        newBaseTypes.add(baseType);
-      }
-    }
-    return _simplify(newBaseTypes);
-  }
-
-  ClassElement getUniqueType() {
-    if (baseTypes.length == 1) {
-      var iterator = baseTypes.iterator;
-      iterator.moveNext();
-      BaseType uniqueBaseType = iterator.current;
-      if (uniqueBaseType.isClass()) {
-        ClassBaseType uniqueClassType = uniqueBaseType;
-        return uniqueClassType.element;
-      }
-    }
-    return null;
-  }
-
-  String toString() => baseTypes.toString();
-}
-
-class ConcreteTypeSystem extends TypeSystem<ConcreteType> {
-  final Compiler compiler;
-  final ConcreteTypesInferrer inferrer;
-  final BaseTypes baseTypes;
-
-  final ConcreteType nullType;
-  final ConcreteType _intType;
-  final ConcreteType _uint31Type;
-  final ConcreteType _uint32Type;
-  final ConcreteType _positiveIntType;
-  final ConcreteType _doubleType;
-  final ConcreteType _numType;
-  final ConcreteType _boolType;
-  final ConcreteType _functionType;
-  final ConcreteType _listType;
-  final ConcreteType _constListType;
-  final ConcreteType _fixedListType;
-  final ConcreteType _growableListType;
-  final ConcreteType _mapType;
-  final ConcreteType _constMapType;
-  final ConcreteType _stringType;
-
-  final ConcreteType dynamicType;
-  final ConcreteType typeType;
-  final ConcreteType nonNullEmptyType;
-
-  ConcreteTypeSystem.internal(ConcreteTypesInferrer inferrer,
-                              BaseTypes baseTypes,
-                              ConcreteType singleton(BaseType baseType))
-      : this.compiler = inferrer.compiler
-      , this.inferrer = inferrer
-      , this.baseTypes = baseTypes
-      , this._constListType = singleton(baseTypes.constMapBaseType)
-      , this._constMapType = singleton(baseTypes.constMapBaseType)
-      , this._doubleType = singleton(baseTypes.doubleBaseType)
-      , this._fixedListType = singleton(baseTypes.fixedListBaseType)
-      , this._functionType = singleton(baseTypes.functionBaseType)
-      , this._growableListType = singleton(baseTypes.growableListBaseType)
-      , this._intType = singleton(baseTypes.intBaseType)
-      , this._listType = singleton(baseTypes.listBaseType)
-      , this._mapType = singleton(baseTypes.mapBaseType)
-      , this._numType = singleton(baseTypes.numBaseType)
-      , this._boolType = singleton(baseTypes.boolBaseType)
-      , this._stringType = singleton(baseTypes.stringBaseType)
-      , this.typeType = singleton(baseTypes.typeBaseType)
-      , this.dynamicType = const UnknownConcreteType()
-      , this.nullType = singleton(const NullBaseType())
-      , this.nonNullEmptyType = new ConcreteType.empty(
-          inferrer.compiler.maxConcreteTypeSize, baseTypes)
-      // TODO(polux): have better types here
-      , this._uint31Type = singleton(baseTypes.intBaseType)
-      , this._uint32Type = singleton(baseTypes.intBaseType)
-      , this._positiveIntType = singleton(baseTypes.intBaseType);
-
-  factory ConcreteTypeSystem(ConcreteTypesInferrer inferrer) {
-    Compiler compiler = inferrer.compiler;
-    BaseTypes baseTypes = new BaseTypes(compiler);
-    return new ConcreteTypeSystem.internal(
-        inferrer,
-        baseTypes,
-        (BaseType baseType) => new ConcreteType.singleton(
-            compiler.maxConcreteTypeSize, baseTypes, baseType));
-  }
-
-  @override
-  ConcreteType get intType {
-    inferrer.augmentSeenClasses(compiler.backend.intImplementation);
-    return _intType;
-  }
-
-  @override
-  ConcreteType get uint31Type {
-    inferrer.augmentSeenClasses(compiler.backend.uint31Implementation);
-    return _uint31Type;
-  }
-
-  @override
-  ConcreteType get uint32Type {
-    inferrer.augmentSeenClasses(compiler.backend.uint32Implementation);
-    return _uint32Type;
-  }
-
-  @override
-  ConcreteType get positiveIntType {
-    inferrer.augmentSeenClasses(compiler.backend.positiveIntImplementation);
-    return _positiveIntType;
-  }
-
-  @override
-  ConcreteType get doubleType {
-    inferrer.augmentSeenClasses(compiler.backend.doubleImplementation);
-    return _doubleType;
-  }
-
-  @override
-  ConcreteType get numType {
-    inferrer.augmentSeenClasses(compiler.backend.numImplementation);
-    return _numType;
-  }
-
-  @override
-  ConcreteType get boolType {
-    inferrer.augmentSeenClasses(compiler.backend.boolImplementation);
-    return _boolType;
-  }
-
-  @override
-  ConcreteType get functionType {
-    inferrer.augmentSeenClasses(compiler.backend.functionImplementation);
-    return _functionType;
-  }
-
-  @override
-  ConcreteType get listType {
-    inferrer.augmentSeenClasses(compiler.backend.listImplementation);
-    return _listType;
-  }
-
-  @override
-  ConcreteType get constListType {
-    inferrer.augmentSeenClasses(compiler.backend.constListImplementation);
-    return _constListType;
-  }
-
-  @override
-  ConcreteType get fixedListType {
-    inferrer.augmentSeenClasses(compiler.backend.fixedListImplementation);
-    return _fixedListType;
-  }
-
-  @override
-  ConcreteType get growableListType {
-    inferrer.augmentSeenClasses(compiler.backend.growableListImplementation);
-    return _growableListType;
-  }
-
-  @override
-  ConcreteType get mapType {
-    inferrer.augmentSeenClasses(compiler.backend.mapImplementation);
-    return _mapType;
-  }
-
-  @override
-  ConcreteType get constMapType {
-    inferrer.augmentSeenClasses(compiler.backend.constMapImplementation);
-    return _constMapType;
-  }
-
-  @override
-  ConcreteType get stringType {
-    inferrer.augmentSeenClasses(compiler.backend.stringImplementation);
-    return _stringType;
-  }
-
-  @override
-  ConcreteType stringLiteralType(_) {
-    inferrer.augmentSeenClasses(compiler.backend.stringImplementation);
-    return _stringType;
-  }
-
-  @override
-  ConcreteType boolLiteralType(_) {
-    inferrer.augmentSeenClasses(compiler.backend.boolImplementation);
-    return _boolType;
-  }
-
-  /**
-   * Returns the [TypeMask] representation of [baseType].
-   */
-  TypeMask baseTypeToTypeMask(BaseType baseType) {
-    if (baseType.isUnknown()) {
-      return const DynamicTypeMask();
-    } else if (baseType.isNull()) {
-      return new TypeMask.empty();
-    } else {
-      ClassBaseType classBaseType = baseType;
-      final element = classBaseType.element;
-      assert(element != null);
-      if (element == compiler.backend.numImplementation) {
-        return new TypeMask.nonNullSubclass(compiler.backend.numImplementation,
-                                            compiler.world);
-      } else if (element == compiler.backend.intImplementation) {
-        return new TypeMask.nonNullSubclass(compiler.backend.intImplementation,
-                                            compiler.world);
-      } else if (!compiler.world.isInstantiated(element.declaration)) {
-        return new TypeMask.nonNullSubtype(element.declaration, compiler.world);
-      } else {
-        return new TypeMask.nonNullExact(element.declaration, compiler.world);
-      }
-    }
-  }
-
-  /**
-   * Returns the [TypeMask] representation of [concreteType].
-   */
-  TypeMask concreteTypeToTypeMask(ConcreteType concreteType) {
-    if (concreteType == null) return null;
-    TypeMask typeMask = new TypeMask.nonNullEmpty();
-    for (BaseType baseType in concreteType.baseTypes) {
-      TypeMask baseMask = baseTypeToTypeMask(baseType);
-      if (baseMask == const DynamicTypeMask()) return baseMask;
-      typeMask = typeMask.union(baseMask, compiler.world);
-    }
-    return typeMask;
-  }
-
-  @override
-  ConcreteType addPhiInput(Local variable,
-                           ConcreteType phiType,
-                           ConcreteType newType) {
-    return computeLUB(phiType, newType);
-  }
-
-  @override
-  ConcreteType allocateDiamondPhi(ConcreteType firstInput,
-                                  ConcreteType secondInput) {
-    return computeLUB(firstInput, secondInput);
-  }
-
-  @override
-  ConcreteType allocatePhi(Node node, Local variable, ConcreteType inputType) {
-    return inputType;
-  }
-
-  @override
-  ConcreteType allocateLoopPhi(Node node, Local variable,
-                               ConcreteType inputType) {
-    return inputType;
-  }
-
-  @override
-  ConcreteType computeLUB(ConcreteType firstType, ConcreteType secondType) {
-    if (firstType == null) {
-      return secondType;
-    } else if (secondType == null) {
-      return firstType;
-    } else {
-      return firstType.union(secondType);
-    }
-  }
-
-  // Implementation Inspired by
-  // type_graph_inferrer.TypeInformationSystem.narrowType
-  @override
-  ConcreteType narrowType(ConcreteType type,
-                          DartType annotation,
-                          {bool isNullable: true}) {
-    if (annotation.treatAsDynamic) return type;
-    if (annotation.isVoid) return nullType;
-    if (annotation.element == compiler.objectClass) return type;
-    ConcreteType otherType;
-    if (annotation.isTypedef || annotation.isFunctionType) {
-      otherType = functionType;
-    } else if (annotation.isTypeVariable) {
-      // TODO(polux): Narrow to bound.
-      return type;
-    } else {
-      assert(annotation.isInterfaceType);
-      otherType = nonNullSubtype(annotation.element);
-    }
-    if (isNullable) otherType = otherType.union(nullType);
-    if (type == null) return otherType;
-    return type.intersection(otherType);
-  }
-
-  @override
-  TypeMask newTypedSelector(ConcreteType receiver, TypeMask mask) {
-    return concreteTypeToTypeMask(receiver);
-  }
-
-  @override
-  ConcreteType nonNullEmpty() {
-    return nonNullEmptyType;
-  }
-
-  @override
-  ConcreteType nonNullExact(ClassElement cls) {
-    return nonNullSubtype(cls);
-  }
-
-  /**
-   * Helper method for [nonNullSubtype] and [nonNullSubclass].
-   */
-  ConcreteType nonNullSubX(ClassElement cls,
-                           Iterable<ClassElement> extractor(ClassElement cls)) {
-    if (cls == compiler.objectClass) {
-      return dynamicType;
-    }
-    ConcreteType result = nonNullEmptyType;
-    void registerClass(ClassElement element) {
-      if (!element.isAbstract) {
-        result = result.union(
-            new ConcreteType.singleton(compiler.maxConcreteTypeSize,
-                                       baseTypes,
-                                       new ClassBaseType(element)));
-        inferrer.augmentSeenClasses(element);
-      }
-    }
-    registerClass(cls);
-    Iterable<ClassElement> subtypes = extractor(cls);
-    subtypes.forEach(registerClass);
-    return result;
-  }
-
-  @override
-  ConcreteType nonNullSubclass(ClassElement cls) {
-    return nonNullSubX(cls, compiler.world.strictSubclassesOf);
-  }
-
-  @override
-  ConcreteType nonNullSubtype(ClassElement cls) {
-    return nonNullSubX(cls, compiler.world.strictSubtypesOf);
-  }
-
-  @override
-  ConcreteType simplifyPhi(Node node,
-                           Local variable,
-                           ConcreteType phiType) {
-    return phiType;
-  }
-
-  @override
-  bool selectorNeedsUpdate(ConcreteType type, TypeMask mask) {
-    return concreteTypeToTypeMask(type) != mask;
-  }
-
-  @override
-  ConcreteType refineReceiver(Selector selector,
-                              TypeMask mask,
-                              ConcreteType receiverType,
-      bool isConditional) {
-    if (isConditional) {
-      throw new UnimplementedError("isConditional in concrete type inferrer");
-    }
-    return receiverType.refine(selector, compiler);
-  }
-
-  @override
-  bool isNull(ConcreteType type) {
-    return (type.baseTypes.length == 1) && (type.baseTypes.first.isNull());
-  }
-
-  @override
-  ConcreteType allocateClosure(Node node, Element element) {
-    // TODO(polux): register closure here instead of in visitor?
-    return functionType;
-  }
-
-  @override
-  ConcreteType allocateList(ConcreteType type,
-                            Node node,
-                            Element enclosing,
-                            [ConcreteType elementType, int length]) {
-    if (elementType != null) {
-      inferrer.augmentListElementType(elementType);
-    }
-    return type;
-  }
-
-  @override
-  ConcreteType allocateMap(ConcreteType type,
-                           Node node,
-                           Element element,
-                           [List<ConcreteType> keyTypes,
-                            List<ConcreteType> valueTypes]) {
-    // TODO(polux): treat maps the same way we treat lists
-    return type;
-  }
-
-  @override
-  ConcreteType getConcreteTypeFor(TypeMask mask) {
-    if (mask.isUnion) {
-      UnionTypeMask union = mask;
-      return union.disjointMasks.fold(
-          nonNullEmptyType,
-          (type1, type2) => type1.union(getConcreteTypeFor(type2)));
-    } else {
-      FlatTypeMask flat = mask;
-      ConcreteType result;
-      if (flat.isEmpty) {
-        result = nonNullEmptyType;
-      } else if (flat.isExact) {
-        result = nonNullExact(flat.base);
-      } else if (flat.isSubclass) {
-        result = nonNullSubclass(flat.base);
-      } else if (flat.isSubtype) {
-        result = nonNullSubtype(flat.base);
-      } else {
-        throw new ArgumentError("unexpected mask");
-      }
-      return flat.isNullable ? result.union(nullType) : result;
-    }
-  }
-}
-
-/**
- * The cartesian product of concrete types: an iterable of
- * [ConcreteTypesEnvironment]s.
- */
-class ConcreteTypeCartesianProduct
-    extends IterableBase<ConcreteTypesEnvironment> {
-  final ConcreteTypesInferrer inferrer;
-  final ClassElement typeOfThis;
-  final Map<Element, ConcreteType> concreteTypes;
-  ConcreteTypeCartesianProduct(this.inferrer, this.typeOfThis,
-                               this.concreteTypes);
-  Iterator get iterator => concreteTypes.isEmpty
-      ? [new ConcreteTypesEnvironment(typeOfThis)].iterator
-      : new ConcreteTypeCartesianProductIterator(inferrer, typeOfThis,
-                                                 concreteTypes);
-  String toString() => this.toList().toString();
-}
-
-/**
- * An helper class for [ConcreteTypeCartesianProduct].
- */
-class ConcreteTypeCartesianProductIterator
-    implements Iterator<ConcreteTypesEnvironment> {
-  final ConcreteTypesInferrer inferrer;
-  final ClassElement classOfThis;
-  final Map<Element, ConcreteType> concreteTypes;
-  final Map<Element, BaseType> nextValues;
-  final Map<Element, Iterator> state;
-  int size = 1;
-  int counter = 0;
-  ConcreteTypesEnvironment _current;
-
-  ConcreteTypeCartesianProductIterator(this.inferrer, this.classOfThis,
-      Map<Element, ConcreteType> concreteTypes)
-      : this.concreteTypes = concreteTypes,
-        nextValues = new Map<Element, BaseType>(),
-        state = new Map<Element, Iterator>() {
-    if (concreteTypes.isEmpty) {
-      size = 0;
-      return;
-    }
-    for (final e in concreteTypes.keys) {
-      final baseTypes = concreteTypes[e].baseTypes;
-      size *= baseTypes.length;
-    }
-  }
-
-  ConcreteTypesEnvironment get current => _current;
-
-  ConcreteTypesEnvironment takeSnapshot() {
-    Map<Element, ConcreteType> result = new Map<Element, ConcreteType>();
-    nextValues.forEach((k, v) {
-      result[k] = inferrer.singletonConcreteType(v);
-    });
-    return new ConcreteTypesEnvironment.of(result, classOfThis);
-  }
-
-  bool moveNext() {
-    if (counter >= size) {
-      _current = null;
-      return false;
-    }
-    for (final key in concreteTypes.keys) {
-      final iterator = state[key];
-      if (iterator != null && iterator.moveNext()) {
-        nextValues[key] = state[key].current;
-        break;
-      }
-      Iterator newIterator = concreteTypes[key].baseTypes.iterator;
-      state[key] = newIterator;
-      newIterator.moveNext();
-      nextValues[key] = newIterator.current;
-    }
-    counter++;
-    _current = takeSnapshot();
-    return true;
-  }
-}
-
-/**
- * [BaseType] Constants.
- */
-class BaseTypes {
-  final ClassBaseType intBaseType;
-  final ClassBaseType doubleBaseType;
-  final ClassBaseType numBaseType;
-  final ClassBaseType boolBaseType;
-  final ClassBaseType stringBaseType;
-  final ClassBaseType listBaseType;
-  final ClassBaseType growableListBaseType;
-  final ClassBaseType fixedListBaseType;
-  final ClassBaseType constListBaseType;
-  final ClassBaseType mapBaseType;
-  final ClassBaseType constMapBaseType;
-  final ClassBaseType objectBaseType;
-  final ClassBaseType typeBaseType;
-  final ClassBaseType functionBaseType;
-  final ClassBaseType uint31Type;
-  final ClassBaseType uint32Type;
-  final ClassBaseType positiveIntType;
-
-  BaseTypes(Compiler compiler) :
-    intBaseType = new ClassBaseType(compiler.backend.intImplementation),
-    doubleBaseType = new ClassBaseType(compiler.backend.doubleImplementation),
-    numBaseType = new ClassBaseType(compiler.backend.numImplementation),
-    boolBaseType = new ClassBaseType(compiler.backend.boolImplementation),
-    stringBaseType = new ClassBaseType(compiler.backend.stringImplementation),
-    listBaseType = new ClassBaseType(compiler.backend.listImplementation),
-    growableListBaseType =
-        new ClassBaseType(compiler.backend.growableListImplementation),
-    fixedListBaseType =
-        new ClassBaseType(compiler.backend.fixedListImplementation),
-    constListBaseType =
-        new ClassBaseType(compiler.backend.constListImplementation),
-    mapBaseType = new ClassBaseType(compiler.backend.mapImplementation),
-    constMapBaseType =
-        new ClassBaseType(compiler.backend.constMapImplementation),
-    objectBaseType = new ClassBaseType(compiler.objectClass),
-    typeBaseType = new ClassBaseType(compiler.backend.typeImplementation),
-    functionBaseType =
-        new ClassBaseType(compiler.backend.functionImplementation),
-    uint31Type = new ClassBaseType(compiler.backend.uint31Implementation),
-    uint32Type = new ClassBaseType(compiler.backend.uint32Implementation),
-    positiveIntType =
-        new ClassBaseType(compiler.backend.positiveIntImplementation);
-}
-
-/**
- * An immutable mapping from method arguments to [ConcreteTypes].
- */
-class ConcreteTypesEnvironment {
-  final Map<Element, ConcreteType> environment;
-  final ClassElement classOfThis;
-
-  ConcreteTypesEnvironment([this.classOfThis]) :
-      environment = new Map<Element, ConcreteType>();
-  ConcreteTypesEnvironment.of(this.environment, this.classOfThis);
-
-  ConcreteType lookupType(Element element) => environment[element];
-
-  bool operator ==(ConcreteTypesEnvironment other) {
-    if (other is! ConcreteTypesEnvironment) return false;
-    if (classOfThis != other.classOfThis) return false;
-    if (environment.length != other.environment.length) return false;
-    for (Element key in environment.keys) {
-      if (!other.environment.containsKey(key)
-          || (environment[key] != other.environment[key])) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  int get hashCode {
-    int result = (classOfThis != null) ? classOfThis.hashCode : 1;
-    environment.forEach((element, concreteType) {
-      result = 31 * (31 * result + element.hashCode) + concreteType.hashCode;
-    });
-    return result;
-  }
-
-  String toString() => "{ this: $classOfThis, env: $environment }";
-}
-
-class ClosureEnvironment {
-  ConcreteType thisType;
-  final LocalsHandler locals;
-
-  ClosureEnvironment(this.thisType, this.locals);
-
-  bool mergeLocals(LocalsHandler newLocals) {
-    assert((locals == null) == (newLocals == null));
-    return (locals != null) ? locals.mergeAll([newLocals]) : false;
-  }
-
-  /// Returns true if changed.
-  bool merge(ConcreteType thisType, LocalsHandler locals) {
-    ConcreteType oldThisType = this.thisType;
-    if (this.thisType == null) {
-      this.thisType = thisType;
-    } else if (thisType != null) {
-      this.thisType = this.thisType.union(thisType);
-    }
-    return mergeLocals(locals) || (this.thisType != oldThisType);
-  }
-
-  toString() => "ClosureEnvironment { thisType = $thisType, locals = ... }";
-}
-
-/**
- * A set of encoutered closures.
- */
-class Closures {
-  final Compiler compiler;
-  final Map<FunctionElement, ClosureEnvironment> closures =
-      new Map<FunctionElement, ClosureEnvironment>();
-
-  Closures(this.compiler);
-
-  /// Returns true if the environment of the closure has changed.
-  bool put(FunctionElement closure,
-           ConcreteType typeOfThis,
-           LocalsHandler locals) {
-    ClosureEnvironment oldEnvironent = closures[closure];
-    if (oldEnvironent == null) {
-      closures[closure] = new ClosureEnvironment(typeOfThis, locals);
-      return true;
-    } else {
-      return oldEnvironent.merge(typeOfThis, locals);
-    }
-  }
-
-  ClosureEnvironment getEnvironmentOrNull(FunctionElement function) {
-    return closures[function];
-  }
-
-  Iterable<FunctionElement> get functionElements => closures.keys;
-
-  bool contains(FunctionElement function) => closures.containsKey(function);
-
-  String toString() => closures.toString();
-}
-
-/**
- * A work item for the type inference queue.
- */
-class InferenceWorkItem {
-  Element method;
-  ConcreteTypesEnvironment environment;
-  InferenceWorkItem(this.method, this.environment);
-
-  toString() => "{ method = $method, environment = $environment }";
-
-  bool operator ==(other) {
-    return (other is InferenceWorkItem)
-        && method == other.method
-        && environment == other.environment;
-  }
-
-  int get hashCode => 31 * method.hashCode + environment.hashCode;
-}
-
-/**
- * A sentinel type mask class representing the dynamicType. It is absorbing
- * for [:ConcreteTypesEnvironment.typeMaskUnion:].
- */
-class DynamicTypeMask implements TypeMask {
-  const DynamicTypeMask();
-
-  String toString() => 'sentinel type mask';
-
-  TypeMask nullable() {
-    throw new UnsupportedError("");
-  }
-
-  TypeMask nonNullable() {
-    throw new UnsupportedError("");
-  }
-
-  bool get isEmpty {
-    throw new UnsupportedError("");
-  }
-
-  bool get isNullable {
-    throw new UnsupportedError("");
-  }
-
-  bool get isExact {
-    throw new UnsupportedError("");
-  }
-
-  bool get isUnion {
-    throw new UnsupportedError("");
-  }
-
-  bool get isContainer {
-    throw new UnsupportedError("");
-  }
-
-  bool get isMap {
-    throw new UnsupportedError("");
-  }
-
-  bool get isDictionary {
-    throw new UnsupportedError("");
-  }
-
-  bool get isForwarding {
-    throw new UnsupportedError("");
-  }
-
-  bool get isValue {
-    throw new UnsupportedError("");
-  }
-
-  bool containsOnlyInt(ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool containsOnlyDouble(ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool containsOnlyNum(ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool containsOnlyBool(ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool containsOnlyString(ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool containsOnly(ClassElement element) {
-    throw new UnsupportedError("");
-  }
-
-  bool satisfies(ClassElement cls, ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool contains(ClassElement type, ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool containsAll(ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  ClassElement singleClass(ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  TypeMask union(TypeMask other, ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  TypeMask intersection(TypeMask other, ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool canHit(Element element, Selector selector, ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  Element locateSingleElement(Selector selector,
-                              TypeMask mask,
-                              Compiler compiler) {
-    throw new UnsupportedError("");
-  }
-
-  bool needsNoSuchMethodHandling(Selector selector, ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool isInMask(TypeMask other, ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool containsMask(TypeMask other, ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-}
-
-class WorkQueue {
-  final Queue<InferenceWorkItem> queue = new Queue<InferenceWorkItem>();
-
-  void add(InferenceWorkItem workItem) {
-    if (!queue.contains(workItem)) {
-      queue.addLast(workItem);
-    }
-  }
-
-  InferenceWorkItem remove() {
-    return queue.removeFirst();
-  }
-
-  bool get isEmpty => queue.isEmpty;
-}
-
-/**
- * A task which conservatively infers a [ConcreteType] for each sub expression
- * of the program. The entry point is [analyzeMain].
- */
-class ConcreteTypesInferrer
-    extends InferrerEngine<ConcreteType, ConcreteTypeSystem>
-    implements TypesInferrer {
-
-  final String name = "Type inferrer";
-
-  /**
-   * When true, the string literal [:"__dynamic_for_test":] is inferred to
-   * have the unknown type.
-   */
-  // TODO(polux): get rid of this hack once we have a natural way of inferring
-  // the unknown type.
-  bool testMode = false;
-
-  // --- constants ---
-
-  /**
-   * Constants representing builtin base types. Initialized by [initialize]
-   * and not by the constructor because the compiler elements are not yet
-   * populated.
-   */
-  BaseTypes baseTypes;
-
-  /** The associated type system */
-  ConcreteTypeSystem types;
-
-  /**
-   * Constant representing [:ConcreteList#[]:] where [:ConcreteList:] is the
-   * concrete implementation of lists for the selected backend.
-   */
-  FunctionElement listIndex;
-
-  /**
-   * Constant representing [:ConcreteList#[]=:] where [:ConcreteList:] is the
-   * concrete implementation of lists for the selected backend.
-   */
-  FunctionElement listIndexSet;
-
-  /**
-   * Constant representing [:ConcreteList#add:] where [:ConcreteList:] is the
-   * concrete implementation of lists for the selected backend.
-   */
-  FunctionElement listAdd;
-
-  /**
-   * Constant representing [:ConcreteList#removeAt:] where [:ConcreteList:] is
-   * the concrete implementation of lists for the selected backend.
-   */
-  FunctionElement listRemoveAt;
-
-  /**
-   * Constant representing [:ConcreteList#insert:] where [:ConcreteList:] is
-   * the concrete implementation of lists for the selected backend.
-   */
-  FunctionElement listInsert;
-
-  /**
-   * Constant representing [:ConcreteList#removeLast:] where [:ConcreteList:] is
-   * the concrete implementation of lists for the selected backend.
-   */
-  FunctionElement listRemoveLast;
-
-  /** Constant representing [:List():]. */
-  FunctionElement listConstructor;
-
-  /** The unknown concrete type */
-  final ConcreteType unknownConcreteType;
-
-  /** The empty concrete type */
-  ConcreteType emptyConcreteType;
-
-  /** The null concrete type */
-  ConcreteType nullConcreteType;
-
-  // --- state updated by the inference ---
-
-  /**
-   * A map from (function x argument base types) to their inferred concrete
-   * type. Another way of seeing [methodToTemplates] is as a map from
-   * [FunctionElement]s to "templates" in the sense of "The Cartesian Product
-   * Algorithm - Simple and Precise Type Inference of Parametric Polymorphism"
-   * by Ole Agesen.
-   */
-  // TODO(polux): build a better abstraction, like Closures
-  final Map<FunctionElement, Map<ConcreteTypesEnvironment, ConcreteType>>
-      methodToTemplates;
-
-  /** The set of encountered closures. */
-  final Closures closures;
-
-  /** A map from expressions to their inferred concrete types. */
-  final Map<Node, ConcreteType> inferredTypes;
-
-  /** A map from fields to their inferred concrete types. */
-  final Map<Element, ConcreteType> inferredFieldTypes;
-
-  /**
-   * [:callers[f]:] is the list of [:f:]'s possible callers or fields
-   * whose initialization is a call to [:f:].
-   */
-  final Map<FunctionElement, Set<Element>> callers;
-
-  /**
-   * [:readers[field]:] is the list of [:field:]'s possible readers or fields
-   * whose initialization is a read of [:field:].
-   */
-  final Map<Element, Set<Element>> fieldReaders;
-
-  /**
-   * [:readers[local]:] is the list of [:local:]'s possible readers.
-   */
-  final Map<Local, Set<FunctionElement>> capturedLocalsReaders;
-
-  /// The set of classes encountered so far.
-  final Set<ClassElement> seenClasses;
-
-  /**
-   * A map from selector names to callers of methods with this name on objects
-   * of unknown inferred type.
-   */
-  final Map<String, Set<FunctionElement>> dynamicCallers;
-
-  /** The inferred type of elements stored in Lists. */
-  ConcreteType listElementType;
-
-  /**
-   * A map from parameters to their inferred concrete types. It plays no role
-   * in the analysis, it is write only.
-   */
-  final Map<VariableElement, ConcreteType> inferredParameterTypes;
-
-  /**
-   * A map from selectors to their inferred type masks, indexed by the mask
-   * of the receiver. It plays no role in the analysis, it is write only.
-   */
-  final Map<Selector, Map<TypeMask, TypeMask>> inferredSelectorTypes;
-
-  /** The work queue consumed by [analyzeMain]. */
-  final WorkQueue workQueue;
-
-  /** The item being worked on. */
-  InferenceWorkItem currentWorkItem;
-
-  ConcreteTypesInferrer(Compiler compiler)
-      : methodToTemplates = new Map<FunctionElement,
-            Map<ConcreteTypesEnvironment, ConcreteType>>(),
-        closures = new Closures(compiler),
-        inferredTypes = new Map<Node, ConcreteType>(),
-        inferredFieldTypes = new Map<Element, ConcreteType>(),
-        inferredParameterTypes = new Map<VariableElement, ConcreteType>(),
-        workQueue = new WorkQueue(),
-        callers = new Map<FunctionElement, Set<Element>>(),
-        fieldReaders = new Map<Element, Set<Element>>(),
-        capturedLocalsReaders = new Map<Local, Set<FunctionElement>>(),
-        seenClasses = new Set<ClassElement>(),
-        dynamicCallers = new Map<String, Set<FunctionElement>>(),
-        inferredSelectorTypes = new Map<Selector, Map<TypeMask, TypeMask>>(),
-        unknownConcreteType = new ConcreteType.unknown(),
-        super(compiler, null);
-
-  /* Initialization code that cannot be run in the constructor because it
-   * requires the compiler's elements to be populated.
-   */
-  void initialize() {
-    baseTypes = new BaseTypes(compiler);
-    types = new ConcreteTypeSystem(this);
-    ClassElement jsArrayClass = baseTypes.listBaseType.element;
-    listIndex = jsArrayClass.lookupMember('[]');
-    listIndexSet = jsArrayClass.lookupMember('[]=');
-    listAdd = jsArrayClass.lookupMember('add');
-    listRemoveAt = jsArrayClass.lookupMember('removeAt');
-    listInsert = jsArrayClass.lookupMember('insert');
-    listRemoveLast =
-        jsArrayClass.lookupMember('removeLast');
-    listConstructor =
-        compiler.listClass.lookupDefaultConstructor();
-    if (listConstructor != null) {
-      listConstructor = listConstructor.implementation;
-    }
-    emptyConcreteType = new ConcreteType.empty(compiler.maxConcreteTypeSize,
-                                               baseTypes);
-    nullConcreteType = singletonConcreteType(const NullBaseType());
-    listElementType = emptyConcreteType;
-  }
-
-  // --- utility methods ---
-
-  /** Creates a singleton concrete type containing [baseType]. */
-  ConcreteType singletonConcreteType(BaseType baseType) {
-    return new ConcreteType.singleton(compiler.maxConcreteTypeSize, baseTypes,
-                                      baseType);
-  }
-
-  /**
-   * Computes the union of [mask1] and [mask2] where [mask1] and [mask2] are
-   * possibly equal to [: DynamicTypeMask.instance :].
-   */
-  TypeMask typeMaskUnion(TypeMask mask1, TypeMask mask2) {
-    if (mask1 == const DynamicTypeMask() || mask2 == const DynamicTypeMask()) {
-      return const DynamicTypeMask();
-    }
-    return mask1.union(mask2, compiler.world);
-  }
-
-  /**
-   * Returns all the members matching [selector].
-   */
-  Set<Element> getMembersBySelector(Selector selector) {
-    // TODO(polux): memoize?
-    Set<Element> result = new Set<Element>();
-    for (ClassElement cls in seenClasses) {
-      Element elem = cls.lookupByName(selector.memberName);
-      if (elem != null) {
-        result.add(elem.implementation);
-      }
-    }
-    return result;
-  }
-
-  /**
-   * Returns all the subtypes of [cls], [cls] included.
-   */
-  Set<ClassElement> getReflexiveSubtypesOf(ClassElement cls) {
-    // TODO(polux): memoize?
-    Set<ClassElement> result = new Set<ClassElement>()..add(cls);
-    for (ClassElement candidate in seenClasses) {
-      if (compiler.world.isSubtypeOf(candidate, cls)) {
-        result.add(candidate);
-      }
-    }
-    return result;
-  }
-
-  /**
-   * Sets the concrete type associated to [node] to the union of the inferred
-   * concrete type so far and of [type].
-   */
-  void augmentInferredType(Node node, ConcreteType type) {
-    ConcreteType currentType = inferredTypes[node];
-    inferredTypes[node] =
-        (currentType == null) ? type : currentType.union(type);
-  }
-
-  /**
-   * Sets the concrete type associated to [selector] to the union of the
-   * inferred concrete type so far and of [returnType].
-   *
-   * Precondition: [:(typeOfThis != null) && (returnType != null):]
-   */
-  void augmentInferredSelectorType(Selector selector,
-                                   TypeMask typeOfThis,
-                                   TypeMask returnType) {
-    assert(returnType != null);
-    assert(typeOfThis != null);
-
-    Map<TypeMask, TypeMask> currentMap = inferredSelectorTypes.putIfAbsent(
-        selector, () => new Map<TypeMask, TypeMask>());
-    TypeMask currentReturnType = currentMap[typeOfThis];
-    currentMap[typeOfThis] = (currentReturnType == null)
-        ? returnType
-        : typeMaskUnion(currentReturnType, returnType);
-  }
-
-  /**
-   * Returns the current inferred concrete type of [field].
-   */
-  ConcreteType getFieldType(Selector selector, Element field) {
-    ensureFieldInitialized(field);
-    ConcreteType result = inferredFieldTypes[field];
-    result = (result == null) ? emptyConcreteType : result;
-    if (selector != null) {
-      Element enclosing = field.enclosingElement;
-      if (enclosing.isClass) {
-        ClassElement cls = enclosing;
-        TypeMask receiverMask = new TypeMask.exact(cls.declaration, classWorld);
-        TypeMask resultMask = types.concreteTypeToTypeMask(result);
-        augmentInferredSelectorType(selector, receiverMask, resultMask);
-      }
-    }
-    return result;
-  }
-
-  /**
-   * Sets the concrete type associated to [field] to the union of the inferred
-   * concrete type so far and of [type].
-   */
-  void augmentFieldType(Element field, ConcreteType type) {
-    ensureFieldInitialized(field);
-    ConcreteType oldType = inferredFieldTypes[field];
-    ConcreteType newType = (oldType != null) ? oldType.union(type) : type;
-    if (oldType != newType) {
-      inferredFieldTypes[field] = newType;
-      invalidateReaders(field);
-    }
-  }
-
-  /** Augment the inferred type of elements stored in Lists. */
-  void augmentListElementType(ConcreteType type) {
-    ConcreteType newType = listElementType.union(type);
-    if (newType != listElementType) {
-      invalidateCallers(listIndex);
-      listElementType = newType;
-    }
-  }
-
-  /**
-   * Sets the concrete type associated to [parameter] to the union of the
-   * inferred concrete type so far and of [type].
-   */
-  void augmentParameterType(VariableElement parameter, ConcreteType type) {
-    ConcreteType oldType = inferredParameterTypes[parameter];
-    inferredParameterTypes[parameter] =
-        (oldType == null) ? type : oldType.union(type);
-  }
-
-  /** Augments the set of classes encountered so far. */
-  void augmentSeenClasses(ClassElement cls) {
-    if (!seenClasses.contains(cls)) {
-      seenClasses.add(cls);
-      cls.forEachMember((_, Element member) {
-        Set<FunctionElement> functions = dynamicCallers[member.name];
-        if (functions != null) {
-          functions.forEach(invalidate);
-        }
-      }, includeSuperAndInjectedMembers: true);
-    }
-  }
-
-  /**
-   * Add [caller] to the set of [callee]'s callers.
-   */
-  void addCaller(FunctionElement callee, Element caller) {
-    callers.putIfAbsent(callee, () => new Set<Element>())
-           .add(caller);
-  }
-
-  /**
-   * Add [caller] to the set of [callee]'s dynamic callers.
-   */
-  void addDynamicCaller(Selector callee, FunctionElement caller) {
-      dynamicCallers
-          .putIfAbsent(callee.name, () => new Set<FunctionElement>())
-          .add(caller);
-  }
-
-  /**
-   * Add [reader] to the set of [field]'s readers.
-   */
-  void addFieldReader(Element field, Element reader) {
-    fieldReaders.putIfAbsent(field, () => new Set<Element>())
-                .add(reader);
-  }
-
-  /**
-   * Add [reader] to the set of [local]'s readers.
-   */
-  void addCapturedLocalReader(Local local, FunctionElement reader) {
-    capturedLocalsReaders.putIfAbsent(local, () => new Set<FunctionElement>())
-                         .add(reader);
-  }
-
-  /**
-   * Add a closure to the set of seen closures. Invalidate callers if
-   * the set of locals has changed.
-   */
-  void addClosure(FunctionElement closure,
-                  ConcreteType typeOfThis,
-                  LocalsHandler locals) {
-    if (closures.put(closure, typeOfThis, locals)) {
-      invalidateCallers(closure);
-    }
-  }
-
-  /**
-   * Invalidate all callers of [function].
-   */
-  void invalidateCallers(FunctionElement function) {
-    Set<Element> methodCallers = callers[function];
-    if (methodCallers != null) {
-      methodCallers.forEach(invalidate);
-    }
-  }
-
-  /**
-   * Invalidate all reader of [field].
-   */
-  void invalidateReaders(Element field) {
-    Set<Element> readers = fieldReaders[field];
-    if (readers != null) {
-      readers.forEach(invalidate);
-    }
-  }
-
-  /**
-   * Add all templates of [methodOrField] to the workqueue.
-   */
-  void invalidate(Element methodOrField) {
-    if (methodOrField.isField) {
-      workQueue.add(new InferenceWorkItem(
-          methodOrField, new ConcreteTypesEnvironment()));
-    } else {
-      Map<ConcreteTypesEnvironment, ConcreteType> templates =
-          methodToTemplates[methodOrField];
-      if (templates != null) {
-        templates.forEach((environment, _) {
-          workQueue.add(
-              new InferenceWorkItem(methodOrField, environment));
-        });
-      }
-    }
-  }
-
-  /**
-   * Returns the template associated to [function] or create an empty template
-   * for [function] return it.
-   */
-  // TODO(polux): encapsulate this in an abstraction for templates
-  Map<ConcreteTypesEnvironment, ConcreteType>
-      getTemplatesOrEmpty(FunctionElement function) {
-    return methodToTemplates.putIfAbsent(
-        function,
-        () => new Map<ConcreteTypesEnvironment, ConcreteType>());
-  }
-
-  // -- methods of types.TypesInferrer (interface with the backend) --
-
-  /** Get the inferred concrete type of [node]. */
-  @override
-  TypeMask getTypeOfNode(Element owner, Node node) {
-    TypeMask result = types.concreteTypeToTypeMask(inferredTypes[node]);
-    return (result == const DynamicTypeMask()) ? null : result;
-  }
-
-  /** Get the inferred concrete type of [element]. */
-  @override
-  TypeMask getTypeOfElement(Element element) {
-    final result = types.concreteTypeToTypeMask(typeOfElement(element));
-    return (result == const DynamicTypeMask()) ? null : result;
-  }
-
-  /**
-   * Get the inferred concrete return type of [element]. A null return value
-   * means "I don't know".
-   */
-  @override
-  TypeMask getReturnTypeOfElement(Element element) {
-    assert(element is FunctionElement);
-    Map<ConcreteTypesEnvironment, ConcreteType> templates =
-        methodToTemplates[element];
-    if (templates == null) return null;
-    ConcreteType returnType = emptyConcreteType;
-    templates.forEach((_, concreteType) {
-      returnType = returnType.union(concreteType);
-    });
-    TypeMask result = types.concreteTypeToTypeMask(returnType);
-    return (result == const DynamicTypeMask()) ? null : result;
-  }
-
-  /**
-   * Get the inferred concrete type of [selector]. A null return value means
-   * "I don't know".
-   */
-  @override
-  TypeMask getTypeOfSelector(Selector selector, TypeMask mask) {
-    Map<TypeMask, TypeMask> candidates = inferredSelectorTypes[selector];
-    if (candidates == null) {
-      return null;
-    }
-    TypeMask result = new TypeMask.nonNullEmpty();
-    if (mask == null) {
-      candidates.forEach((TypeMask receiverType, TypeMask returnType) {
-        result = typeMaskUnion(result, returnType);
-      });
-    } else {
-      candidates.forEach((TypeMask receiverType, TypeMask returnType) {
-        TypeMask intersection = receiverType.intersection(mask, compiler.world);
-        if (!intersection.isEmpty || intersection.isNullable) {
-          result = typeMaskUnion(result, returnType);
-        }
-      });
-    }
-    return result == const DynamicTypeMask() ? null : result;
-  }
-
-  @override
-  void clear() {
-    throw new UnsupportedError("clearing is not yet implemented");
-  }
-
-  @override
-  bool isCalledOnce(Element element) {
-    // Never called by SimpleTypeInferrer.
-    throw new UnsupportedError("");
-  }
-
-  @override
-  bool isFixedArrayCheckedForGrowable(Node node) {
-    // Never called by SimpleTypeInferrer.
-    throw new UnsupportedError("");
-  }
-
-  // --- analysis ---
-
-  /**
-   * Returns the concrete type returned by [function] given arguments of
-   * concrete types [argumentsTypes]. If [function] is static then
-   * [receiverType] must be null, else [function] must be a member of
-   * [receiverType].
-   */
-  ConcreteType getSendReturnType(Selector selector,
-                                 FunctionElement function,
-                                 ClassElement receiverType,
-                                 ArgumentsTypes<ConcreteType> argumentsTypes) {
-    assert(function != null);
-
-    ConcreteType result = emptyConcreteType;
-    Map<Element, ConcreteType> argumentMap =
-        associateArguments(function, argumentsTypes);
-    // if the association failed, this send will never occur or will fail
-    if (argumentMap == null) {
-      return emptyConcreteType;
-    }
-
-    argumentMap.forEach(augmentParameterType);
-    ConcreteTypeCartesianProduct product =
-        new ConcreteTypeCartesianProduct(this, receiverType, argumentMap);
-    for (ConcreteTypesEnvironment environment in product) {
-      result = result.union(
-          getMonomorphicSendReturnType(function, environment));
-    }
-
-    if (selector != null && receiverType != null) {
-      // TODO(polux): generalize to any abstract class if we ever handle other
-      // abstract classes than num.
-      TypeMask receiverMask =
-          (receiverType == compiler.backend.numImplementation
-          || receiverType == compiler.backend.intImplementation)
-              ? new TypeMask.nonNullSubclass(receiverType.declaration,
-                  compiler.world)
-              : new TypeMask.nonNullExact(receiverType.declaration,
-                  compiler.world);
-      TypeMask resultMask = types.concreteTypeToTypeMask(result);
-      augmentInferredSelectorType(selector, receiverMask, resultMask);
-    }
-
-    return result;
-  }
-
-  /**
-   * Given a method signature and a list of concrete types, builds a map from
-   * formals to their corresponding concrete types. Returns null if the
-   * association is impossible (for instance: too many arguments).
-   */
-  Map<Element, ConcreteType> associateArguments(
-      FunctionElement function,
-      ArgumentsTypes<ConcreteType> argumentsTypes) {
-    final Map<Element, ConcreteType> result = new Map<Element, ConcreteType>();
-    final FunctionSignature signature = function.functionSignature;
-
-    // guard 1: too many arguments
-    if (argumentsTypes.length > signature.parameterCount) {
-      return null;
-    }
-    // guard 2: not enough arguments
-    if (argumentsTypes.positional.length < signature.requiredParameterCount) {
-      return null;
-    }
-    // guard 3: too many positional arguments
-    if (signature.optionalParametersAreNamed &&
-        argumentsTypes.positional.length > signature.requiredParameterCount) {
-      return null;
-    }
-
-    handleLeftoverOptionalParameter(ParameterElement parameter) {
-      Expression initializer = parameter.initializer;
-      result[parameter] = (initializer == null)
-          ? nullConcreteType
-          : analyzeDefaultValue(function, initializer);
-    }
-
-    final Iterator<ConcreteType> remainingPositionalArguments =
-        argumentsTypes.positional.iterator;
-    // we attach each positional parameter to its corresponding positional
-    // argument
-    for (Element requiredParameter in signature.requiredParameters) {
-      // we know moveNext() succeeds because of guard 2
-      remainingPositionalArguments.moveNext();
-      result[requiredParameter] = remainingPositionalArguments.current;
-    }
-    if (signature.optionalParametersAreNamed) {
-      // we build a map out of the remaining named parameters
-      final Map<String, Element> leftOverNamedParameters =
-          new Map<String, Element>();
-      for (Element namedParameter in signature.optionalParameters) {
-        leftOverNamedParameters[namedParameter.name] = namedParameter;
-      }
-      // we attach the named arguments to their corresponding optional
-      // parameters
-      for (String source in argumentsTypes.named.keys) {
-        final ConcreteType concreteType = argumentsTypes.named[source];
-        final Element namedParameter = leftOverNamedParameters[source];
-        // unexisting or already used named parameter
-        if (namedParameter == null) return null;
-        result[namedParameter] = concreteType;
-        leftOverNamedParameters.remove(source);
-      }
-      leftOverNamedParameters.forEach((_, Element parameter) {
-        handleLeftoverOptionalParameter(parameter);
-      });
-    } else { // optional parameters are positional
-      // we attach the remaining positional arguments to their corresponding
-      // optional parameters
-      Iterator<Element> remainingOptionalParameters =
-          signature.optionalParameters.iterator;
-      while (remainingPositionalArguments.moveNext()) {
-        // we know this is true because of guard 1
-        remainingOptionalParameters.moveNext();
-        final Element optionalParameter = remainingOptionalParameters.current;
-        result[optionalParameter] = remainingPositionalArguments.current;
-      }
-      while (remainingOptionalParameters.moveNext()) {
-        handleLeftoverOptionalParameter(remainingOptionalParameters.current);
-      }
-    }
-    return result;
-  }
-
-  ConcreteType getMonomorphicSendReturnType(
-      FunctionElement function,
-      ConcreteTypesEnvironment environment) {
-    Map<ConcreteTypesEnvironment, ConcreteType> template =
-        getTemplatesOrEmpty(function);
-    ConcreteType type = template[environment];
-    ConcreteType specialType = getSpecialCaseReturnType(function, environment);
-    if (type != null) {
-      return specialType != null ? specialType : type;
-    } else {
-      workQueue.add(new InferenceWorkItem(function, environment));
-      return specialType != null ? specialType : emptyConcreteType;
-    }
-  }
-
-  /**
-   * Handles external methods that cannot be cached because they depend on some
-   * other state of [ConcreteTypesInferrer] like [:List#[]:] and
-   * [:List#[]=:]. Returns null if [function] and [environment] don't form a
-   * special case
-   */
-  ConcreteType getSpecialCaseReturnType(FunctionElement function,
-                                        ConcreteTypesEnvironment environment) {
-    // Handles int + int, double + double, int - int, ...
-    // We cannot compare function to int#+, int#-, etc. because int and double
-    // don't override these methods. So for 1+2, getSpecialCaseReturnType will
-    // be invoked with function = num#+. We use environment.typeOfThis instead.
-    ClassElement cls = environment.classOfThis;
-    List<Element> parameters = function.parameters;
-    if (cls != null) {
-      String name = function.name;
-      if ((cls == baseTypes.intBaseType.element
-          || cls == baseTypes.doubleBaseType.element)
-          && (name == '+' || name == '-' || name == '*')) {
-        ConcreteType argumentType = environment.lookupType(parameters.single);
-        if (argumentType.getUniqueType() == cls) {
-          return singletonConcreteType(new ClassBaseType(cls));
-        }
-      }
-    }
-
-    if (function == listIndex || function == listRemoveAt) {
-      ConcreteType indexType = environment.lookupType(parameters.single);
-      if (!indexType.baseTypes.contains(baseTypes.intBaseType)) {
-        return emptyConcreteType;
-      }
-      return listElementType;
-    } else if (function == listIndexSet || function == listInsert) {
-      ConcreteType indexType = environment.lookupType(parameters[0]);
-      if (!indexType.baseTypes.contains(baseTypes.intBaseType)) {
-        return emptyConcreteType;
-      }
-      ConcreteType elementType = environment.lookupType(parameters[1]);
-      augmentListElementType(elementType);
-      return emptyConcreteType;
-    } else if (function == listAdd) {
-      ConcreteType elementType = environment.lookupType(parameters.single);
-      augmentListElementType(elementType);
-      return emptyConcreteType;
-    } else if (function == listRemoveLast) {
-      return listElementType;
-    }
-    return null;
-  }
-
-  ConcreteType analyzeMethodOrClosure(Element element,
-      ConcreteTypesEnvironment environment) {
-    ConcreteType specialResult = handleSpecialMethod(element, environment);
-    if (specialResult != null) return specialResult;
-    ClosureEnvironment closureEnv = closures.getEnvironmentOrNull(element);
-    return (closureEnv == null)
-        ? analyzeMethod(element, environment)
-        : analyzeClosure(element, closureEnv, environment);
-  }
-
-  ConcreteType analyzeMethod(Element element,
-                             ConcreteTypesEnvironment environment) {
-    TypeInferrerVisitor visitor = new TypeInferrerVisitor(
-        element,
-        this,
-        singletonConcreteType(new ClassBaseType(environment.classOfThis)),
-        environment.environment);
-    visitor.run();
-    return visitor.returnType;
-  }
-
-  ConcreteType analyzeClosure(Element element,
-                              ClosureEnvironment closureEnv,
-                              ConcreteTypesEnvironment environment) {
-    assert(environment.classOfThis == null);
-    LocalsHandler locals = (closureEnv.locals != null)
-        ? new LocalsHandler.deepCopyOf(closureEnv.locals)
-        : null;
-    TypeInferrerVisitor visitor = new TypeInferrerVisitor(element, this,
-        closureEnv.thisType, environment.environment, locals);
-    visitor.run();
-    return visitor.returnType;
-  }
-
-  /**
-   * Analyze the initializer of a field if it has not yet been done and update
-   * [inferredFieldTypes] accordingly. Invalidate the readers of the field if
-   * needed.
-   */
-  void ensureFieldInitialized(Element field) {
-    // This is test is needed for fitering out BoxFieldElements.
-    if (field is! BoxFieldElement && inferredFieldTypes[field] == null) {
-      analyzeFieldInitialization(field);
-    }
-  }
-
-  /**
-   * Analyze the initializer of a field and update [inferredFieldTypes]
-   * accordingly. Invalidate the readers of the field if needed.
-   */
-  ConcreteType analyzeFieldInitialization(VariableElement field) {
-    Visitor visitor = new TypeInferrerVisitor(field, this, null, new Map());
-    ConcreteType type;
-    if (field.initializer != null) {
-      type = field.initializer.accept(visitor);
-      inferredFieldTypes[field] = type;
-      invalidateReaders(field);
-    }
-    return type;
-  }
-
-  /**
-   * Analyze a default value.
-   */
-  ConcreteType analyzeDefaultValue(Element function, Node expression) {
-    assert((function != null) && (expression != null));
-    Visitor visitor = new TypeInferrerVisitor(function, this, null, {});
-    return expression.accept(visitor);
-  }
-
-  /**
-   * Hook that performs side effects on some special method calls (like
-   * [:List(length):]) and possibly returns a concrete type.
-   */
-  ConcreteType handleSpecialMethod(FunctionElement element,
-                                   ConcreteTypesEnvironment environment) {
-    // We trust the return type of native elements
-    if (isNativeElement(element)) {
-      var elementType = element.type;
-      assert(elementType.isFunctionType);
-      return typeOfNativeBehavior(
-          native.NativeBehavior.ofMethod(element, compiler));
-    }
-    // When List([length]) is called with some length, we must augment
-    // listElementType with {null}.
-    if (element == listConstructor) {
-      List<Element> parameters =
-          listConstructor.functionSignature.optionalParameters;
-      ConcreteType lengthType = environment.lookupType(parameters.first);
-      if (lengthType.baseTypes.contains(baseTypes.intBaseType)) {
-        augmentListElementType(nullConcreteType);
-      }
-    }
-    return null;
-  }
-
-  /**
-   * Performs concrete type inference of the code reachable from [element].
-   */
-  @override
-  bool analyzeMain(Element element) {
-    initialize();
-    workQueue.add(
-        new InferenceWorkItem(element, new ConcreteTypesEnvironment()));
-    while (!workQueue.isEmpty) {
-      currentWorkItem = workQueue.remove();
-      if (currentWorkItem.method.isField) {
-        analyzeFieldInitialization(currentWorkItem.method);
-      } else {
-        Map<ConcreteTypesEnvironment, ConcreteType> template =
-            getTemplatesOrEmpty(currentWorkItem.method);
-        template.putIfAbsent(
-            currentWorkItem.environment, () => emptyConcreteType);
-        recordReturnType(
-            currentWorkItem.method,
-            analyzeMethodOrClosure(currentWorkItem.method,
-                                   currentWorkItem.environment));
-      }
-    }
-    return true;
-  }
-
-  /**
-   * Dumps debugging information on the standard output.
-   */
-  void debug() {
-    print("queue:");
-    for (InferenceWorkItem workItem in workQueue.queue) {
-      print("  $workItem");
-    }
-    print("seen classes:");
-    for (ClassElement cls in seenClasses) {
-      print("  ${cls.name}");
-    }
-    print("callers:");
-    callers.forEach((k,v) {
-      print("  $k: $v");
-    });
-    print("dynamic callers:");
-    dynamicCallers.forEach((k,v) {
-      print("  $k: $v");
-    });
-    print("readers:");
-    fieldReaders.forEach((k,v) {
-      print("  $k: $v");
-    });
-    print("readers of captured locals:");
-    capturedLocalsReaders.forEach((k,v) {
-      print("  $k: $v");
-    });
-    print("inferredFieldTypes:");
-    inferredFieldTypes.forEach((k,v) {
-      print("  $k: $v");
-    });
-    print("listElementType:");
-    print("  $listElementType");
-    print("inferredParameterTypes:");
-    inferredParameterTypes.forEach((k,v) {
-      print("  $k: $v");
-    });
-    print("inferred selector types:");
-    inferredSelectorTypes.forEach((selector, map) {
-      print("  $selector:");
-      map.forEach((k, v) {
-        print("    $k: $v");
-      });
-    });
-    print("cache:");
-    methodToTemplates.forEach((k,v) {
-      print("  $k: $v");
-    });
-    print("closures:");
-    closures.closures.forEach((k, ClosureEnvironment v) {
-      print("  $k");
-      print("    this: ${v.thisType}");
-      if (v.locals != null) {
-        v.locals.locals.forEachLocal((local, type) {
-          print("    $local: $type");
-        });
-      }
-    });
-    print("inferred expression types:");
-    inferredTypes.forEach((k,v) {
-      print("  $k: $v");
-    });
-  }
-
-  @override
-  ConcreteType addReturnTypeFor(Element analyzedElement,
-                                ConcreteType currentType,
-                                ConcreteType newType) {
-    return (currentType == null) ? newType : currentType.union(newType);
-  }
-
-  @override
-  void forEachElementMatching(Selector selector,
-                              TypeMask mask,
-                              bool f(Element element)) {
-    getMembersBySelector(selector).forEach(f);
-  }
-
-  @override
-  void recordReturnType(Element element, ConcreteType type) {
-    assert((type != null) && (element == currentWorkItem.method));
-    Map<ConcreteTypesEnvironment, ConcreteType> template =
-        getTemplatesOrEmpty(element);
-    if (template[currentWorkItem.environment] != type) {
-      template[currentWorkItem.environment] = type;
-      invalidateCallers(element);
-    }
-  }
-
-  @override
-  void recordType(Element element, ConcreteType type) {
-    assert(element is FieldElement);
-    augmentFieldType(element, type);
-  }
-
-  @override
-  void recordTypeOfFinalField(Node node,
-                              Element nodeHolder,
-                              Element field,
-                              ConcreteType type) {
-    augmentFieldType(field, type);
-  }
-
-  @override
-  void recordTypeOfNonFinalField(Spannable node, Element field,
-                                 ConcreteType type) {
-    augmentFieldType(field, type);
-  }
-
-  @override
-  void recordCapturedLocalRead(Local local) {
-    addCapturedLocalReader(local, currentWorkItem.method);
-  }
-
-  @override
-  void recordLocalUpdate(Local local, ConcreteType type) {
-    Set<FunctionElement> localReaders = capturedLocalsReaders[local];
-    if (localReaders != null) {
-      localReaders.forEach(invalidate);
-    }
-  }
-
-  /**
-   * Returns the caller of the current analyzed element, given the alleged
-   * caller provided by SimpleTypeInferrer.
-   *
-   * SimpleTypeInferrer lies about the caller when it's a closure.
-   * Unfortunately we cannot always trust currentWorkItem.method either because
-   * it is wrong for fields initializers.
-   */
-  Element getRealCaller(Element allegedCaller) {
-    Element currentMethod = currentWorkItem.method;
-    if ((currentMethod != allegedCaller)
-        && currentMethod.isFunction
-        && closures.contains(currentMethod)) {
-      return currentMethod;
-    } else {
-      return allegedCaller;
-    }
-  }
-
-  @override
-  ConcreteType registerCalledElement(Spannable node,
-                                     Selector selector,
-                                     TypeMask mask,
-                                     Element caller,
-                                     Element callee,
-                                     ArgumentsTypes<ConcreteType> arguments,
-                                     SideEffects sideEffects,
-                                     bool inLoop) {
-    caller = getRealCaller(caller);
-    if ((selector == null) || (selector.isCall)) {
-      callee = callee.implementation;
-      if (selector != null && selector.name == 'JS') {
-        return null;
-      }
-      if (callee.isField) {  // toplevel closure call
-        getFieldType(selector, callee);  // trigger toplevel field analysis
-        addFieldReader(callee, caller);
-        ConcreteType result = emptyConcreteType;
-        for (FunctionElement function in closures.functionElements) {
-          addCaller(function, caller);
-          result = result.union(
-              getSendReturnType(selector, function, null, arguments));
-        }
-        return result;
-      } else {  // method or constructor call
-        addCaller(callee, caller);
-        ClassElement receiverClass = null;
-        if (callee.isGenerativeConstructor) {
-          receiverClass = callee.enclosingClass;
-        } else if (node is Send) {
-          Send send = node;
-          if (send.receiver != null) {
-            if (send.receiver.isSuper()) {
-              receiverClass =
-                  currentWorkItem.environment.classOfThis.superclass;
-            } else {
-              receiverClass = currentWorkItem.environment.classOfThis;
-            }
-          }
-        }
-        return getSendReturnType(selector, callee, receiverClass, arguments);
-      }
-    } else if (selector.isGetter) {
-      if (callee.isField) {
-        addFieldReader(callee, caller);
-        return getFieldType(selector, callee);
-      } else if (callee.isGetter) {
-        Element enclosing = callee.enclosingElement.isCompilationUnit
-            ? null : callee.enclosingElement;
-        addCaller(callee, caller);
-        ArgumentsTypes noArguments = new ArgumentsTypes([], new Map());
-        return getSendReturnType(selector, callee, enclosing, noArguments);
-      } else if (callee.isFunction) {
-        addClosure(callee, null, null);
-        return singletonConcreteType(baseTypes.functionBaseType);
-      }
-    } else if (selector.isSetter) {
-      ConcreteType argumentType = arguments.positional.first;
-      if (callee.isField) {
-        augmentFieldType(callee, argumentType);
-      } else if (callee.isSetter) {
-        FunctionElement setter = callee;
-        // TODO(polux): A setter always returns void so there's no need to
-        // invalidate its callers even if it is called with new arguments.
-        // However, if we start to record more than returned types, like
-        // exceptions for instance, we need to do it by uncommenting the
-        // following line.
-        // inferrer.addCaller(setter, currentMethod);
-        Element enclosing = callee.enclosingElement.isCompilationUnit
-            ? null : callee.enclosingElement;
-        return getSendReturnType(selector, setter, enclosing,
-            new ArgumentsTypes([argumentType], new Map()));
-      }
-    } else {
-      throw new ArgumentError("unexpected selector kind");
-    }
-    return null;
-  }
-
-  @override
-  ConcreteType registerCalledSelector(Node node,
-                                      Selector selector,
-                                      TypeMask mask,
-                                      ConcreteType receiverType,
-                                      Element caller,
-                                      ArgumentsTypes<ConcreteType> arguments,
-                                      SideEffects sideEffects,
-                                      bool inLoop) {
-    caller = getRealCaller(caller);
-    switch (selector.kind) {
-      case SelectorKind.GETTER:
-        return registerDynamicGetterSend(selector, receiverType, caller);
-      case SelectorKind.SETTER:
-        return registerDynamicSetterSend(
-            selector, receiverType, caller, arguments);
-      default:
-        return registerDynamicSend(selector, receiverType, caller, arguments);
-    }
-  }
-
-  ConcreteType registerDynamicGetterSend(Selector selector,
-                                         ConcreteType receiverType,
-                                         Element caller) {
-    caller = getRealCaller(caller);
-    ConcreteType result = emptyConcreteType;
-
-    void augmentResult(ClassElement baseReceiverType, Element member) {
-      if (member.isField) {
-        addFieldReader(member, caller);
-        result = result.union(getFieldType(selector, member));
-      } else if (member.isGetter) {
-        addCaller(member, caller);
-        ArgumentsTypes noArguments = new ArgumentsTypes([], new Map());
-        result = result.union(
-            getSendReturnType(selector, member, baseReceiverType, noArguments));
-      } else if (member.isFunction) {
-        addClosure(member, receiverType, null);
-        result = result.union(
-            singletonConcreteType(baseTypes.functionBaseType));
-      } else {
-        throw new ArgumentError("unexpected element type");
-      }
-    }
-
-    if (receiverType.isUnknown()) {
-      addDynamicCaller(selector, caller);
-      Set<Element> members = getMembersBySelector(selector);
-      for (Element member in members) {
-        if (!(member.isField || member.isGetter)) continue;
-        for (ClassElement cls in
-            getReflexiveSubtypesOf(member.enclosingElement)) {
-          augmentResult(cls, member);
-        }
-      }
-    } else {
-      for (BaseType baseReceiverType in receiverType.baseTypes) {
-        if (!baseReceiverType.isNull()) {
-          ClassBaseType classBaseType = baseReceiverType;
-          ClassElement cls = classBaseType.element;
-          Element getterOrField = cls.lookupByName(selector.memberName);
-          if (getterOrField != null) {
-            augmentResult(cls, getterOrField.implementation);
-          }
-        }
-      }
-    }
-    return result;
-  }
-
-  ConcreteType registerDynamicSetterSend(
-      Selector selector,
-      ConcreteType receiverType,
-      Element caller,
-      ArgumentsTypes<ConcreteType> arguments) {
-    caller = getRealCaller(caller);
-    ConcreteType argumentType = arguments.positional.first;
-
-    void augmentField(ClassElement receiverType, Element setterOrField) {
-      if (setterOrField.isField) {
-        augmentFieldType(setterOrField, argumentType);
-      } else if (setterOrField.isSetter) {
-        // A setter always returns void so there's no need to invalidate its
-        // callers even if it is called with new arguments. However, if we
-        // start to record more than returned types, like exceptions for
-        // instance, we need to do it by uncommenting the following line.
-        // inferrer.addCaller(setter, currentMethod);
-        getSendReturnType(selector, setterOrField, receiverType,
-            new ArgumentsTypes([argumentType], new Map()));
-      } else {
-        throw new ArgumentError("unexpected element type");
-      }
-    }
-
-    if (receiverType.isUnknown()) {
-      // Same remark as above
-      // addDynamicCaller(selector, caller);
-      for (Element member in getMembersBySelector(selector)) {
-        if (!(member.isField || member.isSetter)) continue;
-        Element cls = member.enclosingClass;
-        augmentField(cls, member);
-      }
-    } else {
-      for (BaseType baseReceiverType in receiverType.baseTypes) {
-        if (!baseReceiverType.isNull()) {
-          ClassBaseType classBaseType = baseReceiverType;
-          ClassElement cls = classBaseType.element;
-          Element setterOrField = cls.lookupByName(selector.memberName);
-          if (setterOrField != null) {
-            augmentField(cls, setterOrField.implementation);
-          }
-        }
-      }
-    }
-    return argumentType;
-  }
-
-  ConcreteType registerDynamicSend(Selector selector,
-                                   ConcreteType receiverType,
-                                   Element caller,
-                                   ArgumentsTypes<ConcreteType> arguments) {
-    caller = getRealCaller(caller);
-    ConcreteType result = emptyConcreteType;
-    if (receiverType.isUnknown()) {
-      addDynamicCaller(selector, caller);
-      Set<Element> elements = getMembersBySelector(selector);
-      for (Element element in elements) {
-        if (element.isFunction) {
-          FunctionElement method = element;
-          addCaller(method, caller);
-          for (ClassElement cls in
-              getReflexiveSubtypesOf(method.enclosingElement)) {
-            result = result.union(
-                getSendReturnType(selector, method, cls, arguments));
-          }
-        } else { // closure call
-          assert(element.isField);
-          for (FunctionElement function in closures.functionElements) {
-            addCaller(function, caller);
-            result = result.union(
-                getSendReturnType(selector, function, null, arguments));
-          }
-        }
-      }
-    } else {
-      for (BaseType baseReceiverType in receiverType.baseTypes) {
-        if (!baseReceiverType.isNull()) {
-          ClassBaseType classBaseReceiverType = baseReceiverType;
-          ClassElement cls = classBaseReceiverType.element;
-          Element method = cls.lookupByName(selector.memberName);
-          if (method != null) {
-            if (method.isFunction) {
-              assert(method is FunctionElement);
-              method = method.implementation;
-              addCaller(method, caller);
-              result = result.union(
-                  getSendReturnType(selector, method, cls, arguments));
-            } else { // closure call
-              for (FunctionElement function in closures.functionElements) {
-                addCaller(function, caller);
-                result = result.union(
-                    getSendReturnType(selector, function, null, arguments));
-              }
-            }
-          }
-        }
-      }
-    }
-    return result;
-  }
-
-  ConcreteType registerAwait(Node node, ConcreteType argumentType) {
-    // TODO(polux): Properly handle await expressions.
-    return types.dynamicType;
-  }
-
-  @override
-  void setDefaultTypeOfParameter(ParameterElement parameter,
-                                 ConcreteType type) {
-    // We handle default parameters our own way in associateArguments
-  }
-
-  /**
-   * TODO(johnniwinther): Remove once synthetic parameters get their own default
-   * values.
-   */
-  bool hasAlreadyComputedTypeOfParameterDefault(Element parameter) => false;
-
-  @override
-  ConcreteType registerCalledClosure(Node node,
-                                     Selector selector,
-                                     TypeMask mask,
-                                     ConcreteType closure,
-                                     Element caller,
-                                     ArgumentsTypes<ConcreteType> arguments,
-                                     SideEffects sideEffects,
-                                     bool inLoop) {
-    caller = getRealCaller(caller);
-    ConcreteType result = emptyConcreteType;
-    for (FunctionElement function in closures.functionElements) {
-      addCaller(function, caller);
-      result = result.union(
-          getSendReturnType(selector, function, null, arguments));
-    }
-    return result;
-  }
-
-  @override
-  ConcreteType returnTypeOfElement(Element element) {
-    // Never called by SimpleTypeInferrer.
-    throw new UnsupportedError("");
-  }
-
-  @override
-  ConcreteType typeOfElement(Element element) {
-    if (currentWorkItem != null) {
-      final result = currentWorkItem.environment.lookupType(element);
-      if (result != null) return result;
-    }
-    if (element.isParameter || element.isInitializingFormal) {
-      return inferredParameterTypes[element];
-    } else if (element.isField) {
-      return inferredFieldTypes[element];
-    }
-    throw new ArgumentError("unexpected element type");
-  }
-
-  @override
-  void analyze(Element element, ArgumentsTypes arguments) {
-    FunctionElement function = element;
-    getSendReturnType(
-        null, function, currentWorkItem.environment.classOfThis, arguments);
-  }
-}
-
-class TypeInferrerVisitor extends SimpleTypeInferrerVisitor<ConcreteType> {
-  final ConcreteType thisType;
-  ConcreteTypesInferrer get inferrer => super.inferrer;
-
-  TypeInferrerVisitor(Element element,
-                      ConcreteTypesInferrer inferrer,
-                      this.thisType,
-                      Map<Element, ConcreteType> environment,
-                      [LocalsHandler<ConcreteType> handler])
-      : super(element, inferrer.compiler, inferrer, handler);
-
-  @override
-  ConcreteType visitFunctionExpression(FunctionExpression node) {
-    Element element = elements[node];
-    // visitFunctionExpression should be only called for closures
-    assert(element != analyzedElement);
-    inferrer.addClosure(
-        element, thisType, new LocalsHandler.deepCopyOf(locals));
-    return types.functionType;
-  }
-
-  @override
-  ConcreteType visitLiteralString(LiteralString node) {
-    // TODO(polux): get rid of this hack once we have a natural way of inferring
-    // the unknown type.
-    if (inferrer.testMode
-        && (node.dartString.slowToString() == "__dynamic_for_test")) {
-      return inferrer.unknownConcreteType;
-    }
-    return super.visitLiteralString(node);
-  }
-
-  /**
-   * Same as super.visitLiteralList except it doesn't cache anything.
-   */
-  @override
-  ConcreteType visitLiteralList(LiteralList node) {
-    ConcreteType elementType;
-    int length = 0;
-    for (Node element in node.elements.nodes) {
-      ConcreteType type = visit(element);
-      elementType = elementType == null
-          ? types.allocatePhi(null, null, type)
-          : types.addPhiInput(null, elementType, type);
-      length++;
-    }
-    elementType = elementType == null
-        ? types.nonNullEmpty()
-        : types.simplifyPhi(null, null, elementType);
-    ConcreteType containerType = node.isConst
-        ? types.constListType
-        : types.growableListType;
-    return types.allocateList(
-        containerType,
-        node,
-        outermostElement,
-        elementType,
-        length);
-  }
-
-  /**
-   * Same as super.handleLocalGet except it records the type of nodes in test
-   * mode.
-   */
-  @override
-  ConcreteType handleLocalGet(Send node, LocalElement local) {
-    if (inferrer.testMode) {
-      ConcreteType type = locals.use(local);
-      if (type != null) {
-        inferrer.augmentInferredType(node, type);
-      }
-    }
-    return super.handleLocalGet(node, local);
-  }
-}
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart b/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
index bfd3360..b1cf504 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
@@ -12,6 +12,8 @@
 import '../constants/constant_system.dart';
 import '../constants/expressions.dart';
 import '../dart_types.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import '../diagnostics/spannable.dart' show
     Spannable;
 import '../elements/elements.dart';
@@ -749,6 +751,8 @@
     locals = new LocalsHandler<T>(inferrer, types, compiler, node, fieldScope);
   }
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   @override
   SemanticSendVisitor get sendVisitor => this;
 
@@ -1463,7 +1467,7 @@
   }
 
   internalError(Spannable node, String reason) {
-    compiler.internalError(node, reason);
+    reporter.internalError(node, reason);
   }
 
   T visitSwitchStatement(SwitchStatement node) {
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
index 1bcb5d5..d1f9253 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
@@ -21,6 +21,8 @@
     FunctionType,
     InterfaceType,
     TypeKind;
+import '../diagnostics/diagnostic_listener.dart' show
+  DiagnosticReporter;
 import '../diagnostics/invariant.dart' show
     invariant;
 import '../diagnostics/spannable.dart' show
@@ -588,6 +590,7 @@
 
   JavaScriptBackend get backend => compiler.backend;
   Annotations get annotations => backend.annotations;
+  DiagnosticReporter get reporter => compiler.reporter;
 
   /**
    * A set of selector names that [List] implements, that we know return
@@ -668,15 +671,16 @@
       compiler.progress.reset();
     }
     sortResolvedElements().forEach((Element element) {
+      assert(compiler.enqueuer.resolution.hasBeenProcessed(element));
       if (compiler.shouldPrintProgress) {
-        compiler.log('Added $addedInGraph elements in inferencing graph.');
+        reporter.log('Added $addedInGraph elements in inferencing graph.');
         compiler.progress.reset();
       }
       // This also forces the creation of the [ElementTypeInformation] to ensure
       // it is in the graph.
       types.withMember(element, () => analyze(element, null));
     });
-    compiler.log('Added $addedInGraph elements in inferencing graph.');
+    reporter.log('Added $addedInGraph elements in inferencing graph.');
 
     buildWorkQueue();
     refine();
@@ -820,7 +824,7 @@
       });
     }
 
-    compiler.log('Inferred $overallRefineCount types.');
+    reporter.log('Inferred $overallRefineCount types.');
 
     processLoopInformation();
   }
@@ -833,7 +837,7 @@
     SimpleTypeInferrerVisitor visitor =
         new SimpleTypeInferrerVisitor(element, compiler, this);
     TypeInformation type;
-    compiler.withCurrentElement(element, () {
+    reporter.withCurrentElement(element, () {
       type = visitor.run();
     });
     addedInGraph++;
@@ -913,7 +917,7 @@
   void refine() {
     while (!workQueue.isEmpty) {
       if (compiler.shouldPrintProgress) {
-        compiler.log('Inferred $overallRefineCount types.');
+        reporter.log('Inferred $overallRefineCount types.');
         compiler.progress.reset();
       }
       TypeInformation info = workQueue.remove();
@@ -1217,10 +1221,10 @@
   Iterable<Element> sortResolvedElements() {
     int max = 0;
     Map<int, Setlet<Element>> methodSizes = new Map<int, Setlet<Element>>();
-    compiler.enqueuer.resolution.resolvedElements.forEach((AstElement element) {
+    compiler.enqueuer.resolution.processedElements.forEach((AstElement element) {
         // TODO(ngeoffray): Not sure why the resolver would put a null
         // mapping.
-        if (!compiler.enqueuer.resolution.hasBeenResolved(element)) return;
+        if (!compiler.enqueuer.resolution.hasBeenProcessed(element)) return;
         TreeElementMapping mapping = element.resolvedAst.elements;
         element = element.implementation;
         if (element.impliesType) return;
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index df00807..c1d51cc 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -928,10 +928,11 @@
         return containerTypeMask.elementType;
       } else if (inferrer.returnsMapValueType(selector, typeMask)) {
         if (typeMask.isDictionary &&
-            arguments.positional[0].type.isValue) {
+            arguments.positional[0].type.isValue &&
+            arguments.positional[0].type.value.isString) {
           DictionaryTypeMask dictionaryTypeMask = typeMask;
           ValueTypeMask arg = arguments.positional[0].type;
-          String key = arg.value;
+          String key = arg.value.primitiveValue.slowToString();
           if (dictionaryTypeMask.typeMap.containsKey(key)) {
             if (_VERBOSE) {
               print("Dictionary lookup for $key yields "
@@ -1116,7 +1117,7 @@
   final ast.DartString value;
 
   StringLiteralTypeInformation(value, TypeMask mask)
-      : super(new ValueTypeMask(mask, value.slowToString())),
+      : super(new ValueTypeMask(mask, new StringConstantValue(value))),
         this.value = value;
 
   String asString() => value.slowToString();
@@ -1131,7 +1132,8 @@
   final ast.LiteralBool value;
 
   BoolLiteralTypeInformation(value, TypeMask mask)
-      : super(new ValueTypeMask(mask, value.value)),
+      : super(new ValueTypeMask(mask,
+            value.value ? new TrueConstantValue() : new FalseConstantValue())),
         this.value = value;
 
   String toString() => 'Type $type value ${value.value}';
diff --git a/pkg/compiler/lib/src/info/analysis_result.dart b/pkg/compiler/lib/src/info/analysis_result.dart
new file mode 100644
index 0000000..5266a01
--- /dev/null
+++ b/pkg/compiler/lib/src/info/analysis_result.dart
@@ -0,0 +1,73 @@
+// 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.
+
+/// API to get results from a static analysis of the source program.
+library compiler.src.stats.analysis_result;
+
+import '../tree/tree.dart' show Node;
+import '../universe/selector.dart' show Selector;
+
+/// A three-value logic bool (yes, no, maybe). We say that `yes` and `maybe` are
+/// "truthy", while `no` and `maybe` are "falsy".
+// TODO(sigmund): is it worth using an enum? or switch to true/false/null?
+enum Boolish { yes, no, maybe }
+
+/// Specifies results of some kind of static analysis on a source program.
+abstract class AnalysisResult {
+  /// Information computed about a specific [receiver].
+  ReceiverInfo infoForReceiver(Node receiver);
+
+  /// Information computed about a specific [selector] applied to a specific
+  /// [receiver].
+  SelectorInfo infoForSelector(Node receiver, Selector selector);
+}
+
+/// Analysis information about a receiver of a send.
+abstract class ReceiverInfo {
+  /// Receiver node for which this information is computed.
+  Node get receiver;
+
+  /// Return whether [receiver] resolves to a value that implements no such
+  /// method. The answer is `yes` if all values that [receiver] could evaluate
+  /// to at runtime contain it, or `no` if none of them does. Maybe if it
+  /// depends on some context or we can't determine this information precisely.
+  Boolish get hasNoSuchMethod;
+
+  /// When [hasNoSuchMethod] is yes, the precise number of possible noSuchMethod
+  /// handlers for this receiver.
+  int get possibleNsmTargets;
+
+  /// Return whether [receiver] may ever be null.
+  Boolish get isNull;
+}
+
+/// Information about a specific selector applied to a specific receiver.
+abstract class SelectorInfo {
+  /// Receiver node of the [selector].
+  Node get receiver;
+
+  /// Specific selector on [receiver] for which this information is computed.
+  Selector get selector;
+
+  /// Whether a member matching [selector] exists in [receiver].
+  Boolish get exists;
+
+  /// Whether [receiver] needs an interceptor to implement [selector].
+  Boolish get usesInterceptor;
+
+  /// Possible total number of methods that could be the target of the selector.
+  /// This needs to be combined with [isAccurate] to correctly understand the
+  /// value. Some invariants:
+  ///
+  ///   * If [exists] is `no`, the value here should be 0, regardless of
+  ///   accuracy.
+  ///   * If [exists] is `yes`, the value is always considered 1 or more.
+  ///     If [isAccurate] is false, we treat it as there may be many possible
+  ///     targets.
+  ///   * If [exists] is `maybe`, the value is considered 0 or more.
+  int get possibleTargets;
+
+  /// Whether the information about [possibleTargets] is accurate.
+  bool get isAccurate;
+}
diff --git a/pkg/compiler/lib/src/info/naive_analysis_result.dart b/pkg/compiler/lib/src/info/naive_analysis_result.dart
new file mode 100644
index 0000000..0061be4
--- /dev/null
+++ b/pkg/compiler/lib/src/info/naive_analysis_result.dart
@@ -0,0 +1,44 @@
+// 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.
+
+/// API to get results from a static analysis of the source program.
+// TODO(sigmund): split out implementations out of this file.
+library compiler.src.stats.naive_analysis_result;
+
+import 'analysis_result.dart';
+import '../tree/tree.dart' show Node;
+import '../universe/selector.dart' show Selector;
+
+/// A naive [AnalysisResult] that tells us very little. This is the most
+/// conservative we can be when we only use information from the AST structure
+/// and from resolution, but no type information.
+class NaiveAnalysisResult implements AnalysisResult {
+  NaiveAnalysisResult();
+
+  ReceiverInfo infoForReceiver(Node receiver) =>
+    new NaiveReceiverInfo(receiver);
+  SelectorInfo infoForSelector(Node receiver, Selector selector) =>
+    new NaiveSelectorInfo(receiver, selector);
+}
+
+class NaiveReceiverInfo implements ReceiverInfo {
+  final Node receiver;
+
+  NaiveReceiverInfo(this.receiver);
+  Boolish get hasNoSuchMethod => Boolish.maybe;
+  Boolish get isNull => Boolish.maybe;
+  int get possibleNsmTargets => -1;
+}
+
+class NaiveSelectorInfo implements SelectorInfo {
+  final Node receiver;
+  final Selector selector;
+
+  NaiveSelectorInfo(this.receiver, this.selector);
+
+  Boolish get exists => Boolish.maybe;
+  Boolish get usesInterceptor => Boolish.maybe;
+  int get possibleTargets => -1;
+  bool get isAccurate => false;
+}
diff --git a/pkg/compiler/lib/src/info/send_info.dart b/pkg/compiler/lib/src/info/send_info.dart
new file mode 100644
index 0000000..0299142
--- /dev/null
+++ b/pkg/compiler/lib/src/info/send_info.dart
@@ -0,0 +1,2383 @@
+// 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.
+
+/// Computes measurements about sends in a function.
+library compiler.src.info.send_info;
+
+import 'dart:convert';
+import 'package:dart2js_info/src/measurements.dart';
+import 'package:dart2js_info/src/util.dart' show recursiveDiagnosticString;
+
+import '../diagnostics/diagnostic_listener.dart' show DiagnosticReporter;
+import '../diagnostics/messages.dart' show MessageKind;
+import '../compiler.dart' show Compiler;
+import '../common/tasks.dart' show CompilerTask;
+import '../dart_types.dart';
+import '../closure.dart';
+import '../elements/elements.dart';
+import '../elements/visitor.dart' show ElementVisitor;
+import '../resolution/operators.dart';
+import '../resolution/semantic_visitor.dart';
+import '../resolution/send_resolver.dart';
+import '../resolution/tree_elements.dart';
+import '../constants/expressions.dart';
+import '../parser/partial_elements.dart' show PartialElement;
+import '../tree/tree.dart';
+import '../universe/selector.dart' show Selector;
+import '../universe/call_structure.dart' show CallStructure;
+
+import 'analysis_result.dart';
+import 'naive_analysis_result.dart';
+import 'trusted_types_analysis_result.dart';
+
+/// Collects a set of [Measurements] about send expressions in the function [f].
+// TODO(sigmund): collect information on initializers too.
+Measurements collectSendMeasurements(FunctionElement f,
+                                     Compiler compiler) {
+  DiagnosticReporter reporter = compiler.reporter;
+  return reporter.withCurrentElement(f, () {
+    // TODO(sigmund): enable for platform too.
+    if (f.library.isPlatformLibrary) return null;
+    var name = _qualifiedName(f);
+    if (!f.hasNode) {
+      if (f is PartialElement) return const Measurements.unreachableFunction();
+      assert (f is ConstructorElement && f.isSynthesized);
+      // TODO(sigmund): measure synthethic forwarding sends, measure
+      // initializers
+      return new Measurements.reachableFunction();
+    }
+    if (!f.hasResolvedAst) {
+      _debug('no resolved ast ${f.runtimeType}');
+      return null;
+    }
+    var resolvedAst = f.resolvedAst;
+    if (resolvedAst.node == null) {
+      _debug('no node ${f.runtimeType}');
+      return null;
+    }
+    var def = resolvedAst.elements.getFunctionDefinition(resolvedAst.node);
+    if (def == null) {
+      assert (f is PartialElement);
+      return const Measurements.unreachableFunction();
+    }
+
+    var visitor = new _StatsTraversalVisitor(
+        compiler, resolvedAst.elements,
+        reporter.spanFromSpannable(resolvedAst.node).uri);
+    resolvedAst.node.accept(visitor);
+    return visitor.measurements;
+  });
+}
+
+_qualifiedName(FunctionElement f) {
+  var cls = f.enclosingClass;
+  return (cls != null) ? '${cls.name}.${f.name}' : f.name;
+}
+
+/// Visitor that categorizes data about an individual send.
+class _StatsVisitor<T> extends Visitor
+    with SendResolverMixin, SemanticSendResolvedMixin<dynamic, T>
+    implements SemanticSendVisitor<dynamic, T> {
+
+  // TODO(sigmund): consider passing in several AnalysisResults at once, so we
+  // can compute the different metrics together.
+  /// Information we know about the program from static analysis.
+  final AnalysisResult info;
+
+  /// Results from this function.
+  final Measurements measurements;
+
+  final DiagnosticReporter reporter;
+  final TreeElements elements;
+
+  SemanticSendVisitor<dynamic, T> get sendVisitor => this;
+
+  _StatsVisitor(this.reporter, this.elements, this.info, Uri sourceUri)
+      : measurements = new Measurements.reachableFunction(sourceUri);
+
+  visitNode(Node node) => throw "unhandled ${node.runtimeType}: $node";
+  apply(Node node, T arg) => throw "missing apply ${node.runtimeType}: $node";
+  internalError(Node node, String arg) => throw "internal error on $node";
+
+  visitSend(Send node) {
+    _checkInvariant(node, 'before');
+    var span = reporter.spanFromSpannable(node);
+    measurements.record(Metric.send, span.begin, span.end);
+    if (node is SendSet) {
+      if ((node.assignmentOperator != null &&
+                node.assignmentOperator.source != '=') ||
+            node.isPrefix ||
+            node.isPostfix) {
+        assert(!node.isIfNullAssignment);
+        // We count get and set separately in case one of them is defined by the
+        // other could be a nSM error.
+        measurements.record(Metric.send, span.begin, span.end);
+        measurements.record(Metric.send, span.begin, span.end);
+      } else if (node.isIfNullAssignment) {
+        measurements.record(Metric.send, span.begin, span.end);
+      }
+    }
+    super.visitSend(node);
+    _checkInvariant(node, 'after ');
+  }
+
+  visitNewExpression(NewExpression node) {
+    _checkInvariant(node, 'before');
+    var span = reporter.spanFromSpannable(node);
+    measurements.record(Metric.send, span.begin, span.end);
+    super.visitNewExpression(node);
+    _checkInvariant(node, 'after ');
+  }
+
+  /// A monomorphic local variable read.
+  ///
+  /// See [Metric.send] for a full categorization of sends.
+  handleLocal(Node node) {
+    var span = reporter.spanFromSpannable(node);
+    measurements.record(Metric.monomorphicSend, span.begin, span.end);
+    measurements.record(Metric.localSend, span.begin, span.end);
+  }
+
+  /// A monomorphic virual call on [node], where we know which function is the
+  /// target of the call (for example, because only one type in a class
+  /// hierarchy implements a function with a given name).
+  ///
+  /// See [Metric.send] for a full categorization of sends.
+  handleSingleInstance(Node node) {
+    var span = reporter.spanFromSpannable(node);
+    measurements.record(Metric.monomorphicSend, span.begin, span.end);
+    measurements.record(Metric.instanceSend, span.begin, span.end);
+  }
+
+  /// A monomorphic call that goes through an interceptor. This is equivalent in
+  /// terms of what the compiler knows as we do with [handleSignleInstance], and
+  /// because we know the target of the call, we also know that it doesn't live
+  /// in the object instance, but on an interceptor on the side.
+  ///
+  /// See [Metric.send] for a full categorization of sends.
+  handleSingleInterceptor(Node node) {
+    var span = reporter.spanFromSpannable(node);
+    measurements.record(Metric.monomorphicSend, span.begin, span.end);
+    measurements.record(Metric.interceptorSend, span.begin, span.end);
+  }
+
+  /// A polymorphic call that goes through an interceptor.
+  ///
+  /// See [Metric.send] for a full categorization of sends.
+  handleMultiInterceptor(Node node) {
+    var span = reporter.spanFromSpannable(node);
+    measurements.record(Metric.polymorphicSend, span.begin, span.end);
+    measurements.record(Metric.multiInterceptorSend, span.begin, span.end);
+  }
+
+  handleConstructor(Node node) {
+    var span = reporter.spanFromSpannable(node);
+    measurements.record(Metric.monomorphicSend, span.begin, span.end);
+    measurements.record(Metric.constructorSend, span.begin, span.end);
+  }
+
+  handleDynamic(Node node) {
+    var span = reporter.spanFromSpannable(node);
+    measurements.record(Metric.polymorphicSend, span.begin, span.end);
+    measurements.record(Metric.dynamicSend, span.begin, span.end);
+  }
+
+  handleVirtual(Node node) {
+    var span = reporter.spanFromSpannable(node);
+    measurements.record(Metric.polymorphicSend, span.begin, span.end);
+    measurements.record(Metric.virtualSend, span.begin, span.end);
+  }
+
+  handleNSMError(Node node) {
+    var span = reporter.spanFromSpannable(node);
+    measurements.record(Metric.monomorphicSend, span.begin, span.end);
+    measurements.record(Metric.nsmErrorSend, span.begin, span.end);
+  }
+
+  handleNSMSingle(Node node) {
+    var span = reporter.spanFromSpannable(node);
+    measurements.record(Metric.monomorphicSend, span.begin, span.end);
+    measurements.record(Metric.singleNsmCallSend, span.begin, span.end);
+  }
+
+  handleNSMSuper(Node node, ClassElement type) {
+    var superclass = type.superclass;
+    var member = superclass.lookupMember('noSuchMethod');
+    if (!member.enclosingClass.isObject) {
+      handleNSMSingle(node);
+    } else {
+      handleNSMError(node);
+    }
+  }
+
+  handleNSMAny(Node node) {
+    var span = reporter.spanFromSpannable(node);
+    measurements.record(Metric.polymorphicSend, span.begin, span.end);
+    measurements.record(Metric.multiNsmCallSend, span.begin, span.end);
+  }
+
+  handleSuper(Node node) {
+    var span = reporter.spanFromSpannable(node);
+    measurements.record(Metric.monomorphicSend, span.begin, span.end);
+    measurements.record(Metric.superSend, span.begin, span.end);
+  }
+  handleTypeVariable(Node node) {
+    var span = reporter.spanFromSpannable(node);
+    measurements.record(Metric.monomorphicSend, span.begin, span.end);
+    measurements.record(Metric.typeVariableSend, span.begin, span.end);
+  }
+  handleStatic(Node node) {
+    var span = reporter.spanFromSpannable(node);
+    measurements.record(Metric.monomorphicSend, span.begin, span.end);
+    measurements.record(Metric.staticSend, span.begin, span.end);
+  }
+
+  handleNoSend(Node node) {
+    measurements.popLast(Metric.send);
+  }
+
+  void handleDynamicProperty(Node node, Node receiver, Selector selector) {
+    // staticSend: no (automatically)
+    // superSend: no (automatically)
+    // localSend: no (automatically)
+    // constructorSend: no (automatically)
+    // typeVariableSend: no (automatically)
+
+    // nsmErrorSend:      receiver has no `selector` nor nSM.
+    // singleNsmCallSend: receiver has no `selector`, but definitely has `nSM`
+    // instanceSend:      receiver has `selector`, no need to use an interceptor
+    // interceptorSend:   receiver has `selector`, but we know we need an
+    //                    interceptor to get it
+
+    // multiNsmCallSend:  receiver has no `selector`, not sure if receiver has
+    //                    nSM, or not sure which nSM is called (does this one
+    //                    matter, or does nSM is treated like an instance method
+    //                    call)?
+    // virtualSend:       receiver has `selector`, we know we do not need an
+    //                    interceptor, not sure which specific type implements
+    //                    the selector.
+    // multiInterceptorSend: multiple possible receiver types, all using an
+    //                       interceptor to get the `selector`, might be
+    //                       possbile to pick a special selector logic for this
+    //                       combination?
+    // dynamicSend: any combination of the above.
+
+    ReceiverInfo receiverInfo = info.infoForReceiver(receiver);
+    SelectorInfo selectorInfo = info.infoForSelector(receiver, selector);
+    Boolish hasSelector = selectorInfo.exists;
+    Boolish hasNsm = receiverInfo.hasNoSuchMethod;
+
+    if (hasSelector == Boolish.no) {
+      if (hasNsm == Boolish.no) {
+        handleNSMError(node);
+      } else if (hasNsm == Boolish.yes) {
+        if (receiverInfo.possibleNsmTargets == 1) {
+          handleNSMSingle(node);
+        } else {
+          handleNSMAny(node);
+        }
+      } else {
+        handleDynamic(node);
+      }
+      return;
+    }
+
+    Boolish usesInterceptor = selectorInfo.usesInterceptor;
+    if (hasSelector == Boolish.yes) {
+      if (selectorInfo.isAccurate && selectorInfo.possibleTargets == 1) {
+        assert (usesInterceptor != Boolish.maybe);
+        if (usesInterceptor == Boolish.yes) {
+          handleSingleInterceptor(node);
+        } else {
+          handleSingleInstance(node);
+        }
+      } else {
+        if (usesInterceptor == Boolish.no) {
+          handleVirtual(node);
+        } else if (usesInterceptor == Boolish.yes) {
+          handleMultiInterceptor(node);
+        } else {
+          handleDynamic(node);
+        }
+      }
+      return;
+    }
+    handleDynamic(node);
+  }
+
+  void handleThisProperty(Send node, Selector selector) {
+    handleDynamicProperty(node, node.receiver, selector);
+  }
+
+  void handleIndex(Node node) {
+    handleDynamic(node);
+  }
+
+  void handleOperator(Node node) {
+    handleDynamic(node);
+  }
+
+  void handleInvoke(Node node) {
+    handleDynamic(node);
+  }
+
+  void handleEquals(Node node) {
+    handleDynamic(node);
+  }
+
+  // Constructors
+
+  void visitAbstractClassConstructorInvoke(NewExpression node,
+      ConstructorElement element, InterfaceType type, NodeList arguments,
+      CallStructure callStructure, T arg) {
+    handleConstructor(node);
+  }
+
+  void visitBoolFromEnvironmentConstructorInvoke(NewExpression node,
+      BoolFromEnvironmentConstantExpression constant, T arg) {
+    handleConstructor(node);
+  }
+
+  void visitConstConstructorInvoke(
+      NewExpression node, ConstructedConstantExpression constant, T arg) {
+    handleConstructor(node);
+  }
+
+  void visitGenerativeConstructorInvoke(NewExpression node,
+      ConstructorElement constructor, InterfaceType type, NodeList arguments,
+      CallStructure callStructure, T arg) {
+    handleConstructor(node);
+  }
+
+  void visitIntFromEnvironmentConstructorInvoke(NewExpression node,
+      IntFromEnvironmentConstantExpression constant, T arg) {
+    handleConstructor(node);
+  }
+
+  void visitRedirectingFactoryConstructorInvoke(NewExpression node,
+      ConstructorElement constructor, InterfaceType type,
+      ConstructorElement effectiveTarget, InterfaceType effectiveTargetType,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleConstructor(node);
+  }
+
+  void visitRedirectingGenerativeConstructorInvoke(NewExpression node,
+      ConstructorElement constructor, InterfaceType type, NodeList arguments,
+      CallStructure callStructure, T arg) {
+    handleConstructor(node);
+  }
+
+  void visitStringFromEnvironmentConstructorInvoke(NewExpression node,
+      StringFromEnvironmentConstantExpression constant, T arg) {
+    handleConstructor(node);
+  }
+
+  // Dynamic sends
+
+
+  // TODO(sigmund): many many things to add:
+  // -- support for operators, indexers, etc.
+  // -- logic about nullables
+  // -- int, JSArray
+  // -- all interceptors
+
+  void visitBinary(
+      Send node, Node left, BinaryOperator operator, Node right, T arg) {
+    handleOperator(node);
+  }
+
+  void visitCompoundIndexSet(SendSet node, Node receiver, Node index,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleIndex(node); // t1 = receiver[index]
+    handleOperator(node); // t2 = t1 op rhs
+    handleIndex(node); // receiver[index] = t2
+  }
+
+  void visitDynamicPropertyCompound(Send node, Node receiver,
+      Name name, AssignmentOperator operator, Node rhs, T arg) {
+    handleDynamicProperty(node, receiver, new Selector.getter(name));
+    handleOperator(node);
+    handleDynamicProperty(node, receiver, new Selector.setter(name));
+  }
+
+
+  void visitDynamicPropertyGet(
+      Send node, Node receiver, Name name, T arg) {
+    handleDynamicProperty(node, receiver, new Selector.getter(name));
+  }
+
+  void visitDynamicPropertyInvoke(
+      Send node, Node receiver, NodeList arguments, Selector selector, T arg) {
+    handleDynamicProperty(node, receiver, selector);
+  }
+
+  void visitDynamicPropertyPostfix(Send node, Node receiver,
+       Name name, IncDecOperator operator, T arg) {
+    handleDynamicProperty(node, receiver, new Selector.getter(name));
+    handleOperator(node);
+    handleDynamicProperty(node, receiver, new Selector.setter(name));
+  }
+
+  void visitDynamicPropertyPrefix(Send node, Node receiver, Name name,
+      IncDecOperator operator, T arg) {
+    handleDynamicProperty(node, receiver, new Selector.getter(name));
+    handleOperator(node);
+    handleDynamicProperty(node, receiver, new Selector.setter(name));
+  }
+
+  void visitDynamicPropertySet(
+      SendSet node, Node receiver, Name name, Node rhs, T arg) {
+    handleDynamicProperty(node, receiver, new Selector.setter(name));
+  }
+
+  void visitDynamicPropertySetIfNull(
+      Send node, Node receiver, Name name, Node rhs, T arg) {
+    // read to check for null?
+    handleDynamicProperty(node, receiver, new Selector.getter(name));
+    handleDynamicProperty(node, receiver, new Selector.setter(name));
+  }
+
+  void visitEquals(Send node, Node left, Node right, T arg) {
+    handleEquals(node);
+  }
+
+  void visitExpressionInvoke(Send node, Node expression, NodeList arguments,
+      CallStructure callStructure, T arg) {
+    handleInvoke(node);
+  }
+
+  void visitIfNotNullDynamicPropertyCompound(Send node, Node receiver,
+      Name name, AssignmentOperator operator, Node rhs, T arg) {
+    handleDynamicProperty(node, receiver, new Selector.getter(name));
+    handleOperator(node);
+    handleDynamicProperty(node, receiver, new Selector.setter(name));
+  }
+
+  void visitIfNotNullDynamicPropertyGet(
+      Send node, Node receiver, Name name, T arg) {
+    handleDynamicProperty(node, receiver, new Selector.getter(name));
+  }
+
+  void visitIfNotNullDynamicPropertyInvoke(
+      Send node, Node receiver, NodeList arguments, Selector selector, T arg) {
+    handleDynamicProperty(node, receiver, selector);
+  }
+
+  void visitIfNotNullDynamicPropertyPostfix(Send node, Node receiver, Name name,
+      IncDecOperator operator, T arg) {
+    handleDynamicProperty(node, receiver, new Selector.getter(name));
+    handleOperator(node);
+    handleDynamicProperty(node, receiver, new Selector.setter(name));
+  }
+
+  void visitIfNotNullDynamicPropertyPrefix(Send node, Node receiver, Name name,
+      IncDecOperator operator, T arg) {
+    handleDynamicProperty(node, receiver, new Selector.getter(name));
+    handleOperator(node);
+    handleDynamicProperty(node, receiver, new Selector.setter(name));
+  }
+
+  void visitIfNotNullDynamicPropertySet(
+      SendSet node, Node receiver, Name name, Node rhs, T arg) {
+    handleDynamicProperty(node, receiver, new Selector.setter(name));
+  }
+
+  void visitIfNotNullDynamicPropertySetIfNull(
+      Send node, Node receiver, Name name, Node rhs, T arg) {
+    handleDynamicProperty(node, receiver, new Selector.getter(name));
+    handleDynamicProperty(node, receiver, new Selector.setter(name));
+  }
+
+  void visitIndex(Send node, Node receiver, Node index, T arg) {
+    handleIndex(node);
+  }
+
+  void visitIndexPostfix(
+      Send node, Node receiver, Node index, IncDecOperator operator, T arg) {
+    handleIndex(node);
+    handleOperator(node);
+    handleIndex(node);
+  }
+
+  void visitIndexPrefix(
+      Send node, Node receiver, Node index, IncDecOperator operator, T arg) {
+    handleIndex(node);
+    handleOperator(node);
+    handleIndex(node);
+  }
+
+  void visitIndexSet(SendSet node, Node receiver, Node index, Node rhs, T arg) {
+    handleIndex(node);
+  }
+
+  void visitLocalVariableCompound(Send node, LocalVariableElement variable,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleLocal(node);
+    handleOperator(node);
+    handleLocal(node);
+  }
+
+  void visitLocalVariableInvoke(Send node, LocalVariableElement variable,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleInvoke(node);
+  }
+
+  void visitLocalVariablePostfix(Send node, LocalVariableElement variable,
+      IncDecOperator operator, T arg) {
+    handleLocal(node);
+    handleOperator(node);
+    handleLocal(node);
+  }
+
+  void visitLocalVariablePrefix(Send node, LocalVariableElement variable,
+      IncDecOperator operator, T arg) {
+    handleLocal(node);
+    handleOperator(node);
+    handleLocal(node);
+  }
+
+  void visitNotEquals(Send node, Node left, Node right, T arg) {
+    handleEquals(node);
+  }
+
+  void visitParameterCompound(Send node, ParameterElement parameter,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleLocal(node);
+    handleOperator(node);
+    handleLocal(node);
+  }
+
+  void visitParameterInvoke(Send node, ParameterElement parameter,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleInvoke(node);
+  }
+
+  void visitParameterPostfix(
+      Send node, ParameterElement parameter, IncDecOperator operator, T arg) {
+    handleLocal(node);
+    handleOperator(node);
+    handleLocal(node);
+  }
+
+  void visitParameterPrefix(
+      Send node, ParameterElement parameter, IncDecOperator operator, T arg) {
+    handleLocal(node);
+    handleOperator(node);
+    handleLocal(node);
+  }
+
+  void visitStaticFieldCompound(Send node, FieldElement field,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleStatic(node);
+    handleOperator(node);
+    handleStatic(node);
+  }
+
+  void visitStaticFieldInvoke(Send node, FieldElement field, NodeList arguments,
+      CallStructure callStructure, T arg) {
+    handleInvoke(node);
+  }
+
+  void visitStaticFieldPostfix(
+      Send node, FieldElement field, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleOperator(node);
+    handleStatic(node);
+  }
+
+  void visitStaticFieldPrefix(
+      Send node, FieldElement field, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleOperator(node);
+    handleStatic(node);
+  }
+
+  void visitStaticGetterInvoke(Send node, FunctionElement getter,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleInvoke(node);
+  }
+
+  void visitStaticGetterSetterCompound(Send node, FunctionElement getter,
+      FunctionElement setter, AssignmentOperator operator, Node rhs, T arg) {
+    handleStatic(node);
+    handleOperator(node);
+    handleStatic(node);
+  }
+
+  void visitStaticGetterSetterPostfix(Send node, FunctionElement getter,
+      FunctionElement setter, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleOperator(node);
+    handleStatic(node);
+  }
+
+  void visitStaticGetterSetterPrefix(Send node, FunctionElement getter,
+      FunctionElement setter, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleOperator(node);
+    handleStatic(node);
+  }
+
+  void visitSuperFieldCompound(Send node, FieldElement field,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitSuperFieldFieldCompound(Send node, FieldElement readField,
+      FieldElement writtenField, AssignmentOperator operator, Node rhs, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitSuperFieldFieldPostfix(Send node, FieldElement readField,
+      FieldElement writtenField, IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitSuperFieldFieldPrefix(Send node, FieldElement readField,
+      FieldElement writtenField, IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitSuperFieldFieldSetIfNull(
+      Send node, FieldElement readField, FieldElement writtenField, Node rhs,
+      T arg) {
+    handleSuper(node);
+    handleNSMSuper(node, readField.enclosingClass);
+  }
+
+  void visitSuperFieldInvoke(Send node, FieldElement field, NodeList arguments,
+      CallStructure callStructure, T arg) {
+    handleInvoke(node);
+  }
+
+  void visitSuperFieldPostfix(
+      Send node, FieldElement field, IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitSuperFieldPrefix(
+      Send node, FieldElement field, IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitSuperFieldSetterCompound(Send node, FieldElement field,
+      FunctionElement setter, AssignmentOperator operator, Node rhs, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitSuperFieldSetterPostfix(Send node, FieldElement field,
+      FunctionElement setter, IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitSuperFieldSetterPrefix(Send node, FieldElement field,
+      FunctionElement setter, IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitSuperFieldSetterSetIfNull(Send node, FieldElement field,
+      FunctionElement setter, Node rhs, T arg) {
+    handleSuper(node);
+    handleSuper(node);
+  }
+
+  void visitSuperGetterFieldCompound(Send node, FunctionElement getter,
+      FieldElement field, AssignmentOperator operator, Node rhs, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitSuperGetterFieldPostfix(Send node, FunctionElement getter,
+      FieldElement field, IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitSuperGetterFieldPrefix(Send node, FunctionElement getter,
+      FieldElement field, IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitSuperGetterFieldSetIfNull(Send node, FunctionElement getter,
+      FieldElement field, Node rhs, T arg) {
+    handleSuper(node);
+    handleSuper(node);
+  }
+
+  void visitSuperGetterInvoke(Send node, FunctionElement getter,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleInvoke(node);
+  }
+
+  void visitSuperGetterSetterCompound(Send node, FunctionElement getter,
+      FunctionElement setter, AssignmentOperator operator, Node rhs, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitSuperGetterSetterPostfix(Send node, FunctionElement getter,
+      FunctionElement setter, IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitSuperGetterSetterPrefix(Send node, FunctionElement getter,
+      FunctionElement setter, IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitSuperGetterSetterSetIfNull(Send node, FunctionElement getter,
+      FunctionElement setter, Node rhs, T arg) {
+    handleSuper(node);
+    handleSuper(node);
+  }
+
+  void visitSuperIndexPostfix(Send node, MethodElement indexFunction,
+      MethodElement indexSetFunction, Node index, IncDecOperator operator,
+      T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitSuperIndexPrefix(Send node, MethodElement indexFunction,
+      MethodElement indexSetFunction, Node index, IncDecOperator operator,
+      T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitSuperMethodSetterCompound(Send node, FunctionElement method,
+      FunctionElement setter, AssignmentOperator operator, Node rhs, T arg) {
+    handleSuper(node);
+    handleNSMSuper(node, method.enclosingClass);
+    handleSuper(node);
+  }
+
+  void visitSuperMethodSetterPostfix(Send node, FunctionElement method,
+      FunctionElement setter, IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleNSMSuper(node, method.enclosingClass);
+    handleSuper(node);
+  }
+
+  void visitSuperMethodSetterPrefix(Send node, FunctionElement method,
+      FunctionElement setter, IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleNSMSuper(node, method.enclosingClass);
+    handleSuper(node);
+  }
+
+  void visitSuperMethodSetterSetIfNull(Send node, FunctionElement method,
+      FunctionElement setter, Node rhs, T arg) {
+    handleSuper(node);
+    handleSuper(node);
+  }
+
+  void visitThisPropertyCompound(Send node, Name name,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleThisProperty(node, new Selector.getter(name));
+    handleOperator(node);
+    handleThisProperty(node, new Selector.setter(name));
+  }
+
+  void visitThisPropertyInvoke(
+      Send node, NodeList arguments, Selector selector, T arg) {
+    handleThisProperty(node, selector);
+  }
+
+  void visitThisPropertyPostfix(Send node, Name name, IncDecOperator operator,
+      T arg) {
+    handleThisProperty(node, new Selector.getter(name));
+    handleOperator(node);
+    handleThisProperty(node, new Selector.setter(name));
+  }
+
+  void visitThisPropertyPrefix(Send node, Name name, IncDecOperator operator,
+      T arg) {
+    handleThisProperty(node, new Selector.getter(name));
+    handleOperator(node);
+    handleThisProperty(node, new Selector.setter(name));
+  }
+
+  void visitTopLevelFieldCompound(Send node, FieldElement field,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleStatic(node);
+    handleOperator(node);
+    handleStatic(node);
+  }
+
+  void visitTopLevelFieldInvoke(Send node, FieldElement field,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleInvoke(node);
+  }
+
+  void visitTopLevelFieldPostfix(
+      Send node, FieldElement field, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleOperator(node);
+    handleStatic(node);
+  }
+
+  void visitTopLevelFieldPrefix(
+      Send node, FieldElement field, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleOperator(node);
+    handleStatic(node);
+  }
+
+  void visitTopLevelGetterInvoke(Send node, FunctionElement getter,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleInvoke(node);
+  }
+
+  void visitTopLevelGetterSetterCompound(Send node, FunctionElement getter,
+      FunctionElement setter, AssignmentOperator operator, Node rhs, T arg) {
+    handleStatic(node);
+    handleOperator(node);
+    handleStatic(node);
+  }
+
+  void visitTopLevelGetterSetterPostfix(Send node, FunctionElement getter,
+      FunctionElement setter, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleOperator(node);
+    handleStatic(node);
+  }
+
+  void visitTopLevelGetterSetterPrefix(Send node, FunctionElement getter,
+      FunctionElement setter, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleOperator(node);
+    handleStatic(node);
+  }
+
+  void visitUnary(Send node, UnaryOperator operator, Node expression, T arg) {
+    handleDynamic(node);
+  }
+
+  // Local variable sends
+
+  void visitLocalFunctionGet(Send node, LocalFunctionElement function, T arg) {
+    handleLocal(node);
+  }
+
+  void visitLocalFunctionInvoke(Send node, LocalFunctionElement function,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleLocal(node);
+  }
+
+  void visitLocalVariableGet(Send node, LocalVariableElement variable, T arg) {
+    handleLocal(node);
+  }
+
+  void visitLocalVariableSet(
+      SendSet node, LocalVariableElement variable, Node rhs, T arg) {
+    handleLocal(node);
+  }
+
+  void visitLocalVariableSetIfNull(
+      SendSet node, LocalVariableElement variable, Node rhs, T arg) {
+    handleLocal(node);
+    handleLocal(node);
+  }
+
+  void visitParameterGet(Send node, ParameterElement parameter, T arg) {
+    handleLocal(node);
+  }
+
+  void visitParameterSet(
+      SendSet node, ParameterElement parameter, Node rhs, T arg) {
+    handleLocal(node);
+  }
+
+  void visitParameterSetIfNull(
+      Send node, ParameterElement parameter, Node rhs, T arg) {
+    handleLocal(node);
+    handleLocal(node);
+  }
+
+  // Super monomorphic sends
+
+  void visitSuperBinary(Send node, FunctionElement function,
+      BinaryOperator operator, Node argument, T arg) {
+    handleSuper(node);
+  }
+
+  void visitSuperEquals(
+      Send node, FunctionElement function, Node argument, T arg) {
+    handleSuper(node);
+  }
+
+  void visitSuperFieldGet(Send node, FieldElement field, T arg) {
+    handleSuper(node);
+  }
+
+  void visitSuperFieldSet(SendSet node, FieldElement field, Node rhs, T arg) {
+    handleSuper(node);
+  }
+
+  void visitSuperFieldSetIfNull(
+      SendSet node, FieldElement field, Node rhs, T arg) {
+    handleSuper(node);
+    handleSuper(node);
+  }
+
+  void visitSuperGetterGet(Send node, FunctionElement getter, T arg) {
+    handleSuper(node);
+  }
+
+  void visitSuperGetterSet(
+      SendSet node, FunctionElement getter, Node rhs, T arg) {
+    handleSuper(node);
+  }
+
+  void visitSuperIndex(Send node, FunctionElement function, Node index, T arg) {
+    handleSuper(node);
+  }
+
+  void visitSuperIndexSet(
+      SendSet node, FunctionElement function, Node index, Node rhs, T arg) {
+    handleSuper(node);
+  }
+
+  void visitSuperMethodGet(Send node, MethodElement method, T arg) {
+    handleSuper(node);
+  }
+
+  void visitSuperMethodInvoke(Send node, MethodElement method,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleSuper(node);
+  }
+
+  void visitSuperNotEquals(
+      Send node, FunctionElement function, Node argument, T arg) {
+    handleSuper(node);
+  }
+
+  void visitSuperSetterSet(
+      SendSet node, FunctionElement setter, Node rhs, T arg) {
+    handleSuper(node);
+  }
+
+  void visitSuperUnary(
+      Send node, UnaryOperator operator, FunctionElement function, T arg) {
+    handleSuper(node);
+  }
+
+  // Statically known "no such method" sends
+
+  void visitConstructorIncompatibleInvoke(NewExpression node,
+      ConstructorElement constructor, InterfaceType type, NodeList arguments,
+      CallStructure callStructure, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitFinalLocalVariableCompound(Send node, LocalVariableElement variable,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleLocal(node);
+    handleOperator(node);
+    handleNSMError(node);
+  }
+
+  void visitFinalLocalVariablePostfix(Send node, LocalVariableElement variable,
+      IncDecOperator operator, T arg) {
+    handleLocal(node);
+    handleOperator(node);
+    handleNSMError(node);
+  }
+
+  void visitFinalLocalVariablePrefix(Send node, LocalVariableElement variable,
+      IncDecOperator operator, T arg) {
+    handleLocal(node);
+    handleOperator(node);
+    handleNSMError(node);
+  }
+
+  void visitFinalLocalVariableSet(
+      SendSet node, LocalVariableElement variable, Node rhs, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitFinalLocalVariableSetIfNull(
+      SendSet node, LocalVariableElement variable, Node rhs, T arg) {
+    handleLocal(node); // read for null
+    handleNSMError(node); // set fails
+  }
+
+  void visitFinalParameterCompound(Send node, ParameterElement parameter,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleLocal(node);
+    handleOperator(node);
+    handleNSMError(node);
+  }
+
+  void visitFinalParameterPostfix(
+      Send node, ParameterElement parameter, IncDecOperator operator, T arg) {
+    handleLocal(node);
+    handleOperator(node);
+    handleNSMError(node);
+  }
+
+  void visitFinalParameterPrefix(
+      Send node, ParameterElement parameter, IncDecOperator operator, T arg) {
+    handleLocal(node);
+    handleOperator(node);
+    handleNSMError(node);
+  }
+
+  void visitFinalParameterSet(
+      SendSet node, ParameterElement parameter, Node rhs, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitFinalParameterSetIfNull(
+      SendSet node, ParameterElement parameter, Node rhs, T arg) {
+    handleLocal(node);
+    handleNSMError(node);
+  }
+
+  void visitFinalStaticFieldCompound(Send node, FieldElement field,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleStatic(node);
+    handleOperator(node);
+    handleNSMError(node);
+  }
+
+  void visitFinalStaticFieldPostfix(
+      Send node, FieldElement field, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleOperator(node);
+    handleNSMError(node);
+  }
+
+  void visitFinalStaticFieldPrefix(
+      Send node, FieldElement field, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleOperator(node);
+    handleNSMError(node);
+  }
+
+  void visitFinalStaticFieldSet(
+      SendSet node, FieldElement field, Node rhs, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitFinalStaticFieldSetIfNull(
+      SendSet node, FieldElement field, Node rhs, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+  }
+
+  void visitFinalSuperFieldSetIfNull(Send node, FieldElement field,
+      Node rhs, T arg) {
+    handleSuper(node);
+    handleNSMSuper(node, field.enclosingClass);
+  }
+
+  void visitFinalSuperFieldCompound(Send node, FieldElement field,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleNSMSuper(node, field.enclosingClass);
+  }
+
+  void visitFinalSuperFieldPostfix(
+      Send node, FieldElement field, IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleNSMSuper(node, field.enclosingClass);
+  }
+
+  void visitFinalSuperFieldPrefix(
+      Send node, FieldElement field, IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleNSMSuper(node, field.enclosingClass);
+  }
+
+  void visitFinalSuperFieldSet(
+      SendSet node, FieldElement field, Node rhs, T arg) {
+    handleNSMSuper(node, field.enclosingClass);
+  }
+
+  void visitFinalTopLevelFieldCompound(Send node, FieldElement field,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleStatic(node);
+    handleOperator(node);
+    handleNSMError(node);
+  }
+
+  void visitFinalTopLevelFieldPostfix(
+      Send node, FieldElement field, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleOperator(node);
+    handleNSMError(node);
+  }
+
+  void visitFinalTopLevelFieldPrefix(
+      Send node, FieldElement field, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleOperator(node);
+    handleNSMError(node);
+  }
+
+  void visitFinalTopLevelFieldSet(
+      SendSet node, FieldElement field, Node rhs, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitFinalTopLevelFieldSetIfNull(
+      SendSet node, FieldElement field, Node rhs, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+  }
+
+  void visitTopLevelGetterSetterSetIfNull(Send node, FunctionElement getter,
+      FunctionElement setter, Node rhs, T arg) {
+    handleStatic(node);
+    handleStatic(node);
+  }
+
+  void visitTopLevelMethodSetterSetIfNull(Send node, FunctionElement method,
+      FunctionElement setter, Node rhs, T arg) {
+    handleStatic(node);
+    handleStatic(node);
+  }
+
+  void visitTopLevelMethodSetIfNull(Send node, FunctionElement method,
+      Node rhs, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+  }
+
+  void visitLocalFunctionIncompatibleInvoke(Send node,
+      LocalFunctionElement function, NodeList arguments,
+      CallStructure callStructure, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitLocalFunctionCompound(Send node, LocalFunctionElement function,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleLocal(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitLocalFunctionPostfix(Send node, LocalFunctionElement function,
+      IncDecOperator operator, T arg) {
+    handleLocal(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitLocalFunctionPrefix(Send node, LocalFunctionElement function,
+      IncDecOperator operator, T arg) {
+    handleLocal(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitLocalFunctionSet(
+      SendSet node, LocalFunctionElement function, Node rhs, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitLocalFunctionSetIfNull(
+      SendSet node, LocalFunctionElement function, Node rhs, T arg) {
+    handleLocal(node);
+    handleNSMError(node);
+  }
+
+  void visitStaticFunctionIncompatibleInvoke(Send node, MethodElement function,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitStaticFunctionSet(
+      Send node, MethodElement function, Node rhs, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitStaticMethodCompound(Send node, MethodElement method,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleStatic(node);
+    handleNSMError(node); // operator on a method closure yields nSM
+    handleNoSend(node); // setter is not invoked, don't count it.
+  }
+
+  void visitStaticMethodPostfix(
+      Send node, MethodElement method, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitStaticMethodPrefix(
+      Send node, MethodElement method, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitStaticMethodSetterCompound(Send node, MethodElement method,
+      MethodElement setter, AssignmentOperator operator, Node rhs, T arg) {
+    handleStatic(node);
+    handleNSMError(node); // operator on a method closure yields nSM
+    handleNoSend(node); // setter is not invoked, don't count it.
+  }
+
+  void visitStaticMethodSetterPostfix(Send node, FunctionElement getter,
+      FunctionElement setter, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitStaticMethodSetterPrefix(Send node, FunctionElement getter,
+      FunctionElement setter, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitStaticSetterGet(Send node, FunctionElement setter, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitStaticSetterInvoke(Send node, FunctionElement setter,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitSuperMethodCompound(Send node, FunctionElement method,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleSuper(node);
+
+    // An operator send on a method closure yields nSM
+    handleNSMSuper(node, method.enclosingClass);
+
+    handleNoSend(node); // setter is not invoked, don't count it.
+  }
+
+  void visitSuperMethodIncompatibleInvoke(Send node, MethodElement method,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleNSMSuper(node, method.enclosingClass);
+  }
+
+  void visitSuperMethodPostfix(
+      Send node, FunctionElement method, IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleNSMSuper(node, method.enclosingClass);
+    handleNoSend(node);
+  }
+
+  void visitSuperMethodPrefix(
+      Send node, FunctionElement method, IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleNSMSuper(node, method.enclosingClass);
+    handleNoSend(node);
+  }
+
+  void visitSuperMethodSet(Send node, MethodElement method, Node rhs, T arg) {
+    handleNSMSuper(node, method.enclosingClass);
+  }
+
+  void visitSuperMethodSetIfNull(
+      Send node, MethodElement method, Node rhs, T arg) {
+    handleNSMSuper(node, method.enclosingClass);
+  }
+
+  void visitSuperSetterGet(Send node, FunctionElement setter, T arg) {
+    handleNSMSuper(node, setter.enclosingClass);
+  }
+
+  void visitSuperSetterInvoke(Send node, FunctionElement setter,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleNSMSuper(node, setter.enclosingClass);
+  }
+
+  void visitTopLevelFunctionIncompatibleInvoke(Send node,
+      MethodElement function, NodeList arguments, CallStructure callStructure,
+      T arg) {
+    handleNSMError(node);
+  }
+
+  void visitTopLevelFunctionSet(
+      Send node, MethodElement function, Node rhs, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitTopLevelGetterSet(
+      SendSet node, FunctionElement getter, Node rhs, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitTopLevelMethodCompound(Send node, FunctionElement method,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleStatic(node);
+    handleNSMError(node); // operator on a method closure yields nSM
+    handleNoSend(node); // setter is not invoked, don't count it.
+  }
+
+  void visitTopLevelMethodPostfix(
+      Send node, MethodElement method, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitTopLevelMethodPrefix(
+      Send node, MethodElement method, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitTopLevelMethodSetterCompound(Send node, FunctionElement method,
+      FunctionElement setter, AssignmentOperator operator, Node rhs, T arg) {
+    handleStatic(node);
+    handleNSMError(node); // operator on a method closure yields nSM
+    handleNoSend(node); // setter is not invoked, don't count it.
+  }
+
+  void visitTopLevelMethodSetterPostfix(Send node, FunctionElement method,
+      FunctionElement setter, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitTopLevelMethodSetterPrefix(Send node, FunctionElement method,
+      FunctionElement setter, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitTopLevelSetterGet(Send node, FunctionElement setter, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitTopLevelSetterInvoke(Send node, FunctionElement setter,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitTypeVariableTypeLiteralCompound(Send node,
+      TypeVariableElement element, AssignmentOperator operator, Node rhs,
+      T arg) {
+    handleTypeVariable(node);
+    handleNSMError(node); // operator on a method closure yields nSM
+    handleNoSend(node); // setter is not invoked, don't count it.
+  }
+
+  void visitTypeVariableTypeLiteralGet(
+      Send node, TypeVariableElement element, T arg) {
+    handleTypeVariable(node);
+  }
+
+  void visitTypeVariableTypeLiteralInvoke(Send node,
+      TypeVariableElement element, NodeList arguments,
+      CallStructure callStructure, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitTypeVariableTypeLiteralPostfix(
+      Send node, TypeVariableElement element, IncDecOperator operator, T arg) {
+    handleTypeVariable(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitTypeVariableTypeLiteralPrefix(
+      Send node, TypeVariableElement element, IncDecOperator operator, T arg) {
+    handleTypeVariable(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitTypeVariableTypeLiteralSet(
+      SendSet node, TypeVariableElement element, Node rhs, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitTypeVariableTypeLiteralSetIfNull(
+      SendSet node, TypeVariableElement element, Node rhs, T arg) {
+    handleTypeVariable(node);
+    handleNSMError(node);
+  }
+
+  void visitTypedefTypeLiteralCompound(Send node, ConstantExpression constant,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleTypeVariable(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitTypedefTypeLiteralGet(
+      Send node, ConstantExpression constant, T arg) {
+    handleTypeVariable(node);
+  }
+
+  void visitTypedefTypeLiteralInvoke(Send node, ConstantExpression constant,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitTypedefTypeLiteralPostfix(
+      Send node, ConstantExpression constant, IncDecOperator operator, T arg) {
+    handleTypeVariable(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitTypedefTypeLiteralPrefix(
+      Send node, ConstantExpression constant, IncDecOperator operator, T arg) {
+    handleTypeVariable(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitTypedefTypeLiteralSet(
+      SendSet node, ConstantExpression constant, Node rhs, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitTypedefTypeLiteralSetIfNull(
+      SendSet node, ConstantExpression constant, Node rhs, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+  }
+
+  void visitUnresolvedClassConstructorInvoke(NewExpression node,
+      Element element, DartType type, NodeList arguments, Selector selector,
+      T arg) {
+    handleNSMError(node);
+  }
+
+  void visitUnresolvedCompound(Send node, Element element,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedConstructorInvoke(NewExpression node, Element constructor,
+      DartType type, NodeList arguments, Selector selector, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitUnresolvedGet(Send node, Element element, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitUnresolvedInvoke(Send node, Element element, NodeList arguments,
+      Selector selector, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitUnresolvedPostfix(
+      Send node, Element element, IncDecOperator operator, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedPrefix(
+      Send node, Element element, IncDecOperator operator, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedRedirectingFactoryConstructorInvoke(NewExpression node,
+      ConstructorElement constructor, InterfaceType type, NodeList arguments,
+      CallStructure callStructure, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitUnresolvedSet(Send node, Element element, Node rhs, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitUnresolvedSetIfNull(Send node, Element element, Node rhs, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedStaticGetterCompound(Send node, Element element,
+      MethodElement setter, AssignmentOperator operator, Node rhs, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedStaticGetterPostfix(Send node, Element element,
+      MethodElement setter, IncDecOperator operator, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedStaticGetterPrefix(Send node, Element element,
+      MethodElement setter, IncDecOperator operator, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedStaticGetterSetIfNull(Send node, Element element,
+      MethodElement setter, Node rhs, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedStaticSetterCompound(Send node, MethodElement getter,
+      Element element, AssignmentOperator operator, Node rhs, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedStaticSetterPostfix(Send node, MethodElement getter,
+      Element element, IncDecOperator operator, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedStaticSetterPrefix(Send node, MethodElement getter,
+      Element element, IncDecOperator operator, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedStaticSetterSetIfNull(Send node, MethodElement getter,
+      Element element, Node rhs, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedSuperBinary(Send node, Element element,
+      BinaryOperator operator, Node argument, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedSuperCompound(Send node, Element element,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+    // TODO(sigmund): we should only count the next 2 if we know that the
+    // superclass has a nSM method.
+    handleOperator(node);
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedSuperCompoundIndexSet(Send node, Element element,
+      Node index, AssignmentOperator operator, Node rhs, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+    handleNoSend(node);
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedSuperGet(Send node, Element element, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedSuperSetIfNull(
+      Send node, Element element, Node rhs, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedSuperGetterCompound(Send node, Element element,
+      MethodElement setter, AssignmentOperator operator, Node rhs, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitUnresolvedSuperGetterCompoundIndexSet(Send node, Element element,
+      MethodElement setter, Node index, AssignmentOperator operator, Node rhs,
+      T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitUnresolvedSuperGetterIndexPostfix(Send node, Element element,
+      MethodElement setter, Node index, IncDecOperator operator, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitUnresolvedSuperGetterIndexPrefix(Send node, Element element,
+      MethodElement setter, Node index, IncDecOperator operator, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitUnresolvedSuperGetterPostfix(Send node, Element element,
+      MethodElement setter, IncDecOperator operator, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitUnresolvedSuperGetterPrefix(Send node, Element element,
+      MethodElement setter, IncDecOperator operator, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitUnresolvedSuperGetterSetIfNull(Send node, Element element,
+      MethodElement setter, Node rhs, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+    handleSuper(node);
+  }
+
+  void visitUnresolvedSuperIndex(
+      Send node, Element element, Node index, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedSuperIndexPostfix(
+      Send node, Element element, Node index, IncDecOperator operator, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+    handleOperator(node);
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedSuperIndexPrefix(
+      Send node, Element element, Node index, IncDecOperator operator, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+    handleOperator(node);
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedSuperIndexSet(
+      Send node, Element element, Node index, Node rhs, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedSuperInvoke(Send node, Element element,
+      NodeList arguments, Selector selector, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedSuperPostfix(
+      Send node, Element element, IncDecOperator operator, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+    handleOperator(node);
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedSuperPrefix(
+      Send node, Element element, IncDecOperator operator, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+    handleOperator(node);
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedSuperSetterCompound(Send node, MethodElement getter,
+      Element element, AssignmentOperator operator, Node rhs, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedSuperSetterCompoundIndexSet(Send node,
+      MethodElement getter, Element element, Node index,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedSuperSetterIndexPostfix(Send node,
+      MethodElement indexFunction, Element element, Node index,
+      IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedSuperSetterIndexPrefix(Send node,
+      MethodElement indexFunction, Element element, Node index,
+      IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedSuperSetterPostfix(Send node, MethodElement getter,
+      Element element, IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedSuperSetterPrefix(Send node, MethodElement getter,
+      Element element, IncDecOperator operator, T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedSuperSetterSetIfNull(Send node, MethodElement getter,
+      Element element, Node rhs, T arg) {
+    handleSuper(node);
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedSuperUnary(
+      Send node, UnaryOperator operator, Element element, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
+  void visitUnresolvedTopLevelGetterCompound(Send node, Element element,
+      MethodElement setter, AssignmentOperator operator, Node rhs, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedTopLevelGetterPostfix(Send node, Element element,
+      MethodElement setter, IncDecOperator operator, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedTopLevelGetterPrefix(Send node, Element element,
+      MethodElement setter, IncDecOperator operator, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedTopLevelGetterSetIfNull(Send node, Element element,
+      MethodElement setter, Node rhs, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedTopLevelSetterCompound(Send node, MethodElement getter,
+      Element element, AssignmentOperator operator, Node rhs, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedTopLevelSetterPostfix(Send node, MethodElement getter,
+      Element element, IncDecOperator operator, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedTopLevelSetterPrefix(Send node, MethodElement getter,
+      Element element, IncDecOperator operator, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+  void visitUnresolvedTopLevelSetterSetIfNull(Send node, MethodElement getter,
+      Element element, Node rhs, T arg) {
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  // Static
+
+  void visitConstantGet(Send node, ConstantExpression constant, T arg) {
+    handleStatic(node);
+  }
+
+  void visitConstantInvoke(Send node, ConstantExpression constant,
+      NodeList arguments, CallStructure callStreucture, T arg) {
+    handleStatic(node);
+  }
+
+  void visitFactoryConstructorInvoke(NewExpression node,
+      ConstructorElement constructor, InterfaceType type, NodeList arguments,
+      CallStructure callStructure, T arg) {
+    handleStatic(node);
+  }
+
+  void visitStaticFieldGet(Send node, FieldElement field, T arg) {
+    handleStatic(node);
+  }
+
+  void visitStaticFieldSet(SendSet node, FieldElement field, Node rhs, T arg) {
+    handleStatic(node);
+  }
+
+  void visitStaticFieldSetIfNull(
+      SendSet node, FieldElement field, Node rhs, T arg) {
+    handleStatic(node);
+    handleStatic(node);
+  }
+
+  void visitStaticFunctionGet(Send node, MethodElement function, T arg) {
+    handleStatic(node);
+  }
+
+  void visitStaticFunctionInvoke(Send node, MethodElement function,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleStatic(node);
+  }
+
+  void visitStaticGetterGet(Send node, FunctionElement getter, T arg) {
+    handleStatic(node);
+  }
+
+  void visitStaticGetterSet(
+      SendSet node, FunctionElement getter, Node rhs, T arg) {
+    handleStatic(node);
+  }
+
+  void visitStaticSetterSet(
+      SendSet node, FunctionElement setter, Node rhs, T arg) {
+    handleStatic(node);
+  }
+
+  void visitStaticGetterSetterSetIfNull(
+      Send node,
+      FunctionElement getter,
+      FunctionElement setter,
+      Node rhs,
+      T arg) {
+    handleStatic(node);
+    handleStatic(node);
+  }
+
+  void visitStaticMethodSetterSetIfNull(
+      Send node,
+      MethodElement method,
+      MethodElement setter,
+      Node rhs,
+      T arg) {
+    handleStatic(node);
+    handleStatic(node);
+  }
+
+  void visitStaticMethodSetIfNull(
+      Send node,
+      FunctionElement method,
+      Node rhs,
+      T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+  }
+
+  void visitTopLevelFieldGet(Send node, FieldElement field, T arg) {
+    handleStatic(node);
+  }
+
+  void visitTopLevelFieldSet(
+      SendSet node, FieldElement field, Node rhs, T arg) {
+    handleStatic(node);
+  }
+
+  void visitTopLevelFieldSetIfNull(
+      SendSet node, FieldElement field, Node rhs, T arg) {
+    handleStatic(node);
+    handleStatic(node);
+  }
+
+  void visitTopLevelFunctionGet(Send node, MethodElement function, T arg) {
+    handleStatic(node);
+  }
+
+  void visitTopLevelFunctionInvoke(Send node, MethodElement function,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleStatic(node);
+  }
+
+  void visitTopLevelGetterGet(Send node, FunctionElement getter, T arg) {
+    handleStatic(node);
+  }
+
+  void visitTopLevelSetterSet(
+      SendSet node, FunctionElement setter, Node rhs, T arg) {
+    handleStatic(node);
+  }
+
+  // Virtual
+
+  void visitSuperCompoundIndexSet(SendSet node, MethodElement getter,
+      MethodElement setter, Node index, AssignmentOperator operator, Node rhs,
+      T arg) {
+    handleSuper(node);
+    handleOperator(node);
+    handleSuper(node);
+  }
+
+  void visitThisGet(Identifier node, T arg) {
+    handleLocal(node); // TODO(sigmund): should we add a metric for "this"?
+  }
+
+  void visitThisInvoke(
+      Send node, NodeList arguments, CallStructure callStructure, T arg) {
+    // TODO(sigmund): implement (treat like this.call())
+    handleDynamic(node);
+  }
+
+  void visitThisPropertyGet(Send node, Name name, T arg) {
+    handleThisProperty(node, new Selector.getter(name));
+  }
+
+  void visitThisPropertySet(SendSet node, Name name, Node rhs, T arg) {
+    handleThisProperty(node, new Selector.setter(name));
+  }
+
+  void visitThisPropertySetIfNull(Send node, Name name, Node rhs, T arg) {
+    handleThisProperty(node, new Selector.getter(name));
+    handleThisProperty(node, new Selector.setter(name));
+  }
+
+  // Not count
+
+  void errorNonConstantConstructorInvoke(NewExpression node, Element element,
+      DartType type, NodeList arguments, CallStructure callStructure, T arg) {
+    handleNoSend(node);
+  }
+
+  void errorUndefinedBinaryExpression(
+      Send node, Node left, Operator operator, Node right, T arg) {
+    handleNoSend(node);
+  }
+
+  void errorUndefinedUnaryExpression(
+      Send node, Operator operator, Node expression, T arg) {
+    handleNoSend(node);
+  }
+
+  void errorInvalidGet(
+      Send node,
+      ErroneousElement error,
+      T arg) {
+    handleNoSend(node);
+  }
+
+  void errorInvalidInvoke(
+      Send node,
+      ErroneousElement error,
+      NodeList arguments,
+      Selector selector,
+      T arg) {
+    handleNoSend(node);
+  }
+
+  void errorInvalidSet(
+      Send node,
+      ErroneousElement error,
+      Node rhs,
+      T arg) {
+    handleNoSend(node);
+  }
+
+  void errorInvalidSetIfNull(
+      Send node, ErroneousElement error, Node rhs, T arg) {
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+
+  void errorInvalidPrefix(
+      Send node,
+      ErroneousElement error,
+      IncDecOperator operator,
+      T arg) {
+    handleNoSend(node);
+  }
+
+  void errorInvalidPostfix(
+      Send node,
+      ErroneousElement error,
+      IncDecOperator operator,
+      T arg) {
+    handleNoSend(node);
+  }
+
+  void errorInvalidCompound(
+      Send node,
+      ErroneousElement error,
+      AssignmentOperator operator,
+      Node rhs,
+      T arg) {
+    handleNoSend(node);
+  }
+
+  void errorInvalidUnary(
+      Send node,
+      UnaryOperator operator,
+      ErroneousElement error,
+      T arg) {
+    handleNoSend(node);
+  }
+
+  void errorInvalidEquals(
+      Send node,
+      ErroneousElement error,
+      Node right,
+      T arg) {
+    handleNoSend(node);
+  }
+
+  void errorInvalidNotEquals(
+      Send node,
+      ErroneousElement error,
+      Node right,
+      T arg) {
+    handleNoSend(node);
+  }
+
+  void errorInvalidBinary(
+      Send node,
+      ErroneousElement error,
+      BinaryOperator operator,
+      Node right,
+      T arg) {
+    handleNoSend(node);
+  }
+
+  void errorInvalidIndex(
+      Send node,
+      ErroneousElement error,
+      Node index,
+      T arg) {
+    handleNoSend(node);
+  }
+
+  void errorInvalidIndexSet(
+      Send node,
+      ErroneousElement error,
+      Node index,
+      Node rhs,
+      T arg) {
+    handleNoSend(node);
+  }
+
+  void errorInvalidCompoundIndexSet(
+      Send node,
+      ErroneousElement error,
+      Node index,
+      AssignmentOperator operator,
+      Node rhs,
+      T arg) {
+    handleNoSend(node);
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+  void errorInvalidIndexPrefix(
+      Send node,
+      ErroneousElement error,
+      Node index,
+      IncDecOperator operator,
+      T arg) {
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+  void errorInvalidIndexPostfix(
+      Send node,
+      ErroneousElement error,
+      Node index,
+      IncDecOperator operator,
+      T arg) {
+    handleNoSend(node);
+    handleNoSend(node);
+  }
+
+  void previsitDeferredAccess(
+      Send node,
+      PrefixElement prefix,
+      T arg) {
+  }
+
+
+  void visitAs(Send node, Node expression, DartType type, T arg) {
+    handleNoSend(node);
+  }
+
+  void visitClassTypeLiteralCompound(Send node, ConstantExpression constant,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitClassTypeLiteralGet(Send node, ConstantExpression constant, T arg) {
+    handleStatic(node);
+  }
+
+  void visitClassTypeLiteralInvoke(Send node, ConstantExpression constant,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitClassTypeLiteralPostfix(
+      Send node, ConstantExpression constant, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitClassTypeLiteralPrefix(
+      Send node, ConstantExpression constant, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitClassTypeLiteralSet(
+      SendSet node, ConstantExpression constant, Node rhs, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitClassTypeLiteralSetIfNull(
+      SendSet node, ConstantExpression constant, Node rhs, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+  }
+
+  void visitDynamicTypeLiteralCompound(Send node, ConstantExpression constant,
+      AssignmentOperator operator, Node rhs, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitDynamicTypeLiteralGet(
+      Send node, ConstantExpression constant, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitDynamicTypeLiteralInvoke(Send node, ConstantExpression constant,
+      NodeList arguments, CallStructure callStructure, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitDynamicTypeLiteralPostfix(
+      Send node, ConstantExpression constant, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitDynamicTypeLiteralPrefix(
+      Send node, ConstantExpression constant, IncDecOperator operator, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+    handleNoSend(node);
+  }
+
+  void visitDynamicTypeLiteralSet(
+      SendSet node, ConstantExpression constant, Node rhs, T arg) {
+    handleNSMError(node);
+  }
+
+  void visitDynamicTypeLiteralSetIfNull(
+      SendSet node, ConstantExpression constant, Node rhs, T arg) {
+    handleStatic(node);
+    handleNSMError(node);
+  }
+
+  void visitIfNull(Send node, Node left, Node right, T arg) {
+    handleNoSend(node);
+  }
+
+  void visitIs(Send node, Node expression, DartType type, T arg) {
+    handleNoSend(node);
+  }
+
+  void visitIsNot(Send node, Node expression, DartType type, T arg) {
+    handleNoSend(node);
+  }
+
+  void visitLogicalAnd(Send node, Node left, Node right, T arg) {
+    handleNoSend(node);
+  }
+
+  void visitLogicalOr(Send node, Node left, Node right, T arg) {
+    handleNoSend(node);
+  }
+
+  void visitNot(Send node, Node expression, T arg) {
+    handleNoSend(node);
+  }
+
+  String last;
+  _checkInvariant(node, String msg) {
+    msg = '$msg ${recursiveDiagnosticString(measurements, Metric.send)}';
+    if (!measurements.checkInvariant(Metric.send) ||
+        !measurements.checkInvariant(Metric.monomorphicSend) ||
+        !measurements.checkInvariant(Metric.polymorphicSend)) {
+      reporter.reportErrorMessage(node,
+          MessageKind.GENERIC, {'text': 'bad\n-- $msg\nlast:\n-- $last\n'});
+      last = msg;
+    } else {
+      last = msg;
+    }
+  }
+}
+
+/// Visitor that collects statistics for a single function.
+class _StatsTraversalVisitor<T> extends TraversalVisitor<dynamic, T>
+    implements SemanticSendVisitor<dynamic, T> {
+  final DiagnosticReporter reporter;
+  final _StatsVisitor statsVisitor;
+  Measurements get measurements => statsVisitor.measurements;
+  _StatsTraversalVisitor(
+      Compiler compiler, TreeElements elements, Uri sourceUri)
+      : reporter = compiler.reporter,
+        statsVisitor = new _StatsVisitor(compiler.reporter, elements,
+            // TODO(sigmund): accept a list of analyses, so we can compare them
+            // together.
+            true
+            ? new TrustTypesAnalysisResult(elements, compiler.world)
+            : new NaiveAnalysisResult(),
+            sourceUri),
+        super(elements);
+
+  void visitSend(Send node) {
+    try {
+      node.accept(statsVisitor);
+    } catch (e, t) {
+      reporter.reportErrorMessage(
+          node, MessageKind.GENERIC, {'text': '$e\n$t'});
+    }
+    super.visitSend(node);
+  }
+
+  void visitNewExpression(NewExpression node) {
+    try {
+      node.accept(statsVisitor);
+    } catch (e, t) {
+      reporter.reportErrorMessage(
+          node, MessageKind.GENERIC, {'text': '$e\n$t'});
+    }
+    super.visitNewExpression(node);
+  }
+}
+
+/// Helper to visit elements recursively
+// TODO(sigmund): maybe generalize and move to elements/visitor.dart?
+abstract class RecursiveElementVisitor<R, A> extends ElementVisitor<R, A> {
+
+  @override
+  R visitWarnOnUseElement(WarnOnUseElement e, A arg) =>
+      e.wrappedElement.accept(this, arg);
+
+  R visitScopeContainerElement(ScopeContainerElement e, A arg) {
+    e.forEachLocalMember((l) => l.accept(this, arg));
+    return null;
+  }
+
+  @override
+  R visitCompilationUnitElement(CompilationUnitElement e, A arg) {
+    e.forEachLocalMember((l) => l.accept(this, arg));
+    return null;
+  }
+
+  @override
+  R visitLibraryElement(LibraryElement e, A arg) {
+    e.implementation.compilationUnits.forEach((u) => u.accept(this, arg));
+    return null;
+  }
+
+  @override
+  R visitVariableElement(VariableElement e, A arg) => null;
+
+  @override
+  R visitParameterElement(ParameterElement e, A arg) => null;
+
+  @override
+  R visitFormalElement(FormalElement e, A arg) => null;
+
+  @override
+  R visitFieldElement(FieldElement e, A arg) => null;
+
+  @override
+  R visitFieldParameterElement(InitializingFormalElement e, A arg) => null;
+
+  @override
+  R visitAbstractFieldElement(AbstractFieldElement e, A arg) => null;
+
+  @override
+  R visitFunctionElement(FunctionElement e, A arg) => null;
+
+  @override
+  R visitConstructorElement(ConstructorElement e, A arg) {
+    return visitFunctionElement(e, arg);
+  }
+
+  @override
+  R visitConstructorBodyElement(ConstructorBodyElement e, A arg) {
+    return visitFunctionElement(e.constructor, arg);
+  }
+
+  @override
+  R visitClassElement(ClassElement e, A arg) {
+    return visitScopeContainerElement(e, arg);
+  }
+
+  @override
+  R visitEnumClassElement(EnumClassElement e, A arg) {
+    return visitClassElement(e, arg);
+  }
+
+  @override
+  R visitBoxFieldElement(BoxFieldElement e, A arg) => null;
+
+  @override
+  R visitClosureClassElement(ClosureClassElement e, A arg) {
+    return visitClassElement(e, arg);
+  }
+
+  @override
+  R visitClosureFieldElement(ClosureFieldElement e, A arg) {
+    return visitVariableElement(e, arg);
+  }
+}
+
+// TODO(sigmund): get rid of debug messages.
+_debug(String message) {
+  print('debug: $message');
+}
diff --git a/pkg/compiler/lib/src/info/trusted_types_analysis_result.dart b/pkg/compiler/lib/src/info/trusted_types_analysis_result.dart
new file mode 100644
index 0000000..8de59ae
--- /dev/null
+++ b/pkg/compiler/lib/src/info/trusted_types_analysis_result.dart
@@ -0,0 +1,104 @@
+// 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.
+
+/// API to get results from a static analysis of the source program.
+// TODO(sigmund): split out implementations out of this file.
+library compiler.src.stats.trusted_types_analysis_result;
+
+import 'analysis_result.dart';
+import '../tree/tree.dart' show Node;
+import '../universe/selector.dart' show Selector;
+import '../resolution/tree_elements.dart' show TreeElements;
+import '../world.dart' show ClassWorld;
+import '../dart_types.dart' show InterfaceType;
+
+/// An [AnalysisResult] produced by using type-propagation based on
+/// trusted type annotations.
+class TrustTypesAnalysisResult implements AnalysisResult {
+  final ClassWorld world;
+  final TreeElements elements;
+
+  TrustTypesAnalysisResult(this.elements, this.world);
+
+  ReceiverInfo infoForReceiver(Node receiver) =>
+    new TrustTypesReceiverInfo(receiver, elements.typesCache[receiver], world);
+  SelectorInfo infoForSelector(Node receiver, Selector selector) =>
+    new TrustTypesSelectorInfo(
+        receiver, elements.typesCache[receiver], selector, world);
+}
+
+class _SelectorLookupResult {
+  final Boolish exists;
+  // TODO(sigmund): implement
+  final Boolish usesInterceptor = Boolish.no;
+  final int possibleTargets;
+
+  _SelectorLookupResult(this.exists, this.possibleTargets);
+
+  const _SelectorLookupResult.dontKnow()
+    : exists = Boolish.maybe, possibleTargets = -1;
+}
+
+_SelectorLookupResult _lookupSelector(
+    String selectorName, InterfaceType type, ClassWorld world) {
+  if (type == null) return const _SelectorLookupResult.dontKnow();
+  bool isNsm = selectorName == 'noSuchMethod';
+  bool notFound = false;
+  var uniqueTargets = new Set();
+  for (var cls in world.subtypesOf(type.element)) {
+    var member = cls.lookupMember(selectorName);
+    if (member != null && !member.isAbstract
+        // Don't match nsm in Object
+        && (!isNsm || !member.enclosingClass.isObject)) {
+      uniqueTargets.add(member);
+    } else {
+      notFound = true;
+    }
+  }
+  Boolish exists = uniqueTargets.length > 0
+        ? (notFound ? Boolish.maybe : Boolish.yes)
+        : Boolish.no;
+  return new _SelectorLookupResult(exists, uniqueTargets.length);
+}
+
+class TrustTypesReceiverInfo implements ReceiverInfo {
+  final Node receiver;
+  final Boolish hasNoSuchMethod;
+  final int possibleNsmTargets;
+  final Boolish isNull = Boolish.maybe;
+
+  factory TrustTypesReceiverInfo(
+      Node receiver, InterfaceType type, ClassWorld world) {
+    // TODO(sigmund): refactor, maybe just store nsm as a SelectorInfo
+    var res = _lookupSelector('noSuchMethod', type, world);
+    return new TrustTypesReceiverInfo._(receiver,
+        res.exists, res.possibleTargets);
+  }
+
+  TrustTypesReceiverInfo._(this.receiver, this.hasNoSuchMethod,
+      this.possibleNsmTargets);
+}
+
+class TrustTypesSelectorInfo implements SelectorInfo {
+  final Node receiver;
+  final Selector selector;
+
+  final Boolish exists;
+  final Boolish usesInterceptor;
+  final int possibleTargets;
+  final bool isAccurate;
+
+  factory TrustTypesSelectorInfo(Node receiver, InterfaceType type,
+      Selector selector, ClassWorld world) {
+    var res = _lookupSelector(
+        selector != null ? selector.name : null, type, world);
+    return new TrustTypesSelectorInfo._(receiver, selector, res.exists,
+        res.usesInterceptor, res.possibleTargets,
+        res.exists != Boolish.maybe);
+  }
+  TrustTypesSelectorInfo._(
+      this.receiver, this.selector, this.exists, this.usesInterceptor,
+      this.possibleTargets, this.isAccurate);
+}
+
diff --git a/pkg/compiler/lib/src/js/js.dart b/pkg/compiler/lib/src/js/js.dart
index 7618b96..a72da8f 100644
--- a/pkg/compiler/lib/src/js/js.dart
+++ b/pkg/compiler/lib/src/js/js.dart
@@ -9,6 +9,8 @@
 
 import '../compiler.dart' show
     Compiler;
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import '../diagnostics/spannable.dart' show
     NO_LOCATION_SPANNABLE;
 import '../dump_info.dart' show
@@ -40,7 +42,7 @@
           new SourceLocationsMapper(outBuffer));
   Dart2JSJavaScriptPrintingContext context =
       new Dart2JSJavaScriptPrintingContext(
-          compiler, monitor, outBuffer, sourceInformationProcessor);
+          compiler.reporter, monitor, outBuffer, sourceInformationProcessor);
   Printer printer = new Printer(options, context);
   printer.visit(node);
   sourceInformationProcessor.process(node);
@@ -48,20 +50,20 @@
 }
 
 class Dart2JSJavaScriptPrintingContext implements JavaScriptPrintingContext {
-  final Compiler compiler;
+  final DiagnosticReporter reporter;
   final DumpInfoTask monitor;
   final CodeBuffer outBuffer;
   final CodePositionListener codePositionListener;
 
   Dart2JSJavaScriptPrintingContext(
-      this.compiler,
+      this.reporter,
       this.monitor,
       this.outBuffer,
       this.codePositionListener);
 
   @override
   void error(String message) {
-    compiler.internalError(NO_LOCATION_SPANNABLE, message);
+    reporter.internalError(NO_LOCATION_SPANNABLE, message);
   }
 
   @override
diff --git a/pkg/compiler/lib/src/js/rewrite_async.dart b/pkg/compiler/lib/src/js/rewrite_async.dart
index e1e90c3..854213b 100644
--- a/pkg/compiler/lib/src/js/rewrite_async.dart
+++ b/pkg/compiler/lib/src/js/rewrite_async.dart
@@ -158,7 +158,7 @@
   js.VariableUse get self => new js.VariableUse(selfName);
   String selfName;
 
-  final DiagnosticListener diagnosticListener;
+  final DiagnosticReporter reporter;
   // For error reporting only.
   Spannable get spannable {
     return (_spannable == null) ? NO_LOCATION_SPANNABLE : _spannable;
@@ -178,11 +178,10 @@
   bool get isSyncStar => false;
   bool get isAsyncStar => false;
 
-  AsyncRewriterBase(this.diagnosticListener,
-                    spannable,
+  AsyncRewriterBase(this.reporter,
+                    this._spannable,
                     this.safeVariableName,
-                    this.bodyName)
-      : _spannable = spannable;
+                    this.bodyName);
 
   /// Initialize names used by the subClass.
   void initializeNames();
@@ -352,7 +351,7 @@
   }
 
   void unreachable(js.Node node) {
-    diagnosticListener.internalError(
+    reporter.internalError(
         spannable, "Internal error, trying to visit $node");
   }
 
@@ -1376,7 +1375,7 @@
           clauses.add(new js.Default(gotoAndBreak(labels[i])));
           hasDefault = true;
         } else {
-          diagnosticListener.internalError(
+          reporter.internalError(
               spannable, "Unknown clause type $clause");
         }
         i++;
@@ -1695,21 +1694,21 @@
 
   final js.Expression wrapBody;
 
-  AsyncRewriter(DiagnosticListener diagnosticListener,
-                spannable,
+  AsyncRewriter(DiagnosticReporter reporter,
+                Spannable spannable,
                 {this.asyncHelper,
                  this.newCompleter,
                  this.wrapBody,
                  String safeVariableName(String proposedName),
                  js.Name bodyName})
-        : super(diagnosticListener,
+        : super(reporter,
                 spannable,
                 safeVariableName,
                 bodyName);
 
   @override
   void addYield(js.DartYield node, js.Expression expression) {
-    diagnosticListener.internalError(spannable,
+    reporter.internalError(spannable,
         "Yield in non-generating async function");
   }
 
@@ -1827,7 +1826,7 @@
   /// Used by sync* functions to throw exeptions.
   final js.Expression uncaughtErrorExpression;
 
-  SyncStarRewriter(DiagnosticListener diagnosticListener,
+  SyncStarRewriter(DiagnosticReporter diagnosticListener,
                 spannable,
                 {this.endOfIteration,
                  this.newIterable,
@@ -1937,7 +1936,7 @@
 
   @override
   js.Statement awaitStatement(js.Expression value) {
-    throw diagnosticListener.internalError(spannable,
+    throw reporter.internalError(spannable,
         "Sync* functions cannot contain await statements.");
   }
 
@@ -1998,17 +1997,17 @@
 
   final js.Expression wrapBody;
 
-  AsyncStarRewriter(DiagnosticListener diagnosticListener,
-                spannable,
-                {this.asyncStarHelper,
-                 this.streamOfController,
-                 this.newController,
-                 this.yieldExpression,
-                 this.yieldStarExpression,
-                 this.wrapBody,
-                 String safeVariableName(String proposedName),
-                 js.Name bodyName})
-        : super(diagnosticListener,
+  AsyncStarRewriter(DiagnosticReporter reporter,
+                    Spannable spannable,
+                    {this.asyncStarHelper,
+                     this.streamOfController,
+                     this.newController,
+                     this.yieldExpression,
+                     this.yieldStarExpression,
+                     this.wrapBody,
+                     String safeVariableName(String proposedName),
+                     js.Name bodyName})
+        : super(reporter,
                 spannable,
                 safeVariableName,
                 bodyName);
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index ff254c9d..cbf7de4 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -652,7 +652,7 @@
         compiler, namer, generateSourceMap, useStartupEmitter);
     typeVariableHandler = new TypeVariableHandler(compiler);
     customElementsAnalysis = new CustomElementsAnalysis(this);
-    lookupMapAnalysis = new LookupMapAnalysis(this);
+    lookupMapAnalysis = new LookupMapAnalysis(this, reporter);
     noSuchMethodRegistry = new NoSuchMethodRegistry(this);
     constantCompilerTask = new JavaScriptConstantTask(compiler);
     resolutionCallbacks = new JavaScriptResolutionCallbacks(this);
@@ -665,6 +665,10 @@
 
   ConstantSystem get constantSystem => constants.constantSystem;
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
+  Resolution get resolution => compiler.resolution;
+
   /// Returns constant environment for the JavaScript interpretation of the
   /// constants.
   JavaScriptConstantCompiler get constants {
@@ -886,7 +890,7 @@
   void validateInterceptorImplementsAllObjectMethods(
       ClassElement interceptorClass) {
     if (interceptorClass == null) return;
-    interceptorClass.ensureResolved(compiler);
+    interceptorClass.ensureResolved(resolution);
     compiler.objectClass.forEachMember((_, Element member) {
       if (member.isGenerativeConstructor) return;
       Element interceptorMember = interceptorClass.lookupMember(member.name);
@@ -899,10 +903,10 @@
   void addInterceptorsForNativeClassMembers(
       ClassElement cls, Enqueuer enqueuer) {
     if (enqueuer.isResolutionQueue) {
-      cls.ensureResolved(compiler);
+      cls.ensureResolved(resolution);
       cls.forEachMember((ClassElement classElement, Element member) {
         if (member.name == Identifiers.call) {
-          compiler.reportErrorMessage(
+          reporter.reportErrorMessage(
               member,
               MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS);
           return;
@@ -932,7 +936,7 @@
     if (enqueuer.isResolutionQueue) {
       _interceptedClasses.add(jsInterceptorClass);
       _interceptedClasses.add(cls);
-      cls.ensureResolved(compiler);
+      cls.ensureResolved(resolution);
       cls.forEachMember((ClassElement classElement, Element member) {
           // All methods on [Object] are shadowed by [Interceptor].
           if (classElement == compiler.objectClass) return;
@@ -1087,7 +1091,7 @@
           if (ctor == null
               || (Name.isPrivateName(name)
                   && ctor.library != mapLiteralClass.library)) {
-            compiler.internalError(mapLiteralClass,
+            reporter.internalError(mapLiteralClass,
                                    "Map literal class $mapLiteralClass missing "
                                    "'$name' constructor"
                                    "  ${mapLiteralClass.constructors}");
@@ -1100,7 +1104,7 @@
           ClassElement implementation = cls.patch != null ? cls.patch : cls;
           Element element = implementation.lookupLocalMember(name);
           if (element == null || !element.isFunction || !element.isStatic) {
-            compiler.internalError(mapLiteralClass,
+            reporter.internalError(mapLiteralClass,
                 "Map literal class $mapLiteralClass missing "
                 "'$name' static member function");
           }
@@ -1264,7 +1268,7 @@
   }
 
   void registerBoundClosure(Enqueuer enqueuer) {
-    boundClosureClass.ensureResolved(compiler);
+    boundClosureClass.ensureResolved(resolution);
     registerInstantiatedType(
         boundClosureClass.rawType,
         enqueuer,
@@ -1273,7 +1277,7 @@
   }
 
   void registerGetOfStaticFunction(Enqueuer enqueuer) {
-    closureClass.ensureResolved(compiler);
+    closureClass.ensureResolved(resolution);
     registerInstantiatedType(
         closureClass.rawType,
         enqueuer,
@@ -1303,7 +1307,7 @@
                                  Enqueuer world,
                                  Registry registry) {
     assert(!registry.isForResolution);
-    type = type.unalias(compiler);
+    type = type.unalias(resolution);
     enqueueClass(world, compiler.boolClass, registry);
     bool inCheckedMode = compiler.enableTypeAssertions;
     // [registerIsCheck] is also called for checked mode checks, so we
@@ -1349,6 +1353,40 @@
     noSuchMethodRegistry.registerNoSuchMethod(noSuchMethod);
   }
 
+  /// Called when resolving a call to a foreign function.
+  void registerForeignCall(Send node,
+                           Element element,
+                           CallStructure callStructure,
+                           ForeignResolver resolver) {
+    native.NativeResolutionEnqueuer nativeEnqueuer =
+        compiler.enqueuer.resolution.nativeEnqueuer;
+    if (element.name == 'JS') {
+      nativeEnqueuer.registerJsCall(node, resolver);
+    } else if (element.name == 'JS_EMBEDDED_GLOBAL') {
+      nativeEnqueuer.registerJsEmbeddedGlobalCall(node, resolver);
+    } else if (element.name == 'JS_BUILTIN') {
+      nativeEnqueuer.registerJsBuiltinCall(node, resolver);
+    } else if (element.name == 'JS_INTERCEPTOR_CONSTANT') {
+      // The type constant that is an argument to JS_INTERCEPTOR_CONSTANT names
+      // a class that will be instantiated outside the program by attaching a
+      // native class dispatch record referencing the interceptor.
+      if (!node.argumentsNode.isEmpty) {
+        Node argument = node.argumentsNode.nodes.head;
+        ConstantExpression constant = resolver.getConstant(argument);
+        if (constant != null && constant.kind == ConstantExpressionKind.TYPE) {
+          TypeConstantExpression typeConstant = constant;
+          if (typeConstant.type is InterfaceType) {
+            resolver.registerInstantiatedType(typeConstant.type);
+            return;
+          }
+        }
+      }
+      reporter.reportErrorMessage(
+          node,
+          MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
+    }
+  }
+
   void enableNoSuchMethod(Enqueuer world) {
     enqueue(world, getCreateInvocationMirror(), compiler.globalDependencies);
     world.registerInvocation(
@@ -1382,7 +1420,7 @@
     }
   }
 
-  void registerRequiredType(DartType type, Element enclosingElement) {
+  void registerRequiredType(DartType type) {
     // If [argument] has type variables or is a type variable, this method
     // registers a RTI dependency between the class where the type variable is
     // defined (that is the enclosing class of the current element being
@@ -1390,7 +1428,6 @@
     // then the class of the type variable does too.
     ClassElement contextClass = Types.getClassContext(type);
     if (contextClass != null) {
-      assert(contextClass == enclosingElement.enclosingClass.declaration);
       rti.registerRtiDependency(type.element, contextClass);
     }
   }
@@ -1462,7 +1499,7 @@
     if (cls.declaration != cls.implementation) {
       helpersUsed.add(cls.implementation);
     }
-    cls.ensureResolved(compiler);
+    cls.ensureResolved(resolution);
     registerInstantiatedType(cls.rawType, enqueuer, registry);
   }
 
@@ -1535,7 +1572,7 @@
     if (totalMethodCount != preMirrorsMethodCount) {
       int mirrorCount = totalMethodCount - preMirrorsMethodCount;
       double percentage = (mirrorCount / totalMethodCount) * 100;
-      DiagnosticMessage hint = compiler.createMessage(
+      DiagnosticMessage hint = reporter.createMessage(
           compiler.mainApp, MessageKind.MIRROR_BLOAT,
           {'count': mirrorCount,
            'total': totalMethodCount,
@@ -1551,12 +1588,12 @@
               compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(library)
               ? MessageKind.MIRROR_IMPORT
               : MessageKind.MIRROR_IMPORT_NO_USAGE;
-          compiler.withCurrentElement(library, () {
-            infos.add(compiler.createMessage(import, kind));
+          reporter.withCurrentElement(library, () {
+            infos.add(reporter.createMessage(import, kind));
           });
         }
       }
-      compiler.reportHint(hint, infos);
+      reporter.reportHint(hint, infos);
     }
     return programSize;
   }
@@ -1902,19 +1939,19 @@
 
   Element getYieldStar() {
     ClassElement classElement = findAsyncHelper("_IterationMarker");
-    classElement.ensureResolved(compiler);
+    classElement.ensureResolved(resolution);
     return classElement.lookupLocalMember("yieldStar");
   }
 
   Element getYieldSingle() {
     ClassElement classElement = findAsyncHelper("_IterationMarker");
-    classElement.ensureResolved(compiler);
+    classElement.ensureResolved(resolution);
     return classElement.lookupLocalMember("yieldSingle");
   }
 
   Element getSyncStarUncaughtError() {
     ClassElement classElement = findAsyncHelper("_IterationMarker");
-    classElement.ensureResolved(compiler);
+    classElement.ensureResolved(resolution);
     return classElement.lookupLocalMember("uncaughtError");
   }
 
@@ -1928,32 +1965,32 @@
 
   Element getEndOfIteration() {
     ClassElement classElement = findAsyncHelper("_IterationMarker");
-    classElement.ensureResolved(compiler);
+    classElement.ensureResolved(resolution);
     return classElement.lookupLocalMember("endOfIteration");
   }
 
   Element getSyncStarIterable() {
     ClassElement classElement = findAsyncHelper("_SyncStarIterable");
-    classElement.ensureResolved(compiler);
+    classElement.ensureResolved(resolution);
     return classElement;
   }
 
   Element getSyncStarIterableConstructor() {
     ClassElement classElement = getSyncStarIterable();
-    classElement.ensureResolved(compiler);
+    classElement.ensureResolved(resolution);
     return classElement.lookupConstructor("");
   }
 
   Element getSyncCompleterConstructor() {
     ClassElement classElement = find(compiler.asyncLibrary, "Completer");
-    classElement.ensureResolved(compiler);
+    classElement.ensureResolved(resolution);
     return classElement.lookupConstructor("sync");
   }
 
   Element getASyncStarController() {
     ClassElement classElement =
         findAsyncHelper("_AsyncStarStreamController");
-    classElement.ensureResolved(compiler);
+    classElement.ensureResolved(resolution);
     return classElement;
   }
 
@@ -1964,7 +2001,7 @@
 
   Element getStreamIteratorConstructor() {
     ClassElement classElement = find(compiler.asyncLibrary, "StreamIterator");
-    classElement.ensureResolved(compiler);
+    classElement.ensureResolved(resolution);
     return classElement.lookupConstructor("");
   }
 
@@ -2052,7 +2089,7 @@
     if (mustRetainMetadata) hasRetainedMetadata = true;
     if (mustRetainMetadata && referencedFromMirrorSystem(element)) {
       for (MetadataAnnotation metadata in element.metadata) {
-        metadata.ensureResolved(compiler);
+        metadata.ensureResolved(resolution);
         ConstantValue constant =
             constants.getConstantValueForMetadata(metadata);
         constants.addCompileTimeConstantForEmission(constant);
@@ -2092,7 +2129,7 @@
     boundClosureClass = lookupHelperClass('BoundClosure');
     closureClass = lookupHelperClass('Closure');
     if (!missingHelperClasses.isEmpty) {
-      compiler.internalError(jsHelperLibrary,
+      reporter.internalError(jsHelperLibrary,
           'dart:_js_helper library does not contain required classes: '
           '$missingHelperClasses');
     }
@@ -2199,7 +2236,7 @@
     assert(loadedLibraries.containsLibrary(DART_JS_HELPER));
 
     if (jsInvocationMirrorClass != null) {
-      jsInvocationMirrorClass.ensureResolved(compiler);
+      jsInvocationMirrorClass.ensureResolved(resolution);
       invokeOnMethod = jsInvocationMirrorClass.lookupLocalMember(INVOKE_ON);
     }
 
@@ -2225,16 +2262,16 @@
     // subclasses, so we check to see if they are defined before
     // trying to resolve them.
     if (jsFixedArrayClass != null) {
-      jsFixedArrayClass.ensureResolved(compiler);
+      jsFixedArrayClass.ensureResolved(resolution);
     }
     if (jsExtendableArrayClass != null) {
-      jsExtendableArrayClass.ensureResolved(compiler);
+      jsExtendableArrayClass.ensureResolved(resolution);
     }
     if (jsUnmodifiableArrayClass != null) {
-      jsUnmodifiableArrayClass.ensureResolved(compiler);
+      jsUnmodifiableArrayClass.ensureResolved(resolution);
     }
 
-    jsIndexableClass.ensureResolved(compiler);
+    jsIndexableClass.ensureResolved(resolution);
     jsIndexableLength = compiler.lookupElementIn(
         jsIndexableClass, 'length');
     if (jsIndexableLength != null && jsIndexableLength.isAbstractField) {
@@ -2242,12 +2279,12 @@
       jsIndexableLength = element.getter;
     }
 
-    jsArrayClass.ensureResolved(compiler);
+    jsArrayClass.ensureResolved(resolution);
     jsArrayTypedConstructor = compiler.lookupElementIn(jsArrayClass, 'typed');
     jsArrayRemoveLast = compiler.lookupElementIn(jsArrayClass, 'removeLast');
     jsArrayAdd = compiler.lookupElementIn(jsArrayClass, 'add');
 
-    jsStringClass.ensureResolved(compiler);
+    jsStringClass.ensureResolved(resolution);
     jsStringSplit = compiler.lookupElementIn(jsStringClass, 'split');
     jsStringOperatorAdd = compiler.lookupElementIn(jsStringClass, '+');
     jsStringToString = compiler.lookupElementIn(jsStringClass, 'toString');
@@ -2341,7 +2378,7 @@
       // TODO(kasperl): It would be nice if we didn't have to resolve
       // all metadata but only stuff that potentially would match one
       // of the used meta targets.
-      metadata.ensureResolved(compiler);
+      metadata.ensureResolved(resolution);
       ConstantValue value =
           compiler.constants.getConstantValue(metadata.constant);
       if (value == null) continue;
@@ -2389,13 +2426,13 @@
         reflectableMembers.add(cls);
         // 2) its constructors (if resolved)
         cls.constructors.forEach((Element constructor) {
-          if (resolution.hasBeenResolved(constructor)) {
+          if (resolution.hasBeenProcessed(constructor)) {
             reflectableMembers.add(constructor);
           }
         });
         // 3) all members, including fields via getter/setters (if resolved)
         cls.forEachClassMember((Member member) {
-          if (resolution.hasBeenResolved(member.element)) {
+          if (resolution.hasBeenProcessed(member.element)) {
             memberNames.add(member.name);
             reflectableMembers.add(member.element);
           }
@@ -2407,8 +2444,8 @@
               if (memberNames.contains(member.name)) {
                 // TODO(20993): find out why this assertion fails.
                 // assert(invariant(member.element,
-                //    resolution.hasBeenResolved(member.element)));
-                if (resolution.hasBeenResolved(member.element)) {
+                //    resolution.hasBeenProcessed(member.element)));
+                if (resolution.hasBeenProcessed(member.element)) {
                   reflectableMembers.add(member.element);
                 }
               }
@@ -2424,13 +2461,13 @@
       } else {
         // check members themselves
         cls.constructors.forEach((ConstructorElement element) {
-          if (!resolution.hasBeenResolved(element)) return;
+          if (!resolution.hasBeenProcessed(element)) return;
           if (referencedFromMirrorSystem(element, false)) {
             reflectableMembers.add(element);
           }
         });
         cls.forEachClassMember((Member member) {
-          if (!resolution.hasBeenResolved(member.element)) return;
+          if (!resolution.hasBeenProcessed(member.element)) return;
           if (referencedFromMirrorSystem(member.element, false)) {
             reflectableMembers.add(member.element);
           }
@@ -2455,7 +2492,7 @@
       if (lib.isInternalLibrary) continue;
       lib.forEachLocalMember((Element member) {
         if (!member.isClass &&
-            resolution.hasBeenResolved(member) &&
+            resolution.hasBeenProcessed(member) &&
             referencedFromMirrorSystem(member)) {
           reflectableMembers.add(member);
         }
@@ -2608,13 +2645,21 @@
       enqueuer.enqueueReflectiveStaticFields(_findStaticFieldTargets());
     }
 
-    if (mustPreserveNames) compiler.log('Preserving names.');
+    if (mustPreserveNames) reporter.log('Preserving names.');
 
     if (mustRetainMetadata) {
-      compiler.log('Retaining metadata.');
+      reporter.log('Retaining metadata.');
 
       compiler.libraryLoader.libraries.forEach(retainMetadataOf);
-      if (!enqueuer.isResolutionQueue) {
+      if (enqueuer.isResolutionQueue) {
+        for (Dependency dependency in metadataConstants) {
+          registerCompileTimeConstant(
+              dependency.constant,
+              new EagerRegistry(compiler,
+                  dependency.annotatedElement.analyzableElement.treeElements),
+              addForEmission: false);
+        }
+      } else {
         for (Dependency dependency in metadataConstants) {
           registerCompileTimeConstant(
               dependency.constant,
@@ -2649,7 +2694,7 @@
     bool hasNoThrows = false;
     bool hasNoSideEffects = false;
     for (MetadataAnnotation metadata in element.implementation.metadata) {
-      metadata.ensureResolved(compiler);
+      metadata.ensureResolved(resolution);
       ConstantValue constantValue =
           compiler.constants.getConstantValue(metadata.constant);
       if (!constantValue.isConstructedObject) continue;
@@ -2658,7 +2703,7 @@
       if (cls == forceInlineClass) {
         hasForceInline = true;
         if (VERBOSE_OPTIMIZER_HINTS) {
-          compiler.reportHintMessage(
+          reporter.reportHintMessage(
               element,
               MessageKind.GENERIC,
               {'text': "Must inline"});
@@ -2667,7 +2712,7 @@
       } else if (cls == noInlineClass) {
         hasNoInline = true;
         if (VERBOSE_OPTIMIZER_HINTS) {
-          compiler.reportHintMessage(
+          reporter.reportHintMessage(
               element,
               MessageKind.GENERIC,
               {'text': "Cannot inline"});
@@ -2676,12 +2721,12 @@
       } else if (cls == noThrowsClass) {
         hasNoThrows = true;
         if (!Elements.isStaticOrTopLevelFunction(element)) {
-          compiler.internalError(element,
+          reporter.internalError(element,
               "@NoThrows() is currently limited to top-level"
               " or static functions");
         }
         if (VERBOSE_OPTIMIZER_HINTS) {
-          compiler.reportHintMessage(
+          reporter.reportHintMessage(
               element,
               MessageKind.GENERIC,
               {'text': "Cannot throw"});
@@ -2690,7 +2735,7 @@
       } else if (cls == noSideEffectsClass) {
         hasNoSideEffects = true;
         if (VERBOSE_OPTIMIZER_HINTS) {
-          compiler.reportHintMessage(
+          reporter.reportHintMessage(
               element,
               MessageKind.GENERIC,
               {'text': "Has no side effects"});
@@ -2699,15 +2744,15 @@
       }
     }
     if (hasForceInline && hasNoInline) {
-      compiler.internalError(element,
+      reporter.internalError(element,
           "@ForceInline() must not be used with @NoInline.");
     }
     if (hasNoThrows && !hasNoInline) {
-      compiler.internalError(element,
+      reporter.internalError(element,
           "@NoThrows() should always be combined with @NoInline.");
     }
     if (hasNoSideEffects && !hasNoInline) {
-      compiler.internalError(element,
+      reporter.internalError(element,
           "@NoSideEffects() should always be combined with @NoInline.");
     }
     if (element == invokeOnMethod) {
@@ -2761,33 +2806,48 @@
                            Enqueuer enqueuer,
                            Registry registry) {
     if (element.asyncMarker == AsyncMarker.ASYNC) {
-      enqueue(enqueuer, getAsyncHelper(), registry);
-      enqueue(enqueuer, getSyncCompleterConstructor(), registry);
-      enqueue(enqueuer, getStreamIteratorConstructor(), registry);
-      enqueue(enqueuer, getWrapBody(), registry);
+      _registerAsync(enqueuer, registry);
     } else if (element.asyncMarker == AsyncMarker.SYNC_STAR) {
-      ClassElement clsSyncStarIterable = getSyncStarIterable();
-      clsSyncStarIterable.ensureResolved(compiler);
-      registerInstantiatedType(clsSyncStarIterable.rawType, enqueuer, registry);
-      enqueue(enqueuer, getSyncStarIterableConstructor(), registry);
-      enqueue(enqueuer, getEndOfIteration(), registry);
-      enqueue(enqueuer, getYieldStar(), registry);
-      enqueue(enqueuer, getSyncStarUncaughtError(), registry);
+      _registerSyncStar(enqueuer, registry);
     } else if (element.asyncMarker == AsyncMarker.ASYNC_STAR) {
-      ClassElement clsASyncStarController = getASyncStarController();
-      clsASyncStarController.ensureResolved(compiler);
-      registerInstantiatedType(
-          clsASyncStarController.rawType, enqueuer, registry);
-      enqueue(enqueuer, getAsyncStarHelper(), registry);
-      enqueue(enqueuer, getStreamOfController(), registry);
-      enqueue(enqueuer, getYieldSingle(), registry);
-      enqueue(enqueuer, getYieldStar(), registry);
-      enqueue(enqueuer, getASyncStarControllerConstructor(), registry);
-      enqueue(enqueuer, getStreamIteratorConstructor(), registry);
-      enqueue(enqueuer, getWrapBody(), registry);
+      _registerAsyncStar(enqueuer, registry);
     }
   }
 
+  void _registerAsync(Enqueuer enqueuer,
+                      Registry registry) {
+    enqueue(enqueuer, getAsyncHelper(), registry);
+    enqueue(enqueuer, getSyncCompleterConstructor(), registry);
+    enqueue(enqueuer, getStreamIteratorConstructor(), registry);
+    enqueue(enqueuer, getWrapBody(), registry);
+  }
+
+  void _registerSyncStar(Enqueuer enqueuer,
+                         Registry registry) {
+    ClassElement clsSyncStarIterable = getSyncStarIterable();
+    clsSyncStarIterable.ensureResolved(compiler.resolution);
+    registerInstantiatedType(clsSyncStarIterable.rawType, enqueuer, registry);
+    enqueue(enqueuer, getSyncStarIterableConstructor(), registry);
+    enqueue(enqueuer, getEndOfIteration(), registry);
+    enqueue(enqueuer, getYieldStar(), registry);
+    enqueue(enqueuer, getSyncStarUncaughtError(), registry);
+  }
+
+  void _registerAsyncStar(Enqueuer enqueuer,
+                          Registry registry) {
+    ClassElement clsASyncStarController = getASyncStarController();
+    clsASyncStarController.ensureResolved(compiler.resolution);
+    registerInstantiatedType(
+        clsASyncStarController.rawType, enqueuer, registry);
+    enqueue(enqueuer, getAsyncStarHelper(), registry);
+    enqueue(enqueuer, getStreamOfController(), registry);
+    enqueue(enqueuer, getYieldSingle(), registry);
+    enqueue(enqueuer, getYieldStar(), registry);
+    enqueue(enqueuer, getASyncStarControllerConstructor(), registry);
+    enqueue(enqueuer, getStreamIteratorConstructor(), registry);
+    enqueue(enqueuer, getWrapBody(), registry);
+  }
+
   @override
   bool enableDeferredLoadingIfSupported(Spannable node, Registry registry) {
     registerCheckDeferredIsLoaded(registry);
@@ -2797,7 +2857,7 @@
   @override
   bool enableCodegenWithErrorsIfSupported(Spannable node) {
     if (compiler.useCpsIr) {
-      compiler.reportHintMessage(
+      reporter.reportHintMessage(
           node,
           MessageKind.GENERIC,
           {'text': "Generation of code with compile time errors is currently "
@@ -2814,8 +2874,8 @@
     switch (element.asyncMarker) {
       case AsyncMarker.ASYNC:
         rewriter = new AsyncRewriter(
-            compiler,
-            compiler.currentElement,
+            reporter,
+            element,
             asyncHelper:
                 emitter.staticFunctionAccess(getAsyncHelper()),
             wrapBody:
@@ -2827,8 +2887,8 @@
         break;
       case AsyncMarker.SYNC_STAR:
         rewriter = new SyncStarRewriter(
-            compiler,
-            compiler.currentElement,
+            reporter,
+            element,
             endOfIteration: emitter.staticFunctionAccess(
                 getEndOfIteration()),
             newIterable: emitter.staticFunctionAccess(
@@ -2842,8 +2902,8 @@
          break;
       case AsyncMarker.ASYNC_STAR:
         rewriter = new AsyncStarRewriter(
-            compiler,
-            compiler.currentElement,
+            reporter,
+            element,
             asyncStarHelper: emitter.staticFunctionAccess(
                 getAsyncStarHelper()),
             streamOfController: emitter.staticFunctionAccess(
@@ -2880,6 +2940,8 @@
 
   JavaScriptBackend get backend => compiler.backend;
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   Annotations(this.compiler);
 
   void onLibraryScanned(LibraryElement library) {
@@ -2921,7 +2983,7 @@
   /// Returns `true` if [element] is annotated with [annotationClass].
   bool _hasAnnotation(Element element, ClassElement annotationClass) {
     if (annotationClass == null) return false;
-    return compiler.withCurrentElement(element, () {
+    return reporter.withCurrentElement(element, () {
       for (MetadataAnnotation metadata in element.metadata) {
         assert(invariant(metadata, metadata.constant != null,
             message: "Unevaluated metadata constant."));
@@ -2944,13 +3006,142 @@
 
   JavaScriptResolutionCallbacks(this.backend);
 
+  WorldImpact transformImpact(ResolutionWorldImpact worldImpact) {
+    TransformedWorldImpact transformed =
+        new TransformedWorldImpact(worldImpact);
+    for (Feature feature in worldImpact.features) {
+      switch (feature) {
+        case Feature.ABSTRACT_CLASS_INSTANTIATION:
+          onAbstractClassInstantiation(transformed);
+          break;
+        case Feature.ASSERT:
+          onAssert(false, transformed);
+          break;
+        case Feature.ASSERT_WITH_MESSAGE:
+          onAssert(true, transformed);
+          break;
+        case Feature.ASYNC:
+          backend._registerAsync(
+              backend.compiler.enqueuer.resolution, transformed);
+          break;
+        case Feature.ASYNC_FOR_IN:
+          onAsyncForIn(null, transformed);
+          break;
+        case Feature.ASYNC_STAR:
+          backend._registerAsyncStar(
+              backend.compiler.enqueuer.resolution, transformed);
+          break;
+        case Feature.CATCH_STATEMENT:
+          onCatchStatement(transformed);
+          break;
+        case Feature.COMPILE_TIME_ERROR:
+          onCompileTimeError(transformed, null);
+          break;
+        case Feature.FALL_THROUGH_ERROR:
+          onFallThroughError(transformed);
+          break;
+        case Feature.INC_DEC_OPERATION:
+          onIncDecOperation(transformed);
+          break;
+        case Feature.LAZY_FIELD:
+          onLazyField(transformed);
+          break;
+        case Feature.NEW_SYMBOL:
+          backend.registerNewSymbol(transformed);
+          break;
+        case Feature.STACK_TRACE_IN_CATCH:
+          onStackTraceInCatch(transformed);
+          break;
+        case Feature.STRING_INTERPOLATION:
+          onStringInterpolation(transformed);
+          break;
+        case Feature.SUPER_NO_SUCH_METHOD:
+          onSuperNoSuchMethod(transformed);
+          break;
+        case Feature.SYMBOL_CONSTRUCTOR:
+          onSymbolConstructor(transformed);
+          break;
+        case Feature.SYNC_FOR_IN:
+          onSyncForIn(transformed);
+          break;
+        case Feature.SYNC_STAR:
+          backend._registerSyncStar(
+              backend.compiler.enqueuer.resolution, transformed);
+          break;
+        case Feature.THROW_EXPRESSION:
+          onThrowExpression(transformed);
+          break;
+        case Feature.THROW_NO_SUCH_METHOD:
+          onThrowNoSuchMethod(transformed);
+          break;
+        case Feature.THROW_RUNTIME_ERROR:
+          onThrowRuntimeError(transformed);
+          break;
+        case Feature.TYPE_VARIABLE_BOUNDS_CHECK:
+          onTypeVariableBoundCheck(transformed);
+          break;
+      }
+    }
+    for (DartType type in worldImpact.isChecks) {
+      onIsCheck(type, transformed);
+    }
+    for (DartType type in worldImpact.asCasts) {
+      onIsCheck(type, transformed);
+      onAsCheck(type, transformed);
+    }
+    if (backend.compiler.enableTypeAssertions) {
+      for (DartType type in worldImpact.checkedModeChecks) {
+        onIsCheck(type, transformed);
+      }
+    }
+    for (DartType requiredType in worldImpact.requiredTypes) {
+      backend.registerRequiredType(requiredType);
+    }
+    for (MapLiteralUse mapLiteralUse in worldImpact.mapLiterals) {
+      // TODO(johnniwinther): Use the [isEmpty] property when factory
+      // constructors are registered directly.
+      onMapLiteral(transformed, mapLiteralUse.type, mapLiteralUse.isConstant);
+    }
+    for (ListLiteralUse listLiteralUse in worldImpact.listLiterals) {
+      // TODO(johnniwinther): Use the [isConstant] and [isEmpty] property when
+      // factory constructors are registered directly.
+      transformed.registerInstantiation(listLiteralUse.type);
+    }
+    for (DartType typeLiteral in worldImpact.typeLiterals) {
+      onTypeLiteral(typeLiteral, transformed);
+      transformed.registerInstantiation(backend.compiler.coreTypes.typeType);
+      if (typeLiteral.isTypeVariable) {
+        onTypeVariableExpression(transformed, typeLiteral.element);
+      }
+    }
+    for (String constSymbolName in worldImpact.constSymbolNames) {
+      backend.registerConstSymbol(constSymbolName, transformed);
+    }
+    for (LocalFunctionElement closure in worldImpact.closures) {
+      if (closure.computeType(backend.resolution).containsTypeVariables) {
+        backend.registerClosureWithFreeTypeVariables(
+            closure, backend.compiler.enqueuer.resolution, transformed);
+      }
+    }
+    // TODO(johnniwinther): Remove this when dependency tracking is done on
+    // the world impact itself.
+    for (InterfaceType instantiatedType in worldImpact.instantiatedTypes) {
+      transformed.registerInstantiation(instantiatedType);
+    }
+    for (Element element in worldImpact.staticUses) {
+      transformed.registerStaticInvocation(element);
+    }
+
+    return transformed;
+  }
+
   void registerBackendStaticInvocation(Element element, Registry registry) {
     registry.registerStaticInvocation(backend.registerBackendUse(element));
   }
 
   void registerBackendInstantiation(ClassElement element, Registry registry) {
     backend.registerBackendUse(element);
-    element.ensureResolved(backend.compiler);
+    element.ensureResolved(backend.resolution);
     registry.registerInstantiation(element.rawType);
   }
 
@@ -3041,7 +3232,7 @@
   // TODO(johnniwinther): Maybe split this into [onAssertType] and [onTestType].
   void onIsCheck(DartType type, Registry registry) {
     assert(registry.isForResolution);
-    type = type.unalias(backend.compiler);
+    type = type.unalias(backend.resolution);
     registerBackendInstantiation(backend.compiler.boolClass, registry);
     bool inCheckedMode = backend.compiler.enableTypeAssertions;
     if (inCheckedMode) {
@@ -3149,7 +3340,7 @@
         'Needed to encode the name of super.noSuchMethod.');
   }
 
-  void onMapLiteral(ResolutionRegistry registry,
+  void onMapLiteral(Registry registry,
                     DartType type,
                     bool isConstant) {
     assert(registry.isForResolution);
@@ -3164,7 +3355,7 @@
       enqueue(JavaScriptMapConstant.DART_STRING_CLASS);
       enqueue(JavaScriptMapConstant.DART_GENERAL_CLASS);
     } else {
-      registry.registerInstantiatedType(type);
+      registry.registerInstantiation(type);
     }
   }
 
diff --git a/pkg/compiler/lib/src/js_backend/codegen/glue.dart b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
index 37dd0ae..3a229e3 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/glue.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
@@ -14,6 +14,10 @@
     DartType,
     TypeVariableType,
     InterfaceType;
+import '../../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
+import '../../diagnostics/spannable.dart' show
+    CURRENT_ELEMENT_SPANNABLE;
 import '../../enqueue.dart' show
     CodegenEnqueuer;
 import '../../elements/elements.dart';
@@ -46,12 +50,14 @@
 
   ClassWorld get classWorld => _compiler.world;
 
+  DiagnosticReporter get reporter => _compiler.reporter;
+
   js.Expression constantReference(ConstantValue value) {
     return _emitter.constantReference(value);
   }
 
   reportInternalError(String message) {
-    _compiler.internalError(_compiler.currentElement, message);
+    reporter.internalError(CURRENT_ELEMENT_SPANNABLE, message);
   }
 
   bool isUsedAsMixin(ClassElement classElement) {
diff --git a/pkg/compiler/lib/src/js_backend/codegen/task.dart b/pkg/compiler/lib/src/js_backend/codegen/task.dart
index 92cd2c0..0e12e63 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/task.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/task.dart
@@ -20,6 +20,8 @@
 import '../../cps_ir/cps_ir_nodes.dart' as cps;
 import '../../cps_ir/cps_ir_integrity.dart';
 import '../../cps_ir/cps_ir_builder_task.dart';
+import '../../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import '../../diagnostics/invariant.dart' show
     DEBUG_MODE;
 import '../../tree_ir/tree_ir_nodes.dart' as tree_ir;
@@ -76,16 +78,18 @@
 
   JavaScriptBackend get backend => compiler.backend;
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   /// Generates JavaScript code for `work.element`.
   js.Fun compile(CodegenWorkItem work) {
     AstElement element = work.element;
-    return compiler.withCurrentElement(element, () {
+    return reporter.withCurrentElement(element, () {
       typeSystem = new TypeMaskSystem(compiler);
       try {
         // TODO(karlklose): remove this fallback when we do not need it for
         // testing anymore.
         if (false) {
-          compiler.log('Using SSA compiler for platform element $element');
+          reporter.log('Using SSA compiler for platform element $element');
           return fallbackCompiler.compile(work);
         }
 
@@ -100,7 +104,7 @@
       } on CodegenBailout catch (e) {
         String message = "Unable to compile $element with the new compiler.\n"
             "  Reason: ${e.message}";
-        compiler.internalError(element, message);
+        reporter.internalError(element, message);
       }
     });
   }
@@ -203,7 +207,7 @@
 
   tree_ir.FunctionDefinition compileToTreeIr(cps.FunctionDefinition cpsNode) {
     tree_builder.Builder builder = new tree_builder.Builder(
-        compiler.internalError);
+        reporter.internalError);
     tree_ir.FunctionDefinition treeNode =
         treeBuilderTask.measure(() => builder.buildFunction(cpsNode));
     assert(treeNode != null);
diff --git a/pkg/compiler/lib/src/js_backend/constant_emitter.dart b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
index 3f38a28..f1d7f74 100644
--- a/pkg/compiler/lib/src/js_backend/constant_emitter.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
@@ -39,6 +39,8 @@
       jsAst.Expression this.constantReferenceGenerator(ConstantValue constant),
       this.makeConstantList);
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   /**
    * Constructs a literal expression that evaluates to the constant. Uses a
    * canonical name unless the constant can be emitted multiple times (as for
@@ -54,7 +56,7 @@
 
   @override
   jsAst.Expression visitFunction(FunctionConstantValue constant, [_]) {
-    compiler.internalError(NO_LOCATION_SPANNABLE,
+    reporter.internalError(NO_LOCATION_SPANNABLE,
         "The function constant does not need specific JS code.");
     return null;
   }
@@ -220,7 +222,7 @@
           } else if (field.name == JavaScriptMapConstant.JS_DATA_NAME) {
             arguments.add(jsGeneralMap());
           } else {
-            compiler.internalError(field,
+            reporter.internalError(field,
                 "Compiler has unexpected field ${field.name} for "
                 "${className}.");
           }
@@ -233,7 +235,7 @@
          emittedArgumentCount != 4) ||
         (className == JavaScriptMapConstant.DART_GENERAL_CLASS &&
          emittedArgumentCount != 1)) {
-      compiler.internalError(classElement,
+      reporter.internalError(classElement,
           "Compiler and ${className} disagree on number of fields.");
     }
 
@@ -273,7 +275,7 @@
       case SyntheticConstantKind.NAME:
         return constant.payload;
       default:
-        compiler.internalError(NO_LOCATION_SPANNABLE,
+        reporter.internalError(NO_LOCATION_SPANNABLE,
                                "Unexpected DummyConstantKind ${constant.kind}");
         return null;
     }
diff --git a/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart b/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
index 5d0183a..dcb5661 100644
--- a/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
@@ -196,7 +196,7 @@
     ConstantExpression initialValue =
         initialVariableValues[element.declaration];
     if (initialValue == null) {
-      compiler.internalError(element, "No initial value for given element.");
+      reporter.internalError(element, "No initial value for given element.");
     }
     return getConstantValue(initialValue);
   }
diff --git a/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart b/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
index 3ebe90f6..3dca32b 100644
--- a/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
@@ -263,7 +263,8 @@
   @override
   ConstantValue createType(Compiler compiler, DartType type) {
     return new TypeConstantValue(
-        type, compiler.backend.typeImplementation.computeType(compiler));
+        type,
+        compiler.backend.typeImplementation.computeType(compiler.resolution));
   }
 
   // Integer checks don't verify that the number is not -0.0.
@@ -321,7 +322,7 @@
                        : JavaScriptMapConstant.DART_STRING_CLASS)
         : JavaScriptMapConstant.DART_GENERAL_CLASS;
     ClassElement classElement = backend.jsHelperLibrary.find(className);
-    classElement.ensureResolved(compiler);
+    classElement.ensureResolved(compiler.resolution);
     List<DartType> typeArgument = sourceType.typeArguments;
     InterfaceType type;
     if (sourceType.treatAsRaw) {
diff --git a/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart b/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
index 1cd0c43..00394a5 100644
--- a/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
@@ -67,7 +67,7 @@
       enqueuer.isResolutionQueue ? resolutionJoin : codegenJoin;
 
   void registerInstantiatedClass(ClassElement classElement, Enqueuer enqueuer) {
-    classElement.ensureResolved(compiler);
+    classElement.ensureResolved(compiler.resolution);
     if (!Elements.isNativeOrExtendsNative(classElement)) return;
     if (classElement.isMixinApplication) return;
     if (classElement.isAbstract) return;
@@ -191,7 +191,7 @@
       if (member.isGenerativeConstructor) {
         // Ignore constructors that cannot be called with zero arguments.
         FunctionElement constructor = member;
-        constructor.computeType(compiler);
+        constructor.computeType(compiler.resolution);
         FunctionSignature parameters = constructor.functionSignature;
         if (parameters.requiredParameterCount == 0) {
           result.add(member);
diff --git a/pkg/compiler/lib/src/js_backend/js_backend.dart b/pkg/compiler/lib/src/js_backend/js_backend.dart
index 5cf86f4..f195be4 100644
--- a/pkg/compiler/lib/src/js_backend/js_backend.dart
+++ b/pkg/compiler/lib/src/js_backend/js_backend.dart
@@ -12,7 +12,8 @@
 
 import '../closure.dart';
 import '../common/backend_api.dart' show
-    Backend;
+    Backend,
+    ForeignResolver;
 import '../common/codegen.dart' show
     CodegenRegistry,
     CodegenWorkItem;
@@ -25,7 +26,13 @@
 import '../common/tasks.dart' show
     CompilerTask;
 import '../common/resolution.dart' show
-    ResolutionCallbacks;
+    Feature,
+    ListLiteralUse,
+    MapLiteralUse,
+    Resolution,
+    ResolutionCallbacks,
+    ResolutionWorldImpact,
+    TransformedWorldImpact;
 import '../common/work.dart' show
     ItemCompilationContext;
 import '../compiler.dart' show
@@ -36,11 +43,13 @@
 import '../constants/values.dart';
 import '../dart_types.dart';
 import '../diagnostics/diagnostic_listener.dart' show
-    DiagnosticMessage;
+    DiagnosticMessage,
+    DiagnosticReporter;
 import '../diagnostics/invariant.dart' show
     invariant;
 import '../diagnostics/messages.dart' show MessageKind;
 import '../diagnostics/spannable.dart' show
+    CURRENT_ELEMENT_SPANNABLE,
     NO_LOCATION_SPANNABLE,
     Spannable,
     SpannableAssertionFailure;
@@ -73,7 +82,7 @@
 import '../library_loader.dart' show LibraryLoader, LoadedLibraries;
 import '../native/native.dart' as native;
 import '../resolution/registry.dart' show
-    ResolutionRegistry;
+    EagerRegistry;
 import '../resolution/tree_elements.dart' show
     TreeElements;
 import '../ssa/ssa.dart';
diff --git a/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart b/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
index fa70021..21a643a 100644
--- a/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
@@ -7,14 +7,17 @@
 
 import '../common/registry.dart' show Registry;
 import '../compiler.dart' show Compiler;
-import '../diagnostics/messages.dart' show MessageKind;
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
+import '../diagnostics/messages.dart' show
+    MessageKind;
 import '../constants/values.dart' show
-     ConstantValue,
-     ConstructedConstantValue,
-     ListConstantValue,
-     NullConstantValue,
-     StringConstantValue,
-     TypeConstantValue;
+    ConstantValue,
+    ConstructedConstantValue,
+    ListConstantValue,
+    NullConstantValue,
+    StringConstantValue,
+    TypeConstantValue;
 import '../dart_types.dart' show DartType;
 import '../elements/elements.dart' show
     ClassElement,
@@ -72,6 +75,10 @@
   /// discover that a key in a map is potentially used.
   final JavaScriptBackend backend;
 
+  /// Reference the diagnostic reporting system for logging and reporting issues
+  /// to the end-user.
+  final DiagnosticReporter reporter;
+
   /// The resolved [VariableElement] associated with the top-level `_version`.
   VariableElement lookupMapVersionVariable;
 
@@ -119,7 +126,7 @@
   /// Whether the backend is currently processing the codegen queue.
   bool _inCodegen = false;
 
-  LookupMapAnalysis(this.backend);
+  LookupMapAnalysis(this.backend, this.reporter);
 
   /// Whether this analysis and optimization is enabled.
   bool get _isEnabled {
@@ -136,7 +143,7 @@
     // the lookup_map package. We otherwise produce a warning.
     lookupMapVersionVariable = library.implementation.findLocal('_version');
     if (lookupMapVersionVariable == null) {
-      backend.compiler.reportInfo(library,
+      reporter.reportInfo(library,
           MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP);
     } else {
       backend.compiler.enqueuer.resolution.addToWorkList(
@@ -155,7 +162,7 @@
     StringConstantValue value =
         backend.constants.getConstantValueForVariable(lookupMapVersionVariable);
     if (value == null) {
-      backend.compiler.reportInfo(lookupMapVersionVariable,
+      reporter.reportInfo(lookupMapVersionVariable,
           MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP);
       return;
     }
@@ -168,13 +175,13 @@
     } catch (e) {}
 
     if (version == null || !_validLookupMapVersionConstraint.allows(version)) {
-      backend.compiler.reportInfo(lookupMapVersionVariable,
+      reporter.reportInfo(lookupMapVersionVariable,
           MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP);
       return;
     }
 
     ClassElement cls = lookupMapLibrary.findLocal('LookupMap');
-    cls.computeType(backend.compiler);
+    cls.computeType(backend.resolution);
     entriesField = cls.lookupMember('_entries');
     keyField = cls.lookupMember('_key');
     valueField = cls.lookupMember('_value');
@@ -311,7 +318,7 @@
           count++;
         }
       }
-      compiler.log(count == 0
+      reporter.log(count == 0
           ? 'lookup-map: nothing was tree-shaken'
           : 'lookup-map: found $count unused keys ($sb)');
     }
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 14a399c..de1279f 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -457,6 +457,8 @@
 
   JavaScriptBackend get backend => compiler.backend;
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   String get deferredTypesName => 'deferredTypes';
   String get isolateName => 'Isolate';
   String get isolatePropertiesName => r'$isolateProperties';
@@ -513,7 +515,7 @@
       case JsGetName.FUNCTION_CLASS_TYPE_NAME:
         return runtimeTypeName(compiler.functionClass);
       default:
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
           node,
           MessageKind.GENERIC,
           {'text': 'Error: Namer has no name for "$name".'});
@@ -705,7 +707,8 @@
         return disambiguatedName; // Methods other than call are not annotated.
 
       default:
-        compiler.internalError(compiler.currentElement,
+        reporter.internalError(
+            CURRENT_ELEMENT_SPANNABLE,
             'Unexpected selector kind: ${selector.kind}');
         return null;
     }
@@ -1391,7 +1394,7 @@
 
   String get functionTypeTag => r'func';
 
-  String get functionTypeVoidReturnTag => r'void';
+  String get functionTypeVoidReturnTag => r'v';
 
   String get functionTypeReturnTypeTag => r'ret';
 
@@ -1581,6 +1584,8 @@
 
   ConstantNamingVisitor(this.compiler, this.hasher);
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   String getName(ConstantValue constant) {
     _visit(constant);
     if (root == null) return 'CONSTANT';
@@ -1743,7 +1748,7 @@
         add('name');
         break;
       default:
-        compiler.internalError(compiler.currentElement,
+        reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
                                "Unexpected SyntheticConstantValue");
     }
   }
@@ -1773,6 +1778,8 @@
 
   ConstantCanonicalHasher(this.compiler);
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   int getHash(ConstantValue constant) => _visit(constant);
 
   int _visit(ConstantValue constant) {
@@ -1856,9 +1863,10 @@
         // resolve to integer indexes, they're always part of a larger constant.
         return 0;
       default:
-        compiler.internalError(NO_LOCATION_SPANNABLE,
-                               'SyntheticConstantValue should never be named and '
-                               'never be subconstant');
+        reporter.internalError(
+            NO_LOCATION_SPANNABLE,
+            'SyntheticConstantValue should never be named and '
+            'never be subconstant');
         return 0;
     }
   }
diff --git a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
index 0a322bd..3bb7e45 100644
--- a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
+++ b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
@@ -59,6 +59,8 @@
       : this._backend = backend,
         this._compiler = backend.compiler;
 
+  DiagnosticReporter get reporter => _compiler.reporter;
+
   bool get hasThrowingNoSuchMethod => throwingImpls.isNotEmpty;
   bool get hasComplexNoSuchMethod => otherImpls.isNotEmpty;
 
@@ -82,19 +84,19 @@
   void emitDiagnostic() {
     throwingImpls.forEach((e) {
         if (!_hasForwardingSyntax(e)) {
-          _compiler.reportHintMessage(
+          reporter.reportHintMessage(
               e, MessageKind.DIRECTLY_THROWING_NSM);
         }
       });
     complexNoReturnImpls.forEach((e) {
         if (!_hasForwardingSyntax(e)) {
-          _compiler.reportHintMessage(
+          reporter.reportHintMessage(
               e, MessageKind.COMPLEX_THROWING_NSM);
         }
       });
     complexReturningImpls.forEach((e) {
         if (!_hasForwardingSyntax(e)) {
-          _compiler.reportHintMessage(
+          reporter.reportHintMessage(
               e, MessageKind.COMPLEX_RETURNING_NSM);
         }
       });
diff --git a/pkg/compiler/lib/src/js_backend/patch_resolver.dart b/pkg/compiler/lib/src/js_backend/patch_resolver.dart
index 36dfd07..d827a3e 100644
--- a/pkg/compiler/lib/src/js_backend/patch_resolver.dart
+++ b/pkg/compiler/lib/src/js_backend/patch_resolver.dart
@@ -4,6 +4,8 @@
 
 library dart2js.js_backend.patch_resolver;
 
+import '../common/resolution.dart' show
+    Resolution;
 import '../common/tasks.dart' show
     CompilerTask;
 import '../compiler.dart' show
@@ -22,19 +24,20 @@
 class PatchResolverTask extends CompilerTask {
   PatchResolverTask(Compiler compiler) : super(compiler);
 
+  Resolution get resolution => compiler.resolution;
+
   String get name => 'JavaScript patch resolver';
 
   FunctionElement resolveExternalFunction(FunctionElementX element) {
     if (element.isPatched) {
       FunctionElementX patch = element.patch;
-      compiler.withCurrentElement(patch, () {
-        patch.parseNode(compiler);
-        patch.computeType(compiler);
+      reporter.withCurrentElement(patch, () {
+        patch.computeType(resolution);
       });
       checkMatchingPatchSignatures(element, patch);
       element = patch;
     } else {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
          element, MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
     }
     return element;
@@ -56,19 +59,19 @@
         assert(invariant(origin, originParameter.patch == patchParameter,
                message: "Inconsistent repatch of $originParameter."));
       }
-      DartType originParameterType = originParameter.computeType(compiler);
-      DartType patchParameterType = patchParameter.computeType(compiler);
+      DartType originParameterType = originParameter.computeType(resolution);
+      DartType patchParameterType = patchParameter.computeType(resolution);
       if (originParameterType != patchParameterType) {
-        compiler.reportError(
-            compiler.createMessage(
-                originParameter.parseNode(compiler),
+        reporter.reportError(
+            reporter.createMessage(
+                originParameter,
                 MessageKind.PATCH_PARAMETER_TYPE_MISMATCH,
                 {'methodName': origin.name,
                  'parameterName': originParameter.name,
                  'originParameterType': originParameterType,
                  'patchParameterType': patchParameterType}),
             <DiagnosticMessage>[
-              compiler.createMessage(
+              reporter.createMessage(
                   patchParameter,
                   MessageKind.PATCH_POINT_TO_PARAMETER,
                   {'parameterName': patchParameter.name}),
@@ -80,23 +83,21 @@
 
         // The node contains the type, so there is a potential overlap.
         // Therefore we only check the text if the types are identical.
-        String originParameterText =
-            originParameter.parseNode(compiler).toString();
-        String patchParameterText =
-            patchParameter.parseNode(compiler).toString();
+        String originParameterText = originParameter.node.toString();
+        String patchParameterText = patchParameter.node.toString();
         if (originParameterText != patchParameterText
             // We special case the list constructor because of the
             // optional parameter.
             && origin != compiler.unnamedListConstructor) {
-          compiler.reportError(
-              compiler.createMessage(
-                  originParameter.parseNode(compiler),
+          reporter.reportError(
+              reporter.createMessage(
+                  originParameter,
                   MessageKind.PATCH_PARAMETER_MISMATCH,
                   {'methodName': origin.name,
                    'originParameter': originParameterText,
                    'patchParameter': patchParameterText}),
               <DiagnosticMessage>[
-                  compiler.createMessage(
+                  reporter.createMessage(
                       patchParameter,
                       MessageKind.PATCH_POINT_TO_PARAMETER,
                       {'parameterName': patchParameter.name}),
@@ -115,10 +116,10 @@
     FunctionSignature patchSignature = patch.functionSignature;
 
     if (originSignature.type.returnType != patchSignature.type.returnType) {
-      compiler.withCurrentElement(patch, () {
+      reporter.withCurrentElement(patch, () {
         Node errorNode =
             patchTree.returnType != null ? patchTree.returnType : patchTree;
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             errorNode, MessageKind.PATCH_RETURN_TYPE_MISMATCH,
             {'methodName': origin.name,
              'originReturnType': originSignature.type.returnType,
@@ -127,8 +128,8 @@
     }
     if (originSignature.requiredParameterCount !=
         patchSignature.requiredParameterCount) {
-      compiler.withCurrentElement(patch, () {
-        compiler.reportErrorMessage(
+      reporter.withCurrentElement(patch, () {
+        reporter.reportErrorMessage(
             patchTree,
             MessageKind.PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH,
             {'methodName': origin.name,
@@ -144,8 +145,8 @@
         patchSignature.optionalParameterCount != 0) {
       if (originSignature.optionalParametersAreNamed !=
           patchSignature.optionalParametersAreNamed) {
-        compiler.withCurrentElement(patch, () {
-          compiler.reportErrorMessage(
+        reporter.withCurrentElement(patch, () {
+          reporter.reportErrorMessage(
               patchTree,
               MessageKind.PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH,
               {'methodName': origin.name});
@@ -154,8 +155,8 @@
     }
     if (originSignature.optionalParameterCount !=
         patchSignature.optionalParameterCount) {
-      compiler.withCurrentElement(patch, () {
-        compiler.reportErrorMessage(
+      reporter.withCurrentElement(patch, () {
+        reporter.reportErrorMessage(
             patchTree,
             MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH,
             {'methodName': origin.name,
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index d6f02eb..81b4dd5 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -623,6 +623,7 @@
 
   JavaScriptBackend get backend => compiler.backend;
   Namer get namer => backend.namer;
+  DiagnosticReporter get reporter => compiler.reporter;
 
   TypeRepresentationGenerator(Compiler this.compiler);
 
@@ -744,7 +745,7 @@
 
   visitTypedefType(TypedefType type, _) {
     bool shouldEncode = shouldEncodeTypedef(type);
-    DartType unaliasedType = type.unalias(compiler);
+    DartType unaliasedType = type.unalias(compiler.resolution);
     if (shouldEncode) {
       jsAst.ObjectInitializer initializer = unaliasedType.accept(this, null);
       // We have to encode the aliased type.
@@ -762,7 +763,7 @@
   }
 
   visitStatementType(StatementType type, _) {
-    compiler.internalError(NO_LOCATION_SPANNABLE,
+    reporter.internalError(NO_LOCATION_SPANNABLE,
         'Unexpected type: $type (${type.kind}).');
   }
 }
@@ -814,7 +815,7 @@
   }
 
   visitTypedefType(TypedefType type, bool isTypeArgument) {
-    type.unalias(backend.compiler).accept(this, isTypeArgument);
+    type.unalias(backend.resolution).accept(this, isTypeArgument);
   }
 
   visitInterfaceType(InterfaceType type, bool isTypeArgument) {
@@ -846,7 +847,7 @@
   }
 
   visitTypedefType(TypedefType type, bool inFunctionType) {
-    type.unalias(backend.compiler).accept(this, inFunctionType);
+    type.unalias(backend.resolution).accept(this, inFunctionType);
   }
 
   visitInterfaceType(InterfaceType type, bool inFunctionType) {
diff --git a/pkg/compiler/lib/src/js_backend/type_variable_handler.dart b/pkg/compiler/lib/src/js_backend/type_variable_handler.dart
index 6832d33..ec6eecf 100644
--- a/pkg/compiler/lib/src/js_backend/type_variable_handler.dart
+++ b/pkg/compiler/lib/src/js_backend/type_variable_handler.dart
@@ -36,6 +36,7 @@
   CodeEmitterTask get _task => _backend.emitter;
   MetadataCollector get _metadataCollector => _task.metadataCollector;
   JavaScriptBackend get _backend => _compiler.backend;
+  DiagnosticReporter get reporter => _compiler.reporter;
 
   void registerClassWithTypeVariables(ClassElement cls, Enqueuer enqueuer,
                                       Registry registry) {
@@ -44,10 +45,10 @@
       // resolved.
       if (!_seenClassesWithTypeVariables) {
         _backend.enqueueClass(enqueuer, _typeVariableClass, registry);
-        _typeVariableClass.ensureResolved(_compiler);
+        _typeVariableClass.ensureResolved(_compiler.resolution);
         Link constructors = _typeVariableClass.constructors;
         if (constructors.isEmpty && constructors.tail.isEmpty) {
-          _compiler.internalError(_typeVariableClass,
+          reporter.internalError(_typeVariableClass,
               "Class '$_typeVariableClass' should only have one constructor");
         }
         _typeVariableConstructor = _typeVariableClass.constructors.head;
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart
index c5723ae..5a84ef2 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart
@@ -156,7 +156,7 @@
 
           int code = field.getterFlags + (field.setterFlags << 2);
           if (code == 0) {
-            compiler.internalError(fieldElement,
+            reporter.internalError(fieldElement,
                 'Field code is 0 ($fieldElement).');
           }
           fieldNameParts.add(
@@ -212,7 +212,7 @@
 
     for (Field field in cls.fields) {
       Element member = field.element;
-      compiler.withCurrentElement(member, () {
+      reporter.withCurrentElement(member, () {
         if (field.needsGetter) {
           emitGetterForCSP(member, field.name, field.accessorName, builder);
         }
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/code_emitter_helper.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/code_emitter_helper.dart
index f777014..78c963d 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/code_emitter_helper.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/code_emitter_helper.dart
@@ -15,6 +15,8 @@
 
   Compiler get compiler => emitter.compiler;
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   String get n => emitter.n;
 
   String get _ => emitter._;
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
index c71eaa2..62f5e81 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
@@ -26,7 +26,11 @@
 
 import '../../deferred_load.dart' show OutputUnit;
 
-import '../../diagnostics/messages.dart' show MessageKind;
+import '../../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
+
+import '../../diagnostics/messages.dart' show
+    MessageKind;
 
 import '../../diagnostics/spannable.dart' show
     NO_LOCATION_SPANNABLE;
@@ -192,6 +196,8 @@
     interceptorEmitter.emitter = this;
   }
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   List<jsAst.Node> cspPrecompiledFunctionFor(OutputUnit outputUnit) {
     return _cspPrecompiledFunctions.putIfAbsent(
         outputUnit,
@@ -415,7 +421,7 @@
         return jsAst.js.expressionTemplateFor("$functionGettersMap[#]()");
 
       default:
-        compiler.internalError(NO_LOCATION_SPANNABLE,
+        reporter.internalError(NO_LOCATION_SPANNABLE,
             "Unhandled Builtin: $builtin");
         return null;
     }
@@ -554,7 +560,7 @@
     } else if (element.isTypedef) {
       return element.name;
     }
-    throw compiler.internalError(element,
+    throw reporter.internalError(element,
         'Do not know how to reflect on this $element.');
   }
 
@@ -592,7 +598,7 @@
   void assembleClass(Class cls, ClassBuilder enclosingBuilder,
                      Fragment fragment) {
     ClassElement classElement = cls.element;
-    compiler.withCurrentElement(classElement, () {
+    reporter.withCurrentElement(classElement, () {
       if (compiler.hasIncrementalSupport) {
         ClassBuilder cachedBuilder =
             cachedClassBuilders.putIfAbsent(classElement, () {
@@ -645,7 +651,7 @@
     // [fields] is `null`.
     if (fields != null) {
       for (Element element in fields) {
-        compiler.withCurrentElement(element, () {
+        reporter.withCurrentElement(element, () {
           ConstantValue constant = handler.getInitialValueFor(element);
           parts.add(buildInitialization(element, constantReference(constant)));
         });
@@ -659,7 +665,7 @@
           (OutputUnit fieldsOutputUnit, Iterable<VariableElement> fields) {
         if (fieldsOutputUnit == outputUnit) return;  // Skip the main unit.
         for (Element element in fields) {
-          compiler.withCurrentElement(element, () {
+          reporter.withCurrentElement(element, () {
             parts.add(buildInitialization(element, jsAst.number(0)));
           });
         }
@@ -900,8 +906,8 @@
         #finishedClasses = map();
 
         if (#needsLazyInitializer) {
-          // [staticName] is only provided in non-minified mode. If missing, we 
-          // fall back to [fieldName]. Likewise, [prototype] is optional and 
+          // [staticName] is only provided in non-minified mode. If missing, we
+          // fall back to [fieldName]. Likewise, [prototype] is optional and
           // defaults to the isolateProperties object.
           $lazyInitializerName = function (fieldName, getterName, lazyValue,
                                            staticName, prototype) {
@@ -1332,12 +1338,12 @@
           Elements.sortedByPosition(elements.where((e) => !e.isLibrary));
 
       pendingStatics.forEach((element) =>
-          compiler.reportInfo(
+          reporter.reportInfo(
               element, MessageKind.GENERIC, {'text': 'Pending statics.'}));
     }
 
     if (pendingStatics != null && !pendingStatics.isEmpty) {
-      compiler.internalError(pendingStatics.first,
+      reporter.internalError(pendingStatics.first,
           'Pending statics (see above).');
     }
   }
@@ -1812,7 +1818,7 @@
 
     if (backend.requiresPreamble &&
         !backend.htmlLibraryIsLoaded) {
-      compiler.reportHintMessage(
+      reporter.reportHintMessage(
           NO_LOCATION_SPANNABLE, MessageKind.PREAMBLE);
     }
     // Return the total program size.
@@ -1846,7 +1852,7 @@
       }
     }
     if (owner == null) {
-      compiler.internalError(element, 'Owner is null.');
+      reporter.internalError(element, 'Owner is null.');
     }
     return elementDescriptors
         .putIfAbsent(fragment, () => new Map<Element, ClassBuilder>())
diff --git a/pkg/compiler/lib/src/js_emitter/js_emitter.dart b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
index 1472e53..4289e7c 100644
--- a/pkg/compiler/lib/src/js_emitter/js_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
@@ -20,6 +20,9 @@
 import '../dart_types.dart' show
     TypedefType;
 
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
+
 import '../diagnostics/spannable.dart' show
     NO_LOCATION_SPANNABLE;
 
diff --git a/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart
index d68c38b..2c2f303 100644
--- a/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart
@@ -26,6 +26,9 @@
 import '../js_emitter.dart' as emitterTask show
     Emitter;
 
+import '../../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
+
 import '../../diagnostics/spannable.dart' show
     NO_LOCATION_SPANNABLE;
 
@@ -41,6 +44,8 @@
         this.namer = namer,
         _emitter = new ModelEmitter(compiler, namer, nativeEmitter);
 
+  DiagnosticReporter get reporter => _compiler.reporter;
+
   @override
   String get patchVersion => "lazy";
 
@@ -181,7 +186,7 @@
         throw new UnsupportedError('createDartClosureFromNameOfStaticFunction');
 
       default:
-        _compiler.internalError(NO_LOCATION_SPANNABLE,
+        reporter.internalError(NO_LOCATION_SPANNABLE,
                                 "Unhandled Builtin: $builtin");
         return null;
     }
diff --git a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
index af55455..e0a9b03 100644
--- a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
+++ b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
@@ -145,6 +145,7 @@
 
   JavaScriptBackend get _backend => _compiler.backend;
   TypeVariableHandler get _typeVariableHandler => _backend.typeVariableHandler;
+  DiagnosticReporter get reporter => _compiler.reporter;
 
   bool _mustEmitMetadataFor(Element element) {
     return _backend.mustRetainMetadata &&
@@ -159,13 +160,13 @@
   /// mirrors_patch to implement DeclarationMirror.metadata.
   jsAst.Fun buildMetadataFunction(Element element) {
     if (!_mustEmitMetadataFor(element)) return null;
-    return _compiler.withCurrentElement(element, () {
+    return reporter.withCurrentElement(element, () {
       List<jsAst.Expression> metadata = <jsAst.Expression>[];
       for (MetadataAnnotation annotation in element.metadata) {
         ConstantValue constant =
             _backend.constants.getConstantValueForMetadata(annotation);
         if (constant == null) {
-          _compiler.internalError(annotation, 'Annotation value is null.');
+          reporter.internalError(annotation, 'Annotation value is null.');
         } else {
           metadata.add(_emitter.constantReference(constant));
         }
@@ -195,7 +196,7 @@
     ConstantValue constant =
         _backend.constants.getConstantValueForMetadata(annotation);
     if (constant == null) {
-      _compiler.internalError(annotation, 'Annotation value is null.');
+      reporter.internalError(annotation, 'Annotation value is null.');
       return null;
     }
     return _addGlobalMetadata(_emitter.constantReference(constant));
@@ -255,7 +256,7 @@
     if (representation is jsAst.LiteralString) {
       // We don't want the representation to be a string, since we use
       // strings as indicator for non-initialized types in the lazy emitter.
-      _compiler.internalError(
+      reporter.internalError(
           NO_LOCATION_SPANNABLE, 'reified types should not be strings.');
     }
 
@@ -281,7 +282,7 @@
   }
 
   List<jsAst.DeferredNumber> computeMetadata(FunctionElement element) {
-    return _compiler.withCurrentElement(element, () {
+    return reporter.withCurrentElement(element, () {
       if (!_mustEmitMetadataFor(element)) return const <jsAst.DeferredNumber>[];
       List<jsAst.DeferredNumber> metadata = <jsAst.DeferredNumber>[];
       for (MetadataAnnotation annotation in element.metadata) {
diff --git a/pkg/compiler/lib/src/js_emitter/native_emitter.dart b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
index 0d90d2f..df8778df 100644
--- a/pkg/compiler/lib/src/js_emitter/native_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
@@ -268,7 +268,7 @@
       // parameter that was not provided for this stub.
       for (jsAst.Parameter stubParameter in stubParameters) {
         if (stubParameter.name == name) {
-          DartType type = parameter.type.unalias(compiler);
+          DartType type = parameter.type.unalias(compiler.resolution);
           if (type is FunctionType) {
             // The parameter type is a function type either directly or through
             // typedef(s).
diff --git a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
index f632f90..0d95278 100644
--- a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
@@ -15,6 +15,7 @@
 
   Emitter get emitter => backend.emitter.emitter;
   CodeEmitterTask get emitterTask => backend.emitter;
+  DiagnosticReporter get reporter => compiler.reporter;
 
   bool needsSuperGetter(FunctionElement element) =>
     compiler.codegenWorld.methodsNeedingSuperGetter.contains(element);
@@ -190,10 +191,10 @@
     if (member.enclosingElement.isClosure) {
       ClosureClassElement cls = member.enclosingElement;
       if (cls.supertype.element == backend.boundClosureClass) {
-        compiler.internalError(cls.methodElement, 'Bound closure1.');
+        reporter.internalError(cls.methodElement, 'Bound closure1.');
       }
       if (cls.methodElement.isInstanceMember) {
-        compiler.internalError(cls.methodElement, 'Bound closure2.');
+        reporter.internalError(cls.methodElement, 'Bound closure2.');
       }
     }
 
diff --git a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
index 80ad3f1..233835b 100644
--- a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
@@ -228,7 +228,7 @@
                                     generateSubstitution,
                                     generated);
         }
-        FunctionType callType = callFunction.computeType(compiler);
+        FunctionType callType = callFunction.computeType(compiler.resolution);
         generateFunctionTypeSignature(callFunction, callType);
       }
     }
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
index 45ccabe..ea0537a 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
@@ -27,6 +27,9 @@
 import '../js_emitter.dart' as emitterTask show
     Emitter;
 
+import '../../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
+
 import '../../diagnostics/spannable.dart' show
     NO_LOCATION_SPANNABLE;
 
@@ -44,6 +47,8 @@
         _emitter = new ModelEmitter(
             compiler, namer, nativeEmitter, shouldGenerateSourceMap);
 
+  DiagnosticReporter get reporter => _compiler.reporter;
+
   @override
   String get patchVersion => "startup";
 
@@ -184,7 +189,7 @@
         return js.js.expressionTemplateFor("$functionAccess(#)");
 
       default:
-        _compiler.internalError(NO_LOCATION_SPANNABLE,
+        reporter.internalError(NO_LOCATION_SPANNABLE,
             "Unhandled Builtin: $builtin");
         return null;
     }
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
index 8c9f247..ec8ac00 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
@@ -31,6 +31,9 @@
     Namer,
     ConstantEmitter;
 
+import '../../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
+
 import '../../diagnostics/spannable.dart' show
     NO_LOCATION_SPANNABLE;
 
@@ -100,6 +103,8 @@
         constantListGenerator);
   }
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   js.Expression constantListGenerator(js.Expression array) {
     // TODO(floitsch): remove hard-coded name.
     return js.js('makeConstList(#)', [array]);
@@ -211,7 +216,7 @@
 
     if (backend.requiresPreamble &&
         !backend.htmlLibraryIsLoaded) {
-      compiler.reportHintMessage(
+      reporter.reportHintMessage(
           NO_LOCATION_SPANNABLE, MessageKind.PREAMBLE);
     }
 
diff --git a/pkg/compiler/lib/src/js_emitter/type_test_registry.dart b/pkg/compiler/lib/src/js_emitter/type_test_registry.dart
index ac333cc..f329cbf 100644
--- a/pkg/compiler/lib/src/js_emitter/type_test_registry.dart
+++ b/pkg/compiler/lib/src/js_emitter/type_test_registry.dart
@@ -129,7 +129,7 @@
     backend.generatedCode.keys.where((element) {
       return canBeReflectedAsFunction(element) && canBeReified(element);
     }).forEach((FunctionElement function) {
-      DartType type = function.computeType(compiler);
+      DartType type = function.type;
       for (ClassElement cls in backend.rti.getReferencedClasses(type)) {
         while (cls != null) {
           rtiNeededClasses.add(cls);
diff --git a/pkg/compiler/lib/src/library_loader.dart b/pkg/compiler/lib/src/library_loader.dart
index 08aaf90..241516b 100644
--- a/pkg/compiler/lib/src/library_loader.dart
+++ b/pkg/compiler/lib/src/library_loader.dart
@@ -358,7 +358,7 @@
       currentHandler = new LibraryDependencyHandler(this);
       return createLibrary(currentHandler, null, resolvedUri)
           .then((LibraryElement library) {
-        return compiler.withCurrentElement(library, () {
+        return reporter.withCurrentElement(library, () {
           return measure(() {
             currentHandler.computeExports();
             LoadedLibraries loadedLibraries =
@@ -388,14 +388,14 @@
     Uri base = library.entryCompilationUnit.script.readableUri;
 
     return Future.forEach(library.tags, (LibraryTag tag) {
-      return compiler.withCurrentElement(library, () {
+      return reporter.withCurrentElement(library, () {
 
         Uri computeUri(LibraryDependency node) {
           String tagUriString = node.uri.dartString.slowToString();
           try {
             return Uri.parse(tagUriString);
           } on FormatException {
-            compiler.reportErrorMessage(
+            reporter.reportErrorMessage(
                 node.uri,
                 MessageKind.INVALID_URI, {'uri': tagUriString});
             return null;
@@ -411,7 +411,7 @@
           // TODO(johnniwinther): Create imports during parsing.
           ImportElementX import =
               new ImportElementX(library.entryCompilationUnit, tag, uri);
-          tagState.checkTag(TagState.IMPORT_OR_EXPORT, import.node, compiler);
+          tagState.checkTag(TagState.IMPORT_OR_EXPORT, import.node, reporter);
           if (import.uri == Uris.dart_core) {
             importsDartCore = true;
           }
@@ -426,11 +426,11 @@
           // TODO(johnniwinther): Create exports during parsing.
           ExportElementX export =
               new ExportElementX(library.entryCompilationUnit, tag, uri);
-          tagState.checkTag(TagState.IMPORT_OR_EXPORT, export.node, compiler);
+          tagState.checkTag(TagState.IMPORT_OR_EXPORT, export.node, reporter);
           library.addExportDeclaration(export);
           libraryDependencies.addLast(export);
         } else if (tag.isLibraryName) {
-          tagState.checkTag(TagState.LIBRARY, tag, compiler);
+          tagState.checkTag(TagState.LIBRARY, tag, reporter);
           if (library.libraryTag == null) {
             // Use the first if there are multiple (which is reported as an
             // error in [TagState.checkTag]).
@@ -440,16 +440,16 @@
           Part part = tag;
           StringNode uri = part.uri;
           Uri resolvedUri = base.resolve(uri.dartString.slowToString());
-          tagState.checkTag(TagState.PART, part, compiler);
+          tagState.checkTag(TagState.PART, part, reporter);
           return scanPart(part, resolvedUri, library);
         } else {
-          compiler.internalError(tag, "Unhandled library tag.");
+          reporter.internalError(tag, "Unhandled library tag.");
         }
       });
     }).then((_) {
       return compiler.onLibraryScanned(library, handler);
     }).then((_) {
-      return compiler.withCurrentElement(library, () {
+      return reporter.withCurrentElement(library, () {
         checkDuplicatedLibraryName(library);
 
         // Import dart:core if not already imported.
@@ -466,7 +466,7 @@
     }).then((_) {
       return Future.forEach(libraryDependencies.toList(),
           (LibraryDependencyElementX libraryDependency) {
-        return compiler.withCurrentElement(library, () {
+        return reporter.withCurrentElement(library, () {
           return registerLibraryFromImportExport(
               handler, library, libraryDependency);
         });
@@ -481,8 +481,8 @@
         libraryResourceUriMap.putIfAbsent(resourceUri, () => library);
     if (!identical(existing, library)) {
       if (library.hasLibraryName) {
-        compiler.withCurrentElement(library, () {
-          compiler.reportWarningMessage(
+        reporter.withCurrentElement(library, () {
+          reporter.reportWarningMessage(
               library,
               MessageKind.DUPLICATED_LIBRARY_RESOURCE,
               {'libraryName': library.libraryName,
@@ -491,7 +491,7 @@
                'canonicalUri2': existing.canonicalUri});
         });
       } else {
-        compiler.reportHintMessage(
+        reporter.reportHintMessage(
             library,
             MessageKind.DUPLICATED_RESOURCE,
             {'resourceUri': resourceUri,
@@ -502,14 +502,14 @@
       String name = library.libraryOrScriptName;
       existing = libraryNames.putIfAbsent(name, () => library);
       if (!identical(existing, library)) {
-        compiler.withCurrentElement(library, () {
-          compiler.reportWarningMessage(
+        reporter.withCurrentElement(library, () {
+          reporter.reportWarningMessage(
               library,
               MessageKind.DUPLICATED_LIBRARY_NAME,
               {'libraryName': name});
         });
-        compiler.withCurrentElement(existing, () {
-          compiler.reportWarningMessage(
+        reporter.withCurrentElement(existing, () {
+          reporter.reportWarningMessage(
               existing,
               MessageKind.DUPLICATED_LIBRARY_NAME,
               {'libraryName': name});
@@ -526,17 +526,17 @@
     if (!resolvedUri.isAbsolute) throw new ArgumentError(resolvedUri);
     Uri readableUri = compiler.translateResolvedUri(library, resolvedUri, part);
     if (readableUri == null) return new Future.value();
-    return compiler.withCurrentElement(library, () {
+    return reporter.withCurrentElement(library, () {
       return compiler.readScript(part, readableUri).
           then((Script sourceScript) {
             if (sourceScript == null) return;
 
             CompilationUnitElementX unit =
                 new CompilationUnitElementX(sourceScript, library);
-            compiler.withCurrentElement(unit, () {
+            reporter.withCurrentElement(unit, () {
               compiler.scanner.scan(unit);
               if (unit.partTag == null && !sourceScript.isSynthesized) {
-                compiler.reportErrorMessage(
+                reporter.reportErrorMessage(
                     unit, MessageKind.MISSING_PART_OF_TAG);
               }
             });
@@ -559,7 +559,7 @@
     return createLibrary(handler, library, resolvedUri, libraryDependency)
         .then((LibraryElement loadedLibrary) {
           if (loadedLibrary == null) return;
-          compiler.withCurrentElement(library, () {
+          reporter.withCurrentElement(library, () {
             libraryDependency.libraryDependency = loadedLibrary;
             handler.registerDependency(
                 library, libraryDependency, loadedLibrary);
@@ -612,13 +612,13 @@
       readableUri = resolvedUri;
       readScript = compiler.synthesizeScript;
     }
-    return compiler.withCurrentElement(importingLibrary, () {
+    return reporter.withCurrentElement(importingLibrary, () {
       return readScript(node, readableUri).then((Script script) {
         if (script == null) return null;
         LibraryElement element =
             createLibrarySync(handler, script, resolvedUri);
         return processLibraryTags(handler, element).then((_) {
-          compiler.withCurrentElement(element, () {
+          reporter.withCurrentElement(element, () {
             handler.registerLibraryExports(element);
           });
           return element;
@@ -632,7 +632,7 @@
       Script script,
       Uri resolvedUri) {
     LibraryElement element = new LibraryElementX(script, resolvedUri);
-    return compiler.withCurrentElement(element, () {
+    return reporter.withCurrentElement(element, () {
       if (handler != null) {
         handler.registerNewLibrary(element);
         libraryCanonicalUriMap[resolvedUri] = element;
@@ -679,7 +679,7 @@
 
   /// If [value] is less than [tagState] complain. Regardless, update
   /// [tagState] using transition function for state machine.
-  void checkTag(int value, LibraryTag tag, DiagnosticListener listener) {
+  void checkTag(int value, LibraryTag tag, DiagnosticReporter reporter) {
     if (tagState > value) {
       MessageKind kind;
       switch (value) {
@@ -697,14 +697,14 @@
           } else if (tag.isExport) {
             kind = MessageKind.EXPORT_BEFORE_PARTS;
           } else {
-            listener.internalError(tag, "Expected import or export.");
+            reporter.internalError(tag, "Expected import or export.");
           }
           break;
 
         default:
-          listener.internalError(tag, "Unexpected order of library tags.");
+          reporter.internalError(tag, "Unexpected order of library tags.");
       }
-      listener.reportErrorMessage(tag, kind);
+      reporter.reportErrorMessage(tag, kind);
     }
     tagState = NEXT[value];
     if (value == LIBRARY) {
@@ -725,7 +725,8 @@
   /**
    * Imports the library into the [importingLibrary].
    */
-  void importLibrary(Compiler compiler, LibraryElementX importingLibrary) {
+  void importLibrary(DiagnosticReporter reporter,
+                     LibraryElementX importingLibrary) {
     assert(invariant(importingLibrary,
                      importedLibrary.exportsHandled,
                      message: 'Exports not handled on $importedLibrary'));
@@ -745,22 +746,22 @@
       } else {
         prefixElement = existingElement;
       }
-      importingLibrary.addToScope(prefixElement, compiler);
+      importingLibrary.addToScope(prefixElement, reporter);
       importedLibrary.forEachExport((Element element) {
         if (combinatorFilter.exclude(element)) return;
-        prefixElement.addImport(element, import, compiler);
+        prefixElement.addImport(element, import, reporter);
       });
       import.prefix = prefixElement;
       if (prefixElement.isDeferred) {
         prefixElement.addImport(
             new DeferredLoaderGetterElementX(prefixElement),
-            import, compiler);
+            import, reporter);
       }
     } else {
       importedLibrary.forEachExport((Element element) {
-        compiler.withCurrentElement(importingLibrary, () {
+        reporter.withCurrentElement(importingLibrary, () {
           if (combinatorFilter.exclude(element)) return;
-          importingLibrary.addImport(element, import, compiler);
+          importingLibrary.addImport(element, import, reporter);
         });
       });
     }
@@ -885,7 +886,7 @@
   ///
   /// Additionally, check that all names in the show/hide combinators are in the
   /// export scope of [exportedLibraryElement].
-  void registerHandledExports(DiagnosticListener listener,
+  void registerHandledExports(DiagnosticReporter reporter,
                               LibraryElement exportedLibraryElement,
                               ExportElementX export,
                               CombinatorFilter filter) {
@@ -898,9 +899,11 @@
         pendingExportMap[exportedElement] = exports.prepend(export);
       }
     });
-    listener.withCurrentElement(library, () {
-      checkLibraryDependency(listener, export.node, exportedLibraryElement);
-    });
+    if (!reporter.options.suppressHints) {
+      reporter.withCurrentElement(library, () {
+        checkLibraryDependency(reporter, export.node, exportedLibraryElement);
+      });
+    }
   }
 
   /**
@@ -913,9 +916,9 @@
   /**
    * Registers the imports of the node library.
    */
-  void registerImports(Compiler compiler) {
+  void registerImports(DiagnosticReporter reporter) {
     for (ImportLink link in imports) {
-      link.importLibrary(compiler, library);
+      link.importLibrary(reporter, library);
     }
   }
 
@@ -933,8 +936,10 @@
    * Adds [element] to the export scope for this node. If the [element] name
    * is a duplicate, an error element is inserted into the export scope.
    */
-  Element addElementToExportScope(Compiler compiler, Element element,
-                                  Link<ExportElement> exports) {
+  Element addElementToExportScope(
+      DiagnosticReporter reporter,
+      Element element,
+      Link<ExportElement> exports) {
     String name = element.name;
     DiagnosticMessage error;
     List<DiagnosticMessage> infos = <DiagnosticMessage>[];
@@ -945,15 +950,15 @@
       assert(invariant(library, !duplicateExports.isEmpty,
           message: "No export for $duplicate from ${duplicate.library} "
                    "in $library."));
-      compiler.withCurrentElement(library, () {
+      reporter.withCurrentElement(library, () {
         for (ExportElement export in duplicateExports) {
           if (error == null) {
-            error = compiler.createMessage(
+            error = reporter.createMessage(
                 export,
                 MessageKind.DUPLICATE_EXPORT,
                 {'name': name});
           } else {
-            infos.add(compiler.createMessage(
+            infos.add(reporter.createMessage(
                 export,
                 MessageKind.DUPLICATE_EXPORT_CONT,
                 {'name': name}));
@@ -968,7 +973,7 @@
       assert(invariant(library, !duplicateExports.isEmpty,
           message: "No export for $duplicate from ${duplicate.library} "
                    "in $library."));
-      infos.add(compiler.createMessage(
+      infos.add(reporter.createMessage(
           duplicate,
               MessageKind.DUPLICATE_EXPORT_DECL,
           {'name': name, 'uriString': duplicateExports.head.uri}));
@@ -1001,7 +1006,7 @@
       exporters[element] = exports;
     }
     if (error != null) {
-      compiler.reportError(error, infos);
+      reporter.reportError(error, infos);
     }
     return element;
   }
@@ -1040,37 +1045,52 @@
 
   /// Check that all names in the show/hide combinators of imports and exports
   /// are in the export scope of the imported/exported libraries.
-  void checkCombinators(DiagnosticListener listener) {
-    listener.withCurrentElement(library, () {
+  void checkCombinators(DiagnosticReporter reporter) {
+    reporter.withCurrentElement(library, () {
       for (ImportLink importLink in imports) {
         checkLibraryDependency(
-            listener, importLink.import.node, importLink.importedLibrary);
+            reporter, importLink.import.node, importLink.importedLibrary);
       }
     });
     for (ExportLink exportLink in dependencies) {
-      listener.withCurrentElement(exportLink.exportNode.library, () {
-        checkLibraryDependency(listener, exportLink.export.node, library);
+      reporter.withCurrentElement(exportLink.exportNode.library, () {
+        checkLibraryDependency(reporter, exportLink.export.node, library);
       });
     }
   }
 
   /// Check that all names in the show/hide combinators of [tag] are in the
   /// export scope of [library].
-  void checkLibraryDependency(DiagnosticListener listener,
-                              LibraryDependency tag,
-                              LibraryElement library) {
+  void checkLibraryDependency(
+      DiagnosticReporter reporter,
+      LibraryDependency tag,
+      LibraryElement library) {
     if (tag == null || tag.combinators == null) return;
     for (Combinator combinator in tag.combinators) {
       for (Identifier identifier in combinator.identifiers) {
         String name = identifier.source;
         Element element = library.findExported(name);
         if (element == null) {
-          listener.reportHintMessage(
-              identifier,
-              combinator.isHide
-                  ? MessageKind.EMPTY_HIDE : MessageKind.EMPTY_SHOW,
-              {'uri': library.canonicalUri,
-               'name': name});
+          if (combinator.isHide) {
+            if (library.isPackageLibrary &&
+                !reporter.options.showPackageWarnings) {
+              // Only report hide hint on packages if we show warnings on these:
+              // The hide may be non-empty in some versions of the package, in
+              // which case you shouldn't remove the combinator.
+              continue;
+            }
+            reporter.reportHintMessage(
+                identifier,
+                MessageKind.EMPTY_HIDE,
+                {'uri': library.canonicalUri,
+                 'name': name});
+          } else {
+            reporter.reportHintMessage(
+                identifier,
+                MessageKind.EMPTY_SHOW,
+                {'uri': library.canonicalUri,
+                 'name': name});
+          }
         }
       }
     }
@@ -1102,6 +1122,8 @@
 
   Compiler get compiler => task.compiler;
 
+  DiagnosticReporter get reporter => task.reporter;
+
   /// The libraries loaded with this handler.
   Iterable<LibraryElement> get loadedLibraries => nodeMap.keys;
 
@@ -1130,7 +1152,7 @@
       tasks.forEach((LibraryDependencyNode node,
                      Map<Element, Link<ExportElement>> pendingExports) {
         pendingExports.forEach((Element element, Link<ExportElement> exports) {
-          element = node.addElementToExportScope(compiler, element, exports);
+          element = node.addElementToExportScope(reporter, element, exports);
           if (node.propagateElement(element)) {
             changed = true;
           }
@@ -1147,12 +1169,14 @@
 
     // Setup import scopes.
     nodeMap.forEach((LibraryElement library, LibraryDependencyNode node) {
-      node.registerImports(compiler);
+      node.registerImports(reporter);
     });
 
-    nodeMap.forEach((LibraryElement library, LibraryDependencyNode node) {
-      node.checkCombinators(compiler);
-    });
+    if (!reporter.options.suppressHints) {
+      nodeMap.forEach((LibraryElement library, LibraryDependencyNode node) {
+        node.checkCombinators(reporter);
+      });
+    }
   }
 
   /// Registers that [library] depends on [loadedLibrary] through
@@ -1168,7 +1192,7 @@
         CombinatorFilter combinatorFilter =
             new CombinatorFilter.fromTag(libraryDependency.node);
         exportingNode.registerHandledExports(
-            compiler, loadedLibrary, libraryDependency, combinatorFilter);
+            reporter, loadedLibrary, libraryDependency, combinatorFilter);
         return;
       }
       LibraryDependencyNode exportedNode = nodeMap[loadedLibrary];
diff --git a/pkg/compiler/lib/src/mirrors/dart2js_instance_mirrors.dart b/pkg/compiler/lib/src/mirrors/dart2js_instance_mirrors.dart
index 9a2cbe2..55d8789 100644
--- a/pkg/compiler/lib/src/mirrors/dart2js_instance_mirrors.dart
+++ b/pkg/compiler/lib/src/mirrors/dart2js_instance_mirrors.dart
@@ -56,7 +56,7 @@
   } else if (value.isConstructedObject) {
     return new Dart2JsConstructedConstantMirror(mirrorSystem, constant, value);
   }
-  mirrorSystem.compiler.internalError(NO_LOCATION_SPANNABLE,
+  mirrorSystem.compiler.reporter.internalError(NO_LOCATION_SPANNABLE,
       "Unexpected constant value $value");
   return null;
 }
diff --git a/pkg/compiler/lib/src/mirrors/dart2js_library_mirror.dart b/pkg/compiler/lib/src/mirrors/dart2js_library_mirror.dart
index 2d43e7d..feaf549 100644
--- a/pkg/compiler/lib/src/mirrors/dart2js_library_mirror.dart
+++ b/pkg/compiler/lib/src/mirrors/dart2js_library_mirror.dart
@@ -126,7 +126,7 @@
   SourceLocation get location {
     return new Dart2JsSourceLocation(
       _sourceLibrary._element.entryCompilationUnit.script,
-      _sourceLibrary.mirrorSystem.compiler.spanFromNode(_node));
+      _sourceLibrary.mirrorSystem.compiler.reporter.spanFromSpannable(_node));
   }
 
   List<CombinatorMirror> get combinators {
diff --git a/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart b/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart
index 3834728..247e3f5 100644
--- a/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart
+++ b/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart
@@ -135,7 +135,7 @@
       }
       return members;
     }
-    mirrorSystem.compiler.internalError(element,
+    mirrorSystem.compiler.reporter.internalError(element,
         "Unexpected member type $element ${element.kind}.");
     return null;
   }
@@ -208,8 +208,8 @@
       span = new SourceSpan(script.resourceUri, 0, 0);
     } else {
       Token endToken = getEndToken();
-      span = mirrorSystem.compiler.spanFromTokens(
-          beginToken, endToken, script.resourceUri);
+      span = new SourceSpan.fromTokens(
+          script.resourceUri, beginToken, endToken);
     }
     return new Dart2JsSourceLocation(script, span);
   }
@@ -230,7 +230,7 @@
       for (MetadataAnnotation metadata in _element.metadata) {
         _appendCommentTokens(
             mirrorSystem.compiler.commentMap[metadata.beginToken]);
-        metadata.ensureResolved(mirrorSystem.compiler);
+        metadata.ensureResolved(mirrorSystem.compiler.resolution);
         _metadata.add(_convertConstantToInstanceMirror(
             mirrorSystem, metadata.constant,
             mirrorSystem.compiler.constants.getConstantValue(
@@ -348,7 +348,7 @@
         return new Dart2JsTypedefMirror(this, type);
       }
     }
-    compiler.internalError(type.element,
+    compiler.reporter.internalError(type.element,
         "Unexpected type $type of kind ${type.kind}.");
     return null;
   }
@@ -359,7 +359,7 @@
     } else if (element.isTypedef) {
       return new Dart2JsTypedefDeclarationMirror(this, element.thisType);
     }
-    compiler.internalError(element, "Unexpected element $element.");
+    compiler.reporter.internalError(element, "Unexpected element $element.");
     return null;
   }
 }
diff --git a/pkg/compiler/lib/src/mirrors_used.dart b/pkg/compiler/lib/src/mirrors_used.dart
index 2110d75..8a72eff 100644
--- a/pkg/compiler/lib/src/mirrors_used.dart
+++ b/pkg/compiler/lib/src/mirrors_used.dart
@@ -21,6 +21,8 @@
     DartType,
     InterfaceType,
     TypeKind;
+import 'diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import 'diagnostics/messages.dart' show
     MessageKind;
 import 'diagnostics/spannable.dart' show
@@ -174,6 +176,8 @@
         cachedStrings = new Map<ConstantValue, List<String>>(),
         cachedElements = new Map<ConstantValue, List<Element>>();
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   /// Collect and merge all @MirrorsUsed annotations. As a side-effect, also
   /// compute which libraries have the annotation (which is used by
   /// [MirrorUsageAnalyzerTask.hasMirrorUsage]).
@@ -201,7 +205,7 @@
     for (LibraryElement library in compiler.libraryLoader.libraries) {
       if (library.isInternalLibrary) continue;
       for (ImportElement import in library.imports) {
-        compiler.withCurrentElement(library, () {
+        reporter.withCurrentElement(library, () {
           List<MirrorUsage> usages =
               mirrorsUsedOnLibraryTag(library, import);
           if (usages != null) {
@@ -261,7 +265,7 @@
     }
     List<MirrorUsage> result = <MirrorUsage>[];
     for (MetadataAnnotation metadata in import.metadata) {
-      metadata.ensureResolved(compiler);
+      metadata.ensureResolved(compiler.resolution);
       ConstantValue value =
           compiler.constants.getConstantValue(metadata.constant);
       Element element = value.getType(compiler.coreTypes).element;
@@ -382,6 +386,8 @@
 
   Compiler get compiler => analyzer.compiler;
 
+  DiagnosticReporter get reporter => analyzer.reporter;
+
   /// Convert a constant to a list of [String] and [Type] values. If the
   /// constant is a single [String], it is assumed to be a comma-separated list
   /// of qualified names. If the constant is a [Type] t, the result is [:[t]:].
@@ -409,7 +415,7 @@
           MessageKind kind = onlyStrings
               ? MessageKind.MIRRORS_EXPECTED_STRING
               : MessageKind.MIRRORS_EXPECTED_STRING_OR_TYPE;
-          compiler.reportHintMessage(
+          reporter.reportHintMessage(
               node, kind, {'name': node, 'type': apiTypeOf(entry)});
         }
       }
@@ -427,7 +433,7 @@
       MessageKind kind = onlyStrings
           ? MessageKind.MIRRORS_EXPECTED_STRING_OR_LIST
           : MessageKind.MIRRORS_EXPECTED_STRING_TYPE_OR_LIST;
-      compiler.reportHintMessage(
+      reporter.reportHintMessage(
           node, kind, {'name': node, 'type': apiTypeOf(constant)});
       return null;
     }
@@ -440,7 +446,7 @@
     if (type.isInterfaceType && library.isInternalLibrary) {
       InterfaceType interface = type;
       ClassElement cls = type.element;
-      cls.ensureResolved(compiler);
+      cls.ensureResolved(compiler.resolution);
       for (DartType supertype in cls.allSupertypes) {
         if (supertype.isInterfaceType
             && !supertype.element.library.isInternalLibrary) {
@@ -511,7 +517,7 @@
     List<String> identifiers = expression.split('.');
     Element element = enclosingLibrary.find(identifiers[0]);
     if (element == null) {
-      compiler.reportHintMessage(
+      reporter.reportHintMessage(
           spannable,
           MessageKind.MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY,
           {'name': expression});
@@ -530,12 +536,12 @@
       if (e == null) {
         if (current.isLibrary) {
           LibraryElement library = current;
-          compiler.reportHintMessage(
+          reporter.reportHintMessage(
               spannable, MessageKind.MIRRORS_CANNOT_RESOLVE_IN_LIBRARY,
               {'name': identifiers[0],
                'library': library.libraryOrScriptName});
         } else {
-          compiler.reportHintMessage(
+          reporter.reportHintMessage(
               spannable, MessageKind.MIRRORS_CANNOT_FIND_IN_ELEMENT,
               {'name': identifier, 'element': current.name});
         }
@@ -553,7 +559,7 @@
       ScopeContainerElement scope = element;
       if (element.isClass) {
         ClassElement cls = element;
-        cls.ensureResolved(compiler);
+        cls.ensureResolved(compiler.resolution);
       }
       return scope.localLookup(name);
     }
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index dfb2c60..c742a7d 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -196,7 +196,7 @@
   /// latter is used for the type strings of the form '' and 'var'.
   /// [validTags] can be used to restrict which tags are accepted.
   static void processSpecString(
-      DiagnosticListener listener,
+      DiagnosticReporter reporter,
       Spannable spannable,
       String specString,
       {Iterable<String> validTags,
@@ -214,7 +214,7 @@
 
     void reportError(String message) {
       seenError = true;
-      listener.reportErrorMessage(
+      reporter.reportErrorMessage(
           spannable, MessageKind.GENERIC, {'text': message});
     }
 
@@ -424,7 +424,12 @@
     return sideEffects;
   }
 
-  static NativeBehavior ofJsCall(Send jsCall, Compiler compiler, resolver) {
+  static NativeBehavior ofJsCall(
+      Send jsCall,
+      DiagnosticReporter reporter,
+      Parsing parsing,
+      CoreTypes coreTypes,
+      ForeignResolver resolver) {
     // The first argument of a JS-call is a string encoding various attributes
     // of the code.
     //
@@ -435,7 +440,7 @@
 
     var argNodes = jsCall.arguments;
     if (argNodes.isEmpty || argNodes.tail.isEmpty) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           jsCall,
           MessageKind.GENERIC,
           {'text': "JS expression takes two or more arguments."});
@@ -444,7 +449,7 @@
 
     var specArgument = argNodes.head;
     if (specArgument is !StringNode || specArgument.isInterpolation) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           specArgument, MessageKind.GENERIC,
           {'text': "JS first argument must be a string literal."});
       return behavior;
@@ -452,7 +457,7 @@
 
     var codeArgument = argNodes.tail.head;
     if (codeArgument is !StringNode || codeArgument.isInterpolation) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           codeArgument, MessageKind.GENERIC,
           {'text': "JS second argument must be a string literal."});
       return behavior;
@@ -466,7 +471,7 @@
     dynamic resolveType(String typeString) {
       return _parseType(
           typeString,
-          compiler,
+          parsing,
           (name) => resolver.resolveTypeFromString(specArgument, name),
           specArgument);
     }
@@ -492,7 +497,9 @@
       behavior.useGvn = useGvn;
     }
 
-    processSpecString(compiler, specArgument,
+    processSpecString(
+        reporter,
+        specArgument,
         specString,
         setSideEffects: setSideEffects,
         setThrows: setThrows,
@@ -501,8 +508,8 @@
         resolveType: resolveType,
         typesReturned: behavior.typesReturned,
         typesInstantiated: behavior.typesInstantiated,
-        objectType: compiler.objectClass.computeType(compiler),
-        nullType: compiler.nullClass.computeType(compiler));
+        objectType: coreTypes.objectType,
+        nullType: coreTypes.nullType);
 
     if (!sideEffectsAreEncodedInSpecString) {
       new SideEffectsVisitor(behavior.sideEffects)
@@ -519,8 +526,10 @@
   static void _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal(
       NativeBehavior behavior,
       Send jsBuiltinOrEmbeddedGlobalCall,
-      Compiler compiler,
-      ResolverVisitor resolver,
+      DiagnosticReporter reporter,
+      Parsing parsing,
+      CoreTypes coreTypes,
+      ForeignResolver resolver,
       {bool isBuiltin,
        List<String> validTags}) {
     // The first argument of a JS-embedded global call is a string encoding
@@ -533,7 +542,7 @@
 
     Link<Node> argNodes = jsBuiltinOrEmbeddedGlobalCall.arguments;
     if (argNodes.isEmpty) {
-      compiler.internalError(jsBuiltinOrEmbeddedGlobalCall,
+      reporter.internalError(jsBuiltinOrEmbeddedGlobalCall,
           "JS $builtinOrGlobal expression has no type.");
     }
 
@@ -541,13 +550,13 @@
     // This is, because we want to allow non-literals (like references to
     // enums) as names.
     if (argNodes.tail.isEmpty) {
-      compiler.internalError(jsBuiltinOrEmbeddedGlobalCall,
+      reporter.internalError(jsBuiltinOrEmbeddedGlobalCall,
           'JS $builtinOrGlobal is missing name.');
     }
 
     if (!isBuiltin) {
       if (!argNodes.tail.tail.isEmpty) {
-        compiler.internalError(argNodes.tail.tail.head,
+        reporter.internalError(argNodes.tail.tail.head,
             'JS embedded global has more than 2 arguments');
       }
     }
@@ -556,7 +565,7 @@
     if (specLiteral == null) {
       // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2').  It
       // is not very satisfactory because it does not work for void, dynamic.
-      compiler.internalError(argNodes.head, "Unexpected first argument.");
+      reporter.internalError(argNodes.head, "Unexpected first argument.");
     }
 
     String specString = specLiteral.dartString.slowToString();
@@ -564,7 +573,7 @@
     dynamic resolveType(String typeString) {
       return _parseType(
           typeString,
-          compiler,
+          parsing,
           (name) => resolver.resolveTypeFromString(specLiteral, name),
           jsBuiltinOrEmbeddedGlobalCall);
     }
@@ -573,32 +582,46 @@
       behavior.sideEffects.setTo(newEffects);
     }
 
-    processSpecString(compiler, jsBuiltinOrEmbeddedGlobalCall,
-                      specString,
-                      validTags: validTags,
-                      resolveType: resolveType,
-                      setSideEffects: setSideEffects,
-                      typesReturned: behavior.typesReturned,
-                      typesInstantiated: behavior.typesInstantiated,
-                      objectType: compiler.objectClass.computeType(compiler),
-                      nullType: compiler.nullClass.computeType(compiler));
+    processSpecString(
+        reporter,
+        jsBuiltinOrEmbeddedGlobalCall,
+        specString,
+        validTags: validTags,
+        resolveType: resolveType,
+        setSideEffects: setSideEffects,
+        typesReturned: behavior.typesReturned,
+        typesInstantiated: behavior.typesInstantiated,
+        objectType: coreTypes.objectType,
+        nullType: coreTypes.nullType);
   }
 
-  static NativeBehavior ofJsBuiltinCall(Send jsBuiltinCall,
-                                        Compiler compiler,
-                                        ResolverVisitor resolver) {
+  static NativeBehavior ofJsBuiltinCall(
+      Send jsBuiltinCall,
+      DiagnosticReporter reporter,
+      Parsing parsing,
+      CoreTypes coreTypes,
+      ForeignResolver resolver) {
     NativeBehavior behavior = new NativeBehavior();
     behavior.sideEffects.setTo(new SideEffects());
 
     _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal(
-        behavior, jsBuiltinCall, compiler, resolver, isBuiltin: true);
+        behavior,
+        jsBuiltinCall,
+        reporter,
+        parsing,
+        coreTypes,
+        resolver,
+        isBuiltin: true);
 
     return behavior;
   }
 
-  static NativeBehavior ofJsEmbeddedGlobalCall(Send jsEmbeddedGlobalCall,
-                                               Compiler compiler,
-                                               ResolverVisitor resolver) {
+  static NativeBehavior ofJsEmbeddedGlobalCall(
+      Send jsEmbeddedGlobalCall,
+      DiagnosticReporter reporter,
+      Parsing parsing,
+      CoreTypes coreTypes,
+      ForeignResolver resolver) {
     NativeBehavior behavior = new NativeBehavior();
     // TODO(sra): Allow the use site to override these defaults.
     // Embedded globals are usually pre-computed data structures or JavaScript
@@ -607,29 +630,34 @@
     behavior.throwBehavior = NativeThrowBehavior.NEVER;
 
     _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal(
-        behavior, jsEmbeddedGlobalCall, compiler, resolver,
+        behavior,
+        jsEmbeddedGlobalCall,
+        reporter,
+        parsing,
+        coreTypes,
+        resolver,
         isBuiltin: false,
         validTags: const ['returns', 'creates']);
 
     return behavior;
   }
 
-  static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) {
-    FunctionType type = method.computeType(compiler);
+  static NativeBehavior ofMethod(FunctionElement method,  Compiler compiler) {
+    FunctionType type = method.computeType(compiler.resolution);
     var behavior = new NativeBehavior();
     behavior.typesReturned.add(type.returnType);
     if (!type.returnType.isVoid) {
       // Declared types are nullable.
-      behavior.typesReturned.add(compiler.nullClass.computeType(compiler));
+      behavior.typesReturned.add(compiler.coreTypes.nullType);
     }
-    behavior._capture(type, compiler);
+    behavior._capture(type, compiler.resolution);
 
     // TODO(sra): Optional arguments are currently missing from the
     // DartType. This should be fixed so the following work-around can be
     // removed.
     method.functionSignature.forEachOptionalParameter(
         (ParameterElement parameter) {
-          behavior._escape(parameter.type, compiler);
+          behavior._escape(parameter.type, compiler.resolution);
         });
 
     behavior._overrideWithAnnotations(method, compiler);
@@ -637,20 +665,22 @@
   }
 
   static NativeBehavior ofFieldLoad(MemberElement field, Compiler compiler) {
-    DartType type = field.computeType(compiler);
+    Resolution resolution = compiler.resolution;
+    DartType type = field.computeType(resolution);
     var behavior = new NativeBehavior();
     behavior.typesReturned.add(type);
     // Declared types are nullable.
-    behavior.typesReturned.add(compiler.nullClass.computeType(compiler));
-    behavior._capture(type, compiler);
+    behavior.typesReturned.add(resolution.coreTypes.nullType);
+    behavior._capture(type, resolution);
     behavior._overrideWithAnnotations(field, compiler);
     return behavior;
   }
 
   static NativeBehavior ofFieldStore(MemberElement field, Compiler compiler) {
-    DartType type = field.computeType(compiler);
+    Resolution resolution = compiler.resolution;
+    DartType type = field.computeType(resolution);
     var behavior = new NativeBehavior();
-    behavior._escape(type, compiler);
+    behavior._escape(type, resolution);
     // We don't override the default behaviour - the annotations apply to
     // loading the field.
     return behavior;
@@ -664,7 +694,7 @@
       if (e == null) return null;
       if (e is! ClassElement) return null;
       ClassElement cls = e;
-      cls.ensureResolved(compiler);
+      cls.ensureResolved(compiler.resolution);
       return cls.thisType;
     }
 
@@ -689,9 +719,10 @@
    */
   static _collect(Element element, Compiler compiler, Element annotationClass,
                   lookup(str)) {
+    DiagnosticReporter reporter = compiler.reporter;
     var types = null;
     for (MetadataAnnotation annotation in element.implementation.metadata) {
-      annotation.ensureResolved(compiler);
+      annotation.ensureResolved(compiler.resolution);
       ConstantValue value =
           compiler.constants.getConstantValue(annotation.constant);
       if (!value.isConstructedObject) continue;
@@ -701,14 +732,13 @@
       Iterable<ConstantValue> fields = constructedObject.fields.values;
       // TODO(sra): Better validation of the constant.
       if (fields.length != 1 || !fields.single.isString) {
-        PartialMetadataAnnotation partial = annotation;
-        compiler.internalError(annotation,
-            'Annotations needs one string: ${partial.parseNode(compiler)}');
+        reporter.internalError(annotation,
+            'Annotations needs one string: ${annotation.node}');
       }
       StringConstantValue specStringConstant = fields.single;
       String specString = specStringConstant.toDartString().slowToString();
       for (final typeString in specString.split('|')) {
-        var type = _parseType(typeString, compiler, lookup, annotation);
+        var type = _parseType(typeString, compiler.parsing, lookup, annotation);
         if (types == null) types = [];
         types.add(type);
       }
@@ -718,15 +748,15 @@
 
   /// Models the behavior of having intances of [type] escape from Dart code
   /// into native code.
-  void _escape(DartType type, Compiler compiler) {
-    type = type.unalias(compiler);
+  void _escape(DartType type, Resolution resolution) {
+    type = type.unalias(resolution);
     if (type is FunctionType) {
       FunctionType functionType = type;
       // A function might be called from native code, passing us novel
       // parameters.
-      _escape(functionType.returnType, compiler);
+      _escape(functionType.returnType, resolution);
       for (DartType parameter in functionType.parameterTypes) {
-        _capture(parameter, compiler);
+        _capture(parameter, resolution);
       }
     }
   }
@@ -734,21 +764,24 @@
   /// 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, Compiler compiler) {
-    type = type.unalias(compiler);
+  void _capture(DartType type, Resolution resolution) {
+    type = type.unalias(resolution);
     if (type is FunctionType) {
       FunctionType functionType = type;
-      _capture(functionType.returnType, compiler);
+      _capture(functionType.returnType, resolution);
       for (DartType parameter in functionType.parameterTypes) {
-        _escape(parameter, compiler);
+        _escape(parameter, resolution);
       }
     } else {
       typesInstantiated.add(type);
     }
   }
 
-  static dynamic _parseType(String typeString, Compiler compiler,
+  static dynamic _parseType(
+      String typeString,
+      Parsing parsing,
       lookup(name), locationNodeOrElement) {
+    DiagnosticReporter reporter = parsing.reporter;
     if (typeString == '=Object') return SpecialType.JsObject;
     if (typeString == 'dynamic') {
       return const DynamicType();
@@ -758,8 +791,8 @@
 
     int index = typeString.indexOf('<');
     if (index < 1) {
-      compiler.reportErrorMessage(
-          _errorNode(locationNodeOrElement, compiler),
+      reporter.reportErrorMessage(
+          _errorNode(locationNodeOrElement, parsing),
           MessageKind.GENERIC,
           {'text': "Type '$typeString' not found."});
       return const DynamicType();
@@ -769,15 +802,15 @@
       // TODO(sra): Parse type parameters.
       return type;
     }
-    compiler.reportErrorMessage(
-        _errorNode(locationNodeOrElement, compiler),
+    reporter.reportErrorMessage(
+        _errorNode(locationNodeOrElement, parsing),
         MessageKind.GENERIC,
         {'text': "Type '$typeString' not found."});
     return const DynamicType();
   }
 
-  static _errorNode(locationNodeOrElement, compiler) {
+  static _errorNode(locationNodeOrElement, Parsing parsing) {
     if (locationNodeOrElement is Node) return locationNodeOrElement;
-    return locationNodeOrElement.parseNode(compiler);
+    return locationNodeOrElement.parseNode(parsing);
   }
 }
diff --git a/pkg/compiler/lib/src/native/enqueue.dart b/pkg/compiler/lib/src/native/enqueue.dart
index 25a4b26..6b39359 100644
--- a/pkg/compiler/lib/src/native/enqueue.dart
+++ b/pkg/compiler/lib/src/native/enqueue.dart
@@ -34,42 +34,6 @@
   /// Returns whether native classes are being used.
   bool hasInstantiatedNativeClasses() => false;
 
-  /**
-   * Handles JS-calls, which can be an instantiation point for types.
-   *
-   * For example, the following code instantiates and returns native classes
-   * that are `_DOMWindowImpl` or a subtype.
-   *
-   *     JS('_DOMWindowImpl', 'window')
-   *
-   */
-  // TODO(sra): The entry from codegen will not have a resolver.
-  void registerJsCall(Send node, ResolverVisitor resolver) {}
-
-  /**
-   * Handles JS-embedded global calls, which can be an instantiation point for
-   * types.
-   *
-   * For example, the following code instantiates and returns a String class
-   *
-   *     JS_EMBEDDED_GLOBAL('String', 'foo')
-   *
-   */
-  // TODO(sra): The entry from codegen will not have a resolver.
-  void registerJsEmbeddedGlobalCall(Send node, ResolverVisitor resolver) {}
-
-  /**
-   * Handles JS-compiler builtin calls, which can be an instantiation point for
-   * types.
-   *
-   * For example, the following code instantiates and returns a String class
-   *
-   *     JS_BUILTIN('String', 'int2string', 0)
-   *
-   */
-  // TODO(sra): The entry from codegen will not have a resolver.
-  void registerJsBuiltinCall(Send node, ResolverVisitor resolver) {}
-
   /// Emits a summary information using the [log] function.
   void logSummary(log(message)) {}
 
@@ -131,6 +95,9 @@
         processedLibraries = compiler.cacheStrategy.newSet();
 
   JavaScriptBackend get backend => compiler.backend;
+  Resolution get resolution => compiler.resolution;
+
+  DiagnosticReporter get reporter => compiler.reporter;
 
   void processNativeClasses(Iterable<LibraryElement> libraries) {
     if (compiler.hasIncrementalSupport) {
@@ -163,7 +130,7 @@
     nativeClasses.add(classElement);
     unusedClasses.add(classElement);
     // Resolve class to ensure the class has valid inheritance info.
-    classElement.ensureResolved(compiler);
+    classElement.ensureResolved(resolution);
   }
 
   void processSubclassesOfNativeClasses(Iterable<LibraryElement> libraries) {
@@ -202,7 +169,7 @@
 
     void walkPotentialSubclasses(ClassElement element) {
       if (nativeClassesAndSubclasses.contains(element)) return;
-      element.ensureResolved(compiler);
+      element.ensureResolved(resolution);
       ClassElement nativeSuperclass = nativeSuperclassOf(element);
       if (nativeSuperclass != null) {
         nativeClassesAndSubclasses.add(element);
@@ -278,7 +245,7 @@
       return id.value;
     }
 
-    return compiler.withCurrentElement(classElement, () {
+    return reporter.withCurrentElement(classElement, () {
       return scanForExtendsName(classElement.position);
     });
   }
@@ -303,7 +270,7 @@
     ClassElement find(name) {
       Element e = backend.findHelper(name);
       if (e == null || e is! ClassElement) {
-        compiler.internalError(NO_LOCATION_SPANNABLE,
+        reporter.internalError(NO_LOCATION_SPANNABLE,
             "Could not find implementation class '${name}'.");
       }
       return e;
@@ -319,7 +286,7 @@
     String name = null;
     ClassElement annotationClass = annotationJsNameClass;
     for (MetadataAnnotation annotation in element.implementation.metadata) {
-      annotation.ensureResolved(compiler);
+      annotation.ensureResolved(resolution);
       ConstantValue value =
           compiler.constants.getConstantValue(annotation.constant);
       if (!value.isConstructedObject) continue;
@@ -329,18 +296,16 @@
       Iterable<ConstantValue> fields = constructedObject.fields.values;
       // TODO(sra): Better validation of the constant.
       if (fields.length != 1 || fields.single is! StringConstantValue) {
-        PartialMetadataAnnotation partial = annotation;
-        compiler.internalError(annotation,
-            'Annotations needs one string: ${partial.parseNode(compiler)}');
+        reporter.internalError(annotation,
+            'Annotations needs one string: ${annotation.node}');
       }
       StringConstantValue specStringConstant = fields.single;
       String specString = specStringConstant.toDartString().slowToString();
       if (name == null) {
         name = specString;
       } else {
-        PartialMetadataAnnotation partial = annotation;
-        compiler.internalError(annotation,
-            'Too many JSName annotations: ${partial.parseNode(compiler)}');
+        reporter.internalError(annotation,
+            'Too many JSName annotations: ${annotation.node}');
       }
     }
     return name;
@@ -372,21 +337,17 @@
     registeredClasses.add(classElement);
 
     // TODO(ahe): Is this really a global dependency?
-    classElement.ensureResolved(compiler);
+    classElement.ensureResolved(resolution);
     compiler.backend.registerInstantiatedType(
         classElement.rawType, world, compiler.globalDependencies);
 
-    // Also parse the node to know all its methods because otherwise it will
-    // only be parsed if there is a call to one of its constructors.
-    classElement.parseNode(compiler);
-
     if (firstTime) {
       queue.add(onFirstNativeClass);
     }
   }
 
   registerElement(Element element) {
-    compiler.withCurrentElement(element, () {
+    reporter.withCurrentElement(element, () {
       if (element.isFunction || element.isGetter || element.isSetter) {
         handleMethodAnnotations(element);
         if (element.isNative) {
@@ -446,7 +407,7 @@
     if (isIdentifier(name)) {
       List<String> nativeNames = nativeTagsOfClassRaw(element.enclosingClass);
       if (nativeNames.length != 1) {
-        compiler.internalError(element,
+        reporter.internalError(element,
             'Unable to determine a native name for the enclosing class, '
             'options: $nativeNames');
       }
@@ -461,8 +422,8 @@
   bool isNativeMethod(FunctionElementX element) {
     if (!element.library.canUseNative) return false;
     // Native method?
-    return compiler.withCurrentElement(element, () {
-      Node node = element.parseNode(compiler);
+    return reporter.withCurrentElement(element, () {
+      Node node = element.parseNode(resolution.parsing);
       if (node is! FunctionExpression) return false;
       FunctionExpression functionExpression = node;
       node = functionExpression.body;
@@ -489,26 +450,6 @@
     registerNativeBehavior(NativeBehavior.ofFieldStore(field, compiler), field);
   }
 
-  void registerJsCall(Send node, ResolverVisitor resolver) {
-    NativeBehavior behavior = NativeBehavior.ofJsCall(node, compiler, resolver);
-    registerNativeBehavior(behavior, node);
-    nativeBehaviors[node] = behavior;
-  }
-
-  void registerJsEmbeddedGlobalCall(Send node, ResolverVisitor resolver) {
-    NativeBehavior behavior =
-        NativeBehavior.ofJsEmbeddedGlobalCall(node, compiler, resolver);
-    registerNativeBehavior(behavior, node);
-    nativeBehaviors[node] = behavior;
-  }
-
-  void registerJsBuiltinCall(Send node, ResolverVisitor resolver) {
-    NativeBehavior behavior =
-        NativeBehavior.ofJsBuiltinCall(node, compiler, resolver);
-    registerNativeBehavior(behavior, node);
-    nativeBehaviors[node] = behavior;
-  }
-
   NativeBehavior getNativeBehaviorOf(Send node) => nativeBehaviors[node];
 
   processNativeBehavior(NativeBehavior behavior, cause) {
@@ -556,7 +497,7 @@
     // Give an info so that library developers can compile with -v to find why
     // all the native classes are included.
     if (unusedClasses.isEmpty && !allUsedBefore) {
-      compiler.log('All native types marked as used due to $cause.');
+      reporter.log('All native types marked as used due to $cause.');
     }
   }
 
@@ -609,7 +550,7 @@
       ClassElement owner = tagOwner[tag];
       if (owner != null) {
         if (owner != classElement) {
-          compiler.internalError(
+          reporter.internalError(
               classElement, "Tag '$tag' already in use by '${owner.name}'");
         }
       } else {
@@ -622,6 +563,56 @@
     log('Resolved ${registeredClasses.length} native elements used, '
         '${unusedClasses.length} native elements dead.');
   }
+
+  /**
+   * Handles JS-calls, which can be an instantiation point for types.
+   *
+   * For example, the following code instantiates and returns native classes
+   * that are `_DOMWindowImpl` or a subtype.
+   *
+   *     JS('_DOMWindowImpl', 'window')
+   *
+   */
+  void registerJsCall(Send node, ForeignResolver resolver) {
+    NativeBehavior behavior = NativeBehavior.ofJsCall(
+        node, reporter, compiler.parsing, compiler.coreTypes, resolver);
+    registerNativeBehavior(behavior, node);
+    nativeBehaviors[node] = behavior;
+  }
+
+
+  /**
+   * Handles JS-embedded global calls, which can be an instantiation point for
+   * types.
+   *
+   * For example, the following code instantiates and returns a String class
+   *
+   *     JS_EMBEDDED_GLOBAL('String', 'foo')
+   *
+   */
+  void registerJsEmbeddedGlobalCall(Send node, ForeignResolver resolver) {
+    NativeBehavior behavior = NativeBehavior.ofJsEmbeddedGlobalCall(
+        node, reporter, compiler.parsing, compiler.coreTypes, resolver);
+    registerNativeBehavior(behavior, node);
+    nativeBehaviors[node] = behavior;
+  }
+
+
+  /**
+   * Handles JS-compiler builtin calls, which can be an instantiation point for
+   * types.
+   *
+   * For example, the following code instantiates and returns a String class
+   *
+   *     JS_BUILTIN('String', 'int2string', 0)
+   *
+   */
+  void registerJsBuiltinCall(Send node, ForeignResolver resolver) {
+    NativeBehavior behavior = NativeBehavior.ofJsBuiltinCall(
+        node, reporter, compiler.parsing, compiler.coreTypes, resolver);
+    registerNativeBehavior(behavior, node);
+    nativeBehaviors[node] = behavior;
+  }
 }
 
 
diff --git a/pkg/compiler/lib/src/native/native.dart b/pkg/compiler/lib/src/native/native.dart
index fe1659e..c6bd3f1 100644
--- a/pkg/compiler/lib/src/native/native.dart
+++ b/pkg/compiler/lib/src/native/native.dart
@@ -6,13 +6,21 @@
 
 import 'dart:collection' show Queue;
 
+import '../common/backend_api.dart' show
+    ForeignResolver;
 import '../common/registry.dart' show
     Registry;
+import '../common/resolution.dart' show
+    Parsing,
+    Resolution;
 import '../compiler.dart' show
     Compiler;
 import '../constants/values.dart';
+import '../core_types.dart' show
+    CoreTypes;
 import '../dart_types.dart';
-import '../diagnostics/diagnostic_listener.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import '../diagnostics/messages.dart' show
     MessageKind;
 import '../diagnostics/spannable.dart' show
@@ -38,8 +46,6 @@
     ElementListener;
 import '../parser/partial_elements.dart' show
     PartialMetadataAnnotation;
-import '../resolution/members.dart' show
-    ResolverVisitor;
 import '../ssa/ssa.dart';
 import '../tokens/token.dart' show
     BeginGroupToken,
diff --git a/pkg/compiler/lib/src/native/ssa.dart b/pkg/compiler/lib/src/native/ssa.dart
index e622559..a93338b 100644
--- a/pkg/compiler/lib/src/native/ssa.dart
+++ b/pkg/compiler/lib/src/native/ssa.dart
@@ -11,6 +11,7 @@
   FunctionElement element = builder.work.element;
   NativeEmitter nativeEmitter = builder.nativeEmitter;
   JavaScriptBackend backend = builder.backend;
+  DiagnosticReporter reporter = compiler.reporter;
 
   HInstruction convertDartClosure(ParameterElement  parameter,
                                   FunctionType type) {
@@ -40,7 +41,7 @@
     LiteralString jsCode = nativeBody.asLiteralString();
     String str = jsCode.dartString.slowToString();
     if (nativeRedirectionRegExp.hasMatch(str)) {
-      compiler.internalError(
+      reporter.internalError(
           nativeBody, "Deprecated syntax, use @JSName('name') instead.");
     }
     hasBody = true;
@@ -60,7 +61,7 @@
       inputs.add(builder.localsHandler.readThis());
     }
     parameters.forEachParameter((ParameterElement parameter) {
-      DartType type = parameter.type.unalias(compiler);
+      DartType type = parameter.type.unalias(compiler.resolution);
       HInstruction input = builder.localsHandler.readLocal(parameter);
       if (type is FunctionType) {
         // The parameter type is a function type either directly or through
@@ -80,7 +81,7 @@
     } else if (element.kind == ElementKind.SETTER) {
       nativeMethodCall = '$receiver$nativeMethodName = $foreignParameters';
     } else {
-      builder.compiler.internalError(element,
+      builder.reporter.internalError(element,
                                      'Unexpected kind: "${element.kind}".');
     }
 
@@ -98,7 +99,7 @@
         .addSuccessor(builder.graph.exit);
   } else {
     if (parameters.parameterCount != 0) {
-      compiler.internalError(nativeBody,
+      reporter.internalError(nativeBody,
           'native "..." syntax is restricted to '
           'functions with zero parameters.');
     }
diff --git a/pkg/compiler/lib/src/ordered_typeset.dart b/pkg/compiler/lib/src/ordered_typeset.dart
index 48f3228..290b94f 100644
--- a/pkg/compiler/lib/src/ordered_typeset.dart
+++ b/pkg/compiler/lib/src/ordered_typeset.dart
@@ -7,6 +7,8 @@
 import 'compiler.dart' show
     Compiler;
 import 'dart_types.dart';
+import 'diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import 'diagnostics/invariant.dart' show
     invariant;
 import 'diagnostics/messages.dart' show
@@ -163,23 +165,25 @@
       if (type.element != compiler.objectClass) {
         allSupertypes.addLast(compiler.objectClass.rawType);
       }
-      _addAtDepth(compiler, type, maxDepth + 1);
+      DiagnosticReporter reporter = compiler.reporter;
+      _addAtDepth(reporter, type, maxDepth + 1);
     } else {
       if (type.element != compiler.objectClass) {
         allSupertypes.addLast(type);
       }
-      _addAtDepth(compiler, type, type.element.hierarchyDepth);
+      DiagnosticReporter reporter = compiler.reporter;
+      _addAtDepth(reporter, type, type.element.hierarchyDepth);
     }
   }
 
-  void _addAtDepth(Compiler compiler, InterfaceType type, int depth) {
+  void _addAtDepth(DiagnosticReporter reporter, InterfaceType type, int depth) {
     LinkEntry<DartType> prev = null;
     LinkEntry<DartType> link = map[depth];
     while (link != null) {
       DartType existingType = link.head;
       if (existingType == type) return;
       if (existingType.element == type.element) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             cls,
             MessageKind.MULTI_INHERITANCE,
             {'thisType': cls.thisType,
diff --git a/pkg/compiler/lib/src/parser/diet_parser_task.dart b/pkg/compiler/lib/src/parser/diet_parser_task.dart
index ee22ae9..ee65817 100644
--- a/pkg/compiler/lib/src/parser/diet_parser_task.dart
+++ b/pkg/compiler/lib/src/parser/diet_parser_task.dart
@@ -30,7 +30,7 @@
     measure(() {
       Function idGenerator = compiler.getNextFreeClassId;
       ElementListener listener =
-          new ElementListener(compiler, compilationUnit, idGenerator);
+          new ElementListener(compiler.reporter, compilationUnit, idGenerator);
       PartialParser parser = new PartialParser(listener);
       try {
         parser.parseUnit(tokens);
diff --git a/pkg/compiler/lib/src/parser/element_listener.dart b/pkg/compiler/lib/src/parser/element_listener.dart
index 95af9a4..4b97999 100644
--- a/pkg/compiler/lib/src/parser/element_listener.dart
+++ b/pkg/compiler/lib/src/parser/element_listener.dart
@@ -63,7 +63,7 @@
  */
 class ElementListener extends Listener {
   final IdGenerator idGenerator;
-  final DiagnosticListener listener;
+  final DiagnosticReporter reporter;
   final CompilationUnitElementX compilationUnitElement;
   final StringValidator stringValidator;
   Link<StringQuoting> interpolationScope;
@@ -85,11 +85,11 @@
   bool suppressParseErrors = false;
 
   ElementListener(
-      DiagnosticListener listener,
+      DiagnosticReporter reporter,
       this.compilationUnitElement,
       this.idGenerator)
-      : this.listener = listener,
-        stringValidator = new StringValidator(listener),
+      : this.reporter = reporter,
+        stringValidator = new StringValidator(reporter),
         interpolationScope = const Link<StringQuoting>();
 
   bool get currentMemberHasParseError {
@@ -110,7 +110,7 @@
     StringNode node = popNode();
     // TODO(lrn): Handle interpolations in script tags.
     if (node.isInterpolation) {
-      listener.internalError(node,
+      reporter.internalError(node,
           "String interpolation not supported in library tags.");
       return null;
     }
@@ -201,7 +201,7 @@
   }
 
   void addPartOfTag(PartOf tag) {
-    compilationUnitElement.setPartOf(tag, listener);
+    compilationUnitElement.setPartOf(tag, reporter);
   }
 
   void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
@@ -594,7 +594,7 @@
 
   void pushElement(Element element) {
     popMetadata(element);
-    compilationUnitElement.addMember(element, listener);
+    compilationUnitElement.addMember(element, reporter);
   }
 
   List<MetadataAnnotation> popMetadata(ElementX element) {
@@ -614,7 +614,7 @@
     }
     LibraryElementX implementationLibrary =
         compilationUnitElement.implementationLibrary;
-    implementationLibrary.addTag(tag, listener);
+    implementationLibrary.addTag(tag, reporter);
   }
 
   void pushNode(Node node) {
@@ -748,6 +748,6 @@
     if (!memberErrors.isEmpty) {
       memberErrors = memberErrors.tail.prepend(true);
     }
-    listener.reportErrorMessage(spannable, errorCode, arguments);
+    reporter.reportErrorMessage(spannable, errorCode, arguments);
   }
 }
diff --git a/pkg/compiler/lib/src/parser/member_listener.dart b/pkg/compiler/lib/src/parser/member_listener.dart
index cd6de0e..4982d90 100644
--- a/pkg/compiler/lib/src/parser/member_listener.dart
+++ b/pkg/compiler/lib/src/parser/member_listener.dart
@@ -5,7 +5,7 @@
 library dart2js.parser.member_listener;
 
 import '../diagnostics/diagnostic_listener.dart' show
-    DiagnosticListener;
+    DiagnosticReporter;
 import '../diagnostics/messages.dart' show
     MessageKind;
 import '../elements/elements.dart' show
@@ -34,7 +34,7 @@
 class MemberListener extends NodeListener {
   final ClassElementX enclosingClass;
 
-  MemberListener(DiagnosticListener listener,
+  MemberListener(DiagnosticReporter listener,
                  ClassElementX enclosingElement)
       : this.enclosingClass = enclosingElement,
         super(listener, enclosingElement.compilationUnit);
@@ -72,7 +72,7 @@
       return Elements.constructOperatorName(operator.source, isUnary);
     } else {
       if (receiver == null || receiver.source != enclosingClass.name) {
-        listener.reportErrorMessage(
+        reporter.reportErrorMessage(
             send.receiver,
             MessageKind.INVALID_CONSTRUCTOR_NAME,
             {'name': enclosingClass.name});
@@ -113,7 +113,7 @@
     Identifier singleIdentifierName = method.name.asIdentifier();
     if (singleIdentifierName != null && singleIdentifierName.source == name) {
       if (name != enclosingClass.name) {
-        listener.reportErrorMessage(
+        reporter.reportErrorMessage(
             singleIdentifierName,
             MessageKind.INVALID_UNNAMED_CONSTRUCTOR_NAME,
             {'name': enclosingClass.name});
@@ -160,7 +160,7 @@
 
   void addMember(ElementX memberElement) {
     addMetadata(memberElement);
-    enclosingClass.addMember(memberElement, listener);
+    enclosingClass.addMember(memberElement, reporter);
   }
 
   void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
diff --git a/pkg/compiler/lib/src/parser/node_listener.dart b/pkg/compiler/lib/src/parser/node_listener.dart
index d079b70..1344c5d 100644
--- a/pkg/compiler/lib/src/parser/node_listener.dart
+++ b/pkg/compiler/lib/src/parser/node_listener.dart
@@ -31,9 +31,9 @@
 
 class NodeListener extends ElementListener {
   NodeListener(
-      DiagnosticListener listener,
+      DiagnosticReporter reporter,
       CompilationUnitElement element)
-    : super(listener, element, null);
+    : super(reporter, element, null);
 
   void addLibraryTag(LibraryTag tag) {
     pushNode(tag);
@@ -199,7 +199,7 @@
   }
 
   void handleOnError(Token token, var errorInformation) {
-    listener.internalError(token, "'${token.value}': ${errorInformation}");
+    reporter.internalError(token, "'${token.value}': ${errorInformation}");
   }
 
   Token expectedFunctionBody(Token token) {
@@ -270,13 +270,13 @@
       pushNode(new Send(receiver, new Operator(token), arguments));
     }
     if (identical(tokenString, '===')) {
-      listener.reportErrorMessage(
+      reporter.reportErrorMessage(
           token,
           MessageKind.UNSUPPORTED_EQ_EQ_EQ,
           {'lhs': receiver, 'rhs': argument});
     }
     if (identical(tokenString, '!==')) {
-      listener.reportErrorMessage(
+      reporter.reportErrorMessage(
           token,
           MessageKind.UNSUPPORTED_BANG_EQ_EQ,
           {'lhs': receiver, 'rhs': argument});
@@ -451,7 +451,7 @@
   void endRethrowStatement(Token throwToken, Token endToken) {
     pushNode(new Rethrow(throwToken, endToken));
     if (identical(throwToken.stringValue, 'throw')) {
-      listener.reportErrorMessage(
+      reporter.reportErrorMessage(
           throwToken, MessageKind.UNSUPPORTED_THROW_WITHOUT_EXP);
     }
   }
@@ -814,11 +814,11 @@
   }
 
   void log(message) {
-    listener.log(message);
+    reporter.log(message);
   }
 
   void internalError({Token token, Node node}) {
-    // TODO(ahe): This should call listener.internalError.
+    // TODO(ahe): This should call reporter.internalError.
     Spannable spannable = (token == null) ? node : token;
     throw new SpannableAssertionFailure(spannable, 'Internal error in parser.');
   }
diff --git a/pkg/compiler/lib/src/parser/parser_task.dart b/pkg/compiler/lib/src/parser/parser_task.dart
index a0e900a4..24429ad 100644
--- a/pkg/compiler/lib/src/parser/parser_task.dart
+++ b/pkg/compiler/lib/src/parser/parser_task.dart
@@ -29,12 +29,12 @@
   String get name => 'Parser';
 
   Node parse(ElementX element) {
-    return measure(() => element.parseNode(compiler));
+    return measure(() => element.parseNode(compiler.parsing));
   }
 
   Node parseCompilationUnit(Token token) {
     return measure(() {
-      NodeListener listener = new NodeListener(compiler, null);
+      NodeListener listener = new NodeListener(reporter, null);
       Parser parser = new Parser(listener);
       try {
         parser.parseUnit(token);
diff --git a/pkg/compiler/lib/src/parser/partial_elements.dart b/pkg/compiler/lib/src/parser/partial_elements.dart
index 17412f7..b0a1b79 100644
--- a/pkg/compiler/lib/src/parser/partial_elements.dart
+++ b/pkg/compiler/lib/src/parser/partial_elements.dart
@@ -4,10 +4,12 @@
 
 library dart2js.parser.partial_elements;
 
-import '../compiler.dart' show
-    Compiler;
+import '../common/resolution.dart' show
+    Parsing,
+    Resolution;
 import '../dart_types.dart' show DynamicType;
-import '../diagnostics/diagnostic_listener.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import '../diagnostics/invariant.dart' show
     invariant;
 import '../diagnostics/messages.dart';
@@ -104,7 +106,7 @@
     return cachedNode;
   }
 
-  FunctionExpression parseNode(DiagnosticListener listener) {
+  FunctionExpression parseNode(Parsing parsing) {
     if (cachedNode != null) return cachedNode;
     parseFunction(Parser p) {
       if (isClassMember && modifiers.isFactory) {
@@ -113,7 +115,7 @@
         p.parseFunction(beginToken, getOrSet);
       }
     }
-    cachedNode = parse(listener, this, declarationSite, parseFunction);
+    cachedNode = parse(parsing, this, declarationSite, parseFunction);
     return cachedNode;
   }
 
@@ -268,11 +270,12 @@
     super.hasParseError = hasParseError;
   }
 
-  VariableDefinitions parseNode(Element element, DiagnosticListener listener) {
+  VariableDefinitions parseNode(Element element, Parsing parsing) {
     if (definitions != null) return definitions;
-    listener.withCurrentElement(element, () {
+    DiagnosticReporter reporter = parsing.reporter;
+    reporter.withCurrentElement(element, () {
       definitions = parse(
-          listener, element, declarationSite,
+          parsing, element, declarationSite,
           (Parser parser) => parser.parseMember(beginToken));
 
       if (!hasParseError &&
@@ -281,7 +284,7 @@
           !definitions.modifiers.isConst &&
           definitions.type == null &&
           !definitions.isErroneous) {
-        listener.reportErrorMessage(
+        reporter.reportErrorMessage(
             definitions,
             MessageKind.GENERIC,
             { 'text': 'A field declaration must start with var, final, '
@@ -291,17 +294,15 @@
     return definitions;
   }
 
-  computeType(Element element, Compiler compiler) {
+  computeType(Element element, Resolution resolution) {
     if (type != null) return type;
     // TODO(johnniwinther): Compute this in the resolver.
-    compiler.withCurrentElement(element, () {
-      VariableDefinitions node = parseNode(element, compiler);
-      if (node.type != null) {
-        type = compiler.resolver.resolveTypeAnnotation(element, node.type);
-      } else {
-        type = const DynamicType();
-      }
-    });
+    VariableDefinitions node = parseNode(element, resolution.parsing);
+    if (node.type != null) {
+      type = resolution.resolveTypeAnnotation(element, node.type);
+    } else {
+      type = const DynamicType();
+    }
     assert(type != null);
     return type;
   }
@@ -321,10 +322,10 @@
 
   Token get token => beginToken;
 
-  Node parseNode(DiagnosticListener listener) {
+  Node parseNode(Parsing parsing) {
     if (cachedNode != null) return cachedNode;
     cachedNode = parse(
-        listener, this, declarationSite,
+        parsing, this, declarationSite,
         (p) => p.parseTopLevelDeclaration(token));
     return cachedNode;
   }
@@ -363,9 +364,9 @@
     throw new UnsupportedError("endToken=");
   }
 
-  Node parseNode(DiagnosticListener listener) {
+  Node parseNode(Parsing parsing) {
     if (cachedNode != null) return cachedNode;
-    var metadata = parse(listener,
+    var metadata = parse(parsing,
                          annotatedElement,
                          declarationSite,
                          (p) => p.parseMetadata(beginToken));
@@ -419,11 +420,12 @@
     return cachedNode;
   }
 
-  ClassNode parseNode(Compiler compiler) {
+  ClassNode parseNode(Parsing parsing) {
     if (cachedNode != null) return cachedNode;
-    compiler.withCurrentElement(this, () {
-      compiler.parser.measure(() {
-        MemberListener listener = new MemberListener(compiler, this);
+    DiagnosticReporter reporter = parsing.reporter;
+    reporter.withCurrentElement(this, () {
+      parsing.measure(() {
+        MemberListener listener = new MemberListener(reporter, this);
         Parser parser = new ClassElementParser(listener);
         try {
           Token token = parser.parseTopLevelDeclaration(beginToken);
@@ -450,13 +452,9 @@
           hasParseError = true;
         }
       });
-      compiler.patchParser.measure(() {
-        if (isPatched) {
-          // TODO(lrn): Perhaps extract functionality so it doesn't
-          // need compiler.
-          compiler.patchParser.parsePatchClassNode(patch);
-        }
-      });
+      if (isPatched) {
+        parsing.parsePatchClass(patch);
+      }
     });
     return cachedNode;
   }
@@ -477,23 +475,28 @@
 }
 
 Node parse(
-    DiagnosticListener diagnosticListener,
+    Parsing parsing,
     ElementX element,
     PartialElement partial,
     doParse(Parser parser)) {
-  CompilationUnitElement unit = element.compilationUnit;
-  NodeListener listener = new NodeListener(diagnosticListener, unit);
-  listener.memberErrors = listener.memberErrors.prepend(false);
-  try {
-    if (partial.hasParseError) {
-      listener.suppressParseErrors = true;
-    }
-    doParse(new Parser(listener));
-  } on ParserError catch (e) {
-    partial.hasParseError = true;
-    return new ErrorNode(element.position, e.reason);
-  }
-  Node node = listener.popNode();
-  assert(listener.nodes.isEmpty);
-  return node;
+  DiagnosticReporter reporter = parsing.reporter;
+  return parsing.measure(() {
+    return reporter.withCurrentElement(element, () {
+      CompilationUnitElement unit = element.compilationUnit;
+      NodeListener listener = new NodeListener(reporter, unit);
+      listener.memberErrors = listener.memberErrors.prepend(false);
+      try {
+        if (partial.hasParseError) {
+          listener.suppressParseErrors = true;
+        }
+        doParse(new Parser(listener));
+      } on ParserError catch (e) {
+        partial.hasParseError = true;
+        return new ErrorNode(element.position, e.reason);
+      }
+      Node node = listener.popNode();
+      assert(listener.nodes.isEmpty);
+      return node;
+    });
+  });
 }
diff --git a/pkg/compiler/lib/src/patch_parser.dart b/pkg/compiler/lib/src/patch_parser.dart
index 8eb9f85..fb5096b 100644
--- a/pkg/compiler/lib/src/patch_parser.dart
+++ b/pkg/compiler/lib/src/patch_parser.dart
@@ -122,6 +122,8 @@
     Compiler;
 import 'common/tasks.dart' show
     CompilerTask;
+import 'dart_types.dart' show
+    DartType;
 import 'diagnostics/diagnostic_listener.dart';
 import 'diagnostics/messages.dart' show
     MessageKind;
@@ -154,7 +156,6 @@
 import 'tokens/token.dart' show
     StringToken,
     Token;
-import 'util/util.dart';
 
 class PatchParserTask extends CompilerTask {
   final String name = "Patching Parser";
@@ -171,9 +172,9 @@
     return compiler.readScript(originLibrary, patchUri)
         .then((Script script) {
       var patchLibrary = new LibraryElementX(script, null, originLibrary);
-      return compiler.withCurrentElement(patchLibrary, () {
+      return reporter.withCurrentElement(patchLibrary, () {
         loader.registerNewLibrary(patchLibrary);
-        compiler.withCurrentElement(patchLibrary.entryCompilationUnit, () {
+        reporter.withCurrentElement(patchLibrary.entryCompilationUnit, () {
           // This patches the elements of the patch library into [library].
           // Injected elements are added directly under the compilation unit.
           // Patch elements are stored on the patched functions or classes.
@@ -198,7 +199,7 @@
       } on ParserError catch (e) {
         // No need to recover from a parser error in platform libraries, user
         // will never see this if the libraries are tested correctly.
-        compiler.internalError(
+        reporter.internalError(
             compilationUnit, "Parser error in patch file: $e");
       }
     });
@@ -209,7 +210,7 @@
     // of calling its [parseNode] method.
     if (cls.cachedNode != null) return;
 
-    measure(() => compiler.withCurrentElement(cls, () {
+    measure(() => reporter.withCurrentElement(cls, () {
       MemberListener listener = new PatchMemberListener(compiler, cls);
       Parser parser = new PatchClassElementParser(listener);
       try {
@@ -218,7 +219,7 @@
       } on ParserError catch (e) {
         // No need to recover from a parser error in platform libraries, user
         // will never see this if the libraries are tested correctly.
-        compiler.internalError(
+        reporter.internalError(
             cls, "Parser error in patch file: $e");
       }
       cls.cachedNode = listener.popNode();
@@ -232,7 +233,7 @@
 
   PatchMemberListener(Compiler compiler, ClassElement enclosingClass)
       : this.compiler = compiler,
-        super(compiler, enclosingClass);
+        super(compiler.reporter, enclosingClass);
 
   @override
   void addMember(Element patch) {
@@ -242,13 +243,13 @@
     if (patchVersion != null) {
       if (patchVersion.isActive(compiler.patchVersion)) {
         Element origin = enclosingClass.origin.localLookup(patch.name);
-        patchElement(compiler, origin, patch);
-        enclosingClass.addMember(patch, listener);
+        patchElement(compiler, reporter, origin, patch);
+        enclosingClass.addMember(patch, reporter);
       } else {
         // Skip this element.
       }
     } else {
-      enclosingClass.addMember(patch, listener);
+      enclosingClass.addMember(patch, reporter);
     }
   }
 }
@@ -273,7 +274,7 @@
                        CompilationUnitElement patchElement,
                        int idGenerator())
     : this.compiler = compiler,
-      super(compiler, patchElement, idGenerator);
+      super(compiler.reporter, patchElement, idGenerator);
 
   @override
   void pushElement(Element patch) {
@@ -285,22 +286,23 @@
         LibraryElement originLibrary = compilationUnitElement.library;
         assert(originLibrary.isPatched);
         Element origin = originLibrary.localLookup(patch.name);
-        patchElement(listener, origin, patch);
-        compilationUnitElement.addMember(patch, listener);
+        patchElement(compiler, reporter, origin, patch);
+        compilationUnitElement.addMember(patch, reporter);
       } else {
         // Skip this element.
       }
     } else {
-      compilationUnitElement.addMember(patch, listener);
+      compilationUnitElement.addMember(patch, reporter);
     }
   }
 }
 
 void patchElement(Compiler compiler,
+                  DiagnosticReporter reporter,
                   Element origin,
                   Element patch) {
   if (origin == null) {
-    compiler.reportErrorMessage(
+    reporter.reportErrorMessage(
         patch, MessageKind.PATCH_NON_EXISTING, {'name': patch.name});
     return;
   }
@@ -309,50 +311,52 @@
         origin.isFunction ||
         origin.isAbstractField)) {
     // TODO(ahe): Remove this error when the parser rejects all bad modifiers.
-    compiler.reportErrorMessage(origin, MessageKind.PATCH_NONPATCHABLE);
+    reporter.reportErrorMessage(origin, MessageKind.PATCH_NONPATCHABLE);
     return;
   }
   if (patch.isClass) {
-    tryPatchClass(compiler, origin, patch);
+    tryPatchClass(compiler, reporter, origin, patch);
   } else if (patch.isGetter) {
-    tryPatchGetter(compiler, origin, patch);
+    tryPatchGetter(reporter, origin, patch);
   } else if (patch.isSetter) {
-    tryPatchSetter(compiler, origin, patch);
+    tryPatchSetter(reporter, origin, patch);
   } else if (patch.isConstructor) {
-    tryPatchConstructor(compiler, origin, patch);
+    tryPatchConstructor(reporter, origin, patch);
   } else if(patch.isFunction) {
-    tryPatchFunction(compiler, origin, patch);
+    tryPatchFunction(reporter, origin, patch);
   } else {
     // TODO(ahe): Remove this error when the parser rejects all bad modifiers.
-    compiler.reportErrorMessage(patch, MessageKind.PATCH_NONPATCHABLE);
+    reporter.reportErrorMessage(patch, MessageKind.PATCH_NONPATCHABLE);
   }
 }
 
 void tryPatchClass(Compiler compiler,
+                   DiagnosticReporter reporter,
                    Element origin,
                    ClassElement patch) {
   if (!origin.isClass) {
-    compiler.reportError(
-        compiler.createMessage(
+    reporter.reportError(
+        reporter.createMessage(
             origin,
             MessageKind.PATCH_NON_CLASS,
             {'className': patch.name}),
         <DiagnosticMessage>[
-            compiler.createMessage(
+            reporter.createMessage(
                 patch,
                 MessageKind.PATCH_POINT_TO_CLASS,
                 {'className': patch.name}),
         ]);
     return;
   }
-  patchClass(compiler, origin, patch);
+  patchClass(compiler, reporter, origin, patch);
 }
 
 void patchClass(Compiler compiler,
+                DiagnosticReporter reporter,
                 ClassElementX origin,
                 ClassElementX patch) {
   if (origin.isPatched) {
-    compiler.internalError(origin,
+    reporter.internalError(origin,
         "Patching the same class more than once.");
   }
   origin.applyPatch(patch);
@@ -399,7 +403,7 @@
         // TODO(johnniwinther): Perform this check in
         // [Compiler.onLibrariesLoaded].
         compiler.enqueuer.resolution.addDeferredAction(element, () {
-          annotation.ensureResolved(compiler);
+          annotation.ensureResolved(compiler.resolution);
           handler.validate(
               compiler, element, annotation,
               compiler.constants.getConstantValue(annotation.constant));
@@ -446,9 +450,10 @@
                 Element element,
                 MetadataAnnotation annotation,
                 ConstantValue constant) {
-    if (constant.getType(compiler.coreTypes).element !=
-            compiler.nativeAnnotationClass) {
-      compiler.internalError(annotation, 'Invalid @Native(...) annotation.');
+    DartType annotationType = constant.getType(compiler.coreTypes);
+    if (annotationType.element != compiler.nativeAnnotationClass) {
+      DiagnosticReporter reporter = compiler.reporter;
+      reporter.internalError(annotation, 'Invalid @Native(...) annotation.');
     }
   }
 }
@@ -484,25 +489,26 @@
                 Element element,
                 MetadataAnnotation annotation,
                 ConstantValue constant) {
-    if (constant.getType(compiler.coreTypes).element !=
-            compiler.patchAnnotationClass) {
-      compiler.internalError(annotation, 'Invalid patch annotation.');
+    DartType annotationType = constant.getType(compiler.coreTypes);
+    if (annotationType.element != compiler.patchAnnotationClass) {
+      DiagnosticReporter reporter = compiler.reporter;
+      reporter.internalError(annotation, 'Invalid patch annotation.');
     }
   }
 }
 
 
-void tryPatchGetter(DiagnosticListener listener,
+void tryPatchGetter(DiagnosticReporter reporter,
                     Element origin,
                     FunctionElement patch) {
   if (!origin.isAbstractField) {
-    listener.reportError(
-        listener.createMessage(
+    reporter.reportError(
+        reporter.createMessage(
             origin,
             MessageKind.PATCH_NON_GETTER,
             {'name': origin.name}),
         <DiagnosticMessage>[
-            listener.createMessage(
+            reporter.createMessage(
                 patch,
                 MessageKind.PATCH_POINT_TO_GETTER,
                 {'getterName': patch.name}),
@@ -511,13 +517,13 @@
   }
   AbstractFieldElement originField = origin;
   if (originField.getter == null) {
-    listener.reportError(
-        listener.createMessage(
+    reporter.reportError(
+        reporter.createMessage(
             origin,
             MessageKind.PATCH_NO_GETTER,
             {'getterName': patch.name}),
         <DiagnosticMessage>[
-            listener.createMessage(
+            reporter.createMessage(
                 patch,
                 MessageKind.PATCH_POINT_TO_GETTER,
                 {'getterName': patch.name}),
@@ -525,20 +531,20 @@
     return;
   }
   GetterElementX getter = originField.getter;
-  patchFunction(listener, getter, patch);
+  patchFunction(reporter, getter, patch);
 }
 
-void tryPatchSetter(DiagnosticListener listener,
+void tryPatchSetter(DiagnosticReporter reporter,
                     Element origin,
                     FunctionElement patch) {
   if (!origin.isAbstractField) {
-    listener.reportError(
-        listener.createMessage(
+    reporter.reportError(
+        reporter.createMessage(
             origin,
             MessageKind.PATCH_NON_SETTER,
             {'name': origin.name}),
         <DiagnosticMessage>[
-            listener.createMessage(
+            reporter.createMessage(
                 patch,
                 MessageKind.PATCH_POINT_TO_SETTER,
                 {'setterName': patch.name}),
@@ -547,13 +553,13 @@
   }
   AbstractFieldElement originField = origin;
   if (originField.setter == null) {
-    listener.reportError(
-        listener.createMessage(
+    reporter.reportError(
+        reporter.createMessage(
             origin,
             MessageKind.PATCH_NO_SETTER,
             {'setterName': patch.name}),
         <DiagnosticMessage>[
-              listener.createMessage(
+              reporter.createMessage(
                   patch,
                   MessageKind.PATCH_POINT_TO_SETTER,
                   {'setterName': patch.name}),
@@ -561,57 +567,57 @@
     return;
   }
   SetterElementX setter = originField.setter;
-  patchFunction(listener, setter, patch);
+  patchFunction(reporter, setter, patch);
 }
 
-void tryPatchConstructor(DiagnosticListener listener,
+void tryPatchConstructor(DiagnosticReporter reporter,
                          Element origin,
                          FunctionElement patch) {
   if (!origin.isConstructor) {
-    listener.reportError(
-        listener.createMessage(
+    reporter.reportError(
+        reporter.createMessage(
             origin,
             MessageKind.PATCH_NON_CONSTRUCTOR,
             {'constructorName': patch.name}),
         <DiagnosticMessage>[
-            listener.createMessage(
+            reporter.createMessage(
                 patch,
                 MessageKind.PATCH_POINT_TO_CONSTRUCTOR,
                 {'constructorName': patch.name}),
         ]);
     return;
   }
-  patchFunction(listener, origin, patch);
+  patchFunction(reporter, origin, patch);
 }
 
-void tryPatchFunction(DiagnosticListener listener,
+void tryPatchFunction(DiagnosticReporter reporter,
                       Element origin,
                       FunctionElement patch) {
   if (!origin.isFunction) {
-    listener.reportError(
-        listener.createMessage(
+    reporter.reportError(
+        reporter.createMessage(
             origin,
             MessageKind.PATCH_NON_FUNCTION,
             {'functionName': patch.name}),
         <DiagnosticMessage>[
-            listener.createMessage(
+            reporter.createMessage(
                 patch,
                 MessageKind.PATCH_POINT_TO_FUNCTION,
                 {'functionName': patch.name}),
         ]);
     return;
   }
-  patchFunction(listener, origin, patch);
+  patchFunction(reporter, origin, patch);
 }
 
-void patchFunction(DiagnosticListener listener,
+void patchFunction(DiagnosticReporter reporter,
                    BaseFunctionElementX origin,
                    BaseFunctionElementX patch) {
   if (!origin.modifiers.isExternal) {
-    listener.reportError(
-        listener.createMessage(origin, MessageKind.PATCH_NON_EXTERNAL),
+    reporter.reportError(
+        reporter.createMessage(origin, MessageKind.PATCH_NON_EXTERNAL),
         <DiagnosticMessage>[
-              listener.createMessage(
+              reporter.createMessage(
                   patch,
                   MessageKind.PATCH_POINT_TO_FUNCTION,
                   {'functionName': patch.name}),
@@ -619,7 +625,7 @@
     return;
   }
   if (origin.isPatched) {
-    listener.internalError(origin,
+    reporter.internalError(origin,
         "Trying to patch a function more than once.");
   }
   origin.applyPatch(patch);
diff --git a/pkg/compiler/lib/src/resolution/class_hierarchy.dart b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
index 383c671..9f1ce4b 100644
--- a/pkg/compiler/lib/src/resolution/class_hierarchy.dart
+++ b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
@@ -68,7 +68,7 @@
       TypeVariable typeNode = nodeLink.head;
       registry.useType(typeNode, typeVariable);
       if (nameSet.contains(typeName)) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             typeNode,
             MessageKind.DUPLICATE_TYPE_VARIABLE_NAME,
             {'typeVariableName': typeName});
@@ -92,7 +92,7 @@
               if (identical(element, variableElement)) {
                 // Only report an error on the checked type variable to avoid
                 // generating multiple errors for the same cyclicity.
-                compiler.reportWarningMessage(
+                reporter.reportWarningMessage(
                     typeNode.name,
                     MessageKind.CYCLIC_TYPE_VARIABLE,
                     {'typeVariableName': variableElement.name});
@@ -135,14 +135,14 @@
 
   DartType visitClassNode(ClassNode node) {
     if (element == null) {
-      throw compiler.internalError(node, 'element is null');
+      throw reporter.internalError(node, 'element is null');
     }
     if (element.resolutionState != STATE_STARTED) {
-      throw compiler.internalError(element,
+      throw reporter.internalError(element,
           'cyclic resolution of class $element');
     }
 
-    element.computeType(compiler);
+    element.computeType(resolution);
     scope = new TypeDeclarationScope(scope, element);
     // TODO(ahe): It is not safe to call resolveTypeVariableBounds yet.
     // As a side-effect, this may get us back here trying to
@@ -175,12 +175,12 @@
       // Avoid making the superclass (usually Object) extend itself.
       if (element != superElement) {
         if (superElement == null) {
-          compiler.internalError(node,
+          reporter.internalError(node,
               "Cannot resolve default superclass for $element.");
         } else {
-          superElement.ensureResolved(compiler);
+          superElement.ensureResolved(resolution);
         }
-        element.supertype = superElement.computeType(compiler);
+        element.supertype = superElement.computeType(resolution);
       }
     }
 
@@ -198,17 +198,17 @@
         Map arguments = {'constructorName': ''};
         // TODO(ahe): Why is this a compile-time error? Or if it is an error,
         // why do we bother to registerThrowNoSuchMethod below?
-        compiler.reportErrorMessage(node, kind, arguments);
+        reporter.reportErrorMessage(node, kind, arguments);
         superMember = new ErroneousElementX(
             kind, arguments, '', element);
         registry.registerThrowNoSuchMethod();
       } else {
         ConstructorElement superConstructor = superMember;
-        superConstructor.computeType(compiler);
+        superConstructor.computeType(resolution);
         if (!CallStructure.NO_ARGS.signatureApplies(
                 superConstructor.functionSignature)) {
           MessageKind kind = MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT;
-          compiler.reportErrorMessage(node, kind);
+          reporter.reportErrorMessage(node, kind);
           superMember = new ErroneousElementX(kind, {}, '', element);
         }
       }
@@ -217,34 +217,35 @@
       if (superMember.isErroneous) {
         compiler.elementsWithCompileTimeErrors.add(constructor);
       }
-      element.setDefaultConstructor(constructor, compiler);
+      element.setDefaultConstructor(constructor, reporter);
     }
-    return element.computeType(compiler);
+    return element.computeType(resolution);
   }
 
   @override
   DartType visitEnum(Enum node) {
     if (element == null) {
-      throw compiler.internalError(node, 'element is null');
+      throw reporter.internalError(node, 'element is null');
     }
     if (element.resolutionState != STATE_STARTED) {
-      throw compiler.internalError(element,
+      throw reporter.internalError(element,
           'cyclic resolution of class $element');
     }
 
-    InterfaceType enumType = element.computeType(compiler);
-    element.supertype = compiler.objectClass.computeType(compiler);
+    InterfaceType enumType = element.computeType(resolution);
+    element.supertype = compiler.coreTypes.objectType;
     element.interfaces = const Link<DartType>();
     calculateAllSupertypes(element);
 
     if (node.names.nodes.isEmpty) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node,
           MessageKind.EMPTY_ENUM_DECLARATION,
           {'enumName': element.name});
     }
 
-    EnumCreator creator = new EnumCreator(compiler, element);
+    EnumCreator creator =
+        new EnumCreator(reporter, compiler.coreTypes, element);
     creator.createMembers();
     return enumType;
   }
@@ -254,21 +255,21 @@
   DartType checkMixinType(TypeAnnotation mixinNode) {
     DartType mixinType = resolveType(mixinNode);
     if (isBlackListed(mixinType)) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           mixinNode,
           MessageKind.CANNOT_MIXIN,
           {'type': mixinType});
     } else if (mixinType.isTypeVariable) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           mixinNode,
           MessageKind.CLASS_NAME_EXPECTED);
     } else if (mixinType.isMalformed) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           mixinNode,
           MessageKind.CANNOT_MIXIN_MALFORMED,
           {'className': element.name, 'malformedType': mixinType});
     } else if (mixinType.isEnumType) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           mixinNode,
           MessageKind.CANNOT_MIXIN_ENUM,
           {'className': element.name, 'enumType': mixinType});
@@ -278,22 +279,22 @@
 
   DartType visitNamedMixinApplication(NamedMixinApplication node) {
     if (element == null) {
-      throw compiler.internalError(node, 'element is null');
+      throw reporter.internalError(node, 'element is null');
     }
     if (element.resolutionState != STATE_STARTED) {
-      throw compiler.internalError(element,
+      throw reporter.internalError(element,
           'cyclic resolution of class $element');
     }
 
     if (identical(node.classKeyword.stringValue, 'typedef')) {
       // TODO(aprelev@gmail.com): Remove this deprecation diagnostic
       // together with corresponding TODO in parser.dart.
-      compiler.reportWarningMessage(
+      reporter.reportWarningMessage(
           node.classKeyword,
           MessageKind.DEPRECATED_TYPEDEF_MIXIN_SYNTAX);
     }
 
-    element.computeType(compiler);
+    element.computeType(resolution);
     scope = new TypeDeclarationScope(scope, element);
     resolveTypeVariableBounds(node.typeParameters);
 
@@ -306,7 +307,7 @@
       link = link.tail;
     }
     doApplyMixinTo(element, supertype, checkMixinType(link.head));
-    return element.computeType(compiler);
+    return element.computeType(resolution);
   }
 
   DartType applyMixin(DartType supertype, DartType mixinType, Node node) {
@@ -337,7 +338,7 @@
           type.element.bound.subst(typeVariables, element.typeVariables);
     }
     // Setup this and raw type for the mixin application.
-    mixinApplication.computeThisAndRawType(compiler, typeVariables);
+    mixinApplication.computeThisAndRawType(resolution, typeVariables);
     // Substitute in synthetic type variables in super and mixin types.
     supertype = supertype.subst(typeVariables, element.typeVariables);
     mixinType = mixinType.subst(typeVariables, element.typeVariables);
@@ -354,7 +355,7 @@
 
   bool isDefaultConstructor(FunctionElement constructor) {
     if (constructor.name != '') return false;
-    constructor.computeType(compiler);
+    constructor.computeType(resolution);
     return constructor.functionSignature.parameterCount == 0;
   }
 
@@ -363,14 +364,14 @@
     FunctionElement constructor =
         new SynthesizedConstructorElementX.notForDefault(
             target.name, target, enclosing);
-    constructor.computeType(compiler);
+    constructor.computeType(resolution);
     return constructor;
   }
 
   void doApplyMixinTo(MixinApplicationElementX mixinApplication,
                       DartType supertype,
                       DartType mixinType) {
-    Node node = mixinApplication.parseNode(compiler);
+    Node node = mixinApplication.parseNode(resolution.parsing);
 
     if (mixinApplication.supertype != null) {
       // [supertype] is not null if there was a cycle.
@@ -435,7 +436,7 @@
   InterfaceType resolveMixinFor(MixinApplicationElement mixinApplication,
                                 DartType mixinType) {
     ClassElement mixin = mixinType.element;
-    mixin.ensureResolved(compiler);
+    mixin.ensureResolved(resolution);
 
     // Check for cycles in the mixin chain.
     ClassElement previous = mixinApplication;  // For better error messages.
@@ -443,7 +444,7 @@
     while (current != null && current.isMixinApplication) {
       MixinApplicationElement currentMixinApplication = current;
       if (currentMixinApplication == mixinApplication) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             mixinApplication,
             MessageKind.ILLEGAL_MIXIN_CYCLE,
             {'mixinName1': current.name, 'mixinName2': previous.name});
@@ -467,24 +468,24 @@
     DartType supertype = resolveType(superclass);
     if (supertype != null) {
       if (supertype.isMalformed) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             superclass,
             MessageKind.CANNOT_EXTEND_MALFORMED,
             {'className': element.name, 'malformedType': supertype});
         return objectType;
       } else if (supertype.isEnumType) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             superclass,
             MessageKind.CANNOT_EXTEND_ENUM,
             {'className': element.name, 'enumType': supertype});
         return objectType;
       } else if (!supertype.isInterfaceType) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             superclass.typeName,
             MessageKind.CLASS_NAME_EXPECTED);
         return objectType;
       } else if (isBlackListed(supertype)) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             superclass,
             MessageKind.CANNOT_EXTEND,
             {'type': supertype});
@@ -501,40 +502,40 @@
       DartType interfaceType = resolveType(link.head);
       if (interfaceType != null) {
         if (interfaceType.isMalformed) {
-          compiler.reportErrorMessage(
+          reporter.reportErrorMessage(
               superclass,
               MessageKind.CANNOT_IMPLEMENT_MALFORMED,
               {'className': element.name, 'malformedType': interfaceType});
         } else if (interfaceType.isEnumType) {
-          compiler.reportErrorMessage(
+          reporter.reportErrorMessage(
               superclass,
               MessageKind.CANNOT_IMPLEMENT_ENUM,
               {'className': element.name, 'enumType': interfaceType});
         } else if (!interfaceType.isInterfaceType) {
           // TODO(johnniwinther): Handle dynamic.
           TypeAnnotation typeAnnotation = link.head;
-          compiler.reportErrorMessage(
+          reporter.reportErrorMessage(
               typeAnnotation.typeName, MessageKind.CLASS_NAME_EXPECTED);
         } else {
           if (interfaceType == element.supertype) {
-            compiler.reportErrorMessage(
+            reporter.reportErrorMessage(
                 superclass,
                 MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS,
                 {'type': interfaceType});
-            compiler.reportErrorMessage(
+            reporter.reportErrorMessage(
                 link.head,
                 MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS,
                 {'type': interfaceType});
           }
           if (result.contains(interfaceType)) {
-            compiler.reportErrorMessage(
+            reporter.reportErrorMessage(
                 link.head,
                 MessageKind.DUPLICATE_IMPLEMENTS,
                 {'type': interfaceType});
           }
           result = result.prepend(interfaceType);
           if (isBlackListed(interfaceType)) {
-            compiler.reportErrorMessage(
+            reporter.reportErrorMessage(
                 link.head,
                 MessageKind.CANNOT_IMPLEMENT,
                 {'type': interfaceType});
@@ -581,12 +582,12 @@
            interfaces = interfaces.tail) {
         addAllSupertypes(allSupertypes, interfaces.head);
       }
-      allSupertypes.add(compiler, cls.computeType(compiler));
+      allSupertypes.add(compiler, cls.computeType(resolution));
       cls.allSupertypesAndSelf = allSupertypes.toTypeSet();
     } else {
       assert(identical(cls, compiler.objectClass));
       cls.allSupertypesAndSelf =
-          new OrderedTypeSet.singleton(cls.computeType(compiler));
+          new OrderedTypeSet.singleton(cls.computeType(resolution));
     }
   }
 
@@ -635,7 +636,7 @@
   void loadSupertype(ClassElement element, Node from) {
     if (!element.isResolved) {
       compiler.resolver.loadSupertypes(element, from);
-      element.ensureResolved(compiler);
+      element.ensureResolved(resolution);
     }
   }
 
@@ -678,7 +679,7 @@
   }
 
   void visitIdentifier(Identifier node) {
-    Element element = lookupInScope(compiler, node, context, node.source);
+    Element element = lookupInScope(reporter, node, context, node.source);
     if (element != null && element.isClass) {
       loadSupertype(element, node);
     }
@@ -687,13 +688,13 @@
   void visitSend(Send node) {
     Identifier prefix = node.receiver.asIdentifier();
     if (prefix == null) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver});
       return;
     }
-    Element element = lookupInScope(compiler, prefix, context, prefix.source);
+    Element element = lookupInScope(reporter, prefix, context, prefix.source);
     if (element == null || !identical(element.kind, ElementKind.PREFIX)) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver});
       return;
     }
@@ -701,7 +702,7 @@
     Identifier selector = node.selector.asIdentifier();
     var e = prefixElement.lookupLocalMember(selector.source);
     if (e == null || !e.impliesType) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node.selector,
           MessageKind.CANNOT_RESOLVE_TYPE,
           {'typeName': node.selector});
diff --git a/pkg/compiler/lib/src/resolution/class_members.dart b/pkg/compiler/lib/src/resolution/class_members.dart
index 2bcf2dd..b8f8784 100644
--- a/pkg/compiler/lib/src/resolution/class_members.dart
+++ b/pkg/compiler/lib/src/resolution/class_members.dart
@@ -6,11 +6,14 @@
 
 import '../common/names.dart' show
     Identifiers;
+import '../common/resolution.dart' show
+    Resolution;
 import '../compiler.dart' show
     Compiler;
 import '../dart_types.dart';
 import '../diagnostics/diagnostic_listener.dart' show
-    DiagnosticMessage;
+    DiagnosticMessage,
+    DiagnosticReporter;
 import '../diagnostics/invariant.dart' show
     invariant;
 import '../diagnostics/messages.dart' show
@@ -47,6 +50,10 @@
         message: "Members may only be computed on declarations."));
   }
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
+  Resolution get resolution => compiler.resolution;
+
   void reportMessage(var marker, MessageKind kind, report()) {
     Set<MessageKind> messages =
         reportedMessages.putIfAbsent(marker,
@@ -194,7 +201,7 @@
 
         Name name = new Name(element.name, library);
         if (element.isField) {
-          DartType type = element.computeType(compiler);
+          DartType type = element.computeType(resolution);
           addDeclaredMember(name, type, new FunctionType.synthesized(type));
           if (!element.isConst && !element.isFinal) {
             addDeclaredMember(name.setter, type,
@@ -203,11 +210,11 @@
                                  <DartType>[type]));
           }
         } else if (element.isGetter) {
-          FunctionType functionType = element.computeType(compiler);
+          FunctionType functionType = element.computeType(resolution);
           DartType type = functionType.returnType;
           addDeclaredMember(name, type, functionType);
         } else if (element.isSetter) {
-          FunctionType functionType = element.computeType(compiler);
+          FunctionType functionType = element.computeType(resolution);
           DartType type;
           if (!functionType.parameterTypes.isEmpty) {
             type = functionType.parameterTypes.first;
@@ -218,7 +225,7 @@
           addDeclaredMember(name, type, functionType);
         } else {
           assert(invariant(element, element.isFunction));
-          FunctionType type = element.computeType(compiler);
+          FunctionType type = element.computeType(resolution);
           addDeclaredMember(name, type, type);
         }
       }
@@ -256,7 +263,7 @@
       }
       reportMessage(
           interfaceMember.element, MessageKind.ABSTRACT_METHOD, () {
-        compiler.reportWarningMessage(
+        reporter.reportWarningMessage(
             interfaceMember.element, kind,
             {'class': cls.name, 'name': name.text});
       });
@@ -268,7 +275,7 @@
         Member inherited = interfaceMember.declarations.first;
         reportMessage(
             interfaceMember, MessageKind.UNIMPLEMENTED_METHOD, () {
-          DiagnosticMessage warning = compiler.createMessage(
+          DiagnosticMessage warning = reporter.createMessage(
               cls,
               interfaceMember.declarations.length == 1
                   ? singleKind : multipleKind,
@@ -278,14 +285,14 @@
                'declarer': inherited.declarer});
           List<DiagnosticMessage> infos = <DiagnosticMessage>[];
           for (Member inherited in interfaceMember.declarations) {
-            infos.add(compiler.createMessage(
+            infos.add(reporter.createMessage(
                 inherited.element,
                 inherited.isDeclaredByField ?
                     implicitlyDeclaredKind : explicitlyDeclaredKind,
                 {'class': inherited.declarer.name,
                  'name': name.text}));
           }
-          compiler.reportWarning(warning, infos);
+          reporter.reportWarning(warning, infos);
         });
       }
       if (interfaceMember.isSetter) {
@@ -320,7 +327,7 @@
     if (compiler.backend.isBackendLibrary(cls.library)) return;
 
     reportMessage(compiler.functionClass, MessageKind.UNIMPLEMENTED_METHOD, () {
-      compiler.reportWarningMessage(
+      reporter.reportWarningMessage(
           cls,
           MessageKind.UNIMPLEMENTED_METHOD_ONE,
           {'class': cls.name,
@@ -345,14 +352,14 @@
           if (superMember != null && superMember.isStatic) {
             reportMessage(superMember, MessageKind.INSTANCE_STATIC_SAME_NAME,
                 () {
-              compiler.reportWarning(
-                  compiler.createMessage(
+              reporter.reportWarning(
+                  reporter.createMessage(
                       declared.element,
                       MessageKind.INSTANCE_STATIC_SAME_NAME,
                       {'memberName': declared.name,
                        'className': superclass.name}),
                   <DiagnosticMessage>[
-                      compiler.createMessage(
+                      reporter.createMessage(
                           superMember.element,
                           MessageKind.INSTANCE_STATIC_SAME_NAME_CONT),
                   ]);
@@ -399,15 +406,15 @@
         void reportError(MessageKind errorKind, MessageKind infoKind) {
           reportMessage(
               inherited.element, MessageKind.INVALID_OVERRIDE_METHOD, () {
-            compiler.reportError(
-                compiler.createMessage(
+            reporter.reportError(
+                reporter.createMessage(
                     declared.element,
                     errorKind,
                     {'name': declared.name.text,
                      'class': cls.thisType,
                      'inheritedClass': inherited.declarer}),
                 <DiagnosticMessage>[
-                    compiler.createMessage(
+                    reporter.createMessage(
                         inherited.element,
                         infoKind,
                         {'name': declared.name.text,
@@ -435,8 +442,8 @@
                                MessageKind warningKind,
                                MessageKind infoKind) {
               reportMessage(marker, MessageKind.INVALID_OVERRIDE_METHOD, () {
-                compiler.reportWarning(
-                    compiler.createMessage(
+                reporter.reportWarning(
+                    reporter.createMessage(
                         declared.element,
                         warningKind,
                         {'declaredType': declared.type,
@@ -445,7 +452,7 @@
                          'inheritedType': inherited.type,
                          'inheritedClass': inherited.declarer}),
                     <DiagnosticMessage>[
-                        compiler.createMessage(
+                        reporter.createMessage(
                             inherited.element,
                             infoKind,
                             {'name': declared.name.text,
@@ -502,14 +509,14 @@
                               MessageKind errorMessage,
                               Element contextElement,
                               MessageKind contextMessage) {
-    compiler.reportError(
-        compiler.createMessage(
+    reporter.reportError(
+        reporter.createMessage(
             errorneousElement,
             errorMessage,
             {'memberName': contextElement.name,
              'className': contextElement.enclosingClass.name}),
         <DiagnosticMessage>[
-            compiler.createMessage(contextElement, contextMessage),
+            reporter.createMessage(contextElement, contextMessage),
         ]);
   }
 
@@ -713,7 +720,7 @@
               () => new Setlet<Member>()).add(inherited);
         }
         if (someAreGetters && !allAreGetters) {
-          DiagnosticMessage warning = compiler.createMessage(
+          DiagnosticMessage warning = reporter.createMessage(
               cls,
               MessageKind.INHERIT_GETTER_AND_METHOD,
               {'class': thisType, 'name': name.text });
@@ -732,12 +739,12 @@
                 kind = MessageKind.INHERITED_EXPLICIT_GETTER;
               }
             }
-            infos.add(compiler.createMessage(
+            infos.add(reporter.createMessage(
                 inherited.element,
                 kind,
                 {'class': inherited.declarer, 'name': name.text}));
           }
-          compiler.reportWarning(warning, infos);
+          reporter.reportWarning(warning, infos);
           interfaceMembers[name] = new ErroneousMember(inheritedMembers);
         } else if (subtypesOfAllInherited.length == 1) {
           // All signatures have the same type.
@@ -846,6 +853,7 @@
   /// this class.
   MembersCreator _prepareCreator(Compiler compiler) {
     if (classMembers == null) {
+      ensureResolved(compiler.resolution);
       classMembers = new Map<Name, Member>();
 
       if (interfaceMembersAreClassMembers) {
diff --git a/pkg/compiler/lib/src/resolution/constructors.dart b/pkg/compiler/lib/src/resolution/constructors.dart
index 94dcc525..256be2d 100644
--- a/pkg/compiler/lib/src/resolution/constructors.dart
+++ b/pkg/compiler/lib/src/resolution/constructors.dart
@@ -11,7 +11,7 @@
 import '../constants/expressions.dart';
 import '../dart_types.dart';
 import '../diagnostics/diagnostic_listener.dart' show
-    DiagnosticListener,
+    DiagnosticReporter,
     DiagnosticMessage;
 import '../diagnostics/invariant.dart' show
     invariant;
@@ -62,7 +62,7 @@
 
   ResolutionRegistry get registry => visitor.registry;
 
-  DiagnosticListener get listener => visitor.compiler;
+  DiagnosticReporter get reporter => visitor.reporter;
 
   bool isFieldInitializer(SendSet node) {
     if (node.selector.asIdentifier() == null) return false;
@@ -72,13 +72,13 @@
   }
 
   reportDuplicateInitializerError(Element field, Node init, Node existing) {
-    listener.reportError(
-        listener.createMessage(
+    reporter.reportError(
+        reporter.createMessage(
             init,
             MessageKind.DUPLICATE_INITIALIZER,
             {'fieldName': field.name}),
         <DiagnosticMessage>[
-            listener.createMessage(
+            reporter.createMessage(
                 existing,
                 MessageKind.ALREADY_INITIALIZED,
                 {'fieldName': field.name}),
@@ -92,7 +92,7 @@
     if (initialized.containsKey(field)) {
       reportDuplicateInitializerError(field, init, initialized[field]);
     } else if (field.isFinal) {
-      field.parseNode(visitor.compiler);
+      field.parseNode(visitor.resolution.parsing);
       Expression initializer = field.initializer;
       if (initializer != null) {
         reportDuplicateInitializerError(field, init, initializer);
@@ -111,23 +111,23 @@
     if (isFieldInitializer(init)) {
       target = constructor.enclosingClass.lookupLocalMember(name);
       if (target == null) {
-        listener.reportErrorMessage(
+        reporter.reportErrorMessage(
             selector, MessageKind.CANNOT_RESOLVE, {'name': name});
         target = new ErroneousFieldElementX(
             selector.asIdentifier(), constructor.enclosingClass);
       } else if (target.kind != ElementKind.FIELD) {
-        listener.reportErrorMessage(
+        reporter.reportErrorMessage(
             selector, MessageKind.NOT_A_FIELD, {'fieldName': name});
         target = new ErroneousFieldElementX(
             selector.asIdentifier(), constructor.enclosingClass);
       } else if (!target.isInstanceMember) {
-        listener.reportErrorMessage(
+        reporter.reportErrorMessage(
             selector, MessageKind.INIT_STATIC_FIELD, {'fieldName': name});
       } else {
         field = target;
       }
     } else {
-      listener.reportErrorMessage(
+      reporter.reportErrorMessage(
           init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER);
     }
     registry.useElement(init, target);
@@ -152,7 +152,7 @@
     if (isSuperCall) {
       // Calculate correct lookup target and constructor name.
       if (identical(constructor.enclosingClass, visitor.compiler.objectClass)) {
-        listener.reportErrorMessage(
+        reporter.reportErrorMessage(
             diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT);
         isValidAsConstant = false;
       } else {
@@ -264,23 +264,23 @@
       MessageKind kind = isImplicitSuperCall
           ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT
           : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR;
-      listener.reportErrorMessage(
+      reporter.reportErrorMessage(
           diagnosticNode, kind, {'constructorName': fullConstructorName});
       isValidAsConstant = false;
     } else {
-      lookedupConstructor.computeType(visitor.compiler);
+      lookedupConstructor.computeType(visitor.resolution);
       if (!call.signatureApplies(lookedupConstructor.functionSignature)) {
         MessageKind kind = isImplicitSuperCall
                            ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT
                            : MessageKind.NO_MATCHING_CONSTRUCTOR;
-        listener.reportErrorMessage(diagnosticNode, kind);
+        reporter.reportErrorMessage(diagnosticNode, kind);
         isValidAsConstant = false;
       } else if (constructor.isConst
                  && !lookedupConstructor.isConst) {
         MessageKind kind = isImplicitSuperCall
                            ? MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT
                            : MessageKind.CONST_CALLS_NON_CONST;
-        listener.reportErrorMessage(diagnosticNode, kind);
+        reporter.reportErrorMessage(diagnosticNode, kind);
         isValidAsConstant = false;
       }
     }
@@ -350,13 +350,13 @@
       } else if (link.head.asSend() != null) {
         final Send call = link.head.asSend();
         if (call.argumentsNode == null) {
-          listener.reportErrorMessage(
+          reporter.reportErrorMessage(
               link.head, MessageKind.INVALID_INITIALIZER);
           continue;
         }
         if (Initializers.isSuperConstructorCall(call)) {
           if (resolvedSuper) {
-            listener.reportErrorMessage(
+            reporter.reportErrorMessage(
                 call, MessageKind.DUPLICATE_SUPER_INITIALIZER);
           }
           ResolutionResult result = resolveSuperOrThisForSend(call);
@@ -373,12 +373,12 @@
           // constructor is also const, we already reported an error in
           // [resolveMethodElement].
           if (functionNode.hasBody() && !constructor.isConst) {
-            listener.reportErrorMessage(
+            reporter.reportErrorMessage(
                 functionNode, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY);
           }
           // Check that there are no other initializers.
           if (!initializers.tail.isEmpty) {
-            listener.reportErrorMessage(
+            reporter.reportErrorMessage(
                 call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER);
           } else {
             constructor.isRedirectingGenerative = true;
@@ -388,7 +388,7 @@
           signature.forEachParameter((ParameterElement parameter) {
             if (parameter.isInitializingFormal) {
               Node node = parameter.node;
-              listener.reportErrorMessage(
+              reporter.reportErrorMessage(
                   node, MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED);
               isValidAsConstant = false;
             }
@@ -409,12 +409,12 @@
           }
           return result.element;
         } else {
-          listener.reportErrorMessage(
+          reporter.reportErrorMessage(
               call, MessageKind.CONSTRUCTOR_CALL_EXPECTED);
           return null;
         }
       } else {
-        listener.reportErrorMessage(
+        reporter.reportErrorMessage(
             link.head, MessageKind.INVALID_INITIALIZER);
       }
     }
@@ -462,10 +462,10 @@
       registry.registerThrowRuntimeError();
     }
     if (isError || inConstContext) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           diagnosticNode, kind, arguments);
     } else {
-      compiler.reportWarningMessage(
+      reporter.reportWarningMessage(
           diagnosticNode, kind, arguments);
     }
     ErroneousElement error = new ErroneousConstructorElementX(
@@ -481,7 +481,7 @@
       Node diagnosticNode,
       String constructorName) {
     ClassElement cls = type.element;
-    cls.ensureResolved(compiler);
+    cls.ensureResolved(resolution);
     ConstructorElement constructor = findConstructor(
         resolver.enclosingElement.library, cls, constructorName);
     if (constructor == null) {
@@ -495,14 +495,14 @@
           {'constructorName': fullConstructorName},
           missingConstructor: true);
     } else if (inConstContext && !constructor.isConst) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST);
       return new ConstructorResult(
           ConstructorResultKind.NON_CONSTANT, constructor, type);
     } else {
       if (constructor.isGenerativeConstructor) {
         if (cls.isAbstract) {
-          compiler.reportWarningMessage(
+          reporter.reportWarningMessage(
               diagnosticNode, MessageKind.ABSTRACT_CLASS_INSTANTIATION);
           registry.registerAbstractClassInstantiation();
           return new ConstructorResult(
@@ -587,7 +587,7 @@
 
     Identifier name = node.selector.asIdentifier();
     if (name == null) {
-      compiler.internalError(node.selector, 'unexpected node');
+      reporter.internalError(node.selector, 'unexpected node');
     }
 
     if (receiver.type != null) {
@@ -606,7 +606,7 @@
       Element member = prefix.lookupLocalMember(name.source);
       return constructorResultForElement(node, name.source, member);
     } else {
-      return compiler.internalError(
+      return reporter.internalError(
           node.receiver, 'unexpected receiver $receiver');
     }
   }
@@ -614,7 +614,7 @@
   ConstructorResult visitIdentifier(Identifier node) {
     String name = node.source;
     Element element = resolver.reportLookupErrorIfAny(
-        lookupInScope(compiler, node, resolver.scope, name), node, name);
+        lookupInScope(reporter, node, resolver.scope, name), node, name);
     registry.useElement(node, element);
     // TODO(johnniwinther): Change errors to warnings, cf. 11.11.1.
     return constructorResultForElement(node, name, element);
@@ -629,7 +629,7 @@
 
   ConstructorResult constructorResultForElement(
       Node node, String name, Element element) {
-    element = Elements.unwrap(element, compiler, node);
+    element = Elements.unwrap(element, reporter, node);
     if (element == null) {
       return reportAndCreateErroneousConstructorElement(
           node,
@@ -641,13 +641,13 @@
       return constructorResultForErroneous(node, element);
     } else if (element.isClass) {
       ClassElement cls = element;
-      cls.computeType(compiler);
+      cls.computeType(resolution);
       return constructorResultForType(node, cls.rawType);
     } else if (element.isPrefix) {
       return new ConstructorResult.forElement(element);
     } else if (element.isTypedef) {
       TypedefElement typdef = element;
-      typdef.ensureResolved(compiler);
+      typdef.ensureResolved(resolution);
       return constructorResultForType(node, typdef.rawType);
     } else if (element.isTypeVariable) {
       TypeVariableElement typeVariableElement = element;
@@ -699,7 +699,7 @@
           MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE,
           {'typeVariableName': name});
     }
-    return compiler.internalError(node, "Unexpected constructor type $type");
+    return reporter.internalError(node, "Unexpected constructor type $type");
   }
 
 }
diff --git a/pkg/compiler/lib/src/resolution/enum_creator.dart b/pkg/compiler/lib/src/resolution/enum_creator.dart
index 02c2c53..127833d 100644
--- a/pkg/compiler/lib/src/resolution/enum_creator.dart
+++ b/pkg/compiler/lib/src/resolution/enum_creator.dart
@@ -4,8 +4,11 @@
 
 library dart2js.resolution.enum_creator;
 
-import '../compiler.dart';
+import '../core_types.dart' show
+    CoreTypes;
 import '../dart_types.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import '../elements/elements.dart';
 import '../elements/modelx.dart';
 import '../tokens/keyword.dart' show
@@ -179,18 +182,19 @@
 }
 
 class EnumCreator {
-  final Compiler compiler;
+  final DiagnosticReporter reporter;
+  final CoreTypes coreTypes;
   final EnumClassElementX enumClass;
 
-  EnumCreator(this.compiler, this.enumClass);
+  EnumCreator(this.reporter, this.coreTypes, this.enumClass);
 
   void createMembers() {
     Enum node = enumClass.node;
     InterfaceType enumType = enumClass.thisType;
     AstBuilder builder = new AstBuilder(enumClass.position.charOffset);
 
-    InterfaceType intType = compiler.intClass.computeType(compiler);
-    InterfaceType stringType = compiler.stringClass.computeType(compiler);
+    InterfaceType intType = coreTypes.intType;
+    InterfaceType stringType = coreTypes.stringType;
 
     EnumFieldElementX addInstanceMember(String name, InterfaceType type) {
       Identifier identifier = builder.identifier(name);
@@ -199,7 +203,7 @@
       variableList.type = type;
       EnumFieldElementX variable = new EnumFieldElementX(
           identifier, enumClass, variableList, identifier);
-      enumClass.addMember(variable, compiler);
+      enumClass.addMember(variable, reporter);
       return variable;
     }
 
@@ -229,8 +233,8 @@
         requiredParameterCount: 1,
         type: new FunctionType(constructor, const VoidType(),
             <DartType>[intType]));
-    constructor.functionSignatureCache = constructorSignature;
-    enumClass.addMember(constructor, compiler);
+    constructor.functionSignature = constructorSignature;
+    enumClass.addMember(constructor, reporter);
 
     List<FieldElement> enumValues = <FieldElement>[];
     VariableList variableList =
@@ -262,14 +266,13 @@
       EnumFieldElementX field = new EnumFieldElementX(
           name, enumClass, variableList, definition, initializer);
       enumValues.add(field);
-      enumClass.addMember(field, compiler);
+      enumClass.addMember(field, reporter);
       index++;
     }
 
     VariableList valuesVariableList =
         new VariableList(builder.modifiers(isStatic: true, isConst: true));
-    InterfaceType listType = compiler.listClass.computeType(compiler);
-    valuesVariableList.type = listType.createInstantiation([enumType]);
+    valuesVariableList.type = coreTypes.listType(enumType);
 
     Identifier valuesIdentifier = builder.identifier('values');
     // TODO(johnniwinther): Add type argument.
@@ -282,7 +285,7 @@
         valuesIdentifier, enumClass, valuesVariableList,
         definition, initializer);
 
-    enumClass.addMember(valuesVariable, compiler);
+    enumClass.addMember(valuesVariable, reporter);
 
     // TODO(johnniwinther): Support return type. Note `String` might be prefixed
     // or not imported within the current library.
@@ -301,8 +304,8 @@
         enumClass, Modifiers.EMPTY, toStringNode);
     FunctionSignatureX toStringSignature = new FunctionSignatureX(
         type: new FunctionType(toString, stringType));
-    toString.functionSignatureCache = toStringSignature;
-    enumClass.addMember(toString, compiler);
+    toString.functionSignature = toStringSignature;
+    enumClass.addMember(toString, reporter);
 
     enumClass.enumValues = enumValues;
   }
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 8546700..2237a60 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -15,7 +15,8 @@
 import '../core_types.dart';
 import '../dart_types.dart';
 import '../diagnostics/diagnostic_listener.dart' show
-    DiagnosticMessage;
+    DiagnosticMessage,
+    DiagnosticReporter;
 import '../diagnostics/invariant.dart' show
     invariant;
 import '../diagnostics/messages.dart' show
@@ -125,12 +126,6 @@
   int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION
       | ElementCategory.IMPLIES_TYPE;
 
-  /**
-   * Record of argument nodes to JS_INTERCEPTOR_CONSTANT for deferred
-   * processing.
-   */
-  Set<Node> argumentsToJsInterceptorConstant = null;
-
   /// When visiting the type declaration of the variable in a [ForIn] loop,
   /// the initializer of the variable is implicit and we should not emit an
   /// error when verifying that all final variables are initialized.
@@ -210,7 +205,7 @@
   Element reportLookupErrorIfAny(Element result, Node node, String name) {
     if (!Elements.isUnresolved(result)) {
       if (!inInstanceContext && result.isInstanceMember) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.NO_INSTANCE_AVAILABLE, {'name': name});
         return new ErroneousElementX(MessageKind.NO_INSTANCE_AVAILABLE,
                                      {'name': name},
@@ -222,7 +217,7 @@
               name,
               ambiguous.messageKind,
               ambiguous.messageArguments,
-              infos: ambiguous.computeInfos(enclosingElement, compiler),
+              infos: ambiguous.computeInfos(enclosingElement, reporter),
               isError: true);
       }
     }
@@ -307,11 +302,11 @@
       {List<DiagnosticMessage> infos: const <DiagnosticMessage>[],
        bool isError: false}) {
     if (isError) {
-      compiler.reportError(
-          compiler.createMessage(node, kind, arguments), infos);
+      reporter.reportError(
+          reporter.createMessage(node, kind, arguments), infos);
     } else {
-      compiler.reportWarning(
-          compiler.createMessage(node, kind, arguments), infos);
+      reporter.reportWarning(
+          reporter.createMessage(node, kind, arguments), infos);
     }
     // TODO(ahe): Use [allowedCategory] to synthesize a more precise subclass
     // of [ErroneousElementX]. For example, [ErroneousFieldElementX],
@@ -360,23 +355,23 @@
   ResolutionResult visitIdentifier(Identifier node) {
     if (node.isThis()) {
       if (!inInstanceContext) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.NO_INSTANCE_AVAILABLE, {'name': node});
       }
       return const NoneResult();
     } else if (node.isSuper()) {
       if (!inInstanceContext) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.NO_SUPER_IN_STATIC);
       }
       if ((ElementCategory.SUPER & allowedCategory) == 0) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.INVALID_USE_OF_SUPER);
       }
       return const NoneResult();
     } else {
       String name = node.source;
-      Element element = lookupInScope(compiler, node, scope, name);
+      Element element = lookupInScope(reporter, node, scope, name);
       if (Elements.isUnresolved(element) && name == 'dynamic') {
         // TODO(johnniwinther): Remove this hack when we can return more complex
         // objects than [Element] from this method.
@@ -401,7 +396,7 @@
       }
       if (!Elements.isUnresolved(element) && element.isClass) {
         ClassElement classElement = element;
-        classElement.ensureResolved(compiler);
+        classElement.ensureResolved(resolution);
       }
       if (element != null) {
         registry.useElement(node, element);
@@ -419,7 +414,7 @@
   TypeResult visitTypeAnnotation(TypeAnnotation node) {
     DartType type = resolveTypeAnnotation(node);
     if (inCheckContext) {
-      registry.registerIsCheck(type);
+      registry.registerCheckedModeCheck(type);
     }
     return new TypeResult(type);
   }
@@ -437,7 +432,7 @@
   }
 
   FunctionElement resolveConstructorRedirection(FunctionElementX constructor) {
-    FunctionExpression node = constructor.parseNode(compiler);
+    FunctionExpression node = constructor.parseNode(resolution.parsing);
 
     // A synthetic constructor does not have a node.
     if (node == null) return null;
@@ -457,7 +452,7 @@
     Element enclosingElement = function.enclosingElement;
     if (node.modifiers.isStatic &&
         enclosingElement.kind != ElementKind.CLASS) {
-      compiler.reportErrorMessage(node, MessageKind.ILLEGAL_STATIC);
+      reporter.reportErrorMessage(node, MessageKind.ILLEGAL_STATIC);
     }
 
     scope = new MethodScope(scope, function);
@@ -505,7 +500,7 @@
     });
     if (inCheckContext) {
       functionParameters.forEachParameter((ParameterElement element) {
-        registry.registerIsCheck(element.type);
+        registry.registerCheckedModeCheck(element.type);
       });
     }
   }
@@ -513,7 +508,7 @@
   ResolutionResult visitAssert(Assert node) {
     if (!compiler.enableAssertMessage) {
       if (node.hasMessage) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.EXPERIMENTAL_ASSERT_MESSAGE);
       }
     }
@@ -608,7 +603,7 @@
       {bool inFunctionDeclaration: false}) {
     bool doAddToScope = inFunctionDeclaration;
     if (!inFunctionDeclaration && node.name != null) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node.name,
           MessageKind.NAMED_FUNCTION_EXPRESSION,
           {'name': node.name});
@@ -624,7 +619,7 @@
         name, node, ElementKind.FUNCTION, Modifiers.EMPTY,
         enclosingElement);
     ResolverTask.processAsyncMarker(compiler, function, registry);
-    function.functionSignatureCache = SignatureResolver.analyze(
+    function.functionSignature = SignatureResolver.analyze(
         compiler,
         node.parameters,
         node.returnType,
@@ -773,7 +768,7 @@
           seenNamedArguments[source] = namedArgument;
         }
       } else if (!seenNamedArguments.isEmpty) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             argument, MessageKind.INVALID_ARGUMENT_AFTER_NAMED);
         isValidAsConstant = false;
       }
@@ -1195,7 +1190,7 @@
 
     Node typeNode = node.arguments.head;
     DartType type = resolveTypeAnnotation(typeNode);
-    registry.registerAsCheck(type);
+    registry.registerAsCast(type);
     registry.registerSendStructure(node, new AsStructure(type));
     return const NoneResult();
   }
@@ -1259,7 +1254,7 @@
                 knownExpressionType == coreTypes.doubleType;
             break;
           case UnaryOperatorKind.NOT:
-            compiler.internalError(node,
+            reporter.internalError(node,
                 "Unexpected user definable unary operator: $operator");
         }
         if (isValidConstant) {
@@ -1477,7 +1472,7 @@
           case BinaryOperatorKind.LOGICAL_AND:
           case BinaryOperatorKind.LOGICAL_OR:
           case BinaryOperatorKind.IF_NULL:
-            compiler.internalError(
+            reporter.internalError(
                 node, "Unexpected binary operator '${operator}'.");
             break;
         }
@@ -1528,7 +1523,7 @@
         case BinaryOperatorKind.LOGICAL_AND:
         case BinaryOperatorKind.LOGICAL_OR:
         case BinaryOperatorKind.IF_NULL:
-          compiler.internalError(
+          reporter.internalError(
               node, "Unexpected binary operator '${operator}'.");
           break;
       }
@@ -1593,7 +1588,7 @@
       return const NoneResult();
     } else {
       // TODO(johnniwinther): Handle get of `this` when it is a [Send] node.
-      compiler.internalError(
+      reporter.internalError(
           node, "Unexpected node '$node'.");
     }
     return const NoneResult();
@@ -1620,7 +1615,7 @@
       switch (semantics.kind) {
         case AccessKind.SUPER_METHOD:
           MethodElementX superMethod = semantics.element;
-          superMethod.computeSignature(compiler);
+          superMethod.computeType(resolution);
           if (!callStructure.signatureApplies(
                   superMethod.functionSignature)) {
             registry.registerThrowNoSuchMethod();
@@ -1648,7 +1643,7 @@
           // 'super' is not allowed.
           break;
         default:
-          compiler.internalError(
+          reporter.internalError(
               node, "Unexpected super property access $semantics.");
           break;
       }
@@ -1676,7 +1671,7 @@
           // 'super' is not allowed.
           break;
         default:
-          compiler.internalError(
+          reporter.internalError(
               node, "Unexpected super property access $semantics.");
           break;
       }
@@ -1878,7 +1873,7 @@
   ResolutionResult handleStaticMemberAccess(
       Send node, Name memberName, ClassElement receiverClass) {
     String name = memberName.text;
-    receiverClass.ensureResolved(compiler);
+    receiverClass.ensureResolved(resolution);
     if (node.isOperator) {
       // When the resolved receiver is a class, we can have two cases:
       //  1) a static send: C.foo, or
@@ -1912,7 +1907,7 @@
   ResolutionResult handleStaticMemberUpdate(
       Send node, Name memberName, ClassElement receiverClass) {
     String name = memberName.text;
-    receiverClass.ensureResolved(compiler);
+    receiverClass.ensureResolved(resolution);
     MembersCreator.computeClassMembersByName(
         compiler, receiverClass.declaration, name);
     Element member = receiverClass.lookupLocalMember(name);
@@ -1957,7 +1952,6 @@
     } else {
       semantics = new StaticAccess.typeParameterTypeLiteral(element);
     }
-    registry.registerTypeVariableExpression(element);
 
     registry.useElement(node, element);
     registry.registerTypeLiteral(node, element.type);
@@ -2010,14 +2004,10 @@
             MessageKind.ASSIGNING_TYPE, const {});
       }
 
-      if (node.isComplex) {
-        // We read the type variable before trying write to it.
-        registry.registerTypeVariableExpression(element);
-      }
-
       // TODO(23998): Remove this when all information goes through
       // the [SendStructure].
       registry.useElement(node, error);
+      // TODO(johnniwinther): Register only on read?
       registry.registerTypeLiteral(node, element.type);
       registry.registerThrowNoSuchMethod();
       semantics = new StaticAccess.typeParameterTypeLiteral(element);
@@ -2058,7 +2048,7 @@
     } else {
       analyzeConstantDeferred(node, enforceConst: false);
 
-      // TODO(johnniwinther): Avoid the need for a [Selector] here.
+      registry.setConstant(node, semantics.constant);
       registry.registerSendStructure(node, new GetStructure(semantics));
       return new ConstantResult(node, semantics.constant);
     }
@@ -2109,7 +2099,7 @@
       Send node,
       Name name,
       TypedefElement typdef) {
-    typdef.ensureResolved(compiler);
+    typdef.ensureResolved(resolution);
     DartType type = typdef.rawType;
     ConstantExpression constant = new TypeConstantExpression(type);
     AccessSemantics semantics = new ConstantAccess.typedefTypeLiteral(constant);
@@ -2122,7 +2112,7 @@
       SendSet node,
       Name name,
       TypedefElement typdef) {
-    typdef.ensureResolved(compiler);
+    typdef.ensureResolved(resolution);
     DartType type = typdef.rawType;
     ConstantExpression constant = new TypeConstantExpression(type);
     AccessSemantics semantics = new ConstantAccess.typedefTypeLiteral(constant);
@@ -2159,7 +2149,7 @@
       Send node,
       Name name,
       ClassElement cls) {
-    cls.ensureResolved(compiler);
+    cls.ensureResolved(resolution);
     DartType type = cls.rawType;
     ConstantExpression constant = new TypeConstantExpression(type);
     AccessSemantics semantics = new ConstantAccess.classTypeLiteral(constant);
@@ -2172,7 +2162,7 @@
       SendSet node,
       Name name,
       ClassElement cls) {
-    cls.ensureResolved(compiler);
+    cls.ensureResolved(resolution);
     DartType type = cls.rawType;
     ConstantExpression constant = new TypeConstantExpression(type);
     AccessSemantics semantics = new ConstantAccess.classTypeLiteral(constant);
@@ -2186,7 +2176,7 @@
       Send node,
       Name name,
       ClassElement cls) {
-    cls.ensureResolved(compiler);
+    cls.ensureResolved(resolution);
     if (sendIsMemberAccess) {
       registry.useElement(node, cls);
       return new PrefixResult(null, cls);
@@ -2524,7 +2514,7 @@
         name.text,
         element.messageKind,
         element.messageArguments,
-        infos: element.computeInfos(enclosingElement, compiler));
+        infos: element.computeInfos(enclosingElement, reporter));
     registry.registerThrowNoSuchMethod();
 
     // TODO(johnniwinther): Support ambiguous access as an [AccessSemantics].
@@ -2543,7 +2533,7 @@
         name.text,
         element.messageKind,
         element.messageArguments,
-        infos: element.computeInfos(enclosingElement, compiler));
+        infos: element.computeInfos(enclosingElement, reporter));
     registry.registerThrowNoSuchMethod();
 
     // TODO(johnniwinther): Support ambiguous access as an [AccessSemantics].
@@ -2576,7 +2566,7 @@
       switch (semantics.kind) {
         case AccessKind.LOCAL_FUNCTION:
           LocalFunctionElementX function = semantics.element;
-          function.computeSignature(compiler);
+          function.computeType(resolution);
           if (!callStructure.signatureApplies(function.functionSignature)) {
             registry.registerThrowNoSuchMethod();
             registry.registerDynamicInvocation(
@@ -2593,7 +2583,7 @@
               new UniverseSelector(selector, null));
           break;
         default:
-          compiler.internalError(node,
+          reporter.internalError(node,
               "Unexpected local access $semantics.");
           break;
       }
@@ -2639,7 +2629,7 @@
           }
           break;
         default:
-          compiler.internalError(node,
+          reporter.internalError(node,
               "Unexpected local access $semantics.");
           break;
       }
@@ -2724,12 +2714,12 @@
     }
     // TODO(johnniwinther): Needed to provoke a parsing and with it discovery
     // of parse errors to make [element] erroneous. Fix this!
-    member.computeType(compiler);
+    member.computeType(resolution);
 
 
     if (member == compiler.mirrorSystemGetNameFunction &&
         !compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) {
-      compiler.reportHintMessage(
+      reporter.reportHintMessage(
           node.selector, MessageKind.STATIC_FUNCTION_BLOAT,
           {'class': compiler.mirrorSystemClass.name,
            'name': compiler.mirrorSystemGetNameFunction.name});
@@ -2749,7 +2739,7 @@
         case AccessKind.STATIC_METHOD:
         case AccessKind.TOPLEVEL_METHOD:
           MethodElement method = semantics.element;
-          method.computeType(compiler);
+          method.computeType(resolution);
           if (!callStructure.signatureApplies(method.functionSignature)) {
             registry.registerThrowNoSuchMethod();
             registry.registerDynamicInvocation(
@@ -2757,7 +2747,7 @@
             isIncompatibleInvoke = true;
           } else {
             registry.registerStaticUse(semantics.element);
-            handleForeignCall(node, semantics.element, selector);
+            handleForeignCall(node, semantics.element, callStructure);
             if (method == compiler.identicalFunction &&
                 argumentsResult.isValidAsConstant) {
               result = new ConstantResult(node,
@@ -2787,7 +2777,7 @@
               MessageKind.CANNOT_RESOLVE_GETTER, const {});
           break;
         default:
-          compiler.internalError(node,
+          reporter.internalError(node,
               "Unexpected statically resolved access $semantics.");
           break;
       }
@@ -2822,7 +2812,7 @@
               MessageKind.CANNOT_RESOLVE_GETTER, const {});
           break;
         default:
-          compiler.internalError(node,
+          reporter.internalError(node,
               "Unexpected statically resolved access $semantics.");
           break;
       }
@@ -2907,7 +2897,7 @@
       MemberElement member = element;
       // TODO(johnniwinther): Needed to provoke a parsing and with it discovery
       // of parse errors to make [element] erroneous. Fix this!
-      member.computeType(compiler);
+      member.computeType(resolution);
       registry.registerStaticUse(member);
       if (member.isErroneous) {
         // [member] has parse errors.
@@ -2985,7 +2975,7 @@
     } else if (element.isStatic || element.isTopLevel) {
       return handleStaticOrTopLevelAccess(node, name, element);
     }
-    return compiler.internalError(node, "Unexpected resolved send: $element");
+    return reporter.internalError(node, "Unexpected resolved send: $element");
   }
 
   /// Handle update to resolved [element].
@@ -3023,7 +3013,7 @@
     } else if (element.isStatic || element.isTopLevel) {
       return handleStaticOrTopLevelUpdate(node, name, element);
     }
-    return compiler.internalError(node, "Unexpected resolved send: $element");
+    return reporter.internalError(node, "Unexpected resolved send: $element");
   }
 
   /// Handle an unqualified [Send], that is where the `node.receiver` is null,
@@ -3041,7 +3031,7 @@
     }
     // `name` or `name()`
     Name name = new Name(text, enclosingElement.library);
-    Element element = lookupInScope(compiler, node, scope, text);
+    Element element = lookupInScope(reporter, node, scope, text);
     if (element == null) {
       if (text == 'dynamic') {
         // `dynamic` or `dynamic()` where 'dynamic' is not declared in the
@@ -3066,7 +3056,7 @@
     Identifier selector = node.selector.asIdentifier();
     String text = selector.source;
     Name name = new Name(text, enclosingElement.library);
-    Element element = lookupInScope(compiler, node, scope, text);
+    Element element = lookupInScope(reporter, node, scope, text);
     if (element == null) {
       if (text == 'dynamic') {
         // `dynamic = b`, `dynamic++`, or `dynamic += b` where 'dynamic' is not
@@ -3110,34 +3100,22 @@
   }
 
   // TODO(johnniwinther): Move this to the backend resolution callbacks.
-  void handleForeignCall(Send node, Element target, Selector selector) {
+  void handleForeignCall(Send node,
+                         Element target,
+                         CallStructure callStructure) {
     if (target != null && compiler.backend.isForeign(target)) {
-      if (selector.name == 'JS') {
-        registry.registerJsCall(node, this);
-      } else if (selector.name == 'JS_EMBEDDED_GLOBAL') {
-        registry.registerJsEmbeddedGlobalCall(node, this);
-      } else if (selector.name == 'JS_BUILTIN') {
-        registry.registerJsBuiltinCall(node, this);
-      } else if (selector.name == 'JS_INTERCEPTOR_CONSTANT') {
-        if (!node.argumentsNode.isEmpty) {
-          Node argument = node.argumentsNode.nodes.head;
-          if (argumentsToJsInterceptorConstant == null) {
-            argumentsToJsInterceptorConstant = new Set<Node>();
-          }
-          argumentsToJsInterceptorConstant.add(argument);
-        }
-      }
+      registry.registerForeignCall(node, target, callStructure, this);
     }
   }
 
   /// Callback for native enqueuer to parse a type.  Returns [:null:] on error.
   DartType resolveTypeFromString(Node node, String typeName) {
-    Element element = lookupInScope(compiler, node, scope, typeName);
+    Element element = lookupInScope(reporter, node, scope, typeName);
     if (element == null) return null;
     if (element is! ClassElement) return null;
     ClassElement cls = element;
-    cls.ensureResolved(compiler);
-    return cls.computeType(compiler);
+    cls.ensureResolved(resolution);
+    return cls.computeType(resolution);
   }
 
   /// Handle index operations like `a[b] = c`, `a[b] += c`, and `a[b]++`.
@@ -3354,7 +3332,7 @@
           registry.registerStaticInvocation(semantics.setter);
           switch (semantics.kind) {
             case AccessKind.SUPER_FINAL_FIELD:
-              compiler.reportWarningMessage(
+              reporter.reportWarningMessage(
                   node,
                   MessageKind.ASSIGNING_FINAL_FIELD_IN_SUPER,
                   {'name': name,
@@ -3365,7 +3343,7 @@
               registry.registerSuperNoSuchMethod();
               break;
             case AccessKind.SUPER_METHOD:
-              compiler.reportWarningMessage(
+              reporter.reportWarningMessage(
                   node, MessageKind.ASSIGNING_METHOD_IN_SUPER,
                   {'name': name,
                    'superclassName': semantics.setter.enclosingClass.name});
@@ -3567,7 +3545,7 @@
     String name = node.slowNameString;
     registry.registerConstSymbol(name);
     if (!validateSymbol(node, name, reportError: false)) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node,
           MessageKind.UNSUPPORTED_LITERAL_SYMBOL,
           {'value': name});
@@ -3600,7 +3578,7 @@
 
   ResolutionResult visitRethrow(Rethrow node) {
     if (!inCatchBlock) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node, MessageKind.THROW_WITHOUT_EXPRESSION);
     }
     return const NoneResult();
@@ -3613,11 +3591,11 @@
         // It is a compile-time error if a return statement of the form
         // `return e;` appears in a generative constructor.  (Dart Language
         // Specification 13.12.)
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             expression,
             MessageKind.CANNOT_RETURN_FROM_CONSTRUCTOR);
       } else if (!node.isArrowBody && currentAsyncMarker.isYielding) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node,
             MessageKind.RETURN_IN_GENERATOR,
             {'modifier': currentAsyncMarker});
@@ -3628,8 +3606,8 @@
   }
 
   ResolutionResult visitYield(Yield node) {
-    compiler.streamClass.ensureResolved(compiler);
-    compiler.iterableClass.ensureResolved(compiler);
+    compiler.streamClass.ensureResolved(resolution);
+    compiler.iterableClass.ensureResolved(resolution);
     visit(node.expression);
     return const NoneResult();
   }
@@ -3637,9 +3615,9 @@
   ResolutionResult visitRedirectingFactoryBody(RedirectingFactoryBody node) {
     final isSymbolConstructor = enclosingElement == compiler.symbolConstructor;
     if (!enclosingElement.isFactoryConstructor) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node, MessageKind.FACTORY_REDIRECTION_IN_NON_FACTORY);
-      compiler.reportHintMessage(
+      reporter.reportHintMessage(
           enclosingElement, MessageKind.MISSING_FACTORY_KEYWORD);
     }
     ConstructorElementX constructor = enclosingElement;
@@ -3663,12 +3641,12 @@
     } else {
       if (isConstConstructor &&
           !redirectionTarget.isConst) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.CONSTRUCTOR_IS_NOT_CONST);
         isValidAsConstant = false;
       }
       if (redirectionTarget == constructor) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.CYCLIC_REDIRECTING_FACTORY);
         // TODO(johnniwinther): Create constant constructor for this case and
         // let evaluation detect the cyclicity.
@@ -3680,12 +3658,12 @@
     // redirecting constructor.
     ClassElement targetClass = redirectionTarget.enclosingClass;
     InterfaceType type = registry.getType(node);
-    FunctionType targetType = redirectionTarget.computeType(compiler)
+    FunctionType targetType = redirectionTarget.computeType(resolution)
         .subst(type.typeArguments, targetClass.typeVariables);
-    FunctionType constructorType = constructor.computeType(compiler);
+    FunctionType constructorType = constructor.computeType(resolution);
     bool isSubtype = compiler.types.isSubtype(targetType, constructorType);
     if (!isSubtype) {
-      compiler.reportWarningMessage(
+      reporter.reportWarningMessage(
           node,
           MessageKind.NOT_ASSIGNABLE,
           {'fromType': targetType, 'toType': constructorType});
@@ -3693,9 +3671,9 @@
       isValidAsConstant = false;
     }
 
-    redirectionTarget.computeType(compiler);
+    redirectionTarget.computeType(resolution);
     FunctionSignature targetSignature = redirectionTarget.functionSignature;
-    constructor.computeType(compiler);
+    constructor.computeType(resolution);
     FunctionSignature constructorSignature = constructor.functionSignature;
     if (!targetSignature.isCompatibleWith(constructorSignature)) {
       assert(!isSubtype);
@@ -3750,7 +3728,7 @@
   }
 
   ResolutionResult visitAwait(Await node) {
-    compiler.futureClass.ensureResolved(compiler);
+    compiler.futureClass.ensureResolved(resolution);
     visit(node.expression);
     return const NoneResult();
   }
@@ -3778,7 +3756,7 @@
         }
       }
       assert(modifierNode != null);
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           modifierNode, MessageKind.EXTRANEOUS_MODIFIER,
           {'modifier': modifier});
     }
@@ -3845,7 +3823,7 @@
     if (Elements.isUnresolved(constructor)) {
       return new ResolutionResult.forElement(constructor);
     }
-    constructor.computeType(compiler);
+    constructor.computeType(resolution);
     if (!callSelector.applies(constructor, compiler.world)) {
       registry.registerThrowNoSuchMethod();
     }
@@ -3855,7 +3833,7 @@
     registry.registerStaticUse(constructor.declaration);
     ClassElement cls = constructor.enclosingClass;
     if (cls.isEnumClass && currentClass != cls) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node,
           MessageKind.CANNOT_INSTANTIATE_ENUM,
           {'enumName': cls.name});
@@ -3864,7 +3842,7 @@
 
     InterfaceType type = registry.getType(node);
     if (node.isConst && type.containsTypeVariables) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node.send.selector,
           MessageKind.TYPE_VARIABLE_IN_CONSTANT);
       isValidAsConstant = false;
@@ -3885,7 +3863,7 @@
         ConstantValue name = compiler.constants.getConstantValue(constant);
         if (!name.isString) {
           DartType type = name.getType(coreTypes);
-          compiler.reportErrorMessage(
+          reporter.reportErrorMessage(
               argumentNode,
               MessageKind.STRING_EXPECTED,
               {'type': type});
@@ -3899,7 +3877,7 @@
       } else {
         if (!compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(
                 enclosingElement)) {
-          compiler.reportHintMessage(
+          reporter.reportHintMessage(
               node.newToken, MessageKind.NON_CONST_BLOAT,
               {'name': compiler.symbolClass.name});
         }
@@ -3953,7 +3931,7 @@
       if (cls == compiler.stringClass) continue;
       Element equals = cls.lookupMember('==');
       if (equals.enclosingClass != compiler.objectClass) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             spannable,
             MessageKind.CONST_MAP_KEY_OVERRIDES_EQUALS,
             {'type': keyType});
@@ -3975,27 +3953,6 @@
     if (value.isMap) {
       checkConstMapKeysDontOverrideEquals(node, value);
     }
-
-    // The type constant that is an argument to JS_INTERCEPTOR_CONSTANT names
-    // a class that will be instantiated outside the program by attaching a
-    // native class dispatch record referencing the interceptor.
-    if (argumentsToJsInterceptorConstant != null &&
-        argumentsToJsInterceptorConstant.contains(node)) {
-      if (value.isType) {
-        TypeConstantValue typeConstant = value;
-        if (typeConstant.representedType is InterfaceType) {
-          registry.registerInstantiatedType(typeConstant.representedType);
-        } else {
-          compiler.reportErrorMessage(
-              node,
-              MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
-        }
-      } else {
-        compiler.reportErrorMessage(
-            node,
-            MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
-      }
-    }
   }
 
   void analyzeConstantDeferred(Node node, {bool enforceConst: true}) {
@@ -4008,14 +3965,14 @@
     if (name.isEmpty) return true;
     if (name.startsWith('_')) {
       if (reportError) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.PRIVATE_IDENTIFIER, {'value': name});
       }
       return false;
     }
     if (!symbolValidationPattern.hasMatch(name)) {
       if (reportError) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.INVALID_SYMBOL, {'value': name});
       }
       return false;
@@ -4046,7 +4003,7 @@
         this, node, malformedIsError: malformedIsError,
         deferredIsMalformed: deferredIsMalformed);
     if (inCheckContext) {
-      registry.registerIsCheck(type);
+      registry.registerCheckedModeCheck(type);
       registry.registerRequiredType(type, enclosingElement);
     }
     return type;
@@ -4062,13 +4019,13 @@
       Link<Node> nodes = arguments.nodes;
       if (nodes.isEmpty) {
         // The syntax [: <>[] :] is not allowed.
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             arguments, MessageKind.MISSING_TYPE_ARGUMENT);
         isValidAsConstant = false;
       } else {
         typeArgument = resolveTypeAnnotation(nodes.head);
         for (nodes = nodes.tail; !nodes.isEmpty; nodes = nodes.tail) {
-          compiler.reportWarningMessage(
+          reporter.reportWarningMessage(
               nodes.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT);
           resolveTypeAnnotation(nodes.head);
         }
@@ -4077,7 +4034,7 @@
     DartType listType;
     if (typeArgument != null) {
       if (node.isConst && typeArgument.containsTypeVariables) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             arguments.nodes.head,
             MessageKind.TYPE_VARIABLE_IN_CONSTANT);
         isValidAsConstant = false;
@@ -4086,8 +4043,11 @@
     } else {
       listType = coreTypes.listType();
     }
-    registry.setType(node, listType);
-    registry.registerInstantiatedType(listType);
+    registry.registerLiteralList(
+        node,
+        listType,
+        isConstant: node.isConst,
+        isEmpty: node.elements.isEmpty);
     registry.registerRequiredType(listType, enclosingElement);
     if (node.isConst) {
       List<ConstantExpression> constantExpressions = <ConstantExpression>[];
@@ -4172,7 +4132,7 @@
     if (node.target == null) {
       target = statementScope.currentBreakTarget();
       if (target == null) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.NO_BREAK_TARGET);
         return const NoneResult();
       }
@@ -4181,13 +4141,13 @@
       String labelName = node.target.source;
       LabelDefinition label = statementScope.lookupLabel(labelName);
       if (label == null) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node.target, MessageKind.UNBOUND_LABEL, {'labelName': labelName});
         return const NoneResult();
       }
       target = label.target;
       if (!target.statement.isValidBreakTarget()) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node.target, MessageKind.INVALID_BREAK);
         return const NoneResult();
       }
@@ -4203,7 +4163,7 @@
     if (node.target == null) {
       target = statementScope.currentContinueTarget();
       if (target == null) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.NO_CONTINUE_TARGET);
         return const NoneResult();
       }
@@ -4212,13 +4172,13 @@
       String labelName = node.target.source;
       LabelDefinition label = statementScope.lookupLabel(labelName);
       if (label == null) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node.target, MessageKind.UNBOUND_LABEL, {'labelName': labelName});
         return const NoneResult();
       }
       target = label.target;
       if (!target.statement.isValidContinueTarget()) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node.target, MessageKind.INVALID_CONTINUE);
       }
       label.setContinueTarget();
@@ -4289,26 +4249,26 @@
       loopVariable = registry.getDefinition(send);
       Identifier identifier = send.selector.asIdentifier();
       if (identifier == null) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             send.selector, MessageKind.INVALID_FOR_IN);
       } else {
         loopVariableSelector = new Selector.setter(
             new Name(identifier.source, library));
       }
       if (send.receiver != null) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             send.receiver, MessageKind.INVALID_FOR_IN);
       }
     } else if (variableDefinitions != null) {
       Link<Node> nodes = variableDefinitions.definitions.nodes;
       if (!nodes.tail.isEmpty) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             nodes.tail.head, MessageKind.INVALID_FOR_IN);
       }
       Node first = nodes.head;
       Identifier identifier = first.asIdentifier();
       if (identifier == null) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             first, MessageKind.INVALID_FOR_IN);
       } else {
         loopVariableSelector = new Selector.setter(
@@ -4316,7 +4276,7 @@
         loopVariable = registry.getDefinition(identifier);
       }
     } else {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           declaration, MessageKind.INVALID_FOR_IN);
     }
     if (loopVariableSelector != null) {
@@ -4353,7 +4313,7 @@
       if (element.isTarget) {
         registry.defineLabel(element.label, element);
       } else {
-        compiler.reportWarningMessage(
+        reporter.reportWarningMessage(
             element.label,
             MessageKind.UNUSED_LABEL,
             {'labelName': labelName});
@@ -4376,19 +4336,19 @@
       Link<Node> nodes = arguments.nodes;
       if (nodes.isEmpty) {
         // The syntax [: <>{} :] is not allowed.
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             arguments, MessageKind.MISSING_TYPE_ARGUMENT);
         isValidAsConstant = false;
       } else {
         keyTypeArgument = resolveTypeAnnotation(nodes.head);
         nodes = nodes.tail;
         if (nodes.isEmpty) {
-          compiler.reportWarningMessage(
+          reporter.reportWarningMessage(
               arguments, MessageKind.MISSING_TYPE_ARGUMENT);
         } else {
           valueTypeArgument = resolveTypeAnnotation(nodes.head);
           for (nodes = nodes.tail; !nodes.isEmpty; nodes = nodes.tail) {
-            compiler.reportWarningMessage(
+            reporter.reportWarningMessage(
                 nodes.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT);
             resolveTypeAnnotation(nodes.head);
           }
@@ -4402,12 +4362,16 @@
       mapType = coreTypes.mapType();
     }
     if (node.isConst && mapType.containsTypeVariables) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           arguments,
           MessageKind.TYPE_VARIABLE_IN_CONSTANT);
       isValidAsConstant = false;
     }
-    registry.registerMapLiteral(node, mapType, node.isConst);
+    registry.registerMapLiteral(
+        node,
+        mapType,
+        isConstant: node.isConst,
+        isEmpty: node.entries.isEmpty);
     registry.registerRequiredType(mapType, enclosingElement);
     if (node.isConst) {
 
@@ -4500,16 +4464,16 @@
           // We only report the bad type on the first class element. All others
           // get a "type differs" error.
           if (caseType.element == compiler.doubleClass) {
-            compiler.reportErrorMessage(
+            reporter.reportErrorMessage(
                 node,
                 MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS,
                 {'type': "double"});
           } else if (caseType.element == compiler.functionClass) {
-            compiler.reportErrorMessage(
+            reporter.reportErrorMessage(
                 node, MessageKind.SWITCH_CASE_FORBIDDEN,
                 {'type': "Function"});
           } else if (value.isObject && overridesEquals(caseType)) {
-            compiler.reportErrorMessage(
+            reporter.reportErrorMessage(
                 firstCase.expression,
                 MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS,
                 {'type': caseType});
@@ -4517,16 +4481,16 @@
         } else {
           if (caseType != firstCaseType) {
             if (error == null) {
-              error = compiler.createMessage(
+              error = reporter.createMessage(
                   node,
                   MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL,
                   {'type': firstCaseType});
-              infos.add(compiler.createMessage(
+              infos.add(reporter.createMessage(
                   firstCase.expression,
                   MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE,
                   {'type': firstCaseType}));
             }
-            infos.add(compiler.createMessage(
+            infos.add(reporter.createMessage(
                 caseMatch.expression,
                 MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE,
                 {'type': caseType}));
@@ -4535,7 +4499,7 @@
       }
     }
     if (error != null) {
-      compiler.reportError(error, infos);
+      reporter.reportError(error, infos);
     }
   }
 
@@ -4559,13 +4523,13 @@
         LabelDefinition existingElement = continueLabels[labelName];
         if (existingElement != null) {
           // It's an error if the same label occurs twice in the same switch.
-          compiler.reportError(
-              compiler.createMessage(
+          reporter.reportError(
+              reporter.createMessage(
                   label,
                   MessageKind.DUPLICATE_LABEL,
                   {'labelName': labelName}),
               <DiagnosticMessage>[
-                  compiler.createMessage(
+                  reporter.createMessage(
                     existingElement.label,
                     MessageKind.EXISTING_LABEL,
                     {'labelName': labelName}),
@@ -4574,13 +4538,13 @@
           // It's only a warning if it shadows another label.
           existingElement = statementScope.lookupLabel(labelName);
           if (existingElement != null) {
-            compiler.reportWarning(
-                compiler.createMessage(
+            reporter.reportWarning(
+                reporter.createMessage(
                     label,
                     MessageKind.DUPLICATE_LABEL,
                     {'labelName': labelName}),
                 <DiagnosticMessage>[
-                    compiler.createMessage(
+                    reporter.createMessage(
                         existingElement.label,
                         MessageKind.EXISTING_LABEL,
                         {'labelName': labelName}),
@@ -4596,7 +4560,7 @@
       cases = cases.tail;
       // Test that only the last case, if any, is a default case.
       if (switchCase.defaultKeyword != null && !cases.isEmpty) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             switchCase, MessageKind.INVALID_CASE_DEFAULT);
       }
     }
@@ -4642,7 +4606,7 @@
 
     visit(node.tryBlock);
     if (node.catchBlocks.isEmpty && node.finallyBlock == null) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node.getEndToken().next, MessageKind.NO_CATCH_NOR_FINALLY);
     }
     visit(node.catchBlocks);
@@ -4659,7 +4623,7 @@
     if (node.formals != null) {
       Link<Node> formalsToProcess = node.formals.nodes;
       if (formalsToProcess.isEmpty) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.EMPTY_CATCH_DECLARATION);
       } else {
         exceptionDefinition = formalsToProcess.head.asVariableDefinitions();
@@ -4669,7 +4633,7 @@
           formalsToProcess = formalsToProcess.tail;
           if (!formalsToProcess.isEmpty) {
             for (Node extra in formalsToProcess) {
-              compiler.reportErrorMessage(
+              reporter.reportErrorMessage(
                   extra, MessageKind.EXTRA_CATCH_DECLARATION);
             }
           }
@@ -4686,17 +4650,17 @@
         // sequence of optional parameters.
         NodeList nodeList = link.head.asNodeList();
         if (nodeList != null) {
-          compiler.reportErrorMessage(
+          reporter.reportErrorMessage(
               nodeList, MessageKind.OPTIONAL_PARAMETER_IN_CATCH);
         } else {
           VariableDefinitions declaration = link.head;
           for (Node modifier in declaration.modifiers.nodes) {
-            compiler.reportErrorMessage(
+            reporter.reportErrorMessage(
                 modifier, MessageKind.PARAMETER_WITH_MODIFIER_IN_CATCH);
           }
           TypeAnnotation type = declaration.type;
           if (type != null) {
-            compiler.reportErrorMessage(
+            reporter.reportErrorMessage(
                 type, MessageKind.PARAMETER_WITH_TYPE_IN_CATCH);
           }
         }
@@ -4730,7 +4694,7 @@
 }
 
 /// Looks up [name] in [scope] and unwraps the result.
-Element lookupInScope(Compiler compiler, Node node,
+Element lookupInScope(DiagnosticReporter reporter, Node node,
                       Scope scope, String name) {
-  return Elements.unwrap(scope.lookup(name), compiler, node);
+  return Elements.unwrap(scope.lookup(name), reporter, node);
 }
diff --git a/pkg/compiler/lib/src/resolution/registry.dart b/pkg/compiler/lib/src/resolution/registry.dart
index de12ef0..51aa37c 100644
--- a/pkg/compiler/lib/src/resolution/registry.dart
+++ b/pkg/compiler/lib/src/resolution/registry.dart
@@ -5,7 +5,13 @@
 library dart2js.resolution.registry;
 
 import '../common/backend_api.dart' show
-    Backend;
+    Backend,
+    ForeignResolver;
+import '../common/resolution.dart' show
+    Feature,
+    ListLiteralUse,
+    MapLiteralUse,
+    ResolutionWorldImpact;
 import '../common/registry.dart' show
     Registry;
 import '../compiler.dart' show
@@ -15,12 +21,14 @@
 import '../diagnostics/invariant.dart' show
     invariant;
 import '../enqueue.dart' show
-    ResolutionEnqueuer,
-    WorldImpact;
+    ResolutionEnqueuer;
 import '../elements/elements.dart';
+import '../helpers/helpers.dart';
 import '../tree/tree.dart';
 import '../util/util.dart' show
     Setlet;
+import '../universe/call_structure.dart' show
+    CallStructure;
 import '../universe/selector.dart' show
     Selector;
 import '../universe/universe.dart' show
@@ -34,11 +42,7 @@
 import 'tree_elements.dart' show
     TreeElementMapping;
 
-/// [ResolutionRegistry] collects all resolution information. It stores node
-/// related information in a [TreeElements] mapping and registers calls with
-/// [Backend], [World] and [Enqueuer].
-// TODO(johnniwinther): Split this into an interface and implementation class.
-
+// TODO(johnniwinther): Remove this.
 class EagerRegistry implements Registry {
   final Compiler compiler;
   final TreeElementMapping mapping;
@@ -97,19 +101,35 @@
   String toString() => 'EagerRegistry for ${mapping.analyzedElement}';
 }
 
-class ResolutionWorldImpact implements WorldImpact {
+class _ResolutionWorldImpact implements ResolutionWorldImpact {
   final Registry registry;
+  // TODO(johnniwinther): Do we benefit from lazy initialization of the
+  // [Setlet]s?
   Setlet<UniverseSelector> _dynamicInvocations;
   Setlet<UniverseSelector> _dynamicGetters;
   Setlet<UniverseSelector> _dynamicSetters;
   Setlet<InterfaceType> _instantiatedTypes;
   Setlet<Element> _staticUses;
-  Setlet<DartType> _checkedTypes;
+  Setlet<DartType> _isChecks;
+  Setlet<DartType> _asCasts;
+  Setlet<DartType> _checkedModeChecks;
   Setlet<MethodElement> _closurizedFunctions;
+  Setlet<LocalFunctionElement> _closures;
+  Setlet<Feature> _features;
+  // TODO(johnniwinther): This seems to be a union of other sets.
+  Setlet<DartType> _requiredTypes;
+  Setlet<MapLiteralUse> _mapLiterals;
+  Setlet<ListLiteralUse> _listLiterals;
+  Setlet<DartType> _typeLiterals;
+  Setlet<String> _constSymbolNames;
 
-  ResolutionWorldImpact(Compiler compiler, TreeElementMapping mapping)
+  _ResolutionWorldImpact(Compiler compiler, TreeElementMapping mapping)
       : this.registry = new EagerRegistry(compiler, mapping);
 
+  void registerDependency(Element element) {
+    registry.registerDependency(element);
+  }
+
   void registerDynamicGetter(UniverseSelector selector) {
     if (_dynamicGetters == null) {
       _dynamicGetters = new Setlet<UniverseSelector>();
@@ -150,10 +170,6 @@
   }
 
   void registerInstantiatedType(InterfaceType type) {
-    // TODO(johnniwinther): Enable this when registration doesn't require a
-    // [Registry].
-    throw new UnsupportedError(
-        'Lazy registration of instantiated not supported.');
     if (_instantiatedTypes == null) {
       _instantiatedTypes = new Setlet<InterfaceType>();
     }
@@ -166,6 +182,58 @@
         ? _instantiatedTypes : const <InterfaceType>[];
   }
 
+  void registerTypeLiteral(DartType type) {
+    if (_typeLiterals == null) {
+      _typeLiterals = new Setlet<DartType>();
+    }
+    _typeLiterals.add(type);
+  }
+
+  @override
+  Iterable<DartType> get typeLiterals {
+    return _typeLiterals != null
+        ? _typeLiterals : const <DartType>[];
+  }
+
+  void registerRequiredType(DartType type) {
+    if (_requiredTypes == null) {
+      _requiredTypes = new Setlet<DartType>();
+    }
+    _requiredTypes.add(type);
+  }
+
+  @override
+  Iterable<DartType> get requiredTypes {
+    return _requiredTypes != null
+        ? _requiredTypes : const <DartType>[];
+  }
+
+  void registerMapLiteral(MapLiteralUse mapLiteralUse) {
+    if (_mapLiterals == null) {
+      _mapLiterals = new Setlet<MapLiteralUse>();
+    }
+    _mapLiterals.add(mapLiteralUse);
+  }
+
+  @override
+  Iterable<MapLiteralUse> get mapLiterals {
+    return _mapLiterals != null
+        ? _mapLiterals : const <MapLiteralUse>[];
+  }
+
+  void registerListLiteral(ListLiteralUse listLiteralUse) {
+    if (_listLiterals == null) {
+      _listLiterals = new Setlet<ListLiteralUse>();
+    }
+    _listLiterals.add(listLiteralUse);
+  }
+
+  @override
+  Iterable<ListLiteralUse> get listLiterals {
+    return _listLiterals != null
+        ? _listLiterals : const <ListLiteralUse>[];
+  }
+
   void registerStaticUse(Element element) {
     if (_staticUses == null) {
       _staticUses = new Setlet<Element>();
@@ -178,17 +246,43 @@
     return _staticUses != null ? _staticUses : const <Element>[];
   }
 
-  void registerCheckedType(DartType type) {
-    if (_checkedTypes == null) {
-      _checkedTypes = new Setlet<DartType>();
+  void registerIsCheck(DartType type) {
+    if (_isChecks == null) {
+      _isChecks = new Setlet<DartType>();
     }
-    _checkedTypes.add(type);
+    _isChecks.add(type);
   }
 
   @override
-  Iterable<DartType> get checkedTypes {
-    return _checkedTypes != null
-        ? _checkedTypes : const <DartType>[];
+  Iterable<DartType> get isChecks {
+    return _isChecks != null
+        ? _isChecks : const <DartType>[];
+  }
+
+  void registerAsCast(DartType type) {
+    if (_asCasts == null) {
+      _asCasts = new Setlet<DartType>();
+    }
+    _asCasts.add(type);
+  }
+
+  @override
+  Iterable<DartType> get asCasts {
+    return _asCasts != null
+        ? _asCasts : const <DartType>[];
+  }
+
+  void registerCheckedModeCheckedType(DartType type) {
+    if (_checkedModeChecks == null) {
+      _checkedModeChecks = new Setlet<DartType>();
+    }
+    _checkedModeChecks.add(type);
+  }
+
+  @override
+  Iterable<DartType> get checkedModeChecks {
+    return _checkedModeChecks != null
+        ? _checkedModeChecks : const <DartType>[];
   }
 
   void registerClosurizedFunction(MethodElement element) {
@@ -203,17 +297,61 @@
     return _closurizedFunctions != null
         ? _closurizedFunctions : const <MethodElement>[];
   }
+
+  void registerClosure(LocalFunctionElement element) {
+    if (_closures == null) {
+      _closures = new Setlet<LocalFunctionElement>();
+    }
+    _closures.add(element);
+  }
+
+  @override
+  Iterable<LocalFunctionElement> get closures {
+    return _closures != null
+        ? _closures : const <LocalFunctionElement>[];
+  }
+
+  void registerConstSymbolName(String name) {
+    if (_constSymbolNames == null) {
+      _constSymbolNames = new Setlet<String>();
+    }
+    _constSymbolNames.add(name);
+  }
+
+  @override
+  Iterable<String> get constSymbolNames {
+    return _constSymbolNames != null
+        ? _constSymbolNames : const <String>[];
+  }
+
+  void registerFeature(Feature feature) {
+    if (_features == null) {
+      _features = new Setlet<Feature>();
+    }
+    _features.add(feature);
+  }
+
+  @override
+  Iterable<Feature> get features {
+    return _features != null ? _features : const <Feature>[];
+  }
+
+  String toString() => '$registry';
 }
 
+/// [ResolutionRegistry] collects all resolution information. It stores node
+/// related information in a [TreeElements] mapping and registers calls with
+/// [Backend], [World] and [Enqueuer].
+// TODO(johnniwinther): Split this into an interface and implementation class.
 class ResolutionRegistry implements Registry {
   final Compiler compiler;
   final TreeElementMapping mapping;
-  final ResolutionWorldImpact worldImpact;
+  final _ResolutionWorldImpact worldImpact;
 
   ResolutionRegistry(Compiler compiler, TreeElementMapping mapping)
       : this.compiler = compiler,
         this.mapping = mapping,
-        this.worldImpact = new ResolutionWorldImpact(compiler, mapping);
+        this.worldImpact = new _ResolutionWorldImpact(compiler, mapping);
 
   bool get isForResolution => true;
 
@@ -398,59 +536,61 @@
   }
 
   void registerImplicitSuperCall(FunctionElement superConstructor) {
-    universe.registerImplicitSuperCall(this, superConstructor);
+    registerDependency(superConstructor);
   }
 
   // TODO(johnniwinther): Remove this.
   // Use [registerInstantiatedType] of `rawType` instead.
   @deprecated
   void registerInstantiatedClass(ClassElement element) {
-    element.ensureResolved(compiler);
+    element.ensureResolved(compiler.resolution);
     registerInstantiatedType(element.rawType);
   }
 
   void registerLazyField() {
-    backend.resolutionCallbacks.onLazyField(this);
+    worldImpact.registerFeature(Feature.LAZY_FIELD);
   }
 
-  void registerMetadataConstant(MetadataAnnotation metadata,
-                                Element annotatedElement) {
-    backend.registerMetadataConstant(metadata, annotatedElement, this);
+  void registerMetadataConstant(MetadataAnnotation metadata) {
+    backend.registerMetadataConstant(metadata, metadata.annotatedElement, this);
   }
 
   void registerThrowRuntimeError() {
-    backend.resolutionCallbacks.onThrowRuntimeError(this);
+    worldImpact.registerFeature(Feature.THROW_RUNTIME_ERROR);
   }
 
   void registerCompileTimeError(ErroneousElement error) {
-    backend.resolutionCallbacks.onCompileTimeError(this, error);
+    worldImpact.registerFeature(Feature.COMPILE_TIME_ERROR);
   }
 
   void registerTypeVariableBoundCheck() {
-    backend.resolutionCallbacks.onTypeVariableBoundCheck(this);
+    worldImpact.registerFeature(Feature.TYPE_VARIABLE_BOUNDS_CHECK);
   }
 
   void registerThrowNoSuchMethod() {
-    backend.resolutionCallbacks.onThrowNoSuchMethod(this);
+    worldImpact.registerFeature(Feature.THROW_NO_SUCH_METHOD);
   }
 
-  void registerIsCheck(DartType type) {
-    worldImpact.registerCheckedType(type);
-    backend.resolutionCallbacks.onIsCheck(type, this);
+  /// Register a checked mode check against [type].
+  void registerCheckedModeCheck(DartType type) {
+    worldImpact.registerCheckedModeCheckedType(type);
     mapping.addRequiredType(type);
   }
 
-  void registerAsCheck(DartType type) {
-    registerIsCheck(type);
-    backend.resolutionCallbacks.onAsCheck(type, this);
+  /// Register an is-test or is-not-test of [type].
+  void registerIsCheck(DartType type) {
+    worldImpact.registerIsCheck(type);
+    mapping.addRequiredType(type);
+  }
+
+  /// Register an as-cast of [type].
+  void registerAsCast(DartType type) {
+    worldImpact.registerAsCast(type);
     mapping.addRequiredType(type);
   }
 
   void registerClosure(LocalFunctionElement element) {
-    if (element.computeType(compiler).containsTypeVariables) {
-      backend.registerClosureWithFreeTypeVariables(element, world, this);
-    }
-    world.registerClosure(element);
+    worldImpact.registerClosure(element);
   }
 
   void registerSuperUse(Node node) {
@@ -462,40 +602,39 @@
   }
 
   void registerSuperNoSuchMethod() {
-    backend.resolutionCallbacks.onSuperNoSuchMethod(this);
-  }
-
-  void registerTypeVariableExpression(TypeVariableElement element) {
-    backend.resolutionCallbacks.onTypeVariableExpression(this, element);
+    worldImpact.registerFeature(Feature.SUPER_NO_SUCH_METHOD);
   }
 
   void registerTypeLiteral(Send node, DartType type) {
     mapping.setType(node, type);
-    backend.resolutionCallbacks.onTypeLiteral(type, this);
-    backend.registerInstantiatedType(compiler.coreTypes.typeType, world, this);
+    worldImpact.registerTypeLiteral(type);
   }
 
-  void registerMapLiteral(Node node, DartType type, bool isConstant) {
+  void registerLiteralList(Node node,
+                           InterfaceType type,
+                           {bool isConstant,
+                            bool isEmpty}) {
     setType(node, type);
-    backend.resolutionCallbacks.onMapLiteral(this, type, isConstant);
+    worldImpact.registerListLiteral(
+        new ListLiteralUse(type, isConstant: isConstant, isEmpty: isEmpty));
   }
 
-  // TODO(johnniwinther): Remove the [ResolverVisitor] dependency. Its only
-  // needed to lookup types in the current scope.
-  void registerJsCall(Node node, ResolverVisitor visitor) {
-    world.registerJsCall(node, visitor);
+  void registerMapLiteral(Node node,
+                          InterfaceType type,
+                          {bool isConstant,
+                           bool isEmpty}) {
+    setType(node, type);
+    worldImpact.registerMapLiteral(
+        new MapLiteralUse(type, isConstant: isConstant, isEmpty: isEmpty));
   }
 
-  // TODO(johnniwinther): Remove the [ResolverVisitor] dependency. Its only
-  // needed to lookup types in the current scope.
-  void registerJsEmbeddedGlobalCall(Node node, ResolverVisitor visitor) {
-    world.registerJsEmbeddedGlobalCall(node, visitor);
-  }
-
-  // TODO(johnniwinther): Remove the [ResolverVisitor] dependency. Its only
-  // needed to lookup types in the current scope.
-  void registerJsBuiltinCall(Node node, ResolverVisitor visitor) {
-    world.registerJsBuiltinCall(node, visitor);
+  void registerForeignCall(Node node,
+                           Element element,
+                           CallStructure callStructure,
+                           ResolverVisitor visitor) {
+    backend.registerForeignCall(
+        node, element, callStructure,
+        new ForeignResolutionResolver(visitor, this));
   }
 
   void registerGetOfStaticFunction(FunctionElement element) {
@@ -513,49 +652,49 @@
   }
 
   void registerConstSymbol(String name) {
-    backend.registerConstSymbol(name, this);
+    worldImpact.registerConstSymbolName(name);
   }
 
   void registerSymbolConstructor() {
-    backend.resolutionCallbacks.onSymbolConstructor(this);
+    worldImpact.registerFeature(Feature.SYMBOL_CONSTRUCTOR);
   }
 
   void registerInstantiatedType(InterfaceType type) {
-    backend.registerInstantiatedType(type, world, this);
+    worldImpact.registerInstantiatedType(type);
     mapping.addRequiredType(type);
   }
 
   void registerAbstractClassInstantiation() {
-    backend.resolutionCallbacks.onAbstractClassInstantiation(this);
+    worldImpact.registerFeature(Feature.ABSTRACT_CLASS_INSTANTIATION);
   }
 
   void registerNewSymbol() {
-    backend.registerNewSymbol(this);
+    worldImpact.registerFeature(Feature.NEW_SYMBOL);
   }
 
   void registerRequiredType(DartType type, Element enclosingElement) {
-    backend.registerRequiredType(type, enclosingElement);
+    worldImpact.registerRequiredType(type);
     mapping.addRequiredType(type);
   }
 
   void registerStringInterpolation() {
-    backend.resolutionCallbacks.onStringInterpolation(this);
+    worldImpact.registerFeature(Feature.STRING_INTERPOLATION);
   }
 
   void registerFallThroughError() {
-    backend.resolutionCallbacks.onFallThroughError(this);
+    worldImpact.registerFeature(Feature.FALL_THROUGH_ERROR);
   }
 
   void registerCatchStatement() {
-    backend.resolutionCallbacks.onCatchStatement(this);
+    worldImpact.registerFeature(Feature.CATCH_STATEMENT);
   }
 
   void registerStackTraceInCatch() {
-    backend.resolutionCallbacks.onStackTraceInCatch(this);
+    worldImpact.registerFeature(Feature.STACK_TRACE_IN_CATCH);
   }
 
   void registerSyncForIn(Node node) {
-    backend.resolutionCallbacks.onSyncForIn(this);
+    worldImpact.registerFeature(Feature.SYNC_FOR_IN);
   }
 
   ClassElement defaultSuperclass(ClassElement element) {
@@ -568,7 +707,7 @@
   }
 
   void registerThrowExpression() {
-    backend.resolutionCallbacks.onThrowExpression(this);
+    worldImpact.registerFeature(Feature.THROW_EXPRESSION);
   }
 
   void registerDependency(Element element) {
@@ -586,11 +725,12 @@
   }
 
   void registerInstantiation(InterfaceType type) {
-    backend.registerInstantiatedType(type, world, this);
+    registerInstantiatedType(type);
   }
 
   void registerAssert(bool hasMessage) {
-    backend.resolutionCallbacks.onAssert(hasMessage, this);
+    worldImpact.registerFeature(
+        hasMessage ? Feature.ASSERT_WITH_MESSAGE : Feature.ASSERT);
   }
 
   void registerSendStructure(Send node, SendStructure sendStructure) {
@@ -604,18 +744,52 @@
   }
 
   void registerAsyncMarker(FunctionElement element) {
-    backend.registerAsyncMarker(element, world, this);
+    switch (element.asyncMarker) {
+      case AsyncMarker.SYNC:
+        break;
+      case AsyncMarker.SYNC_STAR:
+        worldImpact.registerFeature(Feature.SYNC_STAR);
+        break;
+      case AsyncMarker.ASYNC:
+        worldImpact.registerFeature(Feature.ASYNC);
+        break;
+      case AsyncMarker.ASYNC_STAR:
+        worldImpact.registerFeature(Feature.ASYNC_STAR);
+        break;
+    }
   }
 
   void registerAsyncForIn(AsyncForIn node) {
-    backend.resolutionCallbacks.onAsyncForIn(node, this);
+    worldImpact.registerFeature(Feature.ASYNC_FOR_IN);
   }
 
   void registerIncDecOperation() {
-    backend.resolutionCallbacks.onIncDecOperation(this);
+    worldImpact.registerFeature(Feature.INC_DEC_OPERATION);
   }
 
   void registerTryStatement() {
     mapping.containsTryStatement = true;
   }
 }
+
+class ForeignResolutionResolver implements ForeignResolver {
+  final ResolverVisitor visitor;
+  final ResolutionRegistry registry;
+
+  ForeignResolutionResolver(this.visitor, this.registry);
+
+  @override
+  ConstantExpression getConstant(Node node) {
+    return registry.getConstant(node);
+  }
+
+  @override
+  void registerInstantiatedType(InterfaceType type) {
+    registry.registerInstantiatedType(type);
+  }
+
+  @override
+  DartType resolveTypeFromString(Node node, String typeName) {
+    return visitor.resolveTypeFromString(node, typeName);
+  }
+}
diff --git a/pkg/compiler/lib/src/resolution/resolution.dart b/pkg/compiler/lib/src/resolution/resolution.dart
index 7256536..2f5a617 100644
--- a/pkg/compiler/lib/src/resolution/resolution.dart
+++ b/pkg/compiler/lib/src/resolution/resolution.dart
@@ -8,6 +8,10 @@
 
 import '../common/names.dart' show
     Identifiers;
+import '../common/resolution.dart' show
+    Parsing,
+    Resolution,
+    ResolutionWorldImpact;
 import '../common/tasks.dart' show
     CompilerTask,
     DeferredAction;
@@ -19,7 +23,8 @@
     ConstantValue;
 import '../dart_types.dart';
 import '../diagnostics/diagnostic_listener.dart' show
-    DiagnosticMessage;
+    DiagnosticMessage,
+    DiagnosticReporter;
 import '../diagnostics/invariant.dart' show
     invariant;
 import '../diagnostics/messages.dart' show
@@ -69,19 +74,23 @@
 
   String get name => 'Resolver';
 
-  WorldImpact resolve(Element element) {
+  Resolution get resolution => compiler.resolution;
+
+  Parsing get parsing => compiler.parsing;
+
+  ResolutionWorldImpact resolve(Element element) {
     return measure(() {
       if (Elements.isErroneous(element)) {
         // TODO(johnniwinther): Add a predicate for this.
         assert(invariant(element, element is! ErroneousElement,
             message: "Element $element expected to have parse errors."));
         _ensureTreeElements(element);
-        return const WorldImpact();
+        return const ResolutionWorldImpact();
       }
 
       WorldImpact processMetadata([WorldImpact result]) {
         for (MetadataAnnotation metadata in element.implementation.metadata) {
-          metadata.ensureResolved(compiler);
+          metadata.ensureResolved(resolution);
         }
         return result;
       }
@@ -99,8 +108,8 @@
       }
       if (element.isClass) {
         ClassElement cls = element;
-        cls.ensureResolved(compiler);
-        return processMetadata(const WorldImpact());
+        cls.ensureResolved(resolution);
+        return processMetadata(const ResolutionWorldImpact());
       } else if (element.isTypedef) {
         TypedefElement typdef = element;
         return processMetadata(resolveTypedef(typdef));
@@ -123,7 +132,7 @@
       // Ensure that we follow redirections through implementation elements.
       redirection = redirection.implementation;
       if (seen.contains(redirection)) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE);
         return;
       }
@@ -135,6 +144,8 @@
   static void processAsyncMarker(Compiler compiler,
                                  BaseFunctionElementX element,
                                  ResolutionRegistry registry) {
+    DiagnosticReporter reporter = compiler.reporter;
+    Resolution resolution = compiler.resolution;
     FunctionExpression functionExpression = element.node;
     AsyncModifier asyncModifier = functionExpression.asyncModifier;
     if (asyncModifier != null) {
@@ -146,18 +157,18 @@
         element.asyncMarker = AsyncMarker.SYNC_STAR;
       }
       if (element.isAbstract) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             asyncModifier,
             MessageKind.ASYNC_MODIFIER_ON_ABSTRACT_METHOD,
             {'modifier': element.asyncMarker});
       } else if (element.isConstructor) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             asyncModifier,
             MessageKind.ASYNC_MODIFIER_ON_CONSTRUCTOR,
             {'modifier': element.asyncMarker});
       } else {
         if (element.isSetter) {
-          compiler.reportErrorMessage(
+          reporter.reportErrorMessage(
               asyncModifier,
               MessageKind.ASYNC_MODIFIER_ON_SETTER,
               {'modifier': element.asyncMarker});
@@ -165,7 +176,7 @@
         }
         if (functionExpression.body.asReturn() != null &&
             element.asyncMarker.isYielding) {
-          compiler.reportErrorMessage(
+          reporter.reportErrorMessage(
               asyncModifier,
               MessageKind.YIELDING_MODIFIER_ON_ARROW_BODY,
               {'modifier': element.asyncMarker});
@@ -174,13 +185,13 @@
       registry.registerAsyncMarker(element);
       switch (element.asyncMarker) {
       case AsyncMarker.ASYNC:
-        compiler.futureClass.ensureResolved(compiler);
+        compiler.futureClass.ensureResolved(resolution);
         break;
       case AsyncMarker.ASYNC_STAR:
-        compiler.streamClass.ensureResolved(compiler);
+        compiler.streamClass.ensureResolved(resolution);
         break;
       case AsyncMarker.SYNC_STAR:
-        compiler.iterableClass.ensureResolved(compiler);
+        compiler.iterableClass.ensureResolved(resolution);
         break;
       }
     }
@@ -197,22 +208,22 @@
 
   WorldImpact resolveMethodElementImplementation(
       FunctionElement element, FunctionExpression tree) {
-    return compiler.withCurrentElement(element, () {
+    return reporter.withCurrentElement(element, () {
       if (element.isExternal && tree.hasBody()) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             element,
             MessageKind.EXTERNAL_WITH_BODY,
             {'functionName': element.name});
       }
       if (element.isConstructor) {
         if (tree.returnType != null) {
-          compiler.reportErrorMessage(
+          reporter.reportErrorMessage(
               tree, MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE);
         }
         if (element.isConst &&
             tree.hasBody() &&
             !tree.isRedirectingFactory) {
-          compiler.reportErrorMessage(
+          reporter.reportErrorMessage(
               tree, MessageKind.CONST_CONSTRUCTOR_HAS_BODY);
         }
       }
@@ -233,7 +244,7 @@
           resolveRedirectingConstructor(resolver, tree, element, redirection);
         }
       } else if (tree.initializers != null) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             tree, MessageKind.FUNCTION_WITH_INITIALIZER);
       }
 
@@ -264,7 +275,7 @@
       if (Elements.isInstanceMethod(element) &&
           element.name == Identifiers.noSuchMethod_ &&
           _isNativeClassOrExtendsNativeClass(enclosingClass)) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             tree, MessageKind.NO_SUCH_METHOD_IN_NATIVE);
       }
 
@@ -275,14 +286,14 @@
 
   WorldImpact resolveMethodElement(FunctionElementX element) {
     assert(invariant(element, element.isDeclaration));
-    return compiler.withCurrentElement(element, () {
-      if (compiler.enqueuer.resolution.hasBeenResolved(element)) {
+    return reporter.withCurrentElement(element, () {
+      if (compiler.enqueuer.resolution.hasBeenProcessed(element)) {
         // TODO(karlklose): Remove the check for [isConstructor]. [elememts]
         // should never be non-null, not even for constructors.
         assert(invariant(element, element.isConstructor,
             message: 'Non-constructor element $element '
                      'has already been analyzed.'));
-        return const WorldImpact();
+        return const ResolutionWorldImpact();
       }
       if (element.isSynthesized) {
         if (element.isGenerativeConstructor) {
@@ -293,7 +304,7 @@
           // Ensure the signature of the synthesized element is
           // resolved. This is the only place where the resolver is
           // seeing this element.
-          element.computeSignature(compiler);
+          element.computeType(resolution);
           if (!target.isErroneous) {
             registry.registerStaticUse(target);
             registry.registerImplicitSuperCall(target);
@@ -302,11 +313,11 @@
         } else {
           assert(element.isDeferredLoaderGetter || element.isErroneous);
           _ensureTreeElements(element);
-          return const WorldImpact();
+          return const ResolutionWorldImpact();
         }
       } else {
-        element.parseNode(compiler);
-        element.computeType(compiler);
+        element.parseNode(resolution.parsing);
+        element.computeType(resolution);
         FunctionElementX implementation = element;
         if (element.isExternal) {
           implementation = compiler.backend.resolveExternalFunction(element);
@@ -330,9 +341,9 @@
   }
 
   WorldImpact resolveField(FieldElementX element) {
-    VariableDefinitions tree = element.parseNode(compiler);
+    VariableDefinitions tree = element.parseNode(parsing);
     if(element.modifiers.isStatic && element.isTopLevel) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           element.modifiers.getStatic(),
           MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC);
     }
@@ -356,10 +367,10 @@
       // [Compiler.analyzeSignaturesOnly] is set.
       visitor.visit(initializer);
     } else if (modifiers.isConst) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           element, MessageKind.CONST_WITHOUT_INITIALIZER);
     } else if (modifiers.isFinal && !element.isInstanceMember) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           element, MessageKind.FINAL_WITHOUT_INITIALIZER);
     } else {
       registry.registerInstantiatedClass(compiler.nullClass);
@@ -383,7 +394,7 @@
     }
 
     // Perform various checks as side effect of "computing" the type.
-    element.computeType(compiler);
+    element.computeType(resolution);
 
     return registry.worldImpact;
   }
@@ -391,7 +402,7 @@
   DartType resolveTypeAnnotation(Element element, TypeAnnotation annotation) {
     DartType type = resolveReturnType(element, annotation);
     if (type.isVoid) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           annotation, MessageKind.VOID_NOT_ALLOWED);
     }
     return type;
@@ -426,7 +437,7 @@
 
       Element nextTarget = target.immediateRedirectionTarget;
       if (seen.contains(nextTarget)) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.CYCLIC_REDIRECTING_FACTORY);
         targetType = target.enclosingClass.thisType;
         break;
@@ -455,7 +466,7 @@
       TreeElements treeElements = factory.treeElements;
       assert(invariant(node, treeElements != null,
           message: 'No TreeElements cached for $factory.'));
-      FunctionExpression functionNode = factory.parseNode(compiler);
+      FunctionExpression functionNode = factory.parseNode(parsing);
       RedirectingFactoryBody redirectionNode = functionNode.body;
       DartType factoryType = treeElements.getType(redirectionNode);
       if (!factoryType.isDynamic) {
@@ -473,10 +484,10 @@
    * called by [resolveClass] and [ClassSupertypeResolver].
    */
   void loadSupertypes(BaseClassElementX cls, Spannable from) {
-    compiler.withCurrentElement(cls, () => measure(() {
+    reporter.withCurrentElement(cls, () => measure(() {
       if (cls.supertypeLoadState == STATE_DONE) return;
       if (cls.supertypeLoadState == STATE_STARTED) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             from,
             MessageKind.CYCLIC_CLASS_HIERARCHY,
             {'className': cls.name});
@@ -484,7 +495,7 @@
         cls.hasIncompleteHierarchy = true;
         cls.allSupertypesAndSelf =
             compiler.objectClass.allSupertypesAndSelf.extendClass(
-                cls.computeType(compiler));
+                cls.computeType(resolution));
         cls.supertype = cls.allSupertypes.head;
         assert(invariant(from, cls.supertype != null,
             message: 'Missing supertype on cyclic class $cls.'));
@@ -492,9 +503,9 @@
         return;
       }
       cls.supertypeLoadState = STATE_STARTED;
-      compiler.withCurrentElement(cls, () {
+      reporter.withCurrentElement(cls, () {
         // TODO(ahe): Cache the node in cls.
-        cls.parseNode(compiler).accept(
+        cls.parseNode(parsing).accept(
             new ClassSupertypeResolver(compiler, cls));
         if (cls.supertypeLoadState != STATE_DONE) {
           cls.supertypeLoadState = STATE_DONE;
@@ -519,7 +530,7 @@
   // 'TypeDeclarationResolver'.
   _resolveTypeDeclaration(TypeDeclarationElement element,
                           resolveTypeDeclaration()) {
-    return compiler.withCurrentElement(element, () {
+    return reporter.withCurrentElement(element, () {
       return measure(() {
         TypeDeclarationElement previousResolvedTypeDeclaration =
             currentlyResolvedTypeDeclaration;
@@ -528,7 +539,7 @@
         if (previousResolvedTypeDeclaration == null) {
           do {
             while (!pendingClassesToBeResolved.isEmpty) {
-              pendingClassesToBeResolved.removeFirst().ensureResolved(compiler);
+              pendingClassesToBeResolved.removeFirst().ensureResolved(resolution);
             }
             while (!pendingClassesToBePostProcessed.isEmpty) {
               _postProcessClassElement(
@@ -553,7 +564,7 @@
    * resolved.
    *
    * Warning: Do not call this method directly. Instead use
-   * [:element.ensureResolved(compiler):].
+   * [:element.ensureResolved(resolution):].
    */
   TreeElements resolveClass(BaseClassElementX element) {
     return _resolveTypeDeclaration(element, () {
@@ -567,7 +578,7 @@
 
   void ensureClassWillBeResolvedInternal(ClassElement element) {
     if (currentlyResolvedTypeDeclaration == null) {
-      element.ensureResolved(compiler);
+      element.ensureResolved(resolution);
     } else {
       pendingClassesToBeResolved.add(element);
     }
@@ -576,10 +587,10 @@
   void resolveClassInternal(BaseClassElementX element,
                             ResolutionRegistry registry) {
     if (!element.isPatch) {
-      compiler.withCurrentElement(element, () => measure(() {
+      reporter.withCurrentElement(element, () => measure(() {
         assert(element.resolutionState == STATE_NOT_STARTED);
         element.resolutionState = STATE_STARTED;
-        Node tree = element.parseNode(compiler);
+        Node tree = element.parseNode(parsing);
         loadSupertypes(element, tree);
 
         ClassResolverVisitor visitor =
@@ -591,14 +602,14 @@
       }));
       if (element.isPatched) {
         // Ensure handling patch after origin.
-        element.patch.ensureResolved(compiler);
+        element.patch.ensureResolved(resolution);
       }
     } else { // Handle patch classes:
       element.resolutionState = STATE_STARTED;
       // Ensure handling origin before patch.
-      element.origin.ensureResolved(compiler);
+      element.origin.ensureResolved(resolution);
       // Ensure that the type is computed.
-      element.computeType(compiler);
+      element.computeType(resolution);
       // Copy class hierarchy from origin.
       element.supertype = element.origin.supertype;
       element.interfaces = element.origin.interfaces;
@@ -614,7 +625,7 @@
 
   void _postProcessClassElement(BaseClassElementX element) {
     for (MetadataAnnotation metadata in element.implementation.metadata) {
-      metadata.ensureResolved(compiler);
+      metadata.ensureResolved(resolution);
       ConstantValue value =
           compiler.constants.getConstantValue(metadata.constant);
       if (!element.isProxy && compiler.isProxyConstant(value)) {
@@ -629,9 +640,9 @@
     // TODO(ahe): Avoid this eager resolution.
     element.forEachMember((_, Element member) {
       if (!member.isInstanceMember) {
-        compiler.withCurrentElement(member, () {
+        reporter.withCurrentElement(member, () {
           for (MetadataAnnotation metadata in member.implementation.metadata) {
-            metadata.ensureResolved(compiler);
+            metadata.ensureResolved(resolution);
           }
         });
       }
@@ -662,7 +673,7 @@
     int illegalFlags = modifiers.flags & ~Modifiers.FLAG_ABSTRACT;
     if (illegalFlags != 0) {
       Modifiers illegalModifiers = new Modifiers.withFlags(null, illegalFlags);
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           modifiers,
           MessageKind.ILLEGAL_MIXIN_APPLICATION_MODIFIERS,
           {'modifiers': illegalModifiers});
@@ -676,7 +687,7 @@
 
     // Check that we're not trying to use Object as a mixin.
     if (mixin.superclass == null) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           mixinApplication,
           MessageKind.ILLEGAL_MIXIN_OBJECT);
       // Avoid reporting additional errors for the Object class.
@@ -690,7 +701,7 @@
 
     // Check that the mixed in class has Object as its superclass.
     if (!mixin.superclass.isObject) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           mixin, MessageKind.ILLEGAL_MIXIN_SUPERCLASS);
     }
 
@@ -698,7 +709,7 @@
     // make sure we aren't mixing in methods that use 'super'.
     mixin.forEachLocalMember((AstElement member) {
       if (member.isGenerativeConstructor && !member.isSynthesized) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             member, MessageKind.ILLEGAL_MIXIN_CONSTRUCTOR);
       } else {
         // Get the resolution tree and check that the resolved member
@@ -707,7 +718,7 @@
         // mixin application has been performed.
         // TODO(johnniwinther): Obtain the [TreeElements] for [member]
         // differently.
-        if (compiler.enqueuer.resolution.hasBeenResolved(member)) {
+        if (compiler.enqueuer.resolution.hasBeenProcessed(member)) {
           checkMixinSuperUses(
               member.resolvedAst.elements,
               mixinApplication,
@@ -724,18 +735,18 @@
     if (resolutionTree == null) return;
     Iterable<Node> superUses = resolutionTree.superUses;
     if (superUses.isEmpty) return;
-    DiagnosticMessage error = compiler.createMessage(
+    DiagnosticMessage error = reporter.createMessage(
         mixinApplication,
         MessageKind.ILLEGAL_MIXIN_WITH_SUPER,
         {'className': mixin.name});
     // Show the user the problematic uses of 'super' in the mixin.
     List<DiagnosticMessage> infos = <DiagnosticMessage>[];
     for (Node use in superUses) {
-      infos.add(compiler.createMessage(
+      infos.add(reporter.createMessage(
           use,
           MessageKind.ILLEGAL_MIXIN_SUPER_USE));
     }
-    compiler.reportError(error, infos);
+    reporter.reportError(error, infos);
   }
 
   void checkClassMembers(ClassElement cls) {
@@ -746,13 +757,13 @@
     List<Element> constConstructors = <Element>[];
     List<Element> nonFinalInstanceFields = <Element>[];
     cls.forEachMember((holder, member) {
-      compiler.withCurrentElement(member, () {
+      reporter.withCurrentElement(member, () {
         // Perform various checks as side effect of "computing" the type.
-        member.computeType(compiler);
+        member.computeType(resolution);
 
         // Check modifiers.
         if (member.isFunction && member.modifiers.isFinal) {
-          compiler.reportErrorMessage(
+          reporter.reportErrorMessage(
               member, MessageKind.ILLEGAL_FINAL_METHOD_MODIFIER);
         }
         if (member.isConstructor) {
@@ -762,7 +773,7 @@
           if (mismatchedFlagsBits != 0) {
             final mismatchedFlags =
                 new Modifiers.withFlags(null, mismatchedFlagsBits);
-            compiler.reportErrorMessage(
+            reporter.reportErrorMessage(
                 member,
                 MessageKind.ILLEGAL_CONSTRUCTOR_MODIFIERS,
                 {'modifiers': mismatchedFlags});
@@ -773,7 +784,7 @@
         }
         if (member.isField) {
           if (member.modifiers.isConst && !member.modifiers.isStatic) {
-            compiler.reportErrorMessage(
+            reporter.reportErrorMessage(
                 member, MessageKind.ILLEGAL_CONST_FIELD_MODIFIER);
           }
           if (!member.modifiers.isStatic && !member.modifiers.isFinal) {
@@ -787,24 +798,24 @@
     if (!constConstructors.isEmpty && !nonFinalInstanceFields.isEmpty) {
       Spannable span = constConstructors.length > 1
           ? cls : constConstructors[0];
-      DiagnosticMessage error = compiler.createMessage(
+      DiagnosticMessage error = reporter.createMessage(
           span,
           MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS,
           {'className': cls.name});
       List<DiagnosticMessage> infos = <DiagnosticMessage>[];
       if (constConstructors.length > 1) {
         for (Element constructor in constConstructors) {
-          infos.add(compiler.createMessage(
+          infos.add(reporter.createMessage(
               constructor,
               MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR));
         }
       }
       for (Element field in nonFinalInstanceFields) {
-        infos.add(compiler.createMessage(
+        infos.add(reporter.createMessage(
             field,
             MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD));
       }
-      compiler.reportError(error, infos);
+      reporter.reportError(error, infos);
     }
   }
 
@@ -818,11 +829,11 @@
     ClassElement classElement = member.enclosingClass;
     Element lookupElement = classElement.lookupLocalMember(member.name);
     if (lookupElement == null) {
-      compiler.internalError(member,
+      reporter.internalError(member,
           "No abstract field for accessor");
     } else if (!identical(lookupElement.kind, ElementKind.ABSTRACT_FIELD)) {
       if (lookupElement.isErroneous || lookupElement.isAmbiguous) return;
-      compiler.internalError(member,
+      reporter.internalError(member,
           "Inaccessible abstract field for accessor");
     }
     AbstractFieldElement field = lookupElement;
@@ -836,11 +847,11 @@
     if (!identical(getterFlags, setterFlags)) {
       final mismatchedFlags =
         new Modifiers.withFlags(null, getterFlags ^ setterFlags);
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           field.getter,
           MessageKind.GETTER_MISMATCH,
           {'modifiers': mismatchedFlags});
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           field.setter,
           MessageKind.SETTER_MISMATCH,
           {'modifiers': mismatchedFlags});
@@ -876,7 +887,7 @@
       messageKind = MessageKind.TERNARY_OPERATOR_BAD_ARITY;
       requiredParameterCount = 2;
     } else {
-      compiler.internalError(function,
+      reporter.internalError(function,
           'Unexpected user defined operator $value');
     }
     checkArity(function, requiredParameterCount, messageKind, isMinus);
@@ -888,7 +899,7 @@
     Element hashCodeImplementation =
         cls.lookupLocalMember('hashCode');
     if (hashCodeImplementation != null) return;
-    compiler.reportHintMessage(
+    reporter.reportHintMessage(
         operatorEquals, MessageKind.OVERRIDE_EQUALS_NOT_HASH_CODE,
         {'class': cls.name});
   }
@@ -929,19 +940,19 @@
           errorNode = node.parameters.nodes.skip(requiredParameterCount).head;
         }
       }
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           errorNode, messageKind, {'operatorName': function.name});
     }
     if (signature.optionalParameterCount != 0) {
       Node errorNode =
           node.parameters.nodes.skip(signature.requiredParameterCount).head;
       if (signature.optionalParametersAreNamed) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             errorNode,
             MessageKind.OPERATOR_NAMED_PARAMETERS,
             {'operatorName': function.name});
       } else {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             errorNode,
             MessageKind.OPERATOR_OPTIONAL_PARAMETERS,
             {'operatorName': function.name});
@@ -953,14 +964,14 @@
                          MessageKind errorMessage,
                          Element contextElement,
                          MessageKind contextMessage) {
-    compiler.reportError(
-        compiler.createMessage(
+    reporter.reportError(
+        reporter.createMessage(
             errorneousElement,
             errorMessage,
             {'memberName': contextElement.name,
              'className': contextElement.enclosingClass.name}),
         <DiagnosticMessage>[
-            compiler.createMessage(contextElement, contextMessage),
+            reporter.createMessage(contextElement, contextMessage),
         ]);
   }
 
@@ -968,14 +979,13 @@
   FunctionSignature resolveSignature(FunctionElementX element) {
     MessageKind defaultValuesError = null;
     if (element.isFactoryConstructor) {
-      FunctionExpression body = element.parseNode(compiler);
+      FunctionExpression body = element.parseNode(parsing);
       if (body.isRedirectingFactory) {
         defaultValuesError = MessageKind.REDIRECTING_FACTORY_WITH_DEFAULT;
       }
     }
-    return compiler.withCurrentElement(element, () {
-      FunctionExpression node =
-          compiler.parser.measure(() => element.parseNode(compiler));
+    return reporter.withCurrentElement(element, () {
+      FunctionExpression node = element.parseNode(parsing);
       return measure(() => SignatureResolver.analyze(
           compiler, node.parameters, node.returnType, element,
           new ResolutionRegistry(compiler, _ensureTreeElements(element)),
@@ -985,17 +995,16 @@
   }
 
   WorldImpact resolveTypedef(TypedefElementX element) {
-    if (element.isResolved) return const WorldImpact();
+    if (element.isResolved) return const ResolutionWorldImpact();
     compiler.world.allTypedefs.add(element);
     return _resolveTypeDeclaration(element, () {
       ResolutionRegistry registry = new ResolutionRegistry(
           compiler, _ensureTreeElements(element));
-      return compiler.withCurrentElement(element, () {
+      return reporter.withCurrentElement(element, () {
         return measure(() {
           assert(element.resolutionState == STATE_NOT_STARTED);
           element.resolutionState = STATE_STARTED;
-          Typedef node =
-            compiler.parser.measure(() => element.parseNode(compiler));
+          Typedef node = element.parseNode(parsing);
           TypedefResolverVisitor visitor =
             new TypedefResolverVisitor(compiler, element, registry);
           visitor.visit(node);
@@ -1007,17 +1016,17 @@
   }
 
   void resolveMetadataAnnotation(MetadataAnnotationX annotation) {
-    compiler.withCurrentElement(annotation.annotatedElement, () => measure(() {
+    reporter.withCurrentElement(annotation.annotatedElement, () => measure(() {
       assert(annotation.resolutionState == STATE_NOT_STARTED);
       annotation.resolutionState = STATE_STARTED;
 
-      Node node = annotation.parseNode(compiler);
+      Node node = annotation.parseNode(parsing);
       Element annotatedElement = annotation.annotatedElement;
       AnalyzableElement context = annotatedElement.analyzableElement;
       ClassElement classElement = annotatedElement.enclosingClass;
       if (classElement != null) {
         // The annotation is resolved in the scope of [classElement].
-        classElement.ensureResolved(compiler);
+        classElement.ensureResolved(resolution);
       }
       assert(invariant(node, context != null,
           message: "No context found for metadata annotation "
@@ -1034,7 +1043,7 @@
       // and the annotated element instead. This will allow the backend to
       // retrieve the backend constant and only register metadata on the
       // elements for which it is needed. (Issue 17732).
-      registry.registerMetadataConstant(annotation, annotatedElement);
+      registry.registerMetadataConstant(annotation);
       annotation.resolutionState = STATE_DONE;
     }));
   }
@@ -1046,7 +1055,7 @@
       ParameterMetadataAnnotation metadataAnnotation =
           new ParameterMetadataAnnotation(annotation);
       metadataAnnotation.annotatedElement = element;
-      metadata.add(metadataAnnotation.ensureResolved(compiler));
+      metadata.add(metadataAnnotation.ensureResolved(resolution));
     }
     return metadata;
   }
diff --git a/pkg/compiler/lib/src/resolution/resolution_common.dart b/pkg/compiler/lib/src/resolution/resolution_common.dart
index eb7b80b..1b0b6b5 100644
--- a/pkg/compiler/lib/src/resolution/resolution_common.dart
+++ b/pkg/compiler/lib/src/resolution/resolution_common.dart
@@ -4,12 +4,15 @@
 
 library dart2js.resolution.common;
 
+import '../common/resolution.dart' show
+    Resolution;
 import '../common/tasks.dart' show
     DeferredAction;
 import '../compiler.dart' show
     Compiler;
 import '../diagnostics/diagnostic_listener.dart' show
-    DiagnosticMessage;
+    DiagnosticMessage,
+    DiagnosticReporter;
 import '../diagnostics/messages.dart' show
     MessageKind;
 import '../diagnostics/spannable.dart' show
@@ -29,8 +32,12 @@
 
   CommonResolverVisitor(Compiler this.compiler);
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
+  Resolution get resolution => compiler.resolution;
+
   R visitNode(Node node) {
-    return compiler.internalError(node,
+    return reporter.internalError(node,
         'internal error: Unhandled node: ${node.getObjectDescription()}');
   }
 
@@ -75,7 +82,7 @@
       if (element.name == 'yield' ||
           element.name == 'async' ||
           element.name == 'await') {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.ASYNC_KEYWORD_AS_IDENTIFIER,
             {'keyword': element.name,
              'modifier': currentAsyncMarker});
@@ -86,7 +93,7 @@
   /// Register [node] as the definition of [element].
   void defineLocalVariable(Node node, LocalVariableElement element) {
     if (element == null) {
-      throw compiler.internalError(node, 'element is null');
+      throw reporter.internalError(node, 'element is null');
     }
     checkLocalDefinitionName(node, element);
     registry.defineElement(node, element);
@@ -95,13 +102,13 @@
   void reportDuplicateDefinition(String name,
                                  Spannable definition,
                                  Spannable existing) {
-    compiler.reportError(
-        compiler.createMessage(
+    reporter.reportError(
+        reporter.createMessage(
             definition,
             MessageKind.DUPLICATE_DEFINITION,
             {'name': name}),
         <DiagnosticMessage>[
-            compiler.createMessage(
+            reporter.createMessage(
                 existing,
                 MessageKind.EXISTING_DEFINITION,
                 {'name': name}),
diff --git a/pkg/compiler/lib/src/resolution/signatures.dart b/pkg/compiler/lib/src/resolution/signatures.dart
index 858f9b5..831aed0 100644
--- a/pkg/compiler/lib/src/resolution/signatures.dart
+++ b/pkg/compiler/lib/src/resolution/signatures.dart
@@ -7,6 +7,8 @@
 import '../compiler.dart' show
     Compiler;
 import '../dart_types.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import '../diagnostics/invariant.dart' show
     invariant;
 import '../diagnostics/messages.dart' show
@@ -66,7 +68,7 @@
     // This must be a list of optional arguments.
     String value = node.beginToken.stringValue;
     if ((!identical(value, '[')) && (!identical(value, '{'))) {
-      compiler.internalError(node, "expected optional parameters");
+      reporter.internalError(node, "expected optional parameters");
     }
     optionalParametersAreNamed = (identical(value, '{'));
     isOptionalParameter = true;
@@ -78,26 +80,26 @@
   FormalElementX visitVariableDefinitions(VariableDefinitions node) {
     Link<Node> definitions = node.definitions.nodes;
     if (definitions.isEmpty) {
-      compiler.internalError(node, 'no parameter definition');
+      reporter.internalError(node, 'no parameter definition');
       return null;
     }
     if (!definitions.tail.isEmpty) {
-      compiler.internalError(definitions.tail.head, 'extra definition');
+      reporter.internalError(definitions.tail.head, 'extra definition');
       return null;
     }
     Node definition = definitions.head;
     if (definition is NodeList) {
-      compiler.internalError(node, 'optional parameters are not implemented');
+      reporter.internalError(node, 'optional parameters are not implemented');
     }
     if (node.modifiers.isConst) {
-      compiler.reportErrorMessage(node, MessageKind.FORMAL_DECLARED_CONST);
+      reporter.reportErrorMessage(node, MessageKind.FORMAL_DECLARED_CONST);
     }
     if (node.modifiers.isStatic) {
-      compiler.reportErrorMessage(node, MessageKind.FORMAL_DECLARED_STATIC);
+      reporter.reportErrorMessage(node, MessageKind.FORMAL_DECLARED_STATIC);
     }
 
     if (currentDefinitions != null) {
-      compiler.internalError(node, 'function type parameters not supported');
+      reporter.internalError(node, 'function type parameters not supported');
     }
     currentDefinitions = node;
     FormalElementX element = definition.accept(this);
@@ -113,7 +115,7 @@
     if (isOptionalParameter &&
         optionalParametersAreNamed &&
         Name.isPrivateName(node.source)) {
-      compiler.reportErrorMessage(node, MessageKind.PRIVATE_NAMED_PARAMETER);
+      reporter.reportErrorMessage(node, MessageKind.PRIVATE_NAMED_PARAMETER);
     }
   }
 
@@ -124,8 +126,7 @@
           compiler, functionExpression.parameters,
           functionExpression.returnType, element, registry,
           defaultValuesError: MessageKind.FUNCTION_TYPE_FORMAL_WITH_DEFAULT);
-      element.functionSignatureCache = functionSignature;
-      element.typeCache = functionSignature.type;
+      element.functionSignature = functionSignature;
     }
 
     if (currentDefinitions.type != null) {
@@ -148,7 +149,7 @@
         assert(invariant(currentDefinitions,
             link.head.asIdentifier() != null || link.head.asSend() != null));
         if (fieldElement != null) {
-          element.typeCache = fieldElement.computeType(compiler);
+          element.typeCache = fieldElement.computeType(resolution);
         } else {
           element.typeCache = const DynamicType();
         }
@@ -172,7 +173,7 @@
           functionExpression.name.asIdentifier() != null) {
         return functionExpression.name.asIdentifier();
       } else {
-        compiler.internalError(node,
+        reporter.internalError(node,
             'internal error: unimplemented receiver on parameter send');
         return null;
       }
@@ -205,12 +206,12 @@
     InitializingFormalElementX element;
     Identifier receiver = node.receiver.asIdentifier();
     if (receiver == null || !receiver.isThis()) {
-      compiler.reportErrorMessage(node, MessageKind.INVALID_PARAMETER);
+      reporter.reportErrorMessage(node, MessageKind.INVALID_PARAMETER);
       return new ErroneousInitializingFormalElementX(
           getParameterName(node), enclosingElement);
     } else {
       if (!enclosingElement.isGenerativeConstructor) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED);
         return new ErroneousInitializingFormalElementX(
             getParameterName(node), enclosingElement);
@@ -221,12 +222,12 @@
           enclosingElement.enclosingClass.lookupLocalMember(name.source);
       if (fieldElement == null ||
           !identical(fieldElement.kind, ElementKind.FIELD)) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.NOT_A_FIELD, {'fieldName': name});
         fieldElement = new ErroneousFieldElementX(
             name, enclosingElement.enclosingClass);
       } else if (!fieldElement.isInstanceMember) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.NOT_INSTANCE_FIELD, {'fieldName': name});
         fieldElement = new ErroneousFieldElementX(
             name, enclosingElement.enclosingClass);
@@ -250,7 +251,7 @@
     }
     Node defaultValue = node.arguments.head;
     if (!defaultValuesAllowed) {
-      compiler.reportErrorMessage(defaultValue, defaultValuesError);
+      reporter.reportErrorMessage(defaultValue, defaultValuesError);
     }
     return element;
   }
@@ -259,12 +260,12 @@
     // This is a function typed parameter.
     Modifiers modifiers = currentDefinitions.modifiers;
     if (modifiers.isFinal) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           modifiers,
           MessageKind.FINAL_FUNCTION_TYPE_PARAMETER);
     }
     if (modifiers.isVar) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           modifiers, MessageKind.VAR_FUNCTION_TYPE_PARAMETER);
     }
 
@@ -281,7 +282,7 @@
         // If parameter is null, the current node should be the last,
         // and a list of optional named parameters.
         if (!link.tail.isEmpty || (link.head is !NodeList)) {
-          compiler.internalError(link.head, "expected optional parameters");
+          reporter.internalError(link.head, "expected optional parameters");
         }
       }
     }
@@ -305,6 +306,7 @@
       {MessageKind defaultValuesError,
        bool createRealParameters: false,
        bool isFunctionExpression: false}) {
+    DiagnosticReporter reporter = compiler.reporter;
 
     SignatureResolver visitor = new SignatureResolver(compiler, element,
         registry, defaultValuesError: defaultValuesError,
@@ -320,7 +322,7 @@
           // parse. So we suppress the message about missing formals.
           assert(invariant(element, compiler.compilationFailed));
         } else {
-          compiler.reportErrorMessage(element, MessageKind.MISSING_FORMALS);
+          reporter.reportErrorMessage(element, MessageKind.MISSING_FORMALS);
         }
       }
     } else {
@@ -328,7 +330,7 @@
         if (!identical(formalParameters.endToken.next.stringValue,
                        // TODO(ahe): Remove the check for native keyword.
                        'native')) {
-          compiler.reportErrorMessage(
+          reporter.reportErrorMessage(
               formalParameters,
               MessageKind.EXTRA_FORMALS);
         }
@@ -374,7 +376,7 @@
                                visitor.optionalParameterCount != 0)) {
       // If there are no formal parameters, we already reported an error above.
       if (formalParameters != null) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             formalParameters,
             MessageKind.ILLEGAL_SETTER_FORMALS);
       }
@@ -433,7 +435,7 @@
   DartType resolveTypeAnnotation(TypeAnnotation annotation) {
     DartType type = resolveReturnType(annotation);
     if (type.isVoid) {
-      compiler.reportErrorMessage(annotation, MessageKind.VOID_NOT_ALLOWED);
+      reporter.reportErrorMessage(annotation, MessageKind.VOID_NOT_ALLOWED);
     }
     return type;
   }
diff --git a/pkg/compiler/lib/src/resolution/tree_elements.dart b/pkg/compiler/lib/src/resolution/tree_elements.dart
index 1204017..ca76d2b 100644
--- a/pkg/compiler/lib/src/resolution/tree_elements.dart
+++ b/pkg/compiler/lib/src/resolution/tree_elements.dart
@@ -44,6 +44,7 @@
   Iterable<Element> get otherDependencies;
 
   Element operator[](Node node);
+  Map<Node, DartType> get typesCache;
 
   SendStructure getSendStructure(Send send);
 
@@ -132,6 +133,7 @@
   Map<Spannable, Selector> _selectors;
   Map<Spannable, TypeMask> _typeMasks;
   Map<Node, DartType> _types;
+  Map<Node, DartType> typesCache = <Node, DartType>{};
   Setlet<Node> _superUses;
   Setlet<Element> _otherDependencies;
   Map<Node, ConstantExpression> _constants;
diff --git a/pkg/compiler/lib/src/resolution/type_resolver.dart b/pkg/compiler/lib/src/resolution/type_resolver.dart
index a4335c8..0101625 100644
--- a/pkg/compiler/lib/src/resolution/type_resolver.dart
+++ b/pkg/compiler/lib/src/resolution/type_resolver.dart
@@ -3,13 +3,16 @@
 // BSD-style license that can be found in the LICENSE file.
 
 library dart2js.resolution.types;
+
+import '../common/resolution.dart' show
+    Resolution;
 import '../compiler.dart' show
     Compiler;
 import '../dart_backend/dart_backend.dart' show
     DartBackend;
 import '../dart_types.dart';
 import '../diagnostics/diagnostic_listener.dart' show
-    DiagnosticListener,
+    DiagnosticReporter,
     DiagnosticMessage;
 import '../diagnostics/messages.dart' show
     MessageKind;
@@ -42,7 +45,9 @@
 
   TypeResolver(this.compiler);
 
-  DiagnosticListener get listener => compiler;
+  DiagnosticReporter get reporter => compiler.reporter;
+
+  Resolution get resolution => compiler.resolution;
 
   /// Tries to resolve the type name as an element.
   Element resolveTypeName(Identifier prefixName,
@@ -52,7 +57,7 @@
     Element element;
     if (prefixName != null) {
       Element prefixElement =
-          lookupInScope(compiler, prefixName, scope, prefixName.source);
+          lookupInScope(reporter, prefixName, scope, prefixName.source);
       if (prefixElement != null && prefixElement.isPrefix) {
         // The receiver is a prefix. Lookup in the imported members.
         PrefixElement prefix = prefixElement;
@@ -74,7 +79,7 @@
         element = null;
       }
     } else {
-      element = lookupInScope(compiler, typeName, scope, typeName.source);
+      element = lookupInScope(reporter, typeName, scope, typeName.source);
     }
     return element;
   }
@@ -131,13 +136,13 @@
          Element erroneousElement,
          List<DiagnosticMessage> infos: const <DiagnosticMessage>[]}) {
       if (malformedIsError) {
-        listener.reportError(
-            listener.createMessage(node, messageKind, messageArguments),
+        reporter.reportError(
+            reporter.createMessage(node, messageKind, messageArguments),
             infos);
       } else {
         registry.registerThrowRuntimeError();
-        listener.reportWarning(
-            listener.createMessage(node, messageKind, messageArguments),
+        reporter.reportWarning(
+            reporter.createMessage(node, messageKind, messageArguments),
             infos);
       }
       if (erroneousElement == null) {
@@ -162,7 +167,7 @@
           ambiguous.messageKind,
           ambiguous.messageArguments,
           infos: ambiguous.computeInfos(
-              registry.mapping.analyzedElement, compiler));
+              registry.mapping.analyzedElement, reporter));
       ;
     } else if (element.isErroneous) {
       if (element is ErroneousElement) {
@@ -182,7 +187,7 @@
         // TODO(johnniwinther): [ensureClassWillBeResolvedInternal] should imply
         // [computeType].
         compiler.resolver.ensureClassWillBeResolvedInternal(cls);
-        cls.computeType(compiler);
+        cls.computeType(resolution);
         List<DartType> arguments = <DartType>[];
         bool hasTypeArgumentMismatch = resolveTypeArguments(
             visitor, node, cls.typeVariables, arguments);
@@ -202,8 +207,8 @@
       } else if (element.isTypedef) {
         TypedefElement typdef = element;
         // TODO(johnniwinther): [ensureResolved] should imply [computeType].
-        typdef.ensureResolved(compiler);
-        typdef.computeType(compiler);
+        typdef.ensureResolved(resolution);
+        typdef.computeType(resolution);
         List<DartType> arguments = <DartType>[];
         bool hasTypeArgumentMismatch = resolveTypeArguments(
             visitor, node, typdef.typeVariables, arguments);
@@ -235,7 +240,7 @@
         }
         type = checkNoTypeArguments(type);
       } else {
-        compiler.internalError(node,
+        reporter.internalError(node,
             "Unexpected element kind ${element.kind}.");
       }
       if (addTypeVariableBoundsCheck) {
@@ -255,7 +260,7 @@
                                    TypeVariableType typeVariable,
                                    DartType bound) {
       if (!compiler.types.isSubtype(typeArgument, bound)) {
-        compiler.reportWarningMessage(
+        reporter.reportWarningMessage(
             node,
             MessageKind.INVALID_TYPE_VARIABLE_BOUND,
             {'typeVariable': typeVariable,
@@ -288,7 +293,7 @@
          !typeArguments.isEmpty;
          typeArguments = typeArguments.tail, index++) {
       if (index > expectedVariables - 1) {
-        compiler.reportWarningMessage(
+        reporter.reportWarningMessage(
             typeArguments.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT);
         typeArgumentCountMismatch = true;
       }
@@ -297,7 +302,7 @@
       arguments.add(argType);
     }
     if (index < expectedVariables) {
-      compiler.reportWarningMessage(
+      reporter.reportWarningMessage(
           node.typeArguments, MessageKind.MISSING_TYPE_ARGUMENT);
       typeArgumentCountMismatch = true;
     }
diff --git a/pkg/compiler/lib/src/resolution/typedefs.dart b/pkg/compiler/lib/src/resolution/typedefs.dart
index b86593c..11f57c7 100644
--- a/pkg/compiler/lib/src/resolution/typedefs.dart
+++ b/pkg/compiler/lib/src/resolution/typedefs.dart
@@ -7,6 +7,8 @@
 import '../compiler.dart' show
     Compiler;
 import '../dart_types.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import '../diagnostics/messages.dart' show
     MessageKind;
 import '../elements/elements.dart' show
@@ -39,7 +41,7 @@
       : super(compiler, typedefElement, registry);
 
   visitTypedef(Typedef node) {
-    element.computeType(compiler);
+    element.computeType(resolution);
     scope = new TypeDeclarationScope(scope, element);
     resolveTypeVariableBounds(node.typeParameters);
 
@@ -54,7 +56,7 @@
     element.alias = signature.type;
 
     void checkCyclicReference() {
-      element.checkCyclicReference(compiler);
+      element.checkCyclicReference(resolution);
     }
     addDeferredAction(element, checkCyclicReference);
   }
@@ -63,7 +65,7 @@
 // TODO(johnniwinther): Replace with a traversal on the AST when the type
 // annotations in typedef alias are stored in a [TreeElements] mapping.
 class TypedefCyclicVisitor extends BaseDartTypeVisitor {
-  final Compiler compiler;
+  final DiagnosticReporter reporter;
   final TypedefElementX element;
   bool hasCyclicReference = false;
 
@@ -74,7 +76,7 @@
   Link<TypeVariableElement> seenTypeVariables =
       const Link<TypeVariableElement>();
 
-  TypedefCyclicVisitor(Compiler this.compiler, TypedefElement this.element);
+  TypedefCyclicVisitor(this.reporter, TypedefElement this.element);
 
   visitType(DartType type, _) {
     // Do nothing.
@@ -89,13 +91,13 @@
         hasCyclicReference = true;
         if (seenTypedefsCount == 1) {
           // Direct cyclicity.
-          compiler.reportErrorMessage(
+          reporter.reportErrorMessage(
               element,
               MessageKind.CYCLIC_TYPEDEF,
               {'typedefName': element.name});
         } else if (seenTypedefsCount == 2) {
           // Cyclicity through one other typedef.
-          compiler.reportErrorMessage(
+          reporter.reportErrorMessage(
               element,
               MessageKind.CYCLIC_TYPEDEF_ONE,
               {'typedefName': element.name,
@@ -104,7 +106,7 @@
           // Cyclicity through more than one other typedef.
           for (TypedefElement cycle in seenTypedefs) {
             if (!identical(typedefElement, cycle)) {
-              compiler.reportErrorMessage(
+              reporter.reportErrorMessage(
                   element,
                   MessageKind.CYCLIC_TYPEDEF_ONE,
                   {'typedefName': element.name,
diff --git a/pkg/compiler/lib/src/resolution/variables.dart b/pkg/compiler/lib/src/resolution/variables.dart
index 5fe7193..03d0fb8 100644
--- a/pkg/compiler/lib/src/resolution/variables.dart
+++ b/pkg/compiler/lib/src/resolution/variables.dart
@@ -46,7 +46,7 @@
         new VariableDefinitionScope(resolver.scope, name);
     resolver.visitIn(node.arguments.head, scope);
     if (scope.variableReferencedInInitializer) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           identifier, MessageKind.REFERENCE_IN_INITIALIZATION,
           {'variableName': name});
     }
@@ -57,12 +57,12 @@
     // The variable is initialized to null.
     registry.registerInstantiatedClass(compiler.nullClass);
     if (definitions.modifiers.isConst) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node, MessageKind.CONST_WITHOUT_INITIALIZER);
     }
     if (definitions.modifiers.isFinal &&
         !resolver.allowFinalWithoutInitializer) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node, MessageKind.FINAL_WITHOUT_INITIALIZER);
     }
     return node;
diff --git a/pkg/compiler/lib/src/scanner/scanner_task.dart b/pkg/compiler/lib/src/scanner/scanner_task.dart
index cc13bb5..17b3dbc 100644
--- a/pkg/compiler/lib/src/scanner/scanner_task.dart
+++ b/pkg/compiler/lib/src/scanner/scanner_task.dart
@@ -30,9 +30,9 @@
     String canonicalUri = library.canonicalUri.toString();
     String resolvedUri = compilationUnit.script.resourceUri.toString();
     if (canonicalUri == resolvedUri) {
-      compiler.log("Scanning library $canonicalUri");
+      reporter.log("Scanning library $canonicalUri");
     } else {
-      compiler.log("Scanning library $canonicalUri ($resolvedUri)");
+      reporter.log("Scanning library $canonicalUri ($resolvedUri)");
     }
     scan(compilationUnit);
   }
diff --git a/pkg/compiler/lib/src/serialization/modelz.dart b/pkg/compiler/lib/src/serialization/modelz.dart
index 83b8f5b..a4719ed 100644
--- a/pkg/compiler/lib/src/serialization/modelz.dart
+++ b/pkg/compiler/lib/src/serialization/modelz.dart
@@ -11,6 +11,8 @@
 
 import 'serialization.dart';
 import 'keys.dart';
+import '../common/resolution.dart' show
+    Resolution;
 import '../compiler.dart'
     show Compiler;
 import '../constants/constructors.dart';
@@ -18,7 +20,6 @@
 import '../diagnostics/source_span.dart'
     show SourceSpan;
 import '../dart_types.dart';
-import '../diagnostics/diagnostic_listener.dart';
 import '../elements/elements.dart';
 import '../elements/modelx.dart' show
     FunctionSignatureX;
@@ -662,7 +663,7 @@
   }
 
   @override
-  DartType computeType(Compiler compiler) => type;
+  DartType computeType(Resolution resolution) => type;
 }
 
 abstract class ParametersMixin
@@ -897,8 +898,8 @@
   ClassElement get superclass => supertype != null ? supertype.element : null;
 
   @override
-  void ensureResolved(Compiler compiler) {
-    compiler.world.registerClass(this);
+  void ensureResolved(Resolution resolution) {
+    resolution.registerClass(this);
   }
 }
 
@@ -1236,7 +1237,7 @@
   }
 
   @override
-  T computeType(Compiler compiler) => thisType;
+  T computeType(Resolution resolution) => thisType;
 
   @override
   bool get isResolved => true;
@@ -1275,10 +1276,10 @@
   }
 
   @override
-  void ensureResolved(Compiler compiler) {}
+  void ensureResolved(Resolution resolution) {}
 
   @override
-  void checkCyclicReference(Compiler compiler) {}
+  void checkCyclicReference(Resolution resolution) {}
 }
 
 class TypeVariableElementZ extends DeserializedElementZ
diff --git a/pkg/compiler/lib/src/serialization/task.dart b/pkg/compiler/lib/src/serialization/task.dart
index 3573b35..2b86c5e 100644
--- a/pkg/compiler/lib/src/serialization/task.dart
+++ b/pkg/compiler/lib/src/serialization/task.dart
@@ -65,7 +65,7 @@
   @override
   WorldImpact run(Compiler compiler, ResolutionEnqueuer world) {
     _isAnalyzed = true;
-    world.registerResolvedElement(element);
+    world.registerProcessedElement(element);
     return worldImpact;
   }
 }
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 0273c96..bcf70e2 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -60,10 +60,12 @@
       backend = backend,
       super(backend.compiler);
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   HGraph build(CodegenWorkItem work) {
     return measure(() {
       Element element = work.element.implementation;
-      return compiler.withCurrentElement(element, () {
+      return reporter.withCurrentElement(element, () {
         HInstruction.idCounter = 0;
         SsaBuilder builder =
             new SsaBuilder(
@@ -86,7 +88,7 @@
             graph = builder.buildLazyInitializer(element);
           }
         } else {
-          compiler.internalError(element, 'Unexpected element kind $kind.');
+          reporter.internalError(element, 'Unexpected element kind $kind.');
         }
         assert(graph.isValid());
         if (!identical(kind, ElementKind.FIELD)) {
@@ -439,10 +441,10 @@
     if (isAccessedDirectly(local)) {
       if (directLocals[local] == null) {
         if (local is TypeVariableElement) {
-          builder.compiler.internalError(builder.compiler.currentElement,
+          builder.reporter.internalError(builder.compiler.currentElement,
               "Runtime type information not available for $local.");
         } else {
-          builder.compiler.internalError(local,
+          builder.reporter.internalError(local,
               "Cannot find value $local.");
         }
       }
@@ -792,17 +794,17 @@
 // used as the target of a break, and therefore doesn't need a break
 // handler associated with it.
 class NullJumpHandler implements JumpHandler {
-  final Compiler compiler;
+  final DiagnosticReporter reporter;
 
-  NullJumpHandler(this.compiler);
+  NullJumpHandler(this.reporter);
 
   void generateBreak([LabelDefinition label]) {
-    compiler.internalError(CURRENT_ELEMENT_SPANNABLE,
+    reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
         'NullJumpHandler.generateBreak should not be called.');
   }
 
   void generateContinue([LabelDefinition label]) {
-    compiler.internalError(CURRENT_ELEMENT_SPANNABLE,
+    reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
         'NullJumpHandler.generateContinue should not be called.');
   }
 
@@ -1105,6 +1107,12 @@
             work.element.implementation);
   }
 
+
+  DiagnosticReporter get reporter => compiler.reporter;
+
+  // TODO(johnniwinther): Avoid the need for this.
+  Resolution get resolution => compiler.resolution;
+
   @override
   SemanticSendVisitor get sendVisitor => this;
 
@@ -1493,7 +1501,7 @@
 
   inlinedFrom(Element element, f()) {
     assert(element is FunctionElement || element is VariableElement);
-    return compiler.withCurrentElement(element, () {
+    return reporter.withCurrentElement(element, () {
       // The [sourceElementStack] contains declaration elements.
       SourceInformationBuilder oldSourceInformationBuilder =
           sourceInformationBuilder;
@@ -1865,7 +1873,7 @@
                              Map<Element, HInstruction> fieldValues,
                              FunctionElement caller) {
     callee = callee.implementation;
-    compiler.withCurrentElement(callee, () {
+    reporter.withCurrentElement(callee, () {
       constructors.add(callee);
       ClassElement enclosingClass = callee.enclosingClass;
       if (backend.classNeedsRti(enclosingClass)) {
@@ -1980,7 +1988,7 @@
         // forwarding constructor in a mixin application did not match the
         // constructor (which, for example, may happen when the libraries are
         // not compatible for private names, see issue 20394).
-        compiler.internalError(constructor,
+        reporter.internalError(constructor,
                                'forwarding constructor call does not match');
       }
       inlineSuperOrRedirect(
@@ -2042,7 +2050,7 @@
         // TODO(johnniwinther): Should we find injected constructors as well?
         FunctionElement target = superClass.lookupDefaultConstructor();
         if (target == null) {
-          compiler.internalError(superClass,
+          reporter.internalError(superClass,
               "No default constructor available.");
         }
         List<HInstruction> arguments =
@@ -2072,7 +2080,7 @@
     classElement.forEachInstanceField(
         (ClassElement enclosingClass, VariableElement member) {
           if (compiler.elementHasCompileTimeError(member)) return;
-          compiler.withCurrentElement(member, () {
+          reporter.withCurrentElement(member, () {
             TreeElements definitions = member.treeElements;
             ast.Node node = member.node;
             ast.Expression initializer = member.initializer;
@@ -2479,7 +2487,7 @@
                                    DartType type,
                                    int kind) {
     if (type == null) return original;
-    type = type.unalias(compiler);
+    type = type.unalias(resolution);
     assert(assertTypeInContext(type, original));
     if (type.isInterfaceType && !type.treatAsRaw) {
       TypeMask subtype = new TypeMask.subtype(type.element, compiler.world);
@@ -2515,7 +2523,7 @@
     assert(compiler.trustTypeAnnotations);
     assert(type != null);
     type = localsHandler.substInContext(type);
-    type = type.unalias(compiler);
+    type = type.unalias(resolution);
     if (type.isDynamic) return original;
     if (!type.isInterfaceType) return original;
     // The type element is either a class or the void element.
@@ -2660,19 +2668,19 @@
       if (!isReachable) {
         // The block has been aborted by a return or a throw.
         if (!stack.isEmpty) {
-          compiler.internalError(node, 'Non-empty instruction stack.');
+          reporter.internalError(node, 'Non-empty instruction stack.');
         }
         return;
       }
     }
     assert(!current.isClosed());
     if (!stack.isEmpty) {
-      compiler.internalError(node, 'Non-empty instruction stack.');
+      reporter.internalError(node, 'Non-empty instruction stack.');
     }
   }
 
   visitClassNode(ast.ClassNode node) {
-    compiler.internalError(node,
+    reporter.internalError(node,
         'SsaBuilder.visitClassNode should not be called.');
   }
 
@@ -3212,7 +3220,7 @@
     if (node.isThis()) {
       visitThisGet(node);
     } else {
-      compiler.internalError(node,
+      reporter.internalError(node,
           "SsaFromAstMixin.visitIdentifier on non-this.");
     }
   }
@@ -3810,7 +3818,7 @@
   HInstruction buildIsNode(ast.Node node,
                            DartType type,
                            HInstruction expression) {
-    type = localsHandler.substInContext(type).unalias(compiler);
+    type = localsHandler.substInContext(type).unalias(resolution);
     if (type.isFunctionType) {
       List arguments = [buildFunctionType(type), expression];
       pushInvokeDynamic(
@@ -4075,7 +4083,7 @@
     // argument, which is the foreign code.
     if (link.isEmpty || link.tail.isEmpty) {
       // We should not get here because the call should be compiled to NSM.
-      compiler.internalError(node.argumentsNode,
+      reporter.internalError(node.argumentsNode,
           'At least two arguments expected.');
     }
     native.NativeBehavior nativeBehavior =
@@ -4085,7 +4093,7 @@
     addGenericSendArgumentsToList(link.tail.tail, inputs);
 
     if (nativeBehavior.codeTemplate.positionalArgumentCount != inputs.length) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node, MessageKind.GENERIC,
           {'text':
             'Mismatch between number of placeholders'
@@ -4119,14 +4127,14 @@
     List<HInstruction> inputs = <HInstruction>[];
     addGenericSendArgumentsToList(node.arguments, inputs);
     if (inputs.length != 2) {
-      compiler.internalError(node.argumentsNode, 'Two arguments expected.');
+      reporter.internalError(node.argumentsNode, 'Two arguments expected.');
     }
     push(new HStringConcat(inputs[0], inputs[1], node, backend.stringType));
   }
 
   void handleForeignJsCurrentIsolateContext(ast.Send node) {
     if (!node.arguments.isEmpty) {
-      compiler.internalError(node,
+      reporter.internalError(node,
           'Too many arguments to JS_CURRENT_ISOLATE_CONTEXT.');
     }
 
@@ -4143,7 +4151,7 @@
       // Leg's isolate.
       Element element = backend.isolateHelperLibrary.find('_currentIsolate');
       if (element == null) {
-        compiler.internalError(node,
+        reporter.internalError(node,
             'Isolate library and compiler mismatch.');
       }
       pushInvokeStatic(null, element, [], typeMask: backend.dynamicType);
@@ -4155,7 +4163,7 @@
      ast.Node argument;
      switch (arguments.length) {
      case 0:
-       compiler.reportErrorMessage(
+       reporter.reportErrorMessage(
            node, MessageKind.GENERIC,
            {'text': 'Error: Expected one argument to JS_GET_FLAG.'});
        return;
@@ -4164,7 +4172,7 @@
        break;
      default:
        for (int i = 1; i < arguments.length; i++) {
-         compiler.reportErrorMessage(
+         reporter.reportErrorMessage(
              arguments[i], MessageKind.GENERIC,
              {'text': 'Error: Extra argument to JS_GET_FLAG.'});
        }
@@ -4172,7 +4180,7 @@
      }
      ast.LiteralString string = argument.asLiteralString();
      if (string == null) {
-       compiler.reportErrorMessage(
+       reporter.reportErrorMessage(
            argument, MessageKind.GENERIC,
            {'text': 'Error: Expected a literal string.'});
      }
@@ -4186,7 +4194,7 @@
          value = compiler.useContentSecurityPolicy;
          break;
        default:
-         compiler.reportErrorMessage(
+         reporter.reportErrorMessage(
              node, MessageKind.GENERIC,
              {'text': 'Error: Unknown internal flag "$name".'});
      }
@@ -4198,7 +4206,7 @@
     ast.Node argument;
     switch (arguments.length) {
     case 0:
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node, MessageKind.GENERIC,
           {'text': 'Error: Expected one argument to JS_GET_NAME.'});
       return;
@@ -4207,7 +4215,7 @@
       break;
     default:
       for (int i = 1; i < arguments.length; i++) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             arguments[i], MessageKind.GENERIC,
             {'text': 'Error: Extra argument to JS_GET_NAME.'});
       }
@@ -4217,7 +4225,7 @@
     if (element == null ||
         element is! FieldElement ||
         element.enclosingClass != backend.jsGetNameEnum) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           argument, MessageKind.GENERIC,
           {'text': 'Error: Expected a JsGetName enum value.'});
     }
@@ -4233,7 +4241,7 @@
     List<ast.Node> arguments = node.arguments.toList();
     ast.Node argument;
     if (arguments.length < 2) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node, MessageKind.GENERIC,
           {'text': 'Error: Expected at least two arguments to JS_BUILTIN.'});
     }
@@ -4242,7 +4250,7 @@
     if (builtinElement == null ||
         (builtinElement is! FieldElement) ||
         builtinElement.enclosingClass != backend.jsBuiltinEnum) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           argument, MessageKind.GENERIC,
           {'text': 'Error: Expected a JsBuiltin enum value.'});
     }
@@ -4276,7 +4284,7 @@
     switch (arguments.length) {
     case 0:
     case 1:
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node, MessageKind.GENERIC,
           {'text': 'Error: Expected two arguments to JS_EMBEDDED_GLOBAL.'});
       return;
@@ -4287,7 +4295,7 @@
       break;
     default:
       for (int i = 2; i < arguments.length; i++) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             arguments[i], MessageKind.GENERIC,
             {'text': 'Error: Extra argument to JS_EMBEDDED_GLOBAL.'});
       }
@@ -4296,7 +4304,7 @@
     visit(globalNameNode);
     HInstruction globalNameHNode = pop();
     if (!globalNameHNode.isConstantString()) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           arguments[1], MessageKind.GENERIC,
           {'text': 'Error: Expected String as second argument '
                    'to JS_EMBEDDED_GLOBAL.'});
@@ -4333,7 +4341,7 @@
         }
       }
     }
-    compiler.reportErrorMessage(
+    reporter.reportErrorMessage(
         node,
         MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
     stack.add(graph.addConstantNull(compiler));
@@ -4352,7 +4360,7 @@
       // Call a helper method from the isolate library.
       Element element = backend.isolateHelperLibrary.find('_callInIsolate');
       if (element == null) {
-        compiler.internalError(node,
+        reporter.internalError(node,
             'Isolate library and compiler mismatch.');
       }
       List<HInstruction> inputs = <HInstruction>[];
@@ -4363,13 +4371,13 @@
 
   FunctionSignature handleForeignRawFunctionRef(ast.Send node, String name) {
     if (node.arguments.isEmpty || !node.arguments.tail.isEmpty) {
-      compiler.internalError(node.argumentsNode,
+      reporter.internalError(node.argumentsNode,
           '"$name" requires exactly one argument.');
     }
     ast.Node closure = node.arguments.head;
     Element element = elements[closure];
     if (!Elements.isStaticOrTopLevelFunction(element)) {
-      compiler.internalError(closure,
+      reporter.internalError(closure,
           '"$name" requires a static or top-level method.');
     }
     FunctionElement function = element;
@@ -4379,7 +4387,7 @@
     FunctionElement implementation = function.implementation;
     FunctionSignature params = implementation.functionSignature;
     if (params.optionalParameterCount != 0) {
-      compiler.internalError(closure,
+      reporter.internalError(closure,
           '"$name" does not handle closure with optional parameters.');
     }
 
@@ -4402,7 +4410,7 @@
 
   void handleForeignJsSetStaticState(ast.Send node) {
     if (node.arguments.isEmpty || !node.arguments.tail.isEmpty) {
-      compiler.internalError(node.argumentsNode,
+      reporter.internalError(node.argumentsNode,
           'Exactly one argument required.');
     }
     visit(node.arguments.head);
@@ -4419,7 +4427,7 @@
 
   void handleForeignJsGetStaticState(ast.Send node) {
     if (!node.arguments.isEmpty) {
-      compiler.internalError(node.argumentsNode, 'Too many arguments.');
+      reporter.internalError(node.argumentsNode, 'Too many arguments.');
     }
     push(new HForeignCode(js.js.parseForeignJS(backend.namer.staticStateHolder),
                           backend.dynamicType,
@@ -4457,7 +4465,7 @@
     } else if (name == 'JS_STRING_CONCAT') {
       handleJsStringConcat(node);
     } else {
-      compiler.internalError(node, "Unknown foreign: ${element}");
+      reporter.internalError(node, "Unknown foreign: ${element}");
     }
   }
 
@@ -4884,7 +4892,7 @@
           type.element,
           sourceInformation: sourceInformation);
     } else {
-      compiler.internalError(type.element,
+      reporter.internalError(type.element,
           'Unexpected type variable in static context.');
       return null;
     }
@@ -5571,7 +5579,7 @@
 
   // TODO(antonm): migrate rest of SsaFromAstMixin to internalError.
   internalError(Spannable node, String reason) {
-    compiler.internalError(node, reason);
+    reporter.internalError(node, reason);
   }
 
   void generateError(ast.Node node, String message, Element helper) {
@@ -6891,7 +6899,7 @@
   visitNodeList(ast.NodeList node) {
     for (Link<ast.Node> link = node.nodes; !link.isEmpty; link = link.tail) {
       if (isAborted()) {
-        compiler.reportHintMessage(
+        reporter.reportHintMessage(
             link.head,
             MessageKind.GENERIC,
             {'text': 'dead code'});
@@ -6907,7 +6915,7 @@
 
   visitOperator(ast.Operator node) {
     // Operators are intercepted in their surrounding Send nodes.
-    compiler.internalError(node,
+    reporter.internalError(node,
         'SsaBuilder.visitOperator should not be called.');
   }
 
@@ -6934,7 +6942,7 @@
     HInstruction exception = rethrowableException;
     if (exception == null) {
       exception = graph.addConstantNull(compiler);
-      compiler.internalError(node,
+      reporter.internalError(node,
           'rethrowableException should not be null.');
     }
     handleInTryStatement();
@@ -7059,7 +7067,7 @@
   }
 
   visitTypeAnnotation(ast.TypeAnnotation node) {
-    compiler.internalError(node,
+    reporter.internalError(node,
         'Visiting type annotation in SSA builder.');
   }
 
@@ -7135,7 +7143,7 @@
 
   visitStringInterpolationPart(ast.StringInterpolationPart node) {
     // The parts are iterated in visitStringInterpolation.
-    compiler.internalError(node,
+    reporter.internalError(node,
       'SsaBuilder.visitStringInterpolation should not be called.');
   }
 
@@ -7190,7 +7198,7 @@
     JumpTarget element = elements.getTargetDefinition(node);
     if (element == null || !identical(element.statement, node)) {
       // No breaks or continues to this node.
-      return new NullJumpHandler(compiler);
+      return new NullJumpHandler(reporter);
     }
     if (isLoopJump && node is ast.SwitchStatement) {
       // Create a special jump handler for loops created for switch statements
@@ -7457,7 +7465,7 @@
   }
 
   visitLabel(ast.Label node) {
-    compiler.internalError(node, 'SsaFromAstMixin.visitLabel.');
+    reporter.internalError(node, 'SsaFromAstMixin.visitLabel.');
   }
 
   visitLabeledStatement(ast.LabeledStatement node) {
@@ -7787,7 +7795,7 @@
       // is not the generated switch statement but instead the loop generated
       // in the call to [handleLoop] below.
       handleSwitch(node,
-                   new NullJumpHandler(compiler),
+                   new NullJumpHandler(reporter),
                    buildExpression, node.cases, getConstants,
                    (_) => false, // No case is default.
                    buildSwitchCase);
@@ -7954,11 +7962,11 @@
   }
 
   visitSwitchCase(ast.SwitchCase node) {
-    compiler.internalError(node, 'SsaFromAstMixin.visitSwitchCase.');
+    reporter.internalError(node, 'SsaFromAstMixin.visitSwitchCase.');
   }
 
   visitCaseMatch(ast.CaseMatch node) {
-    compiler.internalError(node, 'SsaFromAstMixin.visitCaseMatch.');
+    reporter.internalError(node, 'SsaFromAstMixin.visitCaseMatch.');
   }
 
   /// Calls [buildTry] inside a synthetic try block with [buildFinally] in the
@@ -8109,7 +8117,7 @@
         if (catchBlock.onKeyword != null) {
           DartType type = elements.getType(catchBlock.type);
           if (type == null) {
-            compiler.internalError(catchBlock.type, 'On with no type.');
+            reporter.internalError(catchBlock.type, 'On with no type.');
           }
           HInstruction condition =
               buildIsNode(catchBlock.type, type, unwrappedException);
@@ -8127,7 +8135,7 @@
             // condition.
             DartType type = elements.getType(declaration.type);
             if (type == null) {
-              compiler.internalError(catchBlock, 'Catch with unresolved type.');
+              reporter.internalError(catchBlock, 'Catch with unresolved type.');
             }
             condition = buildIsNode(declaration.type, type, unwrappedException);
             push(condition);
@@ -8266,7 +8274,7 @@
   }
 
   visitTypeVariable(ast.TypeVariable node) {
-    compiler.internalError(node, 'SsaFromAstMixin.visitTypeVariable.');
+    reporter.internalError(node, 'SsaFromAstMixin.visitTypeVariable.');
   }
 
   /**
@@ -8403,7 +8411,7 @@
   }
 
   visitNode(ast.Node node) {
-    builder.compiler.internalError(node, 'Unexpected node.');
+    builder.reporter.internalError(node, 'Unexpected node.');
   }
 
   void visitExpression(ast.Node node) {
@@ -8984,7 +8992,7 @@
   }
 
   void visitTypedefType(TypedefType type, SsaBuilder builder) {
-    DartType unaliased = type.unalias(builder.compiler);
+    DartType unaliased = type.unalias(builder.compiler.resolution);
     if (unaliased is TypedefType) throw 'unable to unalias $type';
     unaliased.accept(this, builder);
   }
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 4ac5881..7b7596e 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -152,12 +152,17 @@
       continueAction = new Map<Entity, EntityAction>();
 
   Compiler get compiler => backend.compiler;
+
   NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter;
+
   CodegenRegistry get registry => work.registry;
+
   native.NativeEnqueuer get nativeEnqueuer {
     return compiler.enqueuer.codegen.nativeEnqueuer;
   }
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   bool isGenerateAtUseSite(HInstruction instruction) {
     return generateAtUseSite.contains(instruction);
   }
@@ -935,7 +940,7 @@
         currentContainer = oldContainer;
         break;
       default:
-        compiler.internalError(condition.conditionExpression,
+        reporter.internalError(condition.conditionExpression,
             'Unexpected loop kind: ${info.kind}.');
     }
     js.Statement result = loop;
@@ -1336,10 +1341,10 @@
     // is responsible for visiting the successor.
     if (dominated.isEmpty) return;
     if (dominated.length > 2) {
-      compiler.internalError(node, 'dominated.length = ${dominated.length}');
+      reporter.internalError(node, 'dominated.length = ${dominated.length}');
     }
     if (dominated.length == 2 && block != currentGraph.entry) {
-      compiler.internalError(node, 'node.block != currentGraph.entry');
+      reporter.internalError(node, 'node.block != currentGraph.entry');
     }
     assert(dominated[0] == block.successors[0]);
     visitBasicBlock(dominated[0]);
@@ -1430,7 +1435,7 @@
   visitTry(HTry node) {
     // We should never get here. Try/catch/finally is always handled using block
     // information in [visitTryInfo].
-    compiler.internalError(node, 'visitTry should not be called.');
+    reporter.internalError(node, 'visitTry should not be called.');
   }
 
   bool tryControlFlowOperation(HIf node) {
@@ -2703,7 +2708,7 @@
       checkString(input, '!==', input.sourceInformation);
       return pop();
     }
-    compiler.internalError(input, 'Unexpected check: $checkedType.');
+    reporter.internalError(input, 'Unexpected check: $checkedType.');
     return null;
   }
 
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 4fa2735..ed3f955 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -1312,7 +1312,7 @@
 
   HInstruction convertType(Compiler compiler, DartType type, int kind) {
     if (type == null) return this;
-    type = type.unalias(compiler);
+    type = type.unalias(compiler.resolution);
     // Only the builder knows how to create [HTypeConversion]
     // instructions with generics. It has the generic type context
     // available.
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 07611f6..741dd32 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -200,6 +200,41 @@
     return node;
   }
 
+  ConstantValue getConstantFromType(HInstruction node) {
+    if (node.isValue() && !node.canBeNull()) {
+      ValueTypeMask valueMask = node.instructionType;
+      if (valueMask.value.isBool) {
+        return valueMask.value;
+      }
+      // TODO(het): consider supporting other values (short strings?)
+    }
+    return null;
+  }
+
+  void propagateConstantValueToUses(HInstruction node) {
+    if (node.usedBy.isEmpty) return;
+    ConstantValue value = getConstantFromType(node);
+    if (value != null) {
+      HConstant constant = graph.addConstant(value, compiler);
+      for (HInstruction user in node.usedBy.toList()) {
+        user.changeUse(node, constant);
+      }
+    }
+  }
+
+  HInstruction visitParameterValue(HParameterValue node) {
+    // It is possible for the parameter value to be assigned to in the function
+    // body. If that happens then we should not forward the constant value to
+    // its uses since since the uses reachable from the assignment may have
+    // values in addition to the constant passed to the function.
+    if (node.usedBy.any((user) =>
+            user is HLocalSet && identical(user.local, node))) {
+      return node;
+    }
+    propagateConstantValueToUses(node);
+    return node;
+  }
+
   HInstruction visitBoolify(HBoolify node) {
     List<HInstruction> inputs = node.inputs;
     assert(inputs.length == 1);
@@ -372,6 +407,7 @@
   }
 
   HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
+    propagateConstantValueToUses(node);
     if (node.isInterceptedCall) {
       HInstruction folded = handleInterceptedCall(node);
       if (folded != node) return folded;
@@ -437,7 +473,7 @@
     bool canInline = true;
     signature.forEachParameter((ParameterElement element) {
       if (inputPosition++ < inputs.length && canInline) {
-        DartType type = element.type.unalias(compiler);
+        DartType type = element.type.unalias(compiler.resolution);
         if (type is FunctionType) {
           canInline = false;
         }
@@ -806,6 +842,7 @@
   }
 
   HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) {
+    propagateConstantValueToUses(node);
     if (node.isInterceptedCall) {
       HInstruction folded = handleInterceptedCall(node);
       if (folded != node) return folded;
@@ -867,6 +904,7 @@
   }
 
   HInstruction visitInvokeStatic(HInvokeStatic node) {
+    propagateConstantValueToUses(node);
     if (node.element == backend.getCheckConcurrentModificationError()) {
       if (node.inputs.length == 2) {
         HInstruction firstArgument = node.inputs[0];
@@ -1306,13 +1344,6 @@
       } else {
         markBlockLive(instruction.elseBlock);
       }
-    } else if (condition.isValue()) {
-      ValueTypeMask valueType = condition.instructionType;
-      if (valueType.value == true) {
-        markBlockLive(instruction.thenBlock);
-      } else {
-        markBlockLive(instruction.elseBlock);
-      }
     } else {
       visitControlFlow(instruction);
     }
diff --git a/pkg/compiler/lib/src/ssa/ssa.dart b/pkg/compiler/lib/src/ssa/ssa.dart
index 77322c9..3ab874f 100644
--- a/pkg/compiler/lib/src/ssa/ssa.dart
+++ b/pkg/compiler/lib/src/ssa/ssa.dart
@@ -15,6 +15,8 @@
 import '../common/names.dart' show
     Identifiers,
     Selectors;
+import '../common/resolution.dart' show
+    Resolution;
 import '../common/tasks.dart' show
     CompilerTask;
 import '../compiler.dart' show
@@ -24,6 +26,8 @@
 import '../constants/expressions.dart';
 import '../constants/values.dart';
 import '../dart_types.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import '../diagnostics/invariant.dart' show
     invariant;
 import '../diagnostics/messages.dart';
diff --git a/pkg/compiler/lib/src/ssa/variable_allocator.dart b/pkg/compiler/lib/src/ssa/variable_allocator.dart
index bd95f58..fb35705 100644
--- a/pkg/compiler/lib/src/ssa/variable_allocator.dart
+++ b/pkg/compiler/lib/src/ssa/variable_allocator.dart
@@ -209,10 +209,12 @@
     : liveInstructions = new Map<HBasicBlock, LiveEnvironment>(),
       liveIntervals = new Map<HInstruction, LiveInterval>();
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   void visitGraph(HGraph graph) {
     visitPostDominatorTree(graph);
     if (!liveInstructions[graph.entry].isEmpty) {
-      compiler.internalError(CURRENT_ELEMENT_SPANNABLE, 'LiveIntervalBuilder.');
+      reporter.internalError(CURRENT_ELEMENT_SPANNABLE, 'LiveIntervalBuilder.');
     }
   }
 
diff --git a/pkg/compiler/lib/src/string_validator.dart b/pkg/compiler/lib/src/string_validator.dart
index f953ec0..b790774 100644
--- a/pkg/compiler/lib/src/string_validator.dart
+++ b/pkg/compiler/lib/src/string_validator.dart
@@ -15,9 +15,9 @@
 import 'util/characters.dart';
 
 class StringValidator {
-  final DiagnosticListener listener;
+  final DiagnosticReporter reporter;
 
-  StringValidator(this.listener);
+  StringValidator(this.reporter);
 
   DartString validateInterpolationPart(Token token, StringQuoting quoting,
                                        {bool isFirst: false,
@@ -102,7 +102,7 @@
   }
 
   void stringParseError(String message, Token token, int offset) {
-    listener.reportErrorMessage(
+    reporter.reportErrorMessage(
         token, MessageKind.GENERIC, {'text': "$message @ $offset"});
   }
 
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 3aef3a6..ddaf34d 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
@@ -1534,6 +1534,7 @@
 
   visitYield(Yield node) {
     node.input = visitExpression(node.input);
+    node.next = visitStatement(node.next);
     return node;
   }
 }
diff --git a/pkg/compiler/lib/src/typechecker.dart b/pkg/compiler/lib/src/typechecker.dart
index ec44ea0..fe017ef 100644
--- a/pkg/compiler/lib/src/typechecker.dart
+++ b/pkg/compiler/lib/src/typechecker.dart
@@ -6,6 +6,8 @@
 
 import 'common/names.dart' show
     Identifiers;
+import 'common/resolution.dart' show
+    Resolution;
 import 'common/tasks.dart' show
     CompilerTask;
 import 'compiler.dart' show
@@ -15,7 +17,8 @@
 import 'core_types.dart';
 import 'dart_types.dart';
 import 'diagnostics/diagnostic_listener.dart' show
-    DiagnosticMessage;
+    DiagnosticMessage,
+    DiagnosticReporter;
 import 'diagnostics/invariant.dart' show
     invariant;
 import 'diagnostics/messages.dart';
@@ -66,7 +69,7 @@
     if (element.isClass) return;
     if (element.isTypedef) return;
     ResolvedAst resolvedAst = element.resolvedAst;
-    compiler.withCurrentElement(element.implementation, () {
+    reporter.withCurrentElement(element.implementation, () {
       measure(() {
         TypeCheckerVisitor visitor = new TypeCheckerVisitor(
             compiler, resolvedAst.elements, compiler.types);
@@ -104,7 +107,7 @@
 
   String get name => element.name;
 
-  DartType computeType(Compiler compiler);
+  DartType computeType(Resolution resolution);
 
   /// Returns [: true :] if the element can be access as an invocation.
   bool isCallable(Compiler compiler) {
@@ -116,7 +119,7 @@
       }
     }
     return compiler.types.isAssignable(
-        computeType(compiler), compiler.coreTypes.functionType);
+        computeType(compiler.resolution), compiler.coreTypes.functionType);
   }
 }
 
@@ -128,7 +131,7 @@
 
   Element get element => member.declarations.first.element;
 
-  DartType computeType(Compiler compiler) => member.type;
+  DartType computeType(Resolution resolution) => member.type;
 
   String toString() => 'MemberAccess($member)';
 }
@@ -141,7 +144,7 @@
 
   String get name => 'dynamic';
 
-  DartType computeType(Compiler compiler) => const DynamicType();
+  DartType computeType(Resolution resolution) => const DynamicType();
 
   bool isCallable(Compiler compiler) => true;
 
@@ -159,14 +162,14 @@
     assert(element != null);
   }
 
-  DartType computeType(Compiler compiler) {
+  DartType computeType(Resolution resolution) {
     if (element.isGetter) {
       GetterElement getter = element;
-      FunctionType functionType = getter.computeType(compiler);
+      FunctionType functionType = getter.computeType(resolution);
       return functionType.returnType;
     } else if (element.isSetter) {
       SetterElement setter = element;
-      FunctionType functionType = setter.computeType(compiler);
+      FunctionType functionType = setter.computeType(resolution);
       if (functionType.parameterTypes.length != 1) {
         // TODO(johnniwinther,karlklose): this happens for malformed static
         // setters. Treat them the same as instance members.
@@ -175,11 +178,11 @@
       return functionType.parameterTypes.first;
     } else if (element.isTypedef || element.isClass) {
       TypeDeclarationElement typeDeclaration = element;
-      typeDeclaration.computeType(compiler);
+      typeDeclaration.computeType(resolution);
       return typeDeclaration.thisType;
     } else {
       TypedElement typedElement = element;
-      typedElement.computeType(compiler);
+      typedElement.computeType(resolution);
       return typedElement.type;
     }
   }
@@ -197,7 +200,7 @@
     assert(type != null);
   }
 
-  DartType computeType(Compiler compiler) => type;
+  DartType computeType(Resolution resolution) => type;
 
   String toString() => 'PromotedAccess($element,$type)';
 }
@@ -214,7 +217,7 @@
 
   Element get element => type.element;
 
-  DartType computeType(Compiler compiler) => type;
+  DartType computeType(Resolution resolution) => type;
 
   String toString() => 'TypeAccess($type)';
 }
@@ -233,7 +236,7 @@
 
   String get name => type.name;
 
-  DartType computeType(Compiler compiler) => compiler.typeClass.rawType;
+  DartType computeType(Resolution resolution) => resolution.coreTypes.typeType;
 
   String toString() => 'TypeLiteralAccess($type)';
 }
@@ -248,7 +251,7 @@
 
   String get name => 'call';
 
-  DartType computeType(Compiler compiler) => type;
+  DartType computeType(Resolution resolution) => type;
 
   bool isCallable(Compiler compiler) => true;
 
@@ -305,6 +308,10 @@
 
   CoreTypes get coreTypes => compiler.coreTypes;
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
+  Resolution get resolution => compiler.resolution;
+
   InterfaceType get intType => coreTypes.intType;
   InterfaceType get doubleType => coreTypes.doubleType;
   InterfaceType get boolType => coreTypes.boolType;
@@ -394,16 +401,16 @@
 
   reportTypeWarning(Spannable spannable, MessageKind kind,
                     [Map arguments = const {}]) {
-    compiler.reportWarningMessage(spannable, kind, arguments);
+    reporter.reportWarningMessage(spannable, kind, arguments);
   }
 
   reportMessage(Spannable spannable, MessageKind kind,
                 Map arguments,
                 {bool isHint: false}) {
     if (isHint) {
-      compiler.reportHintMessage(spannable, kind, arguments);
+      reporter.reportHintMessage(spannable, kind, arguments);
     } else {
-      compiler.reportWarningMessage(spannable, kind, arguments);
+      reporter.reportWarningMessage(spannable, kind, arguments);
     }
   }
 
@@ -411,7 +418,7 @@
     if (!reportedTypePromotions.contains(typePromotion)) {
       reportedTypePromotions.add(typePromotion);
       for (TypePromotionMessage message in typePromotion.messages) {
-        compiler.reportHint(message.hint, message.infos);
+        reporter.reportHint(message.hint, message.infos);
       }
     }
   }
@@ -437,9 +444,9 @@
     if (node == null) {
       final String error = 'Unexpected node: null';
       if (lastSeenNode != null) {
-        compiler.internalError(lastSeenNode, error);
+        reporter.internalError(lastSeenNode, error);
       } else {
-        compiler.internalError(executableContext, error);
+        reporter.internalError(executableContext, error);
       }
     } else {
       lastSeenNode = node;
@@ -449,9 +456,9 @@
     DartType result = node.accept(this);
     analyzingInitializer = previouslyInitializer;
     if (result == null) {
-      compiler.internalError(node, 'Type is null.');
+      reporter.internalError(node, 'Type is null.');
     }
-    return result;
+    return _record(node, result);
   }
 
   void checkTypePromotion(Node node, TypePromotion typePromotion,
@@ -461,13 +468,13 @@
     List<Node> potentialMutationsIn =
         elements.getPotentialMutationsIn(node, variable);
     if (!potentialMutationsIn.isEmpty) {
-      DiagnosticMessage hint = compiler.createMessage(
+      DiagnosticMessage hint = reporter.createMessage(
           typePromotion.node,
           MessageKind.POTENTIAL_MUTATION,
           {'variableName': variableName, 'shownType': typePromotion.type});
       List<DiagnosticMessage> infos = <DiagnosticMessage>[];
       for (Node mutation in potentialMutationsIn) {
-        infos.add(compiler.createMessage(mutation,
+        infos.add(reporter.createMessage(mutation,
             MessageKind.POTENTIAL_MUTATION_HERE,
             {'variableName': variableName}));
       }
@@ -476,13 +483,13 @@
     List<Node> potentialMutationsInClosures =
         elements.getPotentialMutationsInClosure(variable);
     if (!potentialMutationsInClosures.isEmpty) {
-      DiagnosticMessage hint = compiler.createMessage(
+      DiagnosticMessage hint = reporter.createMessage(
           typePromotion.node,
           MessageKind.POTENTIAL_MUTATION_IN_CLOSURE,
           {'variableName': variableName, 'shownType': typePromotion.type});
       List<DiagnosticMessage> infos = <DiagnosticMessage>[];
       for (Node mutation in potentialMutationsInClosures) {
-        infos.add(compiler.createMessage(
+        infos.add(reporter.createMessage(
             mutation,
             MessageKind.POTENTIAL_MUTATION_IN_CLOSURE_HERE,
             {'variableName': variableName}));
@@ -493,19 +500,19 @@
       List<Node> accesses = elements.getAccessesByClosureIn(node, variable);
       List<Node> mutations = elements.getPotentialMutations(variable);
       if (!accesses.isEmpty && !mutations.isEmpty) {
-        DiagnosticMessage hint = compiler.createMessage(
+        DiagnosticMessage hint = reporter.createMessage(
             typePromotion.node,
             MessageKind.ACCESSED_IN_CLOSURE,
             {'variableName': variableName, 'shownType': typePromotion.type});
         List<DiagnosticMessage> infos = <DiagnosticMessage>[];
         for (Node access in accesses) {
-          infos.add(compiler.createMessage(
+          infos.add(reporter.createMessage(
               access,
               MessageKind.ACCESSED_IN_CLOSURE_HERE,
               {'variableName': variableName}));
         }
         for (Node mutation in mutations) {
-          infos.add(compiler.createMessage(
+          infos.add(reporter.createMessage(
               mutation,
               MessageKind.POTENTIAL_MUTATION_HERE,
               {'variableName': variableName}));
@@ -560,12 +567,12 @@
                        {bool isConst: false}) {
     if (!types.isAssignable(from, to)) {
       if (compiler.enableTypeAssertions && isConst) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             spannable,
             MessageKind.NOT_ASSIGNABLE,
             {'fromType': from, 'toType': to});
       } else {
-        compiler.reportWarningMessage(
+        reporter.reportWarningMessage(
             spannable,
             MessageKind.NOT_ASSIGNABLE,
             {'fromType': from, 'toType': to});
@@ -656,14 +663,14 @@
         if (parameter.isInitializingFormal) {
           InitializingFormalElement fieldParameter = parameter;
           checkAssignable(parameter, parameter.type,
-              fieldParameter.fieldElement.computeType(compiler));
+              fieldParameter.fieldElement.computeType(resolution));
         }
       });
       if (node.initializers != null) {
         analyze(node.initializers, inInitializer: true);
       }
     } else {
-      FunctionType functionType = element.computeType(compiler);
+      FunctionType functionType = element.computeType(resolution);
       returnType = functionType.returnType;
       type = functionType;
     }
@@ -695,7 +702,7 @@
                              element.isParameter ||
                              element.isField,
           message: 'Unexpected context element ${element}'));
-      return element.computeType(compiler);
+      return element.computeType(resolution);
     }
   }
 
@@ -878,13 +885,13 @@
                             MemberKind memberKind,
                             {bool isHint: false}) {
     return lookupMember(node, type, name, memberKind, null, isHint: isHint)
-        .computeType(compiler);
+        .computeType(resolution);
   }
 
   void analyzeArguments(Send send, Element element, DartType type,
                         [LinkBuilder<DartType> argumentTypes]) {
     Link<Node> arguments = send.arguments;
-    DartType unaliasedType = type.unalias(compiler);
+    DartType unaliasedType = type.unalias(resolution);
     if (identical(unaliasedType.kind, TypeKind.FUNCTION)) {
 
       /// Report [warning] including info(s) about the declaration of [element]
@@ -897,17 +904,17 @@
         if (declaration == null) {
           declaration = type.element;
         } else if (type.isTypedef) {
-          infos.add(compiler.createMessage(
+          infos.add(reporter.createMessage(
               declaration,
               MessageKind.THIS_IS_THE_DECLARATION,
               {'name': element.name}));
           declaration = type.element;
         }
         if (declaration != null) {
-          infos.add(compiler.createMessage(
+          infos.add(reporter.createMessage(
               declaration, MessageKind.THIS_IS_THE_METHOD));
         }
-        compiler.reportWarning(warning, infos);
+        reporter.reportWarning(warning, infos);
       }
 
       /// Report a warning on [node] if [argumentType] is not assignable to
@@ -916,7 +923,7 @@
                            DartType argumentType,
                            DartType parameterType) {
         if (!types.isAssignable(argumentType, parameterType)) {
-          reportWarning(compiler.createMessage(
+          reportWarning(reporter.createMessage(
               node,
               MessageKind.NOT_ASSIGNABLE,
               {'fromType': argumentType, 'toType': parameterType}));
@@ -938,7 +945,7 @@
           if (namedParameterType == null) {
             // TODO(johnniwinther): Provide better information on the called
             // function.
-            reportWarning(compiler.createMessage(
+            reportWarning(reporter.createMessage(
                 argument,
                 MessageKind.NAMED_ARGUMENT_NOT_FOUND,
                 {'argumentName': argumentName}));
@@ -956,7 +963,7 @@
 
               // TODO(johnniwinther): Provide better information on the
               // called function.
-              reportWarning(compiler.createMessage(
+              reportWarning(reporter.createMessage(
                   argument, MessageKind.ADDITIONAL_ARGUMENT));
 
               DartType argumentType = analyze(argument);
@@ -978,7 +985,7 @@
       if (parameterTypes.moveNext()) {
         // TODO(johnniwinther): Provide better information on the called
         // function.
-        reportWarning(compiler.createMessage(
+        reportWarning(reporter.createMessage(
             send, MessageKind.MISSING_ARGUMENT,
             {'argumentType': parameterTypes.current}));
       }
@@ -997,7 +1004,7 @@
   // analysis.
   DartType analyzeInvocation(Send node, ElementAccess elementAccess,
                              [LinkBuilder<DartType> argumentTypes]) {
-    DartType type = elementAccess.computeType(compiler);
+    DartType type = elementAccess.computeType(resolution);
     if (elementAccess.isCallable(compiler)) {
       analyzeArguments(node, elementAccess.element, type, argumentTypes);
     } else {
@@ -1006,7 +1013,7 @@
       analyzeArguments(node, elementAccess.element, const DynamicType(),
                        argumentTypes);
     }
-    type = type.unalias(compiler);
+    type = type.unalias(resolution);
     if (identical(type.kind, TypeKind.FUNCTION)) {
       FunctionType funType = type;
       return funType.returnType;
@@ -1086,7 +1093,7 @@
     } else if (element.isGetter || element.isSetter) {
       return createResolvedAccess(node, name, element);
     } else {
-      compiler.internalError(element,
+      reporter.internalError(element,
           'Unexpected element kind ${element.kind}.');
       return null;
     }
@@ -1117,9 +1124,9 @@
                              {bool lookupClassMember: false}) {
     DartType type =
         computeAccess(node, name, element, memberKind,
-            lookupClassMember: lookupClassMember).computeType(compiler);
+            lookupClassMember: lookupClassMember).computeType(resolution);
     if (type == null) {
-      compiler.internalError(node, 'Type is null on access of $name on $node.');
+      reporter.internalError(node, 'Type is null on access of $name on $node.');
     }
     return type;
   }
@@ -1159,6 +1166,23 @@
 
   }
 
+  static bool _fyiShown = false;
+  DartType _record(Node node, DartType type) {
+    if (node is! Expression) return type;
+    if (const bool.fromEnvironment('send_stats') &&
+        executableContext != null &&
+        // TODO(sigmund): enable also in core libs.
+        !executableContext.library.isPlatformLibrary && !type.isDynamic) {
+      if (!_fyiShown) {
+        print('FYI experiment to collect send stats is on: '
+            'caching types of expressions');
+        _fyiShown = true;
+      }
+      elements.typesCache[node] = type;
+    }
+    return type;
+  }
+
   DartType visitSend(Send node) {
     Element element = elements[node];
 
@@ -1221,7 +1245,7 @@
             if (!types.isMoreSpecific(shownType, knownType)) {
               String variableName = variable.name;
               if (!types.isSubtype(shownType, knownType)) {
-                typePromotion.addHint(compiler.createMessage(
+                typePromotion.addHint(reporter.createMessage(
                     node,
                     MessageKind.NOT_MORE_SPECIFIC_SUBTYPE,
                     {'variableName': variableName,
@@ -1231,7 +1255,7 @@
                 DartType shownTypeSuggestion =
                     computeMoreSpecificType(shownType, knownType);
                 if (shownTypeSuggestion != null) {
-                  typePromotion.addHint(compiler.createMessage(
+                  typePromotion.addHint(reporter.createMessage(
                       node,
                       MessageKind.NOT_MORE_SPECIFIC_SUGGESTION,
                       {'variableName': variableName,
@@ -1239,7 +1263,7 @@
                        'shownTypeSuggestion': shownTypeSuggestion,
                        'knownType': knownType}));
                 } else {
-                  typePromotion.addHint(compiler.createMessage(
+                  typePromotion.addHint(reporter.createMessage(
                       node,
                       MessageKind.NOT_MORE_SPECIFIC,
                       {'variableName': variableName,
@@ -1334,7 +1358,7 @@
     } else if (node.isPropertyAccess) {
       ElementAccess access =
           computeAccess(node, selector.source, element, MemberKind.GETTER);
-      return access.computeType(compiler);
+      return access.computeType(resolution);
     } else if (node.isFunctionObjectInvocation) {
       return unhandledExpression();
     } else {
@@ -1528,7 +1552,7 @@
         case '<<=': operatorName = '<<'; break;
         case '>>=': operatorName = '>>'; break;
         default:
-          compiler.internalError(node, 'Unexpected assignment operator $name.');
+          reporter.internalError(node, 'Unexpected assignment operator $name.');
       }
       if (node.isIndex) {
         // base[key] o= value for some operator o.
@@ -1578,7 +1602,7 @@
   DartType computeConstructorType(ConstructorElement constructor,
                                   DartType type) {
     if (Elements.isUnresolved(constructor)) return const DynamicType();
-    DartType constructorType = constructor.computeType(compiler);
+    DartType constructorType = constructor.computeType(resolution);
     if (identical(type.kind, TypeKind.INTERFACE)) {
       if (constructor.isSynthesized) {
         // TODO(johnniwinther): Remove this when synthesized constructors handle
@@ -1732,6 +1756,17 @@
         SendSet initialization = definition;
         DartType initializer = analyzeNonVoid(initialization.arguments.head);
         checkAssignable(initialization.assignmentOperator, initializer, type);
+        // TODO(sigmund): explore inferring a type for `var` using the RHS (like
+        // DDC does), for example:
+        // if (node.type == null && node.modifiers.isVar &&
+        //     !initializer.isDynamic) {
+        //   var variable = elements[definition];
+        //   if (variable != null) {
+        //     var typePromotion = new TypePromotion(
+        //         node, variable, initializer);
+        //     registerKnownTypePromotion(typePromotion);
+        //   }
+        // }
       }
     }
     return const StatementType();
@@ -1801,7 +1836,7 @@
     DartType elementType = computeForInElementType(node);
     DartType expressionType = analyze(node.expression);
     // TODO(johnniwinther): Move this to _CompilerCoreTypes.
-    compiler.streamClass.ensureResolved(compiler);
+    compiler.streamClass.ensureResolved(resolution);
     DartType streamOfDynamic = coreTypes.streamType();
     if (!types.isAssignable(expressionType, streamOfDynamic)) {
       reportMessage(node.expression,
@@ -1936,7 +1971,7 @@
         }
         unreferencedFields.addAll(enumValues.values);
         if (!unreferencedFields.isEmpty) {
-          compiler.reportWarningMessage(
+          reporter.reportWarningMessage(
               node, MessageKind.MISSING_ENUM_CASES,
               {'enumType': expressionType,
                'enumValues': unreferencedFields.map(
@@ -1973,7 +2008,7 @@
   }
 
   visitNode(Node node) {
-    compiler.internalError(node,
+    reporter.internalError(node,
         'Unexpected node ${node.getObjectDescription()} in the type checker.');
   }
 }
diff --git a/pkg/compiler/lib/src/types/constants.dart b/pkg/compiler/lib/src/types/constants.dart
index e036901..0a303d4 100644
--- a/pkg/compiler/lib/src/types/constants.dart
+++ b/pkg/compiler/lib/src/types/constants.dart
@@ -7,8 +7,13 @@
 import '../compiler.dart' show
     Compiler;
 import '../constants/values.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
+import '../diagnostics/spannable.dart' show
+    CURRENT_ELEMENT_SPANNABLE;
+import '../js_backend/js_backend.dart' show
+    SyntheticConstantKind;
 import 'types.dart';
-import '../js_backend/js_backend.dart' show SyntheticConstantKind;
 
 /// Computes the [TypeMask] for the constant [value].
 TypeMask computeTypeMask(Compiler compiler, ConstantValue value) {
@@ -58,7 +63,8 @@
       case SyntheticConstantKind.NAME:
         return compiler.typesTask.stringType;
       default:
-        compiler.internalError(compiler.currentElement,
+        DiagnosticReporter reporter = compiler.reporter;
+        reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
                                "Unexpected DummyConstantKind.");
         return null;
     }
diff --git a/pkg/compiler/lib/src/types/types.dart b/pkg/compiler/lib/src/types/types.dart
index 9858a6e..6b18981 100644
--- a/pkg/compiler/lib/src/types/types.dart
+++ b/pkg/compiler/lib/src/types/types.dart
@@ -10,13 +10,13 @@
     CompilerTask;
 import '../compiler.dart' show
     Compiler;
+import '../constants/values.dart' show
+    PrimitiveConstantValue;
 import '../diagnostics/invariant.dart' show
     invariant;
 import '../diagnostics/spannable.dart' show
     NO_LOCATION_SPANNABLE;
 import '../elements/elements.dart';
-import '../inferrer/concrete_types_inferrer.dart' show
-    ConcreteTypesInferrer;
 import '../inferrer/type_graph_inferrer.dart' show
     TypeGraphInferrer;
 import '../tree/tree.dart';
@@ -64,15 +64,11 @@
   final String name = 'Type inference';
   final ClassWorld classWorld;
   TypesInferrer typesInferrer;
-  ConcreteTypesInferrer concreteTypesInferrer;
 
   TypesTask(Compiler compiler)
       : this.classWorld = compiler.world,
         super(compiler) {
     typesInferrer = new TypeGraphInferrer(compiler);
-    if (compiler.enableConcreteTypeInference) {
-      concreteTypesInferrer = new ConcreteTypesInferrer(compiler);
-    }
   }
 
   TypeMask dynamicTypeCache;
@@ -284,15 +280,6 @@
   void onResolutionComplete(Element mainElement) {
     measure(() {
       typesInferrer.analyzeMain(mainElement);
-      if (concreteTypesInferrer != null) {
-        bool success = concreteTypesInferrer.analyzeMain(mainElement);
-        if (!success) {
-          // If the concrete type inference bailed out, we pretend it didn't
-          // happen. In the future we might want to record that it failed but
-          // use the partial results as hints.
-          concreteTypesInferrer = null;
-        }
-      }
     });
     typesInferrer.clear();
   }
@@ -303,11 +290,7 @@
   TypeMask getGuaranteedTypeOfElement(Element element) {
     return measure(() {
       TypeMask guaranteedType = typesInferrer.getTypeOfElement(element);
-      return (concreteTypesInferrer == null)
-          ? guaranteedType
-          : intersection(guaranteedType,
-                         concreteTypesInferrer.getTypeOfElement(element),
-                         element);
+      return guaranteedType;
     });
   }
 
@@ -315,11 +298,7 @@
     return measure(() {
       TypeMask guaranteedType =
           typesInferrer.getReturnTypeOfElement(element);
-      return (concreteTypesInferrer == null)
-          ? guaranteedType
-          : intersection(guaranteedType,
-                         concreteTypesInferrer.getReturnTypeOfElement(element),
-                         element);
+      return guaranteedType;
     });
   }
 
@@ -330,11 +309,7 @@
   TypeMask getGuaranteedTypeOfNode(owner, node) {
     return measure(() {
       TypeMask guaranteedType = typesInferrer.getTypeOfNode(owner, node);
-      return (concreteTypesInferrer == null)
-          ? guaranteedType
-          : intersection(guaranteedType,
-                         concreteTypesInferrer.getTypeOfNode(owner, node),
-                         node);
+      return guaranteedType;
     });
   }
 
@@ -345,12 +320,7 @@
     return measure(() {
       TypeMask guaranteedType =
           typesInferrer.getTypeOfSelector(selector, mask);
-      return (concreteTypesInferrer == null)
-          ? guaranteedType
-          : intersection(
-              guaranteedType,
-              concreteTypesInferrer.getTypeOfSelector(selector, mask),
-              selector);
+      return guaranteedType;
     });
   }
 }
diff --git a/pkg/compiler/lib/src/types/value_type_mask.dart b/pkg/compiler/lib/src/types/value_type_mask.dart
index 737be5e..72c5af2 100644
--- a/pkg/compiler/lib/src/types/value_type_mask.dart
+++ b/pkg/compiler/lib/src/types/value_type_mask.dart
@@ -6,7 +6,7 @@
 
 class ValueTypeMask extends ForwardingTypeMask {
   final TypeMask forwardTo;
-  final value;
+  final PrimitiveConstantValue value;
 
   ValueTypeMask(this.forwardTo, this.value);
 
@@ -44,6 +44,6 @@
   }
 
   String toString() {
-    return 'Value mask: [$value] type: $forwardTo';
+    return 'Value mask: [${value.unparse()}] type: $forwardTo';
   }
 }
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/universe/universe.dart b/pkg/compiler/lib/src/universe/universe.dart
index ccb402b..6e572b5 100644
--- a/pkg/compiler/lib/src/universe/universe.dart
+++ b/pkg/compiler/lib/src/universe/universe.dart
@@ -6,30 +6,21 @@
 
 import 'dart:collection';
 
-import '../common/names.dart' show
-    Identifiers,
-    Names,
-    Selectors;
+import '../common/resolution.dart' show
+    Resolution;
 import '../compiler.dart' show
     Compiler;
 import '../diagnostics/invariant.dart' show
     invariant;
-import '../diagnostics/spannable.dart' show
-    SpannableAssertionFailure;
 import '../elements/elements.dart';
 import '../dart_types.dart';
-import '../tree/tree.dart';
-import '../types/types.dart';
 import '../util/util.dart';
 import '../world.dart' show
     ClassWorld,
     World;
 
-import 'call_structure.dart';
 import 'selector.dart' show
     Selector;
-import 'function_set.dart';
-import 'side_effects.dart';
 
 class UniverseSelector {
   final Selector selector;
@@ -393,7 +384,7 @@
   }
 
   DartType registerIsCheck(DartType type, Compiler compiler) {
-    type = type.unalias(compiler);
+    type = type.unalias(compiler.resolution);
     // Even in checked mode, type annotations for return type and argument
     // types do not imply type checks, so there should never be a check
     // against the type variable of a typedef.
diff --git a/pkg/compiler/lib/src/use_unused_api.dart b/pkg/compiler/lib/src/use_unused_api.dart
index d2e8648..7a9c03c 100644
--- a/pkg/compiler/lib/src/use_unused_api.dart
+++ b/pkg/compiler/lib/src/use_unused_api.dart
@@ -28,7 +28,6 @@
 import 'elements/modelx.dart' as modelx;
 import 'elements/visitor.dart' as elements_visitor;
 import 'filenames.dart' as filenames;
-import 'inferrer/concrete_types_inferrer.dart' as concrete_types_inferrer;
 import 'inferrer/type_graph_inferrer.dart' as type_graph_inferrer;
 import 'io/line_column_provider.dart' as io;
 import 'io/source_map_builder.dart' as io;
@@ -69,7 +68,6 @@
   useJsNode(new js.ArrayHole());
   useJsOther(new js.SimpleJavaScriptPrintingContext());
   useJsBackend(null);
-  useConcreteTypesInferrer(null);
   useColor();
   useFilenames();
   useSsa(null);
@@ -230,10 +228,6 @@
   backend.getGeneratedCode(null);
 }
 
-useConcreteTypesInferrer(concrete_types_inferrer.ConcreteTypesInferrer c) {
-  c.debug();
-}
-
 useColor() {
   colors.white(null);
   colors.blue(null);
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index 502ea8e..46cc830 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -13,6 +13,8 @@
 import 'compiler.dart' show
     Compiler;
 import 'dart_types.dart';
+import 'diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import 'diagnostics/invariant.dart' show
     invariant;
 import 'elements/elements.dart' show
@@ -87,6 +89,10 @@
   /// including [cls] itself.
   Iterable<ClassElement> strictSubclassesOf(ClassElement cls);
 
+  /// Returns an iterable over the directly instantiated that implement [cls]
+  /// possibly including [cls] itself, if it is live.
+  Iterable<ClassElement> subtypesOf(ClassElement cls);
+
   /// Returns an iterable over the live classes that implement [cls] _not_
   /// including [cls] if it is live.
   Iterable<ClassElement> strictSubtypesOf(ClassElement cls);
@@ -218,6 +224,19 @@
   }
 
   /// Returns an iterable over the directly instantiated that implement [cls]
+  /// possibly including [cls] itself, if it is live.
+  Iterable<ClassElement> subtypesOf(ClassElement cls) {
+    ClassSet classSet = _classSets[cls.declaration];
+    if (classSet == null) {
+      return const <ClassElement>[];
+    } else {
+      return classSet.subtypes(
+          includeIndirectlyInstantiated: false,
+          includeUninstantiated: false);
+    }
+  }
+
+  /// Returns an iterable over the directly instantiated that implement [cls]
   /// _not_ including [cls].
   Iterable<ClassElement> strictSubtypesOf(ClassElement cls) {
     ClassSet classSet = _classSets[cls.declaration];
@@ -417,6 +436,8 @@
         this.compiler = compiler,
         alreadyPopulated = compiler.cacheStrategy.newSet();
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   /// Called to add [cls] to the set of known classes.
   ///
   /// This ensures that class hierarchy queries can be performed on [cls] and
@@ -500,7 +521,7 @@
       }
       assert(cls.isDeclaration);
       if (!cls.isResolved) {
-        compiler.internalError(cls, 'Class "${cls.name}" is not resolved.');
+        reporter.internalError(cls, 'Class "${cls.name}" is not resolved.');
       }
 
       updateClassHierarchyNodeForClass(cls, directlyInstantiated: true);
@@ -658,11 +679,6 @@
     return elementsThatCannotThrow.contains(element);
   }
 
-  void registerImplicitSuperCall(Registry registry,
-                                 FunctionElement superConstructor) {
-    registry.registerDependency(superConstructor);
-  }
-
   void registerMightBePassedToApply(Element element) {
     functionsThatMightBePassedToApply.add(element);
   }
diff --git a/pkg/compiler/pubspec.yaml b/pkg/compiler/pubspec.yaml
index 8e74b36..f396ed0 100644
--- a/pkg/compiler/pubspec.yaml
+++ b/pkg/compiler/pubspec.yaml
@@ -11,11 +11,11 @@
     path: ../../sdk/lib/_internal/js_runtime
   sdk_library_metadata:
     path: ../../sdk/lib/_internal/sdk_library_metadata
-  dart2js_info: ^0.0.2
+  dart2js_info:
+    path: ../../../../dart2js_info
   lookup_map:
     path: ../lookup_map
 
-
 # Uncomment if running gclient, so you can depend directly on the downloaded
 # versions of dart2js's transitive dependencies:
 #
diff --git a/pkg/compiler/tool/track_memory.dart b/pkg/compiler/tool/track_memory.dart
new file mode 100644
index 0000000..effd92f
--- /dev/null
+++ b/pkg/compiler/tool/track_memory.dart
@@ -0,0 +1,193 @@
+// 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 script to track the high water-mark of memory usage of an application.
+/// To monitor how much memory dart2js is using, run dart2js as follows:
+///
+///     DART_VM_OPTIONS=--observe dart2js ...
+///
+/// and run this script immediately after.
+library compiler.tool.track_memory;
+
+import 'dart:math' show max;
+import 'dart:io';
+import 'dart:async';
+
+import 'dart:convert';
+
+/// Socket to connect to the vm observatory service.
+WebSocket socket;
+
+main(args) async {
+  _printHeader();
+  _showProgress(0, 0, 0, 0);
+  try {
+    var port = args.length > 0 ? int.parse(args[0]) : 8181;
+    socket = await WebSocket.connect('ws://localhost:$port/ws');
+    socket.listen(_handleResponse);
+    await _resumeMainIsolateIfPaused();
+    _streamListen('GC');
+    _streamListen('Isolate');
+    _streamListen('Debug');
+  } catch (e) {
+    // TODO(sigmund): add better error messages, maybe option to retry.
+    print('\n${_RED}error${_NONE}: $e');
+    print('usage:\n'
+        '  Start a Dart process with the --observe flag (and optionally '
+        'the --pause_isolates_on_start flag), then invoke:\n'
+        '      dart tool/track_memory.dart [<port>]\n'
+        '  by default port is 8181');
+  }
+}
+
+/// Internal counter for request ids.
+int _requestId = 0;
+Map _pendingResponses = {};
+
+/// Subscribe to listen to a vm service data stream.
+_streamListen(String streamId) =>
+    _sendMessage('streamListen', {'streamId': '$streamId'});
+
+/// Tell the vm service to resume a specific isolate.
+_resumeIsolate(String isolateId) =>
+    _sendMessage('resume', {'isolateId': '$isolateId'});
+
+/// Resumes the main isolate if it was paused on start.
+_resumeMainIsolateIfPaused() async {
+  var vm = await _sendMessage('getVM');
+  var isolateId = vm['isolates'][0]['id'];
+  var isolate = await _sendMessage('getIsolate', {'isolateId': isolateId});
+  bool isPaused = isolate['pauseEvent']['kind'] == 'PauseStart';
+  if (isPaused) _resumeIsolate(isolateId);
+}
+
+/// Send a message to the vm service.
+Future _sendMessage(String method, [Map args= const {}]) {
+  var id = _requestId++;
+  _pendingResponses[id] = new Completer();
+  socket.add(JSON.encode({
+      'jsonrpc': '2.0',
+      'id': '$id',
+      'method': '$method',
+      'params': args,
+    }));
+  return _pendingResponses[id].future;
+}
+
+/// Handle all responses
+_handleResponse(String s) {
+  var json = JSON.decode(s);
+  if (json['method'] != 'streamNotify') {
+    var id = json['id'];
+    if (id is String) id = int.parse(id);
+    if (id == null || !_pendingResponses.containsKey(id)) return;
+    _pendingResponses.remove(id).complete(json['result']);
+    return;
+  }
+
+  // isolate pauses on exit automatically. We detect this to stop and exit.
+  if (json['params']['streamId'] == 'Debug') {
+    _handleDebug(json);
+  } else if (json['params']['streamId'] == 'Isolate') {
+    _handleIsolate(json);
+  } else if (json['params']['streamId'] == 'GC') {
+    _handleGC(json);
+  }
+}
+
+/// Handle a `Debug` notification.
+_handleDebug(Map json) {
+  var isolateId = json['params']['event']['isolate']['id'];
+  if (json['params']['event']['kind'] == 'PauseStart') {
+    _resumeIsolate(isolateId);
+  } if (json['params']['event']['kind'] == 'PauseExit') {
+    _resumeIsolate(isolateId);
+  }
+}
+
+/// Handle a `Isolate` notification.
+_handleIsolate(Map json) {
+  if (json['params']['event']['kind'] == 'IsolateExit') {
+    print('');
+    socket.close();
+  }
+}
+
+/// Handle a `GC` notification.
+_handleGC(Map json) {
+  // print(new JsonEncoder.withIndent(' ').convert(json));
+  var event = json['params']['event'];
+  var newUsed = event['new']['used'];
+  var newCapacity = event['new']['capacity'];
+  var oldUsed = event['old']['used'];
+  var oldCapacity = event['old']['capacity'];
+  _showProgress(newUsed, newCapacity, oldUsed, oldCapacity);
+}
+
+int lastNewUsed = 0;
+int lastOldUsed = 0;
+int lastMaxUsed = 0;
+int lastNewCapacity = 0;
+int lastOldCapacity = 0;
+int lastMaxCapacity = 0;
+
+/// Shows a status line with use/capacity numbers for new/old/total/max,
+/// highlighting in red when capacity increases, and in green when it decreases.
+_showProgress(newUsed, newCapacity, oldUsed, oldCapacity) {
+  var sb = new StringBuffer();
+  sb.write('\r '); // replace the status-line in place
+  _writeNumber(sb, lastNewUsed, newUsed);
+  _writeNumber(sb, lastNewCapacity, newCapacity, color: true);
+
+  sb.write(' | ');
+  _writeNumber(sb, lastOldUsed, oldUsed);
+  _writeNumber(sb, lastOldCapacity, oldCapacity, color: true);
+
+  sb.write(' | ');
+  _writeNumber(sb, lastNewUsed + lastOldUsed, newUsed + oldUsed);
+  _writeNumber(sb, lastNewCapacity + lastOldCapacity, newCapacity + oldCapacity,
+      color: true);
+
+  sb.write(' | ');
+  var maxUsed = max(lastMaxUsed, newUsed + oldUsed);
+  var maxCapacity = max(lastMaxCapacity, newCapacity + oldCapacity);
+  _writeNumber(sb, lastMaxUsed, maxUsed);
+  _writeNumber(sb, lastMaxCapacity, maxCapacity, color: true);
+  stdout.write('$sb');
+
+  lastNewUsed = newUsed;
+  lastOldUsed = oldUsed;
+  lastMaxUsed = maxUsed;
+  lastNewCapacity = newCapacity;
+  lastOldCapacity = oldCapacity;
+  lastMaxCapacity = maxCapacity;
+}
+
+const mega = 1024 * 1024;
+_writeNumber(sb, before, now, {color: false}) {
+  if (color) sb.write(before < now ? _RED : before > now ? _GREEN : '');
+  var string;
+  if (now < 1024) {
+    string = ' ${now}b';
+  } else if (now < mega) {
+    string = ' ${(now/1024).toStringAsFixed(0)}K';
+  } else {
+    string = ' ${(now/mega).toStringAsFixed(1)}M';
+  }
+  if (string.length < 10) string = '${' ' * (8 - string.length)}$string';
+  sb.write(string);
+  if (color) sb.write(before != now ? _NONE : '');
+  return before > now;
+}
+
+_printHeader() {
+  print('''
+Memory usage:
+ new generation   | old generation   | total            | max
+  in-use/capacity |  in-use/capacity |  in-use/capacity |  in-use/capacity ''');
+}
+
+const _RED = '\x1b[31m';
+const _GREEN = '\x1b[32m';
+const _NONE = '\x1b[0m';
diff --git a/pkg/dart2js_incremental/lib/library_updater.dart b/pkg/dart2js_incremental/lib/library_updater.dart
index 3499f4f..eb4bbd1 100644
--- a/pkg/dart2js_incremental/lib/library_updater.dart
+++ b/pkg/dart2js_incremental/lib/library_updater.dart
@@ -74,11 +74,7 @@
 import 'package:compiler/src/js/js.dart' as jsAst;
 
 import 'package:compiler/src/js_emitter/js_emitter.dart' show
-    ClassBuilder,
-    ClassEmitter,
     CodeEmitterTask,
-    ContainerBuilder,
-    MemberInfo,
     computeMixinClass;
 
 import 'package:compiler/src/js_emitter/full_emitter/emitter.dart'
@@ -687,7 +683,7 @@
       PartialFunctionElement before,
       PartialFunctionElement after) {
     FunctionExpression node =
-        after.parseNode(compiler).asFunctionExpression();
+        after.parseNode(compiler.parsing).asFunctionExpression();
     if (node == null) {
       return cannotReuse(after, "Not a function expression: '$node'");
     }
@@ -709,7 +705,7 @@
       Token diffToken,
       PartialClassElement before,
       PartialClassElement after) {
-    ClassNode node = after.parseNode(compiler).asClassNode();
+    ClassNode node = after.parseNode(compiler.parsing).asClassNode();
     if (node == null) {
       return cannotReuse(after, "Not a ClassNode: '$node'");
     }
diff --git a/pkg/pkg.status b/pkg/pkg.status
index bd76884..40e35e9 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -165,3 +165,33 @@
 
 [ $compiler == dart2js && $cps_ir ]
 lookup_map/test/lookup_map_test: RuntimeError # $async$temp1.get$tests is not a function
+
+[ $compiler == dart2js && $cps_ir && $host_checked ]
+analyzer/test/src/task/html_test: Crash # Issue 24485
+analyzer/test/src/task/incremental_element_builder_test: Crash # Issue 24485
+analyzer/test/src/task/strong_mode_test: Crash # Issue 24485
+analyzer/test/src/task/inputs_test: Crash # Issue 24485
+analyzer/test/src/task/model_test: Crash # Issue 24485
+analyzer/test/src/task/manager_test: Crash # Issue 24485
+analyzer/test/generated/static_warning_code_test: Crash # Issue 24485
+analyzer/test/generated/utilities_test: Crash # Issue 24485
+analyzer/test/src/task/dart_test: Crash # Issue 24485
+analyzer/test/src/task/html_work_manager_test: Crash # Issue 24485
+analyzer/test/src/task/general_test: Crash # Issue 24485
+analyzer/test/src/task/dart_work_manager_test: Crash # Issue 24485
+analyzer/test/generated/parser_test: Crash # Issue 24485
+analyzer/test/generated/static_type_warning_code_test: Crash # Issue 24485
+analyzer/test/src/context/cache_test: Crash # Issue 24485
+analyzer/test/generated/incremental_resolver_test: Crash # Issue 24485
+analyzer/test/generated/element_test: Crash # Issue 24485
+analyzer/test/generated/incremental_scanner_test: Crash # Issue 24485
+analyzer/test/generated/scanner_test: Crash # Issue 24485
+analyzer/test/src/task/driver_test: Crash # Issue 24485
+analyzer/test/generated/compile_time_error_code_test: Crash # Issue 24485
+analyzer/test/generated/non_error_resolver_test: Crash # Issue 24485
+analyzer/test/generated/resolver_test: Crash # Issue 24485
+analyzer/test/generated/source_factory_test: Crash # Issue 24485
+analyzer/test/generated/ast_test: Crash # Issue 24485
+analyzer/test/src/context/context_test: Crash # Issue 24485
+analyzer/test/enum_test: Crash # Issue 24485
+analyzer/test/generated/all_the_rest_test: Crash # Issue 24485
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index 253d8d7..1185ee4 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -205,6 +205,8 @@
     "*secure_socket.h",
     "*filter_unsupported.cc",
     "*io_service_unsupported.cc",
+    "*io_service.cc",
+    "*io_service.h",
     "*_test.cc",
     "*_test.h",
     "*dbg*",
diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index 78a71e7..1777513 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -137,6 +137,9 @@
         'log_macos.cc',
         'log_win.cc',
       ],
+      'defines': [
+        'LEGACY_DEBUG_PROTOCOL_ENABLED',
+      ],
       'includes': [
         'builtin_impl_sources.gypi',
         '../platform/platform_sources.gypi',
@@ -737,6 +740,7 @@
         '../vm/vm_sources.gypi',
       ],
       'defines': [
+        'LEGACY_DEBUG_PROTOCOL_ENABLED',
         'TESTING',
       ],
       # Only include _test.[cc|h] files.
diff --git a/runtime/bin/builtin.dart b/runtime/bin/builtin.dart
index feb26a9..8ee15ce 100644
--- a/runtime/bin/builtin.dart
+++ b/runtime/bin/builtin.dart
@@ -71,8 +71,7 @@
 SendPort _loadPort;
 // The receive port for a load request. Multiple sources can be fetched in
 // a single load request.
-RawReceivePort _receivePort;
-SendPort _sendPort;
+RawReceivePort _dataPort;
 // A request id valid only for the current load cycle (while the number of
 // outstanding load requests is greater than 0). Can be reset when loading is
 // completed.
@@ -125,17 +124,16 @@
 
 // Class collecting all of the information about a particular load request.
 class _LoadRequest {
-  final int _id;
+  final int _id = _reqId++;
   final int _tag;
   final String _uri;
   final Uri _resourceUri;
   final _context;
 
-  _LoadRequest(this._id,
-               this._tag,
-               this._uri,
-               this._resourceUri,
-               this._context);
+  _LoadRequest(this._tag, this._uri, this._resourceUri, this._context) {
+    assert(_reqMap[_id] == null);
+    _reqMap[_id] = this;
+  }
 
   toString() => "LoadRequest($_id, $_tag, $_uri, $_resourceUri, $_context)";
 }
@@ -320,13 +318,13 @@
     }
   }
 
-  if (!_pendingLoads()) {
+  if (!_pendingLoads() && (_dataPort != null)) {
+    // Close the _dataPort now that there are no more requests outstanding.
     if (_traceLoading) {
       _log("Closing loading port.");
     }
-    _receivePort.close();
-    _receivePort = null;
-    _sendPort = null;
+    _dataPort.close();
+    _dataPort = null;
     _reqId = 0;
     _signalDoneLoading();
   }
@@ -367,33 +365,26 @@
 
 
 void _startLoadRequest(int tag, String uri, Uri resourceUri, context) {
-  if (_receivePort == null) {
+  if (_dataPort == null) {
     if (_traceLoading) {
       _log("Initializing load port.");
     }
-    assert(_receivePort == null);
-    assert(_sendPort == null);
-    _receivePort = new RawReceivePort(_handleLoaderReply);
-    _sendPort = _receivePort.sendPort;
+    assert(_dataPort == null);
+    _dataPort = new RawReceivePort(_handleLoaderReply);
   }
   // Register the load request and send it to the VM service isolate.
-  var curId = _reqId++;
+  var req = new _LoadRequest(tag, uri, resourceUri, context);
 
-  assert(_reqMap[curId] == null);
-  _reqMap[curId] = new _LoadRequest(curId, tag, uri, resourceUri, context);
-
-  assert(_receivePort != null);
-  assert(_sendPort != null);
-
+  assert(_dataPort != null);
   var msg = new List(4);
-  msg[0] = _sendPort;
+  msg[0] = _dataPort.sendPort;
   msg[1] = _traceLoading;
-  msg[2] = curId;
+  msg[2] = req._id;
   msg[3] = resourceUri.toString();
   _loadPort.send(msg);
 
   if (_traceLoading) {
-    _log("Loading of $resourceUri for $uri started with id: $curId. "
+    _log("Loading of $resourceUri for $uri started with id: ${req._id}. "
          "${_reqMap.length} requests remaining, "
          "${_pendingPackageLoads.length} packages pending.");
   }
@@ -434,17 +425,10 @@
 
   // Resolve all pending package loads now that we know how to resolve them.
   while (_pendingPackageLoads.length > 0) {
+    // Order does not matter as we queue all of the requests up right now.
     var req = _pendingPackageLoads.removeLast();
-    if (req != null) {
-      if (_traceLoading) {
-        _log("Handling deferred load request: $req");
-      }
-      _loadPackage(req._tag, req._uri, req._resourceUri, req._context);
-    } else {
-      if (_traceLoading) {
-        _log("Skipping dummy deferred request.");
-      }
-    }
+    // Call the registered closure, to handle the delayed action.
+    req();
   }
   // Reset the pending package loads to empty. So that we eventually can
   // finish loading.
@@ -516,7 +500,13 @@
 
   // Signal that the resolution of the packages map has started. But in this
   // case it is not tied to a particular request.
-  _pendingPackageLoads.add(null);
+  _pendingPackageLoads.add(() {
+    // Nothing to be done beyond registering that there is pending package
+    // resolution requested by having an empty entry.
+    if (_traceLoading) {
+      _log("Skipping dummy deferred request.");
+    }
+  });
 
   if (_traceLoading) {
     _log("Requested packages map at '$packagesUri'.");
@@ -553,8 +543,10 @@
     }
     // Wrap inside a _LoadError unless we are already propagating a previously
     // seen _LoadError.
-    var error = (e is _LoadError) ? e : new _LoadError(e.toString());
-    _asyncLoadError(tag, uri, context, error, s);
+    var error = (e is _LoadError) ? e : new _LoadError(uri, e.toString());
+    // Register a dummy load request and fail to load it.
+    var req = new _LoadRequest(tag, uri, resourceUri, context);
+    _asyncLoadError(req, error, s);
   }
 }
 
@@ -570,8 +562,15 @@
       // request for package resolution & loading.
       _requestPackagesMap();
     }
-    var req = new _LoadRequest(-1, tag, uri, resourceUri, context);
-    _pendingPackageLoads.add(req);
+    // Register the action of loading this package once the package resolution
+    // is ready.
+    _pendingPackageLoads.add(() {
+      if (_traceLoading) {
+        _log("Handling deferred package request: "
+             "$tag, $uri, $resourceUri, $context");
+      }
+      _loadPackage(tag, uri, resourceUri, context);
+    });
     if (_traceLoading) {
       _log("Pending package load of '$uri': "
       "${_pendingPackageLoads.length} pending");
@@ -635,6 +634,48 @@
 }
 
 
+// Handling of access to the package root or package map from user code.
+_triggerPackageResolution(action) {
+  if (_packagesReady()) {
+    // Packages are ready. Execute the action now.
+    action();
+  } else {
+    if (_pendingPackageLoads.isEmpty) {
+      // Package resolution has not been setup yet, and this is the first
+      // request for package resolution & loading.
+      _requestPackagesMap();
+    }
+    // Register the action for when the package resolution is ready.
+    _pendingPackageLoads.add(action);
+  }
+}
+
+
+Future<Uri> _getPackageRoot() {
+  if (_traceLoading) {
+    _log("Request for package root from user code.");
+  }
+  var completer = new Completer<Uri>();
+  _triggerPackageResolution(() {
+    completer.complete(_packageRoot);
+  });
+  return completer.future;
+}
+
+
+Future<Map<String, Uri>> _getPackageMap() {
+  if (_traceLoading) {
+    _log("Request for package map from user code.");
+  }
+  var completer = new Completer<Map<String, Uri>>();
+  _triggerPackageResolution(() {
+    var result = (_packageMap != null) ? new Map.from(_packageMap) : {};
+    completer.complete(result);
+  });
+  return completer.future;
+}
+
+
 // Handling of Resource class by dispatching to the load port.
 Future<List<int>> _resourceReadAsBytes(Uri uri) {
   var completer = new Completer<List<int>>();
@@ -762,4 +803,6 @@
 _setupHooks() {
   _setupCompleted = true;
   VMLibraryHooks.resourceReadAsBytes = _resourceReadAsBytes;
+  VMLibraryHooks.getPackageRoot = _getPackageRoot;
+  VMLibraryHooks.getPackageMap = _getPackageMap;
 }
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index 6e27f82..33f59d6 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -29,6 +29,7 @@
 
 static const int kBufferSize = 64 * 1024;
 static const int kStdOverlappedBufferSize = 16 * 1024;
+static const int kMaxUDPPackageLength = 64 * 1024;
 
 OverlappedBuffer* OverlappedBuffer::AllocateBuffer(int buffer_size,
                                                    Operation operation) {
@@ -989,7 +990,8 @@
   ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
   ASSERT(pending_read_ == NULL);
 
-  OverlappedBuffer* buffer = OverlappedBuffer::AllocateRecvFromBuffer(1024);
+  OverlappedBuffer* buffer =
+      OverlappedBuffer::AllocateRecvFromBuffer(kMaxUDPPackageLength);
 
   DWORD flags;
   flags = 0;
@@ -1212,14 +1214,18 @@
                                                 int bytes,
                                                 OverlappedBuffer* buffer) {
   ASSERT(handle->is_datagram_socket());
-  buffer->set_data_length(bytes);
-  handle->ReadComplete(buffer);
-  if (!handle->IsClosing()) {
-    int event_mask = 1 << kInEvent;
-    if ((handle->Mask() & event_mask) != 0) {
+  if (bytes >= 0) {
+    buffer->set_data_length(bytes);
+    handle->ReadComplete(buffer);
+    if (!handle->IsClosing()) {
+      int event_mask = 1 << kInEvent;
+      if ((handle->Mask() & event_mask) != 0) {
         Dart_Port port = handle->NextNotifyDartPort(event_mask);
-      DartUtils::PostInt32(port, event_mask);
+        DartUtils::PostInt32(port, event_mask);
+      }
     }
+  } else {
+    HandleError(handle);
   }
 
   DeleteIfClosed(handle);
@@ -1413,6 +1419,11 @@
           last_error == ERROR_BROKEN_PIPE) {
         ASSERT(bytes == 0);
         handler_impl->HandleIOCompletion(bytes, key, overlapped);
+      } else if (last_error == ERROR_MORE_DATA) {
+        // Don't ASSERT no bytes in this case. This can happen if the receive
+        // buffer for datagram sockets is to small to contain a full datagram,
+        // and in this case bytes hold the bytes that was read.
+        handler_impl->HandleIOCompletion(-1, key, overlapped);
       } else {
         ASSERT(bytes == 0);
         handler_impl->HandleIOCompletion(-1, key, overlapped);
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index 9c28ac1..086e9f3 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -132,7 +132,6 @@
   V(Socket_SetOption, 4)                                                       \
   V(Socket_JoinMulticast, 4)                                                   \
   V(Socket_LeaveMulticast, 4)                                                  \
-  V(Socket_MarkSocketAsSharedHack, 1)                                          \
   V(Socket_GetSocketId, 1)                                                     \
   V(Socket_SetSocketId, 2)                                                     \
   V(Stdin_ReadByte, 1)                                                         \
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 09dfbf0..d829587 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -81,6 +81,12 @@
 static bool has_run_precompiled_snapshot = false;
 
 
+// Global flag that is used to indicate that we want to compile everything in
+// the same way as precompilation before main, then continue running in the
+// same process.
+static bool has_noopt = false;
+
+
 extern const char* kPrecompiledLibraryName;
 extern const char* kPrecompiledSymbolName;
 static const char* kPrecompiledVmIsolateName = "precompiled.vmisolate";
@@ -108,6 +114,8 @@
 static const int kCompilationErrorExitCode = 254;
 // Exit code indicating an unhandled error that is not a compilation error.
 static const int kErrorExitCode = 255;
+// Exit code indicating a vm restart request.  Never returned to the user.
+static const int kRestartRequestExitCode = 1000;
 
 extern bool do_vm_shutdown;  // Defined in bin/process.cc
 static void ErrorExit(int exit_code, const char* format, ...) {
@@ -326,7 +334,7 @@
     return false;
   }
   has_gen_precompiled_snapshot = true;
-  vm_options->AddArgument("--precompile");
+  vm_options->AddArgument("--precompilation");
   return true;
 }
 
@@ -339,7 +347,20 @@
     return false;
   }
   has_run_precompiled_snapshot = true;
-  vm_options->AddArgument("--precompile");
+  vm_options->AddArgument("--precompilation");
+  return true;
+}
+
+
+static bool ProcessNooptOption(
+    const char* arg,
+    CommandLineOptions* vm_options) {
+  ASSERT(arg != NULL);
+  if (*arg != '\0') {
+    return false;
+  }
+  has_noopt = true;
+  vm_options->AddArgument("--precompilation");
   return true;
 }
 
@@ -483,6 +504,7 @@
   { "--debug", ProcessDebugOption },
   { "--enable-vm-service", ProcessEnableVmServiceOption },
   { "--gen-precompiled-snapshot", ProcessGenPrecompiledSnapshotOption },
+  { "--noopt", ProcessNooptOption },
   { "--observe", ProcessObserveOption },
   { "--run-precompiled-snapshot", ProcessRunPrecompiledSnapshotOption },
   { "--shutdown", ProcessShutdownOption },
@@ -665,8 +687,15 @@
 #define CHECK_RESULT(result)                                                   \
   if (Dart_IsError(result)) {                                                  \
     *error = strdup(Dart_GetError(result));                                    \
-    *exit_code = Dart_IsCompilationError(result) ? kCompilationErrorExitCode : \
-        (Dart_IsApiError(result) ? kApiErrorExitCode : kErrorExitCode);        \
+    if (Dart_IsCompilationError(result)) {                                     \
+      *exit_code = kCompilationErrorExitCode;                                  \
+    } else if (Dart_IsApiError(result)) {                                      \
+      *exit_code = kApiErrorExitCode;                                          \
+    } else if (Dart_IsVMRestartRequest(result)) {                              \
+      *exit_code = kRestartRequestExitCode;                                    \
+    } else {                                                                   \
+      *exit_code = kErrorExitCode;                                             \
+    }                                                                          \
     Dart_ExitScope();                                                          \
     Dart_ShutdownIsolate();                                                    \
     return NULL;                                                               \
@@ -782,6 +811,7 @@
 
 #undef CHECK_RESULT
 
+
 static Dart_Isolate CreateIsolateAndSetup(const char* script_uri,
                                           const char* main,
                                           const char* package_root,
@@ -887,9 +917,6 @@
 "  enables the VM service and listens on specified port for connections\n"
 "  (default port number is 8181)\n"
 "\n"
-"--noopt\n"
-"  run unoptimized code only\n"
-"\n"
 "The following options are only used for VM development and may\n"
 "be changed in any future version:\n");
     const char* print_flags = "--print_flags";
@@ -933,16 +960,6 @@
   return buffer;
 }
 
-static void DartExitOnError(Dart_Handle error) {
-  if (!Dart_IsError(error)) {
-    return;
-  }
-  const int exit_code = Dart_IsCompilationError(error) ?
-      kCompilationErrorExitCode : kErrorExitCode;
-  ErrorExit(exit_code, "%s\n", Dart_GetError(error));
-}
-
-
 static void ShutdownIsolate(void* callback_data) {
   IsolateData* isolate_data = reinterpret_cast<IsolateData*>(callback_data);
   delete isolate_data;
@@ -1077,6 +1094,212 @@
 }
 
 
+#define CHECK_RESULT(result)                                                   \
+  if (Dart_IsError(result)) {                                                  \
+    if (Dart_IsVMRestartRequest(result)) {                                     \
+      Dart_ExitScope();                                                        \
+      Dart_ShutdownIsolate();                                                  \
+      return true;                                                             \
+    }                                                                          \
+    const int exit_code = Dart_IsCompilationError(result) ?                    \
+        kCompilationErrorExitCode : kErrorExitCode;                            \
+    ErrorExit(exit_code, "%s\n", Dart_GetError(result));                       \
+  }
+
+bool RunMainIsolate(const char* script_name,
+                    CommandLineOptions* dart_options) {
+  // Call CreateIsolateAndSetup which creates an isolate and loads up
+  // the specified application script.
+  char* error = NULL;
+  int exit_code = 0;
+  char* isolate_name = BuildIsolateName(script_name, "main");
+  Dart_Isolate isolate = CreateIsolateAndSetupHelper(script_name,
+                                                     "main",
+                                                     commandline_package_root,
+                                                     commandline_packages_file,
+                                                     NULL,
+                                                     &error,
+                                                     &exit_code);
+  if (isolate == NULL) {
+    delete [] isolate_name;
+    if (exit_code == kRestartRequestExitCode) {
+      free(error);
+      return true;
+    }
+    Log::PrintErr("%s\n", error);
+    free(error);
+    error = NULL;
+    Process::TerminateExitCodeHandler();
+    error = Dart_Cleanup();
+    if (error != NULL) {
+      Log::PrintErr("VM cleanup failed: %s\n", error);
+      free(error);
+    }
+    if (do_vm_shutdown) {
+      DebuggerConnectionHandler::StopHandler();
+      EventHandler::Stop();
+    }
+    exit((exit_code != 0) ? exit_code : kErrorExitCode);
+  }
+  delete [] isolate_name;
+
+  Dart_EnterIsolate(isolate);
+  ASSERT(isolate == Dart_CurrentIsolate());
+  ASSERT(isolate != NULL);
+  Dart_Handle result;
+
+  Dart_EnterScope();
+
+  if (generate_script_snapshot) {
+    // First create a snapshot.
+    Dart_Handle result;
+    uint8_t* buffer = NULL;
+    intptr_t size = 0;
+    result = Dart_CreateScriptSnapshot(&buffer, &size);
+    CHECK_RESULT(result);
+
+    // Open the snapshot file.
+    File* snapshot_file = File::Open(snapshot_filename, File::kWriteTruncate);
+    if (snapshot_file == NULL) {
+      ErrorExit(kErrorExitCode,
+                "Unable to open file %s for writing the snapshot\n",
+                snapshot_filename);
+    }
+
+    // Write the magic number to indicate file is a script snapshot.
+    DartUtils::WriteMagicNumber(snapshot_file);
+
+    // Now write the snapshot out to specified file.
+    bool bytes_written = snapshot_file->WriteFully(buffer, size);
+    ASSERT(bytes_written);
+    delete snapshot_file;
+    snapshot_file = NULL;
+  } else {
+    // Lookup the library of the root script.
+    Dart_Handle root_lib = Dart_RootLibrary();
+    // Import the root library into the builtin library so that we can easily
+    // lookup the main entry point exported from the root library.
+    Dart_Handle builtin_lib =
+        Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
+    ASSERT(!Dart_IsError(builtin_lib));
+    result = Dart_LibraryImportLibrary(builtin_lib, root_lib, Dart_Null());
+
+    if (has_noopt || has_gen_precompiled_snapshot) {
+      Dart_QualifiedFunctionName standalone_entry_points[] = {
+        { "dart:_builtin", "::", "_getMainClosure" },
+        { "dart:_builtin", "::", "_getPrintClosure" },
+        { "dart:_builtin", "::", "_getUriBaseClosure" },
+        { "dart:_builtin", "::", "_resolveUri" },
+        { "dart:_builtin", "::", "_setWorkingDirectory" },
+        { "dart:_builtin", "::", "_loadDataAsync" },
+        { "dart:io", "::", "_makeUint8ListView" },
+        { "dart:io", "::", "_makeDatagram" },
+        { "dart:io", "::", "_setupHooks" },
+        { "dart:io", "CertificateException", "CertificateException." },
+        { "dart:io", "HandshakeException", "HandshakeException." },
+        { "dart:io", "TlsException", "TlsException." },
+        { "dart:io", "X509Certificate", "X509Certificate." },
+        { "dart:io", "_ExternalBuffer", "set:data" },
+        { "dart:io", "_Platform", "set:_nativeScript" },
+        { "dart:io", "_ProcessStartStatus", "set:_errorCode" },
+        { "dart:io", "_ProcessStartStatus", "set:_errorMessage" },
+        { "dart:io", "_SecureFilterImpl", "get:ENCRYPTED_SIZE" },
+        { "dart:io", "_SecureFilterImpl", "get:SIZE" },
+        { "dart:vmservice_io", "::", "_addResource" },
+        { "dart:vmservice_io", "::", "main" },
+        { NULL, NULL, NULL }  // Must be terminated with NULL entries.
+      };
+
+      const bool reset_fields = has_gen_precompiled_snapshot;
+      result = Dart_Precompile(standalone_entry_points, reset_fields);
+      CHECK_RESULT(result);
+    }
+
+    if (has_gen_precompiled_snapshot) {
+      uint8_t* vm_isolate_buffer = NULL;
+      intptr_t vm_isolate_size = 0;
+      uint8_t* isolate_buffer = NULL;
+      intptr_t isolate_size = 0;
+      uint8_t* instructions_buffer = NULL;
+      intptr_t instructions_size = 0;
+      result = Dart_CreatePrecompiledSnapshot(&vm_isolate_buffer,
+                                              &vm_isolate_size,
+                                              &isolate_buffer,
+                                              &isolate_size,
+                                              &instructions_buffer,
+                                              &instructions_size);
+      CHECK_RESULT(result);
+      WriteSnapshotFile(kPrecompiledVmIsolateName,
+                        vm_isolate_buffer,
+                        vm_isolate_size);
+      WriteSnapshotFile(kPrecompiledIsolateName,
+                        isolate_buffer,
+                        isolate_size);
+      WriteSnapshotFile(kPrecompiledInstructionsName,
+                        instructions_buffer,
+                        instructions_size);
+    } else {
+      if (has_compile_all) {
+        result = Dart_CompileAll();
+        CHECK_RESULT(result);
+      }
+
+      if (Dart_IsNull(root_lib)) {
+        ErrorExit(kErrorExitCode,
+                  "Unable to find root library for '%s'\n",
+                  script_name);
+      }
+
+      // The helper function _getMainClosure creates a closure for the main
+      // entry point which is either explicitly or implictly exported from the
+      // root library.
+      Dart_Handle main_closure = Dart_Invoke(builtin_lib,
+          Dart_NewStringFromCString("_getMainClosure"), 0, NULL);
+      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;
+      Dart_Handle isolate_args[kNumIsolateArgs];
+      isolate_args[0] = main_closure;                        // entryPoint
+      isolate_args[1] = CreateRuntimeOptions(dart_options);  // args
+
+      Dart_Handle isolate_lib =
+          Dart_LookupLibrary(Dart_NewStringFromCString("dart:isolate"));
+      result = Dart_Invoke(isolate_lib,
+                           Dart_NewStringFromCString("_startMainIsolate"),
+                           kNumIsolateArgs, isolate_args);
+      CHECK_RESULT(result);
+
+      // Keep handling messages until the last active receive port is closed.
+      result = Dart_RunLoop();
+      CHECK_RESULT(result);
+    }
+  }
+
+  Dart_ExitScope();
+  // Shutdown the isolate.
+  Dart_ShutdownIsolate();
+
+  // No restart.
+  return false;
+}
+
+#undef CHECK_RESULT
+
+
 void main(int argc, char** argv) {
   char* script_name;
   const int EXTRA_VM_ARGUMENTS = 2;
@@ -1183,182 +1406,11 @@
   Dart_SetServiceStreamCallbacks(&ServiceStreamListenCallback,
                                  &ServiceStreamCancelCallback);
 
-  // Call CreateIsolateAndSetup which creates an isolate and loads up
-  // the specified application script.
-  int exit_code = 0;
-  char* isolate_name = BuildIsolateName(script_name, "main");
-  Dart_Isolate isolate = CreateIsolateAndSetupHelper(script_name,
-                                                     "main",
-                                                     commandline_package_root,
-                                                     commandline_packages_file,
-                                                     NULL,
-                                                     &error,
-                                                     &exit_code);
-  if (isolate == NULL) {
-    Log::PrintErr("%s\n", error);
-    free(error);
-    error = NULL;
-    delete [] isolate_name;
-    Process::TerminateExitCodeHandler();
-    error = Dart_Cleanup();
-    if (error != NULL) {
-      Log::PrintErr("VM cleanup failed: %s\n", error);
-      free(error);
-    }
-    if (do_vm_shutdown) {
-      DebuggerConnectionHandler::StopHandler();
-      EventHandler::Stop();
-    }
-    exit((exit_code != 0) ? exit_code : kErrorExitCode);
-  }
-  delete [] isolate_name;
-
-  Dart_EnterIsolate(isolate);
-  ASSERT(isolate == Dart_CurrentIsolate());
-  ASSERT(isolate != NULL);
-  Dart_Handle result;
-
-  Dart_EnterScope();
-
-  if (generate_script_snapshot) {
-    // First create a snapshot.
-    Dart_Handle result;
-    uint8_t* buffer = NULL;
-    intptr_t size = 0;
-    result = Dart_CreateScriptSnapshot(&buffer, &size);
-    DartExitOnError(result);
-
-    // Open the snapshot file.
-    File* snapshot_file = File::Open(snapshot_filename, File::kWriteTruncate);
-    if (snapshot_file == NULL) {
-      ErrorExit(kErrorExitCode,
-                "Unable to open file %s for writing the snapshot\n",
-                snapshot_filename);
-    }
-
-    // Write the magic number to indicate file is a script snapshot.
-    DartUtils::WriteMagicNumber(snapshot_file);
-
-    // Now write the snapshot out to specified file.
-    bool bytes_written = snapshot_file->WriteFully(buffer, size);
-    ASSERT(bytes_written);
-    delete snapshot_file;
-    snapshot_file = NULL;
-  } else {
-    // Lookup the library of the root script.
-    Dart_Handle root_lib = Dart_RootLibrary();
-    // Import the root library into the builtin library so that we can easily
-    // lookup the main entry point exported from the root library.
-    Dart_Handle builtin_lib =
-        Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
-    ASSERT(!Dart_IsError(builtin_lib));
-    result = Dart_LibraryImportLibrary(builtin_lib, root_lib, Dart_Null());
-
-    if (has_gen_precompiled_snapshot) {
-      Dart_QualifiedFunctionName standalone_entry_points[] = {
-        { "dart:_builtin", "::", "_getMainClosure" },
-        { "dart:_builtin", "::", "_getPrintClosure" },
-        { "dart:_builtin", "::", "_getUriBaseClosure" },
-        { "dart:_builtin", "::", "_resolveUri" },
-        { "dart:_builtin", "::", "_setWorkingDirectory" },
-        { "dart:_builtin", "::", "_loadDataAsync" },
-        { "dart:io", "::", "_makeUint8ListView" },
-        { "dart:io", "::", "_makeDatagram" },
-        { "dart:io", "::", "_setupHooks" },
-        { "dart:io", "CertificateException", "CertificateException." },
-        { "dart:io", "HandshakeException", "HandshakeException." },
-        { "dart:io", "TlsException", "TlsException." },
-        { "dart:io", "X509Certificate", "X509Certificate." },
-        { "dart:io", "_ExternalBuffer", "set:data" },
-        { "dart:io", "_Platform", "set:_nativeScript" },
-        { "dart:io", "_ProcessStartStatus", "set:_errorCode" },
-        { "dart:io", "_ProcessStartStatus", "set:_errorMessage" },
-        { "dart:io", "_SecureFilterImpl", "get:ENCRYPTED_SIZE" },
-        { "dart:io", "_SecureFilterImpl", "get:SIZE" },
-        { "dart:vmservice_io", "::", "_addResource" },
-        { "dart:vmservice_io", "::", "main" },
-        { NULL, NULL, NULL }  // Must be terminated with NULL entries.
-      };
-
-      result = Dart_Precompile(standalone_entry_points);
-      DartExitOnError(result);
-
-      uint8_t* vm_isolate_buffer = NULL;
-      intptr_t vm_isolate_size = 0;
-      uint8_t* isolate_buffer = NULL;
-      intptr_t isolate_size = 0;
-      uint8_t* instructions_buffer = NULL;
-      intptr_t instructions_size = 0;
-      result = Dart_CreatePrecompiledSnapshot(&vm_isolate_buffer,
-                                              &vm_isolate_size,
-                                              &isolate_buffer,
-                                              &isolate_size,
-                                              &instructions_buffer,
-                                              &instructions_size);
-      DartExitOnError(result);
-      WriteSnapshotFile(kPrecompiledVmIsolateName,
-                        vm_isolate_buffer,
-                        vm_isolate_size);
-      WriteSnapshotFile(kPrecompiledIsolateName,
-                        isolate_buffer,
-                        isolate_size);
-      WriteSnapshotFile(kPrecompiledInstructionsName,
-                        instructions_buffer,
-                        instructions_size);
-    } else {
-      if (has_compile_all) {
-        result = Dart_CompileAll();
-        DartExitOnError(result);
-      }
-
-      if (Dart_IsNull(root_lib)) {
-        ErrorExit(kErrorExitCode,
-                  "Unable to find root library for '%s'\n",
-                  script_name);
-      }
-
-      // The helper function _getMainClosure creates a closure for the main
-      // entry point which is either explicitly or implictly exported from the
-      // root library.
-      Dart_Handle main_closure = Dart_Invoke(builtin_lib,
-          Dart_NewStringFromCString("_getMainClosure"), 0, NULL);
-      DartExitOnError(main_closure);
-
-      // Set debug breakpoint if specified on the command line before calling
-      // the main function.
-      if (breakpoint_at != NULL) {
-        result = SetBreakpoint(breakpoint_at, root_lib);
-        if (Dart_IsError(result)) {
-          ErrorExit(kErrorExitCode,
-                    "Error setting breakpoint at '%s': %s\n",
-                    breakpoint_at,
-                    Dart_GetError(result));
-        }
-      }
-
-      // Call _startIsolate in the isolate library to enable dispatching the
-      // initial startup message.
-      const intptr_t kNumIsolateArgs = 2;
-      Dart_Handle isolate_args[kNumIsolateArgs];
-      isolate_args[0] = main_closure;                         // entryPoint
-      isolate_args[1] = CreateRuntimeOptions(&dart_options);  // args
-
-      Dart_Handle isolate_lib =
-          Dart_LookupLibrary(Dart_NewStringFromCString("dart:isolate"));
-      result = Dart_Invoke(isolate_lib,
-                           Dart_NewStringFromCString("_startMainIsolate"),
-                           kNumIsolateArgs, isolate_args);
-      DartExitOnError(result);
-
-      // Keep handling messages until the last active receive port is closed.
-      result = Dart_RunLoop();
-      DartExitOnError(result);
-    }
+  // Run the main isolate until we aren't told to restart.
+  while (RunMainIsolate(script_name, &dart_options)) {
+    Log::PrintErr("Restarting VM\n");
   }
 
-  Dart_ExitScope();
-  // Shutdown the isolate.
-  Dart_ShutdownIsolate();
   // Terminate process exit-code handler.
   Process::TerminateExitCodeHandler();
 
diff --git a/runtime/bin/process.cc b/runtime/bin/process.cc
index 9e3e14e..47e2ff5 100644
--- a/runtime/bin/process.cc
+++ b/runtime/bin/process.cc
@@ -262,7 +262,15 @@
     free(error);
   }
   if (do_vm_shutdown) {
+#ifdef LEGACY_DEBUG_PROTOCOL_ENABLED
+    // Note that this dependency crosses logical project boundaries by making
+    // the dart:io implementation depend upon the standalone VM's legacy debug
+    // protocol. This breaks projects which want to use our dart:io
+    // implementation. Because the protocol is going away shortly, it's
+    // reasonable to leave it behind a #ifdef that is only enabled for the
+    // standalone VM for now.
     DebuggerConnectionHandler::StopHandler();
+#endif
     EventHandler::Stop();
   }
   exit(static_cast<int>(status));
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index af90fab..1b82008 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -43,18 +43,33 @@
 static const bool SSL_LOG_STATUS = false;
 static const bool SSL_LOG_DATA = false;
 
-static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 200;
+static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 1000;
 
 /* Handle an error reported from the BoringSSL library. */
-static void ThrowIOException(const char* exception_type,
+static void ThrowIOException(int status,
+                             const char* exception_type,
                              const char* message,
                              bool free_message = false) {
-  // TODO(24068): Get the error code and message from the error stack.
-  // There may be more than one error on the stack - should we
-  // concatenate the error messages?
-  int error_code = 0;
-  const char* error_message = "Unknown error from BoringSSL library";
-  OSError os_error_struct(error_code, error_message, OSError::kBoringSSL);
+  char error_string[SSL_ERROR_MESSAGE_BUFFER_SIZE];
+  error_string[0] = '\0';
+  int error = ERR_get_error();
+  while (error != 0) {
+    int length = strlen(error_string);
+    int free_length = SSL_ERROR_MESSAGE_BUFFER_SIZE - length;
+    if (free_length > 16) {
+      // Enough room for error code at least.
+      if (length > 0) {
+        error_string[length] = '\n';
+        error_string[length + 1] = '\0';
+        length++;
+        free_length--;
+      }
+      ERR_error_string_n(error, error_string + length, free_length);
+      // ERR_error_string_n is guaranteed to leave a null-terminated string.
+    }
+    error = ERR_get_error();
+  }
+  OSError os_error_struct(status, error_string, OSError::kBoringSSL);
   Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct);
   Dart_Handle exception =
       DartUtils::NewDartIOException(exception_type, message, os_error);
@@ -332,28 +347,26 @@
 
 int PasswordCallback(char* buf, int size, int rwflag, void* userdata) {
   char* password = static_cast<char*>(userdata);
-  if (static_cast<size_t>(size) < strlen(password) + 1) {
-    Log::PrintErr("Password buffer too small.\n");
-    exit(1);
-    // TODO(24182): Find the actual value of size passed in here, and
-    // check for password length longer than this in the Dart function
-    // that passes in the password, so we never have this problem.
-  }
-  strncpy(buf, static_cast<char*>(userdata), size);
-  return strlen(static_cast<char*>(userdata));
+  ASSERT(size == PEM_BUFSIZE);
+  strncpy(buf, password, size);
+  return strlen(password);
 }
 
 
-void CheckStatus(int status, const char* message, int line) {
+void CheckStatus(int status,
+                 const char* type,
+                 const char* message) {
   // TODO(24183): Take appropriate action on failed calls,
   // throw exception that includes all messages from the error stack.
-  if (status != 1 && SSL_LOG_STATUS) {
+  if (status == 1) return;
+  if (SSL_LOG_STATUS) {
     int error = ERR_get_error();
-    Log::PrintErr("Failed: %s line %d\n", message, line);
+    Log::PrintErr("Failed: %s status %d", message, status);
     char error_string[SSL_ERROR_MESSAGE_BUFFER_SIZE];
     ERR_error_string_n(error, error_string, SSL_ERROR_MESSAGE_BUFFER_SIZE);
     Log::PrintErr("ERROR: %d %s\n", error, error_string);
   }
+  ThrowIOException(status, type, message);
 }
 
 
@@ -371,12 +384,16 @@
   const char* password = NULL;
   if (Dart_IsString(password_object)) {
     ThrowIfError(Dart_StringToCString(password_object, &password));
+    if (strlen(password) > PEM_BUFSIZE - 1) {
+      Dart_ThrowException(DartUtils::NewDartArgumentError(
+        "SecurityContext.usePrivateKey password length is greater than"
+        " 1023 (PEM_BUFSIZE)"));
+    }
   } else if (Dart_IsNull(password_object)) {
     password = "";
   } else {
     Dart_ThrowException(DartUtils::NewDartArgumentError(
-        "Password argument to SecurityContext.usePrivateKey is not "
-        "a String or null"));
+        "SecurityContext.usePrivateKey password is not a String or null"));
   }
 
   SSL_CTX_set_default_passwd_cb(context, PasswordCallback);
@@ -387,7 +404,7 @@
   // TODO(24184): Handle different expected errors here - file missing,
   // incorrect password, file not a PEM, and throw exceptions.
   // CheckStatus should also throw an exception in uncaught cases.
-  CheckStatus(status, "SSL_CTX_use_PrivateKey_file", __LINE__);
+  CheckStatus(status, "TlsException", "Failure in usePrivateKey");
   SSL_CTX_set_default_passwd_cb_userdata(context, NULL);
 }
 
@@ -413,7 +430,8 @@
   }
 
   int status = SSL_CTX_load_verify_locations(context, filename, directory);
-  CheckStatus(status, "SSL_CTX_load_verify_locations", __LINE__);
+  CheckStatus(
+      status, "TlsException", "SSL_CTX_load_verify_locations");
 }
 
 
@@ -448,7 +466,9 @@
         " is not a String"));
   }
   int status = SSL_CTX_use_certificate_chain_file(context, filename);
-  CheckStatus(status, "SSL_CTX_use_certificate_chain_file", __LINE__);
+  CheckStatus(status,
+              "TlsException",
+              "Failure in useCertificateChain");
 }
 
 
@@ -873,13 +893,9 @@
   int error;
   BIO* ssl_side;
   status = BIO_new_bio_pair(&ssl_side, 10000, &socket_side_, 10000);
-  CheckStatus(status, "BIO_new_bio_pair", __LINE__);
+  CheckStatus(status, "TlsException", "BIO_new_bio_pair");
 
-  if (context == NULL) {
-    DART_CHECK_VALID(Dart_ThrowException(DartUtils::NewDartArgumentError(
-        "Default SecurityContext not implemented, context cannot be null.")));
-  }
-
+  assert(context != NULL);
   ssl_ = SSL_new(context);
   SSL_set_bio(ssl_, ssl_side, ssl_side);
   SSL_set_mode(ssl_, SSL_MODE_AUTO_RETRY);  // TODO(whesse): Is this right?
@@ -891,6 +907,8 @@
     SSL_set_verify(ssl_, SSL_VERIFY_NONE, NULL);
   } else {
     SetAlpnProtocolList(protocols_handle, ssl_, NULL, false);
+    status = SSL_set_tlsext_host_name(ssl_, hostname);
+    CheckStatus(status, "TlsException", "Set SNI host name");
     // Sets the hostname in the certificate-checking object, so it is checked
     // against the certificate presented by the server.
     X509_VERIFY_PARAM* certificate_checking_parameters = SSL_get0_param(ssl_);
@@ -899,11 +917,10 @@
                                 X509_V_FLAG_PARTIAL_CHAIN |
                                 X509_V_FLAG_TRUSTED_FIRST);
     X509_VERIFY_PARAM_set_hostflags(certificate_checking_parameters, 0);
-    X509_VERIFY_PARAM_set1_host(certificate_checking_parameters,
-                                hostname_, strlen(hostname_));
-    // TODO(24225) Check return value of set1_host().
-    // TODO(24186) free hostname_ if it is not freed when SSL is destroyed.
-    // otherwise, make it a local variable, not a instance field.
+    status = X509_VERIFY_PARAM_set1_host(certificate_checking_parameters,
+                                         hostname_, strlen(hostname_));
+    CheckStatus(status, "TlsException",
+                "Set hostname for certificate checking");
   }
   // Make the connection:
   if (is_server_) {
@@ -948,7 +965,6 @@
 void SSLFilter::Handshake() {
   // Try and push handshake along.
   int status;
-  int error;
   status = SSL_do_handshake(ssl_);
   if (callback_error != NULL) {
     // The SSL_do_handshake will try performing a handshake and might call
@@ -957,57 +973,33 @@
     // logic and we propagate the error"
     Dart_PropagateError(callback_error);
   }
-  if (SSL_LOG_STATUS) Log::Print("SSL_handshake status: %d\n", status);
-  if (status != 1) {
-    error = SSL_get_error(ssl_, status);
-    if (SSL_LOG_STATUS) {
-      Log::Print("ERROR: %d\n", error);
-      ERR_print_errors_cb(printErrorCallback, NULL);
-    }
+  if (SSL_want_write(ssl_) || SSL_want_read(ssl_)) {
+    in_handshake_ = true;
+    return;
   }
-  if (status == 1) {
-    if (in_handshake_) {
-      // TODO(24071): Check return value of SSL_get_verify_result, this
-      //    should give us the hostname check.
-      int result = SSL_get_verify_result(ssl_);
-      if (SSL_LOG_STATUS) {
-        Log::Print("Handshake verification status: %d\n", result);
-        X509* peer_certificate = SSL_get_peer_certificate(ssl_);
-        if (peer_certificate == NULL) {
-          Log::Print("No peer certificate received\n");
-        } else {
-          X509_NAME* s_name = X509_get_subject_name(peer_certificate);
-          printf("Peer certificate SN: ");
-          X509_NAME_print_ex_fp(stdout, s_name, 4, 0);
-          printf("\n");
-        }
-      }
-      ThrowIfError(Dart_InvokeClosure(
-          Dart_HandleFromPersistent(handshake_complete_), 0, NULL));
-      in_handshake_ = false;
-    }
-  } else if (status == 0) {
-    if (is_server_) {
-      ThrowIOException("HandshakeException",
-                       "Handshake error in server");
-    } else {
-      ThrowIOException("HandshakeException",
-                       "Handshake error in client");
-    }
-  } else if (status < 0) {
-    if (SSL_want_write(ssl_) || SSL_want_read(ssl_)) {
-      if (!in_handshake_) {
-        in_handshake_ = true;
-      }
-    } else {
-      if (is_server_) {
-        ThrowIOException("HandshakeException",
-                         "Handshake error in server");
+  CheckStatus(status,
+      "HandshakeException",
+      is_server_ ? "Handshake error in server" : "Handshake error in client");
+  // Handshake succeeded.
+  if (in_handshake_) {
+    // TODO(24071): Check return value of SSL_get_verify_result, this
+    //    should give us the hostname check.
+    int result = SSL_get_verify_result(ssl_);
+    if (SSL_LOG_STATUS) {
+      Log::Print("Handshake verification status: %d\n", result);
+      X509* peer_certificate = SSL_get_peer_certificate(ssl_);
+      if (peer_certificate == NULL) {
+        Log::Print("No peer certificate received\n");
       } else {
-        ThrowIOException("HandshakeException",
-                         "Handshake error in client");
+        X509_NAME* s_name = X509_get_subject_name(peer_certificate);
+        printf("Peer certificate SN: ");
+        X509_NAME_print_ex_fp(stdout, s_name, 4, 0);
+        printf("\n");
       }
     }
+    ThrowIfError(Dart_InvokeClosure(
+        Dart_HandleFromPersistent(handshake_complete_), 0, NULL));
+    in_handshake_ = false;
   }
 }
 
@@ -1044,6 +1036,10 @@
     BIO_free(socket_side_);
     socket_side_ = NULL;
   }
+  if (hostname_ != NULL) {
+    free(hostname_);
+    hostname_ = NULL;
+  }
   for (int i = 0; i < kNumBuffers; ++i) {
     Dart_DeletePersistentHandle(dart_buffer_objects_[i]);
     delete[] buffers_[i];
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc
index ea5154e..b0b6a34 100644
--- a/runtime/bin/socket.cc
+++ b/runtime/bin/socket.cc
@@ -170,20 +170,6 @@
 }
 
 
-Dart_Handle ListeningSocketRegistry::MarkSocketFdAsSharableHack(
-    intptr_t socketfd) {
-  MutexLocker ml(ListeningSocketRegistry::mutex_);
-
-  SocketsIterator it = sockets_by_fd_.find(socketfd);
-  if (it != sockets_by_fd_.end()) {
-    it->second->shared = true;
-    return Dart_True();
-  } else {
-    return Dart_False();
-  }
-}
-
-
 void FUNCTION_NAME(InternetAddress_Parse)(Dart_NativeArguments args) {
   const char* address =
       DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
@@ -855,15 +841,6 @@
 }
 
 
-void FUNCTION_NAME(Socket_MarkSocketAsSharedHack)(Dart_NativeArguments args) {
-  intptr_t socketfd =
-      Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
-
-  ListeningSocketRegistry *registry = ListeningSocketRegistry::Instance();
-  Dart_SetReturnValue(args, registry->MarkSocketFdAsSharableHack(socketfd));
-}
-
-
 void Socket::SetSocketIdNativeField(Dart_Handle socket, intptr_t id) {
   Dart_Handle err =
       Dart_SetNativeInstanceField(socket, kSocketIdNativeField, id);
diff --git a/runtime/bin/socket.h b/runtime/bin/socket.h
index 507acd9..1910f86 100644
--- a/runtime/bin/socket.h
+++ b/runtime/bin/socket.h
@@ -395,13 +395,6 @@
   // this function.
   bool CloseSafe(intptr_t socketfd);
 
-  // Mark an existing socket as sharable if it is not already marked as
-  // sharable.
-  //
-  // NOTE: This is a temporary measure until ServerSocketReference's are
-  // removed.
-  Dart_Handle MarkSocketFdAsSharableHack(intptr_t socketfd);
-
   Mutex *mutex() { return mutex_; }
 
  private:
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index 47e5f44..7de16a9 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -1083,8 +1083,6 @@
   bool nativeLeaveMulticast(
       List<int> addr, List<int> interfaceAddr, int interfaceIndex)
       native "Socket_LeaveMulticast";
-  bool _nativeMarkSocketAsSharedHack()
-      native "Socket_MarkSocketAsSharedHack";
 }
 
 
@@ -1187,50 +1185,10 @@
     }
   }
 
-  RawServerSocketReference get reference {
-    if (_referencePort == null) {
-      bool successfull = _socket._nativeMarkSocketAsSharedHack();
-      _referencePort = new ReceivePort();
-      _referencePort.listen((sendPort) {
-        sendPort.send(
-          [_socket.address,
-           _socket.port,
-           _v6Only]);
-      });
-    }
-    return new _RawServerSocketReference(_referencePort.sendPort);
-  }
-
   void set _owner(owner) { _socket.owner = owner; }
 }
 
 
-class _RawServerSocketReference implements RawServerSocketReference {
-  final SendPort _sendPort;
-
-  _RawServerSocketReference(this._sendPort);
-
-  Future<RawServerSocket> create() {
-    var port = new ReceivePort();
-    _sendPort.send(port.sendPort);
-    return port.first.then((List args) {
-      port.close();
-
-      InternetAddress address = args[0];
-      int tcpPort = args[1];
-      bool v6Only = args[2];
-      return
-          RawServerSocket.bind(address, tcpPort, v6Only: v6Only, shared: true);
-    });
-  }
-
-  int get hashCode => _sendPort.hashCode;
-
-  bool operator==(Object other)
-      => other is _RawServerSocketReference && _sendPort == other._sendPort;
-}
-
-
 class _RawSocket extends Stream<RawSocketEvent>
                  implements RawSocket {
   final _NativeSocket _socket;
@@ -1393,17 +1351,6 @@
 }
 
 
-class _ServerSocketReference implements ServerSocketReference {
-  final RawServerSocketReference _rawReference;
-
-  _ServerSocketReference(this._rawReference);
-
-  Future<ServerSocket> create() {
-    return _rawReference.create().then((raw) => new _ServerSocket(raw));
-  }
-}
-
-
 class _ServerSocket extends Stream<Socket>
                     implements ServerSocket {
   final _socket;
@@ -1436,10 +1383,6 @@
 
   Future close() => _socket.close().then((_) => this);
 
-  ServerSocketReference get reference {
-    return new _ServerSocketReference(_socket.reference);
-  }
-
   void set _owner(owner) { _socket._owner = owner; }
 }
 
diff --git a/runtime/bin/vmservice/vmservice_io.dart b/runtime/bin/vmservice/vmservice_io.dart
index d9b0c75..eb44a6c 100644
--- a/runtime/bin/vmservice/vmservice_io.dart
+++ b/runtime/bin/vmservice/vmservice_io.dart
@@ -8,7 +8,7 @@
 import 'dart:convert';
 import 'dart:io';
 import 'dart:isolate';
-import 'dart:vmservice';
+import 'dart:_vmservice';
 
 part 'loader.dart';
 part 'resources.dart';
diff --git a/runtime/codereview.settings b/runtime/codereview.settings
index 210cc8b..b731156 100644
--- a/runtime/codereview.settings
+++ b/runtime/codereview.settings
@@ -1,4 +1,4 @@
 # This file is used by gcl to get repository specific information.
-CODE_REVIEW_SERVER: http://codereview.chromium.org/
+CODE_REVIEW_SERVER: http://codereview.chromium.org
 VIEW_VC: https://github.com/dart-lang/sdk/commit/
 CC_LIST: reviews@dartlang.org,vm-dev@dartlang.org
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 031b8c5..c5658951 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -131,7 +131,10 @@
  *   occur in any function which triggers the execution of Dart code.
  *
  * - Fatal error handles are produced when the system wants to shut
- *   down the current isolate.
+ *   down the current isolate. Sometimes a fatal error may be a
+ *   restart request (see Dart_IsRestartRequest). If the embedder does
+ *   not support restarting the VM, then this should be treated as a
+ *   normal fatal error.
  *
  * --- Propagating errors ---
  *
@@ -268,6 +271,17 @@
 DART_EXPORT bool Dart_IsFatalError(Dart_Handle handle);
 
 /**
+ * Is this error a request to restart the VM?
+ *
+ * If an embedder chooses to support restarting the VM from tools
+ * (such as a debugger), then this function is used to distinguish
+ * restart requests from other fatal errors.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT bool Dart_IsVMRestartRequest(Dart_Handle handle);
+
+/**
  * Gets the error message from an error handle.
  *
  * Requires there to be a current isolate.
@@ -2877,8 +2891,29 @@
 } Dart_QualifiedFunctionName;
 
 
+/**
+ * Compiles all functions reachable from the provided entry points and marks
+ * the isolate to disallow future compilation.
+ *
+ * \param entry_points A list of functions that may be invoked through the
+ * embedding API, e.g. Dart_Invoke/GetField/SetField/New/InvokeClosure.
+ *
+ * \param reset_fields Controls whether static fields are reset. Fields without
+ * an initializer will be set to null, and fields with an initializer will have
+ * their initializer run the next time they are accessed.
+ *
+ * reset_fields is true when we are about to create a precompilated snapshot.
+ * Some fields are already been initialized as part of the loading logic, and
+ * we want them to be reinitialized in the new process that will load the
+ * snapshot. reset_fields is false for --noopt, which will continue running in
+ * the same process.
+ *
+ * \return An error handle if a compilation error or runtime error running const
+ * constructors was encountered.
+ */
 DART_EXPORT Dart_Handle Dart_Precompile(
-    Dart_QualifiedFunctionName entry_points[]);
+    Dart_QualifiedFunctionName entry_points[],
+    bool reset_fields);
 
 
 DART_EXPORT Dart_Handle Dart_CreatePrecompiledSnapshot(
diff --git a/runtime/include/dart_tools_api.h b/runtime/include/dart_tools_api.h
index 0e279e0..6d1567c 100644
--- a/runtime/include/dart_tools_api.h
+++ b/runtime/include/dart_tools_api.h
@@ -891,19 +891,22 @@
 #define DART_TIMELINE_STREAM_API (1 << 0)
 /** Timeline stream for compiler events */
 #define DART_TIMELINE_STREAM_COMPILER (1 << 1)
+/** Timeline stream for Dart provided events */
+#define DART_TIMELINE_STREAM_DART (1 << 2)
 /** Timeline stream for embedder provided events */
-#define DART_TIMELINE_STREAM_EMBEDDER (1 << 2)
+#define DART_TIMELINE_STREAM_EMBEDDER (1 << 3)
 /** Timeline stream for GC events */
-#define DART_TIMELINE_STREAM_GC (1 << 3)
+#define DART_TIMELINE_STREAM_GC (1 << 4)
 /** Timeline stream for isolate events */
-#define DART_TIMELINE_STREAM_ISOLATE (1 << 4)
+#define DART_TIMELINE_STREAM_ISOLATE (1 << 5)
 
 /** Timeline stream for VM events */
-#define DART_TIMELINE_STREAM_VM (1 << 5)
+#define DART_TIMELINE_STREAM_VM (1 << 6)
 
 /** Enable all timeline stream recording for an isolate */
 #define DART_TIMELINE_STREAM_ALL (DART_TIMELINE_STREAM_API |                   \
                                   DART_TIMELINE_STREAM_COMPILER |              \
+                                  DART_TIMELINE_STREAM_DART |                  \
                                   DART_TIMELINE_STREAM_EMBEDDER |              \
                                   DART_TIMELINE_STREAM_GC |                    \
                                   DART_TIMELINE_STREAM_ISOLATE)
@@ -966,7 +969,7 @@
 typedef void (*Dart_StreamConsumer)(
     Dart_StreamConsumer_State state,
     const char* stream_name,
-    uint8_t* buffer,
+    const uint8_t* buffer,
     intptr_t buffer_length,
     void* stream_callback_data);
 
diff --git a/runtime/lib/async_patch.dart b/runtime/lib/async_patch.dart
index d785347..fdeb5c9 100644
--- a/runtime/lib/async_patch.dart
+++ b/runtime/lib/async_patch.dart
@@ -182,3 +182,5 @@
     return cancellationCompleter.future;
   }
 }
+
+patch void _rethrow(Object error, StackTrace stackTrace) native "Async_rethrow";
diff --git a/runtime/lib/developer_sources.gypi b/runtime/lib/developer_sources.gypi
index 4d4218c..e3f1ea6 100644
--- a/runtime/lib/developer_sources.gypi
+++ b/runtime/lib/developer_sources.gypi
@@ -10,6 +10,8 @@
     'developer.dart',
     'profiler.cc',
     'profiler.dart',
+    'timeline.cc',
+    'timeline.dart',
   ],
 }
 
diff --git a/runtime/lib/errors.cc b/runtime/lib/errors.cc
index 8383a30..c7a2164 100644
--- a/runtime/lib/errors.cc
+++ b/runtime/lib/errors.cc
@@ -126,4 +126,12 @@
   return Object::null();
 }
 
+// Rethrow an error with a stacktrace.
+DEFINE_NATIVE_ENTRY(Async_rethrow, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Instance, error, arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(Instance, stacktrace, arguments->NativeArgAt(1));
+  Exceptions::ReThrow(thread, error, stacktrace);
+  return Object::null();
+}
+
 }  // namespace dart
diff --git a/runtime/lib/internal_patch.dart b/runtime/lib/internal_patch.dart
index f2fe680..8e95506 100644
--- a/runtime/lib/internal_patch.dart
+++ b/runtime/lib/internal_patch.dart
@@ -15,6 +15,9 @@
   static var eventHandlerSendData;
   // Implementation of Resource.readAsBytes.
   static var resourceReadAsBytes;
+  // Implementation of package root/map provision.
+  static var getPackageRoot;
+  static var getPackageMap;
 }
 
 patch class CodeUnits {
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index 5199f19..82f468f 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -259,17 +259,25 @@
 }
 
 
-DEFINE_NATIVE_ENTRY(Isolate_spawnUri, 10) {
+DEFINE_NATIVE_ENTRY(Isolate_spawnUri, 12) {
   GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(String, uri, arguments->NativeArgAt(1));
+
   GET_NON_NULL_NATIVE_ARGUMENT(Instance, args, arguments->NativeArgAt(2));
   GET_NON_NULL_NATIVE_ARGUMENT(Instance, message, arguments->NativeArgAt(3));
+
   GET_NON_NULL_NATIVE_ARGUMENT(Bool, paused, arguments->NativeArgAt(4));
-  GET_NATIVE_ARGUMENT(Bool, checked, arguments->NativeArgAt(5));
-  GET_NATIVE_ARGUMENT(String, package_root, arguments->NativeArgAt(6));
+  GET_NATIVE_ARGUMENT(SendPort, onExit, arguments->NativeArgAt(5));
+  GET_NATIVE_ARGUMENT(SendPort, onError, arguments->NativeArgAt(6));
+
   GET_NATIVE_ARGUMENT(Bool, fatalErrors, arguments->NativeArgAt(7));
-  GET_NATIVE_ARGUMENT(SendPort, onExit, arguments->NativeArgAt(8));
-  GET_NATIVE_ARGUMENT(SendPort, onError, arguments->NativeArgAt(9));
+  GET_NATIVE_ARGUMENT(Bool, checked, arguments->NativeArgAt(8));
+
+  GET_NATIVE_ARGUMENT(Array, environment, arguments->NativeArgAt(9));
+
+  GET_NATIVE_ARGUMENT(String, package_root, arguments->NativeArgAt(10));
+  GET_NATIVE_ARGUMENT(Array, packages, arguments->NativeArgAt(11));
+
 
   // Canonicalize the uri with respect to the current isolate.
   char* error = NULL;
diff --git a/runtime/lib/isolate_patch.dart b/runtime/lib/isolate_patch.dart
index daaaf97..08fc247 100644
--- a/runtime/lib/isolate_patch.dart
+++ b/runtime/lib/isolate_patch.dart
@@ -275,6 +275,22 @@
 
   /* patch */ static Isolate get current => _currentIsolate;
 
+  /* patch */ static Future<Uri> get packageRoot {
+    var hook = VMLibraryHooks.getPackageRoot;
+    if (hook == null) {
+      throw new UnimplementedError("Isolate.packageRoot");
+    }
+    return hook();
+  }
+
+  /* patch */ static Future<Map<String, Uri>> get packageMap {
+    var hook = VMLibraryHooks.getPackageMap;
+    if (hook == null) {
+      throw new UnimplementedError("Isolate.packageMap");
+    }
+    return hook();
+  }
+
   /* patch */ static Future<Isolate> spawn(
       void entryPoint(message), var message,
       {bool paused: false, bool errorsAreFatal,
@@ -318,15 +334,21 @@
        Map<String, Uri> packages}) {
     RawReceivePort readyPort;
     if (environment != null) throw new UnimplementedError("environment");
+    if (packages != null) throw new UnimplementedError("packages");
     try {
       // The VM will invoke [_startIsolate] and not `main`.
       // TODO: Handle [packages].
       readyPort = new RawReceivePort();
       var packageRootString =
           (packageRoot == null) ? null : packageRoot.toString();
-      _spawnUri(readyPort.sendPort, uri.toString(), args, message,
-                paused, checked, packageRootString,
-                errorsAreFatal, onExit, onError);
+      var packagesList = null;
+
+      _spawnUri(readyPort.sendPort, uri.toString(),
+                args, message,
+                paused, onExit, onError,
+                errorsAreFatal, checked,
+                null, /* environment */
+                packageRootString, packagesList);
       Completer completer = new Completer<Isolate>.sync();
       readyPort.handler = (readyMessage) {
         readyPort.close();
@@ -369,8 +391,10 @@
 
   static void _spawnUri(SendPort readyPort, String uri,
                         List<String> args, var message,
-                        bool paused, bool checked, String packageRoot,
-                        bool errorsAreFatal, SendPort onExit, SendPort onError)
+                        bool paused, SendPort onExit, SendPort onError,
+                        bool errorsAreFatal, bool checked,
+                        List environment,
+                        String packageRoot, List packages)
       native "Isolate_spawnUri";
 
   static void _sendOOB(port, msg) native "Isolate_sendOOB";
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 65f7c62..8e80deb 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -91,8 +91,7 @@
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   const Class& cls = Class::Handle(zone, func.Owner());
-  const Error& error = Error::Handle(
-      zone, cls.EnsureIsFinalized(thread->isolate()));
+  const Error& error = Error::Handle(zone, cls.EnsureIsFinalized(thread));
   if (!error.IsNull()) {
     Exceptions::PropagateError(error);
     UNREACHABLE();
@@ -345,7 +344,7 @@
     }
   }
 
-  const Error& error = Error::Handle(cls.EnsureIsFinalized(Isolate::Current()));
+  const Error& error = Error::Handle(cls.EnsureIsFinalized(Thread::Current()));
   if (!error.IsNull()) {
     Exceptions::PropagateError(error);
     UNREACHABLE();
@@ -382,9 +381,17 @@
   str = lib.name();
   args.SetAt(1, str);
   str = lib.url();
-  if (str.Equals("dart:_builtin") || str.Equals("dart:_blink")) {
-    // Censored library (grumble).
-    return Instance::null();
+  const char* censored_libraries[] = {
+    "dart:_builtin",
+    "dart:_blink",
+    "dart:_vmservice",
+    NULL,
+  };
+  for (intptr_t i = 0; censored_libraries[i] != NULL; i++) {
+    if (str.Equals(censored_libraries[i])) {
+      // Censored library (grumble).
+      return Instance::null();
+    }
   }
   if (str.Equals("dart:io")) {
     // Hack around dart:io being loaded into non-service isolates in Dartium.
@@ -589,11 +596,12 @@
 
 static void VerifyMethodKindShifts() {
 #ifdef DEBUG
-  Isolate* isolate = Isolate::Current();
-  const Library& lib = Library::Handle(isolate, Library::MirrorsLibrary());
-  const Class& cls = Class::Handle(isolate,
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  const Library& lib = Library::Handle(zone, Library::MirrorsLibrary());
+  const Class& cls = Class::Handle(zone,
       lib.LookupClassAllowPrivate(Symbols::_LocalMethodMirror()));
-  const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(isolate));
+  const Error& error = Error::Handle(zone, cls.EnsureIsFinalized(thread));
   ASSERT(error.IsNull());
 
   Field& field = Field::Handle();
@@ -977,7 +985,7 @@
     UNREACHABLE();
   }
   const Class& cls = Class::Handle(type.type_class());
-  const Error& error = Error::Handle(cls.EnsureIsFinalized(isolate));
+  const Error& error = Error::Handle(cls.EnsureIsFinalized(thread));
   if (!error.IsNull()) {
     Exceptions::PropagateError(error);
   }
@@ -994,7 +1002,7 @@
     UNREACHABLE();
   }
   const Class& cls = Class::Handle(type.type_class());
-  const Error& error = Error::Handle(cls.EnsureIsFinalized(isolate));
+  const Error& error = Error::Handle(cls.EnsureIsFinalized(thread));
   if (!error.IsNull()) {
     Exceptions::PropagateError(error);
   }
@@ -1059,7 +1067,7 @@
   GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(2));
   const Class& klass = Class::Handle(ref.GetClassReferent());
 
-  const Error& error = Error::Handle(klass.EnsureIsFinalized(isolate));
+  const Error& error = Error::Handle(klass.EnsureIsFinalized(thread));
   if (!error.IsNull()) {
     Exceptions::PropagateError(error);
   }
@@ -1110,7 +1118,7 @@
   GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(2));
   const Class& klass = Class::Handle(ref.GetClassReferent());
 
-  const Error& error = Error::Handle(klass.EnsureIsFinalized(isolate));
+  const Error& error = Error::Handle(klass.EnsureIsFinalized(thread));
   if (!error.IsNull()) {
     Exceptions::PropagateError(error);
   }
diff --git a/runtime/lib/timeline.cc b/runtime/lib/timeline.cc
new file mode 100644
index 0000000..ac2426e
--- /dev/null
+++ b/runtime/lib/timeline.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/bootstrap_natives.h"
+
+#include "include/dart_api.h"
+
+#include "vm/native_entry.h"
+#include "vm/object.h"
+#include "vm/os.h"
+#include "vm/timeline.h"
+
+namespace dart {
+
+// Native implementations for the dart:developer library.
+DEFINE_NATIVE_ENTRY(Timeline_getTraceClock, 0) {
+  return Integer::New(OS::GetCurrentTraceMicros(), Heap::kNew, true);
+}
+
+
+DEFINE_NATIVE_ENTRY(Timeline_reportCompleteEvent, 5) {
+  TimelineEventRecorder* recorder = Timeline::recorder();
+  if (recorder == NULL) {
+    return Object::null();
+  }
+
+  if (!isolate->GetDartStream()->Enabled()) {
+    // Dart stream is not enabled for this isolate, do nothing.
+    return Object::null();
+  }
+
+  GET_NON_NULL_NATIVE_ARGUMENT(Integer, start, arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(Integer, end, arguments->NativeArgAt(1));
+  GET_NON_NULL_NATIVE_ARGUMENT(String, category, arguments->NativeArgAt(2));
+  GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(3));
+  GET_NON_NULL_NATIVE_ARGUMENT(String, args, arguments->NativeArgAt(4));
+
+  int64_t duration = end.AsInt64Value() - start.AsInt64Value();
+  int64_t pid = OS::ProcessId();
+  int64_t tid = OSThread::ThreadIdToIntPtr(OSThread::GetCurrentThreadTraceId());
+
+  char* event = OS::SCreate(zone,
+      "{\"name\":\"%s\",\"cat\":\"%s\",\"tid\":%" Pd64 ",\"pid\":%" Pd64 ","
+      "\"ts\":%" Pd64 ",\"ph\":\"X\",\"dur\":%" Pd64 ",\"args\":%s}",
+      name.ToCString(),
+      category.ToCString(),
+      tid,
+      pid,
+      start.AsInt64Value(),
+      duration,
+      args.ToCString());
+
+  // event was allocated in the zone and will be copied by AppendDartEvent.
+  recorder->AppendDartEvent(isolate, event);
+
+  return Object::null();
+}
+
+}  // namespace dart
diff --git a/runtime/lib/timeline.dart b/runtime/lib/timeline.dart
new file mode 100644
index 0000000..38ffa5f
--- /dev/null
+++ b/runtime/lib/timeline.dart
@@ -0,0 +1,14 @@
+// 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:_internal';
+
+patch int _getTraceClock() native "Timeline_getTraceClock";
+
+patch void _reportCompleteEvent(
+    int start,
+    int end,
+    String category,
+    String name,
+    String argumentsAsJson) native "Timeline_reportCompleteEvent";
diff --git a/runtime/lib/vmservice.cc b/runtime/lib/vmservice.cc
new file mode 100644
index 0000000..29581b4
--- /dev/null
+++ b/runtime/lib/vmservice.cc
@@ -0,0 +1,149 @@
+// 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/bootstrap_natives.h"
+
+#include "vm/dart_api_impl.h"
+#include "vm/exceptions.h"
+#include "vm/message.h"
+#include "vm/native_entry.h"
+#include "vm/object.h"
+#include "vm/port.h"
+#include "vm/service_isolate.h"
+#include "vm/symbols.h"
+
+namespace dart {
+
+DECLARE_FLAG(bool, trace_service);
+
+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);
+}
+
+
+class RegisterRunningIsolatesVisitor : public IsolateVisitor {
+ public:
+  explicit RegisterRunningIsolatesVisitor(Isolate* service_isolate)
+      : IsolateVisitor(),
+        register_function_(Function::Handle(service_isolate)),
+        service_isolate_(service_isolate) {
+    ASSERT(ServiceIsolate::IsServiceIsolate(Isolate::Current()));
+    // Get library.
+    const String& library_url = Symbols::DartVMService();
+    ASSERT(!library_url.IsNull());
+    const Library& library =
+        Library::Handle(Library::LookupLibrary(library_url));
+    ASSERT(!library.IsNull());
+    // Get function.
+    const String& function_name =
+        String::Handle(String::New("_registerIsolate"));
+    ASSERT(!function_name.IsNull());
+    register_function_ = library.LookupFunctionAllowPrivate(function_name);
+    ASSERT(!register_function_.IsNull());
+  }
+
+  virtual void VisitIsolate(Isolate* isolate) {
+    ASSERT(ServiceIsolate::IsServiceIsolate(Isolate::Current()));
+    if (ServiceIsolate::IsServiceIsolateDescendant(isolate) ||
+        (isolate == Dart::vm_isolate())) {
+      // We do not register the service (and descendants) or the vm-isolate.
+      return;
+    }
+    // Setup arguments for call.
+    Dart_Port port_id = isolate->main_port();
+    const Integer& port_int = Integer::Handle(Integer::New(port_id));
+    ASSERT(!port_int.IsNull());
+    const SendPort& send_port = SendPort::Handle(SendPort::New(port_id));
+    const String& name = String::Handle(String::New(isolate->name()));
+    ASSERT(!name.IsNull());
+    const Array& args = Array::Handle(Array::New(3));
+    ASSERT(!args.IsNull());
+    args.SetAt(0, port_int);
+    args.SetAt(1, send_port);
+    args.SetAt(2, name);
+    Object& r = Object::Handle(service_isolate_);
+    r = DartEntry::InvokeFunction(register_function_, args);
+    if (FLAG_trace_service) {
+      OS::Print("vm-service: Isolate %s %" Pd64 " registered.\n",
+                name.ToCString(),
+                port_id);
+    }
+    ASSERT(!r.IsError());
+  }
+
+ private:
+  Function& register_function_;
+  Isolate* service_isolate_;
+};
+
+
+DEFINE_NATIVE_ENTRY(VMService_SendIsolateServiceMessage, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(SendPort, sp, arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(1));
+
+  // Set the type of the OOB message.
+  message.SetAt(0, Smi::Handle(thread->zone(),
+                               Smi::New(Message::kServiceOOBMsg)));
+
+  // Serialize message.
+  uint8_t* data = NULL;
+  MessageWriter writer(&data, &allocator, false);
+  writer.WriteMessage(message);
+
+  // TODO(turnidge): Throw an exception when the return value is false?
+  bool result = PortMap::PostMessage(
+      new Message(sp.Id(), data, writer.BytesWritten(),
+                  Message::kOOBPriority));
+  return Bool::Get(result).raw();
+}
+
+
+DEFINE_NATIVE_ENTRY(VMService_SendRootServiceMessage, 1) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0));
+  Service::HandleRootMessage(message);
+  return Object::null();
+}
+
+
+DEFINE_NATIVE_ENTRY(VMService_OnStart, 0) {
+  if (FLAG_trace_service) {
+    OS::Print("vm-service: Booting dart:vmservice library.\n");
+  }
+  // Boot the dart:vmservice library.
+  ServiceIsolate::BootVmServiceLibrary();
+
+  // Register running isolates with service.
+  RegisterRunningIsolatesVisitor register_isolates(isolate);
+  if (FLAG_trace_service) {
+    OS::Print("vm-service: Registering running isolates.\n");
+  }
+  Isolate::VisitIsolates(&register_isolates);
+
+  return Object::null();
+}
+
+
+DEFINE_NATIVE_ENTRY(VMService_OnExit, 0) {
+  if (FLAG_trace_service) {
+    OS::Print("vm-service: processed exit message.\n");
+  }
+  return Object::null();
+}
+
+
+DEFINE_NATIVE_ENTRY(VMService_ListenStream, 1) {
+  GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0));
+  bool result = Service::ListenStream(stream_id.ToCString());
+  return Bool::Get(result).raw();
+}
+
+
+DEFINE_NATIVE_ENTRY(VMService_CancelStream, 1) {
+  GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0));
+  Service::CancelStream(stream_id.ToCString());
+  return Object::null();
+}
+
+}  // namespace dart
diff --git a/runtime/vm/service/client.dart b/runtime/lib/vmservice/client.dart
similarity index 100%
rename from runtime/vm/service/client.dart
rename to runtime/lib/vmservice/client.dart
diff --git a/runtime/vm/service/constants.dart b/runtime/lib/vmservice/constants.dart
similarity index 100%
rename from runtime/vm/service/constants.dart
rename to runtime/lib/vmservice/constants.dart
diff --git a/runtime/vm/service/message.dart b/runtime/lib/vmservice/message.dart
similarity index 100%
rename from runtime/vm/service/message.dart
rename to runtime/lib/vmservice/message.dart
diff --git a/runtime/vm/service/message_router.dart b/runtime/lib/vmservice/message_router.dart
similarity index 100%
rename from runtime/vm/service/message_router.dart
rename to runtime/lib/vmservice/message_router.dart
diff --git a/runtime/vm/service/running_isolate.dart b/runtime/lib/vmservice/running_isolate.dart
similarity index 100%
rename from runtime/vm/service/running_isolate.dart
rename to runtime/lib/vmservice/running_isolate.dart
diff --git a/runtime/vm/service/running_isolates.dart b/runtime/lib/vmservice/running_isolates.dart
similarity index 100%
rename from runtime/vm/service/running_isolates.dart
rename to runtime/lib/vmservice/running_isolates.dart
diff --git a/runtime/vm/service/vmservice.dart b/runtime/lib/vmservice/vmservice.dart
similarity index 100%
rename from runtime/vm/service/vmservice.dart
rename to runtime/lib/vmservice/vmservice.dart
diff --git a/runtime/lib/vmservice_sources.gypi b/runtime/lib/vmservice_sources.gypi
new file mode 100644
index 0000000..9fb590a
--- /dev/null
+++ b/runtime/lib/vmservice_sources.gypi
@@ -0,0 +1,19 @@
+# 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.
+
+# Sources that make up the library "dart:_vmservice".
+
+{
+  'sources': [
+    'vmservice/vmservice.dart',
+    # The above file needs to be first as it imports required libraries.
+    'vmservice/client.dart',
+    'vmservice/constants.dart',
+    'vmservice/running_isolate.dart',
+    'vmservice/running_isolates.dart',
+    'vmservice/message.dart',
+    'vmservice/message_router.dart',
+    'vmservice.cc',
+  ],
+}
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index 8c1a2ed..4723358 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -1087,6 +1087,51 @@
       'Syntax: refresh <subcommand>\n';
 }
 
+class VmRestartCommand extends DebuggerCommand {
+  VmRestartCommand(Debugger debugger) : super(debugger, 'restart', []);
+
+  Future handleModalInput(String line) async {
+    if (line == 'yes') {
+      debugger.console.printRed('Restarting VM...');
+      await debugger.vm.restart();
+      debugger.input.exitMode();
+    } else if (line == 'no') {
+      debugger.console.printRed('VM restart canceled.');
+      debugger.input.exitMode();
+    } else {
+      debugger.console.printRed("Please type 'yes' or 'no'");
+    }
+  }
+
+  Future run(List<String> args) async {
+    debugger.input.enterMode('Restart vm? (yes/no)', handleModalInput);
+  }
+
+  String helpShort = 'Restart a Dart virtual machine';
+
+  String helpLong =
+      'Restart a Dart virtual machine.\n'
+      '\n'
+      'Syntax: vm restart\n';
+}
+
+class VmCommand extends DebuggerCommand {
+  VmCommand(Debugger debugger) : super(debugger, 'vm', [
+      new VmRestartCommand(debugger),
+  ]);
+
+  Future run(List<String> args) async {
+    debugger.console.print("'vm' expects a subcommand (see 'help vm')");
+  }
+
+  String helpShort = 'Manage a Dart virtual machine';
+
+  String helpLong =
+      'Manage a Dart virtual machine.\n'
+      '\n'
+      'Syntax: vm <subcommand>\n';
+}
+
 class _ConsoleStreamPrinter {
   ObservatoryDebugger _debugger;
 
@@ -1234,6 +1279,7 @@
         new StepCommand(this),
         new SyncNextCommand(this),
         new UpCommand(this),
+        new VmCommand(this),
     ]);
     _consolePrinter = new _ConsoleStreamPrinter(this);
   }
@@ -1254,23 +1300,24 @@
       }
 
       _isolate.reload().then((response) {
+        if (response.isSentinel) {
+          // The isolate has gone away.  The IsolateExit event will
+          // clear the isolate for the debugger page.
+          return;
+        }
         // TODO(turnidge): Currently the debugger relies on all libs
         // being loaded.  Fix this.
         var pending = [];
-        for (var lib in _isolate.libraries) {
+        for (var lib in response.libraries) {
           if (!lib.loaded) {
             pending.add(lib.load());
           }
         }
         Future.wait(pending).then((_) {
-          _refreshStack(isolate.pauseEvent).then((_) {
-            reportStatus();
-          });
-        }).catchError((_) {
-          // Error loading libraries, try and display stack.
-          _refreshStack(isolate.pauseEvent).then((_) {
-            reportStatus();
-          });
+          refreshStack();
+        }).catchError((e) {
+          print("UNEXPECTED ERROR $e");
+          reportStatus();
         });
       });
     } else {
@@ -1300,10 +1347,16 @@
     });
   }
 
-  Future refreshStack() {
-    return _refreshStack(isolate.pauseEvent).then((_) {
+  Future refreshStack() async {
+    try {
+      if (_isolate != null) {
+        await _refreshStack(_isolate.pauseEvent);
+      }
+      flushStdio();
       reportStatus();
-    });
+    } catch (e, st) {
+      console.printRed("Unexpected error in refreshStack: $e\n$st");
+    }
   }
 
   bool isolatePaused() {
@@ -1326,9 +1379,12 @@
 
   Future<ServiceMap> _refreshStack(ServiceEvent pauseEvent) {
     return isolate.getStack().then((result) {
+      if (result.isSentinel) {
+        // The isolate has gone away.  The IsolateExit event will
+        // clear the isolate for the debugger page.
+        return;
+      }
       stack = result;
-      // TODO(turnidge): Replace only the changed part of the stack to
-      // reduce flicker.
       stackElement.updateStack(stack, pauseEvent);
       if (stack['frames'].length > 0) {
         currentFrame = 0;
@@ -1364,8 +1420,7 @@
       console.print(
           "Paused at isolate exit "
           "(type 'continue' or [F7] to exit the isolate')");
-    }
-    if (stack['frames'].length > 0) {
+    } else if (stack['frames'].length > 0) {
       Frame frame = stack['frames'][0];
       var script = frame.location.script;
       script.load().then((_) {
@@ -1429,6 +1484,10 @@
           var iso = event.owner;
           console.print(
               "Isolate ${iso.number} '${iso.name}' has been created");
+          if (isolate == null) {
+            console.print("Switching to isolate ${iso.number} '${iso.name}'");
+            isolate = iso;
+          }
         }
         break;
 
@@ -1436,7 +1495,17 @@
         {
           var iso = event.owner;
           if (iso == isolate) {
-            console.print("The current isolate has exited");
+            console.print("The current isolate ${iso.number} '${iso.name}' "
+                          "has exited");
+            var isolates = vm.isolates;
+            if (isolates.length > 0) {
+              var newIsolate = isolates.first;
+              console.print("Switching to isolate "
+                            "${newIsolate.number} '${newIsolate.name}'");
+              isolate = newIsolate;
+            } else {
+              isolate = null;
+            }
           } else {
             console.print(
                 "Isolate ${iso.number} '${iso.name}' has exited");
@@ -1693,9 +1762,7 @@
   @published Isolate isolate;
 
   isolateChanged(oldValue) {
-    if (isolate != null) {
-      debugger.updateIsolate(isolate);
-    }
+    debugger.updateIsolate(isolate);
   }
   ObservatoryDebugger debugger = new ObservatoryDebugger();
 
@@ -2250,6 +2317,20 @@
   @published String text = '';
   @observable ObservatoryDebugger debugger;
   @observable bool busy = false;
+  @observable String modalPrompt = null;
+  var modalCallback = null;
+
+  void enterMode(String prompt, callback) {
+    assert(prompt == null);
+    modalPrompt = prompt;
+    modalCallback = callback;
+  }
+
+  void exitMode() {
+    assert(prompt != null);
+    modalPrompt = null;
+    modalCallback = null;
+  }
 
   @override
   void ready() {
@@ -2262,7 +2343,19 @@
           return;
         }
         busy = true;
-	switch (e.keyCode) {
+        if (modalCallback != null) {
+          if (e.keyCode == KeyCode.ENTER) {
+            var response = text;
+            modalCallback(response).whenComplete(() {
+              text = '';
+              busy = false;
+            });
+          } else {
+            busy = false;
+          }
+          return;
+        }
+        switch (e.keyCode) {
           case KeyCode.TAB:
             e.preventDefault();
             int cursorPos = textBox.selectionStart;
@@ -2358,7 +2451,7 @@
           default:
             busy = false;
             break;
-	}
+        }
       });
   }
 
diff --git a/runtime/observatory/lib/src/elements/debugger.html b/runtime/observatory/lib/src/elements/debugger.html
index 44195bf..5b74667 100644
--- a/runtime/observatory/lib/src/elements/debugger.html
+++ b/runtime/observatory/lib/src/elements/debugger.html
@@ -100,6 +100,7 @@
       }
       .console {
         flex: 1 1 auto;
+        overflow-x: auto;
         overflow-y: auto;
       }
       .commandline {
@@ -442,14 +443,34 @@
   <template>
     <link rel="stylesheet" href="css/shared.css">
     <style>
+      .container {
+        height: 100%;
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+      }
       .textBox {
+        flex: 1 1 auto;
         margin: 20px;
         padding: 5px;
         font: 400 16px consolas, courier, monospace;
         width: 95%;
       }
+      .modalPrompt {
+        flex: 0 0 auto;
+        margin-top: 20px;
+        margin-left: 20px;
+        padding: 5px;
+        font: 400 16px consolas, courier, monospace;
+        color: red;
+      }
     </style>
-    <input id="textBox" class="textBox" type="text" value="{{ text }}" autofocus>
+    <div class="container">
+      <template if="{{ modalPrompt != null }}">
+        <div class="modalPrompt">{{ modalPrompt }}</div>
+      </template>
+      <input id="textBox" class="textBox" type="text" value="{{ text }}" autofocus>
+    </div>
   </template>
 </polymer-element>
 
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index fac9fc5..e65f5b7 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -637,7 +637,7 @@
   @observable int architectureBits;
   @observable bool assertsEnabled = false;
   @observable bool typeChecksEnabled = false;
-  @observable String pid = '';
+  @observable int pid = 0;
   @observable DateTime startTime;
   @observable DateTime refreshTime;
   @observable Duration get upTime =>
@@ -803,6 +803,10 @@
     }
   }
 
+  Future restart() {
+    return invokeRpc('_restartVM', {});
+  }
+
   Future<ObservableMap> _fetchDirect() async {
     if (!loaded) {
       // The vm service relies on these events to keep the VM and
@@ -877,7 +881,7 @@
     version = map['version'];
     targetCPU = map['targetCPU'];
     architectureBits = map['architectureBits'];
-    var startTimeMillis = map['startTime'].toInt();
+    int startTimeMillis = map['startTime'];
     startTime = new DateTime.fromMillisecondsSinceEpoch(startTimeMillis);
     refreshTime = new DateTime.now();
     notifyPropertyChange(#upTime, 0, 1);
@@ -1270,9 +1274,6 @@
   @observable String vmName;
   @observable ServiceFunction entry;
 
-  @observable final Map<String, double> timers =
-      toObservable(new Map<String, double>());
-
   final HeapSpace newSpace = new HeapSpace();
   final HeapSpace oldSpace = new HeapSpace();
 
@@ -1348,7 +1349,7 @@
       entry = map['entry'];
     }
     var savedStartTime = startTime;
-    var startTimeInMillis = map['startTime'].toInt();
+    int startTimeInMillis = map['startTime'];
     startTime = new DateTime.fromMillisecondsSinceEpoch(startTimeInMillis);
     notifyPropertyChange(#upTime, 0, 1);
     var countersMap = map['_tagCounters'];
@@ -1373,18 +1374,6 @@
         }
       }
     }
-    var timerMap = {};
-    map['timers'].forEach((timer) {
-        timerMap[timer['name']] = timer['time'];
-      });
-    timers['total'] = timerMap['time_total_runtime'];
-    timers['compile'] = timerMap['time_compilation'];
-    timers['gc'] = 0.0;  // TODO(turnidge): Export this from VM.
-    timers['init'] = (timerMap['time_script_loading'] +
-                      timerMap['time_creating_snapshot'] +
-                      timerMap['time_isolate_initialization'] +
-                      timerMap['time_bootstrap']);
-    timers['dart'] = timerMap['time_dart_execution'];
 
     updateHeapsFromMap(map['_heaps']);
     _updateBreakpoints(map['breakpoints']);
@@ -1532,7 +1521,7 @@
     if (col != null) {
       params['column'] = col.toString();
     }
-    return invokeRpc('addBreakpoint', params);
+    return invokeRpc('addBreakpointWithScriptUri', params);
   }
 
   Future<ServiceObject> addBreakpointAtEntry(ServiceFunction function) {
@@ -1894,7 +1883,7 @@
     _upgradeCollection(map, owner);
     assert(map['isolate'] == null || owner == map['isolate']);
     timestamp =
-        new DateTime.fromMillisecondsSinceEpoch(map['timestamp'].toInt());
+        new DateTime.fromMillisecondsSinceEpoch(map['timestamp']);
     kind = map['kind'];
     notifyPropertyChange(#isPauseEvent, 0, 1);
     name = 'ServiceEvent $kind';
@@ -1949,7 +1938,7 @@
     if (map['logRecord'] != null) {
       logRecord = map['logRecord'];
       logRecord['time'] =
-          new DateTime.fromMillisecondsSinceEpoch(logRecord['time'].toInt());
+          new DateTime.fromMillisecondsSinceEpoch(logRecord['time']);
       logRecord['level'] = _findLogLevel(logRecord['level']);
     }
   }
diff --git a/runtime/observatory/tests/service/get_vm_rpc_test.dart b/runtime/observatory/tests/service/get_vm_rpc_test.dart
index 6aa8e33..d9884bd 100644
--- a/runtime/observatory/tests/service/get_vm_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_vm_rpc_test.dart
@@ -16,7 +16,7 @@
     expect(result['targetCPU'], new isInstanceOf<String>());
     expect(result['hostCPU'], new isInstanceOf<String>());
     expect(result['version'], new isInstanceOf<String>());
-    expect(result['pid'], new isInstanceOf<String>());
+    expect(result['pid'], new isInstanceOf<int>());
     expect(result['startTime'], isPositive);
     expect(result['isolates'].length, isPositive);
     expect(result['isolates'][0]['type'], equals('@Isolate'));
diff --git a/runtime/observatory/tests/service/vm_restart_test.dart b/runtime/observatory/tests/service/vm_restart_test.dart
new file mode 100644
index 0000000..de6397f
--- /dev/null
+++ b/runtime/observatory/tests/service/vm_restart_test.dart
@@ -0,0 +1,106 @@
+// 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=--compile-all --error_on_bad_type --error_on_bad_override
+
+import 'dart:async';
+import 'dart:developer';
+import 'dart:io';
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+
+int count = 0;
+
+void test() {
+  while (true) {
+    count++;
+    debugger();
+  }
+}
+
+var tests = [
+  hasStoppedAtBreakpoint,
+
+  (Isolate isolate) async {
+    // The loop has run one time.
+    var result = await isolate.rootLibrary.evaluate('count');
+    expect(result.type, equals('Instance'));
+    expect(result.valueAsString, equals('1'));
+
+    Completer completer = new Completer();
+    var stream = await isolate.vm.getEventStream(VM.kDebugStream);
+    var subscription;
+    subscription = stream.listen((ServiceEvent event) {
+      if (event.kind == ServiceEvent.kResume) {
+        subscription.cancel();
+        completer.complete();
+      }
+    });
+    isolate.resume();
+    await completer.future;
+
+    // The loop has run twice.
+    result = await isolate.rootLibrary.evaluate('count');
+    expect(result.type, equals('Instance'));
+    expect(result.valueAsString, equals('2'));
+  },
+
+  hasStoppedAtBreakpoint,
+
+  (Isolate isolate) async {
+    Isolate newIsolate = null;
+
+    Completer testCompleter = new Completer();
+    var debugStream = await isolate.vm.getEventStream(VM.kDebugStream);
+    var debugSub;
+    debugSub = debugStream.listen((ServiceEvent event) {
+      if (event.kind == ServiceEvent.kPauseBreakpoint) {
+        if (event.isolate == newIsolate) {
+          // The old isolate has died and the new isolate is at
+          // the breakpoint.
+          newIsolate.reload().then((_) {
+            newIsolate.rootLibrary.evaluate('count').then((result) {
+              expect(result.type, equals('Instance'));
+              expect(result.valueAsString, equals('1'));
+              debugSub.cancel();
+              testCompleter.complete();
+            });
+          });
+        }
+      }
+    });
+    
+    Completer restartCompleter = new Completer();
+    var isolateStream = await isolate.vm.getEventStream(VM.kIsolateStream);
+    var isolateSub;
+    bool exit = false;
+    bool start = false;
+    isolateSub = isolateStream.listen((ServiceEvent event) {
+      if (event.kind == ServiceEvent.kIsolateExit) {
+        expect(event.isolate, equals(isolate));
+        print('Old isolate exited');
+        exit = true;
+      }
+      if (event.kind == ServiceEvent.kIsolateStart) {
+        print('New isolate started');
+        newIsolate = event.isolate;
+        start = true;
+      }
+      if (exit && start) {
+        isolateSub.cancel();
+        restartCompleter.complete();
+      }
+    });
+
+    // Restart the vm.
+    print("restarting");
+    await isolate.vm.restart();
+    await restartCompleter.future;
+    print("restarted");
+    await testCompleter.future;
+  },
+];
+
+  
+main(args) => runIsolateTests(args, tests, testeeConcurrent: test);
diff --git a/runtime/tools/verbose_gc_to_bmu.dart b/runtime/tools/verbose_gc_to_bmu.dart
index ccf9306..67c1605 100644
--- a/runtime/tools/verbose_gc_to_bmu.dart
+++ b/runtime/tools/verbose_gc_to_bmu.dart
@@ -1,7 +1,9 @@
 // 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.
-
+//
+// NOTE: See also wrapper script sdk/runtime/tools/bmu_benchmark_gallery.sh
+//
 // Tool to compute bounded mutator utilization (BMU) from a --verbose_gc log.
 // Outputs CSV suitable for, e.g., gnuplot:
 //
diff --git a/runtime/vm/allocation.cc b/runtime/vm/allocation.cc
index b6fda7b..b5f0f6c 100644
--- a/runtime/vm/allocation.cc
+++ b/runtime/vm/allocation.cc
@@ -6,6 +6,7 @@
 
 #include "platform/assert.h"
 #include "vm/isolate.h"
+#include "vm/thread.h"
 #include "vm/zone.h"
 
 namespace dart {
@@ -30,6 +31,41 @@
 }
 
 
+StackResource::~StackResource() {
+  if (thread_ != NULL) {
+    StackResource* top = thread_->top_resource();
+    ASSERT(top == this);
+    thread_->set_top_resource(previous_);
+  }
+#if defined(DEBUG)
+  if (thread_ != NULL) {
+    ASSERT(Thread::Current() == thread_);
+    BaseIsolate::AssertCurrent(reinterpret_cast<BaseIsolate*>(isolate()));
+  }
+#endif
+}
+
+
+Isolate* StackResource::isolate() const {
+  return thread_ == NULL ? NULL : thread_->isolate();
+}
+
+
+void StackResource::Init(Thread* thread) {
+  // We can only have longjumps and exceptions when there is a current
+  // thread and isolate.  If there is no current thread, we don't need to
+  // protect this case.
+  // TODO(23807): Eliminate this special case.
+  if (thread != NULL) {
+    ASSERT(Thread::Current() == thread);
+    thread_ = thread;
+    previous_ = thread_->top_resource();
+    ASSERT((previous_ == NULL) || (previous_->thread_ == thread));
+    thread_->set_top_resource(this);
+  }
+}
+
+
 void StackResource::UnwindAbove(Thread* thread, StackResource* new_top) {
   StackResource* current_resource = thread->top_resource();
   while (current_resource != new_top) {
diff --git a/runtime/vm/allocation.h b/runtime/vm/allocation.h
index 74a2d7d..468c1ad 100644
--- a/runtime/vm/allocation.h
+++ b/runtime/vm/allocation.h
@@ -8,12 +8,12 @@
 #include "platform/assert.h"
 #include "vm/base_isolate.h"
 #include "vm/globals.h"
-#include "vm/thread.h"
 
 namespace dart {
 
 // Forward declarations.
 class Isolate;
+class Thread;
 
 // Stack allocated objects subclass from this base class. Objects of this type
 // cannot be allocated on either the C or object heaps. Destructors for objects
@@ -48,24 +48,10 @@
     Init(thread);
   }
 
-  virtual ~StackResource() {
-    if (thread_ != NULL) {
-      StackResource* top = thread_->top_resource();
-      ASSERT(top == this);
-      thread_->set_top_resource(previous_);
-    }
-#if defined(DEBUG)
-    if (thread_ != NULL) {
-      ASSERT(Thread::Current() == thread_);
-      BaseIsolate::AssertCurrent(reinterpret_cast<BaseIsolate*>(isolate()));
-    }
-#endif
-  }
+  virtual ~StackResource();
 
   // Convenient access to the isolate of the thread of this resource.
-  Isolate* isolate() const {
-    return thread_ == NULL ? NULL : thread_->isolate();
-  }
+  Isolate* isolate() const;
 
   // The thread that owns this resource.
   Thread* thread() const { return thread_; }
@@ -76,19 +62,7 @@
   static void UnwindAbove(Thread* thread, StackResource* new_top);
 
  private:
-  void Init(Thread* thread) {
-    // We can only have longjumps and exceptions when there is a current
-    // thread and isolate.  If there is no current thread, we don't need to
-    // protect this case.
-    // TODO(23807): Eliminate this special case.
-    if (thread != NULL) {
-      ASSERT(Thread::Current() == thread);
-      thread_ = thread;
-      previous_ = thread_->top_resource();
-      ASSERT((previous_ == NULL) || (previous_->thread_ == thread));
-      thread_->set_top_resource(this);
-    }
-  }
+  void Init(Thread* thread);
 
   Thread* thread_;
   StackResource* previous_;
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index 2da0383..7fe4193 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -96,8 +96,13 @@
 
 void Assembler::pushl(const Immediate& imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitUint8(0x68);
-  EmitImmediate(imm);
+  if (imm.is_int8()) {
+    EmitUint8(0x6A);
+    EmitUint8(imm.value() & 0xFF);
+  } else {
+    EmitUint8(0x68);
+    EmitImmediate(imm);
+  }
 }
 
 
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index c391612..075ac70 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -787,6 +787,10 @@
                                            Register array,
                                            Register index);
 
+  static Address VMTagAddress() {
+    return Address(THR, Thread::vm_tag_offset());
+  }
+
   /*
    * Misc. functionality
    */
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index 714e2d8..5316110 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -1593,6 +1593,10 @@
                                     Register array,
                                     Register index);
 
+  static Address VMTagAddress() {
+    return Address(THR, Thread::vm_tag_offset());
+  }
+
   // On some other platforms, we draw a distinction between safe and unsafe
   // smis.
   static bool IsSafe(const Object& object) { return true; }
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 87c1f31..0919521 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -122,7 +122,11 @@
 
 
 void Assembler::pushq(const Immediate& imm) {
-  if (imm.is_int32()) {
+  if (imm.is_int8()) {
+    AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+    EmitUint8(0x6A);
+    EmitUint8(imm.value() & 0xFF);
+  } else if (imm.is_int32()) {
     AssemblerBuffer::EnsureCapacity ensured(&buffer_);
     EmitUint8(0x68);
     EmitImmediate(imm);
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index 89b2944..0a6b694 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -1032,6 +1032,10 @@
                                            Register array,
                                            Register index);
 
+  static Address VMTagAddress() {
+    return Address(THR, Thread::vm_tag_offset());
+  }
+
   // On some other platforms, we draw a distinction between safe and unsafe
   // smis.
   static bool IsSafe(const Object& object) { return true; }
diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h
index fa4ba21..c3b6ac1 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -1226,7 +1226,6 @@
 };
 
 
-
 class LoadInstanceFieldNode : public AstNode {
  public:
   LoadInstanceFieldNode(intptr_t token_pos,
diff --git a/runtime/vm/ast_transformer.cc b/runtime/vm/ast_transformer.cc
index b4583cf..95d8d4f 100644
--- a/runtime/vm/ast_transformer.cc
+++ b/runtime/vm/ast_transformer.cc
@@ -567,12 +567,21 @@
                    node->TempAt(i),
                    new_init_val));
   }
-  // The transformed LetNode does not have any temporary variables.
-  LetNode* result = new(Z) LetNode(node->token_pos());
-  for (intptr_t i = 0; i < node->nodes().length(); i++) {
-    result->AddNode(Transform(node->nodes()[i]));
+
+  // Add all expressions but the last to the preamble. We must do
+  // this because subexpressions of the awaitable expression we
+  // are currently transforming may depend on each other,
+  // e.g. await foo(a++, a++). Thus we must preserve the order of the
+  // transformed subexpressions.
+  for (intptr_t i = 0; i < node->nodes().length() - 1; i++) {
+    preamble_->Add(Transform(node->nodes()[i]));
   }
-  result_ = result;
+
+  // The last expression in the let node is the value of the node.
+  // The result of the transformed let node is this expression.
+  ASSERT(node->nodes().length() > 0);
+  const intptr_t last_node_index = node->nodes().length() - 1;
+  result_ = Transform(node->nodes()[last_node_index]);
 }
 
 
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index 912aa1f..a01f107 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -75,6 +75,10 @@
                typed_data,
                Bootstrap::typed_data_source_paths_,
                Bootstrap::typed_data_patch_paths_),
+  INIT_LIBRARY(ObjectStore::kVMService,
+               _vmservice,
+               Bootstrap::vmservice_source_paths_,
+               NULL),
   { ObjectStore::kNone, NULL, NULL, NULL, NULL }
 };
 
diff --git a/runtime/vm/bootstrap.h b/runtime/vm/bootstrap.h
index 76758b6..ddb7d74 100644
--- a/runtime/vm/bootstrap.h
+++ b/runtime/vm/bootstrap.h
@@ -33,6 +33,7 @@
   static const char* profiler_source_paths_[];
   static const char* typed_data_source_paths_[];
   static const char* utf_source_paths_[];
+  static const char* vmservice_source_paths_[];
 
   // Source path mapping for patch URI and 'parts'.
   static const char* async_patch_paths_[];
diff --git a/runtime/vm/bootstrap_natives.cc b/runtime/vm/bootstrap_natives.cc
index 07c4928..d0bef86 100644
--- a/runtime/vm/bootstrap_natives.cc
+++ b/runtime/vm/bootstrap_natives.cc
@@ -10,6 +10,7 @@
 #include "vm/dart_api_impl.h"
 #include "vm/object.h"
 #include "vm/object_store.h"
+#include "vm/service_isolate.h"
 
 namespace dart {
 
@@ -129,6 +130,11 @@
   ASSERT(!library.IsNull());
   library.set_native_entry_resolver(resolver);
   library.set_native_entry_symbol_resolver(symbol_resolver);
+
+  library = Library::VMServiceLibrary();
+  ASSERT(!library.IsNull());
+  library.set_native_entry_resolver(resolver);
+  library.set_native_entry_symbol_resolver(symbol_resolver);
 }
 
 
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 38a92de..9e6e507 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -149,11 +149,14 @@
   V(DateNatives_timeZoneOffsetInSeconds, 1)                                    \
   V(DateNatives_localTimeZoneAdjustmentInSeconds, 0)                           \
   V(AssertionError_throwNew, 2)                                                \
+  V(Async_rethrow, 2)                                                          \
   V(TypeError_throwNew, 5)                                                     \
   V(FallThroughError_throwNew, 1)                                              \
   V(AbstractClassInstantiationError_throwNew, 2)                               \
   V(Stopwatch_now, 0)                                                          \
   V(Stopwatch_frequency, 0)                                                    \
+  V(Timeline_getTraceClock, 0)                                                 \
+  V(Timeline_reportCompleteEvent, 5)                                           \
   V(TypedData_Int8Array_new, 1)                                                \
   V(TypedData_Uint8Array_new, 1)                                               \
   V(TypedData_Uint8ClampedArray_new, 1)                                        \
@@ -302,7 +305,7 @@
   V(Int32x4_setFlagW, 2)                                                       \
   V(Int32x4_select, 3)                                                         \
   V(Isolate_spawnFunction, 7)                                                  \
-  V(Isolate_spawnUri, 10)                                                      \
+  V(Isolate_spawnUri, 12)                                                      \
   V(Isolate_getPortAndCapabilitiesOfCurrentIsolate, 0)                         \
   V(Isolate_sendOOB, 2)                                                        \
   V(Mirrors_evalInLibraryWithPrivateKey, 2)                                    \
@@ -391,7 +394,12 @@
   V(Profiler_getCurrentTag, 0)                                                 \
   V(ClassID_getID, 1)                                                          \
   V(Num_toString, 1)                                                           \
-
+  V(VMService_SendIsolateServiceMessage, 2)                                    \
+  V(VMService_SendRootServiceMessage, 1)                                       \
+  V(VMService_OnStart, 0)                                                      \
+  V(VMService_OnExit, 0)                                                       \
+  V(VMService_ListenStream, 1)                                                 \
+  V(VMService_CancelStream, 1)                                                 \
 
 class BootstrapNatives : public AllStatic {
  public:
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index e6d61bc..7638850 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -19,7 +19,6 @@
 DEFINE_FLAG(bool, print_classes, false, "Prints details about loaded classes.");
 DEFINE_FLAG(bool, trace_class_finalization, false, "Trace class finalization.");
 DEFINE_FLAG(bool, trace_type_finalization, false, "Trace type finalization.");
-DECLARE_FLAG(bool, supermixin);
 DECLARE_FLAG(bool, use_cha_deopt);
 
 
@@ -2032,25 +2031,6 @@
                 class_name.ToCString());
   }
 
-  if (!FLAG_supermixin) {
-    // Check that the super class of the mixin class is class Object.
-    Class& mixin_super_class = Class::Handle(mixin_class.SuperClass());
-    // Skip over mixin application alias classes, which are implemented as
-    // subclasses of the mixin application classes they name.
-    if (!mixin_super_class.IsNull() && mixin_class.is_mixin_app_alias()) {
-      while (mixin_super_class.is_mixin_app_alias()) {
-        mixin_super_class = mixin_super_class.SuperClass();
-      }
-      mixin_super_class = mixin_super_class.SuperClass();
-    }
-    if (mixin_super_class.IsNull() || !mixin_super_class.IsObjectClass()) {
-      const String& class_name = String::Handle(mixin_class.Name());
-      ReportError(mixin_app_class, mixin_app_class.token_pos(),
-                  "mixin class '%s' must extend class 'Object'",
-                  class_name.ToCString());
-    }
-  }
-
   // Copy type parameters to mixin application class.
   CloneMixinAppTypeParameters(mixin_app_class);
 
@@ -3156,21 +3136,23 @@
 
 void ClassFinalizer::VerifyImplicitFieldOffsets() {
 #ifdef DEBUG
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
+  Zone* zone = thread->zone();
   const ClassTable& class_table = *(isolate->class_table());
-  Class& cls = Class::Handle(isolate);
-  Array& fields_array = Array::Handle(isolate);
-  Field& field = Field::Handle(isolate);
-  String& name = String::Handle(isolate);
-  String& expected_name = String::Handle(isolate);
-  Error& error = Error::Handle(isolate);
+  Class& cls = Class::Handle(zone);
+  Array& fields_array = Array::Handle(zone);
+  Field& field = Field::Handle(zone);
+  String& name = String::Handle(zone);
+  String& expected_name = String::Handle(zone);
+  Error& error = Error::Handle(zone);
 
   // First verify field offsets of all the TypedDataView classes.
   for (intptr_t cid = kTypedDataInt8ArrayViewCid;
        cid <= kTypedDataFloat32x4ArrayViewCid;
        cid++) {
     cls = class_table.At(cid);  // Get the TypedDataView class.
-    error = cls.EnsureIsFinalized(isolate);
+    error = cls.EnsureIsFinalized(thread);
     ASSERT(error.IsNull());
     cls = cls.SuperClass();  // Get it's super class '_TypedListView'.
     cls = cls.SuperClass();
@@ -3193,7 +3175,7 @@
 
   // Now verify field offsets of '_ByteDataView' class.
   cls = class_table.At(kByteDataViewCid);
-  error = cls.EnsureIsFinalized(isolate);
+  error = cls.EnsureIsFinalized(thread);
   ASSERT(error.IsNull());
   fields_array ^= cls.fields();
   ASSERT(fields_array.Length() == TypedDataView::NumberOfFields());
@@ -3214,7 +3196,7 @@
 
   // Now verify field offsets of '_ByteBuffer' class.
   cls = class_table.At(kByteBufferCid);
-  error = cls.EnsureIsFinalized(isolate);
+  error = cls.EnsureIsFinalized(thread);
   ASSERT(error.IsNull());
   fields_array ^= cls.fields();
   ASSERT(fields_array.Length() == ByteBuffer::NumberOfFields());
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index f844cea..5179b4a 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -31,6 +31,8 @@
 DEFINE_FLAG(bool, deoptimize_alot, false,
     "Deoptimizes all live frames when we are about to return to Dart code from"
     " native entries.");
+DEFINE_FLAG(bool, background_compilation, false,
+    "Run optimizing compilation in background");
 DEFINE_FLAG(int, max_subtype_cache_entries, 100,
     "Maximum number of subtype cache entries (number of checks cached).");
 DEFINE_FLAG(int, optimization_counter_threshold, 30000,
@@ -1449,6 +1451,14 @@
     // Reset usage counter for reoptimization before calling optimizer to
     // prevent recursive triggering of function optimization.
     function.set_usage_counter(0);
+    if (FLAG_background_compilation) {
+      BackgroundCompiler::EnsureInit(isolate);
+      ASSERT(isolate->background_compiler() != NULL);
+      isolate->background_compiler()->CompileOptimized(function);
+      // Continue in the same code.
+      arguments.SetReturn(Code::Handle(isolate, function.CurrentCode()));
+      return;
+    }
     if (FLAG_trace_compiler) {
       if (function.HasOptimizedCode()) {
         THR_Print("ReCompiling function: '%s' \n",
@@ -1542,7 +1552,7 @@
   Code& alloc_stub = Code::Handle(isolate, alloc_class.allocation_stub());
   if (alloc_stub.IsNull()) {
     alloc_stub = StubCode::GetAllocationStubForClass(alloc_class);
-    ASSERT(!CodePatcher::IsEntryPatched(alloc_stub));
+    ASSERT(!alloc_stub.IsDisabled());
   }
   CodePatcher::PatchStaticCallAt(frame->pc(),
                                  caller_code,
diff --git a/runtime/vm/code_patcher.cc b/runtime/vm/code_patcher.cc
index c1fe9f7..c62be00 100644
--- a/runtime/vm/code_patcher.cc
+++ b/runtime/vm/code_patcher.cc
@@ -34,26 +34,4 @@
   }
 }
 
-
-// The patch code buffer contains the jmp code which will be inserted at
-// entry point.
-void CodePatcher::PatchEntry(const Code& code, const Code& new_code) {
-  ASSERT(code.instructions() == code.active_instructions());
-  code.set_active_instructions(new_code.instructions());
-}
-
-
-// The entry point is a jmp instruction, the patch code buffer contains
-// original code, the entry point contains the jump instruction.
-void CodePatcher::RestoreEntry(const Code& code) {
-  if (!IsEntryPatched(code)) return;
-  ASSERT(code.instructions() != code.active_instructions());
-  code.set_active_instructions(code.instructions());
-}
-
-
-bool CodePatcher::IsEntryPatched(const Code& code) {
-  return code.instructions() != code.active_instructions();
-}
-
 }  // namespace dart
diff --git a/runtime/vm/code_patcher.h b/runtime/vm/code_patcher.h
index 2f747f2..dc27168 100644
--- a/runtime/vm/code_patcher.h
+++ b/runtime/vm/code_patcher.h
@@ -49,15 +49,6 @@
                                 const Code& code,
                                 const Code& new_target);
 
-  // Patch entry point with a jump as specified in the code's patch region.
-  static void PatchEntry(const Code& code, const Code& new_code);
-
-  // Restore entry point with original code (i.e., before patching).
-  static void RestoreEntry(const Code& code);
-
-  // Has the entry been patched?
-  static bool IsEntryPatched(const Code& code);
-
   // Return the target address of the static call before return_address
   // in given code.
   static RawCode* GetStaticCallTargetAt(uword return_address, const Code& code);
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index fb57537..666a47b 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -68,7 +68,6 @@
 DECLARE_FLAG(bool, trace_failed_optimization_attempts);
 DECLARE_FLAG(bool, trace_inlining_intervals);
 DECLARE_FLAG(bool, trace_irregexp);
-DECLARE_FLAG(bool, trace_patching);
 
 
 bool Compiler::always_optimize_ = false;
@@ -758,17 +757,7 @@
         if (optimized) {
           // We may not have previous code if 'always_optimize' is set.
           if ((osr_id == Isolate::kNoDeoptId) && function.HasCode()) {
-            CodePatcher::PatchEntry(
-                Code::Handle(function.CurrentCode()),
-                Code::Handle(StubCode::FixCallersTarget_entry()->code()));
-            if (FLAG_trace_compiler || FLAG_trace_patching) {
-              if (FLAG_trace_compiler) {
-                THR_Print("  ");
-              }
-              THR_Print("Patch unoptimized '%s' entry point %#" Px "\n",
-                  function.ToFullyQualifiedCString(),
-                  Code::Handle(function.unoptimized_code()).EntryPoint());
-            }
+            Code::Handle(function.CurrentCode()).DisableDartCode();
           }
           function.AttachCode(code);
 
@@ -1021,7 +1010,6 @@
     Isolate* const isolate = thread->isolate();
     StackZone stack_zone(thread);
     Zone* const zone = stack_zone.GetZone();
-    TIMERSCOPE(thread, time_compilation);
     Timer per_compile_timer(FLAG_trace_compiler, "Compilation time");
     per_compile_timer.Start();
 
@@ -1414,4 +1402,164 @@
   return Object::null();
 }
 
+
+// A simple work queue containing functions to be optimized. Use
+// PushFront and PopBack to add and read from queue.
+// TODO(srdjan): Write a more efficient implementation.
+class CompilationWorkQueue : public ValueObject {
+ public:
+  explicit CompilationWorkQueue(Isolate* isolate) :
+      data_(GrowableObjectArray::Handle()) {
+    data_ = isolate->background_compilation_queue();
+  }
+
+  intptr_t IsEmpty() const { return data_.Length() == 0; }
+
+  // Adds to the queue only if 'function' is not already in there.
+  void PushFront(const Function& function) {
+    for (intptr_t i = 0; i < data_.Length(); i++) {
+      if (data_.At(i) == function.raw()) {
+        return;
+      }
+    }
+    // Insert new element in front.
+    Object& f = Object::Handle();
+    data_.Add(f);
+    for (intptr_t i = data_.Length() - 1; i > 0; i--) {
+      f = data_.At(i - 1);
+      data_.SetAt(i, f);
+    }
+    data_.SetAt(0, function);
+  }
+
+  RawFunction* PopBack() {
+    ASSERT(!IsEmpty());
+    Object& result = Object::Handle();
+    result = data_.At(data_.Length() - 1);
+    data_.SetLength(data_.Length() - 1);
+    return Function::Cast(result).raw();
+  }
+
+ private:
+  GrowableObjectArray& data_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationWorkQueue);
+};
+
+
+BackgroundCompiler::BackgroundCompiler(Isolate* isolate)
+    : isolate_(isolate), running_(true), done_(new bool()),
+      monitor_(new Monitor()), done_monitor_(new Monitor())  {
+  *done_ = false;
+}
+
+
+void BackgroundCompiler::Run() {
+  while (running_) {
+    {
+      // Wait to be notified when the work queue is not empty.
+      MonitorLocker ml(monitor_);
+      ml.Wait();
+    }
+
+    Thread::EnterIsolateAsHelper(isolate_);
+    {
+      Thread* thread = Thread::Current();
+      StackZone stack_zone(thread);
+      HANDLESCOPE(thread);
+      Function& function = Function::Handle();
+      function = RemoveOrNull();
+      while (!function.IsNull()) {
+        if (true) {
+          // Debugging printing
+          THR_Print("Background compilation: %s\n",
+              function.ToQualifiedCString());
+        } else {
+          const Error& error = Error::Handle(
+              Compiler::CompileOptimizedFunction(thread, function));
+          // TODO(srdjan): We do not expect errors while compiling optimized
+          // code, any errors should have been caught when compiling
+          // unotpimized code.
+          // If it still happens mark function as not optimizable.
+          ASSERT(error.IsNull());
+        }
+        function = RemoveOrNull();
+      }
+    }
+    Thread::ExitIsolateAsHelper();
+  }
+  {
+    // Notify that the thread is done.
+    MonitorLocker ml_done(done_monitor_);
+    *done_ = true;
+    ml_done.Notify();
+  }
+}
+
+
+void BackgroundCompiler::CompileOptimized(const Function& function) {
+  Add(function);
+}
+
+
+void BackgroundCompiler::Add(const Function& f) const {
+  MonitorLocker ml(monitor_);
+  CompilationWorkQueue queue(isolate_);
+  queue.PushFront(f);
+  ml.Notify();
+}
+
+
+RawFunction* BackgroundCompiler::RemoveOrNull() const {
+  MonitorLocker ml(monitor_);
+  CompilationWorkQueue queue(isolate_);
+  return queue.IsEmpty() ? Function::null() : queue.PopBack();
+}
+
+
+void BackgroundCompiler::Stop(BackgroundCompiler* task) {
+  if (task == NULL) {
+    return;
+  }
+  Monitor* monitor = task->monitor_;
+  Monitor* done_monitor = task->done_monitor_;
+  bool* task_done = task->done_;
+  // Wake up compiler task and stop it.
+  {
+    MonitorLocker ml(task->monitor_);
+    task->running_ = false;
+    // 'task' will be deleted by thread pool.
+    task = NULL;
+    ml.Notify();
+  }
+
+  {
+    MonitorLocker ml_done(done_monitor);
+    while (!(*task_done)) {
+      ml_done.Wait();
+    }
+  }
+  delete task_done;
+  delete done_monitor;
+  delete monitor;
+}
+
+
+void BackgroundCompiler::EnsureInit(Isolate* isolate) {
+  bool start_task = false;
+  {
+    MutexLocker ml(isolate->mutex());
+    if (isolate->background_compiler() == NULL) {
+      BackgroundCompiler* task = new BackgroundCompiler(isolate);
+      isolate->set_background_compiler(task);
+      isolate->set_background_compilation_queue(
+          GrowableObjectArray::Handle(isolate, GrowableObjectArray::New()));
+      start_task = true;
+    }
+  }
+  if (start_task) {
+    Dart::thread_pool()->Run(isolate->background_compiler());
+  }
+}
+
 }  // namespace dart
diff --git a/runtime/vm/compiler.h b/runtime/vm/compiler.h
index 9dc11b8..f31e00a 100644
--- a/runtime/vm/compiler.h
+++ b/runtime/vm/compiler.h
@@ -8,6 +8,7 @@
 #include "vm/allocation.h"
 #include "vm/growable_array.h"
 #include "vm/runtime_entry.h"
+#include "vm/thread_pool.h"
 
 namespace dart {
 
@@ -99,6 +100,35 @@
   static bool allow_recompilation_;
 };
 
+
+// Class to run optimizing compilation in a background thread.
+// Current implementation: one task per isolate, it dies with the owning
+// isolate.
+class BackgroundCompiler : public ThreadPool::Task {
+ public:
+  static void EnsureInit(Isolate* isolate);
+
+  static void Stop(BackgroundCompiler* task);
+
+  void CompileOptimized(const Function& function);
+
+ private:
+  explicit BackgroundCompiler(Isolate* isolate);
+
+  virtual void Run();
+
+  void Add(const Function& f) const;
+  RawFunction* RemoveOrNull() const;
+
+  Isolate* isolate_;
+  bool running_;
+  bool* done_;
+  Monitor* monitor_;
+  Monitor* done_monitor_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(BackgroundCompiler);
+};
+
 }  // namespace dart
 
 #endif  // VM_COMPILER_H_
diff --git a/runtime/vm/constant_propagator.cc b/runtime/vm/constant_propagator.cc
index 37e81b6..6ccc307 100644
--- a/runtime/vm/constant_propagator.cc
+++ b/runtime/vm/constant_propagator.cc
@@ -1020,7 +1020,7 @@
   if (IsConstant(value) && value.IsInteger()) {
     SetValue(instr, Double::Handle(I,
         Double::New(Integer::Cast(value).AsDoubleValue(), Heap::kOld)));
-  } else if (IsNonConstant(value)) {
+  } else if (!IsUnknown(value)) {
     SetValue(instr, non_constant_);
   }
 }
@@ -1031,7 +1031,7 @@
   if (IsConstant(value) && value.IsInteger()) {
     SetValue(instr, Double::Handle(I,
         Double::New(Integer::Cast(value).AsDoubleValue(), Heap::kOld)));
-  } else if (IsNonConstant(value)) {
+  } else if (!IsUnknown(value)) {
     SetValue(instr, non_constant_);
   }
 }
@@ -1042,7 +1042,7 @@
   if (IsConstant(value) && value.IsInteger()) {
     SetValue(instr, Double::Handle(I,
         Double::New(Integer::Cast(value).AsDoubleValue(), Heap::kOld)));
-  } else if (IsNonConstant(value)) {
+  } else if (!IsUnknown(value)) {
     SetValue(instr, non_constant_);
   }
 }
diff --git a/runtime/vm/coverage.cc b/runtime/vm/coverage.cc
index 82e7b54..65dc7e1 100644
--- a/runtime/vm/coverage.cc
+++ b/runtime/vm/coverage.cc
@@ -142,8 +142,7 @@
                               CoverageFilter* filter,
                               bool as_call_sites) {
   Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  if (cls.EnsureIsFinalized(isolate) != Error::null()) {
+  if (cls.EnsureIsFinalized(thread) != Error::null()) {
     // Only classes that have been finalized do have a meaningful list of
     // functions.
     return;
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index fcb7dbc..1d9105d 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -233,7 +233,7 @@
     Isolate::DisableIsolateCreation();
 
     // Send the OOB Kill message to all remaining application isolates.
-    Isolate::KillAllIsolates();
+    Isolate::KillAllIsolates(Isolate::kInternalKillMsg);
 
     // Shutdown the service isolate.
     ServiceIsolate::Shutdown();
@@ -281,7 +281,6 @@
   // Initialize the new isolate.
   Thread* T = Thread::Current();
   Isolate* I = T->isolate();
-  TIMERSCOPE(T, time_isolate_initialization);
   TimelineDurationScope tds(I, I->GetIsolateStream(), "InitializeIsolate");
   tds.SetNumArguments(1);
   tds.CopyArgument(0, "isolateName", I->name());
@@ -364,7 +363,7 @@
     I->class_table()->Print();
   }
 
-  ServiceIsolate::MaybeInjectVMServiceLibrary(I);
+  ServiceIsolate::MaybeMakeServiceIsolate(I);
 
   ServiceIsolate::SendIsolateStartupMessage();
   I->debugger()->NotifyIsolateCreated();
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index b55cdb0..473a665 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -747,6 +747,13 @@
 }
 
 
+DART_EXPORT bool Dart_IsVMRestartRequest(Dart_Handle handle) {
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
+  return (obj.IsUnwindError() && UnwindError::Cast(obj).is_vm_restart());
+}
+
+
 DART_EXPORT const char* Dart_GetError(Dart_Handle handle) {
   DARTSCOPE(Thread::Current());
   const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
@@ -1378,7 +1385,6 @@
   #endif  // defined(DART_NO_SNAPSHOT).
       // We exit the API scope entered above.
       Dart_ExitScope();
-      START_TIMER(I, time_total_runtime);
       return Api::CastIsolate(I);
     }
     *error = strdup(error_obj.ToErrorCString());
@@ -1399,7 +1405,6 @@
     HandleScope handle_scope(T);
     Dart::RunShutdownCallback();
   }
-  STOP_TIMER(I, time_total_runtime);
   Dart::ShutdownIsolate();
 }
 
@@ -1506,7 +1511,6 @@
     intptr_t* isolate_snapshot_size) {
   ASSERT(FLAG_load_deferred_eagerly);
   DARTSCOPE(Thread::Current());
-  TIMERSCOPE(T, time_creating_snapshot);
   if (vm_isolate_snapshot_buffer != NULL &&
       vm_isolate_snapshot_size == NULL) {
     RETURN_NULL_ERROR(vm_isolate_snapshot_size);
@@ -1547,7 +1551,6 @@
                                          uint8_t** buffer,
                                          intptr_t* size) {
   DARTSCOPE(Thread::Current());
-  TIMERSCOPE(T, time_creating_snapshot);
   if (buffer == NULL) {
     RETURN_NULL_ERROR(buffer);
   }
@@ -1678,7 +1681,7 @@
   Isolate* isolate = Isolate::Current();
   CHECK_ISOLATE_SCOPE(isolate);
   CHECK_CALLBACK_STATE(isolate);
-  if (!isolate->message_handler()->HandleNextMessage()) {
+  if (isolate->message_handler()->HandleNextMessage() != MessageHandler::kOK) {
     Dart_Handle error = Api::NewHandle(isolate,
                                        isolate->object_store()->sticky_error());
     isolate->object_store()->clear_sticky_error();
@@ -1694,8 +1697,10 @@
   CHECK_CALLBACK_STATE(isolate);
 
   ASSERT(isolate->GetAndClearResumeRequest() == false);
-  isolate->message_handler()->HandleOOBMessages();
-  return isolate->GetAndClearResumeRequest();
+  MessageHandler::MessageStatus status =
+      isolate->message_handler()->HandleOOBMessages();
+  bool resume = isolate->GetAndClearResumeRequest();
+  return (status != MessageHandler::kOK) || resume;
 }
 
 
@@ -3908,7 +3913,7 @@
     RETURN_TYPE_ERROR(I, type, Type);
   }
   const Class& cls = Class::Handle(Z, type_obj.type_class());
-  const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(I));
+  const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(T));
   if (!error.IsNull()) {
     // An error occurred, return error object.
     return Api::NewHandle(I, error.raw());
@@ -3933,7 +3938,7 @@
     RETURN_NULL_ERROR(native_fields);
   }
   const Class& cls = Class::Handle(Z, type_obj.type_class());
-  const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(I));
+  const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(T));
   if (!error.IsNull()) {
     // An error occurred, return error object.
     return Api::NewHandle(I, error.raw());
@@ -4058,9 +4063,6 @@
                                     Dart_Handle* arguments) {
   DARTSCOPE(Thread::Current());
   CHECK_CALLBACK_STATE(I);
-  // TODO(turnidge): This is a bit simplistic.  It overcounts when
-  // other operations (gc, compilation) are active.
-  TIMERSCOPE(T, time_dart_execution);
 
   const String& function_name = Api::UnwrapStringHandle(I, name);
   if (function_name.IsNull()) {
@@ -5059,7 +5061,6 @@
                                         intptr_t line_offset,
                                         intptr_t column_offset) {
   DARTSCOPE(Thread::Current());
-  TIMERSCOPE(T, time_script_loading);
   const String& url_str = Api::UnwrapStringHandle(I, url);
   if (url_str.IsNull()) {
     RETURN_TYPE_ERROR(I, url, String);
@@ -5083,6 +5084,7 @@
                          CURRENT_FUNC);
   }
   CHECK_CALLBACK_STATE(I);
+  CHECK_COMPILATION_ALLOWED(I);
 
   NoHeapGrowthControlScope no_growth_control;
 
@@ -5103,7 +5105,6 @@
 DART_EXPORT Dart_Handle Dart_LoadScriptFromSnapshot(const uint8_t* buffer,
                                                     intptr_t buffer_len) {
   DARTSCOPE(Thread::Current());
-  TIMERSCOPE(T, time_script_loading);
   StackZone zone(T);
   if (buffer == NULL) {
     RETURN_NULL_ERROR(buffer);
@@ -5127,6 +5128,7 @@
                          CURRENT_FUNC, library_url.ToCString());
   }
   CHECK_CALLBACK_STATE(I);
+  CHECK_COMPILATION_ALLOWED(I);
 
   ASSERT(snapshot->kind() == Snapshot::kScript);
   ScriptSnapshotReader reader(snapshot->content(), snapshot->length(), T);
@@ -5303,7 +5305,6 @@
                                          intptr_t line_offset,
                                          intptr_t column_offset) {
   DARTSCOPE(Thread::Current());
-  TIMERSCOPE(T, time_script_loading);
   const String& url_str = Api::UnwrapStringHandle(I, url);
   if (url_str.IsNull()) {
     RETURN_TYPE_ERROR(I, url, String);
@@ -5321,6 +5322,7 @@
                          CURRENT_FUNC);
   }
   CHECK_CALLBACK_STATE(I);
+  CHECK_COMPILATION_ALLOWED(I);
 
   NoHeapGrowthControlScope no_growth_control;
 
@@ -5378,6 +5380,7 @@
     RETURN_TYPE_ERROR(I, prefix, String);
   }
   CHECK_CALLBACK_STATE(I);
+  CHECK_COMPILATION_ALLOWED(I);
 
   const String& prefix_symbol = String::Handle(Z, Symbols::New(prefix_vm));
   const Namespace& import_ns = Namespace::Handle(Z,
@@ -5405,7 +5408,6 @@
                                         intptr_t line_offset,
                                         intptr_t column_offset) {
   DARTSCOPE(Thread::Current());
-  TIMERSCOPE(T, time_script_loading);
   const Library& lib = Api::UnwrapLibraryHandle(I, library);
   if (lib.IsNull()) {
     RETURN_TYPE_ERROR(I, library, Library);
@@ -5427,6 +5429,7 @@
                          CURRENT_FUNC);
   }
   CHECK_CALLBACK_STATE(I);
+  CHECK_COMPILATION_ALLOWED(I);
 
   NoHeapGrowthControlScope no_growth_control;
 
@@ -5443,7 +5446,6 @@
                                               Dart_Handle url,
                                               Dart_Handle patch_source) {
   DARTSCOPE(Thread::Current());
-  TIMERSCOPE(T, time_script_loading);
   const Library& lib = Api::UnwrapLibraryHandle(I, library);
   if (lib.IsNull()) {
     RETURN_TYPE_ERROR(I, library, Library);
@@ -5457,6 +5459,7 @@
     RETURN_TYPE_ERROR(I, patch_source, String);
   }
   CHECK_CALLBACK_STATE(I);
+  CHECK_COMPILATION_ALLOWED(I);
 
   NoHeapGrowthControlScope no_growth_control;
 
@@ -5680,6 +5683,8 @@
       (stream_mask & DART_TIMELINE_STREAM_API) != 0);
   isolate->GetCompilerStream()->set_enabled(
       (stream_mask & DART_TIMELINE_STREAM_COMPILER) != 0);
+  isolate->GetDartStream()->set_enabled(
+      (stream_mask & DART_TIMELINE_STREAM_DART) != 0);
   isolate->GetEmbedderStream()->set_enabled(
       (stream_mask & DART_TIMELINE_STREAM_EMBEDDER) != 0);
   isolate->GetGCStream()->set_enabled(
@@ -5694,6 +5699,8 @@
   const bool api_enabled = (stream_mask & DART_TIMELINE_STREAM_API) != 0;
   const bool compiler_enabled =
       (stream_mask & DART_TIMELINE_STREAM_COMPILER) != 0;
+  const bool dart_enabled =
+      (stream_mask & DART_TIMELINE_STREAM_DART) != 0;
   const bool embedder_enabled =
       (stream_mask & DART_TIMELINE_STREAM_EMBEDDER) != 0;
   const bool gc_enabled = (stream_mask & DART_TIMELINE_STREAM_GC) != 0;
@@ -5701,6 +5708,7 @@
       (stream_mask & DART_TIMELINE_STREAM_ISOLATE) != 0;
   Timeline::SetStreamAPIEnabled(api_enabled);
   Timeline::SetStreamCompilerEnabled(compiler_enabled);
+  Timeline::SetStreamDartEnabled(dart_enabled);
   Timeline::SetStreamEmbedderEnabled(embedder_enabled);
   Timeline::SetStreamGCEnabled(gc_enabled);
   Timeline::SetStreamIsolateEnabled(isolate_enabled);
@@ -5714,40 +5722,71 @@
 // '[' + ']' + '\0'.
 #define MINIMUM_OUTPUT_LENGTH 3
 
-static void StreamToConsumer(Dart_StreamConsumer consumer,
-                             void* user_data,
-                             char* output,
-                             intptr_t output_length) {
-  if (output == NULL) {
-    return;
-  }
-  if (output_length <= MINIMUM_OUTPUT_LENGTH) {
-    return;
-  }
+// Trims the '[' and ']' characters and, depending on whether or not more events
+// will follow, adjusts the last character of the string to either a '\0' or
+// ','.
+static char* TrimOutput(char* output,
+                        intptr_t* output_length,
+                        bool events_will_follow) {
+  ASSERT(output != NULL);
+  ASSERT(output_length != NULL);
+  ASSERT(*output_length > MINIMUM_OUTPUT_LENGTH);
   // We expect the first character to be the opening of an array.
   ASSERT(output[0] == '[');
   // We expect the last character to be the closing of an array.
-  ASSERT(output[output_length - 2] == ']');
+  ASSERT(output[*output_length - 2] == ']');
+  if (events_will_follow) {
+    // Replace array closing character (']') with ','.
+    output[*output_length - 2] = ',';
+  } else {
+    // Replace array closing character (']') with '\0'.
+    output[*output_length - 2] = '\0';
+  }
+  // Skip the array opening character ('[').
+  *output_length -= 2;
+  return &output[1];
+}
+
+
+static void StartStreamToConsumer(Dart_StreamConsumer consumer,
+                                  void* user_data,
+                                  const char* stream_name) {
   // Start stream.
-  const char* kStreamName = "timeline";
-  const intptr_t kDataSize = 64 * KB;
   consumer(Dart_StreamConsumer_kStart,
-           kStreamName,
+           stream_name,
            NULL,
            0,
            user_data);
+}
 
-  // Stream out data. Skipping the array characters.
-  // Replace array close with '\0'.
-  output[output_length - 2] = '\0';
-  intptr_t cursor = 1;
-  output_length -= 1;
-  intptr_t remaining = output_length - 1;
 
+static void FinishStreamToConsumer(Dart_StreamConsumer consumer,
+                                   void* user_data,
+                                   const char* stream_name) {
+  // Finish stream.
+  consumer(Dart_StreamConsumer_kFinish,
+           stream_name,
+           NULL,
+           0,
+           user_data);
+}
+
+
+static void DataStreamToConsumer(Dart_StreamConsumer consumer,
+                                 void* user_data,
+                                 const char* output,
+                                 intptr_t output_length,
+                                 const char* stream_name) {
+  if (output == NULL) {
+    return;
+  }
+  const intptr_t kDataSize = 64 * KB;
+  intptr_t cursor = 0;
+  intptr_t remaining = output_length;
   while (remaining >= kDataSize) {
     consumer(Dart_StreamConsumer_kData,
-             kStreamName,
-             reinterpret_cast<uint8_t*>(&output[cursor]),
+             stream_name,
+             reinterpret_cast<const uint8_t*>(&output[cursor]),
              kDataSize,
              user_data);
     cursor += kDataSize;
@@ -5756,8 +5795,8 @@
   if (remaining > 0) {
     ASSERT(remaining < kDataSize);
     consumer(Dart_StreamConsumer_kData,
-             kStreamName,
-             reinterpret_cast<uint8_t*>(&output[cursor]),
+             stream_name,
+             reinterpret_cast<const uint8_t*>(&output[cursor]),
              remaining,
              user_data);
     cursor += remaining;
@@ -5765,13 +5804,53 @@
   }
   ASSERT(cursor == output_length);
   ASSERT(remaining == 0);
+}
 
-  // Finish stream.
-  consumer(Dart_StreamConsumer_kFinish,
-           kStreamName,
-           NULL,
-           0,
-           user_data);
+
+static bool StreamTraceEvents(Dart_StreamConsumer consumer,
+                              void* user_data,
+                              JSONStream* js,
+                              const char* dart_events) {
+  ASSERT(js != NULL);
+  // Steal output from JSONStream.
+  char* output = NULL;
+  intptr_t output_length = 0;
+  js->Steal(const_cast<const char**>(&output), &output_length);
+
+  const bool output_vm = output_length > MINIMUM_OUTPUT_LENGTH;
+  const bool output_dart = dart_events != NULL;
+
+  if (!output_vm && !output_dart) {
+    // We stole the JSONStream's output buffer, free it.
+    free(output);
+    // Nothing will be emitted.
+    return false;
+  }
+
+  // Start the stream.
+  StartStreamToConsumer(consumer, user_data, "timeline");
+
+  // Send events from the VM.
+  if (output_vm) {
+    // Add one for the '\0' character.
+    output_length++;
+    char* trimmed_output = TrimOutput(output, &output_length, output_dart);
+    DataStreamToConsumer(consumer, user_data,
+                         trimmed_output, output_length, "timeline");
+  }
+  // We stole the JSONStream's output buffer, free it.
+  free(output);
+
+  // Send events from dart.
+  if (output_dart) {
+    const intptr_t dart_events_len = strlen(dart_events) + 1;  // +1 for '\0'.
+    DataStreamToConsumer(consumer, user_data,
+                         dart_events, dart_events_len, "timeline");
+  }
+
+  // Finish the stream.
+  FinishStreamToConsumer(consumer, user_data, "timeline");
+  return true;
 }
 
 
@@ -5787,25 +5866,18 @@
     // Nothing has been recorded.
     return false;
   }
+  Thread* T = Thread::Current();
+  StackZone zone(T);
   // Reclaim all blocks cached by isolate.
   Timeline::ReclaimIsolateBlocks();
   JSONStream js;
   IsolateTimelineEventFilter filter(isolate);
   timeline_recorder->PrintTraceEvent(&js, &filter);
-
-  // Copy output.
-  char* output = NULL;
-  intptr_t output_length = 0;
-  js.Steal(const_cast<const char**>(&output), &output_length);
-  if (output != NULL) {
-    // Add one for the '\0' character.
-    output_length++;
-    StreamToConsumer(consumer, user_data, output, output_length);
-    // We stole the JSONStream's output buffer, free it.
-    free(output);
-    return output_length > MINIMUM_OUTPUT_LENGTH;
-  }
-  return false;
+  const char* dart_events =
+      DartTimelineEventIterator::PrintTraceEvents(timeline_recorder,
+                                                  zone.GetZone(),
+                                                  isolate);
+  return StreamTraceEvents(consumer, user_data, &js, dart_events);
 }
 
 
@@ -5819,26 +5891,18 @@
     // Nothing has been recorded.
     return false;
   }
-
+  Thread* T = Thread::Current();
+  StackZone zone(T);
   // Reclaim all blocks cached in the system.
   Timeline::ReclaimAllBlocks();
   JSONStream js;
   TimelineEventFilter filter;
   timeline_recorder->PrintTraceEvent(&js, &filter);
-
-  // Copy output.
-  char* output = NULL;
-  intptr_t output_length = 0;
-  js.Steal(const_cast<const char**>(&output), &output_length);
-  if (output != NULL) {
-    // Add one for the '\0' character.
-    output_length++;
-    StreamToConsumer(consumer, user_data, output, output_length);
-    // We stole the JSONStream's output buffer, free it.
-    free(output);
-    return output_length > MINIMUM_OUTPUT_LENGTH;
-  }
-  return false;
+  const char* dart_events =
+      DartTimelineEventIterator::PrintTraceEvents(timeline_recorder,
+                                                  zone.GetZone(),
+                                                  NULL);
+  return StreamTraceEvents(consumer, user_data, &js, dart_events);
 }
 
 
@@ -5950,14 +6014,16 @@
 
 
 DART_EXPORT Dart_Handle Dart_Precompile(
-    Dart_QualifiedFunctionName entry_points[]) {
+    Dart_QualifiedFunctionName entry_points[],
+    bool reset_fields) {
   DARTSCOPE(Thread::Current());
   Dart_Handle result = Api::CheckAndFinalizePendingClasses(I);
   if (::Dart_IsError(result)) {
     return result;
   }
   CHECK_CALLBACK_STATE(I);
-  const Error& error = Error::Handle(Precompiler::CompileAll(entry_points));
+  const Error& error = Error::Handle(Precompiler::CompileAll(entry_points,
+                                                             reset_fields));
   if (!error.IsNull()) {
     return Api::NewHandle(I, error.raw());
   }
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 742f80c..2f635d3 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -316,6 +316,12 @@
     return reinterpret_cast<Dart_Handle>(Api::AcquiredError(isolate));         \
   }                                                                            \
 
+#define CHECK_COMPILATION_ALLOWED(isolate)                                     \
+  if (!isolate->compilation_allowed()) {                                       \
+    return Api::NewError("%s: Cannot load after Dart_Precompile",              \
+                         CURRENT_FUNC);                                        \
+  }                                                                            \
+
 #define ASSERT_CALLBACK_STATE(isolate)                                         \
   ASSERT(isolate->no_callback_scope_depth() == 0)
 
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 1d111e8..34c5cb5 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -9378,7 +9378,7 @@
 
 static void AppendStreamConsumer(Dart_StreamConsumer_State state,
                                  const char* stream_name,
-                                 uint8_t* buffer,
+                                 const uint8_t* buffer,
                                  intptr_t buffer_length,
                                  void* user_data) {
   if (state == Dart_StreamConsumer_kFinish) {
@@ -9446,6 +9446,99 @@
 }
 
 
+TEST_CASE(Timeline_Dart_TimelineGetTraceOnlyDartEvents) {
+  const char* kScriptChars =
+    "import 'dart:developer';\n"
+    ""
+    "main() {\n"
+    "  Timeline.startSync('DART_NAME');\n"
+    "  Timeline.finishSync();\n"
+    "}\n";
+
+  Dart_Handle lib =
+      TestCase::LoadTestScript(kScriptChars, NULL);
+
+  const char* buffer = NULL;
+  intptr_t buffer_length = 0;
+  bool success = false;
+
+  // Enable recording of the Dart stream.
+  Dart_TimelineSetRecordedStreams(DART_TIMELINE_STREAM_DART);
+
+  // Invoke main, which will add a new timeline event from Dart.
+  Dart_Handle result = Dart_Invoke(lib,
+                                   NewString("main"),
+                                   0,
+                                   NULL);
+  EXPECT_VALID(result);
+
+  // Grab the trace.
+  AppendData data;
+  data.buffer = NULL;
+  data.buffer_length = 0;
+  success = Dart_TimelineGetTrace(AppendStreamConsumer, &data);
+  EXPECT(success);
+  buffer = reinterpret_cast<char*>(data.buffer);
+  buffer_length = data.buffer_length;
+  EXPECT(buffer_length > 0);
+  EXPECT(buffer != NULL);
+
+  // Heartbeat test.
+  EXPECT_SUBSTRING("\"cat\":\"Dart\"", buffer);
+  EXPECT_SUBSTRING("\"name\":\"DART_NAME\"", buffer);
+
+  // Free buffer allocated by AppendStreamConsumer
+  free(data.buffer);
+}
+
+
+TEST_CASE(Timeline_Dart_TimelineGetTraceWithDartEvents) {
+  const char* kScriptChars =
+    "import 'dart:developer';\n"
+    "\n"
+    "main() {\n"
+    "  Timeline.startSync('DART_NAME');\n"
+    "  Timeline.finishSync();\n"
+    "}\n";
+
+  Dart_Handle lib =
+      TestCase::LoadTestScript(kScriptChars, NULL);
+
+  const char* buffer = NULL;
+  intptr_t buffer_length = 0;
+  bool success = false;
+
+  // Enable recording of all streams.
+  Dart_TimelineSetRecordedStreams(DART_TIMELINE_STREAM_ALL);
+
+  // 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);
+
+  // Grab the trace.
+  AppendData data;
+  success = Dart_TimelineGetTrace(AppendStreamConsumer, &data);
+  EXPECT(success);
+  buffer = reinterpret_cast<char*>(data.buffer);
+  buffer_length = data.buffer_length;
+  EXPECT(buffer_length > 0);
+  EXPECT(buffer != NULL);
+
+  // Heartbeat test.
+  EXPECT_SUBSTRING("\"cat\":\"Compiler\"", buffer);
+  EXPECT_SUBSTRING("\"name\":\"CompileFunction\"", buffer);
+  EXPECT_SUBSTRING("\"function\":\"::_main\"", buffer);
+  EXPECT_SUBSTRING("\"cat\":\"Dart\"", buffer);
+  EXPECT_SUBSTRING("\"name\":\"DART_NAME\"", buffer);
+
+  // Free buffer allocated by AppendStreamConsumer
+  free(data.buffer);
+}
+
 TEST_CASE(Timeline_Dart_TimelineGetTraceGlobalOverride) {
   const char* kScriptChars =
     "foo() => 'a';\n"
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 0b61458..5e4dfd9 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -310,9 +310,16 @@
 
   if (ServiceNeedsDebuggerEvent(event->type()) && event->IsPauseEvent()) {
     // If we were paused, notify the service that we have resumed.
-    ServiceEvent service_event(event->isolate(), ServiceEvent::kResume);
-    service_event.set_top_frame(event->top_frame());
-    Service::HandleEvent(&service_event);
+    const Error& error =
+        Error::Handle(isolate_, isolate_->object_store()->sticky_error());
+    ASSERT(error.IsNull() || error.IsUnwindError());
+
+    // Only send a resume event when the isolate is not unwinding.
+    if (!error.IsUnwindError()) {
+      ServiceEvent service_event(event->isolate(), ServiceEvent::kResume);
+      service_event.set_top_frame(event->top_frame());
+      Service::HandleEvent(&service_event);
+    }
   }
 }
 
@@ -350,9 +357,6 @@
         OS::Print("[!] Embedder api: terminating isolate:\n"
                   "\tisolate:    %s\n", isolate_->name());
       }
-      // TODO(turnidge): We should give the message handler a way to
-      // detect when an isolate is unwinding.
-      isolate_->message_handler()->set_pause_on_exit(false);
       const String& msg =
           String::Handle(String::New("isolate terminated by embedder"));
       return UnwindError::New(msg);
@@ -362,6 +366,7 @@
   // If any error occurred while in the debug message loop, return it here.
   const Error& error =
       Error::Handle(isolate_, isolate_->object_store()->sticky_error());
+  ASSERT(error.IsNull() || error.IsUnwindError());
   isolate_->object_store()->clear_sticky_error();
   return error.raw();
 }
@@ -1956,7 +1961,7 @@
         continue;
       }
       // Parse class definition if not done yet.
-      error = cls.EnsureIsFinalized(isolate_);
+      error = cls.EnsureIsFinalized(Thread::Current());
       if (!error.IsNull()) {
         // Ignore functions in this class.
         // TODO(hausner): Should we propagate this error? How?
@@ -2776,7 +2781,7 @@
   // Use the isolate's control port as the isolate_id for debugging.
   // This port will be used as a unique ID to represent the isolate in the
   // debugger wire protocol messages.
-  isolate_id_ = isolate->main_port();
+  isolate_id_ = isolate_->main_port();
   initialized_ = true;
 }
 
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 9f99503..8230ac7 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -132,7 +132,7 @@
 // exception handler. Once found, set the pc, sp and fp so that execution
 // can continue in that frame. Sets 'needs_stacktrace' if there is no
 // cath-all handler or if a stack-trace is specified in the catch.
-static bool FindExceptionHandler(Isolate* isolate,
+static bool FindExceptionHandler(Thread* thread,
                                  uword* handler_pc,
                                  uword* handler_sp,
                                  uword* handler_fp,
@@ -146,7 +146,7 @@
   uword temp_handler_pc = kUwordMax;
   while (!frame->IsEntryFrame()) {
     if (frame->IsDartFrame()) {
-      if (frame->FindExceptionHandler(isolate,
+      if (frame->FindExceptionHandler(thread,
                                       &temp_handler_pc,
                                       needs_stacktrace,
                                       &is_catch_all)) {
@@ -311,7 +311,7 @@
   if (use_preallocated_stacktrace) {
     stacktrace ^= isolate->object_store()->preallocated_stack_trace();
     PreallocatedStacktraceBuilder frame_builder(stacktrace);
-    handler_exists = FindExceptionHandler(isolate,
+    handler_exists = FindExceptionHandler(thread,
                                           &handler_pc,
                                           &handler_sp,
                                           &handler_fp,
@@ -327,7 +327,7 @@
 
     // Find the exception handler and determine if the handler needs a
     // stacktrace.
-    handler_exists = FindExceptionHandler(isolate,
+    handler_exists = FindExceptionHandler(thread,
                                           &handler_pc,
                                           &handler_sp,
                                           &handler_fp,
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 2884abf..ee6bdfd 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -46,6 +46,7 @@
     "Inlining interval diagnostics");
 DEFINE_FLAG(bool, use_megamorphic_stub, true, "Out of line megamorphic lookup");
 
+DECLARE_FLAG(bool, background_compilation);
 DECLARE_FLAG(bool, code_comments);
 DECLARE_FLAG(bool, deoptimize_alot);
 DECLARE_FLAG(int, deoptimize_every);
@@ -71,10 +72,17 @@
 DECLARE_FLAG(bool, warn_on_javascript_compatibility);
 DECLARE_FLAG(bool, precompile_collect_closures);
 DECLARE_FLAG(bool, print_stop_message);
+DECLARE_FLAG(bool, lazy_dispatchers);
+DECLARE_FLAG(bool, interpret_irregexp);
+DECLARE_FLAG(bool, enable_mirrors);
+DECLARE_FLAG(bool, link_natives_lazily);
 
-
-static void NooptModeHandler(bool value) {
+static void PrecompilationModeHandler(bool value) {
   if (value) {
+#if defined(TARGET_ARCH_IA32)
+    FATAL("Precompilation not supported on IA32");
+#endif
+
     FLAG_always_megamorphic_calls = true;
     FLAG_polymorphic_with_deopt = false;
     FLAG_optimization_counter_threshold = -1;
@@ -99,29 +107,7 @@
     // Calling the PrintStopMessage stub is not supported in precompiled code
     // since it is done at places where no pool pointer is loaded.
     FLAG_print_stop_message = false;
-  }
-}
 
-
-// --noopt disables optimizer and tunes unoptimized code to run as fast
-// as possible.
-DEFINE_FLAG_HANDLER(NooptModeHandler,
-                    noopt,
-                    "Run fast unoptimized code only.");
-
-
-DECLARE_FLAG(bool, lazy_dispatchers);
-DECLARE_FLAG(bool, interpret_irregexp);
-DECLARE_FLAG(bool, enable_mirrors);
-DECLARE_FLAG(bool, link_natives_lazily);
-
-static void PrecompileModeHandler(bool value) {
-  if (value) {
-#if defined(TARGET_ARCH_IA32)
-    FATAL("Precompilation not supported on IA32");
-#endif
-
-    NooptModeHandler(true);
     FLAG_lazy_dispatchers = false;
     FLAG_interpret_irregexp = true;
     FLAG_enable_mirrors = false;
@@ -129,12 +115,16 @@
     FLAG_link_natives_lazily = true;
     FLAG_fields_may_be_reset = true;
     FLAG_allow_absolute_addresses = false;
+
+    // Background compilation relies on two-stage compilation pipeline,
+    // while precompilation has only one.
+    FLAG_background_compilation = false;
   }
 }
 
 
-DEFINE_FLAG_HANDLER(PrecompileModeHandler,
-                    precompile,
+DEFINE_FLAG_HANDLER(PrecompilationModeHandler,
+                    precompilation,
                     "Precompilation mode");
 
 
@@ -1039,9 +1029,8 @@
 }
 
 
-// Returns 'true' if code generation for this function is complete, i.e.,
-// no fall-through to regular code is needed.
-void FlowGraphCompiler::TryIntrinsify() {
+// Returns 'true' if regular code generation should be skipped.
+bool FlowGraphCompiler::TryIntrinsify() {
   // Intrinsification skips arguments checks, therefore disable if in checked
   // mode.
   if (FLAG_intrinsify && !isolate()->flags().type_checks()) {
@@ -1058,8 +1047,9 @@
       // Reading from a mutable double box requires allocating a fresh double.
       if (load_node.field().guarded_cid() == kDynamicCid) {
         GenerateInlinedGetter(load_node.field().Offset());
+        return true;
       }
-      return;
+      return false;
     }
     if (parsed_function().function().kind() == RawFunction::kImplicitSetter) {
       // An implicit setter must have a specific AST structure.
@@ -1072,7 +1062,7 @@
           *sequence_node.NodeAt(0)->AsStoreInstanceFieldNode();
       if (store_node.field().guarded_cid() == kDynamicCid) {
         GenerateInlinedSetter(store_node.field().Offset());
-        return;
+        return true;
       }
     }
   }
@@ -1089,6 +1079,7 @@
   // before any deoptimization point.
   ASSERT(!intrinsic_slow_path_label_.IsBound());
   assembler()->Bind(&intrinsic_slow_path_label_);
+  return false;
 }
 
 
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index 3151009..1451776 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -328,7 +328,8 @@
   // Bail out of the flow graph compiler. Does not return to the caller.
   void Bailout(const char* reason);
 
-  void TryIntrinsify();
+  // Returns 'true' if regular code generation should be skipped.
+  bool TryIntrinsify();
 
   void GenerateRuntimeCall(intptr_t token_pos,
                            intptr_t deopt_id,
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index e8b2cde..9299a95 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -1020,7 +1020,10 @@
 void FlowGraphCompiler::CompileGraph() {
   InitCompiler();
 
-  TryIntrinsify();
+  if (TryIntrinsify()) {
+    // Skip regular code generation.
+    return;
+  }
 
   EmitFrameEntry();
   ASSERT(assembler()->constant_pool_allowed());
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index 76da180..86167ac 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -1022,7 +1022,10 @@
 void FlowGraphCompiler::CompileGraph() {
   InitCompiler();
 
-  TryIntrinsify();
+  if (TryIntrinsify()) {
+    // Skip regular code generation.
+    return;
+  }
 
   EmitFrameEntry();
   ASSERT(assembler()->constant_pool_allowed());
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 385a30c..2794ff5 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -751,6 +751,8 @@
     Location value = defn->locs()->out(0);
     if (value.IsRegister()) {
       __ pushl(value.reg());
+    } else if (value.IsConstant()) {
+      __ PushObject(value.constant());
     } else {
       ASSERT(value.IsStackSlot());
       __ pushl(value.ToStackSlotAddress());
@@ -1028,7 +1030,10 @@
 void FlowGraphCompiler::CompileGraph() {
   InitCompiler();
 
-  TryIntrinsify();
+  if (TryIntrinsify()) {
+    // Skip regular code generation.
+    return;
+  }
 
   EmitFrameEntry();
 
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 0cc605c..93ec487 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -1040,7 +1040,10 @@
 void FlowGraphCompiler::CompileGraph() {
   InitCompiler();
 
-  TryIntrinsify();
+  if (TryIntrinsify()) {
+    // Skip regular code generation.
+    return;
+  }
 
   EmitFrameEntry();
 
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 7d407f0..4247722 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -741,6 +741,8 @@
     Location value = defn->locs()->out(0);
     if (value.IsRegister()) {
       __ pushq(value.reg());
+    } else if (value.IsConstant()) {
+      __ PushObject(value.constant());
     } else {
       ASSERT(value.IsStackSlot());
       __ pushq(value.ToStackSlotAddress());
@@ -1028,7 +1030,10 @@
 void FlowGraphCompiler::CompileGraph() {
   InitCompiler();
 
-  TryIntrinsify();
+  if (TryIntrinsify()) {
+    // Skip regular code generation.
+    return;
+  }
 
   EmitFrameEntry();
   ASSERT(assembler()->constant_pool_allowed());
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 888017e..9de736b 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -2306,10 +2306,10 @@
 
 
 // Using field class
-static RawField* GetField(intptr_t class_id, const String& field_name) {
-  Isolate* isolate = Isolate::Current();
-  Class& cls = Class::Handle(isolate, isolate->class_table()->At(class_id));
-  Field& field = Field::Handle(isolate);
+RawField* FlowGraphOptimizer::GetField(intptr_t class_id,
+                                       const String& field_name) {
+  Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id));
+  Field& field = Field::Handle(Z);
   while (!cls.IsNull()) {
     field = cls.LookupInstanceField(field_name);
     if (!field.IsNull()) {
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index 0df970b..d0ae717 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -260,6 +260,8 @@
 
   void InstanceCallNoopt(InstanceCallInstr* instr);
 
+  RawField* GetField(intptr_t class_id, const String& field_name);
+
   Thread* thread() const { return flow_graph_->thread(); }
   Isolate* isolate() const { return flow_graph_->isolate(); }
   Zone* zone() const { return flow_graph_->zone(); }
diff --git a/runtime/vm/gc_marker.cc b/runtime/vm/gc_marker.cc
index 42ee7fe..2c53a07 100644
--- a/runtime/vm/gc_marker.cc
+++ b/runtime/vm/gc_marker.cc
@@ -595,7 +595,7 @@
       StackZone stack_zone(Thread::Current());
       Zone* zone = stack_zone.GetZone();
       SkippedCodeFunctions* skipped_code_functions =
-        collect_code_ ? new(zone) SkippedCodeFunctions() : NULL;
+          collect_code_ ? new(zone) SkippedCodeFunctions() : NULL;
       MarkingVisitor visitor(isolate_, heap_, page_space_, marking_stack_,
                              delay_set_, skipped_code_functions);
       // Phase 1: Populate and drain marking stack in task.
diff --git a/runtime/vm/gc_marker.h b/runtime/vm/gc_marker.h
index c01a6e8..e2f8293 100644
--- a/runtime/vm/gc_marker.h
+++ b/runtime/vm/gc_marker.h
@@ -6,6 +6,7 @@
 #define VM_GC_MARKER_H_
 
 #include "vm/allocation.h"
+#include "vm/os_thread.h"  // Mutex.
 
 namespace dart {
 
diff --git a/runtime/vm/heap.cc b/runtime/vm/heap.cc
index f599742..670c868 100644
--- a/runtime/vm/heap.cc
+++ b/runtime/vm/heap.cc
@@ -334,7 +334,6 @@
   switch (space) {
     case kNew: {
       RecordBeforeGC(kNew, reason);
-      TimerScope timer(true, &(isolate()->timer_list().time_gc()), thread);
       VMTagScope tagScope(thread, VMTag::kGCNewSpaceTagId);
       TimelineDurationScope tds(thread,
                                 isolate()->GetGCStream(),
@@ -354,7 +353,6 @@
     case kOld:
     case kCode: {
       RecordBeforeGC(kOld, reason);
-      TimerScope timer(true, &(isolate()->timer_list().time_gc()), thread);
       VMTagScope tagScope(thread, VMTag::kGCOldSpaceTagId);
       TimelineDurationScope tds(thread,
                                 isolate()->GetGCStream(),
@@ -395,7 +393,6 @@
   Thread* thread = Thread::Current();
   {
     RecordBeforeGC(kNew, kFull);
-    TimerScope timer(true, &(isolate()->timer_list().time_gc()), thread);
     VMTagScope tagScope(thread, VMTag::kGCNewSpaceTagId);
     TimelineDurationScope tds(thread,
                               isolate()->GetGCStream(),
@@ -409,7 +406,6 @@
   }
   {
     RecordBeforeGC(kOld, kFull);
-    TimerScope timer(true, &(isolate()->timer_list().time_gc()), thread);
     VMTagScope tagScope(thread, VMTag::kGCOldSpaceTagId);
     TimelineDurationScope tds(thread,
                               isolate()->GetGCStream(),
@@ -457,6 +453,16 @@
 }
 
 
+void Heap::UpdateGlobalMaxUsed() {
+  ASSERT(isolate_ != NULL);
+  // We are accessing the used in words count for both new and old space
+  // without synchronizing. The value of this metric is approximate.
+  isolate_->GetHeapGlobalUsedMaxMetric()->SetValue(
+      (UsedInWords(Heap::kNew) * kWordSize) +
+      (UsedInWords(Heap::kOld) * kWordSize));
+}
+
+
 void Heap::SetGrowthControlState(bool state) {
   old_space_.SetGrowthControlState(state);
 }
@@ -572,8 +578,8 @@
 
 
 void Heap::PrintSizes() const {
-  OS::PrintErr("New space (%" Pd "k of %" Pd "k) "
-               "Old space (%" Pd "k of %" Pd "k)\n",
+  OS::PrintErr("New space (%" Pd64 "k of %" Pd64 "k) "
+               "Old space (%" Pd64 "k of %" Pd64 "k)\n",
                (UsedInWords(kNew) / KBInWords),
                (CapacityInWords(kNew) / KBInWords),
                (UsedInWords(kOld) / KBInWords),
@@ -581,21 +587,23 @@
 }
 
 
-intptr_t Heap::UsedInWords(Space space) const {
+int64_t Heap::UsedInWords(Space space) const {
   return space == kNew ? new_space_.UsedInWords() : old_space_.UsedInWords();
 }
 
 
-intptr_t Heap::CapacityInWords(Space space) const {
+int64_t Heap::CapacityInWords(Space space) const {
   return space == kNew ? new_space_.CapacityInWords() :
                          old_space_.CapacityInWords();
 }
 
-intptr_t Heap::ExternalInWords(Space space) const {
+
+int64_t Heap::ExternalInWords(Space space) const {
   return space == kNew ? new_space_.ExternalInWords() :
                          old_space_.ExternalInWords();
 }
 
+
 int64_t Heap::GCTimeInMicros(Space space) const {
   if (space == kNew) {
     return new_space_.gc_time_micros();
@@ -779,4 +787,16 @@
     heap->SetGrowthControlState(current_growth_controller_state_);
 }
 
+
+WritableVMIsolateScope::WritableVMIsolateScope(Thread* thread)
+    : StackResource(thread) {
+  Dart::vm_isolate()->heap()->WriteProtect(false);
+}
+
+
+WritableVMIsolateScope::~WritableVMIsolateScope() {
+  ASSERT(Dart::vm_isolate()->heap()->UsedInWords(Heap::kNew) == 0);
+  Dart::vm_isolate()->heap()->WriteProtect(true);
+}
+
 }  // namespace dart
diff --git a/runtime/vm/heap.h b/runtime/vm/heap.h
index 8feb555..4639c26 100644
--- a/runtime/vm/heap.h
+++ b/runtime/vm/heap.h
@@ -133,7 +133,8 @@
   void SetGrowthControlState(bool state);
   bool GrowthControlState();
 
-  // Protect access to the heap.
+  // Protect access to the heap. Note: Code pages are made
+  // executable/non-executable when 'read_only' is true/false, respectively.
   void WriteProtect(bool read_only);
   void WriteProtectCode(bool read_only) {
     old_space_.WriteProtectCode(read_only);
@@ -157,9 +158,9 @@
   void PrintSizes() const;
 
   // Return amount of memory used and capacity in a space, excluding external.
-  intptr_t UsedInWords(Space space) const;
-  intptr_t CapacityInWords(Space space) const;
-  intptr_t ExternalInWords(Space space) const;
+  int64_t UsedInWords(Space space) const;
+  int64_t CapacityInWords(Space space) const;
+  int64_t ExternalInWords(Space space) const;
   // Return the amount of GCing in microseconds.
   int64_t GCTimeInMicros(Space space) const;
 
@@ -221,6 +222,8 @@
 
   bool gc_in_progress();
 
+  void UpdateGlobalMaxUsed();
+
   static bool IsAllocatableInNewSpace(intptr_t size) {
     return size <= kNewAllocatableSize;
   }
@@ -358,6 +361,14 @@
   DISALLOW_COPY_AND_ASSIGN(NoHeapGrowthControlScope);
 };
 
+
+// Note: During this scope, the code pages are non-executable.
+class WritableVMIsolateScope : StackResource {
+ public:
+  explicit WritableVMIsolateScope(Thread* thread);
+  ~WritableVMIsolateScope();
+};
+
 }  // namespace dart
 
 #endif  // VM_HEAP_H_
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index c691b85..1387730 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -237,8 +237,8 @@
 static void PrintUse(BufferFormatter* f, const Definition& definition) {
   if (definition.HasSSATemp()) {
     if (definition.HasPairRepresentation()) {
-      f->Print("v%" Pd ", v%" Pd "", definition.ssa_temp_index(),
-                                     definition.ssa_temp_index() + 1);
+      f->Print("(v%" Pd ", v%" Pd ")", definition.ssa_temp_index(),
+                                       definition.ssa_temp_index() + 1);
     } else {
       f->Print("v%" Pd "", definition.ssa_temp_index());
     }
diff --git a/runtime/vm/instructions_ia32.h b/runtime/vm/instructions_ia32.h
index 9cf5243..33d648f 100644
--- a/runtime/vm/instructions_ia32.h
+++ b/runtime/vm/instructions_ia32.h
@@ -62,44 +62,32 @@
 };
 
 
-template<class P>
-class CallOrJumpPattern : public InstructionPattern<P> {
+class CallPattern : public InstructionPattern<CallPattern> {
  public:
+  explicit CallPattern(uword pc) : InstructionPattern(pc) {}
   uword TargetAddress() const {
     ASSERT(this->IsValid());
     return this->start() +
-        P::pattern_length_in_bytes() +
+        CallPattern::pattern_length_in_bytes() +
         *reinterpret_cast<uword*>(this->start() + 1);
   }
 
   void SetTargetAddress(uword new_target) const {
     ASSERT(this->IsValid());
     *reinterpret_cast<uword*>(this->start() + 1) =
-        new_target - this->start() - P::pattern_length_in_bytes();
+        new_target - this->start() - CallPattern::pattern_length_in_bytes();
     CPU::FlushICache(this->start() + 1, kWordSize);
   }
 
- protected:
-  explicit CallOrJumpPattern(uword pc) : InstructionPattern<P>(pc) {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(CallOrJumpPattern);
-};
-
-
-class CallPattern : public CallOrJumpPattern<CallPattern> {
- public:
-  explicit CallPattern(uword pc) : CallOrJumpPattern(pc) {}
-
   static int pattern_length_in_bytes() { return kLengthInBytes; }
   static const int* pattern() {
     static const int kCallPattern[kLengthInBytes] = {0xE8, -1, -1, -1, -1};
     return kCallPattern;
   }
 
+
  private:
   static const int kLengthInBytes = 5;
-
   DISALLOW_COPY_AND_ASSIGN(CallPattern);
 };
 
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 62d8bef..e0bfb7f 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -151,15 +151,19 @@
   const intptr_t kNumInputs = 0;
   return LocationSummary::Make(zone,
                                kNumInputs,
-                               Location::RequiresRegister(),
+                               Assembler::IsSafe(value())
+                                   ? Location::Constant(this)
+                                   : Location::RequiresRegister(),
                                LocationSummary::kNoCall);
 }
 
 
 void ConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   // The register allocator drops constant definitions that have no uses.
-  if (!locs()->out(0).IsInvalid()) {
-    Register result = locs()->out(0).reg();
+  Location out = locs()->out(0);
+  ASSERT(out.IsRegister() || out.IsConstant() || out.IsInvalid());
+  if (out.IsRegister()) {
+    Register result = out.reg();
     __ LoadObjectSafely(result, value());
   }
 }
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index b58e4d1..ea5e685 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -238,15 +238,19 @@
   const intptr_t kNumInputs = 0;
   return LocationSummary::Make(zone,
                                kNumInputs,
-                               Location::RequiresRegister(),
+                               Assembler::IsSafe(value())
+                                   ? Location::Constant(this)
+                                   : Location::RequiresRegister(),
                                LocationSummary::kNoCall);
 }
 
 
 void ConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   // The register allocator drops constant definitions that have no uses.
-  if (!locs()->out(0).IsInvalid()) {
-    Register result = locs()->out(0).reg();
+  Location out = locs()->out(0);
+  ASSERT(out.IsRegister() || out.IsConstant() || out.IsInvalid());
+  if (out.IsRegister()) {
+    Register result = out.reg();
     __ LoadObject(result, value());
   }
 }
diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc
index 76e9b63..bc1e24b 100644
--- a/runtime/vm/intrinsifier.cc
+++ b/runtime/vm/intrinsifier.cc
@@ -36,12 +36,13 @@
 
 #if defined(DART_NO_SNAPSHOT)
 void Intrinsifier::InitializeState() {
-  Isolate* isolate = Isolate::Current();
-  Library& lib = Library::Handle(isolate);
-  Class& cls = Class::Handle(isolate);
-  Function& func = Function::Handle(isolate);
-  String& str = String::Handle(isolate);
-  Error& error = Error::Handle(isolate);
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  Library& lib = Library::Handle(zone);
+  Class& cls = Class::Handle(zone);
+  Function& func = Function::Handle(zone);
+  String& str = String::Handle(zone);
+  Error& error = Error::Handle(zone);
 
 #define SETUP_FUNCTION(class_name, function_name, destination, fp)             \
   if (strcmp(#class_name, "::") == 0) {                                        \
@@ -51,7 +52,7 @@
     str = String::New(#class_name);                                            \
     cls = lib.LookupClassAllowPrivate(str);                                    \
     ASSERT(!cls.IsNull());                                                     \
-    error = cls.EnsureIsFinalized(isolate);                                    \
+    error = cls.EnsureIsFinalized(thread);                                     \
     if (!error.IsNull()) {                                                     \
       OS::PrintErr("%s\n", error.ToErrorCString());                            \
     }                                                                          \
@@ -217,6 +218,8 @@
       return kDoubleCid;
     case kUnboxedFloat32x4:
       return kFloat32x4Cid;
+    case kUnboxedUint32:
+      return kDynamicCid;  // smi or mint.
     default:
       UNREACHABLE();
       return kIllegalCid;
@@ -448,6 +451,60 @@
 }
 
 
+bool Intrinsifier::Build_Uint32ArraySetIndexed(FlowGraph* flow_graph) {
+  GraphEntryInstr* graph_entry = flow_graph->graph_entry();
+  TargetEntryInstr* normal_entry = graph_entry->normal_entry();
+  BlockBuilder builder(flow_graph, normal_entry);
+
+  Definition* value = builder.AddParameter(1);
+  Definition* index = builder.AddParameter(2);
+  Definition* array = builder.AddParameter(3);
+
+  PrepareIndexedOp(&builder, array, index, TypedData::length_offset());
+
+  Definition* unboxed_value =
+      builder.AddUnboxInstr(kUnboxedUint32, new Value(value));
+
+  builder.AddInstruction(
+      new StoreIndexedInstr(new Value(array),
+                            new Value(index),
+                            new Value(unboxed_value),
+                            kNoStoreBarrier,
+                            4,  // index scale
+                            kTypedDataUint32ArrayCid,
+                            Isolate::kNoDeoptId,
+                            builder.TokenPos()));
+  // Return null.
+  Definition* null_def = builder.AddNullDefinition();
+  builder.AddIntrinsicReturn(new Value(null_def));
+  return true;
+}
+
+
+bool Intrinsifier::Build_Uint32ArrayGetIndexed(FlowGraph* flow_graph) {
+  GraphEntryInstr* graph_entry = flow_graph->graph_entry();
+  TargetEntryInstr* normal_entry = graph_entry->normal_entry();
+  BlockBuilder builder(flow_graph, normal_entry);
+
+  Definition* index = builder.AddParameter(1);
+  Definition* array = builder.AddParameter(2);
+
+  PrepareIndexedOp(&builder, array, index, TypedData::length_offset());
+
+  Definition* unboxed_value = builder.AddDefinition(
+      new LoadIndexedInstr(new Value(array),
+                           new Value(index),
+                           4,  // index scale
+                           kTypedDataUint32ArrayCid,
+                           Isolate::kNoDeoptId,
+                           builder.TokenPos()));
+  Definition* result = builder.AddDefinition(
+      BoxInstr::Create(kUnboxedUint32, new Value(unboxed_value)));
+  builder.AddIntrinsicReturn(new Value(result));
+  return true;
+}
+
+
 bool Intrinsifier::Build_Float64ArraySetIndexed(FlowGraph* flow_graph) {
   if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false;
 
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 7bc19b9..dd6d509 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -35,56 +35,14 @@
 intptr_t Intrinsifier::ParameterSlotFromSp() { return -1; }
 
 
-static intptr_t ComputeObjectArrayTypeArgumentsOffset() {
-  const Library& core_lib = Library::Handle(Library::CoreLibrary());
-  const Class& cls = Class::Handle(
-      core_lib.LookupClassAllowPrivate(Symbols::_List()));
-  ASSERT(!cls.IsNull());
-  ASSERT(cls.NumTypeArguments() == 1);
-  const intptr_t field_offset = cls.type_arguments_field_offset();
-  ASSERT(field_offset != Class::kNoTypeArguments);
-  return field_offset;
-}
-
-
 // Intrinsify only for Smi value and index. Non-smi values need a store buffer
 // update. Array length is always a Smi.
 void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) {
-  Label fall_through;
-
   if (Isolate::Current()->flags().type_checks()) {
-    const intptr_t type_args_field_offset =
-        ComputeObjectArrayTypeArgumentsOffset();
-    // Inline simple tests (Smi, null), fallthrough if not positive.
-    Label checked_ok;
-    __ ldr(R2, Address(SP, 0 * kWordSize));  // Value.
-
-    // Null value is valid for any type.
-    __ CompareObject(R2, Object::null_object());
-    __ b(&checked_ok, EQ);
-
-    __ ldr(R1, Address(SP, 2 * kWordSize));  // Array.
-    __ ldr(R1, FieldAddress(R1, type_args_field_offset));
-
-    // R1: Type arguments of array.
-    __ CompareObject(R1, Object::null_object());
-    __ b(&checked_ok, EQ);
-
-    // Check if it's dynamic.
-    // Get type at index 0.
-    __ ldr(R0, FieldAddress(R1, TypeArguments::type_at_offset(0)));
-    __ CompareObject(R0, Type::ZoneHandle(Type::DynamicType()));
-    __ b(&checked_ok, EQ);
-
-    // Check for int and num.
-    __ tst(R2, Operand(kSmiTagMask));  // Value is Smi?
-    __ b(&fall_through, NE);  // Non-smi value.
-    __ CompareObject(R0, Type::ZoneHandle(Type::IntType()));
-    __ b(&checked_ok, EQ);
-    __ CompareObject(R0, Type::ZoneHandle(Type::Number()));
-    __ b(&fall_through, NE);
-    __ Bind(&checked_ok);
+    return;
   }
+
+  Label fall_through;
   __ ldr(R1, Address(SP, 1 * kWordSize));  // Index.
   __ tst(R1, Operand(kSmiTagMask));
   // Index not Smi.
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index 3fd338a..4441fe2 100644
--- a/runtime/vm/intrinsifier_arm64.cc
+++ b/runtime/vm/intrinsifier_arm64.cc
@@ -33,56 +33,14 @@
 intptr_t Intrinsifier::ParameterSlotFromSp() { return -1; }
 
 
-static intptr_t ComputeObjectArrayTypeArgumentsOffset() {
-  const Library& core_lib = Library::Handle(Library::CoreLibrary());
-  const Class& cls = Class::Handle(
-      core_lib.LookupClassAllowPrivate(Symbols::_List()));
-  ASSERT(!cls.IsNull());
-  ASSERT(cls.NumTypeArguments() == 1);
-  const intptr_t field_offset = cls.type_arguments_field_offset();
-  ASSERT(field_offset != Class::kNoTypeArguments);
-  return field_offset;
-}
-
-
 // Intrinsify only for Smi value and index. Non-smi values need a store buffer
 // update. Array length is always a Smi.
 void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) {
-  Label fall_through;
-
   if (Isolate::Current()->flags().type_checks()) {
-    const intptr_t type_args_field_offset =
-        ComputeObjectArrayTypeArgumentsOffset();
-    // Inline simple tests (Smi, null), fallthrough if not positive.
-    Label checked_ok;
-    __ ldr(R2, Address(SP, 0 * kWordSize));  // Value.
-
-    // Null value is valid for any type.
-    __ CompareObject(R2, Object::null_object());
-    __ b(&checked_ok, EQ);
-
-    __ ldr(R1, Address(SP, 2 * kWordSize));  // Array.
-    __ ldr(R1, FieldAddress(R1, type_args_field_offset));
-
-    // R1: Type arguments of array.
-    __ CompareObject(R1, Object::null_object());
-    __ b(&checked_ok, EQ);
-
-    // Check if it's dynamic.
-    // Get type at index 0.
-    __ ldr(R0, FieldAddress(R1, TypeArguments::type_at_offset(0)));
-    __ CompareObject(R0, Type::ZoneHandle(Type::DynamicType()));
-    __ b(&checked_ok, EQ);
-
-    // Check for int and num.
-    __ tsti(R2, Immediate(Immediate(kSmiTagMask)));  // Value is Smi?
-    __ b(&fall_through, NE);  // Non-smi value.
-    __ CompareObject(R0, Type::ZoneHandle(Type::IntType()));
-    __ b(&checked_ok, EQ);
-    __ CompareObject(R0, Type::ZoneHandle(Type::Number()));
-    __ b(&fall_through, NE);
-    __ Bind(&checked_ok);
+    return;
   }
+
+  Label fall_through;
   __ ldr(R1, Address(SP, 1 * kWordSize));  // Index.
   __ tsti(R1, Immediate(kSmiTagMask));
   // Index not Smi.
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 85234a3..7349e85 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -33,53 +33,14 @@
 intptr_t Intrinsifier::ParameterSlotFromSp() { return -1; }
 
 
-static intptr_t ComputeObjectArrayTypeArgumentsOffset() {
-  const Library& core_lib = Library::Handle(Library::CoreLibrary());
-  const Class& cls = Class::Handle(
-      core_lib.LookupClassAllowPrivate(Symbols::_List()));
-  ASSERT(!cls.IsNull());
-  ASSERT(cls.NumTypeArguments() == 1);
-  const intptr_t field_offset = cls.type_arguments_field_offset();
-  ASSERT(field_offset != Class::kNoTypeArguments);
-  return field_offset;
-}
-
-
 // Intrinsify only for Smi value and index. Non-smi values need a store buffer
 // update. Array length is always a Smi.
 void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) {
-  Label fall_through;
-
   if (Isolate::Current()->flags().type_checks()) {
-    const intptr_t type_args_field_offset =
-        ComputeObjectArrayTypeArgumentsOffset();
-    // Inline simple tests (Smi, null), fallthrough if not positive.
-    Label checked_ok;
-    __ lw(T2, Address(SP, 0 * kWordSize));  // Value.
-
-    // Null value is valid for any type.
-    __ LoadObject(T7, Object::null_object());
-    __ beq(T2, T7, &checked_ok);
-
-    __ lw(T1, Address(SP, 2 * kWordSize));  // Array.
-    __ lw(T1, FieldAddress(T1, type_args_field_offset));
-
-    // T1: Type arguments of array.
-    __ beq(T1, T7, &checked_ok);
-
-    // Check if it's dynamic.
-    // Get type at index 0.
-    __ lw(T0, FieldAddress(T1, TypeArguments::type_at_offset(0)));
-    __ BranchEqual(T0, Type::ZoneHandle(Type::DynamicType()), &checked_ok);
-
-    // Check for int and num.
-    __ andi(CMPRES1, T2, Immediate(kSmiTagMask));
-    __ bne(CMPRES1, ZR, &fall_through);  // Non-smi value.
-
-    __ BranchEqual(T0, Type::ZoneHandle(Type::IntType()), &checked_ok);
-    __ BranchNotEqual(T0, Type::ZoneHandle(Type::Number()), &fall_through);
-    __ Bind(&checked_ok);
+    return;
   }
+
+  Label fall_through;
   __ lw(T1, Address(SP, 1 * kWordSize));  // Index.
   __ andi(CMPRES1, T1, Immediate(kSmiTagMask));
   // Index not Smi.
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index e489012..4598ddd 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -37,10 +37,11 @@
   if (Isolate::Current()->flags().type_checks()) {
     return;
   }
+
+  Label fall_through;
   __ movq(RDX, Address(RSP, + 1 * kWordSize));  // Value.
   __ movq(RCX, Address(RSP, + 2 * kWordSize));  // Index.
   __ movq(RAX, Address(RSP, + 3 * kWordSize));  // Array.
-  Label fall_through;
   __ testq(RCX, Immediate(kSmiTagMask));
   __ j(NOT_ZERO, &fall_through);
   // Range check.
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 9229d81..e542420 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -8,7 +8,9 @@
 #include "include/dart_native_api.h"
 #include "platform/assert.h"
 #include "platform/json.h"
+#include "vm/class_finalizer.h"
 #include "vm/code_observers.h"
+#include "vm/compiler.h"
 #include "vm/compiler_stats.h"
 #include "vm/coverage.h"
 #include "vm/dart_api_message.h"
@@ -24,7 +26,6 @@
 #include "vm/object_store.h"
 #include "vm/object.h"
 #include "vm/os_thread.h"
-#include "vm/parser.h"
 #include "vm/port.h"
 #include "vm/profiler.h"
 #include "vm/reusable_handles.h"
@@ -177,7 +178,7 @@
 
   const char* name() const;
   void MessageNotify(Message::Priority priority);
-  bool HandleMessage(Message* message);
+  MessageStatus HandleMessage(Message* message);
   void NotifyPauseOnStart();
   void NotifyPauseOnExit();
 
@@ -193,7 +194,7 @@
   // processing of further events.
   RawError* HandleLibMessage(const Array& message);
 
-  bool ProcessUnhandledException(const Error& result);
+  MessageStatus ProcessUnhandledException(const Error& result);
   Isolate* isolate_;
 };
 
@@ -284,7 +285,8 @@
       break;
     }
     case Isolate::kKillMsg:
-    case Isolate::kInternalKillMsg: {
+    case Isolate::kInternalKillMsg:
+    case Isolate::kVMRestartMsg: {
       // [ OOB, kKillMsg, terminate capability, priority ]
       if (message.Length() != 4) return Error::null();
       Object& obj = Object::Handle(I, message.At(3));
@@ -292,8 +294,8 @@
       const intptr_t priority = Smi::Cast(obj).Value();
       if (priority == Isolate::kImmediateAction) {
         obj = message.At(2);
-        // Signal that the isolate should stop execution.
         if (I->VerifyTerminateCapability(obj)) {
+          // We will kill the current isolate by returning an UnwindError.
           if (msg_type == Isolate::kKillMsg) {
             const String& msg = String::Handle(String::New(
                 "isolate terminated by Isolate.kill"));
@@ -301,14 +303,22 @@
                 UnwindError::Handle(UnwindError::New(msg));
             error.set_is_user_initiated(true);
             return error.raw();
-          } else {
-            // TODO(turnidge): We should give the message handler a way
-            // to detect when an isolate is unwinding.
-            I->message_handler()->set_pause_on_start(false);
-            I->message_handler()->set_pause_on_exit(false);
+          } else if (msg_type == Isolate::kInternalKillMsg) {
             const String& msg = String::Handle(String::New(
                 "isolate terminated by vm"));
             return UnwindError::New(msg);
+          } else if (msg_type == Isolate::kVMRestartMsg) {
+            // If this is the main isolate, this request to restart
+            // will be caught and handled in the embedder.  Otherwise
+            // this unwind error will cause the isolate to exit.
+            const String& msg = String::Handle(String::New(
+                "isolate terminated for vm restart"));
+            const UnwindError& error =
+                UnwindError::Handle(UnwindError::New(msg));
+            error.set_is_vm_restart(true);
+            return error.raw();
+          } else {
+            UNREACHABLE();
           }
         } else {
           return Error::null();
@@ -420,7 +430,8 @@
 }
 
 
-bool IsolateMessageHandler::HandleMessage(Message* message) {
+MessageHandler::MessageStatus IsolateMessageHandler::HandleMessage(
+    Message* message) {
   ASSERT(IsCurrentIsolate());
   Thread* thread = Thread::Current();
   StackZone stack_zone(thread);
@@ -430,10 +441,6 @@
   tds.SetNumArguments(1);
   tds.CopyArgument(0, "isolateName", I->name());
 
-  // TODO(turnidge): Rework collection total dart execution.  This can
-  // overcount when other things (gc, compilation) are active.
-  TIMERSCOPE(thread, time_dart_execution);
-
   // If the message is in band we lookup the handler to dispatch to.  If the
   // receive port was closed, we drop the message without deserializing it.
   // Illegal port is a special case for artificially enqueued isolate library
@@ -453,7 +460,7 @@
       } else {
         delete message;
       }
-      return true;
+      return kOK;
     }
   }
 
@@ -477,7 +484,7 @@
   Instance& msg = Instance::Handle(zone);
   msg ^= msg_obj.raw();  // Can't use Instance::Cast because may be null.
 
-  bool success = true;
+  MessageStatus status = kOK;
   if (message->IsOOB()) {
     // OOB messages are expected to be fixed length arrays where the first
     // element is a Smi describing the OOB destination. Messages that do not
@@ -495,7 +502,7 @@
             case Message::kIsolateLibOOBMsg: {
               const Error& error = Error::Handle(HandleLibMessage(oob_msg));
               if (!error.IsNull()) {
-                success = ProcessUnhandledException(error);
+                status = ProcessUnhandledException(error);
               }
               break;
             }
@@ -522,7 +529,7 @@
             (Smi::Cast(oob_tag).Value() == Message::kDelayedIsolateLibOOBMsg)) {
           const Error& error = Error::Handle(HandleLibMessage(msg_arr));
           if (!error.IsNull()) {
-            success = ProcessUnhandledException(error);
+            status = ProcessUnhandledException(error);
           }
         }
       }
@@ -531,22 +538,22 @@
     const Object& result = Object::Handle(zone,
         DartLibraryCalls::HandleMessage(msg_handler, msg));
     if (result.IsError()) {
-      success = ProcessUnhandledException(Error::Cast(result));
+      status = ProcessUnhandledException(Error::Cast(result));
     } else {
       ASSERT(result.IsNull());
     }
   }
   delete message;
-  if (success) {
+  if (status == kOK) {
     const Object& result =
         Object::Handle(zone, I->InvokePendingServiceExtensionCalls());
     if (result.IsError()) {
-      success = ProcessUnhandledException(Error::Cast(result));
+      status = ProcessUnhandledException(Error::Cast(result));
     } else {
       ASSERT(result.IsNull());
     }
   }
-  return success;
+  return status;
 }
 
 
@@ -590,7 +597,25 @@
 }
 
 
-bool IsolateMessageHandler::ProcessUnhandledException(const Error& result) {
+static MessageHandler::MessageStatus StoreError(Isolate* isolate,
+                                                const Error& error) {
+  isolate->object_store()->set_sticky_error(error);
+  if (error.IsUnwindError()) {
+    const UnwindError& unwind = UnwindError::Cast(error);
+    if (!unwind.is_user_initiated()) {
+      if (unwind.is_vm_restart()) {
+        return MessageHandler::kRestart;
+      } else {
+        return MessageHandler::kShutdown;
+      }
+    }
+  }
+  return MessageHandler::kError;
+}
+
+
+MessageHandler::MessageStatus IsolateMessageHandler::ProcessUnhandledException(
+    const Error& result) {
   // Notify the debugger about specific unhandled exceptions which are withheld
   // when being thrown.
   if (result.IsUnhandledException()) {
@@ -634,9 +659,9 @@
     exc_str = String::New(result.ToErrorCString());
   }
   if (result.IsUnwindError()) {
-    // Unwind errors are always fatal and don't notify listeners.
-    I->object_store()->set_sticky_error(result);
-    return false;
+    // When unwinding we don't notify error listeners and we ignore
+    // whether errors are fatal for the current isolate.
+    return StoreError(I, result);
   } else {
     bool has_listener = I->NotifyErrorListeners(exc_str, stacktrace_str);
     if (I->ErrorsFatal()) {
@@ -645,10 +670,10 @@
       } else {
         I->object_store()->set_sticky_error(result);
       }
-      return false;
+      return kError;
     }
   }
-  return true;
+  return kOK;
 }
 
 
@@ -704,9 +729,15 @@
   object##_handle_(NULL),
 
 Isolate::Isolate(const Dart_IsolateFlags& api_flags)
-  :   vm_tag_(0),
+  :   stack_limit_(0),
       store_buffer_(new StoreBuffer()),
       heap_(NULL),
+      vm_tag_(0),
+      user_tag_(0),
+      current_tag_(UserTag::null()),
+      default_tag_(UserTag::null()),
+      class_table_(),
+      single_step_(false),
       thread_registry_(new ThreadRegistry()),
       message_notify_callback_(NULL),
       name_(NULL),
@@ -724,17 +755,14 @@
       library_tag_handler_(NULL),
       api_state_(NULL),
       debugger_(NULL),
-      single_step_(false),
       resume_request_(false),
       last_resume_timestamp_(OS::GetCurrentTimeMillis()),
       has_compiled_(false),
       flags_(),
       random_(),
       simulator_(NULL),
-      timer_list_(),
       deopt_id_(0),
       mutex_(new Mutex()),
-      stack_limit_(0),
       saved_stack_limit_(0),
       stack_base_(0),
       stack_overflow_flags_(0),
@@ -746,6 +774,7 @@
       gc_epilogue_callback_(NULL),
       defer_finalization_count_(0),
       deopt_context_(NULL),
+      background_compiler_(NULL),
       compiler_stats_(NULL),
       is_service_isolate_(false),
       stacktrace_(NULL),
@@ -756,10 +785,9 @@
       trace_buffer_(NULL),
       profiler_data_(NULL),
       tag_table_(GrowableObjectArray::null()),
-      current_tag_(UserTag::null()),
-      default_tag_(UserTag::null()),
       collected_closures_(GrowableObjectArray::null()),
       deoptimized_code_array_(GrowableObjectArray::null()),
+      background_compilation_queue_(GrowableObjectArray::null()),
       pending_service_extension_calls_(GrowableObjectArray::null()),
       registered_service_extension_handlers_(GrowableObjectArray::null()),
       metrics_list_head_(NULL),
@@ -771,7 +799,7 @@
       REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT)
       reusable_handles_() {
   flags_.CopyFrom(api_flags);
-  set_vm_tag(VMTag::kEmbedderTagId);
+  Thread::Current()->set_vm_tag(VMTag::kEmbedderTagId);
   set_user_tag(UserTags::kDefaultUserTag);
 }
 
@@ -1308,13 +1336,7 @@
 }
 
 
-static void StoreError(Isolate* isolate, const Object& obj) {
-  ASSERT(obj.IsError());
-  isolate->object_store()->set_sticky_error(Error::Cast(obj));
-}
-
-
-static bool RunIsolate(uword parameter) {
+static MessageHandler::MessageStatus RunIsolate(uword parameter) {
   Isolate* isolate = reinterpret_cast<Isolate*>(parameter);
   IsolateSpawnState* state = NULL;
   Thread* thread = Thread::Current();
@@ -1348,15 +1370,19 @@
 
     if (!ClassFinalizer::ProcessPendingClasses()) {
       // Error is in sticky error already.
-      return false;
+#if defined(DEBUG)
+      const Error& error =
+          Error::Handle(isolate->object_store()->sticky_error());
+      ASSERT(!error.IsUnwindError());
+#endif
+      return MessageHandler::kError;
     }
 
     Object& result = Object::Handle();
     result = state->ResolveFunction();
     bool is_spawn_uri = state->is_spawn_uri();
     if (result.IsError()) {
-      StoreError(isolate, result);
-      return false;
+      return StoreError(isolate, Error::Cast(result));
     }
     ASSERT(result.IsFunction());
     Function& func = Function::Handle(isolate);
@@ -1411,11 +1437,10 @@
 
     result = DartEntry::InvokeFunction(entry_point, args);
     if (result.IsError()) {
-      StoreError(isolate, result);
-      return false;
+      return StoreError(isolate, Error::Cast(result));
     }
   }
-  return true;
+  return MessageHandler::kOK;
 }
 
 
@@ -1474,8 +1499,9 @@
     }
   }
   if ((interrupt_bits & kMessageInterrupt) != 0) {
-    bool ok = message_handler()->HandleOOBMessages();
-    if (!ok) {
+    MessageHandler::MessageStatus status =
+        message_handler()->HandleOOBMessages();
+    if (status != MessageHandler::kOK) {
       // False result from HandleOOBMessages signals that the isolate should
       // be terminating.
       if (FLAG_trace_isolates) {
@@ -1483,8 +1509,8 @@
                   "\tisolate:    %s\n", name());
       }
       const Error& error = Error::Handle(object_store()->sticky_error());
+      ASSERT(!error.IsNull() && error.IsUnwindError());
       object_store()->clear_sticky_error();
-      ASSERT(!error.IsNull());
       return error.raw();
     }
   }
@@ -1596,9 +1622,6 @@
   delete message_handler();
   set_message_handler(NULL);
 
-  // Dump all accumulated timer data for the isolate.
-  timer_list_.ReportTimers();
-
   // Before analyzing the isolate's timeline blocks- reclaim all cached blocks.
   ReclaimTimelineBlocks();
 
@@ -1691,6 +1714,8 @@
   }
 #endif
 
+  BackgroundCompiler::Stop(background_compiler_);
+
   // TODO(5411455): For now just make sure there are no current isolates
   // as we are shutting down the isolate.
   Thread::ExitIsolate();
@@ -1766,6 +1791,9 @@
   // Visit array of closures pending precompilation.
   visitor->VisitPointer(reinterpret_cast<RawObject**>(&collected_closures_));
 
+  visitor->VisitPointer(reinterpret_cast<RawObject**>(
+      &background_compilation_queue_));
+
   // Visit the deoptimized code array which is stored in the isolate.
   visitor->VisitPointer(
       reinterpret_cast<RawObject**>(&deoptimized_code_array_));
@@ -1820,15 +1848,6 @@
   }
   int64_t start_time_millis = start_time() / kMicrosecondsPerMillisecond;
   jsobj.AddPropertyTimeMillis("startTime", start_time_millis);
-  IsolateSpawnState* state = spawn_state();
-  if (state != NULL) {
-    const Object& entry = Object::Handle(this, state->ResolveFunction());
-    if (!entry.IsNull() && entry.IsFunction()) {
-      Function& func = Function::Handle(this);
-      func ^= entry.raw();
-      jsobj.AddProperty("entry", func);
-    }
-  }
   {
     JSONObject jsheap(&jsobj, "_heaps");
     heap()->PrintToJSONObject(Heap::kNew, &jsheap);
@@ -1866,7 +1885,6 @@
     jsobj.AddProperty("rootLib", lib);
   }
 
-  timer_list().PrintTimersToJSONProperty(&jsobj);
   {
     JSONObject tagCounters(&jsobj, "_tagCounters");
     vm_tag_counters()->PrintToJSONObject(&tagCounters);
@@ -1953,7 +1971,8 @@
 
 
 void Isolate::ProfileIdle() {
-  vm_tag_counters_.Increment(vm_tag());
+  // Currently we are only sampling the mutator thread.
+  vm_tag_counters_.Increment(VMTag::kIdleTagId);
 }
 
 
@@ -1985,6 +2004,12 @@
 }
 
 
+void Isolate::set_background_compilation_queue(
+    const GrowableObjectArray& value) {
+  background_compilation_queue_ = value.raw();
+}
+
+
 void Isolate::TrackDeoptimizedCode(const Code& code) {
   ASSERT(!code.IsNull());
   const GrowableObjectArray& deoptimized_code =
@@ -2294,7 +2319,7 @@
 }
 
 
-void Isolate::KillLocked() {
+void Isolate::KillLocked(LibMsgId msg_id) {
   Dart_CObject kill_msg;
   Dart_CObject* list_values[4];
   kill_msg.type = Dart_CObject_kArray;
@@ -2308,7 +2333,7 @@
 
   Dart_CObject msg_type;
   msg_type.type = Dart_CObject_kInt32;
-  msg_type.value.as_int32 = Isolate::kInternalKillMsg;
+  msg_type.value.as_int32 = msg_id;
   list_values[1] = &msg_type;
 
   Dart_CObject cap;
@@ -2339,10 +2364,11 @@
 
 class IsolateKillerVisitor : public IsolateVisitor {
  public:
-  IsolateKillerVisitor() : target_(NULL) {}
+  explicit IsolateKillerVisitor(Isolate::LibMsgId msg_id)
+      : target_(NULL), msg_id_(msg_id) {}
 
-  explicit IsolateKillerVisitor(Isolate* isolate)
-      : target_(isolate) {
+  IsolateKillerVisitor(Isolate* isolate, Isolate::LibMsgId msg_id)
+      : target_(isolate), msg_id_(msg_id) {
     ASSERT(isolate != Dart::vm_isolate());
   }
 
@@ -2351,7 +2377,7 @@
   void VisitIsolate(Isolate* isolate) {
     ASSERT(isolate != NULL);
     if (ShouldKill(isolate)) {
-      isolate->KillLocked();
+      isolate->KillLocked(msg_id_);
     }
   }
 
@@ -2366,17 +2392,18 @@
   }
 
   Isolate* target_;
+  Isolate::LibMsgId msg_id_;
 };
 
 
-void Isolate::KillAllIsolates() {
-  IsolateKillerVisitor visitor;
+void Isolate::KillAllIsolates(LibMsgId msg_id) {
+  IsolateKillerVisitor visitor(msg_id);
   VisitIsolates(&visitor);
 }
 
 
-void Isolate::KillIfExists(Isolate* isolate) {
-  IsolateKillerVisitor visitor(isolate);
+void Isolate::KillIfExists(Isolate* isolate, LibMsgId msg_id) {
+  IsolateKillerVisitor visitor(isolate, msg_id);
   VisitIsolates(&visitor);
 }
 
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 265960c..00406ed 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -27,6 +27,7 @@
 class AbstractType;
 class ApiState;
 class Array;
+class BackgroundCompiler;
 class Capability;
 class CHA;
 class Class;
@@ -129,6 +130,7 @@
     // Internal message ids.
     kInterruptMsg = 10,     // Break in the debugger.
     kInternalKillMsg = 11,  // Like kill, but does not run exit listeners, etc.
+    kVMRestartMsg = 12,     // Sent to isolates when vm is restarting.
   };
   // The different Isolate API message priorities for ping and kill messages.
   enum LibMsgPriority {
@@ -217,9 +219,6 @@
 
   ObjectStore* object_store() const { return object_store_; }
   void set_object_store(ObjectStore* value) { object_store_ = value; }
-  static intptr_t object_store_offset() {
-    return OFFSET_OF(Isolate, object_store_);
-  }
 
   // DEPRECATED: Use Thread's methods instead. During migration, these default
   // to using the mutator thread (which must also be the current thread).
@@ -241,21 +240,9 @@
     mutator_thread_->set_top_exit_frame_info(value);
   }
 
-  uword vm_tag() const {
-    return vm_tag_;
-  }
-  void set_vm_tag(uword tag) {
-    vm_tag_ = tag;
-  }
-  static intptr_t vm_tag_offset() {
-    return OFFSET_OF(Isolate, vm_tag_);
-  }
-
   ApiState* api_state() const { return api_state_; }
   void set_api_state(ApiState* value) { api_state_ = value; }
 
-  TimerList& timer_list() { return timer_list_; }
-
   void set_init_callback_data(void* value) {
     init_callback_data_ = value;
   }
@@ -605,6 +592,13 @@
     deopt_context_ = value;
   }
 
+  BackgroundCompiler* background_compiler() const {
+    return background_compiler_;
+  }
+  void set_background_compiler(BackgroundCompiler* value) {
+    background_compiler_ = value;
+  }
+
   void UpdateLastAllocationProfileAccumulatorResetTimestamp() {
     last_allocationprofile_accumulator_reset_timestamp_ =
         OS::GetCurrentTimeMillis();
@@ -701,6 +695,11 @@
   }
   void set_collected_closures(const GrowableObjectArray& value);
 
+  RawGrowableObjectArray* background_compilation_queue() const {
+    return background_compilation_queue_;
+  }
+  void set_background_compilation_queue(const GrowableObjectArray& value);
+
   Metric* metrics_list_head() {
     return metrics_list_head_;
   }
@@ -768,8 +767,8 @@
 
   bool is_service_isolate() const { return is_service_isolate_; }
 
-  static void KillAllIsolates();
-  static void KillIfExists(Isolate* isolate);
+  static void KillAllIsolates(LibMsgId msg_id);
+  static void KillIfExists(Isolate* isolate, LibMsgId msg_id);
 
   static void DisableIsolateCreation();
   static void EnableIsolateCreation();
@@ -786,7 +785,7 @@
                        bool is_vm_isolate = false);
 
   // The isolates_list_monitor_ should be held when calling Kill().
-  void KillLocked();
+  void KillLocked(LibMsgId msg_id);
 
   void LowLevelShutdown();
   void Shutdown();
@@ -832,11 +831,18 @@
 
   template<class T> T* AllocateReusableHandle();
 
-  uword vm_tag_;
+  // Accessed from generated code:
+  uword stack_limit_;
   StoreBuffer* store_buffer_;
   Heap* heap_;
-  ThreadRegistry* thread_registry_;
+  uword vm_tag_;
+  uword user_tag_;
+  RawUserTag* current_tag_;
+  RawUserTag* default_tag_;
   ClassTable class_table_;
+  bool single_step_;
+
+  ThreadRegistry* thread_registry_;
   Dart_MessageNotifyCallback message_notify_callback_;
   char* name_;
   char* debugger_name_;
@@ -853,17 +859,14 @@
   Dart_LibraryTagHandler library_tag_handler_;
   ApiState* api_state_;
   Debugger* debugger_;
-  bool single_step_;
   bool resume_request_;
   int64_t last_resume_timestamp_;
   bool has_compiled_;
   Flags flags_;
   Random random_;
   Simulator* simulator_;
-  TimerList timer_list_;
   intptr_t deopt_id_;
   Mutex* mutex_;  // protects stack_limit_ and saved_stack_limit_.
-  uword stack_limit_;
   uword saved_stack_limit_;
   uword stack_base_;
   uword stack_overflow_flags_;
@@ -875,6 +878,7 @@
   Dart_GcEpilogueCallback gc_epilogue_callback_;
   intptr_t defer_finalization_count_;
   DeoptContext* deopt_context_;
+  BackgroundCompiler* background_compiler_;
 
   CompilerStats* compiler_stats_;
 
@@ -898,13 +902,12 @@
   Mutex profiler_data_mutex_;
 
   VMTagCounters vm_tag_counters_;
-  uword user_tag_;
   RawGrowableObjectArray* tag_table_;
-  RawUserTag* current_tag_;
-  RawUserTag* default_tag_;
+
 
   RawGrowableObjectArray* collected_closures_;
   RawGrowableObjectArray* deoptimized_code_array_;
+  RawGrowableObjectArray* background_compilation_queue_;
 
   // We use 6 list entries for each pending service extension calls.
   enum {
diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc
index f25add7..b5da5dd 100644
--- a/runtime/vm/json_stream.cc
+++ b/runtime/vm/json_stream.cc
@@ -292,23 +292,27 @@
 
 
 void JSONStream::PrintValue(intptr_t i) {
+  EnsureIntegerIsRepresentableInJavaScript(static_cast<int64_t>(i));
   PrintCommaIfNeeded();
   buffer_.Printf("%" Pd "", i);
 }
 
 
 void JSONStream::PrintValue64(int64_t i) {
+  EnsureIntegerIsRepresentableInJavaScript(i);
   PrintCommaIfNeeded();
   buffer_.Printf("%" Pd64 "", i);
 }
 
 
 void JSONStream::PrintValueTimeMillis(int64_t millis) {
-  PrintValue(static_cast<double>(millis));
+  EnsureIntegerIsRepresentableInJavaScript(millis);
+  PrintValue64(millis);
 }
 
 
 void JSONStream::PrintValueTimeMicros(int64_t micros) {
+  EnsureIntegerIsRepresentableInJavaScript(micros);
   PrintValue64(micros);
 }
 
@@ -452,21 +456,19 @@
 
 
 void JSONStream::PrintProperty(const char* name, intptr_t i) {
-  ASSERT(Utils::IsJavascriptInt(i));
   PrintPropertyName(name);
   PrintValue(i);
 }
 
 
 void JSONStream::PrintProperty64(const char* name, int64_t i) {
-  ASSERT(Utils::IsJavascriptInt64(i));
   PrintPropertyName(name);
   PrintValue64(i);
 }
 
 
 void JSONStream::PrintPropertyTimeMillis(const char* name, int64_t millis) {
-  PrintProperty(name, static_cast<double>(millis));
+  PrintProperty64(name, millis);
 }
 
 
@@ -620,6 +622,17 @@
 }
 
 
+void JSONStream::EnsureIntegerIsRepresentableInJavaScript(int64_t i) {
+#ifdef DEBUG
+  if (!Utils::IsJavascriptInt(i)) {
+    OS::Print("JSONStream::EnsureIntegerIsRepresentableInJavaScript failed on "
+              "%" Pd64 "\n", i);
+    UNREACHABLE();
+  }
+#endif
+}
+
+
 void JSONStream::AddEscapedUTF8String(const char* s) {
   if (s == NULL) {
     return;
diff --git a/runtime/vm/json_stream.h b/runtime/vm/json_stream.h
index a6ae55f..78f6fdd 100644
--- a/runtime/vm/json_stream.h
+++ b/runtime/vm/json_stream.h
@@ -172,6 +172,9 @@
 
   intptr_t nesting_level() const { return open_objects_; }
 
+  // Debug only fatal assertion.
+  static void EnsureIntegerIsRepresentableInJavaScript(int64_t i);
+
   intptr_t open_objects_;
   TextBuffer buffer_;
   // Default service id zone.
diff --git a/runtime/vm/locations.h b/runtime/vm/locations.h
index 5e92c16..047b663 100644
--- a/runtime/vm/locations.h
+++ b/runtime/vm/locations.h
@@ -148,7 +148,7 @@
     return (value_ & kLocationTagMask) == kConstantTag;
   }
 
-  static Location Constant(ConstantInstr* obj) {
+  static Location Constant(const ConstantInstr* obj) {
     Location loc(reinterpret_cast<uword>(obj) | kConstantTag);
     ASSERT(obj == loc.constant_instruction());
     return loc;
diff --git a/runtime/vm/message_handler.cc b/runtime/vm/message_handler.cc
index ef8a71e..47ab4b9 100644
--- a/runtime/vm/message_handler.cc
+++ b/runtime/vm/message_handler.cc
@@ -6,6 +6,8 @@
 
 #include "vm/dart.h"
 #include "vm/lockers.h"
+#include "vm/object.h"
+#include "vm/object_store.h"
 #include "vm/os.h"
 #include "vm/port.h"
 #include "vm/thread_interrupter.h"
@@ -35,6 +37,24 @@
 };
 
 
+// static
+const char* MessageHandler::MessageStatusString(MessageStatus status) {
+  switch (status) {
+    case kOK:
+      return "OK";
+    case kError:
+      return "Error";
+    case kRestart:
+      return "Restart";
+    case kShutdown:
+      return "Shutdown";
+    default:
+      UNREACHABLE();
+      return "Illegal";
+  }
+}
+
+
 MessageHandler::MessageHandler()
     : queue_(new MessageQueue()),
       oob_queue_(new MessageQueue()),
@@ -150,8 +170,16 @@
 }
 
 
-bool MessageHandler::HandleMessages(bool allow_normal_messages,
-                                    bool allow_multiple_normal_messages) {
+void MessageHandler::ClearOOBQueue() {
+  oob_queue_->Clear();
+}
+
+
+MessageHandler::MessageStatus MessageHandler::HandleMessages(
+    bool allow_normal_messages,
+    bool allow_multiple_normal_messages) {
+  // TODO(turnidge): Add assert that monitor_ is held here.
+
   // If isolate() returns NULL StartIsolateScope does nothing.
   StartIsolateScope start_isolate(isolate());
 
@@ -159,10 +187,10 @@
   // an isolate to start handling messages.
   ThreadInterrupter::WakeUp();
 
-  // TODO(turnidge): Add assert that monitor_ is held here.
-  bool result = true;
-  Message::Priority min_priority = (allow_normal_messages && !paused()) ?
-      Message::kNormalPriority : Message::kOOBPriority;
+  MessageStatus max_status = kOK;
+  Message::Priority min_priority = ((allow_normal_messages && !paused())
+                                    ? Message::kNormalPriority
+                                    : Message::kOOBPriority);
   Message* message = DequeueMessage(min_priority);
   while (message != NULL) {
     intptr_t message_len = message->len();
@@ -179,38 +207,50 @@
     monitor_.Exit();
     Message::Priority saved_priority = message->priority();
     Dart_Port saved_dest_port = message->dest_port();
-    result = HandleMessage(message);
+    MessageStatus status = HandleMessage(message);
+    if (status > max_status) {
+      max_status = status;
+    }
     message = NULL;  // May be deleted by now.
     monitor_.Enter();
     if (FLAG_trace_isolates) {
-      OS::Print("[.] Message handled:\n"
+      OS::Print("[.] Message handled (%s):\n"
                 "\tlen:        %" Pd "\n"
                 "\thandler:    %s\n"
                 "\tport:       %" Pd64 "\n",
+                MessageStatusString(status),
                 message_len, name(), saved_dest_port);
     }
-    if (!result) {
-      // If we hit an error, we're done processing messages.
+    // If we are shutting down, do not process any more messages.
+    if (status == kShutdown) {
+      ClearOOBQueue();
       break;
     }
+
     // Some callers want to process only one normal message and then quit. At
     // the same time it is OK to process multiple OOB messages.
     if ((saved_priority == Message::kNormalPriority) &&
         !allow_multiple_normal_messages) {
-      break;
+      // We processed one normal message.  Allow no more.
+      allow_normal_messages = false;
     }
 
-    // Reevaluate the minimum allowable priority as the paused state might
-    // have changed as part of handling the message.
-    min_priority = (allow_normal_messages && !paused()) ?
-        Message::kNormalPriority : Message::kOOBPriority;
+    // Reevaluate the minimum allowable priority.  The paused state
+    // may have changed as part of handling the message.  We may also
+    // have encountered an error during message processsing.
+    //
+    // Even if we encounter an error, we still process pending OOB
+    // messages so that we don't lose the message notification.
+    min_priority = (((max_status == kOK) && allow_normal_messages && !paused())
+                    ? Message::kNormalPriority
+                    : Message::kOOBPriority);
     message = DequeueMessage(min_priority);
   }
-  return result;
+  return max_status;
 }
 
 
-bool MessageHandler::HandleNextMessage() {
+MessageHandler::MessageStatus MessageHandler::HandleNextMessage() {
   // We can only call HandleNextMessage when this handler is not
   // assigned to a thread pool.
   MonitorLocker ml(&monitor_);
@@ -222,9 +262,9 @@
 }
 
 
-bool MessageHandler::HandleOOBMessages() {
+MessageHandler::MessageStatus MessageHandler::HandleOOBMessages() {
   if (!oob_message_handling_allowed_) {
-    return true;
+    return kOK;
   }
   MonitorLocker ml(&monitor_);
 #if defined(DEBUG)
@@ -240,29 +280,39 @@
 }
 
 
+static bool ShouldPause(MessageHandler::MessageStatus status) {
+  // If we are restarting or shutting down, we do not want to honor
+  // pause_on_start or pause_on_exit.
+  return (status != MessageHandler::kRestart &&
+          status != MessageHandler::kShutdown);
+}
+
+
 void MessageHandler::TaskCallback() {
   ASSERT(Isolate::Current() == NULL);
-  bool ok = true;
+  MessageStatus status = kOK;
   bool run_end_callback = false;
   {
+    // We will occasionally release and reacquire this monitor in this
+    // function. Whenever we reacquire the monitor we *must* process
+    // all pending OOB messages, or we may miss a request for vm
+    // shutdown.
     MonitorLocker ml(&monitor_);
-    // Initialize the message handler by running its start function,
-    // if we have one.  For an isolate, this will run the isolate's
-    // main() function.
     if (pause_on_start()) {
       if (!paused_on_start_) {
-        // Temporarily drop the lock when calling out to NotifyPauseOnStart.
-        // This avoids a dead lock that can occur when this message handler
-        // tries to post a message while a message is being posted to it.
+        // Temporarily release the monitor when calling out to
+        // NotifyPauseOnStart.  This avoids a dead lock that can occur
+        // when this message handler tries to post a message while a
+        // message is being posted to it.
         paused_on_start_ = true;
         paused_timestamp_ = OS::GetCurrentTimeMillis();
         monitor_.Exit();
         NotifyPauseOnStart();
         monitor_.Enter();
       }
-      // More messages may have come in while we released monitor_.
-      HandleMessages(false, false);
-      if (pause_on_start()) {
+      // More messages may have come in before we (re)acquired the monitor.
+      status = HandleMessages(false, false);
+      if (ShouldPause(status) && pause_on_start()) {
         // Still paused.
         ASSERT(oob_queue_->IsEmpty());
         task_ = NULL;  // No task in queue.
@@ -273,40 +323,49 @@
       }
     }
 
-    if (start_callback_) {
-      // Release the monitor_ temporarily while we call the start callback.
-      // The monitor was acquired with the MonitorLocker above.
-      monitor_.Exit();
-      ok = start_callback_(callback_data_);
-      ASSERT(Isolate::Current() == NULL);
-      start_callback_ = NULL;
-      monitor_.Enter();
+    if (status == kOK) {
+      if (start_callback_) {
+        // Initialize the message handler by running its start function,
+        // if we have one.  For an isolate, this will run the isolate's
+        // main() function.
+        //
+        // Release the monitor_ temporarily while we call the start callback.
+        monitor_.Exit();
+        status = start_callback_(callback_data_);
+        ASSERT(Isolate::Current() == NULL);
+        start_callback_ = NULL;
+        monitor_.Enter();
+      }
+
+      // Handle any pending messages for this message handler.
+      if (status != kShutdown) {
+        status = HandleMessages((status == kOK), true);
+      }
     }
 
-    // Handle any pending messages for this message handler.
-    if (ok) {
-      ok = HandleMessages(true, true);
-    }
-
-    if (!ok || !HasLivePorts()) {
-      if (pause_on_exit()) {
+    // The isolate exits when it encounters an error or when it no
+    // longer has live ports.
+    if (status != kOK || !HasLivePorts()) {
+      if (ShouldPause(status) && pause_on_exit()) {
         if (!paused_on_exit_) {
           if (FLAG_trace_service_pause_events) {
             OS::PrintErr("Isolate %s paused before exiting. "
                          "Use the Observatory to release it.\n", name());
           }
-          // Temporarily drop the lock when calling out to NotifyPauseOnExit.
-          // This avoids a dead lock that can occur when this message handler
-          // tries to post a message while a message is being posted to it.
+          // Temporarily release the monitor when calling out to
+          // NotifyPauseOnExit.  This avoids a dead lock that can
+          // occur when this message handler tries to post a message
+          // while a message is being posted to it.
           paused_on_exit_ = true;
           paused_timestamp_ = OS::GetCurrentTimeMillis();
           monitor_.Exit();
           NotifyPauseOnExit();
           monitor_.Enter();
+
+          // More messages may have come in while we released the monitor.
+          HandleMessages(false, false);
         }
-        // More messages may have come in while we released monitor_.
-        HandleMessages(false, false);
-        if (pause_on_exit()) {
+        if (ShouldPause(status) && pause_on_exit()) {
           // Still paused.
           ASSERT(oob_queue_->IsEmpty());
           task_ = NULL;  // No task in queue.
@@ -317,10 +376,18 @@
         }
       }
       if (FLAG_trace_isolates) {
-        OS::Print("[-] Stopping message handler (%s):\n"
-                  "\thandler:    %s\n",
-                  (ok ? "no live ports" : "error"),
-                  name());
+        if (status != kOK && isolate() != NULL) {
+          const Error& error =
+              Error::Handle(isolate()->object_store()->sticky_error());
+          OS::Print("[-] Stopping message handler (%s):\n"
+                    "\thandler:    %s\n"
+                    "\terror:    %s\n",
+                    MessageStatusString(status), name(), error.ToCString());
+        } else {
+          OS::Print("[-] Stopping message handler (%s):\n"
+                    "\thandler:    %s\n",
+                    MessageStatusString(status), name());
+        }
       }
       pool_ = NULL;
       run_end_callback = true;
diff --git a/runtime/vm/message_handler.h b/runtime/vm/message_handler.h
index 4a939ae..f4d907c 100644
--- a/runtime/vm/message_handler.h
+++ b/runtime/vm/message_handler.h
@@ -18,13 +18,21 @@
   MessageHandler();
 
  public:
+  enum MessageStatus {
+    kOK,        // We successfully handled a message.
+    kError,     // We encountered an error handling a message.
+    kRestart,   // The VM is restarting.
+    kShutdown,  // The VM is shutting down.
+  };
+  static const char* MessageStatusString(MessageStatus status);
+
   virtual ~MessageHandler();
 
   // Allow subclasses to provide a handler name.
   virtual const char* name() const;
 
   typedef uword CallbackData;
-  typedef bool (*StartCallback)(CallbackData data);
+  typedef MessageStatus (*StartCallback)(CallbackData data);
   typedef void (*EndCallback)(CallbackData data);
 
   // Runs this message handler on the thread pool.
@@ -46,13 +54,13 @@
   // or RunBlocking).
   //
   // Returns true on success.
-  bool HandleNextMessage();
+  MessageStatus HandleNextMessage();
 
   // Handles any OOB messages for this message handler.  Can be used
   // even if the message handler is running on the thread pool.
   //
   // Returns true on success.
-  bool HandleOOBMessages();
+  MessageStatus HandleOOBMessages();
 
   // Returns true if there are pending OOB messages for this message
   // handler.
@@ -179,7 +187,7 @@
   // Handles a single message.  Provided by subclass.
   //
   // Returns true on success.
-  virtual bool HandleMessage(Message* message) = 0;
+  virtual MessageStatus HandleMessage(Message* message) = 0;
 
   virtual void NotifyPauseOnStart() {}
   virtual void NotifyPauseOnExit() {}
@@ -199,9 +207,11 @@
   // messages from the queue_.
   Message* DequeueMessage(Message::Priority min_priority);
 
+  void ClearOOBQueue();
+
   // Handles any pending messages.
-  bool HandleMessages(bool allow_normal_messages,
-                      bool allow_multiple_normal_messages);
+  MessageStatus HandleMessages(bool allow_normal_messages,
+                               bool allow_multiple_normal_messages);
 
   Monitor monitor_;  // Protects all fields in MessageHandler.
   MessageQueue* queue_;
diff --git a/runtime/vm/message_handler_test.cc b/runtime/vm/message_handler_test.cc
index 7bfcb9a..ae7edab 100644
--- a/runtime/vm/message_handler_test.cc
+++ b/runtime/vm/message_handler_test.cc
@@ -39,7 +39,7 @@
         message_count_(0),
         start_called_(false),
         end_called_(false),
-        result_(true) {
+        results_(NULL) {
   }
 
   ~TestMessageHandler() {
@@ -50,18 +50,23 @@
     notify_count_++;
   }
 
-  bool HandleMessage(Message* message) {
+  MessageStatus HandleMessage(Message* message) {
     // For testing purposes, keep a list of the ports
     // for all messages we receive.
     AddPortToBuffer(message->dest_port());
     delete message;
     message_count_++;
-    return result_;
+    MessageStatus status = kOK;
+    if (results_ != NULL) {
+      status = results_[0];
+      results_++;
+    }
+    return status;
   }
 
-  bool Start() {
+  MessageStatus Start() {
     start_called_ = true;
-    return true;
+    return kOK;
   }
 
   void End() {
@@ -75,7 +80,7 @@
   bool start_called() const { return start_called_; }
   bool end_called() const { return end_called_; }
 
-  void set_result(bool result) { result_ = result; }
+  void set_results(MessageStatus* results) { results_ = results; }
 
  private:
   void AddPortToBuffer(Dart_Port port) {
@@ -101,13 +106,13 @@
   int message_count_;
   bool start_called_;
   bool end_called_;
-  bool result_;
+  MessageStatus* results_;
 
   DISALLOW_COPY_AND_ASSIGN(TestMessageHandler);
 };
 
 
-bool TestStartFunction(uword data) {
+MessageHandler::MessageStatus TestStartFunction(uword data) {
   return (reinterpret_cast<TestMessageHandler*>(data))->Start();
 }
 
@@ -232,7 +237,7 @@
   handler_peer.PostMessage(oob_message2);
 
   // We handle both oob messages and a single normal message.
-  EXPECT(handler.HandleNextMessage());
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_EQ(3, handler.message_count());
   Dart_Port* ports = handler.port_buffer();
   EXPECT_EQ(port2, ports[0]);
@@ -242,6 +247,75 @@
 }
 
 
+UNIT_TEST_CASE(MessageHandler_HandleNextMessage_ProcessOOBAfterError) {
+  TestMessageHandler handler;
+  MessageHandler::MessageStatus results[] = {
+    MessageHandler::kError,     // oob_message1
+    MessageHandler::kOK,        // oob_message2
+    MessageHandler::kOK,        // unused
+  };
+  handler.set_results(results);
+  MessageHandlerTestPeer handler_peer(&handler);
+  Dart_Port port1 = PortMap::CreatePort(&handler);
+  Dart_Port port2 = PortMap::CreatePort(&handler);
+  Dart_Port port3 = PortMap::CreatePort(&handler);
+  Message* message1 = new Message(port1, NULL, 0, Message::kNormalPriority);
+  handler_peer.PostMessage(message1);
+  Message* oob_message1 = new Message(port2, NULL, 0, Message::kOOBPriority);
+  handler_peer.PostMessage(oob_message1);
+  Message* oob_message2 = new Message(port3, NULL, 0, Message::kOOBPriority);
+  handler_peer.PostMessage(oob_message2);
+
+  // When we get an error, we continue processing oob messages but
+  // stop handling normal messages.
+  EXPECT_EQ(MessageHandler::kError, handler.HandleNextMessage());
+  EXPECT_EQ(2, handler.message_count());
+  Dart_Port* ports = handler.port_buffer();
+  EXPECT_EQ(port2, ports[0]);  // oob_message1, error
+  EXPECT_EQ(port3, ports[1]);  // oob_message2, ok
+  handler_peer.CloseAllPorts();
+}
+
+
+UNIT_TEST_CASE(MessageHandler_HandleNextMessage_Shutdown) {
+  TestMessageHandler handler;
+  MessageHandler::MessageStatus results[] = {
+    MessageHandler::kOK,        // oob_message1
+    MessageHandler::kShutdown,  // oob_message2
+    MessageHandler::kOK,        // unused
+    MessageHandler::kOK,        // unused
+  };
+  handler.set_results(results);
+  MessageHandlerTestPeer handler_peer(&handler);
+  Dart_Port port1 = PortMap::CreatePort(&handler);
+  Dart_Port port2 = PortMap::CreatePort(&handler);
+  Dart_Port port3 = PortMap::CreatePort(&handler);
+  Dart_Port port4 = PortMap::CreatePort(&handler);
+  Message* message1 = new Message(port1, NULL, 0, Message::kNormalPriority);
+  handler_peer.PostMessage(message1);
+  Message* oob_message1 = new Message(port2, NULL, 0, Message::kOOBPriority);
+  handler_peer.PostMessage(oob_message1);
+  Message* oob_message2 = new Message(port3, NULL, 0, Message::kOOBPriority);
+  handler_peer.PostMessage(oob_message2);
+  Message* oob_message3 = new Message(port4, NULL, 0, Message::kOOBPriority);
+  handler_peer.PostMessage(oob_message3);
+
+  // When we get a shutdown message, we stop processing all messages.
+  EXPECT_EQ(MessageHandler::kShutdown, handler.HandleNextMessage());
+  EXPECT_EQ(2, handler.message_count());
+  Dart_Port* ports = handler.port_buffer();
+  EXPECT_EQ(port2, ports[0]);  // oob_message1, ok
+  EXPECT_EQ(port3, ports[1]);  // oob_message2, shutdown
+  {
+    // The oob queue has been cleared.  oob_message3 is gone.
+    MessageHandler::AcquiredQueues aq;
+    handler.AcquireQueues(&aq);
+    EXPECT(aq.oob_queue()->Length() == 0);
+  }
+  handler_peer.CloseAllPorts();
+}
+
+
 UNIT_TEST_CASE(MessageHandler_HandleOOBMessages) {
   TestMessageHandler handler;
   MessageHandlerTestPeer handler_peer(&handler);
@@ -259,7 +333,7 @@
   handler_peer.PostMessage(oob_message2);
 
   // We handle both oob messages but no normal messages.
-  EXPECT(handler.HandleOOBMessages());
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleOOBMessages());
   EXPECT_EQ(2, handler.message_count());
   Dart_Port* ports = handler.port_buffer();
   EXPECT_EQ(port3, ports[0]);
diff --git a/runtime/vm/method_recognizer.h b/runtime/vm/method_recognizer.h
index a931290..5e8e576 100644
--- a/runtime/vm/method_recognizer.h
+++ b/runtime/vm/method_recognizer.h
@@ -130,8 +130,6 @@
   V(_Uint16Array, []=, Uint16ArraySetIndexed, 1594961463)                      \
   V(_Int32Array, [], Int32ArrayGetIndexed, 2052925823)                         \
   V(_Int32Array, []=, Int32ArraySetIndexed, 504626978)                         \
-  V(_Uint32Array, [], Uint32ArrayGetIndexed, 1034114777)                       \
-  V(_Uint32Array, []=, Uint32ArraySetIndexed, 918159348)                       \
   V(_Int64Array, [], Int64ArrayGetIndexed, 297668331)                          \
   V(_Int64Array, []=, Int64ArraySetIndexed, 36465128)                          \
   V(_Float32x4Array, [], Float32x4ArrayGetIndexed, 35821240)                   \
@@ -278,6 +276,8 @@
   V(_Uint8Array, []=, Uint8ArraySetIndexed, 447309008)                         \
   V(_ExternalUint8Array, [], ExternalUint8ArrayGetIndexed, 1293647140)         \
   V(_ExternalUint8Array, []=, ExternalUint8ArraySetIndexed, 1593599192)        \
+  V(_Uint32Array, [], Uint32ArrayGetIndexed, 1034114777)                       \
+  V(_Uint32Array, []=, Uint32ArraySetIndexed, 918159348)                       \
   V(_Float64Array, []=, Float64ArraySetIndexed, 887301703)                     \
   V(_Float64Array, [], Float64ArrayGetIndexed, 1959896670)                     \
   V(_TypedList, get:length, TypedDataLength, 522684521)                        \
diff --git a/runtime/vm/metrics.cc b/runtime/vm/metrics.cc
index 79038fb..0e15c0f 100644
--- a/runtime/vm/metrics.cc
+++ b/runtime/vm/metrics.cc
@@ -276,6 +276,12 @@
 }
 
 
+int64_t MetricHeapUsed::Value() const {
+  ASSERT(isolate() == Isolate::Current());
+  return isolate()->heap()->UsedInWords(Heap::kNew) * kWordSize +
+         isolate()->heap()->UsedInWords(Heap::kOld) * kWordSize;
+}
+
 int64_t MetricIsolateCount::Value() const {
   return Isolate::IsolateListLength();
 }
@@ -307,4 +313,30 @@
   }
 }
 
+
+MaxMetric::MaxMetric()
+    : Metric() {
+  set_value(kMinInt64);
+}
+
+
+void MaxMetric::SetValue(int64_t new_value) {
+  if (new_value > value()) {
+    set_value(new_value);
+  }
+}
+
+
+MinMetric::MinMetric()
+    : Metric() {
+  set_value(kMaxInt64);
+}
+
+
+void MinMetric::SetValue(int64_t new_value) {
+  if (new_value < value()) {
+    set_value(new_value);
+  }
+}
+
 }  // namespace dart
diff --git a/runtime/vm/metrics.h b/runtime/vm/metrics.h
index 03cead2..9fde2d8 100644
--- a/runtime/vm/metrics.h
+++ b/runtime/vm/metrics.h
@@ -15,14 +15,20 @@
 // Metrics for each isolate.
 #define ISOLATE_METRIC_LIST(V)                                                 \
   V(MetricHeapOldUsed, HeapOldUsed, "heap.old.used", kByte)                    \
+  V(MaxMetric, HeapOldUsedMax, "heap.old.used.max", kByte)                     \
   V(MetricHeapOldCapacity, HeapOldCapacity, "heap.old.capacity", kByte)        \
+  V(MaxMetric, HeapOldCapacityMax, "heap.old.capacity.max", kByte)             \
   V(MetricHeapOldExternal, HeapOldExternal, "heap.old.external", kByte)        \
   V(MetricHeapNewUsed, HeapNewUsed, "heap.new.used", kByte)                    \
+  V(MaxMetric, HeapNewUsedMax, "heap.new.used.max", kByte)                     \
   V(MetricHeapNewCapacity, HeapNewCapacity, "heap.new.capacity", kByte)        \
+  V(MaxMetric, HeapNewCapacityMax, "heap.new.capacity.max", kByte)             \
   V(MetricHeapNewExternal, HeapNewExternal, "heap.new.external", kByte)        \
+  V(MetricHeapUsed, HeapGlobalUsed, "heap.global.used", kByte)                 \
+  V(MaxMetric, HeapGlobalUsedMax, "heap.global.used.max", kByte)               \
 
 #define VM_METRIC_LIST(V)                                                      \
-  V(MetricIsolateCount, IsolateCount, "vm.isolate.count", kCounter)            \
+  V(MetricIsolateCount, IsolateCount, "vm.isolate.count", kCounter)
 
 class Metric {
  public:
@@ -102,6 +108,26 @@
 };
 
 
+// A Metric class that reports the maximum value observed.
+// Initial maximum is kMinInt64.
+class MaxMetric : public Metric {
+ public:
+  MaxMetric();
+
+  void SetValue(int64_t new_value);
+};
+
+
+// A Metric class that reports the minimum value observed.
+// Initial minimum is kMaxInt64.
+class MinMetric : public Metric {
+ public:
+  MinMetric();
+
+  void SetValue(int64_t new_value);
+};
+
+
 class MetricHeapOldUsed : public Metric {
  protected:
   virtual int64_t Value() const;
@@ -144,6 +170,11 @@
 };
 
 
+class MetricHeapUsed : public Metric {
+ protected:
+  virtual int64_t Value() const;
+};
+
 }  // namespace dart
 
 #endif  // VM_METRICS_H_
diff --git a/runtime/vm/mirrors_api_impl.cc b/runtime/vm/mirrors_api_impl.cc
index 3d83d44..cb3b93f 100644
--- a/runtime/vm/mirrors_api_impl.cc
+++ b/runtime/vm/mirrors_api_impl.cc
@@ -83,7 +83,7 @@
 
   if (obj.IsType()) {
     const Class& cls = Class::Handle(Z, Type::Cast(obj).type_class());
-    const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(I));
+    const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(T));
     if (!error.IsNull()) {
       return Api::NewHandle(I, error.raw());
     }
diff --git a/runtime/vm/native_entry.h b/runtime/vm/native_entry.h
index 0123b47..25dee39 100644
--- a/runtime/vm/native_entry.h
+++ b/runtime/vm/native_entry.h
@@ -88,7 +88,7 @@
 #define GET_NATIVE_ARGUMENT(type, name, value)                                 \
   const Instance& __##name##_instance__ =                                      \
       Instance::CheckedHandle(zone, value);                                    \
-  type& name = type::Handle(isolate);                                          \
+  type& name = type::Handle(zone);                                             \
   if (!__##name##_instance__.IsNull()) {                                       \
     if (!__##name##_instance__.Is##type()) {                                   \
       const Array& __args__ = Array::Handle(Array::New(1));                    \
diff --git a/runtime/vm/native_entry_test.cc b/runtime/vm/native_entry_test.cc
index 6d48368..6929913 100644
--- a/runtime/vm/native_entry_test.cc
+++ b/runtime/vm/native_entry_test.cc
@@ -56,7 +56,6 @@
 // Arg0-4: 5 smis or null.
 // Result: a smi representing the sum of all non-null arguments.
 void TestNonNullSmiSum(Dart_NativeArguments args) {
-  Isolate* isolate = Isolate::Current();  // Used by GET_NATIVE_ARGUMENT.
   int64_t result = 0;
   int arg_count = Dart_GetNativeArgumentCount(args);
   // Test the lower level macro GET_NATIVE_ARGUMENT.
diff --git a/runtime/vm/native_message_handler.cc b/runtime/vm/native_message_handler.cc
index da869e2..8f8d7a6 100644
--- a/runtime/vm/native_message_handler.cc
+++ b/runtime/vm/native_message_handler.cc
@@ -32,7 +32,8 @@
 #endif
 
 
-bool NativeMessageHandler::HandleMessage(Message* message) {
+MessageHandler::MessageStatus NativeMessageHandler::HandleMessage(
+    Message* message) {
   if (message->IsOOB()) {
     // We currently do not use OOB messages for native ports.
     UNREACHABLE();
@@ -45,7 +46,7 @@
   Dart_CObject* object = reader.ReadMessage();
   (*func())(message->dest_port(), object);
   delete message;
-  return true;
+  return kOK;
 }
 
 }  // namespace dart
diff --git a/runtime/vm/native_message_handler.h b/runtime/vm/native_message_handler.h
index 777cb7f..9a34c77 100644
--- a/runtime/vm/native_message_handler.h
+++ b/runtime/vm/native_message_handler.h
@@ -21,7 +21,7 @@
   const char* name() const { return name_; }
   Dart_NativeMessageHandler func() const { return func_; }
 
-  bool HandleMessage(Message* message);
+  MessageStatus HandleMessage(Message* message);
 
 #if defined(DEBUG)
   // Check that it is safe to access this handler.
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 11cd82b..87f3f10 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -951,12 +951,14 @@
   cls = isolate->object_store()->one_byte_string_class();
   cls.set_name(Symbols::OneByteString());
 
-  // Make the VM isolate read-only after setting all objects as marked.
-  PremarkingVisitor premarker(isolate);
-  isolate->heap()->WriteProtect(false);
-  ASSERT(isolate->heap()->UsedInWords(Heap::kNew) == 0);
-  isolate->heap()->IterateOldObjects(&premarker);
-  isolate->heap()->WriteProtect(true);
+  {
+    ASSERT(isolate == Dart::vm_isolate());
+    WritableVMIsolateScope scope(Thread::Current());
+    PremarkingVisitor premarker(isolate);
+    ASSERT(isolate->heap()->UsedInWords(Heap::kNew) == 0);
+    isolate->heap()->IterateOldObjects(&premarker);
+    // Make the VM isolate read-only again after setting all objects as marked.
+  }
 }
 
 
@@ -1058,7 +1060,6 @@
 RawError* Object::Init(Isolate* isolate) {
   Thread* thread = Thread::Current();
   ASSERT(isolate == thread->isolate());
-  TIMERSCOPE(thread, time_bootstrap);
   TimelineDurationScope tds(isolate,
                             isolate->GetIsolateStream(),
                             "Object::Init");
@@ -1761,10 +1762,22 @@
                               intptr_t class_id,
                               intptr_t size,
                               bool is_vm_object) {
-  uword initial_value = (class_id == kInstructionsCid)
-      ? Assembler::GetBreakInstructionFiller() : reinterpret_cast<uword>(null_);
+  const uword break_instruction_value = Assembler::GetBreakInstructionFiller();
+  const uword null_value = reinterpret_cast<uword>(null_);
+  const bool is_instructions = class_id == kInstructionsCid;
+  uword initial_value =
+      is_instructions ? break_instruction_value : null_value;
   uword cur = address;
   uword end = address + size;
+  if (is_instructions) {
+    // Fill the header with null. The remainder of the Instructions object will
+    // be filled with the break_instruction_value.
+    uword header_end = address + Instructions::HeaderSize();
+    while (cur < header_end) {
+      *reinterpret_cast<uword*>(cur) = null_value;
+      cur += kWordSize;
+    }
+  }
   while (cur < end) {
     *reinterpret_cast<uword*>(cur) = initial_value;
     cur += kWordSize;
@@ -1830,7 +1843,7 @@
   }
   const Class& cls = Class::Handle(class_table->At(cls_id));
   if (cls.TraceAllocation(isolate)) {
-    Profiler::RecordAllocation(isolate, cls_id);
+    Profiler::RecordAllocation(thread, cls_id);
   }
   NoSafepointScope no_safepoint;
   InitializeObject(address, cls_id, size, (isolate == Dart::vm_isolate()));
@@ -2197,8 +2210,9 @@
 
 
 intptr_t Class::FindFunctionIndex(const Function& needle) const {
-  Isolate* isolate = Isolate::Current();
-  if (EnsureIsFinalized(isolate) != Error::null()) {
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
+  if (EnsureIsFinalized(thread) != Error::null()) {
     return -1;
   }
   REUSABLE_ARRAY_HANDLESCOPE(isolate);
@@ -2250,8 +2264,9 @@
 
 
 intptr_t Class::FindImplicitClosureFunctionIndex(const Function& needle) const {
-  Isolate* isolate = Isolate::Current();
-  if (EnsureIsFinalized(isolate) != Error::null()) {
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
+  if (EnsureIsFinalized(thread) != Error::null()) {
     return -1;
   }
   REUSABLE_ARRAY_HANDLESCOPE(isolate);
@@ -2281,8 +2296,9 @@
 
 intptr_t Class::FindInvocationDispatcherFunctionIndex(
     const Function& needle) const {
-  Isolate* isolate = Isolate::Current();
-  if (EnsureIsFinalized(isolate) != Error::null()) {
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
+  if (EnsureIsFinalized(thread) != Error::null()) {
     return -1;
   }
   REUSABLE_ARRAY_HANDLESCOPE(isolate);
@@ -2419,13 +2435,14 @@
 }
 
 
-intptr_t Class::NumTypeParameters(Isolate* isolate) const {
+intptr_t Class::NumTypeParameters(Thread* thread) const {
   if (IsMixinApplication() && !is_mixin_type_applied()) {
     ClassFinalizer::ApplyMixinType(*this);
   }
   if (type_parameters() == TypeArguments::null()) {
     return 0;
   }
+  Isolate* isolate = thread->isolate();
   REUSABLE_TYPE_ARGUMENTS_HANDLESCOPE(isolate);
   TypeArguments& type_params = isolate->TypeArgumentsHandle();
   type_params = type_parameters();
@@ -3017,16 +3034,17 @@
 
 // Ensure that top level parsing of the class has been done.
 // TODO(24109): Migrate interface to Thread*.
-RawError* Class::EnsureIsFinalized(Isolate* isolate) const {
+RawError* Class::EnsureIsFinalized(Thread* thread) const {
   // Finalized classes have already been parsed.
   if (is_finalized()) {
     return Error::null();
   }
-  ASSERT(isolate != NULL);
-  const Error& error = Error::Handle(isolate, Compiler::CompileClass(*this));
+  ASSERT(thread != NULL);
+  const Error& error = Error::Handle(
+      thread->zone(), Compiler::CompileClass(*this));
   if (!error.IsNull()) {
-    ASSERT(isolate == Thread::Current()->isolate());
-    if (Thread::Current()->long_jump_base() != NULL) {
+    ASSERT(thread == Thread::Current());
+    if (thread->long_jump_base() != NULL) {
       Report::LongJump(error);
       UNREACHABLE();
     }
@@ -3074,8 +3092,9 @@
 
 
 intptr_t Class::FindFieldIndex(const Field& needle) const {
-  Isolate* isolate = Isolate::Current();
-  if (EnsureIsFinalized(isolate) != Error::null()) {
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
+  if (EnsureIsFinalized(thread) != Error::null()) {
     return -1;
   }
   REUSABLE_ARRAY_HANDLESCOPE(isolate);
@@ -3688,8 +3707,9 @@
 
 
 intptr_t Class::FindCanonicalTypeIndex(const Type& needle) const {
-  Isolate* isolate = Isolate::Current();
-  if (EnsureIsFinalized(isolate) != Error::null()) {
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
+  if (EnsureIsFinalized(thread) != Error::null()) {
     return -1;
   }
   if (needle.raw() == CanonicalType()) {
@@ -3752,11 +3772,9 @@
   if (existing_stub.IsNull()) {
     return;
   }
-  ASSERT(!CodePatcher::IsEntryPatched(existing_stub));
-  // Patch the stub so that the next caller will regenerate the stub.
-  CodePatcher::PatchEntry(
-      existing_stub,
-      Code::Handle(StubCode::FixAllocationStubTarget_entry()->code()));
+  ASSERT(!existing_stub.IsDisabled());
+  // Change the stub so that the next caller will regenerate the stub.
+  existing_stub.DisableStubCode();
   // Disassociate the existing stub from class.
   StorePointer(&raw_ptr()->allocation_stub_, Code::null());
 }
@@ -4087,8 +4105,9 @@
 
 
 RawFunction* Class::LookupFunction(const String& name, MemberKind kind) const {
-  Isolate* isolate = Isolate::Current();
-  if (EnsureIsFinalized(isolate) != Error::null()) {
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
+  if (EnsureIsFinalized(thread) != Error::null()) {
     return Function::null();
   }
   REUSABLE_ARRAY_HANDLESCOPE(isolate);
@@ -4134,8 +4153,9 @@
 
 RawFunction* Class::LookupFunctionAllowPrivate(const String& name,
                                                MemberKind kind) const {
-  Isolate* isolate = Isolate::Current();
-  if (EnsureIsFinalized(isolate) != Error::null()) {
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
+  if (EnsureIsFinalized(thread) != Error::null()) {
     return Function::null();
   }
   REUSABLE_ARRAY_HANDLESCOPE(isolate);
@@ -4172,8 +4192,9 @@
 RawFunction* Class::LookupAccessorFunction(const char* prefix,
                                            intptr_t prefix_length,
                                            const String& name) const {
-  Isolate* isolate = Isolate::Current();
-  if (EnsureIsFinalized(isolate) != Error::null()) {
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
+  if (EnsureIsFinalized(thread) != Error::null()) {
     return Function::null();
   }
   REUSABLE_ARRAY_HANDLESCOPE(isolate);
@@ -4200,8 +4221,9 @@
 RawFunction* Class::LookupFunctionAtToken(intptr_t token_pos) const {
   // TODO(hausner): we can shortcut the negative case if we knew the
   // beginning and end token position of the class.
-  Isolate* isolate = Isolate::Current();
-  if (EnsureIsFinalized(isolate) != Error::null()) {
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
+  if (EnsureIsFinalized(thread) != Error::null()) {
     return Function::null();
   }
   Function& func = Function::Handle(isolate);
@@ -4239,8 +4261,9 @@
 
 
 RawField* Class::LookupField(const String& name, MemberKind kind) const {
-  Isolate* isolate = Isolate::Current();
-  if (EnsureIsFinalized(isolate) != Error::null()) {
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
+  if (EnsureIsFinalized(thread) != Error::null()) {
     return Field::null();
   }
   REUSABLE_ARRAY_HANDLESCOPE(isolate);
@@ -4313,7 +4336,7 @@
     return;
   }
 
-  const Error& err = Error::Handle(EnsureIsFinalized(Isolate::Current()));
+  const Error& err = Error::Handle(EnsureIsFinalized(Thread::Current()));
   if (!err.IsNull()) {
     jsobj.AddProperty("error", err);
   }
@@ -5313,9 +5336,7 @@
       ToFullyQualifiedCString(),
       current_code.EntryPoint());
   }
-  // Patch entry of the optimized code.
-  CodePatcher::PatchEntry(
-      current_code, Code::Handle(StubCode::FixCallersTarget_entry()->code()));
+  current_code.DisableDartCode();
   const Error& error = Error::Handle(zone,
       Compiler::EnsureUnoptimizedCode(thread, *this));
   if (!error.IsNull()) {
@@ -5323,7 +5344,7 @@
   }
   const Code& unopt_code = Code::Handle(zone, unoptimized_code());
   AttachCode(unopt_code);
-  CodePatcher::RestoreEntry(unopt_code);
+  unopt_code.Enable();
   isolate->TrackDeoptimizedCode(current_code);
 }
 
@@ -5853,7 +5874,9 @@
                   "%" Pd " named passed, at most %" Pd " expected",
                   num_named_arguments,
                   NumOptionalNamedParameters());
-      *error_message = String::New(message_buffer);
+      // Allocate in old space because it can be invoked in background
+      // optimizing compilation.
+      *error_message = String::New(message_buffer, Heap::kOld);
     }
     return false;  // Too many named arguments.
   }
@@ -5873,7 +5896,9 @@
                   num_opt_pos_params > 0 ? " positional" : "",
                   num_opt_pos_params > 0 ? "at most " : "",
                   num_pos_params - num_hidden_params);
-      *error_message = String::New(message_buffer);
+      // Allocate in old space because it can be invoked in background
+      // optimizing compilation.
+      *error_message = String::New(message_buffer, Heap::kOld);
     }
     return false;  // Too many fixed and/or positional arguments.
   }
@@ -5890,7 +5915,9 @@
                   num_opt_pos_params > 0 ? " positional" : "",
                   num_opt_pos_params > 0 ? "at least " : "",
                   num_fixed_parameters() - num_hidden_params);
-      *error_message = String::New(message_buffer);
+      // Allocate in old space because it can be invoked in background
+      // optimizing compilation.
+      *error_message = String::New(message_buffer, Heap::kOld);
     }
     return false;  // Too few fixed and/or positional arguments.
   }
@@ -5935,7 +5962,9 @@
                     kMessageBufferSize,
                     "no optional formal parameter named '%s'",
                     argument_name.ToCString());
-        *error_message = String::New(message_buffer);
+        // Allocate in old space because it can be invoked in background
+        // optimizing compilation.
+        *error_message = String::New(message_buffer, Heap::kOld);
       }
       return false;
     }
@@ -5981,7 +6010,9 @@
                     kMessageBufferSize,
                     "no optional formal parameter named '%s'",
                     argument_name.ToCString());
-        *error_message = String::New(message_buffer);
+        // Allocate in old space because it can be invoked in background
+        // optimizing compilation.
+        *error_message = String::New(message_buffer, Heap::kOld);
       }
       return false;
     }
@@ -7110,7 +7141,7 @@
   Class& cls = Class::Handle(Owner());
   ASSERT(!cls.IsNull());
   Error& err = Error::Handle();
-  err ^= cls.EnsureIsFinalized(Isolate::Current());
+  err ^= cls.EnsureIsFinalized(Thread::Current());
   ASSERT(err.IsNull());
   JSONObject jsobj(stream);
   AddCommonObjectProperties(&jsobj, "Function", ref);
@@ -10240,6 +10271,11 @@
 }
 
 
+RawLibrary* Library::VMServiceLibrary() {
+  return Isolate::Current()->object_store()->vmservice_library();
+}
+
+
 const char* Library::ToCString() const {
   const String& name = String::Handle(url());
   return OS::SCreate(Thread::Current()->zone(),
@@ -10579,7 +10615,7 @@
       THR_Print("Prefix '%s': disabling %s code for %s function '%s'\n",
           String::Handle(prefix_.name()).ToCString(),
           code.is_optimized() ? "optimized" : "unoptimized",
-          CodePatcher::IsEntryPatched(code) ? "patched" : "unpatched",
+          code.IsDisabled() ? "'patched'" : "'unpatched'",
           Function::Handle(code.function()).ToCString());
     }
   }
@@ -10833,7 +10869,7 @@
     ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
     while (it.HasNext()) {
       cls = it.GetNextClass();
-      error = cls.EnsureIsFinalized(Isolate::Current());
+      error = cls.EnsureIsFinalized(Thread::Current());
       if (!error.IsNull()) {
         return error.raw();
       }
@@ -13285,6 +13321,24 @@
 }
 
 
+void Code::DisableDartCode() const {
+  ASSERT(IsFunctionCode());
+  ASSERT(instructions() == active_instructions());
+  const Code& new_code =
+      Code::Handle(StubCode::FixCallersTarget_entry()->code());
+  set_active_instructions(new_code.instructions());
+}
+
+
+void Code::DisableStubCode() const {
+ASSERT(IsAllocationStubCode());
+  ASSERT(instructions() == active_instructions());
+  const Code& new_code =
+      Code::Handle(StubCode::FixAllocationStubTarget_entry()->code());
+  set_active_instructions(new_code.instructions());
+}
+
+
 void Code::PrintJSONImpl(JSONStream* stream, bool ref) const {
   JSONObject jsobj(stream);
   AddCommonObjectProperties(&jsobj, "Code", ref);
@@ -14261,9 +14315,10 @@
                                       space);
     NoSafepointScope no_safepoint;
     result ^= raw;
-    result.StoreNonPointer(&result.raw_ptr()->is_user_initiated_, false);
   }
   result.set_message(message);
+  result.set_is_user_initiated(false);
+  result.set_is_vm_restart(false);
   return result.raw();
 }
 
@@ -14278,6 +14333,11 @@
 }
 
 
+void UnwindError::set_is_vm_restart(bool value) const {
+  StoreNonPointer(&raw_ptr()->is_vm_restart_, value);
+}
+
+
 const char* UnwindError::ToErrorCString() const {
   const String& msg_str = String::Handle(message());
   return msg_str.ToCString();
@@ -14295,6 +14355,8 @@
   jsobj.AddProperty("kind", "TerminationError");
   jsobj.AddServiceId(*this);
   jsobj.AddProperty("message", ToErrorCString());
+  jsobj.AddProperty("_is_user_initiated", is_user_initiated());
+  jsobj.AddProperty("_is_vm_restart", is_vm_restart());
 }
 
 
@@ -14418,9 +14480,12 @@
   if (!CheckAndCanonicalizeFields(error_str)) {
     return Instance::null();
   }
-  Instance& result = Instance::Handle();
-  const Class& cls = Class::Handle(this->clazz());
-  Array& constants = Array::Handle(cls.constants());
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  Isolate* isolate = thread->isolate();
+  Instance& result = Instance::Handle(zone);
+  const Class& cls = Class::Handle(zone, this->clazz());
+  Array& constants = Array::Handle(zone, cls.constants());
   const intptr_t constants_len = constants.Length();
   // Linear search to see whether this value is already present in the
   // list of canonicalized constants.
@@ -14439,7 +14504,23 @@
   // The value needs to be added to the list. Grow the list if
   // it is full.
   result ^= this->raw();
-  if (result.IsNew()) {
+  if (result.IsNew() ||
+      (result.InVMHeap() && (isolate != Dart::vm_isolate()))) {
+    /**
+     * When a snapshot is generated on a 64 bit architecture and then read
+     * into a 32 bit architecture, values which are Smi on the 64 bit
+     * architecture could potentially be converted to Mint objects, however
+     * since Smi values do not have any notion of canonical bits we lose
+     * that information when the object becomes a Mint.
+     * Some of these values could be literal values and end up in the
+     * VM isolate heap. Later when these values are referenced in a
+     * constant list we try to ensure that all the objects in the list
+     * are canonical and try to canonicalize them. When these Mint objects
+     * are encountered they do not have the canonical bit set and
+     * canonicalizing them won't work as the VM heap is read only now.
+     * In these cases we clone the object into the isolate and then
+     * canonicalize it.
+     */
     // Create a canonical object in old space.
     result ^= Object::Clone(result, Heap::kOld);
   }
@@ -14503,8 +14584,7 @@
   }
   Isolate* isolate = Isolate::Current();
   const Class& cls = Class::Handle(isolate, clazz());
-  TypeArguments& type_arguments =
-      TypeArguments::Handle(isolate);
+  TypeArguments& type_arguments = TypeArguments::Handle(isolate);
   if (cls.NumTypeArguments() > 0) {
     type_arguments = GetTypeArguments();
     ASSERT(type_arguments.IsNull() || type_arguments.IsCanonical());
@@ -14630,8 +14710,8 @@
 
 
 RawInstance* Instance::New(const Class& cls, Heap::Space space) {
-  Isolate* isolate = Isolate::Current();
-  if (cls.EnsureIsFinalized(isolate) != Error::null()) {
+  Thread* thread = Thread::Current();
+  if (cls.EnsureIsFinalized(thread) != Error::null()) {
     return Instance::null();
   }
   intptr_t instance_size = cls.instance_size();
@@ -15611,18 +15691,19 @@
   if (arguments() == other_type.arguments()) {
     return true;
   }
-  Isolate* isolate = Isolate::Current();
-  const Class& cls = Class::Handle(isolate, type_class());
-  const intptr_t num_type_params = cls.NumTypeParameters(isolate);
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  const Class& cls = Class::Handle(zone, type_class());
+  const intptr_t num_type_params = cls.NumTypeParameters(thread);
   if (num_type_params == 0) {
     // Shortcut unnecessary handle allocation below.
     return true;
   }
   const intptr_t num_type_args = cls.NumTypeArguments();
   const intptr_t from_index = num_type_args - num_type_params;
-  const TypeArguments& type_args = TypeArguments::Handle(isolate, arguments());
+  const TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
   const TypeArguments& other_type_args = TypeArguments::Handle(
-      isolate, other_type.arguments());
+      zone, other_type.arguments());
   if (type_args.IsNull()) {
     // Ignore from_index.
     return other_type_args.IsRaw(0, num_type_args);
@@ -15642,8 +15723,8 @@
     // depend solely on the type parameters that were just verified to match.
     ASSERT(type_args.Length() >= (from_index + num_type_params));
     ASSERT(other_type_args.Length() >= (from_index + num_type_params));
-    AbstractType& type_arg = AbstractType::Handle(isolate);
-    AbstractType& other_type_arg = AbstractType::Handle(isolate);
+    AbstractType& type_arg = AbstractType::Handle(zone);
+    AbstractType& other_type_arg = AbstractType::Handle(zone);
     for (intptr_t i = 0; i < from_index; i++) {
       type_arg = type_args.TypeAt(i);
       other_type_arg = other_type_args.TypeAt(i);
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 934697e..6a7076a 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -854,10 +854,10 @@
     return Handle(I->current_zone(), raw_ptr);
   }
   static PassiveObject& Handle(RawObject* raw_ptr) {
-    return Handle(Isolate::Current(), raw_ptr);
+    return Handle(Thread::Current()->zone(), raw_ptr);
   }
   static PassiveObject& Handle() {
-    return Handle(Isolate::Current(), Object::null());
+    return Handle(Thread::Current()->zone(), Object::null());
   }
   static PassiveObject& Handle(Zone* zone) {
     return Handle(zone, Object::null());
@@ -993,9 +993,9 @@
       return raw_ptr()->type_parameters_;
   }
   void set_type_parameters(const TypeArguments& value) const;
-  intptr_t NumTypeParameters(Isolate* isolate) const;
+  intptr_t NumTypeParameters(Thread* thread) const;
   intptr_t NumTypeParameters() const {
-    return NumTypeParameters(Isolate::Current());
+    return NumTypeParameters(Thread::Current());
   }
   static intptr_t type_parameters_offset() {
     return OFFSET_OF(RawClass, type_parameters_);
@@ -1331,7 +1331,7 @@
                       const Array& param_names,
                       const Array& param_values) const;
 
-  RawError* EnsureIsFinalized(Isolate* isolate) const;
+  RawError* EnsureIsFinalized(Thread* thread) const;
 
   // Allocate a class used for VM internal objects.
   template <class FakeObject> static RawClass* New();
@@ -3491,6 +3491,7 @@
   static RawLibrary* NativeWrappersLibrary();
   static RawLibrary* ProfilerLibrary();
   static RawLibrary* TypedDataLibrary();
+  static RawLibrary* VMServiceLibrary();
 
   // Eagerly compile all classes and functions in the library.
   static RawError* CompileAll();
@@ -4353,6 +4354,20 @@
   bool IsStubCode() const;
   bool IsFunctionCode() const;
 
+  void DisableDartCode() const;
+
+  void DisableStubCode() const;
+
+  void Enable() const {
+    if (!IsDisabled()) return;
+    ASSERT(instructions() != active_instructions());
+    set_active_instructions(instructions());
+  }
+
+  bool IsDisabled() const {
+    return instructions() != active_instructions();
+  }
+
  private:
   void set_state_bits(intptr_t bits) const;
 
@@ -4813,6 +4828,9 @@
   bool is_user_initiated() const { return raw_ptr()->is_user_initiated_; }
   void set_is_user_initiated(bool value) const;
 
+  bool is_vm_restart() const { return raw_ptr()->is_vm_restart_; }
+  void set_is_vm_restart(bool value) const;
+
   RawString* message() const { return raw_ptr()->message_; }
 
   static intptr_t InstanceSize() {
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 8c32a4a..88c77eb 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -71,6 +71,7 @@
     profiler_library_(Library::null()),
     root_library_(Library::null()),
     typed_data_library_(Library::null()),
+    vmservice_library_(Library::null()),
     libraries_(GrowableObjectArray::null()),
     pending_classes_(GrowableObjectArray::null()),
     pending_functions_(GrowableObjectArray::null()),
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index fda986d..805b9b1 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -32,6 +32,7 @@
     kMirrors,
     kProfiler,
     kTypedData,
+    kVMService,
   };
 
   ~ObjectStore();
@@ -265,6 +266,7 @@
   RawLibrary* mirrors_library() const { return mirrors_library_; }
   RawLibrary* profiler_library() const { return profiler_library_; }
   RawLibrary* typed_data_library() const { return typed_data_library_; }
+  RawLibrary* vmservice_library() const { return vmservice_library_; }
 
   void set_bootstrap_library(BootstrapLibraryId index, const Library& value) {
     switch (index) {
@@ -301,6 +303,9 @@
       case kTypedData:
         typed_data_library_ = value.raw();
         break;
+      case kVMService:
+        vmservice_library_ = value.raw();
+        break;
       default:
         UNREACHABLE();
     }
@@ -520,6 +525,7 @@
   RawLibrary* profiler_library_;
   RawLibrary* root_library_;
   RawLibrary* typed_data_library_;
+  RawLibrary* vmservice_library_;
   RawGrowableObjectArray* libraries_;
   RawGrowableObjectArray* pending_classes_;
   RawGrowableObjectArray* pending_functions_;
diff --git a/runtime/vm/os_macos.cc b/runtime/vm/os_macos.cc
index 9821221..a447e41 100644
--- a/runtime/vm/os_macos.cc
+++ b/runtime/vm/os_macos.cc
@@ -15,6 +15,9 @@
 #include <sys/time.h>  // NOLINT
 #include <sys/resource.h>  // NOLINT
 #include <unistd.h>  // NOLINT
+#if defined(TARGET_OS_IOS)
+#include <sys/sysctl.h>
+#endif
 
 #include "platform/utils.h"
 #include "vm/isolate.h"
@@ -91,7 +94,7 @@
   struct timeval boottime;
   int mib[2] = {CTL_KERN, KERN_BOOTTIME};
   size_t size = sizeof(boottime);
-  int kr = sysctl(mib, arraysize(mib), &boottime, &size, NULL, 0);
+  int kr = sysctl(mib, sizeof(mib) / sizeof(mib[0]), &boottime, &size, NULL, 0);
   ASSERT(KERN_SUCCESS == kr);
   int64_t now = GetCurrentTimeMicros();
   int64_t origin = boottime.tv_sec * kMicrosecondsPerSecond;
diff --git a/runtime/vm/pages.cc b/runtime/vm/pages.cc
index b8341e4..da7ec80 100644
--- a/runtime/vm/pages.cc
+++ b/runtime/vm/pages.cc
@@ -136,7 +136,6 @@
       prot = VirtualMemory::kReadOnly;
     }
   } else {
-    // TODO(23217): Should this really make all pages non-executable?
     prot = VirtualMemory::kReadWrite;
   }
   bool status = memory_->Protect(prot);
@@ -170,6 +169,9 @@
                              FLAG_old_gen_growth_time_ratio),
       gc_time_micros_(0),
       collections_(0) {
+  // We aren't holding the lock but no one can reference us yet.
+  UpdateMaxCapacityLocked();
+  UpdateMaxUsed();
 }
 
 
@@ -533,6 +535,32 @@
 }
 
 
+void PageSpace::UpdateMaxCapacityLocked() {
+  if (heap_ == NULL) {
+    // Some unit tests.
+    return;
+  }
+  ASSERT(heap_ != NULL);
+  ASSERT(heap_->isolate() != NULL);
+  Isolate* isolate = heap_->isolate();
+  isolate->GetHeapOldCapacityMaxMetric()->SetValue(
+      static_cast<int64_t>(usage_.capacity_in_words) * kWordSize);
+}
+
+
+void PageSpace::UpdateMaxUsed() {
+  if (heap_ == NULL) {
+    // Some unit tests.
+    return;
+  }
+  ASSERT(heap_ != NULL);
+  ASSERT(heap_->isolate() != NULL);
+  Isolate* isolate = heap_->isolate();
+  isolate->GetHeapOldUsedMaxMetric()->SetValue(
+      UsedInWords() * kWordSize);
+}
+
+
 bool PageSpace::Contains(uword addr) const {
   for (ExclusivePageIterator it(this); !it.Done(); it.Advance()) {
     if (it.page()->Contains(addr)) {
@@ -648,9 +676,9 @@
   space.AddProperty("name", "old");
   space.AddProperty("vmName", "PageSpace");
   space.AddProperty("collections", collections());
-  space.AddProperty("used", UsedInWords() * kWordSize);
-  space.AddProperty("capacity", CapacityInWords() * kWordSize);
-  space.AddProperty("external", ExternalInWords() * kWordSize);
+  space.AddProperty64("used", UsedInWords() * kWordSize);
+  space.AddProperty64("capacity", CapacityInWords() * kWordSize);
+  space.AddProperty64("external", ExternalInWords() * kWordSize);
   space.AddProperty("time", MicrosecondsToSeconds(gc_time_micros()));
   if (collections() > 0) {
     int64_t run_time = OS::GetCurrentTimeMicros() - isolate->start_time();
@@ -918,6 +946,11 @@
     freelist_[HeapPage::kExecutable].Print();
   }
 
+  UpdateMaxUsed();
+  if (heap_ != NULL) {
+    heap_->UpdateGlobalMaxUsed();
+  }
+
   isolate->thread_registry()->ResumeAllThreads();
 
   // Done, reset the task count.
diff --git a/runtime/vm/pages.h b/runtime/vm/pages.h
index e67bc81..39ef84e 100644
--- a/runtime/vm/pages.h
+++ b/runtime/vm/pages.h
@@ -218,8 +218,8 @@
            NeedsExternalGC();
   }
 
-  intptr_t UsedInWords() const { return usage_.used_in_words; }
-  intptr_t CapacityInWords() const {
+  int64_t UsedInWords() const { return usage_.used_in_words; }
+  int64_t CapacityInWords() const {
     MutexLocker ml(pages_lock_);
     return usage_.capacity_in_words;
   }
@@ -230,8 +230,13 @@
   void IncreaseCapacityInWordsLocked(intptr_t increase_in_words) {
     DEBUG_ASSERT(pages_lock_->IsOwnedByCurrentThread());
     usage_.capacity_in_words += increase_in_words;
+    UpdateMaxCapacityLocked();
   }
-  intptr_t ExternalInWords() const {
+
+  void UpdateMaxCapacityLocked();
+  void UpdateMaxUsed();
+
+  int64_t ExternalInWords() const {
     return usage_.external_in_words;
   }
   SpaceUsage GetCurrentUsage() const {
@@ -277,7 +282,8 @@
         (ExternalInWords() > max_external_in_words_);
   }
 
-  // TODO(koda): Unify protection handling.
+  // Note: Code pages are made executable/non-executable when 'read_only' is
+  // true/false, respectively.
   void WriteProtect(bool read_only);
   void WriteProtectCode(bool read_only);
 
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index a84b79e..a33c4cc 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -44,7 +44,6 @@
 DEFINE_FLAG(bool, load_deferred_eagerly, false,
     "Load deferred libraries eagerly.");
 DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations.");
-DEFINE_FLAG(bool, supermixin, false, "Allow super calls in mixins.");
 DEFINE_FLAG(bool, warn_mixin_typedef, true, "Warning on legacy mixin typedef.");
 DEFINE_FLAG(bool, link_natives_lazily, false, "Link native calls lazily");
 
@@ -11982,10 +11981,7 @@
       ASSERT(!func.IsNull());
       ASSERT(func.kind() == RawFunction::kImplicitStaticFinalGetter);
       Object& const_value = Object::Handle(Z);
-      {
-        PAUSETIMERSCOPE(T, time_compilation);
-        const_value = DartEntry::InvokeFunction(func, Object::empty_array());
-      }
+      const_value = DartEntry::InvokeFunction(func, Object::empty_array());
       if (const_value.IsError()) {
         const Error& error = Error::Cast(const_value);
         if (error.IsUnhandledException()) {
@@ -12064,11 +12060,7 @@
   const Array& args_descriptor = Array::Handle(Z,
       ArgumentsDescriptor::New(num_arguments, arguments->names()));
   Object& result = Object::Handle(Z);
-  {
-    PAUSETIMERSCOPE(T, time_compilation);
-    result = DartEntry::InvokeFunction(
-        constructor, arg_values, args_descriptor);
-  }
+  result = 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
@@ -13559,10 +13551,7 @@
 
   // Call interpolation function.
   Object& result = Object::Handle(Z);
-  {
-    PAUSETIMERSCOPE(T, time_compilation);
-    result = DartEntry::InvokeFunction(func, interpolate_arg);
-  }
+  result = DartEntry::InvokeFunction(func, interpolate_arg);
   if (result.IsUnhandledException()) {
     ReportError("%s", Error::Cast(result).ToErrorCString());
   }
@@ -13853,16 +13842,6 @@
       ReportError("class '%s' does not have a superclass",
                   String::Handle(Z, current_class().Name()).ToCString());
     }
-    if (!FLAG_supermixin) {
-      if (current_class().IsMixinApplication()) {
-        const Type& mixin_type = Type::Handle(Z, current_class().mixin());
-        if (mixin_type.type_class() == current_function().origin()) {
-          ReportError("method of mixin class '%s' may not refer to 'super'",
-                      String::Handle(Z, Class::Handle(Z,
-                          current_function().origin()).Name()).ToCString());
-        }
-      }
-    }
     const intptr_t super_pos = TokenPos();
     ConsumeToken();
     if (CurrentToken() == Token::kPERIOD) {
diff --git a/runtime/vm/port_test.cc b/runtime/vm/port_test.cc
index 34272d1..165d19c 100644
--- a/runtime/vm/port_test.cc
+++ b/runtime/vm/port_test.cc
@@ -38,7 +38,7 @@
     notify_count++;
   }
 
-  bool HandleMessage(Message* message) { return true; }
+  MessageStatus HandleMessage(Message* message) { return kOK; }
 
   int notify_count;
 };
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index b40f5fa..b08183f 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -4,6 +4,7 @@
 
 #include "vm/precompiler.h"
 
+#include "vm/code_patcher.h"
 #include "vm/compiler.h"
 #include "vm/isolate.h"
 #include "vm/log.h"
@@ -29,10 +30,11 @@
 
 
 RawError* Precompiler::CompileAll(
-    Dart_QualifiedFunctionName embedder_entry_points[]) {
+    Dart_QualifiedFunctionName embedder_entry_points[],
+    bool reset_fields) {
   LongJumpScope jump;
   if (setjmp(*jump.Set()) == 0) {
-    Precompiler precompiler(Thread::Current());
+    Precompiler precompiler(Thread::Current(), reset_fields);
     precompiler.DoCompileAll(embedder_entry_points);
     return Error::null();
   } else {
@@ -44,10 +46,11 @@
 }
 
 
-Precompiler::Precompiler(Thread* thread) :
+Precompiler::Precompiler(Thread* thread, bool reset_fields) :
   thread_(thread),
   zone_(thread->zone()),
   isolate_(thread->isolate()),
+  reset_fields_(reset_fields),
   changed_(false),
   function_count_(0),
   class_count_(0),
@@ -104,7 +107,7 @@
     ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
     while (it.HasNext()) {
       cls = it.GetNextClass();
-      error_ = cls.EnsureIsFinalized(I);
+      error_ = cls.EnsureIsFinalized(thread_);
       if (!error_.IsNull()) {
         Jump(error_);
       }
@@ -326,6 +329,8 @@
   DropUncompiledFunctions();
 
   // TODO(rmacnak): DropEmptyClasses();
+
+  BindStaticCalls();
 }
 
 
@@ -443,6 +448,12 @@
     AddClass(cls);
 
     if (field.has_initializer()) {
+      // Should not be in the middle of initialization while precompiling.
+      ASSERT(value.raw() != Object::transition_sentinel().raw());
+
+      const bool is_initialized = value.raw() != Object::sentinel().raw();
+      if (is_initialized && !reset_fields_) return;
+
       if (field.HasPrecompiledInitializer()) return;
 
       if (FLAG_trace_precompiler) {
@@ -683,4 +694,74 @@
   }
 }
 
+
+void Precompiler::BindStaticCalls() {
+  Library& lib = Library::Handle(Z);
+  Class& cls = Class::Handle(Z);
+  Array& functions = Array::Handle(Z);
+  Function& function = Function::Handle(Z);
+  GrowableObjectArray& closures = GrowableObjectArray::Handle(Z);
+
+  for (intptr_t i = 0; i < libraries_.Length(); i++) {
+    lib ^= libraries_.At(i);
+    ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
+    while (it.HasNext()) {
+      cls = it.GetNextClass();
+      if (cls.IsDynamicClass()) {
+        continue;  // class 'dynamic' is in the read-only VM isolate.
+      }
+
+      functions = cls.functions();
+      for (intptr_t j = 0; j < functions.Length(); j++) {
+        function ^= functions.At(j);
+        BindStaticCalls(function);
+      }
+
+      closures = cls.closures();
+      if (!closures.IsNull()) {
+        for (intptr_t j = 0; j < closures.Length(); j++) {
+          function ^= closures.At(j);
+          BindStaticCalls(function);
+        }
+      }
+    }
+  }
+}
+
+
+void Precompiler::BindStaticCalls(const Function& function) {
+  ASSERT(function.HasCode());
+
+  const Code& code = Code::Handle(Z, function.CurrentCode());
+
+  const Array& table = Array::Handle(Z, code.static_calls_target_table());
+  Smi& pc_offset = Smi::Handle(Z);
+  Function& target = Function::Handle(Z);
+  Code& target_code = Code::Handle(Z);
+
+  for (intptr_t i = 0; i < table.Length(); i += Code::kSCallTableEntryLength) {
+    pc_offset ^= table.At(i + Code::kSCallTableOffsetEntry);
+    target ^= table.At(i + Code::kSCallTableFunctionEntry);
+    if (target.IsNull()) {
+      target_code ^= table.At(i + Code::kSCallTableCodeEntry);
+      ASSERT(!target_code.IsNull());
+      ASSERT(!target_code.IsFunctionCode());
+      // Allocation stub or AllocateContext or AllocateArray or ...
+    } else {
+      // Static calls initially call the CallStaticFunction stub because
+      // their target might not be compiled yet. After tree shaking, all
+      // static call targets are compiled.
+      // Cf. runtime entry PatchStaticCall called from CallStaticFunction stub.
+      ASSERT(target.HasCode());
+      target_code ^= target.CurrentCode();
+      CodePatcher::PatchStaticCallAt(pc_offset.Value() + code.EntryPoint(),
+                                     code, target_code);
+    }
+  }
+
+  // We won't patch static calls anymore, so drop the static call table to save
+  // space.
+  code.set_static_calls_target_table(Object::empty_array());
+}
+
 }  // namespace dart
diff --git a/runtime/vm/precompiler.h b/runtime/vm/precompiler.h
index 1692eda..3106984 100644
--- a/runtime/vm/precompiler.h
+++ b/runtime/vm/precompiler.h
@@ -79,10 +79,11 @@
 class Precompiler : public ValueObject {
  public:
   static RawError* CompileAll(
-      Dart_QualifiedFunctionName embedder_entry_points[]);
+      Dart_QualifiedFunctionName embedder_entry_points[],
+      bool reset_fields);
 
  private:
-  explicit Precompiler(Thread* thread);
+  Precompiler(Thread* thread, bool reset_fields);
 
   void DoCompileAll(Dart_QualifiedFunctionName embedder_entry_points[]);
   void ClearAllCode();
@@ -103,6 +104,8 @@
   void CheckForNewDynamicFunctions();
 
   void DropUncompiledFunctions();
+  void BindStaticCalls();
+  void BindStaticCalls(const Function& function);
 
   Thread* thread() const { return thread_; }
   Zone* zone() const { return zone_; }
@@ -112,6 +115,8 @@
   Zone* zone_;
   Isolate* isolate_;
 
+  const bool reset_fields_;
+
   bool changed_;
   intptr_t function_count_;
   intptr_t class_count_;
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 98fd63d..079b350 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -165,7 +165,7 @@
     return;
   }
   Thread* thread = Thread::Current();
-  thread->SetThreadInterrupter(RecordSampleInterruptCallback, isolate);
+  thread->SetThreadInterrupter(RecordSampleInterruptCallback, thread);
   ThreadInterrupter::WakeUp();
 }
 
@@ -850,33 +850,35 @@
 }
 
 
-// Is |isolate| executing Dart code?
-static bool ExecutingDart(Isolate* isolate) {
-  ASSERT(isolate != NULL);
-  return (isolate->top_exit_frame_info() == 0) &&
-         (isolate->vm_tag() == VMTag::kDartTagId);
+// Is |thread| executing Dart code?
+static bool ExecutingDart(Thread* thread) {
+  ASSERT(thread != NULL);
+  return (thread->top_exit_frame_info() == 0) &&
+         (thread->vm_tag() == VMTag::kDartTagId);
 }
 
 
-// Has |isolate| exited Dart code?
-static bool ExitedDart(Isolate* isolate) {
-  return (isolate->top_exit_frame_info() != 0) &&
-         (isolate->vm_tag() != VMTag::kDartTagId);
+// Has |thread| exited Dart code?
+static bool ExitedDart(Thread* thread) {
+  return (thread->top_exit_frame_info() != 0) &&
+         (thread->vm_tag() != VMTag::kDartTagId);
 }
 
 
 // Get |isolate|'s stack boundary and verify that |sp| and |fp| are within
 // it. Return |false| if anything looks suspicious.
-static bool GetAndValidateIsolateStackBounds(Isolate* isolate,
+static bool GetAndValidateIsolateStackBounds(Thread* thread,
                                              uintptr_t sp,
                                              uintptr_t fp,
                                              uword* stack_lower,
                                              uword* stack_upper) {
+  ASSERT(thread != NULL);
+  Isolate* isolate = thread->isolate();
   ASSERT(isolate != NULL);
   ASSERT(stack_lower != NULL);
   ASSERT(stack_upper != NULL);
 #if defined(USING_SIMULATOR)
-  const bool in_dart_code = ExecutingDart(isolate);
+  const bool in_dart_code = ExecutingDart(thread);
   if (in_dart_code) {
     Simulator* simulator = isolate->simulator();
     *stack_lower = simulator->StackBase();
@@ -948,14 +950,15 @@
 }
 
 
-static Sample* SetupSample(Isolate* isolate,
+static Sample* SetupSample(Thread* thread,
                            SampleBuffer* sample_buffer,
                            ThreadId tid) {
-  ASSERT(isolate != NULL);
+  ASSERT(thread != NULL);
+  Isolate* isolate = thread->isolate();
   ASSERT(sample_buffer != NULL);
   Sample* sample = sample_buffer->ReserveSample();
   sample->Init(isolate, OS::GetCurrentTimeMicros(), tid);
-  uword vm_tag = isolate->vm_tag();
+  uword vm_tag = thread->vm_tag();
 #if defined(USING_SIMULATOR)
   // When running in the simulator, the runtime entry function address
   // (stored as the vm tag) is the address of a redirect function.
@@ -993,12 +996,14 @@
 }
 #endif
 
-void Profiler::RecordAllocation(Isolate* isolate, intptr_t cid) {
+void Profiler::RecordAllocation(Thread* thread, intptr_t cid) {
+  ASSERT(thread != NULL);
+  Isolate* isolate = thread->isolate();
   if (!CheckIsolate(isolate)) {
     return;
   }
 
-  const bool exited_dart_code = ExitedDart(isolate);
+  const bool exited_dart_code = ExitedDart(thread);
 
   SampleBuffer* sample_buffer = GetSampleBuffer(isolate);
   if (sample_buffer == NULL) {
@@ -1020,7 +1025,7 @@
       return;
     }
 
-    if (!GetAndValidateIsolateStackBounds(isolate,
+    if (!GetAndValidateIsolateStackBounds(thread,
                                           sp,
                                           fp,
                                           &stack_lower,
@@ -1029,7 +1034,7 @@
       return;
     }
 
-    Sample* sample = SetupSample(isolate,
+    Sample* sample = SetupSample(thread,
                                  sample_buffer,
                                  OSThread::GetCurrentThreadId());
     sample->SetAllocationCid(cid);
@@ -1043,7 +1048,7 @@
                                                   sp);
     native_stack_walker.walk();
   } else if (exited_dart_code) {
-    Sample* sample = SetupSample(isolate,
+    Sample* sample = SetupSample(thread,
                                  sample_buffer,
                                  OSThread::GetCurrentThreadId());
     sample->SetAllocationCid(cid);
@@ -1054,7 +1059,7 @@
   } else {
     // Fall back.
     uintptr_t pc = GetProgramCounter();
-    Sample* sample = SetupSample(isolate,
+    Sample* sample = SetupSample(thread,
                                  sample_buffer,
                                  OSThread::GetCurrentThreadId());
     sample->SetAllocationCid(cid);
@@ -1067,7 +1072,8 @@
 void Profiler::RecordSampleInterruptCallback(
     const InterruptedThreadState& state,
     void* data) {
-  Isolate* isolate = reinterpret_cast<Isolate*>(data);
+  Thread* thread = reinterpret_cast<Thread*>(data);
+  Isolate* isolate = thread->isolate();
   if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) {
     // No isolate.
     return;
@@ -1080,8 +1086,8 @@
     return;
   }
 
-  const bool exited_dart_code = ExitedDart(isolate);
-  const bool in_dart_code = ExecutingDart(isolate);
+  const bool exited_dart_code = ExitedDart(thread);
+  const bool in_dart_code = ExecutingDart(thread);
 
   uintptr_t sp = 0;
   uintptr_t fp = state.fp;
@@ -1118,7 +1124,7 @@
 
   uword stack_lower = 0;
   uword stack_upper = 0;
-  if (!GetAndValidateIsolateStackBounds(isolate,
+  if (!GetAndValidateIsolateStackBounds(thread,
                                         sp,
                                         fp,
                                         &stack_lower,
@@ -1131,7 +1137,7 @@
   // know that our initial stack and frame pointers are within the boundary.
 
   // Setup sample.
-  Sample* sample = SetupSample(isolate,
+  Sample* sample = SetupSample(thread,
                                sample_buffer,
                                OSThread::GetCurrentThreadId());
   // Increment counter for vm tag.
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index fc5ecae..3f32901 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -44,7 +44,7 @@
     return sample_buffer_;
   }
 
-  static void RecordAllocation(Isolate* isolate, intptr_t cid);
+  static void RecordAllocation(Thread* thread, intptr_t cid);
 
  private:
   static bool initialized_;
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index b6f14f0..288584a 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1471,6 +1471,7 @@
     return reinterpret_cast<RawObject**>(&ptr()->message_);
   }
   bool is_user_initiated_;
+  bool is_vm_restart_;
 };
 
 
@@ -1612,11 +1613,12 @@
 class RawMint : public RawInteger {
   RAW_HEAP_OBJECT_IMPLEMENTATION(Mint);
 
-  int64_t value_;
+  ALIGN8 int64_t value_;
 
   friend class Api;
   friend class SnapshotReader;
 };
+COMPILE_ASSERT(sizeof(RawMint) == 16);
 
 
 class RawBigint : public RawInteger {
@@ -1633,11 +1635,12 @@
 class RawDouble : public RawNumber {
   RAW_HEAP_OBJECT_IMPLEMENTATION(Double);
 
-  double value_;
+  ALIGN8 double value_;
 
   friend class Api;
   friend class SnapshotReader;
 };
+COMPILE_ASSERT(sizeof(RawDouble) == 16);
 
 
 class RawString : public RawInstance {
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index d3ec50e..aa2d0d0 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -1306,14 +1306,18 @@
 
   intptr_t length = reader->Read<intptr_t>();
 
-  ObjectPool& result =
-      ObjectPool::ZoneHandle(reader->zone(),
-                             NEW_OBJECT_WITH_LEN(ObjectPool, length));
-  reader->AddBackRef(object_id, &result, kIsDeserialized);
+  ObjectPool* result =
+      reinterpret_cast<ObjectPool*>(reader->GetBackRef(object_id));
+  if (result == NULL) {
+    result =
+        &(ObjectPool::ZoneHandle(reader->zone(),
+                                 NEW_OBJECT_WITH_LEN(ObjectPool, length)));
+    reader->AddBackRef(object_id, result, kIsDeserialized);
+  }
 
   const TypedData& info_array =
       TypedData::Handle(reader->NewTypedData(kTypedDataInt8ArrayCid, length));
-  result.set_info_array(info_array);
+  result->set_info_array(info_array);
 
   NoSafepointScope no_safepoint;
   for (intptr_t i = 0; i < length; i++) {
@@ -1323,19 +1327,19 @@
     switch (entry_type) {
       case ObjectPool::kTaggedObject: {
         (*reader->PassiveObjectHandle()) =
-            reader->ReadObjectImpl(kAsInlinedObject);
-        result.SetObjectAt(i, *(reader->PassiveObjectHandle()));
+            reader->ReadObjectImpl(kAsReference);
+        result->SetObjectAt(i, *(reader->PassiveObjectHandle()));
         break;
       }
       case ObjectPool::kImmediate: {
         intptr_t raw_value = reader->Read<intptr_t>();
-        result.SetRawValueAt(i, raw_value);
+        result->SetRawValueAt(i, raw_value);
         break;
       }
       case ObjectPool::kNativeEntry: {
         // Read nothing. Initialize with the lazy link entry.
         uword new_entry = NativeEntry::LinkNativeCallEntry();
-        result.SetRawValueAt(i, static_cast<intptr_t>(new_entry));
+        result->SetRawValueAt(i, static_cast<intptr_t>(new_entry));
         break;
       }
       default:
@@ -1343,7 +1347,7 @@
     }
   }
 
-  return result.raw();
+  return result->raw();
 }
 
 
@@ -1372,7 +1376,14 @@
     Entry& entry = ptr()->data()[i];
     switch (entry_type) {
       case ObjectPool::kTaggedObject: {
-        writer->WriteObjectImpl(entry.raw_obj_, kAsInlinedObject);
+        if (entry.raw_obj_ == StubCode::CallNativeCFunction_entry()->code()) {
+          // Natives can run while precompiling, becoming linked and switching
+          // their stub. Reset to the initial stub used for lazy-linking.
+          writer->WriteObjectImpl(
+              StubCode::CallBootstrapCFunction_entry()->code(), kAsReference);
+        } else {
+          writer->WriteObjectImpl(entry.raw_obj_, kAsReference);
+        }
         break;
       }
       case ObjectPool::kImmediate: {
@@ -1720,7 +1731,7 @@
   // Set all the object fields.
   READ_OBJECT_FIELDS(result,
                      result.raw()->from(), result.raw()->to(),
-                     kAsInlinedObject);
+                     kAsReference);
 
   return result.raw();
 }
@@ -1743,7 +1754,7 @@
   writer->Write<uint32_t>(ptr()->state_bits_);
 
   // Write out all the object pointer fields.
-  SnapshotWriterVisitor visitor(writer, kAsInlinedObject);
+  SnapshotWriterVisitor visitor(writer, kAsReference);
   visitor.VisitPointers(from(), to());
 }
 
diff --git a/runtime/vm/scavenger.cc b/runtime/vm/scavenger.cc
index e223803..f526af1 100644
--- a/runtime/vm/scavenger.cc
+++ b/runtime/vm/scavenger.cc
@@ -415,13 +415,18 @@
   if (to_ == NULL) {
     FATAL("Out of memory.\n");
   }
-
   // Setup local fields.
   top_ = FirstObjectStart();
   resolved_top_ = top_;
   end_ = to_->end();
 
   survivor_end_ = FirstObjectStart();
+
+  UpdateMaxHeapCapacity();
+  UpdateMaxHeapUsage();
+  if (heap_ != NULL) {
+    heap_->UpdateGlobalMaxUsed();
+  }
 }
 
 
@@ -459,6 +464,7 @@
     // isolate to finish scavenge, etc.).
     FATAL("Out of memory.\n");
   }
+  UpdateMaxHeapCapacity();
   top_ = FirstObjectStart();
   resolved_top_ = top_;
   end_ = to_->end();
@@ -500,6 +506,10 @@
   }
 #endif  // defined(DEBUG)
   from->Delete();
+  UpdateMaxHeapUsage();
+  if (heap_ != NULL) {
+    heap_->UpdateGlobalMaxUsed();
+  }
   if (invoke_api_callbacks && (isolate->gc_epilogue_callback() != NULL)) {
     (isolate->gc_epilogue_callback())();
   }
@@ -705,6 +715,33 @@
 }
 
 
+void Scavenger::UpdateMaxHeapCapacity() {
+  if (heap_ == NULL) {
+    // Some unit tests.
+    return;
+  }
+  ASSERT(to_ != NULL);
+  ASSERT(heap_ != NULL);
+  Isolate* isolate = heap_->isolate();
+  ASSERT(isolate != NULL);
+  isolate->GetHeapNewCapacityMaxMetric()->SetValue(
+      to_->size_in_words() * kWordSize);
+}
+
+
+void Scavenger::UpdateMaxHeapUsage() {
+  if (heap_ == NULL) {
+    // Some unit tests.
+    return;
+  }
+  ASSERT(to_ != NULL);
+  ASSERT(heap_ != NULL);
+  Isolate* isolate = heap_->isolate();
+  ASSERT(isolate != NULL);
+  isolate->GetHeapNewUsedMaxMetric()->SetValue(UsedInWords() * kWordSize);
+}
+
+
 uword Scavenger::ProcessWeakProperty(RawWeakProperty* raw_weak,
                                      ScavengerVisitor* visitor) {
   // The fate of the weak property is determined by its key.
@@ -901,9 +938,9 @@
   } else {
     space.AddProperty("avgCollectionPeriodMillis", 0.0);
   }
-  space.AddProperty("used", UsedInWords() * kWordSize);
-  space.AddProperty("capacity", CapacityInWords() * kWordSize);
-  space.AddProperty("external", ExternalInWords() * kWordSize);
+  space.AddProperty64("used", UsedInWords() * kWordSize);
+  space.AddProperty64("capacity", CapacityInWords() * kWordSize);
+  space.AddProperty64("external", ExternalInWords() * kWordSize);
   space.AddProperty("time", MicrosecondsToSeconds(gc_time_micros()));
 }
 
diff --git a/runtime/vm/scavenger.h b/runtime/vm/scavenger.h
index 00b5706..af3f129 100644
--- a/runtime/vm/scavenger.h
+++ b/runtime/vm/scavenger.h
@@ -164,13 +164,13 @@
   static intptr_t top_offset() { return OFFSET_OF(Scavenger, top_); }
   static intptr_t end_offset() { return OFFSET_OF(Scavenger, end_); }
 
-  intptr_t UsedInWords() const {
+  int64_t UsedInWords() const {
     return (top_ - FirstObjectStart()) >> kWordSizeLog2;
   }
-  intptr_t CapacityInWords() const {
+  int64_t CapacityInWords() const {
     return to_->size_in_words();
   }
-  intptr_t ExternalInWords() const {
+  int64_t ExternalInWords() const {
     return external_size_ >> kWordSizeLog2;
   }
   SpaceUsage GetCurrentUsage() const {
@@ -268,19 +268,22 @@
     return end_ < to_->end();
   }
 
+  void UpdateMaxHeapCapacity();
+  void UpdateMaxHeapUsage();
+
   void ProcessWeakTables();
 
   intptr_t NewSizeInWords(intptr_t old_size_in_words) const;
 
-  SemiSpace* to_;
-
-  Heap* heap_;
-
   // Current allocation top and end. These values are being accessed directly
   // from generated code.
   uword top_;
   uword end_;
 
+  SemiSpace* to_;
+
+  Heap* heap_;
+
   // A pointer to the first unscanned object.  Scanning completes when
   // this value meets the allocation top.
   uword resolved_top_;
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 1dc403b..70d9e43 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -672,9 +672,9 @@
   writer.WriteMessage(list);
   intptr_t len = writer.BytesWritten();
   if (FLAG_trace_service) {
-    OS::Print(
-        "vm-service: Pushing event of type %s to stream %s (%s), len %" Pd "\n",
-        event_type, stream_id, isolate->name(), len);
+    OS::Print("vm-service: Pushing ServiceEvent(isolate='%s', kind='%s',"
+              " len=%" Pd ") to stream %s\n",
+              isolate->name(), event_type, len, stream_id);
   }
   // TODO(turnidge): For now we ignore failure to send an event.  Revisit?
   PortMap::PostMessage(
@@ -770,9 +770,9 @@
     if (isolate != NULL) {
       isolate_name = isolate->name();
     }
-    OS::Print(
-        "vm-service: Pushing event of type %s to stream %s (%s)\n",
-        kind, stream_id, isolate_name);
+    OS::Print("vm-service: Pushing ServiceEvent(isolate='%s', kind='%s') "
+              "to stream %s\n",
+              isolate_name, kind, stream_id);
   }
 
   Dart_PostCObject(ServiceIsolate::Port(), &list_cobj);
@@ -2041,17 +2041,9 @@
 }
 
 
-static const MethodParameter* add_breakpoint_params[] = {
-  ISOLATE_PARAMETER,
-  new IdParameter("scriptId", false),
-  new IdParameter("scriptUri", false),
-  new UIntParameter("line", true),
-  new UIntParameter("column", false),
-  NULL,
-};
-
-
-static bool AddBreakpoint(Isolate* isolate, JSONStream* js) {
+static bool AddBreakpointCommon(Isolate* isolate,
+                                JSONStream* js,
+                                const String& script_uri) {
   const char* line_param = js->LookupParam("line");
   intptr_t line = UIntParameter::Parse(line_param);
   const char* col_param = js->LookupParam("column");
@@ -2064,28 +2056,6 @@
       return true;
     }
   }
-  const char* script_id_param = js->LookupParam("scriptId");
-  const char* script_uri_param = js->LookupParam("scriptUri");
-  if (script_id_param == NULL && script_uri_param == NULL) {
-    js->PrintError(kInvalidParams,
-                   "%s expects the 'scriptId' or the 'scriptUri' parameter",
-                   js->method());
-    return true;
-  }
-  String& script_uri = String::Handle(isolate);
-  if (script_id_param != NULL) {
-    Object& obj =
-        Object::Handle(LookupHeapObject(isolate, script_id_param, NULL));
-    if (obj.raw() == Object::sentinel().raw() || !obj.IsScript()) {
-      PrintInvalidParamError(js, "scriptId");
-      return true;
-    }
-    const Script& script = Script::Cast(obj);
-    script_uri = script.url();
-  }
-  if (script_uri_param != NULL) {
-    script_uri = String::New(script_uri_param);
-  }
   ASSERT(!script_uri.IsNull());
   Breakpoint* bpt = NULL;
   bpt = isolate->debugger()->SetBreakpointAtLineCol(script_uri, line, col);
@@ -2100,6 +2070,46 @@
 }
 
 
+static const MethodParameter* add_breakpoint_params[] = {
+  ISOLATE_PARAMETER,
+  new IdParameter("scriptId", true),
+  new UIntParameter("line", true),
+  new UIntParameter("column", false),
+  NULL,
+};
+
+
+static bool AddBreakpoint(Isolate* isolate, JSONStream* js) {
+  const char* script_id_param = js->LookupParam("scriptId");
+  Object& obj =
+      Object::Handle(LookupHeapObject(isolate, script_id_param, NULL));
+  if (obj.raw() == Object::sentinel().raw() || !obj.IsScript()) {
+    PrintInvalidParamError(js, "scriptId");
+    return true;
+  }
+  const Script& script = Script::Cast(obj);
+  const String& script_uri = String::Handle(script.url());
+  ASSERT(!script_uri.IsNull());
+  return AddBreakpointCommon(isolate, js, script_uri);
+}
+
+
+static const MethodParameter* add_breakpoint_with_script_uri_params[] = {
+  ISOLATE_PARAMETER,
+  new IdParameter("scriptUri", true),
+  new UIntParameter("line", true),
+  new UIntParameter("column", false),
+  NULL,
+};
+
+
+static bool AddBreakpointWithScriptUri(Isolate* isolate, JSONStream* js) {
+  const char* script_uri_param = js->LookupParam("scriptUri");
+  const String& script_uri = String::Handle(String::New(script_uri_param));
+  return AddBreakpointCommon(isolate, js, script_uri);
+}
+
+
 static const MethodParameter* add_breakpoint_at_entry_params[] = {
   ISOLATE_PARAMETER,
   new IdParameter("functionId", true),
@@ -2942,10 +2952,7 @@
   jsobj.AddProperty("targetCPU", CPU::Id());
   jsobj.AddProperty("hostCPU", HostCPUFeatures::hardware());
   jsobj.AddProperty("version", Version::String());
-  // Send pid as a string because it allows us to avoid any issues with
-  // pids > 53-bits (when consumed by JavaScript).
-  // TODO(johnmccutchan): Codify how integers are sent across the service.
-  jsobj.AddPropertyF("pid", "%" Pd "", OS::ProcessId());
+  jsobj.AddProperty("pid", OS::ProcessId());
   jsobj.AddProperty("_assertsEnabled", isolate->flags().asserts());
   jsobj.AddProperty("_typeChecksEnabled", isolate->flags().type_checks());
   int64_t start_time_millis = (Dart::vm_isolate()->start_time() /
@@ -2961,6 +2968,19 @@
 }
 
 
+static const MethodParameter* restart_vm_params[] = {
+  NO_ISOLATE_PARAMETER,
+  NULL,
+};
+
+
+static bool RestartVM(Isolate* isolate, JSONStream* js) {
+  Isolate::KillAllIsolates(Isolate::kVMRestartMsg);
+  PrintSuccess(js);
+  return true;
+}
+
+
 static const MethodParameter* set_exception_pause_info_params[] = {
   ISOLATE_PARAMETER,
   NULL,
@@ -3121,6 +3141,8 @@
     NULL },
   { "addBreakpoint", AddBreakpoint,
     add_breakpoint_params },
+  { "addBreakpointWithScriptUri", AddBreakpointWithScriptUri,
+    add_breakpoint_with_script_uri_params },
   { "addBreakpointAtEntry", AddBreakpointAtEntry,
     add_breakpoint_at_entry_params },
   { "_addBreakpointAtActivation", AddBreakpointAtActivation,
@@ -3185,6 +3207,8 @@
     pause_params },
   { "removeBreakpoint", RemoveBreakpoint,
     remove_breakpoint_params },
+  { "_restartVM", RestartVM,
+    restart_vm_params },
   { "resume", Resume,
     resume_params },
   { "_requestHeapSnapshot", RequestHeapSnapshot,
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index 69beec686..df05a47 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -25,6 +25,7 @@
 - [Private RPCs, Types, and Properties](#private-rpcs-types-and-properties)
 - [Public RPCs](#public-rpcs)
 	- [addBreakpoint](#addbreakpoint)
+	- [addBreakpointWithScriptUri](#addbreakpointwithscripturi)
 	- [addBreakpointAtEntry](#addbreakpointatentry)
 	- [evaluate](#evaluate)
 	- [evaluateInFrame](#evaluateinframe)
@@ -372,8 +373,7 @@
 
 ```
 Breakpoint addBreakpoint(string isolateId,
-                         string scriptId [optional],
-                         string scriptUri [optional],
+                         string scriptId,
                          int line,
                          int column [optional])
 ```
@@ -381,8 +381,41 @@
 The _addBreakpoint_ RPC is used to add a breakpoint at a specific line
 of some script.
 
-The _scriptId_ or _scriptUri_ parameter is used to specify the target
-script. One of these two parameters must always be provided.
+The _scriptId_ parameter is used to specify the target script.
+
+The _line_ parameter is used to specify the target line for the
+breakpoint. If there are multiple possible breakpoints on the target
+line, then the VM will place the breakpoint at the location which
+would execute soonest. If it is not possible to set a breakpoint at
+the target line, the breakpoint will be added at the next possible
+breakpoint location within the same function.
+
+The _column_ parameter may be optionally specified.  This is useful
+for targeting a specific breakpoint on a line with multiple possible
+breakpoints.
+
+If no breakpoint is possible at that line, the _102_ (Cannot add
+breakpoint) error code is returned.
+
+Note that breakpoints are added and removed on a per-isolate basis.
+
+See [Breakpoint](#breakpoint).
+
+### addBreakpointWithScriptUri
+
+```
+Breakpoint addBreakpointWithScriptUri(string isolateId,
+                                      string scriptUri,
+                                      int line,
+                                      int column [optional])
+```
+
+The _addBreakpoint_ RPC is used to add a breakpoint at a specific line
+of some script.  This RPC is useful when a script has not yet been
+assigned an id, for example, if a script is in a deferred library
+which has not yet been loaded.
+
+The _scriptUri_ parameter is used to specify the target script.
 
 The _line_ parameter is used to specify the target line for the
 breakpoint. If there are multiple possible breakpoints on the target
@@ -1655,11 +1688,6 @@
   // running, this will be a resume event.
   Event pauseEvent;
 
-  // The entry function for this isolate.
-  //
-  // Guaranteed to be initialized when the IsolateRunnable event fires.
-  @Function entry [optional];
-
   // The root library for this isolate.
   //
   // Guaranteed to be initialized when the IsolateRunnable event fires.
@@ -2101,7 +2129,7 @@
   string version;
 
   // The process id for the VM.
-  string pid;
+  int pid;
 
   // The time that the VM started in milliseconds since the epoch.
   //
@@ -2117,9 +2145,9 @@
 
 version | comments
 ------- | --------
-1.0 draft 1 | initial revision
-1.1 | Describe protocol version 2.0.
-1.2 | Describe protocol version 3.0.  Added UnresolvedSourceLocation.  Added Sentinel return to getIsolate.
+1.0 | initial revision
+2.0 | Describe protocol version 2.0.
+3.0 | Describe protocol version 3.0.  Added UnresolvedSourceLocation.  Added Sentinel return to getIsolate.  Add AddedBreakpointWithScriptUri.  Removed Isolate.entry. The type of VM.pid was changed from string to int.
 
 
 [discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc
index c07638f..4448820 100644
--- a/runtime/vm/service_isolate.cc
+++ b/runtime/vm/service_isolate.cc
@@ -31,95 +31,12 @@
 DEFINE_FLAG(bool, trace_service_pause_events, false,
             "Trace VM service isolate pause events.");
 
-struct ResourcesEntry {
-  const char* path_;
-  const char* resource_;
-  int length_;
-};
-
-extern ResourcesEntry __service_resources_[];
-
-class Resources {
- public:
-  static const int kNoSuchInstance = -1;
-  static int ResourceLookup(const char* path, const char** resource) {
-    ResourcesEntry* table = ResourceTable();
-    for (int i = 0; table[i].path_ != NULL; i++) {
-      const ResourcesEntry& entry = table[i];
-      if (strcmp(path, entry.path_) == 0) {
-        *resource = entry.resource_;
-        ASSERT(entry.length_ > 0);
-        return entry.length_;
-      }
-    }
-    return kNoSuchInstance;
-  }
-
-  static const char* Path(int idx) {
-    ASSERT(idx >= 0);
-    ResourcesEntry* entry = At(idx);
-    if (entry == NULL) {
-      return NULL;
-    }
-    ASSERT(entry->path_ != NULL);
-    return entry->path_;
-  }
-
-  static int Length(int idx) {
-    ASSERT(idx >= 0);
-    ResourcesEntry* entry = At(idx);
-    if (entry == NULL) {
-      return kNoSuchInstance;
-    }
-    ASSERT(entry->path_ != NULL);
-    return entry->length_;
-  }
-
-  static const uint8_t* Resource(int idx) {
-    ASSERT(idx >= 0);
-    ResourcesEntry* entry = At(idx);
-    if (entry == NULL) {
-      return NULL;
-    }
-    return reinterpret_cast<const uint8_t*>(entry->resource_);
-  }
-
- private:
-  static ResourcesEntry* At(int idx) {
-    ASSERT(idx >= 0);
-    ResourcesEntry* table = ResourceTable();
-    for (int i = 0; table[i].path_ != NULL; i++) {
-      if (idx == i) {
-        return &table[i];
-      }
-    }
-    return NULL;
-  }
-
-  static ResourcesEntry* ResourceTable() {
-    return &__service_resources_[0];
-  }
-
-  DISALLOW_ALLOCATION();
-  DISALLOW_IMPLICIT_CONSTRUCTORS(Resources);
-};
-
-
 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);
 }
 
 
-static Dart_Port ExtractPort(Isolate* isolate, Dart_Handle receivePort) {
-  const ReceivePort& rp = Api::UnwrapReceivePortHandle(isolate, receivePort);
-  if (rp.IsNull()) {
-    return ILLEGAL_PORT;
-  }
-  return rp.Id();
-}
-
-
 // These must be kept in sync with service/constants.dart
 #define VM_SERVICE_ISOLATE_EXIT_MESSAGE_ID 0
 #define VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID 1
@@ -163,217 +80,6 @@
 bool ServiceIsolate::shutting_down_ = false;
 
 
-class RegisterRunningIsolatesVisitor : public IsolateVisitor {
- public:
-  explicit RegisterRunningIsolatesVisitor(Isolate* service_isolate)
-      : IsolateVisitor(),
-        register_function_(Function::Handle(service_isolate)),
-        service_isolate_(service_isolate) {
-    ASSERT(ServiceIsolate::IsServiceIsolate(Isolate::Current()));
-    // Get library.
-    const String& library_url = Symbols::DartVMService();
-    ASSERT(!library_url.IsNull());
-    const Library& library =
-        Library::Handle(Library::LookupLibrary(library_url));
-    ASSERT(!library.IsNull());
-    // Get function.
-    const String& function_name =
-        String::Handle(String::New("_registerIsolate"));
-    ASSERT(!function_name.IsNull());
-    register_function_ = library.LookupFunctionAllowPrivate(function_name);
-    ASSERT(!register_function_.IsNull());
-  }
-
-  virtual void VisitIsolate(Isolate* isolate) {
-    ASSERT(ServiceIsolate::IsServiceIsolate(Isolate::Current()));
-    if (ServiceIsolate::IsServiceIsolateDescendant(isolate) ||
-        (isolate == Dart::vm_isolate())) {
-      // We do not register the service (and descendants) or the vm-isolate.
-      return;
-    }
-    // Setup arguments for call.
-    Dart_Port port_id = isolate->main_port();
-    const Integer& port_int = Integer::Handle(Integer::New(port_id));
-    ASSERT(!port_int.IsNull());
-    const SendPort& send_port = SendPort::Handle(SendPort::New(port_id));
-    const String& name = String::Handle(String::New(isolate->name()));
-    ASSERT(!name.IsNull());
-    const Array& args = Array::Handle(Array::New(3));
-    ASSERT(!args.IsNull());
-    args.SetAt(0, port_int);
-    args.SetAt(1, send_port);
-    args.SetAt(2, name);
-    Object& r = Object::Handle(service_isolate_);
-    r = DartEntry::InvokeFunction(register_function_, args);
-    if (FLAG_trace_service) {
-      OS::Print("vm-service: Isolate %s %" Pd64 " registered.\n",
-                name.ToCString(),
-                port_id);
-    }
-    ASSERT(!r.IsError());
-  }
-
- private:
-  Function& register_function_;
-  Isolate* service_isolate_;
-};
-
-
-
-class ServiceIsolateNatives : public AllStatic {
- public:
-  static void SendIsolateServiceMessage(Dart_NativeArguments args) {
-    NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
-    Thread* thread = arguments->thread();
-    StackZone stack_zone(thread);
-    Zone* zone = stack_zone.GetZone();  // Used by GET_NON_NULL_NATIVE_ARGUMENT.
-    HANDLESCOPE(thread);
-    GET_NON_NULL_NATIVE_ARGUMENT(SendPort, sp, arguments->NativeArgAt(0));
-    GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(1));
-
-    // Set the type of the OOB message.
-    message.SetAt(0, Smi::Handle(thread->zone(),
-                                 Smi::New(Message::kServiceOOBMsg)));
-
-    // Serialize message.
-    uint8_t* data = NULL;
-    MessageWriter writer(&data, &allocator, false);
-    writer.WriteMessage(message);
-
-    // TODO(turnidge): Throw an exception when the return value is false?
-    bool result = PortMap::PostMessage(
-        new Message(sp.Id(), data, writer.BytesWritten(),
-                    Message::kOOBPriority));
-    arguments->SetReturn(Bool::Get(result));
-  }
-
-  static void SendRootServiceMessage(Dart_NativeArguments args) {
-    NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
-    Thread* thread = arguments->thread();
-    StackZone stack_zone(thread);
-    Zone* zone = stack_zone.GetZone();  // Used by GET_NON_NULL_NATIVE_ARGUMENT.
-    HANDLESCOPE(thread);
-    GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0));
-    Service::HandleRootMessage(message);
-  }
-
-  static void OnStart(Dart_NativeArguments args) {
-    NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
-    Thread* thread = arguments->thread();
-    Isolate* isolate = thread->isolate();
-    StackZone zone(thread);
-    HANDLESCOPE(thread);
-    {
-      if (FLAG_trace_service) {
-        OS::Print("vm-service: Booting dart:vmservice library.\n");
-      }
-      // Boot the dart:vmservice library.
-      Dart_EnterScope();
-      Dart_Handle url_str =
-          Dart_NewStringFromCString(Symbols::Name(Symbols::kDartVMServiceId));
-      Dart_Handle library = Dart_LookupLibrary(url_str);
-      ASSERT(Dart_IsLibrary(library));
-      Dart_Handle result =
-          Dart_Invoke(library, Dart_NewStringFromCString("boot"), 0, NULL);
-      ASSERT(!Dart_IsError(result));
-      Dart_Port port = ExtractPort(isolate, result);
-      ASSERT(port != ILLEGAL_PORT);
-      ServiceIsolate::SetServicePort(port);
-      Dart_ExitScope();
-    }
-
-    {
-      if (FLAG_trace_service) {
-        OS::Print("vm-service: Registering running isolates.\n");
-      }
-      // Register running isolates with service.
-      RegisterRunningIsolatesVisitor register_isolates(isolate);
-      Isolate::VisitIsolates(&register_isolates);
-    }
-  }
-
-  static void OnExit(Dart_NativeArguments args) {
-    NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
-    Thread* thread = arguments->thread();
-    StackZone zone(thread);
-    HANDLESCOPE(thread);
-    {
-      if (FLAG_trace_service) {
-        OS::Print("vm-service: processed exit message.\n");
-      }
-    }
-  }
-
-  static void ListenStream(Dart_NativeArguments args) {
-    NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
-    Thread* thread = arguments->thread();
-    StackZone stack_zone(thread);
-    Zone* zone = stack_zone.GetZone();  // Used by GET_NON_NULL_NATIVE_ARGUMENT.
-    HANDLESCOPE(thread);
-    GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0));
-    bool result = Service::ListenStream(stream_id.ToCString());
-    arguments->SetReturn(Bool::Get(result));
-  }
-
-  static void CancelStream(Dart_NativeArguments args) {
-    NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
-    Thread* thread = arguments->thread();
-    StackZone stack_zone(thread);
-    Zone* zone = stack_zone.GetZone();  // Used by GET_NON_NULL_NATIVE_ARGUMENT.
-    HANDLESCOPE(thread);
-    GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0));
-    Service::CancelStream(stream_id.ToCString());
-  }
-};
-
-
-struct ServiceNativeEntry {
-  const char* name;
-  int num_arguments;
-  Dart_NativeFunction function;
-};
-
-
-static ServiceNativeEntry _ServiceNativeEntries[] = {
-  {"VMService_SendIsolateServiceMessage", 2,
-    ServiceIsolateNatives::SendIsolateServiceMessage},
-  {"VMService_SendRootServiceMessage", 1,
-    ServiceIsolateNatives::SendRootServiceMessage},
-  {"VMService_OnStart", 0,
-    ServiceIsolateNatives::OnStart },
-  {"VMService_OnExit", 0,
-    ServiceIsolateNatives::OnExit },
-  {"VMService_ListenStream", 1,
-    ServiceIsolateNatives::ListenStream },
-  {"VMService_CancelStream", 1,
-    ServiceIsolateNatives::CancelStream },
-};
-
-
-static Dart_NativeFunction ServiceNativeResolver(Dart_Handle name,
-                                                 int num_arguments,
-                                                 bool* auto_setup_scope) {
-  const Object& obj = Object::Handle(Api::UnwrapHandle(name));
-  if (!obj.IsString()) {
-    return NULL;
-  }
-  const char* function_name = obj.ToCString();
-  ASSERT(function_name != NULL);
-  ASSERT(auto_setup_scope != NULL);
-  *auto_setup_scope = true;
-  intptr_t n = sizeof(_ServiceNativeEntries) /
-               sizeof(_ServiceNativeEntries[0]);
-  for (intptr_t i = 0; i < n; i++) {
-    ServiceNativeEntry entry = _ServiceNativeEntries[i];
-    if ((strcmp(function_name, entry.name) == 0) &&
-        (num_arguments == entry.num_arguments)) {
-      return entry.function;
-    }
-  }
-  return NULL;
-}
-
-
 bool ServiceIsolate::NameEquals(const char* name) {
   ASSERT(name != NULL);
   return strcmp(name, kName) == 0;
@@ -529,7 +235,7 @@
 }
 
 
-void ServiceIsolate::MaybeInjectVMServiceLibrary(Isolate* I) {
+void ServiceIsolate::MaybeMakeServiceIsolate(Isolate* I) {
   Thread* T = Thread::Current();
   ASSERT(I == T->isolate());
   ASSERT(I != NULL);
@@ -543,46 +249,6 @@
     return;
   }
   SetServiceIsolate(I);
-
-  StackZone zone(T);
-  HANDLESCOPE(T);
-
-  // Register dart:vmservice library.
-  const String& url_str = String::Handle(Z, Symbols::DartVMService().raw());
-  const Library& library = Library::Handle(Z, Library::New(url_str));
-  library.Register();
-  library.set_native_entry_resolver(ServiceNativeResolver);
-
-  // Temporarily install our library tag handler.
-  I->set_library_tag_handler(LibraryTagHandler);
-
-  // Get script source.
-  const char* resource = NULL;
-  const char* path = "/vmservice.dart";
-  intptr_t r = Resources::ResourceLookup(path, &resource);
-  ASSERT(r != Resources::kNoSuchInstance);
-  ASSERT(resource != NULL);
-  const String& source_str = String::Handle(Z,
-      String::FromUTF8(reinterpret_cast<const uint8_t*>(resource), r));
-  ASSERT(!source_str.IsNull());
-  const Script& script = Script::Handle(Z,
-      Script::New(url_str, source_str, RawScript::kLibraryTag));
-
-  // Compile script.
-  Dart_EnterScope();  // Need to enter scope for tag handler.
-  library.SetLoadInProgress();
-  const Error& error = Error::Handle(Z, Compiler::Compile(library, script));
-  if (!error.IsNull()) {
-    OS::PrintErr("vm-service: Isolate creation error: %s\n",
-          error.ToErrorCString());
-  }
-  ASSERT(error.IsNull());
-  Dart_Handle result = Dart_FinalizeLoading(false);
-  ASSERT(!Dart_IsError(result));
-  Dart_ExitScope();
-
-  // Uninstall our library tag handler.
-  I->set_library_tag_handler(NULL);
 }
 
 
@@ -770,7 +436,7 @@
     MonitorLocker ml(monitor_);
     shutting_down_ = true;
   }
-  Isolate::KillIfExists(isolate_);
+  Isolate::KillIfExists(isolate_, Isolate::kInternalKillMsg);
   {
     MonitorLocker ml(monitor_);
     while (shutting_down_) {
@@ -805,50 +471,25 @@
 }
 
 
-Dart_Handle ServiceIsolate::GetSource(const char* name) {
-  ASSERT(name != NULL);
-  int i = 0;
-  while (true) {
-    const char* path = Resources::Path(i);
-    if (path == NULL) {
-      break;
-    }
-    ASSERT(*path != '\0');
-    // Skip the '/'.
-    path++;
-    if (strcmp(name, path) == 0) {
-      const uint8_t* str = Resources::Resource(i);
-      intptr_t length = Resources::Length(i);
-      return Dart_NewStringFromUTF8(str, length);
-    }
-    i++;
+void ServiceIsolate::BootVmServiceLibrary() {
+  const Library& vmservice_library =
+      Library::Handle(Library::LookupLibrary(Symbols::DartVMService()));
+  ASSERT(!vmservice_library.IsNull());
+  const String& boot_function_name = String::Handle(String::New("boot"));
+  const Function& boot_function =
+      Function::Handle(
+          vmservice_library.LookupFunctionAllowPrivate(boot_function_name));
+  ASSERT(!boot_function.IsNull());
+  const Object& result =
+      Object::Handle(
+          DartEntry::InvokeFunction(boot_function, Object::empty_array()));
+  ASSERT(!result.IsNull());
+  Dart_Port port = ILLEGAL_PORT;
+  if (result.IsReceivePort()) {
+    port = ReceivePort::Cast(result).Id();
   }
-  FATAL1("vm-service: Could not find embedded source file: %s ", name);
-  return Dart_Null();
-}
-
-
-Dart_Handle ServiceIsolate::LibraryTagHandler(Dart_LibraryTag tag,
-                                              Dart_Handle library,
-                                              Dart_Handle url) {
-  if (tag == Dart_kCanonicalizeUrl) {
-    // url is already canonicalized.
-    return url;
-  }
-  if (tag != Dart_kSourceTag) {
-    FATAL("ServiceIsolate::LibraryTagHandler encountered an unexpected tag.");
-  }
-  ASSERT(tag == Dart_kSourceTag);
-  const char* url_string = NULL;
-  Dart_Handle result = Dart_StringToCString(url, &url_string);
-  if (Dart_IsError(result)) {
-    return result;
-  }
-  Dart_Handle source = GetSource(url_string);
-  if (Dart_IsError(source)) {
-    return source;
-  }
-  return Dart_LoadSource(library, url, source, 0, 0);
+  ASSERT(port != ILLEGAL_PORT);
+  ServiceIsolate::SetServicePort(port);
 }
 
 }  // namespace dart
diff --git a/runtime/vm/service_isolate.h b/runtime/vm/service_isolate.h
index 86433c9..a942ec1 100644
--- a/runtime/vm/service_isolate.h
+++ b/runtime/vm/service_isolate.h
@@ -32,6 +32,8 @@
   static void SendServiceExitMessage();
   static void Shutdown();
 
+  static void BootVmServiceLibrary();
+
  private:
   static void KillServiceIsolate();
 
@@ -42,15 +44,11 @@
   static void ConstructExitMessageAndCache(Isolate* isolate);
   static void FinishedExiting();
   static void FinishedInitializing();
-  static void MaybeInjectVMServiceLibrary(Isolate* isolate);
+  static void MaybeMakeServiceIsolate(Isolate* isolate);
   static Dart_IsolateCreateCallback create_callback() {
     return create_callback_;
   }
 
-  static Dart_Handle GetSource(const char* name);
-  static Dart_Handle LibraryTagHandler(Dart_LibraryTag tag, Dart_Handle library,
-                                       Dart_Handle url);
-
   static Dart_IsolateCreateCallback create_callback_;
   static uint8_t* exit_message_;
   static intptr_t exit_message_length_;
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index 0bae8ad..406dfbb 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -29,7 +29,7 @@
     free(_msg);
   }
 
-  bool HandleMessage(Message* message) {
+  MessageStatus HandleMessage(Message* message) {
     if (_msg != NULL) {
       free(_msg);
     }
@@ -41,7 +41,7 @@
     String& response = String::Handle();
     response ^= response_obj.raw();
     _msg = strdup(response.ToCString());
-    return true;
+    return kOK;
   }
 
   const char* msg() const { return _msg; }
@@ -191,7 +191,7 @@
   service_msg =
       Eval(lib, "[0, port, '0', 'getObject', ['objectId'], ['code/0']]");
   Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_SUBSTRING("\"error\"", handler.msg());
 
   // The following test checks that a code object can be found only
@@ -201,7 +201,7 @@
                       compile_timestamp,
                       entry);
   Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_SUBSTRING("\"type\":\"Code\"", handler.msg());
   {
     // Only perform a partial match.
@@ -222,7 +222,7 @@
                       compile_timestamp,
                       address);
   Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_SUBSTRING("\"error\"", handler.msg());
 
   // Request code object at (compile_timestamp - 1)-code.EntryPoint()
@@ -233,7 +233,7 @@
                       compile_timestamp - 1,
                       address);
   Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_SUBSTRING("\"error\"", handler.msg());
 
   // Request native code at address. Expect the null code object back.
@@ -242,7 +242,7 @@
                       "['objectId'], ['code/native-%" Px "']]",
                       address);
   Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   // TODO(turnidge): It is pretty broken to return an Instance here.  Fix.
   EXPECT_SUBSTRING("\"kind\":\"Null\"",
                    handler.msg());
@@ -252,7 +252,7 @@
                       "['code/native%" Px "']]",
                       address);
   Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_SUBSTRING("\"error\"", handler.msg());
 }
 
@@ -295,7 +295,7 @@
   service_msg = EvalF(lib, "[0, port, '0', 'getObject', "
                       "['objectId'], ['objects/%" Pd "']]", id);
   Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
 
   // Check type.
   EXPECT_SUBSTRING("\"type\":\"Object\"", handler.msg());
@@ -357,7 +357,7 @@
   service_msg = EvalF(lib, "[0, port, '0', 'getObject', "
                       "['objectId'], ['objects/%" Pd "']]", id);
   Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   // Check type.
   EXPECT_SUBSTRING("\"type\":\"Object\"", handler.msg());
   EXPECT_SUBSTRING("\"_vmType\":\"PcDescriptors\"", handler.msg());
@@ -418,7 +418,7 @@
   service_msg = EvalF(lib, "[0, port, '0', 'getObject', "
                       "['objectId'], ['objects/%" Pd "']]", id);
   Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   // Check type.
   EXPECT_SUBSTRING("\"type\":\"Object\"", handler.msg());
   EXPECT_SUBSTRING("\"_vmType\":\"LocalVarDescriptors\"", handler.msg());
@@ -463,7 +463,7 @@
                 addr);
     service_msg = Eval(lib, buf);
     Service::HandleIsolateMessage(isolate, service_msg);
-    handler.HandleNextMessage();
+    EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
     EXPECT_SUBSTRING(ref ? "\"type\":\"@Instance\"" :
                            "\"type\":\"Instance\"",
                      handler.msg());
@@ -474,7 +474,7 @@
   service_msg = Eval(lib, "[0, port, '0', '_getObjectByAddress', "
                      "['address'], ['7']]");
   Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   // TODO(turnidge): Should this be a ServiceException instead?
   EXPECT_SUBSTRING("{\"type\":\"Sentinel\",\"kind\":\"Free\","
                    "\"valueAsString\":\"<free>\"",
@@ -532,12 +532,12 @@
   Array& service_msg = Array::Handle();
   service_msg = Eval(lib, "[0, port, '\"', 'alpha', [], []]");
   Service::HandleRootMessage(service_msg);
-  handler.HandleNextMessage();
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"result\":alpha,\"id\":\"\\\"\"}",
                handler.msg());
   service_msg = Eval(lib, "[0, port, 1, 'beta', [], []]");
   Service::HandleRootMessage(service_msg);
-  handler.HandleNextMessage();
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"result\":beta,\"id\":1}",
                handler.msg());
 }
@@ -572,12 +572,12 @@
   Array& service_msg = Array::Handle();
   service_msg = Eval(lib, "[0, port, '0', 'alpha', [], []]");
   Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"result\":alpha,\"id\":\"0\"}",
                handler.msg());
   service_msg = Eval(lib, "[0, port, '0', 'beta', [], []]");
   Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"result\":beta,\"id\":\"0\"}",
                handler.msg());
 }
@@ -611,21 +611,21 @@
   Array& service_msg = Array::Handle();
   service_msg = Eval(lib, "[0, port, '0', '_getCpuProfile', [], []]");
   Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   // Expect error (tags required).
   EXPECT_SUBSTRING("\"error\"", handler.msg());
 
   service_msg =
       Eval(lib, "[0, port, '0', '_getCpuProfile', ['tags'], ['None']]");
   Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   // Expect profile
   EXPECT_SUBSTRING("\"type\":\"_CpuProfile\"", handler.msg());
 
   service_msg =
       Eval(lib, "[0, port, '0', '_getCpuProfile', ['tags'], ['Bogus']]");
   Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   // Expect error.
   EXPECT_SUBSTRING("\"error\"", handler.msg());
 }
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 4b3fb8a..5419aaa 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -3868,7 +3868,7 @@
   set_register(FP, static_cast<int32_t>(fp));
   set_register(THR, reinterpret_cast<uword>(thread));
   // Set the tag.
-  isolate->set_vm_tag(VMTag::kDartTagId);
+  thread->set_vm_tag(VMTag::kDartTagId);
   // Clear top exit frame.
   isolate->set_top_exit_frame_info(0);
 
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index 3c7b99d..ac6fe18 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -3528,7 +3528,7 @@
   set_register(NULL, FP, static_cast<int64_t>(fp));
   set_register(NULL, THR, reinterpret_cast<int64_t>(thread));
   // Set the tag.
-  isolate->set_vm_tag(VMTag::kDartTagId);
+  thread->set_vm_tag(VMTag::kDartTagId);
   // Clear top exit frame.
   isolate->set_top_exit_frame_info(0);
 
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index f8da783..a6bd8de 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -2476,7 +2476,7 @@
   set_register(FP, static_cast<int32_t>(fp));
   set_register(THR, reinterpret_cast<int32_t>(thread));
   // Set the tag.
-  isolate->set_vm_tag(VMTag::kDartTagId);
+  thread->set_vm_tag(VMTag::kDartTagId);
   // Clear top exit frame.
   isolate->set_top_exit_frame_info(0);
 
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 5875720..e4c757d 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -65,6 +65,7 @@
   return class_id >= kNumPredefinedCids ||
          class_id == kArrayCid ||
          class_id == kImmutableArrayCid ||
+         class_id == kObjectPoolCid ||
          RawObject::IsImplicitFieldClassId(class_id);
 }
 
@@ -259,7 +260,7 @@
   if (cls.IsNull()) {
     SetReadException("Invalid object found in message.");
   }
-  cls.EnsureIsFinalized(isolate());
+  cls.EnsureIsFinalized(thread());
   return cls.raw();
 }
 
@@ -290,7 +291,7 @@
     if (cls_.IsNull()) {
       SetReadException("Expected a class name, but found an invalid name.");
     }
-    cls_.EnsureIsFinalized(isolate());
+    cls_.EnsureIsFinalized(thread());
     str_ ^= ReadObjectImpl(kAsInlinedObject);
     func ^= cls_.LookupFunctionAllowPrivate(str_);
   }
@@ -327,7 +328,7 @@
       OS::Print("Name of class not found %s\n", str_.ToCString());
       SetReadException("Invalid Class object found in message.");
     }
-    cls_.EnsureIsFinalized(isolate());
+    cls_.EnsureIsFinalized(thread());
     str_ ^= ReadObjectImpl(kAsInlinedObject);
     func = cls_.LookupFunctionAllowPrivate(str_);
   }
@@ -484,6 +485,16 @@
 
     return array.raw();
   }
+  if (class_id == kObjectPoolCid) {
+    ASSERT(kind_ == Snapshot::kFull);
+    // Read the length and allocate an object based on the len.
+    intptr_t len = Read<intptr_t>();
+    ObjectPool& pool = ObjectPool::ZoneHandle(zone(),
+                                              NewObjectPool(len));
+    AddBackRef(object_id, &pool, kIsNotDeserialized);
+
+    return pool.raw();
+  }
 
   // For all other internal VM classes we read the object inline.
   switch (class_id) {
@@ -2008,19 +2019,6 @@
 }
 
 
-class WritableVMIsolateScope : StackResource {
- public:
-  explicit WritableVMIsolateScope(Thread* thread) : StackResource(thread) {
-    Dart::vm_isolate()->heap()->WriteProtect(false);
-  }
-
-  ~WritableVMIsolateScope() {
-    ASSERT(Dart::vm_isolate()->heap()->UsedInWords(Heap::kNew) == 0);
-    Dart::vm_isolate()->heap()->WriteProtect(true);
-  }
-};
-
-
 void FullSnapshotWriter::WriteFullSnapshot() {
   if (!vm_isolate_is_symbolic_) {
     // TODO(asiva): Don't mutate object headers during serialization.
@@ -2275,6 +2273,29 @@
 
     return;
   }
+  if (class_id == kObjectPoolCid) {
+    intptr_t tags = GetObjectTags(raw);
+
+    // Object is being referenced, add it to the forward ref list and mark
+    // it so that future references to this object in the snapshot will use
+    // this object id. Mark it as not having been serialized yet so that we
+    // will serialize the object when we go through the forward list.
+    forward_list_->MarkAndAddObject(raw, kIsNotSerialized);
+
+    RawObjectPool* rawpool = reinterpret_cast<RawObjectPool*>(raw);
+
+    // Write out the serialization header value for this object.
+    WriteInlinedObjectHeader(kOmittedObjectId);
+
+    // Write out the class information.
+    WriteVMIsolateObject(kObjectPoolCid);
+    WriteTags(tags);
+
+    // Write out the length field.
+    Write<intptr_t>(rawpool->ptr()->length_);
+
+    return;
+  }
   // Add object to the forward ref list and mark it so that future references
   // to this object in the snapshot will use this object id. Mark it as having
   // been serialized so that we do not serialize the object when we go through
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index ff5f8a3..5f86c3b 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -203,10 +203,11 @@
 }
 
 
-bool StackFrame::FindExceptionHandler(Isolate* isolate,
+bool StackFrame::FindExceptionHandler(Thread* thread,
                                       uword* handler_pc,
                                       bool* needs_stacktrace,
                                       bool* has_catch_all) const {
+  Isolate* isolate = thread->isolate();
   REUSABLE_CODE_HANDLESCOPE(isolate);
   Code& code = reused_code_handle.Handle();
   code = LookupDartCode();
diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h
index 5dd0f14..2889a1e 100644
--- a/runtime/vm/stack_frame.h
+++ b/runtime/vm/stack_frame.h
@@ -77,7 +77,7 @@
 
   RawFunction* LookupDartFunction() const;
   RawCode* LookupDartCode() const;
-  bool FindExceptionHandler(Isolate* isolate,
+  bool FindExceptionHandler(Thread* thread,
                             uword* handler_pc,
                             bool* needs_stacktrace,
                             bool* is_catch_all) const;
diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc
index df7773d..c42c21a 100644
--- a/runtime/vm/stub_code.cc
+++ b/runtime/vm/stub_code.cc
@@ -94,8 +94,9 @@
 
 
 RawCode* StubCode::GetAllocationStubForClass(const Class& cls) {
-  Isolate* isolate = Isolate::Current();
-  const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(isolate));
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
+  const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(thread));
   ASSERT(error.IsNull());
   if (cls.id() == kArrayCid) {
     return AllocateArray_entry()->code();
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 6c6f283..5acd669 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -45,9 +45,6 @@
 
   __ EnterStubFrame();
 
-  COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R7)) != 0);
-  __ LoadIsolate(R7);
-
   // Save exit frame information to enable stack walking as we are about
   // to transition to Dart VM C++ code.
   __ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset());
@@ -55,7 +52,7 @@
 #if defined(DEBUG)
   { Label ok;
     // Check that we are always entering from Dart code.
-    __ LoadFromOffset(kWord, R6, R7, Isolate::vm_tag_offset());
+    __ LoadFromOffset(kWord, R6, THR, Thread::vm_tag_offset());
     __ CompareImmediate(R6, VMTag::kDartTagId);
     __ b(&ok, EQ);
     __ Stop("Not coming from Dart code.");
@@ -63,8 +60,8 @@
   }
 #endif
 
-  // Mark that the isolate is executing VM code.
-  __ StoreToOffset(kWord, R5, R7, Isolate::vm_tag_offset());
+  // Mark that the thread is executing VM code.
+  __ StoreToOffset(kWord, R5, THR, Thread::vm_tag_offset());
 
   // Reserve space for arguments and align frame before entering C++ world.
   // NativeArguments are passed in registers.
@@ -94,9 +91,9 @@
   // Call runtime or redirection via simulator.
   __ blx(R5);
 
-  // Mark that the isolate is executing Dart code.
+  // Mark that the thread is executing Dart code.
   __ LoadImmediate(R2, VMTag::kDartTagId);
-  __ StoreToOffset(kWord, R2, R7, Isolate::vm_tag_offset());
+  __ StoreToOffset(kWord, R2, THR, Thread::vm_tag_offset());
 
   // Reset exit frame information in Isolate structure.
   __ LoadImmediate(R2, 0);
@@ -140,9 +137,6 @@
 
   __ EnterStubFrame();
 
-  COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R7)) != 0);
-  __ LoadIsolate(R7);
-
   // Save exit frame information to enable stack walking as we are about
   // to transition to native code.
   __ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset());
@@ -150,7 +144,7 @@
 #if defined(DEBUG)
   { Label ok;
     // Check that we are always entering from Dart code.
-    __ LoadFromOffset(kWord, R6, R7, Isolate::vm_tag_offset());
+    __ LoadFromOffset(kWord, R6, THR, Thread::vm_tag_offset());
     __ CompareImmediate(R6, VMTag::kDartTagId);
     __ b(&ok, EQ);
     __ Stop("Not coming from Dart code.");
@@ -158,8 +152,8 @@
   }
 #endif
 
-  // Mark that the isolate is executing Native code.
-  __ StoreToOffset(kWord, R5, R7, Isolate::vm_tag_offset());
+  // Mark that the thread is executing native code.
+  __ StoreToOffset(kWord, R5, THR, Thread::vm_tag_offset());
 
   // Reserve space for the native arguments structure passed on the stack (the
   // outgoing pointer parameter to the native arguments structure is passed in
@@ -197,9 +191,9 @@
   __ ldr(LR, Address(THR, Thread::native_call_wrapper_entry_point_offset()));
   __ blx(LR);
 
-  // Mark that the isolate is executing Dart code.
+  // Mark that the thread is executing Dart code.
   __ LoadImmediate(R2, VMTag::kDartTagId);
-  __ StoreToOffset(kWord, R2, R7, Isolate::vm_tag_offset());
+  __ StoreToOffset(kWord, R2, THR, Thread::vm_tag_offset());
 
   // Reset exit frame information in Isolate structure.
   __ LoadImmediate(R2, 0);
@@ -224,9 +218,6 @@
 
   __ EnterStubFrame();
 
-  COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R7)) != 0);
-  __ LoadIsolate(R7);
-
   // Save exit frame information to enable stack walking as we are about
   // to transition to native code.
   __ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset());
@@ -234,7 +225,7 @@
 #if defined(DEBUG)
   { Label ok;
     // Check that we are always entering from Dart code.
-    __ LoadFromOffset(kWord, R6, R7, Isolate::vm_tag_offset());
+    __ LoadFromOffset(kWord, R6, THR, Thread::vm_tag_offset());
     __ CompareImmediate(R6, VMTag::kDartTagId);
     __ b(&ok, EQ);
     __ Stop("Not coming from Dart code.");
@@ -242,8 +233,8 @@
   }
 #endif
 
-  // Mark that the isolate is executing Native code.
-  __ StoreToOffset(kWord, R5, R7, Isolate::vm_tag_offset());
+  // Mark that the thread is executing native code.
+  __ StoreToOffset(kWord, R5, THR, Thread::vm_tag_offset());
 
   // Reserve space for the native arguments structure passed on the stack (the
   // outgoing pointer parameter to the native arguments structure is passed in
@@ -278,9 +269,9 @@
   // Call native function or redirection via simulator.
   __ blx(R5);
 
-  // Mark that the isolate is executing Dart code.
+  // Mark that the thread is executing Dart code.
   __ LoadImmediate(R2, VMTag::kDartTagId);
-  __ StoreToOffset(kWord, R2, R7, Isolate::vm_tag_offset());
+  __ StoreToOffset(kWord, R2, THR, Thread::vm_tag_offset());
 
   // Reset exit frame information in Isolate structure.
   __ LoadImmediate(R2, 0);
@@ -761,15 +752,14 @@
   if (THR != R3) {
     __ mov(THR, Operand(R3));
   }
-  __ LoadIsolate(R7);
 
   // Save the current VMTag on the stack.
-  __ LoadFromOffset(kWord, R5, R7, Isolate::vm_tag_offset());
+  __ LoadFromOffset(kWord, R5, THR, Thread::vm_tag_offset());
   __ Push(R5);
 
-  // Mark that the isolate is executing Dart code.
+  // Mark that the thread is executing Dart code.
   __ LoadImmediate(R5, VMTag::kDartTagId);
-  __ StoreToOffset(kWord, R5, R7, Isolate::vm_tag_offset());
+  __ StoreToOffset(kWord, R5, THR, Thread::vm_tag_offset());
 
   // Save top resource and top exit frame info. Use R4-6 as temporary registers.
   // StackFrameIterator reads the top exit frame info saved in this frame.
@@ -819,7 +809,6 @@
   // Get rid of arguments pushed on the stack.
   __ AddImmediate(SP, FP, kExitLinkSlotFromEntryFp * kWordSize);
 
-  __ LoadIsolate(R7);
   // Restore the saved top exit frame info and top resource back into the
   // Isolate structure. Uses R5 as a temporary register for this.
   __ Pop(R5);
@@ -829,7 +818,7 @@
 
   // Restore the current VMTag from the stack.
   __ Pop(R4);
-  __ StoreToOffset(kWord, R4, R7, Isolate::vm_tag_offset());
+  __ StoreToOffset(kWord, R4, THR, Thread::vm_tag_offset());
 
   // Restore C++ ABI callee-saved registers.
   if (TargetCPUFeatures::vfp_supported()) {
@@ -1901,10 +1890,9 @@
   __ ldr(THR, Address(SP, 4));  // Thread.
   __ mov(FP, Operand(R2));  // Frame_pointer.
   __ mov(SP, Operand(IP));  // Set Stack pointer.
-  __ LoadIsolate(R3);
   // Set the tag.
   __ LoadImmediate(R2, VMTag::kDartTagId);
-  __ StoreToOffset(kWord, R2, R3, Isolate::vm_tag_offset());
+  __ StoreToOffset(kWord, R2, THR, Thread::vm_tag_offset());
   // Clear top exit frame.
   __ LoadImmediate(R2, 0);
   __ StoreToOffset(kWord, R2, THR, Thread::top_exit_frame_info_offset());
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 41d4544..facc08c 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -46,9 +46,6 @@
   __ Comment("CallToRuntimeStub");
   __ EnterStubFrame();
 
-  COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R28)) != 0);
-  __ LoadIsolate(R28);
-
   // Save exit frame information to enable stack walking as we are about
   // to transition to Dart VM C++ code.
   __ StoreToOffset(FP, THR, Thread::top_exit_frame_info_offset());
@@ -56,7 +53,7 @@
 #if defined(DEBUG)
   { Label ok;
     // Check that we are always entering from Dart code.
-    __ LoadFromOffset(R8, R28, Isolate::vm_tag_offset());
+    __ LoadFromOffset(R8, THR, Thread::vm_tag_offset());
     __ CompareImmediate(R8, VMTag::kDartTagId);
     __ b(&ok, EQ);
     __ Stop("Not coming from Dart code.");
@@ -64,8 +61,8 @@
   }
 #endif
 
-  // Mark that the isolate is executing VM code.
-  __ StoreToOffset(R5, R28, Isolate::vm_tag_offset());
+  // Mark that the thread is executing VM code.
+  __ StoreToOffset(R5, THR, Thread::vm_tag_offset());
 
   // Reserve space for arguments and align frame before entering C++ world.
   // NativeArguments are passed in registers.
@@ -115,9 +112,9 @@
   __ mov(CSP, R26);
 
   // Retval is next to 1st argument.
-  // Mark that the isolate is executing Dart code.
+  // Mark that the thread is executing Dart code.
   __ LoadImmediate(R2, VMTag::kDartTagId);
-  __ StoreToOffset(R2, R28, Isolate::vm_tag_offset());
+  __ StoreToOffset(R2, THR, Thread::vm_tag_offset());
 
   // Reset exit frame information in Isolate structure.
   __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset());
@@ -153,9 +150,6 @@
 
   __ EnterStubFrame();
 
-  COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R28)) != 0);
-  __ LoadIsolate(R28);
-
   // Save exit frame information to enable stack walking as we are about
   // to transition to native code.
   __ StoreToOffset(FP, THR, Thread::top_exit_frame_info_offset());
@@ -163,7 +157,7 @@
 #if defined(DEBUG)
   { Label ok;
     // Check that we are always entering from Dart code.
-    __ LoadFromOffset(R6, R28, Isolate::vm_tag_offset());
+    __ LoadFromOffset(R6, THR, Thread::vm_tag_offset());
     __ CompareImmediate(R6, VMTag::kDartTagId);
     __ b(&ok, EQ);
     __ Stop("Not coming from Dart code.");
@@ -171,8 +165,8 @@
   }
 #endif
 
-  // Mark that the isolate is executing Native code.
-  __ StoreToOffset(R5, R28, Isolate::vm_tag_offset());
+  // Mark that the thread is executing native code.
+  __ StoreToOffset(R5, THR, Thread::vm_tag_offset());
 
   // Reserve space for the native arguments structure passed on the stack (the
   // outgoing pointer parameter to the native arguments structure is passed in
@@ -223,9 +217,9 @@
   __ mov(SP, CSP);
   __ mov(CSP, R26);
 
-  // Mark that the isolate is executing Dart code.
+  // Mark that the thread is executing Dart code.
   __ LoadImmediate(R2, VMTag::kDartTagId);
-  __ StoreToOffset(R2, R28, Isolate::vm_tag_offset());
+  __ StoreToOffset(R2, THR, Thread::vm_tag_offset());
 
   // Reset exit frame information in Isolate structure.
   __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset());
@@ -249,9 +243,6 @@
 
   __ EnterStubFrame();
 
-  COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R28)) != 0);
-  __ LoadIsolate(R28);
-
   // Save exit frame information to enable stack walking as we are about
   // to transition to native code.
   __ StoreToOffset(FP, THR, Thread::top_exit_frame_info_offset());
@@ -259,7 +250,7 @@
 #if defined(DEBUG)
   { Label ok;
     // Check that we are always entering from Dart code.
-    __ LoadFromOffset(R6, R28, Isolate::vm_tag_offset());
+    __ LoadFromOffset(R6, THR, Thread::vm_tag_offset());
     __ CompareImmediate(R6, VMTag::kDartTagId);
     __ b(&ok, EQ);
     __ Stop("Not coming from Dart code.");
@@ -267,8 +258,8 @@
   }
 #endif
 
-  // Mark that the isolate is executing Native code.
-  __ StoreToOffset(R5, R28, Isolate::vm_tag_offset());
+  // Mark that the thread is executing native code.
+  __ StoreToOffset(R5, THR, Thread::vm_tag_offset());
 
   // Reserve space for the native arguments structure passed on the stack (the
   // outgoing pointer parameter to the native arguments structure is passed in
@@ -316,9 +307,9 @@
   __ mov(SP, CSP);
   __ mov(CSP, R26);
 
-  // Mark that the isolate is executing Dart code.
+  // Mark that the thread is executing Dart code.
   __ LoadImmediate(R2, VMTag::kDartTagId);
-  __ StoreToOffset(R2, R28, Isolate::vm_tag_offset());
+  __ StoreToOffset(R2, THR, Thread::vm_tag_offset());
 
   // Reset exit frame information in Isolate structure.
   __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset());
@@ -821,16 +812,14 @@
   if (THR != R3) {
     __ mov(THR, R3);
   }
-  // Load Isolate pointer into temporary register R5.
-  __ LoadIsolate(R5);
 
   // Save the current VMTag on the stack.
-  __ LoadFromOffset(R4, R5, Isolate::vm_tag_offset());
+  __ LoadFromOffset(R4, THR, Thread::vm_tag_offset());
   __ Push(R4);
 
-  // Mark that the isolate is executing Dart code.
+  // Mark that the thread is executing Dart code.
   __ LoadImmediate(R6, VMTag::kDartTagId);
-  __ StoreToOffset(R6, R5, Isolate::vm_tag_offset());
+  __ StoreToOffset(R6, THR, Thread::vm_tag_offset());
 
   // Save top resource and top exit frame info. Use R6 as a temporary register.
   // StackFrameIterator reads the top exit frame info saved in this frame.
@@ -883,8 +872,6 @@
   // Get rid of arguments pushed on the stack.
   __ AddImmediate(SP, FP, kExitLinkSlotFromEntryFp * kWordSize);
 
-  __ LoadIsolate(R28);
-
   // Restore the saved top exit frame info and top resource back into the
   // Isolate structure. Uses R6 as a temporary register for this.
   __ Pop(R6);
@@ -894,7 +881,7 @@
 
   // Restore the current VMTag from the stack.
   __ Pop(R4);
-  __ StoreToOffset(R4, R28, Isolate::vm_tag_offset());
+  __ StoreToOffset(R4, THR, Thread::vm_tag_offset());
 
   // Restore the bottom 64-bits of callee-saved V registers.
   for (int i = kAbiLastPreservedFpuReg; i >= kAbiFirstPreservedFpuReg; i--) {
@@ -1973,10 +1960,9 @@
   __ mov(R0, R3);  // Exception object.
   __ mov(R1, R4);  // StackTrace object.
   __ mov(THR, R5);
-  __ LoadIsolate(R5);
   // Set the tag.
   __ LoadImmediate(R2, VMTag::kDartTagId);
-  __ StoreToOffset(R2, R5, Isolate::vm_tag_offset());
+  __ StoreToOffset(R2, THR, Thread::vm_tag_offset());
   // Clear top exit frame.
   __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset());
   __ ret();  // Jump to the exception handler code.
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index f070b1b..8ca11ef 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -49,8 +49,6 @@
 
   __ EnterFrame(0);
 
-  __ LoadIsolate(EDI);
-
   // Save exit frame information to enable stack walking as we are about
   // to transition to Dart VM C++ code.
   __ movl(Address(THR, Thread::top_exit_frame_info_offset()), EBP);
@@ -58,16 +56,15 @@
 #if defined(DEBUG)
   { Label ok;
     // Check that we are always entering from Dart code.
-    __ cmpl(Address(EDI, Isolate::vm_tag_offset()),
-            Immediate(VMTag::kDartTagId));
+    __ cmpl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
     __ j(EQUAL, &ok, Assembler::kNearJump);
     __ Stop("Not coming from Dart code.");
     __ Bind(&ok);
   }
 #endif
 
-  // Mark that the isolate is executing VM code.
-  __ movl(Address(EDI, Isolate::vm_tag_offset()), ECX);
+  // Mark that the thread is executing VM code.
+  __ movl(Assembler::VMTagAddress(), ECX);
 
   // Reserve space for arguments and align frame before entering C++ world.
   __ AddImmediate(ESP, Immediate(-INT32_SIZEOF(NativeArguments)));
@@ -87,9 +84,7 @@
   __ movl(Address(ESP, retval_offset), EAX);  // Set retval in NativeArguments.
   __ call(ECX);
 
-  // Mark that the isolate is executing Dart code. EDI is callee saved.
-  __ movl(Address(EDI, Isolate::vm_tag_offset()),
-          Immediate(VMTag::kDartTagId));
+  __ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
 
   // Reset exit frame information in Isolate structure.
   __ movl(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
@@ -125,7 +120,6 @@
 //   EAX : address of first argument in argument array.
 //   ECX : address of the native function to call.
 //   EDX : argc_tag including number of arguments and function kind.
-// Uses EDI.
 void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) {
   const intptr_t native_args_struct_offset =
       NativeEntry::kNumCallWrapperArguments * kWordSize;
@@ -140,7 +134,6 @@
 
   __ EnterFrame(0);
 
-  __ LoadIsolate(EDI);
 
   // Save exit frame information to enable stack walking as we are about
   // to transition to dart VM code.
@@ -149,16 +142,15 @@
 #if defined(DEBUG)
   { Label ok;
     // Check that we are always entering from Dart code.
-    __ cmpl(Address(EDI, Isolate::vm_tag_offset()),
-            Immediate(VMTag::kDartTagId));
+    __ cmpl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
     __ j(EQUAL, &ok, Assembler::kNearJump);
     __ Stop("Not coming from Dart code.");
     __ Bind(&ok);
   }
 #endif
 
-  // Mark that the isolate is executing Native code.
-  __ movl(Address(EDI, Isolate::vm_tag_offset()), ECX);
+  // Mark that the thread is executing native code.
+  __ movl(Assembler::VMTagAddress(), ECX);
 
   // Reserve space for the native arguments structure, the outgoing parameters
   // (pointer to the native arguments structure, the C function entry point)
@@ -182,9 +174,7 @@
   ExternalLabel label(NativeEntry::NativeCallWrapperEntry());
   __ call(&label);
 
-  // Mark that the isolate is executing Dart code. EDI is callee saved.
-  __ movl(Address(EDI, Isolate::vm_tag_offset()),
-          Immediate(VMTag::kDartTagId));
+  __ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
 
   // Reset exit frame information in Isolate structure.
   __ movl(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
@@ -200,7 +190,6 @@
 //   EAX : address of first argument in argument array.
 //   ECX : address of the native function to call.
 //   EDX : argc_tag including number of arguments and function kind.
-// Uses EDI.
 void StubCode::GenerateCallBootstrapCFunctionStub(Assembler* assembler) {
   const intptr_t native_args_struct_offset = kWordSize;
   const intptr_t thread_offset =
@@ -214,8 +203,6 @@
 
   __ EnterFrame(0);
 
-  __ LoadIsolate(EDI);
-
   // Save exit frame information to enable stack walking as we are about
   // to transition to dart VM code.
   __ movl(Address(THR, Thread::top_exit_frame_info_offset()), EBP);
@@ -223,16 +210,15 @@
 #if defined(DEBUG)
   { Label ok;
     // Check that we are always entering from Dart code.
-    __ cmpl(Address(EDI, Isolate::vm_tag_offset()),
-            Immediate(VMTag::kDartTagId));
+    __ cmpl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
     __ j(EQUAL, &ok, Assembler::kNearJump);
     __ Stop("Not coming from Dart code.");
     __ Bind(&ok);
   }
 #endif
 
-  // Mark that the isolate is executing Native code.
-  __ movl(Address(EDI, Isolate::vm_tag_offset()), ECX);
+  // Mark that the thread is executing native code.
+  __ movl(Assembler::VMTagAddress(), ECX);
 
   // Reserve space for the native arguments structure, the outgoing parameter
   // (pointer to the native arguments structure) and align frame before
@@ -252,9 +238,7 @@
   __ movl(Address(ESP, 0), EAX);  // Pass the pointer to the NativeArguments.
   __ call(ECX);
 
-  // Mark that the isolate is executing Dart code. EDI is callee saved.
-  __ movl(Address(EDI, Isolate::vm_tag_offset()),
-          Immediate(VMTag::kDartTagId));
+  __ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
 
   // Reset exit frame information in Isolate structure.
   __ movl(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
@@ -721,15 +705,13 @@
 
   // Set up THR, which caches the current thread in Dart code.
   __ movl(THR, EAX);
-  __ LoadIsolate(EDI);
 
   // Save the current VMTag on the stack.
-  __ movl(ECX, Address(EDI, Isolate::vm_tag_offset()));
+  __ movl(ECX, Assembler::VMTagAddress());
   __ pushl(ECX);
 
-  // Mark that the isolate is executing Dart code.
-  __ movl(Address(EDI, Isolate::vm_tag_offset()),
-          Immediate(VMTag::kDartTagId));
+  // Mark that the thread is executing Dart code.
+  __ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
 
   // Save top resource and top exit frame info. Use EDX as a temporary register.
   // StackFrameIterator reads the top exit frame info saved in this frame.
@@ -786,12 +768,11 @@
 
   // Restore the saved top exit frame info and top resource back into the
   // Isolate structure.
-  __ LoadIsolate(EDI);
   __ popl(Address(THR, Thread::top_exit_frame_info_offset()));
   __ popl(Address(THR, Thread::top_resource_offset()));
 
   // Restore the current VMTag from the stack.
-  __ popl(Address(EDI, Isolate::vm_tag_offset()));
+  __ popl(Assembler::VMTagAddress());
 
   // Restore C++ ABI callee-saved registers.
   __ popl(EDI);
@@ -1897,11 +1878,8 @@
   __ movl(EBP, Address(ESP, 3 * kWordSize));  // Load target frame_pointer.
   __ movl(EBX, Address(ESP, 1 * kWordSize));  // Load target PC into EBX.
   __ movl(ESP, Address(ESP, 2 * kWordSize));  // Load target stack_pointer.
-  // TODO(koda): Pass thread instead of isolate.
-  __ LoadIsolate(EDI);
   // Set tag.
-  __ movl(Address(EDI, Isolate::vm_tag_offset()),
-          Immediate(VMTag::kDartTagId));
+  __ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
   // Clear top exit frame.
   __ movl(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
   __ jmp(EBX);  // Jump to the exception handler code.
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index 36f73f7..30a7cdf 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -46,9 +46,6 @@
   __ Comment("CallToRuntimeStub");
   __ EnterStubFrame();
 
-  COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << S2)) != 0);
-  __ LoadIsolate(S2);
-
   // Save exit frame information to enable stack walking as we are about
   // to transition to Dart VM C++ code.
   __ sw(FP, Address(THR, Thread::top_exit_frame_info_offset()));
@@ -56,15 +53,15 @@
 #if defined(DEBUG)
   { Label ok;
     // Check that we are always entering from Dart code.
-    __ lw(T0, Address(S2, Isolate::vm_tag_offset()));
+    __ lw(T0, Assembler::VMTagAddress());
     __ BranchEqual(T0, Immediate(VMTag::kDartTagId), &ok);
     __ Stop("Not coming from Dart code.");
     __ Bind(&ok);
   }
 #endif
 
-  // Mark that the isolate is executing VM code.
-  __ sw(S5, Address(S2, Isolate::vm_tag_offset()));
+  // Mark that the thread is executing VM code.
+  __ sw(S5, Assembler::VMTagAddress());
 
   // Reserve space for arguments and align frame before entering C++ world.
   // NativeArguments are passed in registers.
@@ -101,9 +98,9 @@
   __ delay_slot()->addiu(A3, A2, Immediate(kWordSize));
   __ Comment("CallToRuntimeStub return");
 
-  // Mark that the isolate is executing Dart code.
+  // Mark that the thread is executing Dart code.
   __ LoadImmediate(A2, VMTag::kDartTagId);
-  __ sw(A2, Address(S2, Isolate::vm_tag_offset()));
+  __ sw(A2, Assembler::VMTagAddress());
 
   // Reset exit frame information in Isolate structure.
   __ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset()));
@@ -147,9 +144,6 @@
   __ Comment("CallNativeCFunctionStub");
   __ EnterStubFrame();
 
-  COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << S2)) != 0);
-  __ LoadIsolate(S2);
-
   // Save exit frame information to enable stack walking as we are about
   // to transition to native code.
   __ sw(FP, Address(THR, Thread::top_exit_frame_info_offset()));
@@ -157,15 +151,15 @@
 #if defined(DEBUG)
   { Label ok;
     // Check that we are always entering from Dart code.
-    __ lw(T0, Address(S2, Isolate::vm_tag_offset()));
+    __ lw(T0, Assembler::VMTagAddress());
     __ BranchEqual(T0, Immediate(VMTag::kDartTagId), &ok);
     __ Stop("Not coming from Dart code.");
     __ Bind(&ok);
   }
 #endif
 
-  // Mark that the isolate is executing Native code.
-  __ sw(T5, Address(S2, Isolate::vm_tag_offset()));
+  // Mark that the thread is executing native code.
+  __ sw(T5, Assembler::VMTagAddress());
 
   // Initialize NativeArguments structure and call native function.
   // Registers A0, A1, A2, and A3 are used.
@@ -205,9 +199,9 @@
   __ jalr(T9);
   __ Comment("CallNativeCFunctionStub return");
 
-  // Mark that the isolate is executing Dart code.
+  // Mark that the thread is executing Dart code.
   __ LoadImmediate(A2, VMTag::kDartTagId);
-  __ sw(A2, Address(S2, Isolate::vm_tag_offset()));
+  __ sw(A2, Assembler::VMTagAddress());
 
   // Reset exit frame information in Isolate structure.
   __ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset()));
@@ -232,9 +226,6 @@
   __ Comment("CallNativeCFunctionStub");
   __ EnterStubFrame();
 
-  COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << S2)) != 0);
-  __ LoadIsolate(S2);
-
   // Save exit frame information to enable stack walking as we are about
   // to transition to native code.
   __ sw(FP, Address(THR, Thread::top_exit_frame_info_offset()));
@@ -242,15 +233,15 @@
 #if defined(DEBUG)
   { Label ok;
     // Check that we are always entering from Dart code.
-    __ lw(T0, Address(S2, Isolate::vm_tag_offset()));
+    __ lw(T0, Assembler::VMTagAddress());
     __ BranchEqual(T0, Immediate(VMTag::kDartTagId), &ok);
     __ Stop("Not coming from Dart code.");
     __ Bind(&ok);
   }
 #endif
 
-  // Mark that the isolate is executing Native code.
-  __ sw(T5, Address(S2, Isolate::vm_tag_offset()));
+  // Mark that the thread is executing native code.
+  __ sw(T5, Assembler::VMTagAddress());
 
   // Initialize NativeArguments structure and call native function.
   // Registers A0, A1, A2, and A3 are used.
@@ -291,9 +282,9 @@
   __ jalr(T9);
   __ Comment("CallNativeCFunctionStub return");
 
-  // Mark that the isolate is executing Dart code.
+  // Mark that the thread is executing Dart code.
   __ LoadImmediate(A2, VMTag::kDartTagId);
-  __ sw(A2, Address(S2, Isolate::vm_tag_offset()));
+  __ sw(A2, Assembler::VMTagAddress());
 
   // Reset exit frame information in Isolate structure.
   __ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset()));
@@ -835,15 +826,14 @@
   if (THR != A3) {
     __ mov(THR, A3);
   }
-  __ LoadIsolate(T2);
 
   // Save the current VMTag on the stack.
-  __ lw(T1, Address(T2, Isolate::vm_tag_offset()));
+  __ lw(T1, Assembler::VMTagAddress());
   __ sw(T1, Address(SP, 2 * kWordSize));
 
-  // Mark that the isolate is executing Dart code.
+  // Mark that the thread is executing Dart code.
   __ LoadImmediate(T0, VMTag::kDartTagId);
-  __ sw(T0, Address(T2, Isolate::vm_tag_offset()));
+  __ sw(T0, Assembler::VMTagAddress());
 
   // Save top resource and top exit frame info. Use T0 as a temporary register.
   // StackFrameIterator reads the top exit frame info saved in this frame.
@@ -896,11 +886,10 @@
   // Get rid of arguments pushed on the stack.
   __ AddImmediate(SP, FP, kExitLinkSlotFromEntryFp * kWordSize);
 
-  __ LoadIsolate(S2);
 
   // Restore the current VMTag from the stack.
   __ lw(T1, Address(SP, 2 * kWordSize));
-  __ sw(T1, Address(S2, Isolate::vm_tag_offset()));
+  __ sw(T1, Assembler::VMTagAddress());
 
   // Restore the saved top resource and top exit frame info back into the
   // Isolate structure. Uses T0 as a temporary register for this.
@@ -2048,10 +2037,9 @@
   __ lw(V1, Address(SP, 4 * kWordSize));  // StackTrace object.
   __ mov(FP, A2);  // Frame_pointer.
   __ lw(THR, Address(SP, 5 * kWordSize));  // Thread.
-  __ LoadIsolate(A3);
   // Set tag.
   __ LoadImmediate(A2, VMTag::kDartTagId);
-  __ sw(A2, Address(A3, Isolate::vm_tag_offset()));
+  __ sw(A2, Assembler::VMTagAddress());
   // Clear top exit frame.
   __ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset()));
 
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 7b4561d..44d5f96 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -46,10 +46,6 @@
 
   __ EnterStubFrame();
 
-  COMPILE_ASSERT(
-      (CallingConventions::kCalleeSaveCpuRegisters & (1 << R12)) != 0);
-  __ LoadIsolate(R12);
-
   // Save exit frame information to enable stack walking as we are about
   // to transition to Dart VM C++ code.
   __ movq(Address(THR, Thread::top_exit_frame_info_offset()), RBP);
@@ -58,15 +54,15 @@
   { Label ok;
     // Check that we are always entering from Dart code.
     __ movq(RAX, Immediate(VMTag::kDartTagId));
-    __ cmpq(RAX, Address(R12, Isolate::vm_tag_offset()));
+    __ cmpq(RAX, Assembler::VMTagAddress());
     __ j(EQUAL, &ok, Assembler::kNearJump);
     __ Stop("Not coming from Dart code.");
     __ Bind(&ok);
   }
 #endif
 
-  // Mark that the isolate is executing VM code.
-  __ movq(Address(R12, Isolate::vm_tag_offset()), RBX);
+  // Mark that the thread is executing VM code.
+  __ movq(Assembler::VMTagAddress(), RBX);
 
   // Reserve space for arguments and align frame before entering C++ world.
   __ subq(RSP, Immediate(sizeof(NativeArguments)));
@@ -90,9 +86,8 @@
 #endif
   __ CallCFunction(RBX);
 
-  // Mark that the isolate is executing Dart code.
-  __ movq(Address(R12, Isolate::vm_tag_offset()),
-          Immediate(VMTag::kDartTagId));
+  // Mark that the thread is executing Dart code.
+  __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
 
   // Reset exit frame information in Isolate structure.
   __ movq(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
@@ -144,10 +139,6 @@
 
   __ EnterStubFrame();
 
-  COMPILE_ASSERT(
-      (CallingConventions::kCalleeSaveCpuRegisters & (1 << R12)) != 0);
-  __ LoadIsolate(R12);
-
   // Save exit frame information to enable stack walking as we are about
   // to transition to native code.
   __ movq(Address(THR, Thread::top_exit_frame_info_offset()), RBP);
@@ -156,15 +147,15 @@
   { Label ok;
     // Check that we are always entering from Dart code.
     __ movq(R8, Immediate(VMTag::kDartTagId));
-    __ cmpq(R8, Address(R12, Isolate::vm_tag_offset()));
+    __ cmpq(R8, Assembler::VMTagAddress());
     __ j(EQUAL, &ok, Assembler::kNearJump);
     __ Stop("Not coming from Dart code.");
     __ Bind(&ok);
   }
 #endif
 
-  // Mark that the isolate is executing Native code.
-  __ movq(Address(R12, Isolate::vm_tag_offset()), RBX);
+  // Mark that the thread is executing native code.
+  __ movq(Assembler::VMTagAddress(), RBX);
 
   // Reserve space for the native arguments structure passed on the stack (the
   // outgoing pointer parameter to the native arguments structure is passed in
@@ -189,9 +180,8 @@
   __ movq(RAX, Address(THR, Thread::native_call_wrapper_entry_point_offset()));
   __ CallCFunction(RAX);
 
-  // Mark that the isolate is executing Dart code.
-  __ movq(Address(R12, Isolate::vm_tag_offset()),
-          Immediate(VMTag::kDartTagId));
+  // Mark that the thread is executing Dart code.
+  __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
 
   // Reset exit frame information in Isolate structure.
   __ movq(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
@@ -220,10 +210,6 @@
 
   __ EnterStubFrame();
 
-  COMPILE_ASSERT(
-      (CallingConventions::kCalleeSaveCpuRegisters & (1 << R12)) != 0);
-  __ LoadIsolate(R12);
-
   // Save exit frame information to enable stack walking as we are about
   // to transition to native code.
   __ movq(Address(THR, Thread::top_exit_frame_info_offset()), RBP);
@@ -232,15 +218,15 @@
   { Label ok;
     // Check that we are always entering from Dart code.
     __ movq(R8, Immediate(VMTag::kDartTagId));
-    __ cmpq(R8, Address(R12, Isolate::vm_tag_offset()));
+    __ cmpq(R8, Assembler::VMTagAddress());
     __ j(EQUAL, &ok, Assembler::kNearJump);
     __ Stop("Not coming from Dart code.");
     __ Bind(&ok);
   }
 #endif
 
-  // Mark that the isolate is executing Native code.
-  __ movq(Address(R12, Isolate::vm_tag_offset()), RBX);
+  // Mark that the thread is executing native code.
+  __ movq(Assembler::VMTagAddress(), RBX);
 
   // Reserve space for the native arguments structure passed on the stack (the
   // outgoing pointer parameter to the native arguments structure is passed in
@@ -261,9 +247,8 @@
   __ movq(CallingConventions::kArg1Reg, RSP);
   __ CallCFunction(RBX);
 
-  // Mark that the isolate is executing Dart code.
-  __ movq(Address(R12, Isolate::vm_tag_offset()),
-          Immediate(VMTag::kDartTagId));
+  // Mark that the thread is executing Dart code.
+  __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
 
   // Reset exit frame information in Isolate structure.
   __ movq(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
@@ -753,17 +738,13 @@
   if (THR != kThreadReg) {
     __ movq(THR, kThreadReg);
   }
-  // Load Isolate pointer into kIsolateReg.
-  const Register kIsolateReg = RBX;
-  __ LoadIsolate(kIsolateReg);
 
   // Save the current VMTag on the stack.
-  __ movq(RAX, Address(kIsolateReg, Isolate::vm_tag_offset()));
+  __ movq(RAX, Assembler::VMTagAddress());
   __ pushq(RAX);
 
-  // Mark that the isolate is executing Dart code.
-  __ movq(Address(kIsolateReg, Isolate::vm_tag_offset()),
-          Immediate(VMTag::kDartTagId));
+  // Mark that the thread is executing Dart code.
+  __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
 
   // Save top resource and top exit frame info. Use RAX as a temporary register.
   // StackFrameIterator reads the top exit frame info saved in this frame.
@@ -833,12 +814,11 @@
 
   // Restore the saved top exit frame info and top resource back into the
   // Isolate structure.
-  __ LoadIsolate(kIsolateReg);
   __ popq(Address(THR, Thread::top_exit_frame_info_offset()));
   __ popq(Address(THR, Thread::top_resource_offset()));
 
   // Restore the current VMTag from the stack.
-  __ popq(Address(kIsolateReg, Isolate::vm_tag_offset()));
+  __ popq(Assembler::VMTagAddress());
 
   // Restore C++ ABI callee-saved registers.
   __ PopRegisters(CallingConventions::kCalleeSaveCpuRegisters,
@@ -1961,20 +1941,16 @@
   Register stacktrace_reg = RBX;
   __ movq(stacktrace_reg, Address(RSP, 5 * kWordSize));
   __ movq(THR, Address(RSP, 6 * kWordSize));
-  Register isolate_reg = RDI;
 #else
   Register stacktrace_reg = CallingConventions::kArg5Reg;
   __ movq(THR, CallingConventions::kArg6Reg);
-  Register isolate_reg = CallingConventions::kArg6Reg;
 #endif
-  __ LoadIsolate(isolate_reg);
   __ movq(RBP, CallingConventions::kArg3Reg);
   __ movq(RSP, CallingConventions::kArg2Reg);
   __ movq(kStackTraceObjectReg, stacktrace_reg);
   __ movq(kExceptionObjectReg, CallingConventions::kArg4Reg);
   // Set the tag.
-  __ movq(Address(isolate_reg, Isolate::vm_tag_offset()),
-          Immediate(VMTag::kDartTagId));
+  __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
   // Clear top exit frame.
   __ movq(Address(THR, Thread::top_exit_frame_info_offset()),
           Immediate(0));
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index c9fdbd4..d59ea20a 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -343,7 +343,7 @@
   V(DartIsolate, "dart:isolate")                                               \
   V(DartMirrors, "dart:mirrors")                                               \
   V(DartTypedData, "dart:typed_data")                                          \
-  V(DartVMService, "dart:vmservice")                                           \
+  V(DartVMService, "dart:_vmservice")                                          \
   V(DartIOLibName, "dart.io")                                                  \
   V(EvalSourceUri, "evaluate:source")                                          \
   V(_Random, "_Random")                                                        \
diff --git a/runtime/vm/tags.cc b/runtime/vm/tags.cc
index 4224a22..4349844 100644
--- a/runtime/vm/tags.cc
+++ b/runtime/vm/tags.cc
@@ -84,16 +84,16 @@
 VMTagScope::VMTagScope(Thread* thread, uword tag, bool conditional_set)
     : StackResource(thread) {
   ASSERT(isolate() != NULL);
-  previous_tag_ = isolate()->vm_tag();
+  previous_tag_ = thread->vm_tag();
   if (conditional_set) {
-    isolate()->set_vm_tag(tag);
+    thread->set_vm_tag(tag);
   }
 }
 
 
 VMTagScope::~VMTagScope() {
   ASSERT(isolate() != NULL);
-  isolate()->set_vm_tag(previous_tag_);
+  thread()->set_vm_tag(previous_tag_);
 }
 
 
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index eff0922..0828f40 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -113,7 +113,8 @@
       isolate_(NULL),
       heap_(NULL),
       store_buffer_block_(NULL),
-      log_(new class Log()) {
+      log_(new class Log()),
+      vm_tag_(0) {
   ClearState();
 
 #define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value)    \
@@ -188,7 +189,7 @@
   ASSERT(!isolate->HasMutatorThread());
   thread->isolate_ = isolate;
   isolate->MakeCurrentThreadMutator(thread);
-  isolate->set_vm_tag(VMTag::kVMTagId);
+  thread->set_vm_tag(VMTag::kVMTagId);
   ASSERT(thread->store_buffer_block_ == NULL);
   thread->StoreBufferAcquire();
   ASSERT(isolate->heap() != NULL);
@@ -209,9 +210,9 @@
   // TODO(koda): Move store_buffer_block_ into State.
   thread->StoreBufferRelease();
   if (isolate->is_runnable()) {
-    isolate->set_vm_tag(VMTag::kIdleTagId);
+    thread->set_vm_tag(VMTag::kIdleTagId);
   } else {
-    isolate->set_vm_tag(VMTag::kLoadWaitTagId);
+    thread->set_vm_tag(VMTag::kLoadWaitTagId);
   }
   isolate->ClearMutatorThread();
   thread->isolate_ = NULL;
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 00f601f..1a7d48f 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -282,6 +282,16 @@
     state_.long_jump_base = value;
   }
 
+  uword vm_tag() const {
+    return vm_tag_;
+  }
+  void set_vm_tag(uword tag) {
+    vm_tag_ = tag;
+  }
+  static intptr_t vm_tag_offset() {
+    return OFFSET_OF(Thread, vm_tag_);
+  }
+
   ThreadId id() const {
     ASSERT(id_ != OSThread::kInvalidThreadId);
     return id_;
@@ -304,6 +314,7 @@
   Mutex timeline_block_lock_;
   StoreBufferBlock* store_buffer_block_;
   class Log* log_;
+  uword vm_tag_;
 #define DECLARE_MEMBERS(type_name, member_name, expr, default_init_value)      \
   type_name member_name;
 CACHED_CONSTANTS_LIST(DECLARE_MEMBERS)
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index d55a8dc..1a8536a 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -479,6 +479,36 @@
 }
 
 
+DartTimelineEvent::DartTimelineEvent()
+    : isolate_(NULL),
+      event_as_json_(NULL) {
+}
+
+
+DartTimelineEvent::~DartTimelineEvent() {
+  Clear();
+}
+
+
+void DartTimelineEvent::Clear() {
+  if (isolate_ != NULL) {
+    isolate_ = NULL;
+  }
+  if (event_as_json_ != NULL) {
+    free(event_as_json_);
+    event_as_json_ = NULL;
+  }
+}
+
+
+void DartTimelineEvent::Init(Isolate* isolate, const char* event) {
+  ASSERT(isolate_ == NULL);
+  ASSERT(event != NULL);
+  isolate_ = isolate;
+  event_as_json_ = strdup(event);
+}
+
+
 TimelineEventRecorder::TimelineEventRecorder()
     : global_block_(NULL),
       async_id_(0) {
@@ -550,6 +580,21 @@
 }
 
 
+// Trims the ']' character.
+static void TrimOutput(char* output,
+                       intptr_t* output_length) {
+  ASSERT(output != NULL);
+  ASSERT(output_length != NULL);
+  ASSERT(*output_length >= 2);
+  // We expect the first character to be the opening of an array.
+  ASSERT(output[0] == '[');
+  // We expect the last character to be the closing of an array.
+  ASSERT(output[*output_length - 1] == ']');
+  // Skip the ].
+  *output_length -= 1;
+}
+
+
 void TimelineEventRecorder::WriteTo(const char* directory) {
   Dart_FileOpenCallback file_open = Isolate::file_open_callback();
   Dart_FileWriteCallback file_write = Isolate::file_write_callback();
@@ -557,13 +602,11 @@
   if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) {
     return;
   }
+  Thread* T = Thread::Current();
+  StackZone zone(T);
 
   Timeline::ReclaimAllBlocks();
 
-  JSONStream js;
-  TimelineEventFilter filter;
-  PrintJSON(&js, &filter);
-
   intptr_t pid = OS::ProcessId();
   char* filename = OS::SCreate(NULL,
       "%s/dart-timeline-%" Pd ".json", directory, pid);
@@ -574,8 +617,43 @@
     return;
   }
   free(filename);
-  (*file_write)(js.buffer()->buf(), js.buffer()->length(), file);
+
+  JSONStream js;
+  TimelineEventFilter filter;
+  PrintTraceEvent(&js, &filter);
+  // Steal output from JSONStream.
+  char* output = NULL;
+  intptr_t output_length = 0;
+  js.Steal(const_cast<const char**>(&output), &output_length);
+  TrimOutput(output, &output_length);
+  ASSERT(output_length >= 1);
+  (*file_write)(output, output_length, file);
+  // Free the stolen output.
+  free(output);
+
+  const char* dart_events =
+      DartTimelineEventIterator::PrintTraceEvents(this,
+                                                  zone.GetZone(),
+                                                  NULL);
+
+  // If we wrote out vm events and have dart events, write out the comma.
+  if ((output_length > 1) && (dart_events != NULL)) {
+    // Write out the ',' character.
+    const char* comma = ",";
+    (*file_write)(comma, 1, file);
+  }
+
+  // Write out the Dart events.
+  if (dart_events != NULL) {
+    (*file_write)(dart_events, strlen(dart_events), file);
+  }
+
+  // Write out the ']' character.
+  const char* array_close = "]";
+  (*file_write)(array_close, 1, file);
   (*file_close)(file);
+
+  return;
 }
 
 
@@ -615,7 +693,10 @@
     : blocks_(NULL),
       capacity_(capacity),
       num_blocks_(0),
-      block_cursor_(0) {
+      block_cursor_(0),
+      dart_events_(NULL),
+      dart_events_capacity_(capacity),
+      dart_events_cursor_(0) {
   // Capacity must be a multiple of TimelineEventBlock::kBlockSize
   ASSERT((capacity % TimelineEventBlock::kBlockSize) == 0);
   // Allocate blocks array.
@@ -631,6 +712,13 @@
   for (intptr_t i = 0; i < num_blocks_ - 1; i++) {
     blocks_[i]->set_next(blocks_[i + 1]);
   }
+  // Pre-allocate DartTimelineEvents.
+  dart_events_ =
+      reinterpret_cast<DartTimelineEvent**>(
+          calloc(dart_events_capacity_, sizeof(DartTimelineEvent*)));
+  for (intptr_t i = 0; i < dart_events_capacity_; i++) {
+    dart_events_[i] = new DartTimelineEvent();
+  }
 }
 
 
@@ -641,6 +729,12 @@
     delete block;
   }
   free(blocks_);
+  // Delete all DartTimelineEvents.
+  for (intptr_t i = 0; i < dart_events_capacity_; i++) {
+    DartTimelineEvent* event = dart_events_[i];
+    delete event;
+  }
+  free(dart_events_);
 }
 
 
@@ -681,6 +775,33 @@
 }
 
 
+void TimelineEventRingRecorder::AppendDartEvent(Isolate* isolate,
+                                                const char* event) {
+  MutexLocker ml(&lock_);
+  // TODO(johnmccutchan): If locking becomes an issue, use the Isolate to store
+  // the events.
+  if (dart_events_cursor_ == dart_events_capacity_) {
+    dart_events_cursor_ = 0;
+  }
+  ASSERT(dart_events_[dart_events_cursor_] != NULL);
+  dart_events_[dart_events_cursor_]->Clear();
+  dart_events_[dart_events_cursor_]->Init(isolate, event);
+  dart_events_cursor_++;
+}
+
+
+intptr_t TimelineEventRingRecorder::NumDartEventsLocked() {
+  return dart_events_capacity_;
+}
+
+
+DartTimelineEvent* TimelineEventRingRecorder::DartEventAtLocked(intptr_t i) {
+  ASSERT(i >= 0);
+  ASSERT(i < dart_events_capacity_);
+  return dart_events_[i];
+}
+
+
 void TimelineEventRingRecorder::PrintTraceEvent(JSONStream* js,
                                                 TimelineEventFilter* filter) {
   JSONArray events(js);
@@ -761,6 +882,25 @@
 }
 
 
+void TimelineEventStreamingRecorder::AppendDartEvent(Isolate* isolate,
+                                                     const char* event) {
+  if (event != NULL) {
+    StreamDartEvent(event);
+  }
+}
+
+
+intptr_t TimelineEventStreamingRecorder::NumDartEventsLocked() {
+  return 0;
+}
+
+
+DartTimelineEvent* TimelineEventStreamingRecorder::DartEventAtLocked(
+    intptr_t i) {
+  return NULL;
+}
+
+
 TimelineEvent* TimelineEventStreamingRecorder::StartEvent() {
   TimelineEvent* event = new TimelineEvent();
   return event;
@@ -775,7 +915,10 @@
 
 TimelineEventEndlessRecorder::TimelineEventEndlessRecorder()
     : head_(NULL),
-      block_index_(0) {
+      block_index_(0),
+      dart_events_(NULL),
+      dart_events_capacity_(0),
+      dart_events_cursor_(0) {
 }
 
 
@@ -800,6 +943,31 @@
 }
 
 
+void TimelineEventEndlessRecorder::AppendDartEvent(Isolate* isolate,
+                                                   const char* event) {
+  MutexLocker ml(&lock_);
+  // TODO(johnmccutchan): If locking becomes an issue, use the Isolate to store
+  // the events.
+  if (dart_events_cursor_ == dart_events_capacity_) {
+    // Grow.
+    intptr_t new_capacity =
+        (dart_events_capacity_ == 0) ? 16 : dart_events_capacity_ * 2;
+    dart_events_ = reinterpret_cast<DartTimelineEvent**>(
+        realloc(dart_events_, new_capacity * sizeof(DartTimelineEvent*)));
+    for (intptr_t i = dart_events_capacity_; i < new_capacity; i++) {
+      // Fill with NULLs.
+      dart_events_[i] = NULL;
+    }
+    dart_events_capacity_ = new_capacity;
+  }
+  ASSERT(dart_events_cursor_ < dart_events_capacity_);
+  DartTimelineEvent* dart_event = new DartTimelineEvent();
+  dart_event->Init(isolate, event);
+  ASSERT(dart_events_[dart_events_cursor_] == NULL);
+  dart_events_[dart_events_cursor_++] = dart_event;
+}
+
+
 TimelineEventBlock* TimelineEventEndlessRecorder::GetHeadBlockLocked() {
   return head_;
 }
@@ -833,6 +1001,19 @@
 }
 
 
+intptr_t TimelineEventEndlessRecorder::NumDartEventsLocked() {
+  return dart_events_cursor_;
+}
+
+
+DartTimelineEvent* TimelineEventEndlessRecorder::DartEventAtLocked(
+    intptr_t i) {
+  ASSERT(i >= 0);
+  ASSERT(i < dart_events_cursor_);
+  return dart_events_[i];
+}
+
+
 void TimelineEventEndlessRecorder::PrintJSONEvents(
     JSONArray* events,
     TimelineEventFilter* filter) const {
@@ -1000,4 +1181,80 @@
   return r;
 }
 
+
+DartTimelineEventIterator::DartTimelineEventIterator(
+    TimelineEventRecorder* recorder)
+    : cursor_(0),
+      num_events_(0),
+      recorder_(NULL) {
+  Reset(recorder);
+}
+
+
+DartTimelineEventIterator::~DartTimelineEventIterator() {
+  Reset(NULL);
+}
+
+
+void DartTimelineEventIterator::Reset(TimelineEventRecorder* recorder) {
+  // Clear state.
+  cursor_ = 0;
+  num_events_ = 0;
+  if (recorder_ != NULL) {
+    // Unlock old recorder.
+    recorder_->lock_.Unlock();
+  }
+  recorder_ = recorder;
+  if (recorder_ == NULL) {
+    return;
+  }
+  // Lock new recorder.
+  recorder_->lock_.Lock();
+  cursor_ = 0;
+  num_events_ = recorder_->NumDartEventsLocked();
+}
+
+
+bool DartTimelineEventIterator::HasNext() const {
+  return cursor_ < num_events_;
+}
+
+
+DartTimelineEvent* DartTimelineEventIterator::Next() {
+  ASSERT(cursor_ < num_events_);
+  DartTimelineEvent* r = recorder_->DartEventAtLocked(cursor_);
+  cursor_++;
+  return r;
+}
+
+const char* DartTimelineEventIterator::PrintTraceEvents(
+    TimelineEventRecorder* recorder,
+    Zone* zone,
+    Isolate* isolate) {
+  if (recorder == NULL) {
+    return NULL;
+  }
+
+  if (zone == NULL) {
+    return NULL;
+  }
+
+  char* result = NULL;
+  DartTimelineEventIterator iterator(recorder);
+  while (iterator.HasNext()) {
+    DartTimelineEvent* event = iterator.Next();
+    if (!event->IsValid()) {
+      // Skip invalid
+      continue;
+    }
+    if ((isolate != NULL) && (isolate != event->isolate())) {
+      // If an isolate was specified, skip events from other isolates.
+      continue;
+    }
+    ASSERT(event->event_as_json() != NULL);
+    result = zone->ConcatStrings(result, event->event_as_json());
+  }
+  return result;
+}
+
 }  // namespace dart
diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h
index 669652b..962a207 100644
--- a/runtime/vm/timeline.h
+++ b/runtime/vm/timeline.h
@@ -15,17 +15,20 @@
 class JSONStream;
 class Object;
 class ObjectPointerVisitor;
+class Isolate;
 class RawArray;
 class Thread;
 class TimelineEvent;
 class TimelineEventBlock;
 class TimelineEventRecorder;
 class TimelineStream;
+class Zone;
 
 // (name, enabled by default for isolate).
 #define ISOLATE_TIMELINE_STREAM_LIST(V)                                        \
   V(API, false)                                                                \
   V(Compiler, false)                                                           \
+  V(Dart, false)                                                               \
   V(Embedder, false)                                                           \
   V(GC, false)                                                                 \
   V(Isolate, false)                                                            \
@@ -204,6 +207,8 @@
   void Init(EventType event_type, const char* label);
 
   void set_event_type(EventType event_type) {
+    // We only reserve 4 bits to hold the event type.
+    COMPILE_ASSERT(kNumEventTypes < 16);
     state_ = EventTypeField::update(event_type, state_);
   }
 
@@ -480,6 +485,39 @@
 };
 
 
+// Timeline events from Dart code are eagerly converted to JSON and stored
+// as a C string.
+class DartTimelineEvent {
+ public:
+  DartTimelineEvent();
+  ~DartTimelineEvent();
+
+  void Clear();
+
+  // This function makes a copy of |event|.
+  void Init(Isolate* isolate, const char* event);
+
+  bool IsValid() const {
+    return (isolate_ != NULL) &&
+           (event_as_json_ != NULL);
+  }
+
+  Isolate* isolate() const {
+    return isolate_;
+  }
+
+  char* event_as_json() const {
+    return event_as_json_;
+  }
+
+ private:
+  Isolate* isolate_;
+  char* event_as_json_;
+
+  DISALLOW_COPY_AND_ASSIGN(DartTimelineEvent);
+};
+
+
 // Recorder of |TimelineEvent|s.
 class TimelineEventRecorder {
  public:
@@ -496,6 +534,9 @@
 
   void FinishBlock(TimelineEventBlock* block);
 
+  // Interface method(s) which must be implemented.
+  virtual void AppendDartEvent(Isolate* isolate, const char* event) = 0;
+
  protected:
   void WriteTo(const char* directory);
 
@@ -504,6 +545,8 @@
   virtual void CompleteEvent(TimelineEvent* event) = 0;
   virtual TimelineEventBlock* GetHeadBlockLocked() = 0;
   virtual TimelineEventBlock* GetNewBlockLocked(Isolate* isolate) = 0;
+  virtual intptr_t NumDartEventsLocked() = 0;
+  virtual DartTimelineEvent* DartEventAtLocked(intptr_t i) = 0;
 
   // Utility method(s).
   void PrintJSONMeta(JSONArray* array) const;
@@ -517,6 +560,7 @@
 
   uintptr_t async_id_;
 
+  friend class DartTimelineEventIterator;
   friend class TimelineEvent;
   friend class TimelineEventBlockIterator;
   friend class TimelineStream;
@@ -539,12 +583,16 @@
   void PrintJSON(JSONStream* js, TimelineEventFilter* filter);
   void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter);
 
+  void AppendDartEvent(Isolate* isolate, const char* event);
+
  protected:
   TimelineEvent* StartEvent();
   void CompleteEvent(TimelineEvent* event);
   TimelineEventBlock* GetHeadBlockLocked();
   intptr_t FindOldestBlockIndex() const;
   TimelineEventBlock* GetNewBlockLocked(Isolate* isolate);
+  intptr_t NumDartEventsLocked();
+  DartTimelineEvent* DartEventAtLocked(intptr_t i);
 
   void PrintJSONEvents(JSONArray* array, TimelineEventFilter* filter) const;
 
@@ -552,6 +600,10 @@
   intptr_t capacity_;
   intptr_t num_blocks_;
   intptr_t block_cursor_;
+
+  DartTimelineEvent** dart_events_;
+  intptr_t dart_events_capacity_;
+  intptr_t dart_events_cursor_;
 };
 
 
@@ -564,9 +616,12 @@
   void PrintJSON(JSONStream* js, TimelineEventFilter* filter);
   void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter);
 
+  void AppendDartEvent(Isolate* isolate, const char* event);
+
   // Called when |event| is ready to be streamed. It is unsafe to keep a
   // reference to |event| as it may be freed as soon as this function returns.
   virtual void StreamEvent(TimelineEvent* event) = 0;
+  virtual void StreamDartEvent(const char* event) = 0;
 
  protected:
   TimelineEventBlock* GetNewBlockLocked(Isolate* isolate) {
@@ -575,6 +630,8 @@
   TimelineEventBlock* GetHeadBlockLocked() {
     return NULL;
   }
+  intptr_t NumDartEventsLocked();
+  DartTimelineEvent* DartEventAtLocked(intptr_t i);
   TimelineEvent* StartEvent();
   void CompleteEvent(TimelineEvent* event);
 };
@@ -590,11 +647,15 @@
   void PrintJSON(JSONStream* js, TimelineEventFilter* filter);
   void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter);
 
+  void AppendDartEvent(Isolate* isolate, const char* event);
+
  protected:
   TimelineEvent* StartEvent();
   void CompleteEvent(TimelineEvent* event);
   TimelineEventBlock* GetNewBlockLocked(Isolate* isolate);
   TimelineEventBlock* GetHeadBlockLocked();
+  intptr_t NumDartEventsLocked();
+  DartTimelineEvent* DartEventAtLocked(intptr_t i);
 
   void PrintJSONEvents(JSONArray* array, TimelineEventFilter* filter) const;
 
@@ -604,6 +665,10 @@
   TimelineEventBlock* head_;
   intptr_t block_index_;
 
+  DartTimelineEvent** dart_events_;
+  intptr_t dart_events_capacity_;
+  intptr_t dart_events_cursor_;
+
   friend class TimelineTestHelper;
 };
 
@@ -627,6 +692,33 @@
   TimelineEventRecorder* recorder_;
 };
 
+
+// An iterator for timeline events.
+class DartTimelineEventIterator {
+ public:
+  explicit DartTimelineEventIterator(TimelineEventRecorder* recorder);
+  ~DartTimelineEventIterator();
+
+  void Reset(TimelineEventRecorder* recorder);
+
+  // Returns true if there is another event.
+  bool HasNext() const;
+
+  // Returns the next event and moves forward.
+  DartTimelineEvent* Next();
+
+  // Returns a zone allocated string of all trace events for isolate.
+  // If isolate is NULL, all isolates' events will be included.
+  static const char* PrintTraceEvents(TimelineEventRecorder* recorder,
+                                      Zone* zone,
+                                      Isolate* isolate);
+
+ private:
+  intptr_t cursor_;
+  intptr_t num_events_;
+  TimelineEventRecorder* recorder_;
+};
+
 }  // namespace dart
 
 #endif  // VM_TIMELINE_H_
diff --git a/runtime/vm/timeline_test.cc b/runtime/vm/timeline_test.cc
index e023e28..617e8fe 100644
--- a/runtime/vm/timeline_test.cc
+++ b/runtime/vm/timeline_test.cc
@@ -216,6 +216,10 @@
     counts_[event->event_type()]++;
   }
 
+  void StreamDartEvent(const char* event) {
+    // NOOP.
+  }
+
   intptr_t CountFor(TimelineEvent::EventType type) {
     return counts_[type];
   }
diff --git a/runtime/vm/timer.cc b/runtime/vm/timer.cc
index a0b8707c..5b76b48 100644
--- a/runtime/vm/timer.cc
+++ b/runtime/vm/timer.cc
@@ -8,50 +8,6 @@
 
 namespace dart {
 
-// Define timer command line flags.
-#define DEFINE_TIMER_FLAG(name, msg)                                           \
-  DEFINE_FLAG(bool, name, false, ""#name);
-TIMER_LIST(DEFINE_TIMER_FLAG)
-#undef DEFINE_TIMER_FLAG
-DEFINE_FLAG(bool, time_all, false, "Time all functionality");
 
 
-// Maintains a list of timers per isolate.
-#define INIT_TIMERS(name, msg)                                                 \
-  name##_((FLAG_##name || FLAG_time_all), msg),
-TimerList::TimerList()
-    : TIMER_LIST(INIT_TIMERS)
-      padding_(false) {
-}
-#undef INIT_TIMERS
-
-
-#define TIMER_FIELD_REPORT(name, msg)                                          \
-  if (name().report() && name().message() != NULL) {                           \
-    OS::Print("%s :  %.3f ms total; %.3f ms max.\n",                           \
-              name().message(),                                                \
-              MicrosecondsToMilliseconds(name().TotalElapsedTime()),           \
-              MicrosecondsToMilliseconds(name().MaxContiguous()));             \
-  }
-void TimerList::ReportTimers() {
-  TIMER_LIST(TIMER_FIELD_REPORT);
-}
-#undef TIMER_FIELD_REPORT
-
-
-#define JSON_TIMER(name, msg)                                                  \
-  {                                                                            \
-    JSONObject jsobj(&jsarr);                                                  \
-    jsobj.AddProperty("name", #name);                                          \
-    jsobj.AddProperty("time",                                                  \
-                      MicrosecondsToSeconds(name().TotalElapsedTime()));       \
-    jsobj.AddProperty("max_contiguous",                                        \
-                      MicrosecondsToSeconds(name().MaxContiguous()));          \
-  }
-void TimerList::PrintTimersToJSONProperty(JSONObject* jsobj) {
-  JSONArray jsarr(jsobj, "timers");
-  TIMER_LIST(JSON_TIMER);
-}
-#undef JSON_TIMER
-
 }  // namespace dart
diff --git a/runtime/vm/timer.h b/runtime/vm/timer.h
index 32af994..4738efa 100644
--- a/runtime/vm/timer.h
+++ b/runtime/vm/timer.h
@@ -90,41 +90,6 @@
   DISALLOW_COPY_AND_ASSIGN(Timer);
 };
 
-// List of per isolate timers.
-#define TIMER_LIST(V)                                                          \
-  V(time_script_loading, "Script Loading")                                     \
-  V(time_creating_snapshot, "Snapshot Creation")                               \
-  V(time_isolate_initialization, "Isolate initialization")                     \
-  V(time_compilation, "Function compilation")                                  \
-  V(time_bootstrap, "Bootstrap of core classes")                               \
-  V(time_dart_execution, "Dart execution")                                     \
-  V(time_total_runtime, "Total runtime for isolate")                           \
-  V(time_gc, "Garbage collection")                                             \
-
-// Maintains a list of timers per isolate.
-class TimerList : public ValueObject {
- public:
-  TimerList();
-  ~TimerList() {}
-
-  // Accessors.
-#define TIMER_FIELD_ACCESSOR(name, msg)                                        \
-  Timer& name() { return name##_; }
-  TIMER_LIST(TIMER_FIELD_ACCESSOR)
-#undef TIMER_FIELD_ACCESSOR
-
-  void ReportTimers();
-
-  void PrintTimersToJSONProperty(JSONObject* jsobj);
-
- private:
-#define TIMER_FIELD(name, msg) Timer name##_;
-  TIMER_LIST(TIMER_FIELD)
-#undef TIMER_FIELD
-  bool padding_;
-  DISALLOW_COPY_AND_ASSIGN(TimerList);
-};
-
 
 // The class TimerScope is used to start and stop a timer within a scope.
 // It is used as follows:
@@ -207,21 +172,6 @@
 };
 
 
-// Macros to deal with named timers in the isolate.
-#define START_TIMER(isolate, name)                                             \
-isolate->timer_list().name().Start();
-
-#define STOP_TIMER(isolate, name)                                              \
-isolate->timer_list().name().Stop();
-
-#define TIMERSCOPE(thread, name)                                               \
-  TimerScope vm_internal_timer_(                                               \
-      true, &(thread->isolate()->timer_list().name()), thread)
-
-#define PAUSETIMERSCOPE(thread, name)                                          \
-PauseTimerScope vm_internal_timer_(true,                                       \
-                                   &(thread->isolate()->timer_list().name()),  \
-                                   thread)
 
 }  // namespace dart
 
diff --git a/runtime/vm/vm.gypi b/runtime/vm/vm.gypi
index e298592..4397f96 100644
--- a/runtime/vm/vm.gypi
+++ b/runtime/vm/vm.gypi
@@ -26,30 +26,23 @@
     'mirrors_cc_file': '<(gen_source_dir)/mirrors_gen.cc',
     'mirrors_patch_cc_file': '<(gen_source_dir)/mirrors_patch_gen.cc',
     'profiler_cc_file': '<(gen_source_dir)/profiler_gen.cc',
-    'service_cc_file': '<(gen_source_dir)/service_gen.cc',
     'snapshot_test_dat_file': '<(gen_source_dir)/snapshot_test.dat',
     'snapshot_test_in_dat_file': 'snapshot_test_in.dat',
     'snapshot_test_dart_file': 'snapshot_test.dart',
     'typed_data_cc_file': '<(gen_source_dir)/typed_data_gen.cc',
     'typed_data_patch_cc_file': '<(gen_source_dir)/typed_data_patch_gen.cc',
+    'vmservice_cc_file': '<(gen_source_dir)/vmservice_gen.cc',
   },
   'targets': [
     {
       'target_name': 'libdart_vm',
       'type': 'static_library',
       'toolsets':['host', 'target'],
-      'dependencies': [
-        'generate_service_cc_file#host'
-      ],
       'includes': [
         'vm_sources.gypi',
         '../platform/platform_headers.gypi',
         '../platform/platform_sources.gypi',
       ],
-      'sources': [
-        # Include generated source files.
-        '<(service_cc_file)',
-      ],
       'sources/': [
         # Exclude all _test.[cc|h] files.
         ['exclude', '_test\\.(cc|h)$'],
@@ -105,18 +98,11 @@
       'target_name': 'libdart_vm_nosnapshot',
       'type': 'static_library',
       'toolsets':['host', 'target'],
-      'dependencies': [
-        'generate_service_cc_file#host'
-      ],
       'includes': [
         'vm_sources.gypi',
         '../platform/platform_headers.gypi',
         '../platform/platform_sources.gypi',
       ],
-      'sources': [
-        # Include generated source files.
-        '<(service_cc_file)',
-      ],
       'sources/': [
         # Exclude all _test.[cc|h] files.
         ['exclude', '_test\\.(cc|h)$'],
@@ -197,6 +183,7 @@
         'generate_profiler_cc_file#host',
         'generate_typed_data_cc_file#host',
         'generate_typed_data_patch_cc_file#host',
+        'generate_vmservice_cc_file#host',
       ],
       'includes': [
         '../lib/async_sources.gypi',
@@ -208,6 +195,7 @@
         '../lib/math_sources.gypi',
         '../lib/mirrors_sources.gypi',
         '../lib/typed_data_sources.gypi',
+        '../lib/vmservice_sources.gypi',
       ],
       'sources': [
         'bootstrap.cc',
@@ -233,6 +221,7 @@
         '<(profiler_cc_file)',
         '<(typed_data_cc_file)',
         '<(typed_data_patch_cc_file)',
+        '<(vmservice_cc_file)',
       ],
       'include_dirs': [
         '..',
@@ -252,6 +241,7 @@
         '../lib/math_sources.gypi',
         '../lib/mirrors_sources.gypi',
         '../lib/typed_data_sources.gypi',
+        '../lib/vmservice_sources.gypi',
       ],
       'sources': [
         'bootstrap_nocore.cc',
@@ -1128,32 +1118,41 @@
       ]
     },
     {
-      'target_name': 'generate_service_cc_file',
+      'target_name': 'generate_vmservice_cc_file',
       'type': 'none',
       'toolsets':['host'],
       'includes': [
-        'service_sources.gypi',
+        '../lib/vmservice_sources.gypi',
+      ],
+      'sources/': [
+        # Exclude all .[cc|h] files.
+        # This is only here for reference. Excludes happen after
+        # variable expansion, so the script has to do its own
+        # exclude processing of the sources being passed.
+        ['exclude', '\\.cc|h$'],
       ],
       'actions': [
         {
-          'action_name': 'generate_service_cc',
+          'action_name': 'generate_vmservice_cc',
           'inputs': [
-            '../tools/create_resources.py',
+            '../tools/gen_library_src_paths.py',
+            '<(libgen_in_cc_file)',
             '<@(_sources)',
           ],
           'outputs': [
-            '<(service_cc_file)',
+            '<(vmservice_cc_file)',
           ],
           'action': [
             'python',
-            'tools/create_resources.py',
-            '--output', '<(service_cc_file)',
-            '--outer_namespace', 'dart',
-            '--table_name', 'service',
-            '--root_prefix', 'vm/service/',
-            '<@(_sources)'
+            'tools/gen_library_src_paths.py',
+            '--output', '<(vmservice_cc_file)',
+            '--input_cc', '<(libgen_in_cc_file)',
+            '--include', 'vm/bootstrap.h',
+            '--var_name', 'dart::Bootstrap::vmservice_source_paths_',
+            '--library_name', 'dart:_vmservice',
+            '<@(_sources)',
           ],
-          'message': 'Generating ''<(service_cc_file)'' file.'
+          'message': 'Generating ''<(vmservice_cc_file)'' file.'
         },
       ]
     },
diff --git a/runtime/vm/weak_code.cc b/runtime/vm/weak_code.cc
index 85e623a..cf1e132 100644
--- a/runtime/vm/weak_code.cc
+++ b/runtime/vm/weak_code.cc
@@ -115,17 +115,15 @@
       // function is invoked, it will be compiled again.
       function.ClearCode();
       // Invalidate the old code object so existing references to it
-      // (from optimized code) will fail when invoked.
-      if (!CodePatcher::IsEntryPatched(code)) {
-        CodePatcher::PatchEntry(
-            code, Code::Handle(StubCode::FixCallersTarget_entry()->code()));
+      // (from optimized code) will be patched when invoked.
+      if (!code.IsDisabled()) {
+        code.DisableDartCode();
       }
     } else {
       // Make non-OSR code non-entrant.
-      if (!CodePatcher::IsEntryPatched(code)) {
+      if (!code.IsDisabled()) {
         ReportSwitchingCode(code);
-        CodePatcher::PatchEntry(
-            code, Code::Handle(StubCode::FixCallersTarget_entry()->code()));
+        code.DisableDartCode();
       }
     }
   }
diff --git a/runtime/vm/zone.cc b/runtime/vm/zone.cc
index ea42f49..7cb7977 100644
--- a/runtime/vm/zone.cc
+++ b/runtime/vm/zone.cc
@@ -178,6 +178,21 @@
 }
 
 
+char* Zone::ConcatStrings(const char* a, const char* b, char join) {
+  intptr_t a_len = (a == NULL) ? 0 : strlen(a);
+  const intptr_t b_len = strlen(b) + 1;  // '\0'-terminated.
+  const intptr_t len = a_len + b_len;
+  char* copy = Alloc<char>(len);
+  if (a_len > 0) {
+    strncpy(copy, a, a_len);
+    // Insert join character.
+    copy[a_len++] = join;
+  }
+  strncpy(&copy[a_len], b, b_len);
+  return copy;
+}
+
+
 #if defined(DEBUG)
 void Zone::DumpZoneSizes() {
   intptr_t size = 0;
diff --git a/runtime/vm/zone.h b/runtime/vm/zone.h
index 361e6e2..2008ee9 100644
--- a/runtime/vm/zone.h
+++ b/runtime/vm/zone.h
@@ -8,6 +8,7 @@
 #include "platform/utils.h"
 #include "vm/allocation.h"
 #include "vm/handles.h"
+#include "vm/thread.h"
 #include "vm/memory_region.h"
 
 namespace dart {
@@ -46,6 +47,10 @@
   // Make a copy of the string in the zone allocated area.
   char* MakeCopyOfString(const char* str);
 
+  // Concatenate strings |a| and |b|. |a| may be NULL. If |a| is not NULL,
+  // |join| will be inserted between |a| and |b|.
+  char* ConcatStrings(const char* a, const char* b, char join = ',');
+
   // TODO(zra): Remove these calls and replace them with calls to OS::SCreate
   // and OS::VSCreate.
   // These calls are deprecated. Do not add further calls to these functions.
diff --git a/sdk/lib/_internal/js_runtime/lib/async_patch.dart b/sdk/lib/_internal/js_runtime/lib/async_patch.dart
index f8412c1..1155e79 100644
--- a/sdk/lib/_internal/js_runtime/lib/async_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/async_patch.dart
@@ -506,3 +506,8 @@
 
   Iterator get iterator => new _SyncStarIterator(JS('', '#()', _outerHelper));
 }
+
+@patch
+void _rethrow(Object error, StackTrace stackTrace) {
+  throw new AsyncError(error, stackTrace);
+}
diff --git a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
index 8349d14..2ff405c 100644
--- a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
@@ -44,3 +44,19 @@
 _registerExtension(String method, ServiceExtensionHandler handler) {
   _extensions[method] = handler;
 }
+
+@patch
+int _getTraceClock() {
+  // TODO.
+  return _clockValue++;
+}
+int _clockValue = 0;
+
+@patch
+void _reportCompleteEvent(int start,
+                          int end,
+                          String category,
+                          String name,
+                          String argumentsAsJson) {
+  // TODO.
+}
diff --git a/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart b/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
index 85b30b1..8b8d023 100644
--- a/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
@@ -20,6 +20,16 @@
   static Isolate get current => _currentIsolateCache;
 
   @patch
+  static Future<Uri> get packageRoot {
+    throw new UnsupportedError("Isolate.packageRoot");
+  }
+
+  @patch
+  static Future<Map<String, Uri>> get packageMap {
+    throw new UnsupportedError("Isolate.packageMap");
+  }
+
+  @patch
   static Future<Isolate> spawn(void entryPoint(message), var message,
                                {bool paused: false, bool errorsAreFatal,
                                 SendPort onExit, SendPort onError}) {
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart
index 225f5d1..2520f4d 100644
--- a/sdk/lib/async/zone.dart
+++ b/sdk/lib/async/zone.dart
@@ -891,10 +891,14 @@
 void _rootHandleUncaughtError(
     Zone self, ZoneDelegate parent, Zone zone, error, StackTrace stackTrace) {
   _schedulePriorityAsyncCallback(() {
-    throw new _UncaughtAsyncError(error, stackTrace);
+    if (error == null) error = new NullThrownError();
+    if (stackTrace == null) throw error;
+    _rethrow(error, stackTrace);
   });
 }
 
+external void _rethrow(Object error, StackTrace stackTrace);
+
 dynamic _rootRun(Zone self, ZoneDelegate parent, Zone zone, f()) {
   if (Zone._current == zone) return f();
 
@@ -1009,26 +1013,6 @@
   return new _CustomZone(zone, specification, valueMap);
 }
 
-class _RootZoneSpecification implements ZoneSpecification {
-  HandleUncaughtErrorHandler get handleUncaughtError =>
-      _rootHandleUncaughtError;
-  RunHandler get run => _rootRun;
-  RunUnaryHandler get runUnary => _rootRunUnary;
-  RunBinaryHandler get runBinary => _rootRunBinary;
-  RegisterCallbackHandler get registerCallback => _rootRegisterCallback;
-  RegisterUnaryCallbackHandler get registerUnaryCallback =>
-      _rootRegisterUnaryCallback;
-  RegisterBinaryCallbackHandler get registerBinaryCallback =>
-      _rootRegisterBinaryCallback;
-  ErrorCallbackHandler get errorCallback => _rootErrorCallback;
-  ScheduleMicrotaskHandler get scheduleMicrotask => _rootScheduleMicrotask;
-  CreateTimerHandler get createTimer => _rootCreateTimer;
-  CreatePeriodicTimerHandler get createPeriodicTimer =>
-      _rootCreatePeriodicTimer;
-  PrintHandler get print => _rootPrint;
-  ForkHandler get fork => _rootFork;
-}
-
 class _RootZone extends _Zone {
   const _RootZone();
 
diff --git a/sdk/lib/convert/json.dart b/sdk/lib/convert/json.dart
index d3624ab..08eb797 100644
--- a/sdk/lib/convert/json.dart
+++ b/sdk/lib/convert/json.dart
@@ -53,8 +53,8 @@
  *
  * Examples:
  *
- *     var encoded = JSON.encode([1, 2, { "a": null }]);
- *     var decoded = JSON.decode('["foo", { "bar": 499 }]');
+ *    var encoded = JSON.encode([1, 2, { "a": null }]);
+ *    var decoded = JSON.decode('["foo", { "bar": 499 }]');
  */
 const JsonCodec JSON = const JsonCodec();
 
@@ -65,6 +65,11 @@
 /**
  * A [JsonCodec] encodes JSON objects to strings and decodes strings to
  * JSON objects.
+ *
+ * Examples:
+ *
+ *    var encoded = JSON.encode([1, 2, { "a": null }]);
+ *    var decoded = JSON.decode('["foo", { "bar": 499 }]');
  */
 class JsonCodec extends Codec<Object, String> {
   final _Reviver _reviver;
diff --git a/sdk/lib/core/map.dart b/sdk/lib/core/map.dart
index e92c780..4f7fcf8 100644
--- a/sdk/lib/core/map.dart
+++ b/sdk/lib/core/map.dart
@@ -149,7 +149,7 @@
   /**
    * Returns true if this map contains the given [key].
    *
-   * Returns true if any of the keys in the map ar equal to `key`
+   * Returns true if any of the keys in the map are equal to `key`
    * according to the equality used by the map.
    */
   bool containsKey(Object key);
diff --git a/sdk/lib/core/resource.dart b/sdk/lib/core/resource.dart
index 17bdebc..e8c9c67 100644
--- a/sdk/lib/core/resource.dart
+++ b/sdk/lib/core/resource.dart
@@ -5,16 +5,18 @@
 part of dart.core;
 
 /**
- * A resource that can be read into the program.
+ * DEPRECATED. A resource that can be read into the program.
  *
- * WARNING: This API is _experimental_,
- * and it may be changed or removed in future releases
+ * WARNING: This API is _deprecated_,
+ * and it will be removed in 1.14. Please use
+ * https://pub.dartlang.org/packages/resource instead.
  *
  * A resource is data that can be located using a URI and read into
  * the program at runtime.
  * The URI may use the `package` scheme to read resources provided
  * along with package sources.
  */
+@Deprecated('1.14')
 abstract class Resource {
   /**
    * Creates a resource object with the given [uri] as location.
diff --git a/sdk/lib/developer/developer.dart b/sdk/lib/developer/developer.dart
index d5620e4..722819c 100644
--- a/sdk/lib/developer/developer.dart
+++ b/sdk/lib/developer/developer.dart
@@ -17,6 +17,7 @@
 
 part 'extension.dart';
 part 'profiler.dart';
+part 'timeline.dart';
 
 /// If [when] is true, stop the program as if a breakpoint were hit at the
 /// following statement.
diff --git a/sdk/lib/developer/developer_sources.gypi b/sdk/lib/developer/developer_sources.gypi
index 63d69cc..0c4333a 100644
--- a/sdk/lib/developer/developer_sources.gypi
+++ b/sdk/lib/developer/developer_sources.gypi
@@ -7,6 +7,7 @@
     'developer.dart',
     'extension.dart',
     'profiler.dart',
+    'timeline.dart',
     # The above file needs to be first if additional parts are added to the lib.
   ],
 }
diff --git a/sdk/lib/developer/timeline.dart b/sdk/lib/developer/timeline.dart
new file mode 100644
index 0000000..54c5b80
--- /dev/null
+++ b/sdk/lib/developer/timeline.dart
@@ -0,0 +1,103 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.developer;
+
+typedef dynamic TimelineSyncFunction();
+
+/// Add to the timeline.
+class Timeline {
+  /// Start a synchronous operation labeled [name]. Optionally takes
+  /// a [Map] of [arguments]. This operation must be finished before
+  /// returning to the event queue.
+  static void startSync(String name, {Map arguments}) {
+    if (name is! String) {
+      throw new ArgumentError.value(name,
+                                    'name',
+                                    'Must be a String');
+    }
+    var block = new _SyncBlock._(name, _getTraceClock());
+    if (arguments is Map) {
+      block.arguments.addAll(arguments);
+    }
+    _stack.add(block);
+  }
+
+  /// Finish the last synchronous operation that was started.
+  static void finishSync() {
+    if (_stack.length == 0) {
+      throw new StateError(
+          'Uneven calls to startSync and finishSync');
+    }
+    // Pop top item off of stack.
+    var block = _stack.removeLast();
+    // Close it.
+    block.close();
+  }
+
+  /// A utility method to time a synchronous [function]. Internally calls
+  /// [function] bracketed by calls to [startSync] and [finishSync].
+  static dynamic timeSync(String name,
+                          TimelineSyncFunction function,
+                          {Map arguments}) {
+    startSync(name, arguments: arguments);
+    try {
+      return function();
+    } finally {
+      finishSync();
+    }
+  }
+
+  static final List<_SyncBlock> _stack = new List<_SyncBlock>();
+}
+
+/// A synchronous block of time on the timeline. This block should not be
+/// kept open across isolate messages.
+class _SyncBlock {
+  /// The category this block belongs to.
+  final String category = 'Dart';
+  /// The name of this block.
+  final String name;
+  /// An (optional) set of arguments which will be serialized to JSON and
+  /// associated with this block.
+  final Map arguments = {};
+  // The start time stamp.
+  final int _start;
+  // Has this block been closed?
+  bool _closed = false;
+
+  _SyncBlock._(this.name,
+               this._start);
+
+  /// Close this block of time. At this point, this block can no longer be
+  /// used.
+  void close() {
+    if (_closed) {
+      throw new StateError(
+          'It is illegal to call close twice on the same _SyncBlock');
+    }
+    _closed = true;
+    var end = _getTraceClock();
+
+    // Encode arguments map as JSON before reporting.
+    var argumentsAsJson = JSON.encode(arguments);
+
+    // Report event to runtime.
+    _reportCompleteEvent(_start,
+                         end,
+                         category,
+                         name,
+                         argumentsAsJson);
+  }
+}
+
+/// Returns the current value from the trace clock.
+external int _getTraceClock();
+
+/// Reports a complete synchronous event.
+external void _reportCompleteEvent(int start,
+                                   int end,
+                                   String category,
+                                   String name,
+                                   String argumentsAsJson);
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index b581f65..7bef67f 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -122,6 +122,11 @@
   // TODO(17738): Implement this.
   throw new UnimplementedError();
 }
+
+/// Dartium functions that are a NOOP in dart2js.
+unwrap_jso(dartClass_instance) => dartClass_instance;
+wrap_jso(jsObject) => jsObject;
+createCustomUpgrader(Type customElementClass, $this) => $this;
 // 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/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 95c43f6..14fc413 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -1106,6 +1106,9 @@
  **********                                                          **********
  ******************************************************************************/
 
+// List of known tagName to DartClass for custom elements, used for upgrade.
+var _knownCustomeElements = new Map<String, Type>();
+
 Rectangle make_dart_rectangle(r) =>
     r == null ? null : new Rectangle(r['left'], r['top'], r['width'], r['height']);
 
@@ -1125,19 +1128,7 @@
 /**
  * Return the JsObject associated with a Dart class [dartClass_instance].
  */
-unwrap_jso(dartClass_instance) {
-  try {
-    if (dartClass_instance != null)
-      return dartClass_instance is NativeFieldWrapperClass2 ?
-          dartClass_instance.blink_jsObject : dartClass_instance;
-    else
-      return null;
-  } catch(NoSuchMethodException) {
-    // No blink_jsObject then return the dartClass_instance is probably an
-    // array that was already converted to a Dart class e.g., Uint8ClampedList.
-    return dartClass_instance;
-  }
-}
+unwrap_jso(dartClass_instance) => js.unwrap_jso(dartClass_instance);
 
 /**
  * Create Dart class that maps to the JS Type, add the JsObject as an expando
@@ -1145,10 +1136,26 @@
  */
 wrap_jso(jsObject) {
   try {
-    if (jsObject is! js.JsObject) {
+    if (jsObject is! js.JsObject || jsObject == null) {
       // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
+      // or it's a simple type.
       return jsObject;
     }
+
+    // TODO(alanknight): With upgraded custom elements this causes a failure because
+    // we need a new wrapper after the type changes. We could possibly invalidate this
+    // if the constructor name didn't match?
+    var wrapper = js.getDartHtmlWrapperFor(jsObject);
+    if (wrapper != null) {
+      return wrapper;
+    }
+
+    if (jsObject is js.JsArray) {
+      var wrappingList = new _DartHtmlWrappingList(jsObject);
+      js.setDartHtmlWrapperFor(jsObject, wrappingList);
+      return wrappingList;
+    }
+
     // Try the most general type conversions on it.
     // TODO(alanknight): We may be able to do better. This maintains identity,
     // which is useful, but expensive. And if we nest something that only
@@ -1171,10 +1178,24 @@
       // Got a dart_class (it's a custom element) use it it's already set up.
       dartClass_instance = jsObject['dart_class'];
     } else {
-      var func = getHtmlCreateFunction(jsTypeName);
-      if (func != null) {
-        dartClass_instance = func();
-        dartClass_instance.blink_jsObject = jsObject;
+      var localName = jsObject['localName'];
+      var customElementClass = _knownCustomeElements[localName];
+      // Custom Element to upgrade.
+      if (jsTypeName == 'HTMLElement' && customElementClass != null) {
+        try {
+          dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
+        } finally {
+          dartClass_instance.blink_jsObject = jsObject;
+          jsObject['dart_class'] = dartClass_instance;
+          js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
+       }
+      } else {
+        var func = getHtmlCreateFunction(jsTypeName);
+        if (func != null) {
+          dartClass_instance = func();
+          dartClass_instance.blink_jsObject = jsObject;
+          js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
+        }
       }
     }
     return dartClass_instance;
@@ -1293,6 +1314,41 @@
 // Conversion function place holder (currently not used in dart2js or dartium).
 List convertDartToNative_StringArray(List<String> input) => input;
 
+/**
+ * Wraps a JsArray and will call wrap_jso on its entries.
+ */
+class _DartHtmlWrappingList extends ListBase {
+  _DartHtmlWrappingList(this._basicList);
+
+  final js.JsArray _basicList;
+
+  operator [](int index) => wrap_jso(_basicList[index]);
+
+  operator []=(int index, value) => _basicList[index] = unwrap_jso(value);
+
+  int get length => _basicList.length;
+  int set length(int newLength) => _basicList.length = newLength;
+}
+
+/**
+ * Upgrade the JS HTMLElement to the Dart class.  Used by Dart's Polymer.
+ */
+createCustomUpgrader(Type customElementClass, $this) {
+  var dartClass;
+  try {
+    dartClass = _blink.Blink_Utils.constructElement(customElementClass, $this);
+  } catch (e) {
+    throw e;
+  } finally {
+    // Need to remember the Dart class that was created for this custom so
+    // return it and setup the blink_jsObject to the $this that we'll be working
+    // with as we talk to blink. 
+    $this['dart_class'] = dartClass;
+  }
+
+  return dartClass;
+}
+
 // 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.
@@ -10127,10 +10183,10 @@
 
   void _readEntries(_EntriesCallback successCallback, [_ErrorCallback errorCallback]) {
     if (errorCallback != null) {
-      _blink.BlinkDirectoryReader.instance.readEntries_Callback_2_(unwrap_jso(this), unwrap_jso((entries) => successCallback(entries)), unwrap_jso((error) => errorCallback(wrap_jso(error))));
+      _blink.BlinkDirectoryReader.instance.readEntries_Callback_2_(unwrap_jso(this), unwrap_jso((entries) => successCallback(wrap_jso(entries))), unwrap_jso((error) => errorCallback(wrap_jso(error))));
       return;
     }
-    _blink.BlinkDirectoryReader.instance.readEntries_Callback_1_(unwrap_jso(this), unwrap_jso((entries) => successCallback(entries)));
+    _blink.BlinkDirectoryReader.instance.readEntries_Callback_1_(unwrap_jso(this), unwrap_jso((entries) => successCallback(wrap_jso(entries))));
     return;
   }
 
@@ -11053,6 +11109,8 @@
       wrapped = wrap_jso(newElement);
       if (wrapped == null) {
         wrapped = wrap_jso_custom_element(newElement);
+      } else {
+        wrapped.blink_jsObject['dart_class'] = wrapped;
       }
     }
 
@@ -11075,6 +11133,8 @@
       wrapped = wrap_jso(newElement);
       if (wrapped == null) {
         wrapped = wrap_jso_custom_element(newElement);
+      } else {
+        wrapped.blink_jsObject['dart_class'] = wrapped;
       }
     }
 
@@ -18427,7 +18487,7 @@
   @DomName('FontFaceSetLoadEvent.fontfaces')
   @DocsEditable()
   @Experimental() // untriaged
-  List<FontFace> get fontfaces => _blink.BlinkFontFaceSetLoadEvent.instance.fontfaces_Getter_(unwrap_jso(this));
+  List<FontFace> get fontfaces => wrap_jso(_blink.BlinkFontFaceSetLoadEvent.instance.fontfaces_Getter_(unwrap_jso(this)));
   
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -18657,7 +18717,7 @@
 
   @DomName('Gamepad.axes')
   @DocsEditable()
-  List<num> get axes => _blink.BlinkGamepad.instance.axes_Getter_(unwrap_jso(this));
+  List<num> get axes => wrap_jso(_blink.BlinkGamepad.instance.axes_Getter_(unwrap_jso(this)));
   
   @DomName('Gamepad.connected')
   @DocsEditable()
@@ -20321,6 +20381,9 @@
       }
       var elemProto = js.context['Object'].callMethod("create", [baseElement['prototype']]);
 
+      // Remember for any upgrading done in wrap_jso.
+      _knownCustomeElements[tag] = customElementClass;
+
       // TODO(terry): Hack to stop recursion re-creating custom element when the
       //              created() constructor of the custom element does e.g.,
       //
@@ -22870,7 +22933,7 @@
   @SupportedBrowser(SupportedBrowser.SAFARI)
   @Experimental()
   // http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#concept-input-type-file-selected
-  List<Entry> get entries => _blink.BlinkHTMLInputElement.instance.webkitEntries_Getter_(unwrap_jso(this));
+  List<Entry> get entries => wrap_jso(_blink.BlinkHTMLInputElement.instance.webkitEntries_Getter_(unwrap_jso(this)));
   
   @DomName('HTMLInputElement.webkitdirectory')
   @DocsEditable()
@@ -26123,7 +26186,7 @@
   
   @DomName('MessageEvent.initMessageEvent')
   @DocsEditable()
-  void _initMessageEvent(String typeArg, bool canBubbleArg, bool cancelableArg, Object dataArg, String originArg, String lastEventIdArg, Window sourceArg, List<MessagePort> messagePorts) => _blink.BlinkMessageEvent.instance.initMessageEvent_Callback_8_(unwrap_jso(this), typeArg, canBubbleArg, cancelableArg, dataArg, originArg, lastEventIdArg, unwrap_jso(sourceArg), messagePorts);
+  void _initMessageEvent(String typeArg, bool canBubbleArg, bool cancelableArg, Object dataArg, String originArg, String lastEventIdArg, Window sourceArg, List<MessagePort> messagePorts) => _blink.BlinkMessageEvent.instance.initMessageEvent_Callback_8_(unwrap_jso(this), typeArg, canBubbleArg, cancelableArg, dataArg, originArg, lastEventIdArg, unwrap_jso(sourceArg), unwrap_jso(messagePorts));
   
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -27229,7 +27292,7 @@
   }
   @DocsEditable()
   static MutationObserver _create(callback) => wrap_jso(_blink.BlinkMutationObserver.instance.constructorCallback_1_((mutations, observer) {
-    callback(mutations, wrap_jso(observer));
+    callback(wrap_jso(mutations), wrap_jso(observer));
   }));
 
   /**
@@ -47217,11 +47280,12 @@
     }
   }
 
-  Element upgrade(Element element) {
-    if (element.runtimeType != _nativeType) {
+  Element upgrade(element) {
+    if (element.runtimeType != js.JsObjectImpl) {
       throw new UnsupportedError('Element is incorrect type');
     }
-    return _Utils.changeElementWrapper(element, _type);
+
+    return createCustomUpgrader(_nativeType, element);
   }
 }
 
diff --git a/sdk/lib/io/socket.dart b/sdk/lib/io/socket.dart
index a759598..6464ab4a 100644
--- a/sdk/lib/io/socket.dart
+++ b/sdk/lib/io/socket.dart
@@ -253,41 +253,6 @@
    * is fully closed and is no longer bound.
    */
   Future<RawServerSocket> close();
-
-  /**
-   * Get the [RawServerSocketReference].
-   *
-   * WARNING: This feature is *highly experimental* and currently only
-   * works on Linux. The API will be removed in Dart 1.10. Use the
-   * `shared` optional argument on the `bind` method instead.
-   *
-   * The returned [RawServerSocketReference] can be used to create other
-   * [RawServerSocket]s listening on the same port,
-   * using [RawServerSocketReference.create].
-   * Incoming connections on the port will be distributed fairly between the
-   * active server sockets.
-   * The [RawServerSocketReference] can be distributed to other isolates through
-   * a [RawSendPort].
-   */
-
-  @Deprecated('This will be removed in Dart 1.10. Use the '
-              '`shared` optional argument on the `bind` method instead.')
-  RawServerSocketReference get reference;
-}
-
-
-/**
- * A [RawServerSocketReference].
- *
- * WARNING: This class is used with [RawServerSocket.reference] which is highly
- * experimental.
- */
-@Deprecated('This will be removed in Dart 1.10.')
-abstract class RawServerSocketReference {
-  /**
-   * Create a new [RawServerSocket], from this reference.
-   */
-  Future<RawServerSocket> create();
 }
 
 
@@ -358,40 +323,6 @@
    * is fully closed and is no longer bound.
    */
   Future<ServerSocket> close();
-
-  /**
-   * Get the [ServerSocketReference].
-   *
-   * WARNING: This feature is *highly experimental* and currently only
-   * works on Linux. The API will be removed in Dart 1.10. Use the
-   * `shared` optional argument on the `bind` method instead.
-   *
-   * The returned [ServerSocketReference] can be used to create other
-   * [ServerSocket]s listening on the same port,
-   * using [ServerSocketReference.create].
-   * Incoming connections on the port will be distributed fairly between the
-   * active server sockets.
-   * The [ServerSocketReference] can be distributed to other isolates through a
-   * [SendPort].
-   */
-  @Deprecated('This will be removed in Dart 1.10. Use the '
-              '`shared` optional argument on the `bind` method instead.')
-  ServerSocketReference get reference;
-}
-
-
-/**
- * A [ServerSocketReference].
- *
- * WARNING: This class is used with [ServerSocket.reference] which is highly
- * experimental.
- */
-@Deprecated('This will be removed in Dart 1.10.')
-abstract class ServerSocketReference {
-  /**
-   * Create a new [ServerSocket], from this reference.
-   */
-  Future<ServerSocket> create();
 }
 
 
@@ -735,6 +666,8 @@
   /**
    * Receive a datagram. If there are no datagrams available `null` is
    * returned.
+   *
+   * The maximum length of the datagram that can be received is 65503 bytes.
    */
   Datagram receive();
 
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index c671220..d6b4c0b 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -127,6 +127,29 @@
   external static Isolate get current;
 
   /**
+   * Returns the package root of the current isolate, if any.
+   *
+   * If the isolate is using a [packageMap], this getter returns `null`,
+   * otherwise it returns the package root - a directory that package
+   * URIs are resolved against.
+   */
+  external static Future<Uri> get packageRoot;
+
+  /**
+   * Returns the package mapping of the current isolate, if any.
+   *
+   * If the current isolate is using a [packageRoot], this getter
+   * returns `null`.
+   *
+   * The package map maps the name of a package that is available to the
+   * program, to a URI that package URIs for that package are resolved against.
+   *
+   * Returns an empty map if the isolate does not have a way to resolve package
+   * URIs.
+   */
+  external static Future<Map<String, Uri>> get packageMap;
+
+  /**
    * Creates and spawns an isolate that shares the same code as the current
    * isolate.
    *
diff --git a/sdk/lib/js/dartium/js_dartium.dart b/sdk/lib/js/dartium/js_dartium.dart
index b6c7198..186bde7 100644
--- a/sdk/lib/js/dartium/js_dartium.dart
+++ b/sdk/lib/js/dartium/js_dartium.dart
@@ -480,6 +480,41 @@
 }
 
 /**
+ * Get the dart wrapper object for object. Top-level so we
+ * we can access it from other libraries without it being
+ * a public instance field on JsObject.
+ */
+getDartHtmlWrapperFor(JsObject object) => object._dartHtmlWrapper;
+
+/**
+ * Set the dart wrapper object for object. Top-level so we
+ * we can access it from other libraries without it being
+ * a public instance field on JsObject.
+ */
+void setDartHtmlWrapperFor(JsObject object, wrapper) {
+  object._dartHtmlWrapper = wrapper;
+}
+
+/**
+ * Used by callMethod to get the JS object for each argument passed if the
+ * argument is a Dart class instance that delegates to a DOM object.  See
+ * wrap_jso defined in dart:html.
+ */
+unwrap_jso(dartClass_instance) {
+  try {
+    if (dartClass_instance != null)
+      return dartClass_instance is NativeFieldWrapperClass2 ?
+          dartClass_instance.blink_jsObject : dartClass_instance;
+    else
+      return null;
+  } catch(NoSuchMethodException) {
+    // No blink_jsObject then return the dartClass_instance is probably an
+    // array that was already converted to a Dart class e.g., Uint8ClampedList.
+    return dartClass_instance;
+  }
+}
+
+/**
  * Proxies a JavaScript object to Dart.
  *
  * The properties of the JavaScript object are accessible via the `[]` and
@@ -489,6 +524,12 @@
   JsObject.internal();
 
   /**
+   * If this JsObject is wrapped, e.g. DOM objects, then we can save the
+   * wrapper here and preserve its identity.
+   */
+  var _dartHtmlWrapper;
+
+  /**
    * Constructs a new JavaScript object from [constructor] and returns a proxy
    * to it.
    */
@@ -644,6 +685,10 @@
    */
   callMethod(String method, [List args]) {
     try {
+      if (args != null) {
+        for (var i = 0; i < args.length; i++)
+          args[i] = unwrap_jso(args[i]);
+      }
       return _callMethod(method, args);
     } catch (e) {
       if (hasProperty(method)) {
@@ -785,11 +830,7 @@
       _checkIndex(index);
     }
 
-    // Lazily create the Dart class that wraps the JS object when the object in
-    // a list if fetched.
-    var wrap_entry = html.wrap_jso(super[index]);
-    super[index] = wrap_entry;
-    return wrap_entry;
+    return super[index];
   }
 
   void operator []=(index, E value) {
diff --git a/sdk/lib/web_sql/dartium/web_sql_dartium.dart b/sdk/lib/web_sql/dartium/web_sql_dartium.dart
index 73bc18c..2d8039e 100644
--- a/sdk/lib/web_sql/dartium/web_sql_dartium.dart
+++ b/sdk/lib/web_sql/dartium/web_sql_dartium.dart
@@ -412,6 +412,6 @@
 
   @DomName('SQLTransaction.executeSql')
   @DocsEditable()
-  void executeSql(String sqlStatement, List<Object> arguments, [SqlStatementCallback callback, SqlStatementErrorCallback errorCallback]) => _blink.BlinkSQLTransaction.instance.executeSql_Callback_4_(unwrap_jso(this), sqlStatement, arguments, unwrap_jso((transaction, resultSet) => callback(wrap_jso(transaction), wrap_jso(resultSet))), unwrap_jso((transaction, error) => errorCallback(wrap_jso(transaction), wrap_jso(error))));
+  void executeSql(String sqlStatement, List<Object> arguments, [SqlStatementCallback callback, SqlStatementErrorCallback errorCallback]) => _blink.BlinkSQLTransaction.instance.executeSql_Callback_4_(unwrap_jso(this), sqlStatement, unwrap_jso(arguments), unwrap_jso((transaction, resultSet) => callback(wrap_jso(transaction), wrap_jso(resultSet))), unwrap_jso((transaction, error) => errorCallback(wrap_jso(transaction), wrap_jso(error))));
   
 }
diff --git a/site/try/poi/scope_information_visitor.dart b/site/try/poi/scope_information_visitor.dart
index 5ae18ee..5f1b5a1 100644
--- a/site/try/poi/scope_information_visitor.dart
+++ b/site/try/poi/scope_information_visitor.dart
@@ -120,7 +120,7 @@
       {bool isStatic: false,
        bool omitEnclosing: false,
        bool includeSuper: false}) {
-    e.ensureResolved(compiler);
+    e.ensureResolved(compiler.resolution);
     bool isFirst = true;
     var serializeEnclosing;
     String kind;
@@ -231,7 +231,7 @@
     if (category == ElementCategory.FUNCTION ||
         category == ElementCategory.VARIABLE ||
         element.isConstructor) {
-      type = element.computeType(compiler);
+      type = element.computeType(compiler.resolution);
     }
     if (name == null) {
       name = element.name;
diff --git a/site/try/src/leap.dart b/site/try/src/leap.dart
index 626048f..3688bed 100644
--- a/site/try/src/leap.dart
+++ b/site/try/src/leap.dart
@@ -16,7 +16,6 @@
     SendPort;
 
 import 'compilation.dart' show
-    compilerIsolate,
     compilerPort,
     currentSource;
 
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
index 2e60ccc..c28d8d8 100644
--- a/tests/co19/co19-co19.status
+++ b/tests/co19/co19-co19.status
@@ -4,7 +4,8 @@
 
 # This file contains the tests that have been identified as broken and
 # have been filed on the co19 issue tracker at
-#    https://code.google.com/p/co19/issues/list .
+#    https://code.google.com/p/co19/issues/list (read-only).
+#    https://github.com/dart-lang/co19/issues .
 #
 # In order to qualify here these tests need to fail both on the VM and dart2js.
 
@@ -13,6 +14,10 @@
 [ $runtime == vm || $runtime != vm ]
 # Tests that fail everywhere, including the analyzer.
 
+# Super is now allowed in mixins and mixins may now extend a subclass of Object.
+Language/09_Mixins/09_Mixins_A01_t01: Skip # co19 issue 9.
+Language/09_Mixins/09_Mixins_A03_t01: Skip # co19 issue 9.
+
 # No longer correct, y#$ now has a meaning. github.com/dart-lang/co19/issues/2
 Language/12_Expressions/30_Identifier_Reference_A01_t03: Skip
 
diff --git a/tests/co19/co19-dartium.status b/tests/co19/co19-dartium.status
index 47d5f46..546f5fe 100644
--- a/tests/co19/co19-dartium.status
+++ b/tests/co19/co19-dartium.status
@@ -20,10 +20,7 @@
 LayoutTests/fast/xpath/4XPath/Core/test_parser_t01: RuntimeError # Dartium JSInterop failure
 LayoutTests/fast/xpath/py-dom-xpath/abbreviations_t01: RuntimeError # Dartium JSInterop failure
 LayoutTests/fast/xpath/py-dom-xpath/axes_t01: RuntimeError # Dartium JSInterop failure
-LibTest/html/Element/offsetParent_A01_t01: RuntimeError # Dartium JSInterop failure
-LibTest/html/Event/currentTarget_A01_t01: RuntimeError # Dartium JSInterop failure
-LibTest/html/Event/matchingTarget_A01_t01: RuntimeError # Dartium JSInterop failure
-LibTest/html/Event/target_A01_t01: RuntimeError # Dartium JSInterop failure
+LayoutTests/fast/dom/custom/element-type_t01: RuntimeError # Dartium JsInterop failure (element upgrade)
 
 [ $compiler == none && $runtime == dartium && $checked ]
 LayoutTests/fast/css/style-scoped/style-scoped-scoping-nodes-different-order_t01: RuntimeError # Dartium JSInterop failure
@@ -211,7 +208,6 @@
 LibTest/html/HttpRequest/responseType_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
 LibTest/html/HttpRequest/responseType_A01_t03: RuntimeError # co19-roll r706.  Please triage this failure.
 LibTest/html/HttpRequest/statusText_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
-LibTest/html/IFrameElement/IFrameElement.created_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
 LibTest/html/IFrameElement/appendHtml_A01_t01: RuntimeError # Issue 23462
 LibTest/html/IFrameElement/appendHtml_A01_t02: RuntimeError # Issue 23462
 LibTest/html/IFrameElement/attributeChanged_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
@@ -395,6 +391,7 @@
 LayoutTests/fast/dom/characterdata-api-arguments_t01: RuntimeError # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/client-width-height-quirks_t01: RuntimeError # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/custom/document-register-svg-extends_t01: RuntimeError # co19-roll r738: Please triage this failure.
+LayoutTests/fast/dom/custom/document-register-type-extensions_t01: RuntimeError # Issue 24516
 LayoutTests/fast/dom/dataset-xhtml_t01: RuntimeError # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/dataset_t01: RuntimeError # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/focus-contenteditable_t01: RuntimeError, Pass # co19-roll r738: Please triage this failure.
diff --git a/tests/compiler/dart2js/analyze_unused_dart2js_test.dart b/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
index 0c4870b..90fc59b2 100644
--- a/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
+++ b/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
@@ -85,24 +85,24 @@
       'pkg/compiler/lib/src/helpers/helpers.dart');
   void checkLive(member) {
     if (member.isFunction) {
-      if (compiler.enqueuer.resolution.hasBeenResolved(member)) {
-        compiler.reportHint(compiler.createMessage(
+      if (compiler.enqueuer.resolution.hasBeenProcessed(member)) {
+        compiler.reporter.reportHintMessage(
             member, MessageKind.GENERIC,
-            {'text': "Helper function in production code '$member'."}));
+            {'text': "Helper function in production code '$member'."});
       }
     } else if (member.isClass) {
       if (member.isResolved) {
-        compiler.reportHint(compiler.createMessage(
+        compiler.reporter.reportHintMessage(
             member, MessageKind.GENERIC,
-            {'text': "Helper class in production code '$member'."}));
+            {'text': "Helper class in production code '$member'."});
       } else {
         member.forEachLocalMember(checkLive);
       }
     } else if (member.isTypedef) {
       if (member.isResolved) {
-        compiler.reportHint(compiler.createMessage(
+        compiler.reporter.reportHintMessage(
             member, MessageKind.GENERIC,
-            {'text': "Helper typedef in production code '$member'."}));
+            {'text': "Helper typedef in production code '$member'."});
       }
     }
   }
diff --git a/tests/compiler/dart2js/backend_dart/dart_backend_test.dart b/tests/compiler/dart2js/backend_dart/dart_backend_test.dart
index fb5c3ee..597f056 100644
--- a/tests/compiler/dart2js/backend_dart/dart_backend_test.dart
+++ b/tests/compiler/dart2js/backend_dart/dart_backend_test.dart
@@ -614,7 +614,8 @@
 
 PlaceholderCollector collectPlaceholders(compiler, element) {
   DartBackend backend = compiler.backend;
-  return new PlaceholderCollector(compiler,
+  return new PlaceholderCollector(
+      compiler.reporter,
       backend.mirrorRenamer,
       new Set<String>(),
       new DynoMap(compiler),
diff --git a/tests/compiler/dart2js/backend_dart/dart_printer_test.dart b/tests/compiler/dart2js/backend_dart/dart_printer_test.dart
index f6fd38b..88eabca 100644
--- a/tests/compiler/dart2js/backend_dart/dart_printer_test.dart
+++ b/tests/compiler/dart2js/backend_dart/dart_printer_test.dart
@@ -51,7 +51,7 @@
   print("${x.runtimeType}: ${buf.toString()}");
 }
 
-class PrintDiagnosticListener implements DiagnosticListener {
+class PrintDiagnosticListener implements DiagnosticReporter {
   void log(message) {
     print(message);
   }
diff --git a/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart b/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
index 247a25f..41ed1ba 100644
--- a/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
+++ b/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
@@ -218,7 +218,7 @@
     enableInlining,
     (compiler, element) {
       var expectedTypes = f(compiler);
-      var signature = element.computeSignature(compiler);
+      var signature = element.functionSignature;
       int index = 0;
       var inferrer = compiler.typesTask.typesInferrer;
       signature.forEachParameter((Element element) {
diff --git a/tests/compiler/dart2js/combinator_hint_test.dart b/tests/compiler/dart2js/combinator_hint_test.dart
new file mode 100644
index 0000000..f8b9c26
--- /dev/null
+++ b/tests/compiler/dart2js/combinator_hint_test.dart
@@ -0,0 +1,125 @@
+// 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 hint on empty combinators works as intended.
+
+import 'dart:async';
+import 'package:async_helper/async_helper.dart';
+import 'package:expect/expect.dart';
+import 'package:compiler/src/commandline_options.dart';
+import 'package:compiler/src/compiler.dart';
+import 'memory_compiler.dart';
+
+const SOURCE = const {
+  'show_local.dart': """
+import 'lib.dart' show Foo;
+
+main() {}
+""",
+
+  'hide_local.dart': """
+import 'lib.dart' hide Foo;
+
+main() {}
+""",
+
+  'show_package.dart': """
+import 'package:pkg/pkg.dart' show Foo;
+
+main() {}
+""",
+
+  'hide_package.dart': """
+import 'package:pkg/pkg.dart' hide Foo;
+
+main() {}
+""",
+
+  'lib.dart': '',
+
+  'pkg/pkg/pkg.dart': '',
+};
+
+Future<Compiler> test(Uri entryPoint,
+                      {bool showPackageWarnings: false,
+                       bool suppressHints: false,
+                       int hints: 0,
+                       Compiler cachedCompiler}) async {
+  print('==================================================================');
+  print('test: $entryPoint showPackageWarnings=$showPackageWarnings '
+        'suppressHints=$suppressHints');
+  var options = [Flags.analyzeOnly];
+  if (showPackageWarnings) {
+    options.add(Flags.showPackageWarnings);
+  }
+  if (suppressHints) {
+    options.add(Flags.suppressHints);
+  }
+  var collector = new DiagnosticCollector();
+  CompilationResult result = await runCompiler(
+      entryPoint: entryPoint,
+      memorySourceFiles: SOURCE,
+      options: options,
+      packageRoot: Uri.parse('memory:pkg/'),
+      diagnosticHandler: collector,
+      cachedCompiler: cachedCompiler);
+  Expect.equals(0, collector.errors.length,
+                'Unexpected errors: ${collector.errors}');
+  Expect.equals(0, collector.warnings.length,
+                'Unexpected warnings: ${collector.warnings}');
+  Expect.equals(hints, collector.hints.length,
+                'Unexpected hints: ${collector.hints}');
+  Expect.equals(0, collector.infos.length,
+                'Unexpected infos: ${collector.infos}');
+  print('==================================================================');
+  return result.compiler;
+}
+
+Future<Compiler> testUri(Uri entrypoint,
+                         {bool suppressed: false,
+                          Compiler cachedCompiler}) async {
+  cachedCompiler = await test(
+      entrypoint,
+      showPackageWarnings: true,
+      suppressHints: false,
+      hints: 1,
+      cachedCompiler: cachedCompiler);
+  cachedCompiler = await test(
+      entrypoint,
+      showPackageWarnings: false,
+      suppressHints: false,
+      hints: suppressed ? 0 : 1,
+      cachedCompiler: cachedCompiler);
+  cachedCompiler = await test(
+      entrypoint,
+      showPackageWarnings: true,
+      suppressHints: true,
+      hints: 0,
+      cachedCompiler: cachedCompiler);
+  cachedCompiler = await test(
+      entrypoint,
+      showPackageWarnings: false,
+      suppressHints: true,
+      hints: 0,
+      cachedCompiler: cachedCompiler);
+  return cachedCompiler;
+}
+
+void main() {
+  asyncTest(() async {
+    Compiler cachedCompiler = await testUri(
+        Uri.parse('memory:show_local.dart'));
+    cachedCompiler = await testUri(
+        Uri.parse('memory:hide_local.dart'),
+        cachedCompiler: cachedCompiler);
+    cachedCompiler = await testUri(
+        Uri.parse('memory:show_package.dart'),
+        cachedCompiler: cachedCompiler);
+    cachedCompiler = await testUri(
+        Uri.parse('memory:hide_package.dart'),
+        suppressed: true,
+        cachedCompiler: cachedCompiler);
+  });
+}
+
diff --git a/tests/compiler/dart2js/compiler_test.dart b/tests/compiler/dart2js/compiler_test.dart
index 3b1f425..74f9b17 100644
--- a/tests/compiler/dart2js/compiler_test.dart
+++ b/tests/compiler/dart2js/compiler_test.dart
@@ -5,15 +5,26 @@
 import "dart:async";
 import "package:expect/expect.dart";
 import "package:async_helper/async_helper.dart";
-import "package:compiler/src/diagnostics/messages.dart";
 import "package:compiler/src/elements/elements.dart";
 import "package:compiler/src/resolution/members.dart";
 import "package:compiler/src/diagnostics/diagnostic_listener.dart";
 import "mock_compiler.dart";
+import "diagnostic_reporter_helper.dart";
 
 
 class CallbackMockCompiler extends MockCompiler {
-  CallbackMockCompiler() : super.internal();
+  CallbackReporter reporter;
+
+  CallbackMockCompiler() : super.internal() {
+    reporter = new CallbackReporter(super.reporter);
+  }
+
+}
+
+class CallbackReporter extends DiagnosticReporterWrapper {
+  final DiagnosticReporter reporter;
+
+  CallbackReporter(this.reporter);
 
   var onError;
   var onWarning;
@@ -48,9 +59,9 @@
     ResolverVisitor visitor = compiler.resolverVisitor();
     compiler.parseScript('NoSuchPrefix.NoSuchType foo() {}');
     FunctionElement foo = compiler.mainApp.find('foo');
-    compiler.setOnWarning(
+    compiler.reporter.setOnWarning(
         (c, n, m) => Expect.equals(foo, compiler.currentElement));
-    foo.computeType(compiler);
+    foo.computeType(compiler.resolution);
     Expect.equals(1, compiler.warnings.length);
   });
 }
diff --git a/tests/compiler/dart2js/concrete_type_inference_test.dart b/tests/compiler/dart2js/concrete_type_inference_test.dart
index 5e154c4..8a53a44 100644
--- a/tests/compiler/dart2js/concrete_type_inference_test.dart
+++ b/tests/compiler/dart2js/concrete_type_inference_test.dart
@@ -23,7 +23,7 @@
       'print',
       (compiler, printElement) {
         var parameter =
-          printElement.computeSignature(compiler).requiredParameters.first;
+          printElement.functionSignature.requiredParameters.first;
         var type = compiler.typesTask.getGuaranteedTypeOfElement(parameter);
         checkType(compiler, type);
       }));
@@ -33,7 +33,7 @@
       'print',
       (compiler, printElement) {
         var parameter =
-          printElement.computeSignature(compiler).requiredParameters.first;
+          printElement.functionSignature.requiredParameters.first;
         var type = compiler.typesTask.getGuaranteedTypeOfElement(parameter);
         checkType(compiler, type);
       }));
@@ -43,7 +43,7 @@
       'print',
       (compiler, printElement) {
         var parameter =
-          printElement.computeSignature(compiler).requiredParameters.first;
+          printElement.functionSignature.requiredParameters.first;
         var type = compiler.typesTask.getGuaranteedTypeOfElement(parameter);
         checkType(compiler, type);
       }));
@@ -78,12 +78,12 @@
       'fisk(a, [b, c]) {} main() { fisk(1); }',
       'fisk',
       (compiler, fiskElement) {
-        var firstParameter =
-          fiskElement.computeSignature(compiler).requiredParameters[0];
-        var secondParameter =
-          fiskElement.computeSignature(compiler).optionalParameters[0];
-        var thirdParameter =
-          fiskElement.computeSignature(compiler).optionalParameters[1];
+        var firstParameter = fiskElement.functionSignature
+            .requiredParameters[0];
+        var secondParameter = fiskElement.functionSignature
+          .optionalParameters[0];
+        var thirdParameter = fiskElement.functionSignature
+          .optionalParameters[1];
         var typesTask = compiler.typesTask;
         Expect.identical(
             typesTask.uint31Type,
diff --git a/tests/compiler/dart2js/cpa_inference_test.dart b/tests/compiler/dart2js/cpa_inference_test.dart
deleted file mode 100644
index 50e458b..0000000
--- a/tests/compiler/dart2js/cpa_inference_test.dart
+++ /dev/null
@@ -1,2160 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import "package:expect/expect.dart";
-import "package:async_helper/async_helper.dart";
-import 'package:compiler/src/types/types.dart';
-import 'package:compiler/src/inferrer/concrete_types_inferrer.dart';
-import 'package:compiler/src/universe/call_structure.dart' show
-    CallStructure;
-import 'package:compiler/src/universe/selector.dart' show
-    Selector;
-
-import "compiler_helper.dart";
-import "type_mask_test_helper.dart";
-
-/**
- * Finds the node corresponding to the last occurence of the substring
- * [: identifier; :] in the program represented by the visited AST.
- */
-class VariableFinderVisitor extends Visitor {
-  final String identifier;
-  Node result;
-
-  VariableFinderVisitor(this.identifier);
-
-  visitSend(Send node) {
-    if (node.isPropertyAccess
-        && node.selector.asIdentifier().source == identifier) {
-      result = node;
-    } else {
-      node.visitChildren(this);
-    }
-  }
-
-  visitNode(Node node) {
-    node.visitChildren(this);
-  }
-}
-
-class AnalysisResult {
-  MockCompiler compiler;
-  ConcreteTypesInferrer inferrer;
-  Node ast;
-
-  BaseType int;
-  BaseType double;
-  BaseType num;
-  BaseType bool;
-  BaseType string;
-  BaseType list;
-  BaseType growableList;
-  BaseType map;
-  BaseType nullType;
-  BaseType functionType;
-
-  AnalysisResult(MockCompiler compiler) : this.compiler = compiler {
-    inferrer = compiler.typesTask.concreteTypesInferrer;
-    int = inferrer.baseTypes.intBaseType;
-    double = inferrer.baseTypes.doubleBaseType;
-    num = inferrer.baseTypes.numBaseType;
-    bool = inferrer.baseTypes.boolBaseType;
-    string = inferrer.baseTypes.stringBaseType;
-    list = inferrer.baseTypes.listBaseType;
-    growableList = inferrer.baseTypes.growableListBaseType;
-    map = inferrer.baseTypes.mapBaseType;
-    nullType = const NullBaseType();
-    functionType = inferrer.baseTypes.functionBaseType;
-    FunctionElement mainElement = compiler.mainApp.find('main');
-    ast = mainElement.node;
-  }
-
-  BaseType base(String className) {
-    final source = className;
-    return new ClassBaseType(compiler.mainApp.find(source));
-  }
-
-  /**
-   * Finds the [Node] corresponding to the last occurence of the substring
-   * [: identifier; :] in the program represented by the visited AST. For
-   * instance, returns the AST node representing [: foo; :] in
-   * [: main() { foo = 1; foo; } :].
-   */
-  Node findNode(String identifier) {
-    VariableFinderVisitor finder = new VariableFinderVisitor(identifier);
-    ast.accept(finder);
-    return finder.result;
-  }
-
-  /**
-   * Finds the [Element] corresponding to [: className#fieldName :].
-   */
-  Element findField(String className, String fieldName) {
-    ClassElement element = compiler.mainApp.find(className);
-    return element.lookupLocalMember(fieldName);
-  }
-
-  ConcreteType concreteFrom(List<BaseType> baseTypes) {
-    ConcreteType result = inferrer.emptyConcreteType;
-    for (final baseType in baseTypes) {
-      result = result.union(inferrer.singletonConcreteType(baseType));
-    }
-    // We make sure the concrete types expected by the tests don't default to
-    // dynamic because of widening.
-    assert(!result.isUnknown());
-    return result;
-  }
-
-  /**
-   * Checks that the inferred type of the node corresponding to the last
-   * occurence of [: variable; :] in the program is the concrete type
-   * made of [baseTypes].
-   */
-  void checkNodeHasType(String variable, List<BaseType> baseTypes) {
-    Expect.equals(
-        concreteFrom(baseTypes),
-        inferrer.inferredTypes[findNode(variable)]);
-  }
-
-  /**
-   * Checks that the inferred type of the node corresponding to the last
-   * occurence of [: variable; :] in the program is the unknown concrete type.
-   */
-  void checkNodeHasUnknownType(String variable) {
-    Expect.isTrue(inferrer.inferredTypes[findNode(variable)].isUnknown());
-  }
-
-  /**
-   * Checks that [: className#fieldName :]'s inferred type is the concrete type
-   * made of [baseTypes].
-   */
-  void checkFieldHasType(String className, String fieldName,
-                         List<BaseType> baseTypes) {
-    Expect.equals(
-        concreteFrom(baseTypes),
-        inferrer.inferredFieldTypes[findField(className, fieldName)]);
-  }
-
-  /**
-   * Checks that [: className#fieldName :]'s inferred type is the unknown
-   * concrete type.
-   */
-  void checkFieldHasUknownType(String className, String fieldName) {
-    Expect.isTrue(
-        inferrer.inferredFieldTypes[findField(className, fieldName)]
-                .isUnknown());
-  }
-
-  /** Checks that the inferred type for [selector] is [mask]. */
-  void checkSelectorHasType(Selector selector,
-                            TypeMask mask,
-                            TypeMask expectedMask) {
-    Expect.equals(expectedMask, inferrer.getTypeOfSelector(selector, mask));
-  }
-}
-
-const String DYNAMIC = '"__dynamic_for_test"';
-
-Future<AnalysisResult> analyze(String code, {int maxConcreteTypeSize: 1000}) {
-  Uri uri = new Uri(scheme: 'dart', path: 'test');
-  MockCompiler compiler = new MockCompiler.internal(
-      enableConcreteTypeInference: true,
-      maxConcreteTypeSize: maxConcreteTypeSize);
-  compiler.diagnosticHandler = createHandler(compiler, code);
-  compiler.registerSource(uri, code);
-  compiler.typesTask.concreteTypesInferrer.testMode = true;
-  return compiler.runCompiler(uri).then((_) {
-    return new AnalysisResult(compiler);
-  });
-}
-
-testDynamicBackDoor() {
-  final String source = """
-    main () {
-      var x = $DYNAMIC;
-      x;
-    }
-    """;
-  return analyze(source).then((result) {
-    result.checkNodeHasUnknownType('x');
-  });
-}
-
-testVariableDeclaration() {
-  final String source = r"""
-      main() {
-        var v1;
-        var v2;
-        v2 = 1;
-        v1; v2;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('v1', [result.nullType]);
-    result.checkNodeHasType('v2', [result.int]);
-  });
-}
-
-testLiterals() {
-  final String source = r"""
-      main() {
-        var v1 = 42;
-        var v2 = 42.1;
-        var v3 = 'abc';
-        var v4 = true;
-        var v5 = null;
-        v1; v2; v3; v4; v5;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('v1', [result.int]);
-    result.checkNodeHasType('v2', [result.double]);
-    result.checkNodeHasType('v3', [result.string]);
-    result.checkNodeHasType('v4', [result.bool]);
-    result.checkNodeHasType('v5', [result.nullType]);
-  });
-}
-
-testRedefinition() {
-  final String source = r"""
-      main() {
-        var foo = 42;
-        foo = 'abc';
-        foo;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.string]);
-  });
-}
-
-testIfThenElse() {
-  final String source = r"""
-      main() {
-        var foo = 42;
-        if (true) {
-          foo = 'abc';
-        } else {
-          foo = false;
-        }
-        foo;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.string, result.bool]);
-  });
-}
-
-testTernaryIf() {
-  final String source = r"""
-      main() {
-        var foo = 42;
-        foo = true ? 'abc' : false;
-        foo;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.string, result.bool]);
-  });
-}
-
-testWhile() {
-  final String source = r"""
-      class A { f() => new B(); }
-      class B { f() => new C(); }
-      class C { f() => new A(); }
-      main() {
-        var bar = null;
-        var foo = new A();
-        while(bar = 42) {
-          foo = foo.f();
-        }
-        foo; bar;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType(
-        'foo',
-        [result.base('A'), result.base('B'), result.base('C')]);
-    // Check that the condition is evaluated.
-    // TODO(polux): bar's type could be inferred to be {int} here.
-    result.checkNodeHasType('bar', [result.int, result.nullType]);
-  });
-}
-
-testDoWhile() {
-  final String source = r"""
-      class A { f() => new B(); }
-      class B { f() => new C(); }
-      class C { f() => new A(); }
-      main() {
-        var bar = null;
-        var foo = new A();
-        do {
-          foo = foo.f();
-        } while (bar = 42);
-        foo; bar;
-      }
-      """;
-  return analyze(source).then((AnalysisResult result) {
-    result.checkNodeHasType(
-        'foo',
-        [result.base('A'), result.base('B'), result.base('C')]);
-    // Check that the condition is evaluated.
-    result.checkNodeHasType('bar', [result.int]);
-  });
-}
-
-testFor1() {
-  final String source = r"""
-      class A { f() => new B(); }
-      class B { f() => new C(); }
-      class C { f() => new A(); }
-      main() {
-        var foo = new A();
-        for(;;) {
-          foo = foo.f();
-        }
-        foo;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType(
-        'foo',
-        [result.base('A'), result.base('B'), result.base('C')]);
-  });
-}
-
-testFor2() {
-  final String source = r"""
-      class A { f() => new B(); test() => true; }
-      class B { f() => new A(); test() => true; }
-      main() {
-        var bar = null;
-        var foo = new A();
-        for(var i = new A(); bar = 42; i = i.f()) {
-           foo = i;
-        }
-        foo; bar;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.base('A'), result.base('B')]);
-    // Check that the condition is evaluated.
-    // TODO(polux): bar's type could be inferred to be {int} here.
-    result.checkNodeHasType('bar', [result.int, result.nullType]);
-  });
-}
-
-testFor3() {
-  final String source = r"""
-      main() {
-        var i = 1;
-        for(;;) {
-          var x = 2;
-          i = x;
-        }
-        i;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('i', [result.int]);
-  });
-}
-
-testForIn() {
-  final String source = r"""
-      class MyIterator {
-        var counter = 0;
-
-        moveNext() {
-          if (counter == 0) {
-            counter = 1;
-            return true;
-          } else if (counter == 1) {
-            counter = 2;
-            return true;
-          } else {
-            return false;
-          }
-        }
-
-        get current => (counter == 1) ? "foo" : 42;
-      }
-
-      class MyIterable {
-        get iterator => new MyIterator();
-      }
-
-      main() {
-        var res;
-        for (var i in new MyIterable()) {
-          res = i;
-        }
-        res;
-      }
-      """;
-  return analyze(source).then((AnalysisResult result) {
-    result.checkNodeHasType('res',
-        [result.int, result.string, result.nullType]);
-  });
-}
-
-testToplevelVariable() {
-  final String source = r"""
-      final top = 'abc';
-      class A {
-         f() => top;
-      }
-      main() {
-        var foo = top;
-        var bar = new A().f();
-        foo; bar;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.string]);
-    result.checkNodeHasType('bar', [result.string]);
-  });
-}
-
-testToplevelVariable2() {
-  final String source = r"""
-      class A {
-        var x;
-      }
-      final top = new A().x;
-
-      main() {
-        var a = new A();
-        a.x = 42;
-        a.x = "abc";
-        var foo = top;
-        foo;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.nullType, result.int,
-                                    result.string]);
-  });
-}
-
-testToplevelVariable3() {
-  final String source = r"""
-      var top = "a";
-
-      f() => top;
-
-      main() {
-        var foo = f();
-        var bar = top;
-        top = 42;
-        var baz = top;
-        foo; bar; baz;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int, result.string]);
-    result.checkNodeHasType('bar', [result.int, result.string]);
-    result.checkNodeHasType('baz', [result.int, result.string]);
-  });
-}
-
-testNonRecusiveFunction() {
-  final String source = r"""
-      f(x, y) => true ? x : y;
-      main() { var foo = f(42, "abc"); foo; }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int, result.string]);
-  });
-}
-
-testMultipleReturns() {
-  final String source = r"""
-      f(x, y) {
-        if (true) return x;
-        else return y;
-      }
-      main() { var foo = f(42, "abc"); foo; }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int, result.string]);
-  });
-}
-
-testRecusiveFunction() {
-  final String source = r"""
-      f(x) {
-        if (true) return x;
-        else return f(true ? x : "abc");
-      }
-      main() { var foo = f(42); foo; }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int, result.string]);
-  });
-}
-
-testMutuallyRecusiveFunction() {
-  final String source = r"""
-      f() => true ? 42 : g();
-      g() => true ? "abc" : f();
-      main() { var foo = f(); foo; }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int, result.string]);
-  });
-}
-
-testSimpleSend() {
-  final String source = """
-      class A {
-        f(x) => x;
-      }
-      class B {
-        f(x) => 'abc';
-      }
-      class C {
-        f(x) => 3.14;
-      }
-      class D {
-        var f;  // we check that this field is ignored in calls to dynamic.f()
-        D(this.f);
-      }
-      main() {
-        new B(); new D(42); // we instantiate B and D but not C
-        var foo = new A().f(42);
-        var bar = $DYNAMIC.f(42);
-        foo; bar;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int]);
-    result.checkNodeHasType('bar', [result.int, result.string]);
-  });
-}
-
-testSendToThis1() {
-  final String source = r"""
-      class A {
-        A();
-        f() => g();
-        g() => 42;
-      }
-      main() {
-        var foo = new A().f();
-        foo;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int]);
-  });
-}
-
-testSendToThis2() {
-  final String source = r"""
-      class A {
-        foo() => this;
-      }
-      class B extends A {
-        bar() => foo();
-      }
-      main() {
-        var x = new B().bar();
-        x;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('x', [result.base('B')]);
-  });
-}
-
-testSendToThis3() {
-  final String source = r"""
-      class A {
-        bar() => 42;
-        foo() => bar();
-      }
-      class B extends A {
-        bar() => "abc";
-      }
-      main() {
-        var x = new B().foo();
-        x;
-      }
-      """;
-  return analyze(source).then((AnalysisResult result) {
-    result.checkNodeHasType('x', [result.string]);
-  });
-}
-
-testSendToThis4() {
-  final String source = """
-      class A {
-        bar() => 42;
-        foo() => bar();
-      }
-      class B extends A {
-        bar() => "abc";
-      }
-      main() {
-        new A(); new B();  // make A and B seen
-        var x = $DYNAMIC.foo();
-        x;
-      }
-      """;
-  return analyze(source).then((AnalysisResult result) {
-    result.checkNodeHasType('x', [result.int, result.string]);
-  });
-}
-
-testConstructor() {
-  final String source = r"""
-      class A {
-        var x, y, z;
-        A(this.x, a) : y = a { z = 'abc'; }
-      }
-      main() {
-        new A(42, 'abc');
-        new A(true, null);
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkFieldHasType('A', 'x', [result.int, result.bool]);
-    result.checkFieldHasType('A', 'y', [result.string, result.nullType]);
-    result.checkFieldHasType('A', 'z', [result.string]);
-  });
-}
-
-testGetters() {
-  final String source = """
-      class A {
-        var x;
-        A(this.x);
-        get y => x;
-        get z => y;
-      }
-      class B {
-        var x;
-        B(this.x);
-      }
-      main() {
-        var a = new A(42);
-        var b = new B('abc');
-        var foo = a.x;
-        var bar = a.y;
-        var baz = a.z;
-        var qux = null.x;
-        var quux = $DYNAMIC.x;
-        foo; bar; baz; qux; quux;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int]);
-    result.checkNodeHasType('bar', [result.int]);
-    result.checkNodeHasType('baz', [result.int]);
-    result.checkNodeHasType('qux', []);
-    result.checkNodeHasType('quux', [result.int, result.string]);
-  });
-}
-
-testDynamicGetters() {
-  final String source = """
-      class A {
-        get x => f();
-        f() => 42;
-      }
-      class B extends A {
-        f() => "abc";
-      }
-      main() {
-        new A(); new B();  // make A and B seen
-        var x = $DYNAMIC.x;
-        x;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('x', [result.int, result.string]);
-  });
-}
-
-testToplevelGetters() {
-  final String source = """
-      int _x = 42;
-      get x => _x;
-
-      f() => x;
-
-      main() {
-        var foo = f();
-        var bar = x;
-        _x = "a";
-        var baz = x;
-        foo; bar; baz;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int, result.string]);
-    result.checkNodeHasType('bar', [result.int, result.string]);
-    result.checkNodeHasType('baz', [result.int, result.string]);
-  });
-}
-
-testSetters() {
-  final String source = """
-      class A {
-        var x;
-        var w;
-        A(this.x, this.w);
-        set y(a) { x = a; z = a; }
-        set z(a) { w = a; }
-      }
-      class B {
-        var x;
-        B(this.x);
-      }
-      main() {
-        var a = new A(42, 42);
-        var b = new B(42);
-        a.x = 'abc';
-        a.y = true;
-        null.x = 42;  // should be ignored
-        $DYNAMIC.x = null;
-        $DYNAMIC.y = 3.14;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkFieldHasType('B', 'x',
-                             [result.int,         // new B(42)
-                              result.nullType]);  // dynamic.x = null
-    result.checkFieldHasType('A', 'x',
-                             [result.int,       // new A(42, ...)
-                              result.string,    // a.x = 'abc'
-                              result.bool,      // a.y = true
-                              result.nullType,  // dynamic.x = null
-                              result.double]);  // dynamic.y = 3.14
-    result.checkFieldHasType('A', 'w',
-                             [result.int,       // new A(..., 42)
-                              result.bool,      // a.y = true
-                              result.double]);  // dynamic.y = 3.14
-  });
-}
-
-testToplevelSetters() {
-  final String source = """
-      int _x = 42;
-      set x(y) => _x = y;
-
-      f(y) { x = y; }
-
-      main() {
-        var foo = _x;
-        x = "a";
-        var bar = _x;
-        f(true);
-        var baz = _x;
-        foo; bar; baz;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int, result.string, result.bool]);
-    result.checkNodeHasType('bar', [result.int, result.string, result.bool]);
-    result.checkNodeHasType('baz', [result.int, result.string, result.bool]);
-  });
-}
-
-
-testOptionalNamedParameters() {
-  final String source = r"""
-      class A {
-        var x, y, z, w;
-        A(this.x, {this.y, this.z, this.w});
-      }
-      class B {
-        var x, y;
-        B(this.x, {this.y});
-      }
-      class C {
-        var x, y;
-        C(this.x, {this.y});
-      }
-      class Test {
-        var a, b, c, d;
-        var e, f;
-        var g, h;
-
-        Test(this.a, this.b, this.c, this.d,
-             this.e, this.f,
-             this.g, this.h);
-
-        f1(x, {y, z, w}) {
-          a = x;
-          b = y;
-          c = z;
-          d = w;
-        }
-        f2(x, {y}) {
-          e = x;
-          f = y;
-        }
-        f3(x, {y}) {
-          g = x;
-          h = y;
-        }
-      }
-      class Foo {
-      }
-      main() {
-        // We want to test expiclitely for null later so we initialize all the
-        // fields of Test with a placeholder type: Foo.
-        var foo = new Foo();
-        var test = new Test(foo, foo, foo, foo, foo, foo, foo, foo);
-
-        new A(42);
-        new A('abc', w: true, z: 42.1);
-        test.f1(42);
-        test.f1('abc', w: true, z: 42.1);
-
-        new B('abc', y: true);
-        new B(1, 2);  // too many positional arguments
-        test.f2('abc', y: true);
-        test.f2(1, 2);  // too many positional arguments
-
-        new C('abc', y: true);
-        new C(1, z: 2);  // non-existing named parameter
-        test.f3('abc', y: true);
-        test.f3(1, z: 2);  // non-existing named parameter
-      }
-      """;
-  return analyze(source).then((result) {
-
-    final foo = result.base('Foo');
-    final nil = result.nullType;
-
-    result.checkFieldHasType('A', 'x', [result.int, result.string]);
-    result.checkFieldHasType('A', 'y', [nil]);
-    result.checkFieldHasType('A', 'z', [nil, result.double]);
-    result.checkFieldHasType('A', 'w', [nil, result.bool]);
-    result.checkFieldHasType('Test', 'a', [foo, result.int, result.string]);
-    result.checkFieldHasType('Test', 'b', [foo, nil]);
-    result.checkFieldHasType('Test', 'c', [foo, nil, result.double]);
-    result.checkFieldHasType('Test', 'd', [foo, nil, result.bool]);
-
-    result.checkFieldHasType('B', 'x', [result.string]);
-    result.checkFieldHasType('B', 'y', [result.bool]);
-    result.checkFieldHasType('Test', 'e', [foo, result.string]);
-    result.checkFieldHasType('Test', 'f', [foo, result.bool]);
-
-    result.checkFieldHasType('C', 'x', [result.string]);
-    result.checkFieldHasType('C', 'y', [result.bool]);
-    result.checkFieldHasType('Test', 'g', [foo, result.string]);
-    result.checkFieldHasType('Test', 'h', [foo, result.bool]);
-  });
-}
-
-testOptionalPositionalParameters() {
-  final String source = r"""
-    class A {
-      var x, y, z, w;
-      A(this.x, [this.y, this.z, this.w]);
-    }
-    class B {
-      var x, y;
-      B(this.x, [this.y]);
-    }
-    class Test {
-      var a, b, c, d;
-      var e, f;
-
-      Test(this.a, this.b, this.c, this.d,
-           this.e, this.f);
-
-      f1(x, [y, z, w]) {
-        a = x;
-        b = y;
-        c = z;
-        d = w;
-      }
-      f2(x, [y]) {
-        e = x;
-        f = y;
-      }
-    }
-    class Foo {
-    }
-    main() {
-      // We want to test expiclitely for null later so we initialize all the
-      // fields of Test with a placeholder type: Foo.
-      var foo = new Foo();
-      var test = new Test(foo, foo, foo, foo, foo, foo);
-
-      new A(42);
-      new A('abc', true, 42.1);
-      test.f1(42);
-      test.f1('abc', true, 42.1);
-
-      new B('a', true);
-      new B(1, 2, 3);  // too many arguments
-      test.f2('a', true);
-      test.f2(1, 2, 3);  // too many arguments
-    }
-  """;
-  return analyze(source).then((result) {
-
-    final foo = result.base('Foo');
-    final nil = result.nullType;
-
-    result.checkFieldHasType('A', 'x', [result.int, result.string]);
-    result.checkFieldHasType('A', 'y', [nil, result.bool]);
-    result.checkFieldHasType('A', 'z', [nil, result.double]);
-    result.checkFieldHasType('A', 'w', [nil]);
-    result.checkFieldHasType('Test', 'a', [foo, result.int, result.string]);
-    result.checkFieldHasType('Test', 'b', [foo, nil, result.bool]);
-    result.checkFieldHasType('Test', 'c', [foo, nil, result.double]);
-    result.checkFieldHasType('Test', 'd', [foo, nil]);
-
-    result.checkFieldHasType('B', 'x', [result.string]);
-    result.checkFieldHasType('B', 'y', [result.bool]);
-    result.checkFieldHasType('Test', 'e', [foo, result.string]);
-    result.checkFieldHasType('Test', 'f', [foo, result.bool]);
-  });
-}
-
-testListLiterals() {
-  final String source = r"""
-      class A {
-        var x;
-        A(this.x);
-      }
-      main() {
-        var x = [];
-        var y = [1, "a", null, new A(42)];
-        x; y;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('x', [result.growableList]);
-    result.checkNodeHasType('y', [result.growableList]);
-    result.checkFieldHasType('A', 'x', [result.int]);
-  });
-}
-
-testMapLiterals() {
-  final String source = r"""
-      class A {
-        var x;
-        A(this.x);
-      }
-      main() {
-        var x = {};
-        var y = {'a': "foo", 'b': new A(42) };
-        x; y;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('x', [result.map]);
-    result.checkNodeHasType('y', [result.map]);
-    result.checkFieldHasType('A', 'x', [result.int]);
-  });
-}
-
-testReturn() {
-  final String source = r"""
-      f() { if (true) { return 1; }; return "a"; }
-      g() { f(); return; }
-      main() {
-        var x = f();
-        var y = g();
-        x; y;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('x', [result.int, result.string]);
-    result.checkNodeHasType('y', [result.nullType]);
-  });
-}
-
-testNoReturn() {
-  final String source = r"""
-      f() { if (true) { return 1; }; }
-      g() { f(); }
-      main() {
-        var x = f();
-        var y = g();
-        x; y;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('x', [result.int, result.nullType]);
-    result.checkNodeHasType('y', [result.nullType]);
-  });
-}
-
-testArithmeticOperators() {
-  String source(op) {
-    return """
-        main() {
-          var a = 1 $op 2;
-          var b = 1 $op 2.1;
-          var c = 1.1 $op 2;
-          var d = 1.1 $op 2.1;
-          var e = (1 $op 2.1) $op 1;
-          var f = 1 $op (1 $op 2.1);
-          var g = (1 $op 2.1) $op 1.1;
-          var h = 1.1 $op (1 $op 2);
-          var i = (1 $op 2) $op 1;
-          var j = 1 $op (1 $op 2);
-          var k = (1.1 $op 2.1) $op 1.1;
-          var l = 1.1 $op (1.1 $op 2.1);
-          a; b; c; d; e; f; g; h; i; j; k; l;
-        }""";
-  }
-  return Future.forEach(['+', '*', '-'], (String op) {
-    return analyze(source(op)).then((result) {
-      result.checkNodeHasType('a', [result.int]);
-      result.checkNodeHasType('b', [result.num]);
-      result.checkNodeHasType('c', [result.num]);
-      result.checkNodeHasType('d', [result.double]);
-      result.checkNodeHasType('e', [result.num]);
-      result.checkNodeHasType('f', [result.num]);
-      result.checkNodeHasType('g', [result.num]);
-      result.checkNodeHasType('h', [result.num]);
-      result.checkNodeHasType('i', [result.int]);
-      result.checkNodeHasType('j', [result.int]);
-      result.checkNodeHasType('k', [result.double]);
-      result.checkNodeHasType('l', [result.double]);
-    });
-  });
-}
-
-testBooleanOperators() {
-  String source(op) {
-    return """
-        main() {
-          var a = true $op null;
-          var b = null $op true;
-          var c = 1 $op true;
-          var d = true $op "a";
-          a; b; c; d;
-        }""";
-  }
-  return Future.forEach(['&&', '||'], (String op) {
-    return analyze(source(op)).then((result) {
-      result.checkNodeHasType('a', [result.bool]);
-      result.checkNodeHasType('b', [result.bool]);
-      result.checkNodeHasType('c', [result.bool]);
-      result.checkNodeHasType('d', [result.bool]);
-    });
-  });
-}
-
-testBooleanOperatorsShortCirtcuit() {
-  String source(op) {
-    return """
-        main() {
-          var x = null;
-          "foo" $op (x = 42);
-          x;
-        }""";
-  }
-  return Future.forEach(['&&', '||'], (String op) {
-    return analyze(source(op)).then((AnalysisResult result) {
-      result.checkNodeHasType('x', [result.nullType, result.int]);
-    });
-  });
-}
-
-testOperators() {
-  final String source = r"""
-      class A {
-        operator <(x) => 42;
-        operator <<(x) => "a";
-      }
-      main() {
-        var x = new A() < "foo";
-        var y = new A() << "foo";
-        x; y;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('x', [result.int]);
-    result.checkNodeHasType('y', [result.string]);
-  });
-}
-
-testSetIndexOperator() {
-  final String source = r"""
-      class A {
-        var witness1;
-        var witness2;
-        operator []=(i, x) { witness1 = i; witness2 = x; }
-      }
-      main() {
-        var x = new A()[42] = "abc";
-        x;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('x', [result.string]);
-    result.checkFieldHasType('A', 'witness1', [result.int, result.nullType]);
-    result.checkFieldHasType('A', 'witness2', [result.string, result.nullType]);
-  });
-}
-
-testCompoundOperators1() {
-  final String source = r"""
-      class A {
-        operator +(x) => "foo";
-      }
-      main() {
-        var x1 = 1;
-        x1++;
-        var x2 = 1;
-        ++x2;
-        var x3 = 1;
-        x3 += 42;
-        var x4 = new A();
-        x4++;
-        var x5 = new A();
-        ++x5;
-        var x6 = new A();
-        x6 += true;
-
-        x1; x2; x3; x4; x5; x6;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('x1', [result.int]);
-    result.checkNodeHasType('x2', [result.int]);
-    result.checkNodeHasType('x3', [result.int]);
-    result.checkNodeHasType('x4', [result.string]);
-    result.checkNodeHasType('x5', [result.string]);
-    result.checkNodeHasType('x6', [result.string]);
-  });
-}
-
-
-testCompoundOperators2() {
-  final String source = r"""
-    class A {
-      var xx;
-      var yy;
-      var witness1;
-      var witness2;
-      var witness3;
-      var witness4;
-
-      A(this.xx, this.yy);
-      get x { witness1 = "foo"; return xx; }
-      set x(a) { witness2 = "foo"; xx = a; }
-      get y { witness3 = "foo"; return yy; }
-      set y(a) { witness4 = "foo"; yy = a; }
-    }
-    main () {
-      var a = new A(1, 1);
-      a.x++;
-      a.y++;
-    }
-    """;
-  return analyze(source).then((result) {
-    result.checkFieldHasType('A', 'xx', [result.int]);
-    result.checkFieldHasType('A', 'yy', [result.int]);
-    result.checkFieldHasType('A', 'witness1', [result.string, result.nullType]);
-    result.checkFieldHasType('A', 'witness2', [result.string, result.nullType]);
-    result.checkFieldHasType('A', 'witness3', [result.string, result.nullType]);
-    result.checkFieldHasType('A', 'witness4', [result.string, result.nullType]);
-  });
-}
-
-testInequality() {
-  final String source = r"""
-      class A {
-        var witness;
-        operator ==(x) { witness = "foo"; return "abc"; }
-      }
-      class B {
-        operator ==(x) { throw "error"; }
-      }
-      main() {
-        var foo = 1 != 2;
-        var bar = (new A() != 2);
-        var baz = (new B() != 2);
-        foo; bar; baz;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.bool]);
-    result.checkNodeHasType('bar', [result.bool]);
-    // TODO(polux): could be even better: empty
-    result.checkNodeHasType('baz', [result.bool]);
-    result.checkFieldHasType('A', 'witness', [result.string, result.nullType]);
-  });
-}
-
-testFieldInitialization1() {
-  final String source = r"""
-    class A {
-      var x;
-      var y = 1;
-    }
-    class B extends A {
-      var z = "foo";
-    }
-    main () {
-      // we need to access y and z once to trigger their analysis
-      new B().y;
-      new B().z;
-    }
-    """;
-  return analyze(source).then((result) {
-    result.checkFieldHasType('A', 'x', [result.nullType]);
-    result.checkFieldHasType('A', 'y', [result.int]);
-    result.checkFieldHasType('B', 'z', [result.string]);
-  });
-}
-
-testFieldInitialization2() {
-  final String source = r"""
-    var top = 42;
-    class A {
-      var x = top;
-    }
-    main () {
-      // we need to access X once to trigger its analysis
-      new A().x;
-    }
-    """;
-  return analyze(source).then((result) {
-    result.checkFieldHasType('A', 'x', [result.int]);
-  });
-}
-
-testFieldInitialization3() {
-  final String source = r"""
-    class A {
-      var x;
-    }
-    f() => new A().x;
-    class B {
-      var x = new A().x;
-      var y = f();
-    }
-    main () {
-      var foo = new B().x;
-      var bar = new B().y;
-      new A().x = "a";
-      foo; bar;
-    }
-    """;
-  return analyze(source).then((result) {
-    // checks that B.B is set as a reader of A.x
-    result.checkFieldHasType('B', 'x', [result.nullType, result.string]);
-    // checks that B.B is set as a caller of f
-    result.checkFieldHasType('B', 'y', [result.nullType, result.string]);
-    // checks that readers of x are notified by changes in x's type
-    result.checkNodeHasType('foo', [result.nullType, result.string]);
-    // checks that readers of y are notified by changes in y's type
-    result.checkNodeHasType('bar', [result.nullType, result.string]);
-  });
-}
-
-testLists() {
-  final String source = """
-    class A {}
-    class B {}
-    class C {}
-    class D {}
-    class E {}
-    class F {}
-    class G {}
-
-    main() {
-      var l1 = [new A()];
-      var l2 = [];
-      l1['a'] = new B();  // raises an error, so B should not be recorded
-      l1[1] = new C();
-      l1.add(new D());
-      l1.insert('a', new E());  // raises an error, so E should not be recorded
-      l1.insert(1, new F());
-      $DYNAMIC[1] = new G();
-      var x1 = l1[1];
-      var x2 = l2[1];
-      var x3 = l1['foo'];  // raises an error, should return empty
-      var x4 = l1.removeAt(1);
-      var x5 = l2.removeAt(1);
-      var x6 = l1.removeAt('a');  // raises an error, should return empty
-      var x7 = l1.removeLast();
-      var x8 = l2.removeLast();
-      x1; x2; x3; x4; x5; x6; x7; x8;
-    }""";
-  return analyze(source).then((result) {
-    final expectedTypes = ['A', 'C', 'D', 'F', 'G'].map(result.base).toList();
-    result.checkNodeHasType('x1', expectedTypes);
-    result.checkNodeHasType('x2', expectedTypes);
-    result.checkNodeHasType('x3', []);
-    result.checkNodeHasType('x4', expectedTypes);
-    result.checkNodeHasType('x5', expectedTypes);
-    result.checkNodeHasType('x6', []);
-    result.checkNodeHasType('x7', expectedTypes);
-    result.checkNodeHasType('x8', expectedTypes);
-  });
-}
-
-testListWithCapacity() {
-  final String source = r"""
-    main() {
-      var l = new List(10);
-      var x = [][0];
-      x;
-    }""";
-  return analyze(source).then((result) {
-    result.checkNodeHasType('x', [result.nullType]);
-  });
-}
-
-testEmptyList() {
-  final String source = r"""
-    main() {
-      var l = new List();
-      var x = l[0];
-      x;
-    }""";
-  return analyze(source).then((result) {
-    result.checkNodeHasType('x', []);
-  });
-}
-
-testSendWithWrongArity() {
-  final String source = r"""
-    f(x) { }
-    class A { g(x) { } }
-    main () {
-      var x = f();
-      var y = f(1, 2);
-      var z = new A().g();
-      var w = new A().g(1, 2);
-      x; y; z; w;
-    }
-    """;
-  return analyze(source).then((result) {
-    // TODO(polux): It would be better if x and y also had the empty type. This
-    // requires a change in SimpleTypeInferrerVisitor.visitStaticSend which
-    // would impact the default type inference and possibly break dart2js.
-    // Keeping this change for a later CL.
-    result.checkNodeHasUnknownType('x');
-    result.checkNodeHasUnknownType('y');
-    result.checkNodeHasType('z', []);
-    result.checkNodeHasType('w', []);
-  });
-}
-
-testBigTypesWidening1() {
-  final String source = r"""
-    small() => true ? 1 : 'abc';
-    big() => true ? 1 : (true ? 'abc' : false);
-    main () {
-      var x = small();
-      var y = big();
-      x; y;
-    }
-    """;
-  return analyze(source, maxConcreteTypeSize: 2).then((result) {
-    result.checkNodeHasType('x', [result.int, result.string]);
-    result.checkNodeHasUnknownType('y');
-  });
-}
-
-testBigTypesWidening2() {
-  final String source = r"""
-    class A {
-      var x, y;
-      A(this.x, this.y);
-    }
-    main () {
-      var a = new A(1, 1);
-      a.x = 'abc';
-      a.y = 'abc';
-      a.y = true;
-    }
-    """;
-  return analyze(source, maxConcreteTypeSize: 2).then((result) {
-    result.checkFieldHasType('A', 'x', [result.int, result.string]);
-    result.checkFieldHasUknownType('A', 'y');
-  });
-}
-
-testDynamicIsAbsorbing() {
-  final String source = """
-    main () {
-      var x = 1;
-      if (true) {
-        x = $DYNAMIC;
-      } else {
-        x = 42;
-      }
-      x;
-    }
-    """;
-  return analyze(source).then((result) {
-    result.checkNodeHasUnknownType('x');
-  });
-}
-
-testJsCall() {
-  final String source = r"""
-    import 'dart:_foreign_helper';
-    import 'dart:_interceptors';
-
-    abstract class AbstractA {}
-    class A extends AbstractA {}
-    class B extends A {}
-    class BB extends B {}
-    class C extends A {}
-    class D implements A {}
-    class E extends A {}
-
-    class X {}
-
-    main () {
-      // we don't create any E on purpose
-      new B(); new BB(); new C(); new D();
-
-      var a = JS('', '1');
-      var b = JS('Object', '1');
-      var c = JS('JSExtendableArray', '1');
-      var cNull = JS('JSExtendableArray|Null', '1');
-      var d = JS('String', '1');
-      var dNull = JS('String|Null', '1');
-      var e = JS('int', '1');
-      var eNull = JS('int|Null', '1');
-      var f = JS('double', '1');
-      var fNull = JS('double|Null', '1');
-      var g = JS('num', '1');
-      var gNull = JS('num|Null', '1');
-      var h = JS('bool', '1');
-      var hNull = JS('bool|Null', '1');
-      var i = JS('AbstractA', '1');
-      var iNull = JS('AbstractA|Null', '1');
-
-      a; b; c; cNull; d; dNull; e; eNull; f; fNull; g; gNull; h; hNull; i;
-      iNull;
-    }
-    """;
-  return analyze(source, maxConcreteTypeSize: 6).then((result) {
-    List maybe(List types) => new List.from(types)..add(result.nullType);
-    // a and b have all the types seen by the resolver, which are more than 6
-    result.checkNodeHasUnknownType('a');
-    result.checkNodeHasUnknownType('b');
-    final expectedCType = [result.growableList];
-    result.checkNodeHasType('c', expectedCType);
-    result.checkNodeHasType('cNull', maybe(expectedCType));
-    final expectedDType = [result.string];
-    result.checkNodeHasType('d', expectedDType);
-    result.checkNodeHasType('dNull', maybe(expectedDType));
-    final expectedEType = [result.int];
-    result.checkNodeHasType('e', expectedEType);
-    result.checkNodeHasType('eNull', maybe(expectedEType));
-    final expectedFType = [result.num];
-    result.checkNodeHasType('f', expectedFType);
-    result.checkNodeHasType('fNull', maybe(expectedFType));
-    final expectedGType = [result.num];
-    result.checkNodeHasType('g', expectedGType);
-    result.checkNodeHasType('gNull', maybe(expectedGType));
-    final expectedType = [result.bool];
-    result.checkNodeHasType('h', expectedType);
-    result.checkNodeHasType('hNull', maybe(expectedType));
-    final expectedIType = [result.base('B'),
-                           result.base('BB'),
-                           result.base('C'),
-                           result.base('D')];
-    result.checkNodeHasType('i', expectedIType);
-    result.checkNodeHasType('iNull', maybe(expectedIType));
-  });
-}
-
-testJsCallAugmentsSeenClasses() {
-  final String source1 = """
-    main () {
-      var x = $DYNAMIC.truncate();
-      x;
-    }
-    """;
-  return analyze(source1).then((AnalysisResult result) {
-    result.checkNodeHasType('x', []);
-  }).whenComplete(() {
-
-    final String source2 = """
-      import 'dart:_foreign_helper';
-
-      main () {
-        var x = $DYNAMIC.truncate();
-        JS('double', 'foo');
-        x;
-      }
-      """;
-    return analyze(source2).then((AnalysisResult result) {
-      result.checkNodeHasType('x', [result.int]);
-    });
-  });
-}
-
-testIsCheck() {
-  final String source = r"""
-    main () {
-      var x = (1 is String);
-      x;
-    }
-    """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('x', [result.bool]);
-  });
-}
-
-testSeenClasses() {
-  final String source = """
-      class A {
-        witness() => 42;
-      }
-      class B {
-        witness() => "string";
-      }
-      class AFactory {
-        onlyCalledInAFactory() => new A();
-      }
-      class BFactory {
-        onlyCalledInAFactory() => new B();
-      }
-
-      main() {
-        new AFactory().onlyCalledInAFactory();
-        new BFactory();
-        // should be of type {int} and not {int, String} since B is unreachable
-        var foo = $DYNAMIC.witness();
-        foo;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int]);
-  });
-}
-
-testIntDoubleNum() {
-  final String source = r"""
-      main() {
-        var a = 1;
-        var b = 1.1;
-        var c = true ? 1 : 1.1;
-        a; b; c;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('a', [result.int]);
-    result.checkNodeHasType('b', [result.double]);
-    result.checkNodeHasType('c', [result.num]);
-  });
-}
-
-testConcreteTypeToTypeMask() {
-  final String source = r"""
-      class A {}
-      class B extends A {}
-      class C extends A {}
-      class D implements A {}
-      main() {
-        new A();
-        new B();
-        new C();
-        new D();
-      }
-      """;
-  return analyze(source).then((result) {
-
-  convert(ConcreteType type) {
-    return result.compiler.typesTask.concreteTypesInferrer
-        .types.concreteTypeToTypeMask(type);
-  }
-
-    final nullSingleton =
-        result.compiler.typesTask.concreteTypesInferrer.singletonConcreteType(
-            new NullBaseType());
-
-    singleton(ClassElement element) {
-      return result.compiler.typesTask.concreteTypesInferrer
-          .singletonConcreteType(new ClassBaseType(element));
-    }
-
-    var world = result.compiler.world;
-
-    ClassElement a = findElement(result.compiler, 'A');
-    ClassElement b = findElement(result.compiler, 'B');
-    ClassElement c = findElement(result.compiler, 'C');
-    ClassElement d = findElement(result.compiler, 'D');
-
-    for (ClassElement cls in [a, b, c, d]) {
-      Expect.equals(convert(singleton(cls)),
-                    new TypeMask.nonNullExact(cls, world));
-    }
-
-    for (ClassElement cls in [a, b, c, d]) {
-      Expect.equals(convert(singleton(cls).union(nullSingleton)),
-                    new TypeMask.exact(cls, world));
-    }
-
-    Expect.equals(convert(singleton(a).union(singleton(b))),
-                  new TypeMask.nonNullSubclass(a, world));
-
-    Expect.equals(
-        convert(singleton(a).union(singleton(b)).union(nullSingleton)),
-                  new TypeMask.subclass(a, world));
-
-    Expect.equals(
-        simplify(convert(singleton(b).union(singleton(d))), result.compiler),
-        new TypeMask.nonNullSubtype(a, world));
-  });
-}
-
-testSelectors() {
-  final String source = r"""
-      // ABC <--- A
-      //       `- BC <--- B
-      //               `- C
-
-      class ABC {}
-      class A extends ABC {}
-      class BC extends ABC {}
-      class B extends BC {}
-      class C extends BC {}
-
-      class XY {}
-      class X extends XY { foo() => new B(); }
-      class Y extends XY { foo() => new C(); }
-      class Z { foo() => new A(); }
-
-      main() {
-        new X().foo();
-        new Y().foo();
-        new Z().foo();
-      }
-      """;
-  return analyze(source).then((result) {
-
-    var world = result.compiler.world;
-
-    ClassElement a = findElement(result.compiler, 'A');
-    ClassElement b = findElement(result.compiler, 'B');
-    ClassElement c = findElement(result.compiler, 'C');
-    ClassElement xy = findElement(result.compiler, 'XY');
-    ClassElement x = findElement(result.compiler, 'X');
-    ClassElement y = findElement(result.compiler, 'Y');
-    ClassElement z = findElement(result.compiler, 'Z');
-
-    Selector foo =
-        new Selector.call(const PublicName("foo"), CallStructure.NO_ARGS);
-
-    result.checkSelectorHasType(
-        foo,
-        null,
-        new TypeMask.unionOf([a, b, c]
-            .map((cls) => new TypeMask.nonNullExact(cls, world)),
-            result.compiler.world));
-    result.checkSelectorHasType(
-        foo,
-        new TypeMask.subclass(x, world),
-        new TypeMask.nonNullExact(b, world));
-    result.checkSelectorHasType(
-        foo,
-        new TypeMask.subclass(y, world),
-        new TypeMask.nonNullExact(c, world));
-    result.checkSelectorHasType(
-        foo,
-        new TypeMask.subclass(z, world),
-        new TypeMask.nonNullExact(a, world));
-    result.checkSelectorHasType(
-        foo,
-        new TypeMask.subclass(xy, world),
-        new TypeMask.unionOf([b, c].map((cls) =>
-            new TypeMask.nonNullExact(cls, world)), world));
-
-    result.checkSelectorHasType(
-        new Selector.call(const PublicName("bar"), CallStructure.NO_ARGS),
-        null, null);
-  });
-}
-
-testEqualsNullSelector() {
-  final String source = r"""
-      main() {
-        1 == null;
-      }
-      """;
-  return analyze(source).then((result) {
-    ClassElement bool = result.compiler.backend.boolImplementation;
-    result.checkSelectorHasType(new Selector.binaryOperator('=='),
-                                null,
-                                new TypeMask.nonNullExact(bool,
-                                    result.compiler.world));
-  });
-}
-
-testMixins() {
-  final String source = r"""
-      class A {
-        foo() => "abc";
-        get x => 42;
-      }
-      class B extends Object with A {
-        bar() => foo();
-        baz() => x;
-      }
-      main() {
-        var b = new B();
-        var x = b.foo();
-        var y = b.bar();
-        var z = b.x;
-        var w = b.baz();
-        x; y; z; w;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('x', [result.string]);
-    result.checkNodeHasType('y', [result.string]);
-    result.checkNodeHasType('z', [result.int]);
-    result.checkNodeHasType('w', [result.int]);
-  });
-}
-
-testClosures1() {
-  final String source = r"""
-      class A {
-        final foo = 42;
-      }
-      class B {
-        final foo = "abc";
-      }
-      class C {
-        final foo = true;
-      }
-      main() {
-        var a;
-        var f = (x) {
-          a = x.foo;
-        };
-        // We make sure that x doesn't have type dynamic by adding C to the
-        // set of seen classes and by checking that a's type doesn't contain
-        // bool.
-        new C();
-        f(new A());
-        f(new B());
-        a;
-      }
-      """;
-  return analyze(source).then((AnalysisResult result) {
-    result.checkNodeHasType('a', [result.nullType, result.int, result.string]);
-  });
-}
-
-testClosures2() {
-  final String source = r"""
-      class A {
-        final foo = 42;
-      }
-      class B {
-        final foo = "abc";
-      }
-      class C {
-        final foo = true;
-      }
-      main() {
-        // We make sure that x doesn't have type dynamic by adding C to the
-        // set of seen classes and by checking that a's type doesn't contain
-        // bool.
-        new C();
-
-        var a;
-        f(x) {
-          a = x.foo;
-        }
-        f(new A());
-        f(new B());
-        a; f;
-      }
-      """;
-  return analyze(source).then((AnalysisResult result) {
-    result.checkNodeHasType('a', [result.nullType, result.int, result.string]);
-    result.checkNodeHasType('f', [result.functionType]);
-  });
-}
-
-testClosures3() {
-  final String source = r"""
-      class A {
-        var g;
-        A(this.g);
-      }
-      main() {
-        var foo = new A((x) => x).g(42);
-        foo;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int]);
-  });
-}
-
-testClosures4() {
-  final String source = """
-      class A {
-        var f = $DYNAMIC;
-      }
-      main() {
-        var f = (x) => x;
-        var g = (x) => "a";
-        var h = (x, y) => true;
-
-        var foo = $DYNAMIC(42);
-        var bar = new A().f(1.2);
-        var baz = $DYNAMIC.f(null);
-
-        foo; bar; baz;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int, result.string]);
-    result.checkNodeHasType('bar', [result.double, result.string]);
-    result.checkNodeHasType('baz', [result.nullType, result.string]);
-  });
-}
-
-testClosures5() {
-  final String source = r"""
-      f(x) => x;
-      class A {
-        var g;
-        A(this.g);
-      }
-      main() {
-        var foo = new A(f).g(42);
-        foo;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int]);
-  });
-}
-
-testClosures6() {
-  final String source = r"""
-      class A {
-        var g;
-        A(this.g);
-      }
-      class B {
-        f(x) => x;
-      }
-      main() {
-        var foo = new A(new B().f).g(42);
-        foo;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int]);
-  });
-}
-
-testClosures7() {
-  final String source = r"""
-      class A {
-        final x = 42;
-        f() => () => x;
-      }
-      main() {
-        var foo = new A().f()();
-        foo;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int]);
-  });
-}
-
-testClosures8() {
-  final String source = r"""
-      class A {
-        final x = 42;
-        f() => () => x;
-      }
-      class B extends A {
-        get x => "a";
-      }
-      main() {
-        var foo = new B().f()();
-        foo;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.string]);
-  });
-}
-
-testClosures9() {
-  final String source = r"""
-      class A {
-        g() => 42;
-        f() => () => g();
-      }
-      class B extends A {
-        g() => "a";
-      }
-      main() {
-        var foo = new B().f()();
-        foo;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.string]);
-  });
-}
-
-testClosures10() {
-  final String source = r"""
-      class A {
-        f() => 42;
-      }
-      main() {
-        var a = new A();
-        g() => a.f();
-        var foo = g();
-        foo; a;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int]);
-  });
-}
-
-testClosures11() {
-  final String source = r"""
-      class A {
-        var x;
-        f() => x;
-      }
-      main() {
-        var a = new A();
-        f() => a.f();
-        a.x = 42;
-        var foo = f();
-        foo;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.nullType, result.int]);
-  });
-}
-
-testClosures12() {
-  final String source = r"""
-      var f = (x) => x;
-      main() {
-        var foo = f(1);
-        foo;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int]);
-  });
-}
-
-testRefinement() {
-  final String source = """
-      class A {
-        f() => null;
-        g() => 42;
-      }
-      class B {
-        g() => "aa";
-      }
-      main() {
-        var x = $DYNAMIC ? new A() : new B();
-        x.f();
-        var foo = x.g();
-        foo;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('foo', [result.int]);
-  });
-}
-
-testDefaultArguments() {
-  final String source = r"""
-      f1([x = 42]) => x;
-      g1([x]) => x;
-
-      f2({x: 42}) => x;
-      g2({x}) => x;
-
-      main() {
-        var xf1 = f1();
-        var xg1 = g1();
-        var xf2 = f2();
-        var xg2 = g2();
-        xf1; xg1; xf2; xg2;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkNodeHasType('xf1', [result.int]);
-    result.checkNodeHasType('xg1', [result.nullType]);
-    result.checkNodeHasType('xf2', [result.int]);
-    result.checkNodeHasType('xg2', [result.nullType]);
-  });
-}
-
-testSuperConstructorCall() {
-  final String source = r"""
-      class A {
-        final x;
-        A(this.x);
-      }
-
-      class B extends A {
-        B(x) : super(x);
-      }
-      main() {
-        var b = new B(42);
-        var foo = b.x;
-        foo;
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkFieldHasType('A', 'x', [result.int]);
-    result.checkNodeHasType('foo', [result.int]);
-  });
-}
-
-testSuperConstructorCall2() {
-  final String source = r"""
-      class A {
-        var x;
-        A() {
-          x = 42;
-        }
-      }
-      class B extends A {
-      }
-      main() {
-        new B();
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkFieldHasType('A', 'x', [result.int]);
-  });
-}
-
-testSuperConstructorCall3() {
-  final String source = r"""
-      class A {
-        var x;
-        A() {
-          x = 42;
-        }
-      }
-      class B extends A {
-        B(unused) {}
-      }
-      main() {
-        new B("abc");
-      }
-      """;
-  return analyze(source).then((result) {
-    result.checkFieldHasType('A', 'x', [result.int]);
-  });
-}
-
-void main() {
-  asyncTest(() => Future.forEach([
-    testDynamicBackDoor,
-    testVariableDeclaration,
-    testLiterals,
-    testRedefinition,
-    testIfThenElse,
-    testTernaryIf,
-    testWhile,
-    testDoWhile,
-    testFor1,
-    testFor2,
-    testFor3,
-    testForIn,
-    testToplevelVariable,
-    testToplevelVariable2,
-    testToplevelVariable3,
-    testNonRecusiveFunction,
-    testMultipleReturns,
-    testRecusiveFunction,
-    testMutuallyRecusiveFunction,
-    testSimpleSend,
-    testSendToThis1,
-    testSendToThis2,
-    testSendToThis3,
-    testSendToThis4,
-    testConstructor,
-    testGetters,
-    testToplevelGetters,
-    testDynamicGetters,
-    testSetters,
-    testToplevelSetters,
-    testOptionalNamedParameters,
-    testOptionalPositionalParameters,
-    testListLiterals,
-    testMapLiterals,
-    testReturn,
-    testNoReturn,
-    testArithmeticOperators,
-    testBooleanOperators,
-    testBooleanOperatorsShortCirtcuit,
-    testOperators,
-    testCompoundOperators1,
-    testCompoundOperators2,
-    testSetIndexOperator,
-    testInequality,
-    testFieldInitialization1,
-    testFieldInitialization2,
-    testFieldInitialization3,
-    testSendWithWrongArity,
-    testBigTypesWidening1,
-    testBigTypesWidening2,
-    testDynamicIsAbsorbing,
-    testLists,
-    testListWithCapacity,
-    testEmptyList,
-    testJsCall,
-    testJsCallAugmentsSeenClasses,
-    testIsCheck,
-    testSeenClasses,
-    testIntDoubleNum,
-    testConcreteTypeToTypeMask,
-    testSelectors,
-    // TODO(polux): this test is failing, see http://dartbug.com/16825.
-    //testEqualsNullSelector,
-    testMixins,
-    testClosures1,
-    testClosures2,
-    testClosures3,
-    testClosures4,
-    testClosures5,
-    testClosures6,
-    testClosures7,
-    testClosures8,
-    testClosures9,
-    testClosures10,
-    testClosures11,
-    testClosures12,
-    testRefinement,
-    testDefaultArguments,
-    testSuperConstructorCall,
-    testSuperConstructorCall2,
-    testSuperConstructorCall3,
-  ], (f) => f()));
-}
diff --git a/tests/compiler/dart2js/diagnostic_reporter_helper.dart b/tests/compiler/dart2js/diagnostic_reporter_helper.dart
new file mode 100644
index 0000000..0bff795
--- /dev/null
+++ b/tests/compiler/dart2js/diagnostic_reporter_helper.dart
@@ -0,0 +1,75 @@
+// 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.diagnostic_reporter.helper;
+
+import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
+import 'package:compiler/src/diagnostics/messages.dart';
+import 'package:compiler/src/diagnostics/spannable.dart';
+import 'package:compiler/src/diagnostics/source_span.dart';
+import 'package:compiler/src/elements/elements.dart';
+
+abstract class DiagnosticReporterWrapper extends DiagnosticReporter {
+  DiagnosticReporter get reporter;
+
+  @override
+  DiagnosticMessage createMessage(
+      Spannable spannable,
+      MessageKind messageKind,
+      [Map arguments = const {}]) {
+    return reporter.createMessage(spannable, messageKind, arguments);
+  }
+
+  @override
+  internalError(Spannable spannable, message) {
+    return reporter.internalError(spannable, message);
+  }
+
+  @override
+  void log(message) {
+    return reporter.log(message);
+  }
+
+  @override
+  DiagnosticOptions get options => reporter.options;
+
+  @override
+  void reportError(
+      DiagnosticMessage message,
+      [List<DiagnosticMessage> infos = const <DiagnosticMessage> []]) {
+    reporter.reportError(message, infos);
+  }
+
+  @override
+  void reportHint(
+      DiagnosticMessage message,
+      [List<DiagnosticMessage> infos = const <DiagnosticMessage> []]) {
+    reporter.reportHint(message, infos);
+  }
+
+  @override
+  void reportInfo(
+      Spannable node,
+      MessageKind errorCode,
+      [Map arguments = const {}]) {
+    reporter.reportInfo(node, errorCode, arguments);
+  }
+
+  @override
+  void reportWarning(
+      DiagnosticMessage message,
+      [List<DiagnosticMessage> infos = const <DiagnosticMessage> []]) {
+    reporter.reportWarning(message, infos);
+  }
+
+  @override
+  SourceSpan spanFromSpannable(Spannable node) {
+    return reporter.spanFromSpannable(node);
+  }
+
+  @override
+  withCurrentElement(Element element, f()) {
+    return reporter.withCurrentElement(element, f);
+  }
+}
diff --git a/tests/compiler/dart2js/dump_info_test.dart b/tests/compiler/dart2js/dump_info_test.dart
index 2f3d022..575d6d6 100644
--- a/tests/compiler/dart2js/dump_info_test.dart
+++ b/tests/compiler/dart2js/dump_info_test.dart
@@ -102,8 +102,6 @@
   var compiler = result.compiler;
   Expect.isFalse(compiler.compilationFailed);
   var dumpTask = compiler.dumpInfoTask;
-  dumpTask.collectInfo();
-  var info = dumpTask.infoCollector;
 
   StringBuffer sb = new StringBuffer();
   dumpTask.dumpInfoJson(sb);
diff --git a/tests/compiler/dart2js/exit_code_test.dart b/tests/compiler/dart2js/exit_code_test.dart
index acb111b..ff03975 100644
--- a/tests/compiler/dart2js/exit_code_test.dart
+++ b/tests/compiler/dart2js/exit_code_test.dart
@@ -17,6 +17,7 @@
 import 'package:compiler/src/compile_time_constants.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/dart2js.dart' as entry;
+import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
 import 'package:compiler/src/diagnostics/invariant.dart';
 import 'package:compiler/src/diagnostics/messages.dart';
 import 'package:compiler/src/diagnostics/spannable.dart';
@@ -28,11 +29,13 @@
 import 'package:compiler/src/old_to_new_api.dart';
 import 'package:compiler/src/resolution/resolution.dart';
 import 'package:compiler/src/scanner/scanner_task.dart';
+import 'diagnostic_reporter_helper.dart';
 
 class TestCompiler extends apiimpl.Compiler {
   final String testMarker;
   final String testType;
   final Function onTest;
+  DiagnosticReporter reporter;
 
   TestCompiler(api.CompilerInput inputProvider,
                api.CompilerOutput outputProvider,
@@ -50,6 +53,7 @@
               packageRoot, options, environment, packageConfig, findPackages) {
     scanner = new TestScanner(this);
     resolver = new TestResolver(this, backend.constantCompilerTask);
+    reporter = new TestDiagnosticReporter(this, super.reporter);
     test('Compiler');
   }
 
@@ -78,13 +82,6 @@
     return super.codegen(work, world);
   }
 
-  withCurrentElement(Element element, f()) {
-    return super.withCurrentElement(element, () {
-      test('Compiler.withCurrentElement');
-      return f();
-    });
-  }
-
   test(String marker) {
     if (marker == testMarker) {
       switch (testType) {
@@ -98,19 +95,19 @@
         break;
       case 'warning':
         onTest(testMarker, testType);
-        reportWarning(createMessage(
+        reporter.reportWarningMessage(
             NO_LOCATION_SPANNABLE,
-            MessageKind.GENERIC, {'text': marker}));
+            MessageKind.GENERIC, {'text': marker});
         break;
       case 'error':
         onTest(testMarker, testType);
-        reportError(createMessage(
+        reporter.reportErrorMessage(
             NO_LOCATION_SPANNABLE,
-            MessageKind.GENERIC, {'text': marker}));
+            MessageKind.GENERIC, {'text': marker});
         break;
       case 'internalError':
         onTest(testMarker, testType);
-        internalError(NO_LOCATION_SPANNABLE, marker);
+        reporter.internalError(NO_LOCATION_SPANNABLE, marker);
         break;
       case 'NoSuchMethodError':
         onTest(testMarker, testType);
@@ -124,6 +121,21 @@
   }
 }
 
+class TestDiagnosticReporter extends DiagnosticReporterWrapper {
+  final TestCompiler compiler;
+  final DiagnosticReporter reporter;
+
+  TestDiagnosticReporter(this.compiler, this.reporter);
+
+  @override
+  withCurrentElement(Element element, f()) {
+    return super.withCurrentElement(element, () {
+      compiler.test('Compiler.withCurrentElement');
+      return f();
+    });
+  }
+}
+
 class TestScanner extends ScannerTask {
   TestScanner(TestCompiler compiler) : super(compiler);
 
diff --git a/tests/compiler/dart2js/find_my_name_test.dart b/tests/compiler/dart2js/find_my_name_test.dart
index 60aba02c..dd93af3 100644
--- a/tests/compiler/dart2js/find_my_name_test.dart
+++ b/tests/compiler/dart2js/find_my_name_test.dart
@@ -36,7 +36,7 @@
 testClass(String code, MockCompiler compiler) {
   int skip = code.indexOf('{');
   ClassElementX cls = parseUnit(code, compiler, compiler.mainApp).head;
-  cls.parseNode(compiler);
+  cls.parseNode(compiler.parsing);
   cls.forEachLocalMember((Element e) {
     String name = e.name;
     if (e.isConstructor) {
diff --git a/tests/compiler/dart2js/inference_stats_test.dart b/tests/compiler/dart2js/inference_stats_test.dart
new file mode 100644
index 0000000..e742b0a
--- /dev/null
+++ b/tests/compiler/dart2js/inference_stats_test.dart
@@ -0,0 +1,339 @@
+// 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=-Dsend_stats=true
+
+/// Tests that we compute send metrics correctly in many simple scenarios.
+library dart2js.test.send_measurements_test;
+
+import 'dart:async';
+import 'package:test/test.dart';
+import 'package:dart2js_info/info.dart';
+import 'memory_compiler.dart';
+import 'dart:io';
+
+main() {
+  test('nothing is reachable, nothing to count', () {
+    return _check('''
+      main() {}
+      test() { int x = 3; }
+      ''');
+  });
+
+  test('local variable read', () {
+    return _check('''
+      main() => test();
+      test() { int x = 3; int y = x; }
+      ''',
+      localSend: 1); // from `int y = x`;
+  });
+
+  test('generative constructor call', () {
+    return _check('''
+      class A {
+        get f => 1;
+      }
+      main() => test();
+      test() { new A(); }
+      ''',
+      constructorSend: 1);  // from new A()
+  });
+
+  group('instance call', () {
+    test('monomorphic only one implementor', () {
+      return _check('''
+        class A {
+          get f => 1;
+        }
+        main() => test();
+        test() { new A().f; }
+        ''',
+        constructorSend: 1, // new A()
+        instanceSend: 1);   // f resolved to A.f
+    });
+
+    test('monomorphic only one type possible from types', () {
+      return _check('''
+        class A {
+          get f => 1;
+        }
+        class B extends A {
+          get f => 1;
+        }
+        main() => test();
+        test() { new B().f; }
+        ''',
+        constructorSend: 1,
+        instanceSend: 1); // f resolved to B.f
+    });
+
+    test('monomorphic only one type possible from liveness', () {
+      return _check('''
+        class A {
+          get f => 1;
+        }
+        class B extends A {
+          get f => 1;
+        }
+        main() => test();
+        test() { A x = new B(); x.f; }
+        ''',
+        constructorSend: 1, // new B()
+        localSend: 1,       // x in x.f
+        instanceSend: 1);  // x.f known to resolve to B.f
+    });
+
+    test('monomorphic one possible, more than one live', () {
+      return _check('''
+        class A {
+          get f => 1;
+        }
+        class B extends A {
+          get f => 1;
+        }
+        main() { new A(); test(); }
+        test() { B x = new B(); x.f; }
+        ''',
+        constructorSend: 1, // new B()
+        localSend: 1,       // x in x.f
+        instanceSend: 1);   // x.f resolves to B.f
+    });
+
+    test('polymorphic-virtual couple possible types from liveness', () {
+        // Note: this would be an instanceSend if we used the inferrer.
+      return _check('''
+        class A {
+          get f => 1;
+        }
+        class B extends A {
+          get f => 1;
+        }
+        main() { new A(); test(); }
+        test() { A x = new B(); x.f; }
+        ''',
+        constructorSend: 1, // new B()
+        localSend: 1,       // x in x.f
+        virtualSend: 1);    // x.f may be A.f or B.f (types alone is not enough)
+    });
+
+    test("polymorphic-dynamic: type annotations don't help", () {
+      return _check('''
+        class A {
+          get f => 1;
+        }
+        class B extends A {
+          get f => 1;
+        }
+        main() { new A(); test(); }
+        test() { var x = new B(); x.f; }
+        ''',
+        constructorSend: 1, // new B()
+        localSend: 1,       // x in x.f
+        dynamicSend: 1);    // x.f could be any `f` or no `f`
+    });
+  });
+
+  group('instance this call', () {
+    test('monomorphic only one implementor', () {
+      return _check('''
+        class A {
+          get f => 1;
+          test() => this.f;
+        }
+        main() => new A().test();
+        ''',
+        instanceSend: 1);   // this.f resolved to A.f
+    });
+
+    test('monomorphic only one type possible from types & liveness', () {
+      return _check('''
+        class A {
+          get f => 1;
+          test() => this.f;
+        }
+        class B extends A {
+          get f => 1;
+        }
+        main() => new B().test();
+        ''',
+        instanceSend: 1); // this.f resolved to B.f
+    });
+
+    test('polymorphic-virtual couple possible types from liveness', () {
+        // Note: this would be an instanceSend if we used the inferrer.
+      return _check('''
+        class A {
+          get f => 1;
+          test() => this.f;
+        }
+        class B extends A {
+          get f => 1;
+        }
+        main() { new A(); new B().test(); }
+        ''',
+        virtualSend: 1);    // this.f may be A.f or B.f
+    });
+  });
+
+  group('noSuchMethod', () {
+    test('error will be thrown', () {
+      return _check('''
+        class A {
+        }
+        main() { test(); }
+        test() { new A().f; }
+        ''',
+        constructorSend: 1, // new B()
+        nsmErrorSend: 1);   // f not there, A has no nSM
+    });
+
+    test('nSM will be called - one option', () {
+      return _check('''
+        class A {
+          noSuchMethod(i) => null;
+        }
+        main() { test(); }
+        test() { new A().f; }
+        ''',
+        constructorSend: 1,    // new B()
+        singleNsmCallSend: 1); // f not there, A has nSM
+    });
+
+    // TODO(sigmund): is it worth splitting multiNSMvirtual?
+    test('nSM will be called - multiple options', () {
+      return _check('''
+        class A {
+          noSuchMethod(i) => null;
+        }
+        class B extends A {
+          noSuchMethod(i) => null;
+        }
+        main() { new A(); test(); }
+        test() { A x = new B(); x.f; }
+        ''',
+        constructorSend: 1,   // new B()
+        localSend: 1,         // x in x.f
+        multiNsmCallSend: 1); // f not there, A has nSM
+    });
+
+    // TODO(sigmund): is it worth splitting multiNSMvirtual?
+    test('nSM will be called - multiple options', () {
+      return _check('''
+        class A {
+          noSuchMethod(i) => null;
+        }
+        class B extends A {
+          // don't count A's nsm as distinct
+        }
+        main() { new A(); test(); }
+        test() { A x = new B(); x.f; }
+        ''',
+        constructorSend: 1,    // new B()
+        localSend: 1,          // x in x.f
+        singleNsmCallSend: 1); // f not there, A has nSM
+    });
+
+    test('nSM will be called - multiple options', () {
+      return _check('''
+        class A {
+          noSuchMethod(i) => null;
+        }
+        class B extends A {
+          get f => null;
+        }
+        main() { new A(); test(); }
+        test() { A x = new B(); x.f; }
+        ''',
+        constructorSend: 1,   // new B()
+        localSend: 1,         // x in x.f
+        dynamicSend: 1);      // f not known to be there there, A has nSM
+    });
+
+    test('nSM in super', () {
+      return _check('''
+        class A {
+          noSuchMethod(i) => null;
+        }
+        class B extends A {
+          get f => super.f;
+        }
+        main() { new A(); test(); }
+        test() { A x = new B(); x.f; }
+        ''',
+        singleNsmCallSend: 1, //   super.f
+        testMethod: 'f');
+    });
+  });
+}
+
+
+/// Checks that the `test` function in [code] produces the given distribution of
+/// sends.
+_check(String code, {int staticSend: 0, int superSend: 0, int localSend: 0,
+    int constructorSend: 0, int typeVariableSend: 0, int nsmErrorSend: 0,
+    int singleNsmCallSend: 0, int instanceSend: 0, int interceptorSend: 0,
+    int multiNsmCallSend: 0, int virtualSend: 0, int multiInterceptorSend: 0,
+    int dynamicSend: 0, String testMethod: 'test'}) async {
+
+  // Set up the expectation.
+  var expected = new Measurements();
+  int monomorphic = staticSend + superSend + localSend + constructorSend +
+    typeVariableSend + nsmErrorSend + singleNsmCallSend + instanceSend +
+    interceptorSend;
+  int polymorphic = multiNsmCallSend + virtualSend + multiInterceptorSend +
+    dynamicSend;
+
+  expected.counters[Metric.monomorphicSend] = monomorphic;
+  expected.counters[Metric.staticSend] = staticSend;
+  expected.counters[Metric.superSend] = superSend;
+  expected.counters[Metric.localSend] = localSend;
+  expected.counters[Metric.constructorSend] = constructorSend;
+  expected.counters[Metric.typeVariableSend] = typeVariableSend;
+  expected.counters[Metric.nsmErrorSend] = nsmErrorSend;
+  expected.counters[Metric.singleNsmCallSend] = singleNsmCallSend;
+  expected.counters[Metric.instanceSend] = instanceSend;
+  expected.counters[Metric.interceptorSend] = interceptorSend;
+
+  expected.counters[Metric.polymorphicSend] = polymorphic;
+  expected.counters[Metric.multiNsmCallSend] = multiNsmCallSend;
+  expected.counters[Metric.virtualSend] = virtualSend;
+  expected.counters[Metric.multiInterceptorSend] = multiInterceptorSend;
+  expected.counters[Metric.dynamicSend] = dynamicSend;
+
+  expected.counters[Metric.send] = monomorphic + polymorphic;
+
+  // Run the compiler to get the results.
+  var all = await _compileAndGetStats(code);
+  var function = all.functions.firstWhere((f) => f.name == testMethod,
+      orElse: () => null);
+  var result = function?.measurements;
+  if (function == null) {
+    expect(expected.counters[Metric.send], 0);
+    return;
+  }
+
+  expect(result, isNotNull);
+
+  _compareMetric(Metric key) {
+    var expectedValue = expected.counters[key];
+    var value = result.counters[key];
+    if (value == null) value = 0;
+    if (value == expectedValue) return;
+    expect(expectedValue, value,
+        reason: "count for `$key` didn't match:\n"
+        "expected measurements:\n${recursiveDiagnosticString(expected, key)}\n"
+        "actual measurements:\n${recursiveDiagnosticString(result, key)}");
+  }
+
+  _compareMetric(Metric.send);
+  expected.counters.keys.forEach(_compareMetric);
+}
+
+/// Helper that runs the compiler and returns the [GlobalResult] computed for
+/// it.
+Future<AllInfo> _compileAndGetStats(String program) async {
+  var result = await runCompiler(
+      memorySourceFiles: {'main.dart': program}, options: ['--dump-info']);
+  expect(result.compiler.compilationFailed, isFalse);
+  return result.compiler.dumpInfoTask.infoCollector.result;
+}
diff --git a/tests/compiler/dart2js/js_spec_string_test.dart b/tests/compiler/dart2js/js_spec_string_test.dart
index a169bca..1481da4 100644
--- a/tests/compiler/dart2js/js_spec_string_test.dart
+++ b/tests/compiler/dart2js/js_spec_string_test.dart
@@ -14,7 +14,7 @@
 const OBJECT = 'Object';
 const NULL = 'Null';
 
-class Listener extends DiagnosticListener {
+class Listener extends DiagnosticReporter {
   String errorMessage;
   internalError(spannable, message) {
     errorMessage = message;
diff --git a/tests/compiler/dart2js/least_upper_bound_test.dart b/tests/compiler/dart2js/least_upper_bound_test.dart
index d239812..9d7af4d 100644
--- a/tests/compiler/dart2js/least_upper_bound_test.dart
+++ b/tests/compiler/dart2js/least_upper_bound_test.dart
@@ -381,12 +381,12 @@
     checkLub(DartType a, DartType b, DartType expectedLub) {
       DartType lub = env.computeLeastUpperBound(a, b);
       if (a != b) {
-        expectedLub = expectedLub.unalias(env.compiler);
-        lub = lub.unalias(env.compiler);
+        expectedLub = expectedLub.unalias(env.compiler.resolution);
+        lub = lub.unalias(env.compiler.resolution);
       }
       Expect.equals(expectedLub, lub,
-          'Unexpected lub(${a.unalias(env.compiler)},'
-                         '${b.unalias(env.compiler)}) = '
+          'Unexpected lub(${a.unalias(env.compiler.resolution)},'
+                         '${b.unalias(env.compiler.resolution)}) = '
                          '${lub}, expected ${expectedLub}');
     }
 
diff --git a/tests/compiler/dart2js/memory_compiler.dart b/tests/compiler/dart2js/memory_compiler.dart
index c23b809..906799d 100644
--- a/tests/compiler/dart2js/memory_compiler.dart
+++ b/tests/compiler/dart2js/memory_compiler.dart
@@ -245,10 +245,10 @@
     compiler.deferredLibraryClass = cachedCompiler.deferredLibraryClass;
 
     Iterable cachedTreeElements =
-        cachedCompiler.enqueuer.resolution.resolvedElements;
+        cachedCompiler.enqueuer.resolution.processedElements;
     cachedTreeElements.forEach((element) {
       if (element.library.isPlatformLibrary) {
-        compiler.enqueuer.resolution.registerResolvedElement(element);
+        compiler.enqueuer.resolution.registerProcessedElement(element);
       }
     });
 
diff --git a/tests/compiler/dart2js/message_kind_helper.dart b/tests/compiler/dart2js/message_kind_helper.dart
index 12089cf..9d60632 100644
--- a/tests/compiler/dart2js/message_kind_helper.dart
+++ b/tests/compiler/dart2js/message_kind_helper.dart
@@ -114,7 +114,7 @@
         }
       }
       Expect.isTrue(messageFound, '"$pattern" does not match any in $messages');
-      Expect.isFalse(compiler.hasCrashed);
+      Expect.isFalse(compiler.reporter.hasCrashed);
       if (!unexpectedMessages.isEmpty) {
         for (String message in unexpectedMessages) {
           print("Unexpected message: $message");
@@ -129,13 +129,13 @@
       bool pendingStuff = false;
       for (var e in compiler.resolver.pendingClassesToBePostProcessed) {
         pendingStuff = true;
-        compiler.reportInfo(
+        compiler.reporter.reportInfo(
             e, MessageKind.GENERIC,
             {'text': 'Pending class to be post-processed.'});
       }
       for (var e in compiler.resolver.pendingClassesToBeResolved) {
         pendingStuff = true;
-        compiler.reportInfo(
+        compiler.reporter.reportInfo(
             e, MessageKind.GENERIC,
             {'text': 'Pending class to be resolved.'});
       }
diff --git a/tests/compiler/dart2js/metadata_test.dart b/tests/compiler/dart2js/metadata_test.dart
index 205c897..0f1e9fd 100644
--- a/tests/compiler/dart2js/metadata_test.dart
+++ b/tests/compiler/dart2js/metadata_test.dart
@@ -9,9 +9,14 @@
 import 'compiler_helper.dart';
 import 'package:compiler/src/parser/partial_elements.dart' show
     PartialMetadataAnnotation;
+import 'package:compiler/src/diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 
-void checkPosition(Spannable spannable, Node node, String source, compiler) {
-  SourceSpan span = compiler.spanFromSpannable(spannable);
+void checkPosition(Spannable spannable,
+                   Node node,
+                   String source,
+                   DiagnosticReporter reporter) {
+  SourceSpan span = reporter.spanFromSpannable(spannable);
   Expect.isTrue(span.begin < span.end,
                 'begin = ${span.begin}; end = ${span.end}');
   Expect.isTrue(span.end < source.length,
@@ -36,12 +41,13 @@
     Expect.equals(1, element.metadata.length,
         'Unexpected metadata count on $element.');
     PartialMetadataAnnotation annotation = element.metadata.first;
-    annotation.ensureResolved(compiler);
+    annotation.ensureResolved(compiler.resolution);
     PrimitiveConstantValue value =
         compiler.constants.getConstantValue(annotation.constant);
     Expect.stringEquals('xyz', value.primitiveValue.slowToString());
 
-    checkPosition(annotation, annotation.cachedNode, source1, compiler);
+    checkPosition(
+        annotation, annotation.cachedNode, source1, compiler.reporter);
   });
 
   // Ensure that each repeated annotation has a unique instance of
@@ -56,8 +62,8 @@
     Expect.equals(2, element.metadata.length);
     PartialMetadataAnnotation annotation1 = element.metadata.elementAt(0);
     PartialMetadataAnnotation annotation2 = element.metadata.elementAt(1);
-    annotation1.ensureResolved(compiler);
-    annotation2.ensureResolved(compiler);
+    annotation1.ensureResolved(compiler.resolution);
+    annotation2.ensureResolved(compiler.resolution);
     Expect.isFalse(identical(annotation1, annotation2),
                    'expected unique instances');
     Expect.notEquals(annotation1, annotation2, 'expected unequal instances');
@@ -69,8 +75,10 @@
     Expect.stringEquals('xyz', value1.primitiveValue.slowToString());
     Expect.stringEquals('xyz', value2.primitiveValue.slowToString());
 
-    checkPosition(annotation1, annotation1.cachedNode, source2, compiler);
-    checkPosition(annotation2, annotation2.cachedNode, source2, compiler);
+    checkPosition(
+        annotation1, annotation1.cachedNode, source2, compiler.reporter);
+    checkPosition(
+        annotation2, annotation2.cachedNode, source2, compiler.reporter);
   });
 
   if (isTopLevelOnly) return;
@@ -87,17 +95,18 @@
   compileAndCheck(source3, 'Foo', (compiler, element) {
     compiler.enqueuer.resolution.queueIsClosed = false;
     Expect.equals(0, element.metadata.length);
-    element.ensureResolved(compiler);
+    element.ensureResolved(compiler.resolution);
     Expect.equals(0, element.metadata.length);
     element = element.lookupLocalMember(name);
     Expect.equals(1, element.metadata.length);
     PartialMetadataAnnotation annotation = element.metadata.first;
-    annotation.ensureResolved(compiler);
+    annotation.ensureResolved(compiler.resolution);
     PrimitiveConstantValue value =
         compiler.constants.getConstantValue(annotation.constant);
     Expect.stringEquals('xyz', value.primitiveValue.slowToString());
 
-    checkPosition(annotation, annotation.cachedNode, source3, compiler);
+    checkPosition(
+        annotation, annotation.cachedNode, source3, compiler.reporter);
   });
 
   // Ensure that each repeated annotation has a unique instance of
@@ -112,14 +121,14 @@
   compileAndCheck(source4, 'Foo', (compiler, element) {
     compiler.enqueuer.resolution.queueIsClosed = false;
     Expect.equals(0, element.metadata.length);
-    element.ensureResolved(compiler);
+    element.ensureResolved(compiler.resolution);
     Expect.equals(0, element.metadata.length);
     element = element.lookupLocalMember(name);
     Expect.equals(2, element.metadata.length);
     PartialMetadataAnnotation annotation1 = element.metadata.elementAt(0);
     PartialMetadataAnnotation annotation2 = element.metadata.elementAt(1);
-    annotation1.ensureResolved(compiler);
-    annotation2.ensureResolved(compiler);
+    annotation1.ensureResolved(compiler.resolution);
+    annotation2.ensureResolved(compiler.resolution);
     Expect.isFalse(identical(annotation1, annotation2),
                    'expected unique instances');
     Expect.notEquals(annotation1, annotation2, 'expected unequal instances');
@@ -131,8 +140,10 @@
     Expect.stringEquals('xyz', value1.primitiveValue.slowToString());
     Expect.stringEquals('xyz', value2.primitiveValue.slowToString());
 
-    checkPosition(annotation1, annotation1.cachedNode, source4, compiler);
-    checkPosition(annotation1, annotation2.cachedNode, source4, compiler);
+    checkPosition(
+        annotation1, annotation1.cachedNode, source4, compiler.reporter);
+    checkPosition(
+        annotation1, annotation2.cachedNode, source4, compiler.reporter);
   });
 }
 
@@ -174,12 +185,13 @@
       Expect.equals(1, metadata.length);
 
       PartialMetadataAnnotation annotation = metadata.first;
-      annotation.ensureResolved(compiler);
+      annotation.ensureResolved(compiler.resolution);
       PrimitiveConstantValue value =
           compiler.constants.getConstantValue(annotation.constant);
       Expect.stringEquals('xyz', value.primitiveValue.slowToString());
 
-      checkPosition(annotation, annotation.cachedNode, source, compiler);
+      checkPosition(
+          annotation, annotation.cachedNode, source, compiler.reporter);
     }));
   }
 
diff --git a/tests/compiler/dart2js/minimal_resolution_test.dart b/tests/compiler/dart2js/minimal_resolution_test.dart
index ca61f80..b46b340 100644
--- a/tests/compiler/dart2js/minimal_resolution_test.dart
+++ b/tests/compiler/dart2js/minimal_resolution_test.dart
@@ -6,6 +6,9 @@
 
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/compiler.dart';
+import 'package:compiler/src/elements/elements.dart';
+import 'package:compiler/src/enqueue.dart';
+import 'package:compiler/src/js_backend/js_backend.dart';
 import 'package:expect/expect.dart';
 import 'memory_compiler.dart';
 
@@ -13,15 +16,45 @@
   asyncTest(() async {
     await analyze('main() {}');
     await analyze('main() => proxy;', proxyConstant: true);
+    await analyze('@deprecated main() {}');
+    await analyze('@deprecated main() => deprecated;', deprecatedClass: true);
+    await analyze('main() => deprecated;', deprecatedClass: true);
   });
 }
 
+void checkInstantiated(Compiler compiler, ClassElement cls, bool expected) {
+  ResolutionEnqueuer enqueuer = compiler.enqueuer.resolution;
+  bool isInstantiated =
+      enqueuer.universe.directlyInstantiatedClasses.contains(cls);
+  bool isProcessed = enqueuer.isClassProcessed(cls);
+  Expect.equals(expected, isInstantiated,
+      'Unexpected instantiation state of class $cls.');
+  Expect.equals(expected, isProcessed,
+      'Unexpected processing state of class $cls.');
+}
+
 analyze(String code,
-        {bool proxyConstant: false}) async {
+        {bool proxyConstant: false,
+         bool deprecatedClass: false}) async {
   CompilationResult result = await runCompiler(
       memorySourceFiles: {'main.dart': code},
       options: ['--analyze-only']);
   Expect.isTrue(result.isSuccess);
   Compiler compiler = result.compiler;
-  Expect.equals(proxyConstant, compiler.proxyConstant != null);
+  Expect.equals(proxyConstant, compiler.proxyConstant != null,
+      "Unexpected computation of proxy constant.");
+
+  checkInstantiated(
+      compiler, compiler.coreLibrary.find('_Proxy'), proxyConstant);
+  checkInstantiated(
+      compiler, compiler.coreLibrary.find('Deprecated'), deprecatedClass);
+
+  LibraryElement jsHelperLibrary =
+      compiler.libraryLoader.lookupLibrary(JavaScriptBackend.DART_JS_HELPER);
+  jsHelperLibrary.forEachLocalMember((Element element) {
+    Uri uri = element.compilationUnit.script.resourceUri;
+    if (element.isClass && uri.path.endsWith('annotations.dart')) {
+      checkInstantiated(compiler, element, false);
+    }
+  });
 }
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index 9f67d12..5c33011 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -12,6 +12,7 @@
 import 'package:compiler/src/common/names.dart' show
     Uris;
 import 'package:compiler/src/constants/expressions.dart';
+import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
 import 'package:compiler/src/diagnostics/messages.dart';
 import 'package:compiler/src/diagnostics/source_span.dart';
 import 'package:compiler/src/diagnostics/spannable.dart';
@@ -76,7 +77,6 @@
        bool enableTypeAssertions: false,
        bool enableUserAssertions: false,
        bool enableMinification: false,
-       bool enableConcreteTypeInference: false,
        int maxConcreteTypeSize: 5,
        bool disableTypeInference: false,
        bool analyzeAll: false,
@@ -99,7 +99,6 @@
               enableUserAssertions: enableUserAssertions,
               enableAssertMessage: true,
               enableMinification: enableMinification,
-              enableConcreteTypeInference: enableConcreteTypeInference,
               maxConcreteTypeSize: maxConcreteTypeSize,
               disableTypeInferenceFlag: disableTypeInference,
               analyzeAllFlag: analyzeAll,
@@ -107,7 +106,8 @@
               emitJavaScript: emitJavaScript,
               preserveComments: preserveComments,
               trustTypeAnnotations: trustTypeAnnotations,
-              showPackageWarnings: true,
+              diagnosticOptions:
+                  new DiagnosticOptions(showPackageWarnings: true),
               outputProvider: new LegacyCompilerOutput(outputProvider)) {
     this.disableInlining = disableInlining;
 
@@ -157,7 +157,7 @@
       // dynamic invocation the ArgumentTypesRegistry eventually iterates over
       // the interfaces of the Object class which would be 'null' if the class
       // wasn't resolved.
-      objectClass.ensureResolved(this);
+      objectClass.ensureResolved(resolution);
     }).then((_) => uri);
   }
 
diff --git a/tests/compiler/dart2js/mock_libraries.dart b/tests/compiler/dart2js/mock_libraries.dart
index 957cb56..95bb3fb 100644
--- a/tests/compiler/dart2js/mock_libraries.dart
+++ b/tests/compiler/dart2js/mock_libraries.dart
@@ -347,11 +347,11 @@
         operator &(other) => 42;
         operator ^(other) => 42;
 
-        operator >(other) => true;
-        operator >=(other) => true;
-        operator <(other) => true;
-        operator <=(other) => true;
-        operator ==(other) => true;
+        operator >(other) => !identical(this, other);
+        operator >=(other) => !identical(this, other);
+        operator <(other) => !identical(this, other);
+        operator <=(other) => !identical(this, other);
+        operator ==(other) => identical(this, other);
         get hashCode => throw "JSNumber.hashCode not implemented.";
 
         // We force side effects on _tdivFast to mimic the shortcomings of
diff --git a/tests/compiler/dart2js/override_inheritance_test.dart b/tests/compiler/dart2js/override_inheritance_test.dart
index 0e24785..c71e6b2 100644
--- a/tests/compiler/dart2js/override_inheritance_test.dart
+++ b/tests/compiler/dart2js/override_inheritance_test.dart
@@ -29,7 +29,7 @@
     compiler.diagnosticHandler = createHandler(compiler, source);
     compiler.parseScript(source);
     var cls = compiler.mainApp.find('Class');
-    cls.ensureResolved(compiler);
+    cls.ensureResolved(compiler.resolution);
     MembersCreator.computeAllClassMembers(compiler, cls);
 
     toList(o) => o == null ? [] : o is List ? o : [o];
diff --git a/tests/compiler/dart2js/parser_helper.dart b/tests/compiler/dart2js/parser_helper.dart
index ea49b68..572a082 100644
--- a/tests/compiler/dart2js/parser_helper.dart
+++ b/tests/compiler/dart2js/parser_helper.dart
@@ -37,7 +37,7 @@
 export "package:compiler/src/tokens/token.dart";
 export "package:compiler/src/tokens/token_constants.dart";
 
-class LoggerCanceler extends DiagnosticListener {
+class LoggerCanceler extends DiagnosticReporter {
   void log(message) {
     print(message);
   }
@@ -93,15 +93,15 @@
     .tokenize();
 
 Node parseBodyCode(String text, Function parseMethod,
-                   {DiagnosticListener diagnosticHandler}) {
+                   {DiagnosticReporter reporter}) {
   Token tokens = scan(text);
-  if (diagnosticHandler == null) diagnosticHandler = new LoggerCanceler();
+  if (reporter == null) reporter = new LoggerCanceler();
   Uri uri = new Uri(scheme: "source");
   Script script = new Script(uri, uri,new MockFile(text));
   LibraryElement library = new LibraryElementX(script);
   library.canUseNative = true;
   NodeListener listener =
-      new NodeListener(diagnosticHandler, library.entryCompilationUnit);
+      new NodeListener(reporter, library.entryCompilationUnit);
   Parser parser = new Parser(listener);
   Token endToken = parseMethod(parser, tokens);
   assert(endToken.kind == EOF_TOKEN);
@@ -118,12 +118,14 @@
   ElementX element = parseUnit(text, compiler, compiler.mainApp).head;
   Expect.isNotNull(element);
   Expect.equals(ElementKind.FUNCTION, element.kind);
-  return element.parseNode(compiler);
+  return element.parseNode(compiler.parsing);
 }
 
-Node parseMember(String text, {DiagnosticListener diagnosticHandler}) {
-  return parseBodyCode(text, (parser, tokens) => parser.parseMember(tokens),
-                       diagnosticHandler: diagnosticHandler);
+Node parseMember(String text, {DiagnosticReporter reporter}) {
+  return parseBodyCode(
+      text,
+      (parser, tokens) => parser.parseMember(tokens),
+      reporter: reporter);
 }
 
 class MockFile extends StringSourceFile {
@@ -144,13 +146,16 @@
   var script = new Script(uri, uri, new MockFile(text));
   var unit = new CompilationUnitElementX(script, library);
   int id = 0;
-  ElementListener listener = new ElementListener(compiler, unit, () => id++);
+  DiagnosticReporter reporter = compiler.reporter;
+  ElementListener listener = new ElementListener(reporter, unit, () => id++);
   PartialParser parser = new PartialParser(listener);
-  compiler.withCurrentElement(unit, () => parser.parseUnit(tokens));
+  reporter.withCurrentElement(unit, () => parser.parseUnit(tokens));
   return unit.localMembers;
 }
 
-NodeList fullParseUnit(String source, {DiagnosticListener diagnosticHandler}) {
-  return parseBodyCode(source, (parser, tokens) => parser.parseUnit(tokens),
-                       diagnosticHandler: diagnosticHandler);
+NodeList fullParseUnit(String source, {DiagnosticReporter reporter}) {
+  return parseBodyCode(
+      source,
+      (parser, tokens) => parser.parseUnit(tokens),
+      reporter: reporter);
 }
diff --git a/tests/compiler/dart2js/parser_test.dart b/tests/compiler/dart2js/parser_test.dart
index 17584fb..4674201 100644
--- a/tests/compiler/dart2js/parser_test.dart
+++ b/tests/compiler/dart2js/parser_test.dart
@@ -292,7 +292,7 @@
   Expect.isNull(function.getOrSet);
 }
 
-class Collector extends DiagnosticListener {
+class Collector extends DiagnosticReporter {
   int token = -1;
 
   void reportFatalError(Token token) {
@@ -326,7 +326,7 @@
   return x;
 }''';
   parse() {
-    parseMember(source, diagnosticHandler: new Collector());
+    parseMember(source, reporter: new Collector());
   }
   check(Collector c) {
     Expect.equals(OPEN_CURLY_BRACKET_TOKEN, c.token);
@@ -338,7 +338,7 @@
 void testMissingCloseBraceInClass() {
   final String source = 'class Foo {'; // Missing close '}'.
   parse() {
-    fullParseUnit(source, diagnosticHandler: new Collector());
+    fullParseUnit(source, reporter: new Collector());
   }
   check(Collector c) {
     Expect.equals(BAD_INPUT_TOKEN, c.token);
@@ -350,7 +350,7 @@
 void testUnmatchedAngleBracket() {
   final String source = 'A<'; // unmatched '<'
   parse() {
-    fullParseUnit(source, diagnosticHandler: new Collector());
+    fullParseUnit(source, reporter: new Collector());
   }
   check(Collector c) {
     Expect.equals(LT_TOKEN, c.token);
diff --git a/tests/compiler/dart2js/patch_test.dart b/tests/compiler/dart2js/patch_test.dart
index 10c8bca..1422a1a 100644
--- a/tests/compiler/dart2js/patch_test.dart
+++ b/tests/compiler/dart2js/patch_test.dart
@@ -45,7 +45,7 @@
 }
 
 void expectHasBody(compiler, ElementX element) {
-    var node = element.parseNode(compiler);
+    var node = element.parseNode(compiler.parsing);
     Expect.isNotNull(node, "Element isn't parseable, when a body was expected");
     Expect.isNotNull(node.body);
     // If the element has a body it is either a Block or a Return statement,
@@ -55,7 +55,7 @@
 }
 
 void expectHasNoBody(compiler, ElementX element) {
-    var node = element.parseNode(compiler);
+    var node = element.parseNode(compiler.parsing);
     Expect.isNotNull(node, "Element isn't parseable, when a body was expected");
     Expect.isFalse(node.hasBody());
 }
@@ -248,7 +248,7 @@
       """);
   var classOrigin = ensure(compiler, "Class", compiler.coreLibrary.find,
                            expectIsPatched: true);
-  classOrigin.ensureResolved(compiler);
+  classOrigin.ensureResolved(compiler.resolution);
   var classPatch = ensure(compiler, "Class", compiler.coreLibrary.patch.find,
                           expectIsPatch: true);
 
@@ -287,7 +287,7 @@
       """);
   var classOrigin = ensure(compiler, "Class", compiler.coreLibrary.find,
                            expectIsPatched: true);
-  classOrigin.ensureResolved(compiler);
+  classOrigin.ensureResolved(compiler.resolution);
 
   var classPatch = ensure(compiler, "Class", compiler.coreLibrary.patch.find,
                           expectIsPatch: true);
@@ -331,7 +331,7 @@
       """);
   var container = ensure(compiler, "Class", compiler.coreLibrary.find,
                          expectIsPatched: true);
-  container.parseNode(compiler);
+  container.parseNode(compiler.parsing);
   ensure(compiler, "Class", compiler.coreLibrary.patch.find,
          expectIsPatch: true);
 
@@ -360,7 +360,7 @@
       """);
   var container = ensure(compiler, "Class", compiler.coreLibrary.find,
                          expectIsPatched: true);
-  container.parseNode(compiler);
+  container.parseNode(compiler.parsing);
   ensure(compiler,
          "field",
          container.lookupLocalMember,
@@ -393,7 +393,7 @@
       """);
   var container = ensure(compiler, "Class", compiler.coreLibrary.find,
                          expectIsPatched: true);
-  container.parseNode(compiler);
+  container.parseNode(compiler.parsing);
   ensure(compiler, "Class", compiler.coreLibrary.patch.find,
          expectIsPatch: true);
 
@@ -421,7 +421,7 @@
       """);
   var container = ensure(compiler, "Class", compiler.coreLibrary.find,
                          expectIsPatched: true);
-  container.parseNode(compiler);
+  container.parseNode(compiler.parsing);
   ensure(compiler, "Class", compiler.coreLibrary.patch.find,
          expectIsPatch: true);
 
@@ -489,8 +489,8 @@
       """);
   var container = ensure(compiler, "Class", compiler.coreLibrary.find,
                          expectIsPatched: true);
-  container.ensureResolved(compiler);
-  container.parseNode(compiler);
+  container.ensureResolved(compiler.resolution);
+  container.parseNode(compiler.parsing);
 
   void expect(String methodName, List infos, List errors) {
     compiler.clearMessages();
@@ -568,7 +568,7 @@
       """);
   var container = ensure(compiler, "Class", compiler.coreLibrary.find,
                          expectIsPatched: true);
-  container.parseNode(compiler);
+  container.parseNode(compiler.parsing);
 
   compiler.warnings.clear();
   compiler.errors.clear();
@@ -629,7 +629,7 @@
       """);
   var container = ensure(compiler, "Class", compiler.coreLibrary.find,
                          expectIsPatched: true);
-  container.parseNode(compiler);
+  container.parseNode(compiler.parsing);
 
   Expect.isTrue(compiler.warnings.isEmpty,
                 "Unexpected warnings: ${compiler.warnings}");
@@ -712,7 +712,7 @@
       """);
   var container = ensure(compiler, "Class", compiler.coreLibrary.find,
                          expectIsPatched: true);
-  container.parseNode(compiler);
+  container.parseNode(compiler.parsing);
 
   print('testPatchNonExternalMember.errors:${compiler.errors}');
   print('testPatchNonExternalMember.warnings:${compiler.warnings}');
@@ -866,7 +866,7 @@
 
   ClassElement cls = ensure(compiler, "A", compiler.coreLibrary.find,
                             expectIsPatched: true);
-  cls.ensureResolved(compiler);
+  cls.ensureResolved(compiler.resolution);
 
   ensure(compiler, "method", cls.patch.lookupLocalMember,
          checkHasBody: true, expectIsRegular: true);
@@ -882,7 +882,7 @@
       new Selector.call(const PublicName('method'), CallStructure.NO_ARGS);
   TypeMask typeMask = new TypeMask.exact(cls, world);
   FunctionElement method = cls.implementation.lookupLocalMember('method');
-  method.computeType(compiler);
+  method.computeType(compiler.resolution);
   Expect.isTrue(selector.applies(method, world));
   Expect.isTrue(typeMask.canHit(method, selector, world));
 
@@ -892,14 +892,14 @@
       new Selector.call(const PublicName('clear'), CallStructure.NO_ARGS);
   typeMask = new TypeMask.exact(cls, world);
   method = cls.lookupLocalMember('clear');
-  method.computeType(compiler);
+  method.computeType(compiler.resolution);
   Expect.isTrue(selector.applies(method, world));
   Expect.isTrue(typeMask.canHit(method, selector, world));
 
   // Check that the declaration method in the declaration class is a target
   // for a typed selector on a subclass.
   cls = ensure(compiler, "B", compiler.coreLibrary.find);
-  cls.ensureResolved(compiler);
+  cls.ensureResolved(compiler.resolution);
   typeMask = new TypeMask.exact(cls, world);
   Expect.isTrue(selector.applies(method, world));
   Expect.isTrue(typeMask.canHit(method, selector, world));
diff --git a/tests/compiler/dart2js/related_types.dart b/tests/compiler/dart2js/related_types.dart
index 54d9ab8..6e3f8b2 100644
--- a/tests/compiler/dart2js/related_types.dart
+++ b/tests/compiler/dart2js/related_types.dart
@@ -8,6 +8,7 @@
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/core_types.dart';
 import 'package:compiler/src/dart_types.dart';
+import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
 import 'package:compiler/src/diagnostics/messages.dart';
 import 'package:compiler/src/elements/elements.dart';
 import 'package:compiler/src/filenames.dart';
@@ -55,13 +56,13 @@
 
 /// Check [member] for unrelated types.
 void checkMemberElement(Compiler compiler, MemberElement member) {
-  if (!compiler.enqueuer.resolution.hasBeenResolved(member)) return;
+  if (!compiler.resolution.hasBeenResolved(member)) return;
 
   ResolvedAst resolvedAst = member.resolvedAst;
   RelatedTypesChecker relatedTypesChecker =
       new RelatedTypesChecker(compiler, resolvedAst);
   if (resolvedAst.node != null) {
-    compiler.withCurrentElement(member.implementation, () {
+    compiler.reporter.withCurrentElement(member.implementation, () {
       relatedTypesChecker.apply(resolvedAst.node);
     });
   }
@@ -79,6 +80,8 @@
 
   CoreTypes get coreTypes => compiler.coreTypes;
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   InterfaceType get thisType => resolvedAst.element.enclosingClass.thisType;
 
   /// Returns `true` if there exists no common subtype of [left] and [right].
@@ -97,10 +100,10 @@
   /// a hint otherwise.
   void checkRelated(Node node, DartType left, DartType right) {
     if (hasEmptyIntersection(left, right)) {
-      compiler.reportHint(compiler.createMessage(
+      reporter.reportHintMessage(
           node,
           MessageKind.NO_COMMON_SUBTYPES,
-          {'left': left, 'right': right}));
+          {'left': left, 'right': right});
     }
   }
 
diff --git a/tests/compiler/dart2js/resolver_test.dart b/tests/compiler/dart2js/resolver_test.dart
index 3f18c93..236b0bd 100644
--- a/tests/compiler/dart2js/resolver_test.dart
+++ b/tests/compiler/dart2js/resolver_test.dart
@@ -193,9 +193,9 @@
                            '  bar() { g(Foo<T> f) {}; g(); }'
                            '}');
       ClassElement foo = compiler.mainApp.find('Foo');
-      foo.ensureResolved(compiler);
-      foo.lookupLocalMember('t').computeType(compiler);;
-      foo.lookupLocalMember('foo').computeType(compiler);;
+      foo.ensureResolved(compiler.resolution);
+      foo.lookupLocalMember('t').computeType(compiler.resolution);
+      foo.lookupLocalMember('foo').computeType(compiler.resolution);
       compiler.resolver.resolve(foo.lookupLocalMember('bar'));
       Expect.equals(0, compiler.warnings.length);
       Expect.equals(0, compiler.errors.length);
@@ -219,7 +219,8 @@
         new ResolverVisitor(compiler, fooB,
             new ResolutionRegistry(compiler,
                 new CollectingTreeElements(fooB)));
-    FunctionExpression node = (fooB as FunctionElementX).parseNode(compiler);
+    FunctionExpression node =
+        (fooB as FunctionElementX).parseNode(compiler.parsing);
     visitor.visit(node.body);
     Map mapping = map(visitor);
 
@@ -262,7 +263,7 @@
               new ResolutionRegistry(compiler,
                   new CollectingTreeElements(funElement)));
       FunctionExpression function =
-          (funElement as FunctionElementX).parseNode(compiler);
+          (funElement as FunctionElementX).parseNode(compiler.parsing);
       visitor.visit(function.body);
       Map mapping = map(visitor);
       List<Element> values = mapping.values.toList();
@@ -285,7 +286,7 @@
           new ResolutionRegistry(compiler,
               new CollectingTreeElements(funElement)));
       FunctionExpression function =
-          (funElement as FunctionElementX).parseNode(compiler);
+          (funElement as FunctionElementX).parseNode(compiler.parsing);
       visitor.visit(function.body);
       Expect.equals(0, compiler.warnings.length);
       Expect.equals(1, compiler.errors.length);
@@ -530,7 +531,7 @@
 
       ClassElement fooElement = compiler.mainApp.find('Foo');
       ClassElement barElement = compiler.mainApp.find('Bar');
-      Expect.equals(barElement.computeType(compiler),
+      Expect.equals(barElement.computeType(compiler.resolution),
                     fooElement.supertype);
       Expect.isTrue(fooElement.interfaces.isEmpty);
       Expect.isTrue(barElement.interfaces.isEmpty);
@@ -580,7 +581,7 @@
     Expect.equals(null, barElement.supertype);
     Expect.isTrue(barElement.interfaces.isEmpty);
 
-    Expect.equals(barElement.computeType(compiler),
+    Expect.equals(barElement.computeType(compiler.resolution),
                   fooElement.interfaces.head);
     Expect.equals(1, length(fooElement.interfaces));
   });
@@ -599,8 +600,8 @@
     ClassElement i2 = compiler.mainApp.find('I2');
 
     Expect.equals(2, length(c.interfaces));
-    Expect.equals(i1.computeType(compiler), at(c.interfaces, 0));
-    Expect.equals(i2.computeType(compiler), at(c.interfaces, 1));
+    Expect.equals(i1.computeType(compiler.resolution), at(c.interfaces, 0));
+    Expect.equals(i2.computeType(compiler.resolution), at(c.interfaces, 1));
   });
 }
 
@@ -651,7 +652,8 @@
     compiler.parseScript("int a;");
     VariableElementX element = compiler.mainApp.find("a");
     Expect.equals(ElementKind.FIELD, element.kind);
-    VariableDefinitions node = element.variables.parseNode(element, compiler);
+    VariableDefinitions node =
+        element.variables.parseNode(element, compiler.parsing);
     Identifier typeName = node.type.typeName;
     Expect.equals(typeName.source, 'int');
 
@@ -662,8 +664,10 @@
     Expect.equals(ElementKind.FIELD, cElement.kind);
     Expect.isTrue(bElement != cElement);
 
-    VariableDefinitions bNode = bElement.variables.parseNode(bElement, compiler);
-    VariableDefinitions cNode = cElement.variables.parseNode(cElement, compiler);
+    VariableDefinitions bNode =
+        bElement.variables.parseNode(bElement, compiler.parsing);
+    VariableDefinitions cNode =
+        cElement.variables.parseNode(cElement, compiler.parsing);
     Expect.equals(bNode, cNode);
     Expect.isNull(bNode.type);
     Expect.isTrue(bNode.modifiers.isVar);
@@ -1079,7 +1083,7 @@
   Element memberElement = cls.lookupLocalMember(memberName);
   Expect.isNotNull(memberElement);
   Expect.isTrue(
-      compiler.enqueuer.resolution.hasBeenResolved(memberElement));
+      compiler.enqueuer.resolution.hasBeenProcessed(memberElement));
 }
 
 testToString() {
diff --git a/tests/compiler/dart2js/semantic_visitor_test.dart b/tests/compiler/dart2js/semantic_visitor_test.dart
index 3376a67..f8ea57f 100644
--- a/tests/compiler/dart2js/semantic_visitor_test.dart
+++ b/tests/compiler/dart2js/semantic_visitor_test.dart
@@ -330,7 +330,7 @@
       ResolvedAst resolvedAst = astElement.resolvedAst;
       SemanticTestVisitor visitor = createVisitor(resolvedAst.elements);
       try {
-        compiler.withCurrentElement(resolvedAst.element, () {
+        compiler.reporter.withCurrentElement(resolvedAst.element, () {
           //print(resolvedAst.node.toDebugString());
           resolvedAst.node.accept(visitor);
         });
diff --git a/tests/compiler/dart2js/source_mapping_test.dart b/tests/compiler/dart2js/source_mapping_test.dart
index 40c0f69..6c7b46f 100644
--- a/tests/compiler/dart2js/source_mapping_test.dart
+++ b/tests/compiler/dart2js/source_mapping_test.dart
@@ -68,7 +68,7 @@
 
 String RETURN_TEST = 'void main() { print(((x) { @return x; })(0)); }';
 
-String NOT_TEST = 'void main() { ((x) { if (@!x) print(x); })(false); }';
+String NOT_TEST = 'void main() { ((x) { if (@!x) print(x); })(1==2); }';
 
 String UNARY_TEST = 'void main() { ((x, y) { print(@-x + @~y); })(1,2); }';
 
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart
index fc7b601..045d2be 100644
--- a/tests/compiler/dart2js/type_checker_test.dart
+++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -75,10 +75,11 @@
     Expect.equals(type, analyzeType(compiler, code));
   }
 
-  checkType(compiler.intClass.computeType(compiler), "3");
-  checkType(compiler.boolClass.computeType(compiler), "false");
-  checkType(compiler.boolClass.computeType(compiler), "true");
-  checkType(compiler.stringClass.computeType(compiler), "'hestfisk'");
+  checkType(compiler.intClass.computeType(compiler.resolution), "3");
+  checkType(compiler.boolClass.computeType(compiler.resolution), "false");
+  checkType(compiler.boolClass.computeType(compiler.resolution), "true");
+  checkType(
+      compiler.stringClass.computeType(compiler.resolution), "'hestfisk'");
 }
 
 Future testReturn(MockCompiler compiler) {
@@ -175,7 +176,7 @@
 """;
   compiler.parseScript(script);
   ClassElement foo = compiler.mainApp.find("Class");
-  foo.ensureResolved(compiler);
+  foo.ensureResolved(compiler.resolution);
   FunctionElement method = foo.lookupLocalMember('forIn');
 
   analyzeIn(compiler, method, """{ 
@@ -308,7 +309,7 @@
 """;
   compiler.parseScript(script);
   ClassElement foo = compiler.mainApp.find("Class");
-  foo.ensureResolved(compiler);
+  foo.ensureResolved(compiler.resolution);
   FunctionElement method = foo.lookupLocalMember('forIn');
 
   analyzeIn(compiler, method, """{
@@ -894,11 +895,11 @@
     LibraryElement library = compiler.mainApp;
     compiler.parseScript(CLASS_WITH_METHODS, library);
     ClassElement ClassWithMethods = library.find("ClassWithMethods");
-    ClassWithMethods.ensureResolved(compiler);
+    ClassWithMethods.ensureResolved(compiler.resolution);
     Element c = ClassWithMethods.lookupLocalMember('method');
     assert(c != null);
     ClassElement SubClass = library.find("SubClass");
-    SubClass.ensureResolved(compiler);
+    SubClass.ensureResolved(compiler.resolution);
     Element d = SubClass.lookupLocalMember('method');
     assert(d != null);
 
@@ -1190,7 +1191,7 @@
                      }""";
   compiler.parseScript(script);
   ClassElement foo = compiler.mainApp.find("Foo");
-  foo.ensureResolved(compiler);
+  foo.ensureResolved(compiler.resolution);
   Element method = foo.lookupLocalMember('method');
   analyzeIn(compiler, method, "{ int i = this; }", warnings: NOT_ASSIGNABLE);
   analyzeIn(compiler, method, "{ Object o = this; }");
@@ -1210,7 +1211,7 @@
     ''';
   compiler.parseScript(script);
   ClassElement B = compiler.mainApp.find("B");
-  B.ensureResolved(compiler);
+  B.ensureResolved(compiler.resolution);
   Element method = B.lookupLocalMember('method');
   analyzeIn(compiler, method, "{ int i = super.field; }",
       warnings: NOT_ASSIGNABLE);
@@ -1517,7 +1518,7 @@
                      }""";
   compiler.parseScript(script);
   ClassElement foo = compiler.mainApp.find("Foo");
-  foo.ensureResolved(compiler);
+  foo.ensureResolved(compiler.resolution);
   Element method = foo.lookupLocalMember('method');
 
   analyzeIn(compiler, method, "{ Type type = T; }");
@@ -1552,7 +1553,7 @@
 
   compiler.parseScript(script);
   ClassElement classTest = compiler.mainApp.find("Test");
-  classTest.ensureResolved(compiler);
+  classTest.ensureResolved(compiler.resolution);
   FunctionElement methodTest = classTest.lookupLocalMember("test");
 
   test(String expression, [message]) {
@@ -1592,7 +1593,7 @@
 
   compiler.parseScript(script);
   ClassElement classTest = compiler.mainApp.find("Test");
-  classTest.ensureResolved(compiler);
+  classTest.ensureResolved(compiler.resolution);
   FunctionElement methodTest = classTest.lookupLocalMember("test");
 
   test(String expression, [message]) {
@@ -1614,7 +1615,7 @@
 
   compiler.parseScript(script);
   ClassElement classTest = compiler.mainApp.find("Test");
-  classTest.ensureResolved(compiler);
+  classTest.ensureResolved(compiler.resolution);
   FunctionElement methodTest = classTest.lookupLocalMember("test");
 
   test(String expression, [message]) {
@@ -2325,7 +2326,7 @@
                      }""";
   compiler.parseScript(script);
   ClassElement foo = compiler.mainApp.find("Foo");
-  foo.ensureResolved(compiler);
+  foo.ensureResolved(compiler.resolution);
   FunctionElement method = foo.lookupLocalMember('method');
   analyzeIn(compiler, method, "{ await 0; }");
   analyzeIn(compiler, method, "{ int i = await 0; }");
@@ -2505,17 +2506,17 @@
       element = elements.head;
       if (element.isClass) {
         ClassElementX classElement = element;
-        classElement.ensureResolved(compiler);
+        classElement.ensureResolved(compiler.resolution);
         classElement.forEachLocalMember((Element e) {
           if (!e.isSynthesized) {
             element = e;
-            node = element.parseNode(compiler);
+            node = element.parseNode(compiler.parsing);
             compiler.resolver.resolve(element);
             mapping = element.treeElements;
           }
         });
       } else {
-        node = element.parseNode(compiler);
+        node = element.parseNode(compiler.parsing);
         compiler.resolver.resolve(element);
         mapping = element.treeElements;
       }
@@ -2549,7 +2550,7 @@
   compiler.diagnosticHandler = createHandler(compiler, text);
 
   Token tokens = scan(text);
-  NodeListener listener = new NodeListener(compiler, null);
+  NodeListener listener = new NodeListener(compiler.reporter, null);
   Parser parser = new Parser(listener);
   parser.parseStatement(tokens);
   Node node = listener.popNode();
@@ -2596,7 +2597,7 @@
 
   compiler.resolver.resolve(element);
   Token tokens = scan(text);
-  NodeListener listener = new NodeListener(compiler, null);
+  NodeListener listener = new NodeListener(compiler.reporter, null);
   Parser parser = new Parser(listener,
       yieldIsKeyword: element.asyncMarker.isYielding,
       awaitIsKeyword: element.asyncMarker.isAsync);
diff --git a/tests/compiler/dart2js/type_combination_test.dart b/tests/compiler/dart2js/type_combination_test.dart
index 2dc9f61..c75ad56 100644
--- a/tests/compiler/dart2js/type_combination_test.dart
+++ b/tests/compiler/dart2js/type_combination_test.dart
@@ -734,7 +734,7 @@
     World world = compiler.world;
     backend.interceptorsLibrary.forEachLocalMember((element) {
       if (element.isClass) {
-        element.ensureResolved(compiler);
+        element.ensureResolved(compiler.resolution);
         backend.registerInstantiatedType(
             element.rawType,
             compiler.enqueuer.resolution,
diff --git a/tests/compiler/dart2js/type_equals_test.dart b/tests/compiler/dart2js/type_equals_test.dart
index 3b71f5f..0911d60 100644
--- a/tests/compiler/dart2js/type_equals_test.dart
+++ b/tests/compiler/dart2js/type_equals_test.dart
@@ -10,15 +10,17 @@
 bool test(compiler, String name1, String name2, {bool expect}) {
   Expect.isTrue((expect != null), 'required parameter "expect" not given');
   var clazz = findElement(compiler, "Class");
-  clazz.ensureResolved(compiler);
+  clazz.ensureResolved(compiler.resolution);
   var element1 = clazz.buildScope().lookup(name1);
   var element2 = clazz.buildScope().lookup(name2);
   Expect.isNotNull(element1);
   Expect.isNotNull(element2);
   Expect.equals(element1.kind, ElementKind.FUNCTION);
   Expect.equals(element2.kind, ElementKind.FUNCTION);
-  FunctionSignature signature1 = element1.computeSignature(compiler);
-  FunctionSignature signature2 = element2.computeSignature(compiler);
+  element1.computeType(compiler.resolution);
+  element2.computeType(compiler.resolution);
+  FunctionSignature signature1 = element1.functionSignature;
+  FunctionSignature signature2 = element2.functionSignature;
 
   // Function signatures are used to be to provide void types (only occuring as
   // as return types) and (inlined) function types (only occuring as method
diff --git a/tests/compiler/dart2js/type_inference8_test.dart b/tests/compiler/dart2js/type_inference8_test.dart
index fc2d578..570e43a 100644
--- a/tests/compiler/dart2js/type_inference8_test.dart
+++ b/tests/compiler/dart2js/type_inference8_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "package:async_helper/async_helper.dart";
+import "package:compiler/src/constants/values.dart";
 import "package:compiler/src/types/types.dart";
 import "package:expect/expect.dart";
 import 'compiler_helper.dart';
@@ -37,7 +38,8 @@
     var typesInferrer = typesTask.typesInferrer;
     var element = findElement(compiler, "foo");
     var mask = typesInferrer.getReturnTypeOfElement(element);
-    var falseType = new ValueTypeMask(typesTask.boolType, false);
+    var falseType =
+        new ValueTypeMask(typesTask.boolType, new FalseConstantValue());
     // 'foo' should always return false
     Expect.equals(falseType, mask);
     // the argument to 'bar' is always false
diff --git a/tests/compiler/dart2js/type_order_test.dart b/tests/compiler/dart2js/type_order_test.dart
index e4faa01..5cc9178 100644
--- a/tests/compiler/dart2js/type_order_test.dart
+++ b/tests/compiler/dart2js/type_order_test.dart
@@ -44,15 +44,15 @@
     InterfaceType A_X_Y = add(instantiate(A, [X, Y]));
     InterfaceType A_Y_X = add(instantiate(A, [Y, X]));
 
-    TypedefType B_this = add(B.computeType(env.compiler));
+    TypedefType B_this = add(B.computeType(env.compiler.resolution));
     TypedefType B_raw = add(B.rawType);
     TypeVariableType BT = add(B_this.typeArguments[0]);
     TypeVariableType BS = add(B_this.typeArguments[1]);
     FunctionType B_this_alias = add(B.alias);
     TypedefType B_X_Y = add(instantiate(B, [X, Y]));
-    FunctionType B_X_Y_alias = add(B_X_Y.unalias(env.compiler));
+    FunctionType B_X_Y_alias = add(B_X_Y.unalias(env.compiler.resolution));
     TypedefType B_Y_X = add(instantiate(B, [Y, X]));
-    FunctionType B_Y_X_alias = add(B_Y_X.unalias(env.compiler));
+    FunctionType B_Y_X_alias = add(B_Y_X.unalias(env.compiler.resolution));
 
     InterfaceType C_this = add(C.thisType);
     InterfaceType C_raw = add(C.rawType);
diff --git a/tests/compiler/dart2js/type_representation_test.dart b/tests/compiler/dart2js/type_representation_test.dart
index 81c3654..83f4806 100644
--- a/tests/compiler/dart2js/type_representation_test.dart
+++ b/tests/compiler/dart2js/type_representation_test.dart
@@ -133,7 +133,8 @@
     expect(dynamic_, 'null');
 
     // List<E>
-    expect(List_.computeType(env.compiler), '[$List_rep, $List_E_rep]');
+    expect(List_.computeType(env.compiler.resolution),
+        '[$List_rep, $List_E_rep]');
     // List
     expect(List_.rawType, '$List_rep');
     // List<dynamic>
@@ -194,7 +195,7 @@
           '$args: [$int_rep], $opt: [,]}], $typedefTag: $Typedef10_rep}]');
 
     // Map<K,V>
-    expect(Map_.computeType(env.compiler),
+    expect(Map_.computeType(env.compiler.resolution),
            '[$Map_rep, $Map_K_rep, $Map_V_rep]');
     // Map
     expect(Map_.rawType, '$Map_rep');
@@ -206,49 +207,49 @@
 
 
     // void m1() {}
-    expect(env.getElement('m1').computeType(env.compiler),
+    expect(env.getElement('m1').computeType(env.compiler.resolution),
            '{$func: 1, $retvoid: true}');
 
     // int m2() => 0;
-    expect(env.getElement('m2').computeType(env.compiler),
+    expect(env.getElement('m2').computeType(env.compiler.resolution),
            '{$func: 1, $ret: $int_rep}');
 
     // List<int> m3() => null;
-    expect(env.getElement('m3').computeType(env.compiler),
+    expect(env.getElement('m3').computeType(env.compiler.resolution),
            '{$func: 1, $ret: [$List_rep, $int_rep]}');
 
     // m4() {}
-    expect(env.getElement('m4').computeType(env.compiler),
+    expect(env.getElement('m4').computeType(env.compiler.resolution),
            '{$func: 1}');
 
     // m5(int a, String b) {}
-    expect(env.getElement('m5').computeType(env.compiler),
+    expect(env.getElement('m5').computeType(env.compiler.resolution),
            '{$func: 1, $args: [$int_rep, $String_rep]}');
 
     // m6(int a, [String b]) {}
-    expect(env.getElement('m6').computeType(env.compiler),
+    expect(env.getElement('m6').computeType(env.compiler.resolution),
            '{$func: 1, $args: [$int_rep],'
            ' $opt: [$String_rep]}');
 
     // m7(int a, String b, [List<int> c, d]) {}
-    expect(env.getElement('m7').computeType(env.compiler),
+    expect(env.getElement('m7').computeType(env.compiler.resolution),
            '{$func: 1,'
            ' $args: [$int_rep, $String_rep],'
            ' $opt: [[$List_rep, $int_rep],,]}');
 
     // m8(int a, {String b}) {}
-    expect(env.getElement('m8').computeType(env.compiler),
+    expect(env.getElement('m8').computeType(env.compiler.resolution),
            '{$func: 1,'
            ' $args: [$int_rep], $named: {b: $String_rep}}');
 
     // m9(int a, String b, {List<int> c, d}) {}
-    expect(env.getElement('m9').computeType(env.compiler),
+    expect(env.getElement('m9').computeType(env.compiler.resolution),
            '{$func: 1,'
            ' $args: [$int_rep, $String_rep],'
            ' $named: {c: [$List_rep, $int_rep], d: null}}');
 
     // m10(void f(int a, [b])) {}
-    expect(env.getElement('m10').computeType(env.compiler),
+    expect(env.getElement('m10').computeType(env.compiler.resolution),
            '{$func: 1, $args:'
            ' [{$func: 1,'
            ' $retvoid: true, $args: [$int_rep], $opt: [,]}]}');
diff --git a/tests/compiler/dart2js/type_substitution_test.dart b/tests/compiler/dart2js/type_substitution_test.dart
index dad50ae..91c8718 100644
--- a/tests/compiler/dart2js/type_substitution_test.dart
+++ b/tests/compiler/dart2js/type_substitution_test.dart
@@ -12,11 +12,12 @@
 
 DartType getType(compiler, String name) {
   var clazz = findElement(compiler, "Class");
-  clazz.ensureResolved(compiler);
+  clazz.ensureResolved(compiler.resolution);
   var element = clazz.buildScope().lookup(name);
   Expect.isNotNull(element);
   Expect.equals(element.kind, ElementKind.FUNCTION);
-  FunctionSignature signature = element.computeSignature(compiler);
+  element.computeType(compiler.resolution);
+  FunctionSignature signature = element.functionSignature;
 
   // Function signatures are used to be to provide void types (only occuring as
   // as return types) and (inlined) function types (only occuring as method
@@ -210,7 +211,7 @@
     Expect.isNotNull(Typedef2_int_String);
     DartType Function_int_String = getType(compiler, "Function2b");
     Expect.isNotNull(Function_int_String);
-    DartType unalias1 = Typedef2_int_String.unalias(compiler);
+    DartType unalias1 = Typedef2_int_String.unalias(compiler.resolution);
     Expect.equals(Function_int_String, unalias1,
         '$Typedef2_int_String.unalias=$unalias1 != $Function_int_String');
 
@@ -218,7 +219,7 @@
     Expect.isNotNull(Typedef1);
     DartType Function_dynamic_dynamic = getType(compiler, "Function1c");
     Expect.isNotNull(Function_dynamic_dynamic);
-    DartType unalias2 = Typedef1.unalias(compiler);
+    DartType unalias2 = Typedef1.unalias(compiler.resolution);
     Expect.equals(Function_dynamic_dynamic, unalias2,
         '$Typedef1.unalias=$unalias2 != $Function_dynamic_dynamic');
   }));
diff --git a/tests/compiler/dart2js/type_test_helper.dart b/tests/compiler/dart2js/type_test_helper.dart
index c67d0ba..32ed3ff 100644
--- a/tests/compiler/dart2js/type_test_helper.dart
+++ b/tests/compiler/dart2js/type_test_helper.dart
@@ -92,15 +92,15 @@
     var element = compiler.mainApp.find(name);
     Expect.isNotNull(element);
     if (element.isClass) {
-      element.ensureResolved(compiler);
+      element.ensureResolved(compiler.resolution);
     } else if (element.isTypedef) {
-      element.computeType(compiler);
+      element.computeType(compiler.resolution);
     }
     return element;
   }
 
   DartType getElementType(String name) {
-    return getElement(name).computeType(compiler);
+    return getElement(name).computeType(compiler.resolution);
   }
 
   DartType operator[] (String name) {
@@ -111,7 +111,7 @@
 
   DartType getMemberType(ClassElement element, String name) {
     Element member = element.localLookup(name);
-    return member.computeType(compiler);
+    return member.computeType(compiler.resolution);
   }
 
   bool isSubtype(DartType T, DartType S) {
diff --git a/tests/compiler/dart2js/unparser2_test.dart b/tests/compiler/dart2js/unparser2_test.dart
index 09c713d..91e13aa 100644
--- a/tests/compiler/dart2js/unparser2_test.dart
+++ b/tests/compiler/dart2js/unparser2_test.dart
@@ -99,7 +99,7 @@
   return unparse(node);
 }
 
-class MessageCollector extends DiagnosticListener {
+class MessageCollector extends DiagnosticReporter {
   List<String> messages;
   MessageCollector() {
     messages = [];
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 56f3f17..a257c10 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -237,3 +237,6 @@
 symbol_reserved_word_test/09: RuntimeError # Please triage this failure.
 symbol_reserved_word_test/12: RuntimeError # Please triage this failure.
 symbol_test/none: RuntimeError # Please triage this failure.
+
+[ $compiler == dart2js && $cps_ir && $host_checked ]
+regexp/pcre_test: Crash # Stack Overflow
diff --git a/tests/html/html.status b/tests/html/html.status
index ff918be..557a657 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -13,12 +13,15 @@
 cross_domain_iframe_test: RuntimeError # Dartium JSInterop failure
 crypto_test/functional: RuntimeError # Dartium JSInterop failure
 custom/document_register_basic_test: RuntimeError # Dartium JSInterop failure
+custom/document_register_type_extensions_test/construction: RuntimeError # Issue 24516
+custom/document_register_type_extensions_test/parsing: RuntimeError # Issue 24516
 custom/document_register_type_extensions_test/registration: RuntimeError # Dartium JSInterop failure
 custom/element_upgrade_test: RuntimeError # Dartium JSInterop failure
 custom/js_custom_test: RuntimeError # Dartium JSInterop failure
 custom_elements_test/register: RuntimeError # Dartium JSInterop failure
 indexeddb_2_test: Skip # Dartium JSInterop failure
-js_test: RuntimeError # Dartium JSInterop failure
+js_test/transferrables: RuntimeError # Dartium JSInterop failure
+js_test/JsArray: RuntimeError # Dartium JSInterop failure
 native_gc_test: Skip # Dartium JSInterop failure
 speechrecognition_test/types: RuntimeError # Dartium JSInterop failure
 storage_quota_test/missingenumcheck: RuntimeError # Dartium JSInterop failure
@@ -37,6 +40,7 @@
 
 [ $compiler == dart2js ]
 input_element_test/attributes: Fail # Issue 21555
+wrapping_collections_test: SkipByDesign # Testing an issue that is only relevant to Dartium
 
 [ $compiler == dart2js && $csp && $browser ]
 custom/js_custom_test: Fail # Issue 14643
@@ -59,7 +63,6 @@
 [ $compiler == none && ($runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
 # postMessage in dartium always transfers the typed array buffer, never a view
 postmessage_structured_test/typed_arrays: Fail
-postmessage_structured_test/primitives: RuntimeError # Bug 24432
 # Dartium seems to lose the data from the dispatchEvent.
 async_test: Fail # Uses spawn, not implemented from a DOM isolate in Dartium
 keyboard_event_test: Fail # Issue 13902
@@ -134,10 +137,10 @@
 
 [$runtime == ie10 || $runtime == ie11]
 indexeddb_5_test: Fail # Issue 12893
-js_test: Fail # Issue 14246
-element_test/click: Fail                # IE does not support firing this event.
+js_test/transferrables: RuntimeError # Issue 14246
+element_test/click: Fail # IE does not support firing this event.
 serialized_script_value_test: Fail
-websocket_test/websocket: Fail # TODO(efortuna): Issue 7875.
+websocket_test/websocket: Fail # Issue 7875. Closed with "working as intended".
 canvasrenderingcontext2d_test/drawImage_video_element: Fail # IE does not support drawImage w/ video element
 canvasrenderingcontext2d_test/drawImage_video_element_dataUrl: Fail # IE does not support drawImage w/ video element
 no_linked_scripts_htmltest: Skip # Times out on IE.  Issue 21537
diff --git a/tests/html/js_test.dart b/tests/html/js_test.dart
index 081ab02..ab83a5c 100644
--- a/tests/html/js_test.dart
+++ b/tests/html/js_test.dart
@@ -11,7 +11,7 @@
 import 'dart:js';
 
 import 'package:unittest/unittest.dart';
-import 'package:unittest/html_config.dart';
+import 'package:unittest/html_individual_config.dart';
 
 _injectJs() {
   final script = new ScriptElement();
@@ -230,7 +230,7 @@
 
 main() {
   _injectJs();
-  useHtmlConfiguration();
+  useHtmlIndividualConfiguration();
 
   group('identity', () {
 
@@ -552,7 +552,7 @@
       array.length = 3;
       expect(array, [1, 2, null]);
     });
- 
+
      test('add', () {
       var array = new JsArray();
       array.add('a');
diff --git a/tests/html/wrapping_collections_test.dart b/tests/html/wrapping_collections_test.dart
new file mode 100644
index 0000000..dc84508
--- /dev/null
+++ b/tests/html/wrapping_collections_test.dart
@@ -0,0 +1,26 @@
+library wrapping_collection_test;
+
+import 'dart:html';
+import 'dart:js' as js;
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+/// Test that if we access objects through JS-interop we get the
+/// appropriate objects, even if dart:html maps them.
+main() {
+  test("Access through JS-interop", () {
+    var performance = js.context['performance'];
+    var entries = performance.callMethod('getEntries', const []);
+    entries.forEach((x) {
+        expect(x is js.JsObject, isTrue);
+    });
+  });
+
+  test("Access through dart:html", () {
+    var dartPerformance = wrap_jso(js.context['performance']);
+    var dartEntries = dartPerformance.getEntries();
+    dartEntries.forEach((x) {
+        expect(x is PerformanceEntry, isTrue);
+    });
+  });
+}
\ No newline at end of file
diff --git a/tests/isolate/package_root_test.dart b/tests/isolate/package_root_test.dart
index 2ee6b30..a17bce7 100644
--- a/tests/isolate/package_root_test.dart
+++ b/tests/isolate/package_root_test.dart
@@ -5,32 +5,27 @@
 import 'dart:io';
 import 'dart:isolate';
 
-final SPAWN_PACKAGE_ROOT = Uri.parse("otherPackageRoot");
+final SPAWN_PACKAGE_ROOT = "file:///no/such/file/";
 
 void main([args, port]) {
   if (port != null) {
-    testPackageRoot(args);
+    testPackageRoot(port);
     return;
   }
-  var p = new ReceivePort();
+  var p = new RawReceivePort();
   Isolate.spawnUri(Platform.script,
-                   [p.sendPort, Platform.packageRoot],
-                   {},
-                   packageRoot: SPAWN_PACKAGE_ROOT);
-  p.listen((msg) {
+                   [],
+                   p.sendPort,
+                   packageRoot: Uri.parse(SPAWN_PACKAGE_ROOT));
+  p.handler = (msg) {
     p.close();
-  });
+    if (msg != SPAWN_PACKAGE_ROOT) {
+      throw "Bad package root in child isolate: $msg";
+    }
+  };
 }
 
-
-void testPackageRoot(args) {
-  var parentPackageRoot = args[1];
-  if (parentPackageRoot == Platform.packageRoot) {
-    throw "Got parent package root";
-  }
-  if (Uri.parse(Platform.packageRoot) != SPAWN_PACKAGE_ROOT) {
-    throw "Wrong package root";
-  }
-  args[0].send(null);
+testPackageRoot(port) async {
+  var packageRoot = await Isolate.packageRoot;
+  port.send(packageRoot.toString());
 }
-
diff --git a/tests/language/await_regression_test.dart b/tests/language/await_regression_test.dart
index 9c3e663..90a562d 100644
--- a/tests/language/await_regression_test.dart
+++ b/tests/language/await_regression_test.dart
@@ -30,7 +30,19 @@
   Expect.equals(sum, 0);
 }
 
+testSideEffects() async {
+  Future foo(int a1, int a2) {
+    Expect.equals(10, a1);
+    Expect.equals(11, a2);
+    return new Future.value();
+  }
+  int a = 10;
+  await foo(a++, a++);
+  Expect.equals(12, a);
+}
+
 main() async {
   testNestedFunctions();
   testNamedArguments();
+  testSideEffects();
 }
diff --git a/tests/language/language.status b/tests/language/language.status
index 9ad2646..e164c45 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -73,6 +73,9 @@
 mirror_in_static_init_test: Fail # Issue 22071
 vm/debug_break_enabled_vm_test/*: Skip # Issue 14651.
 
+[ $compiler == none && $runtime == dartium && $system == linux && $arch != x64 ]
+issue_22780_test/01 : Pass, Timeout # Issue 24473
+
 [ $compiler == none && $runtime == drt ]
 disassemble_test: Pass, Fail # Issue 18122
 
@@ -94,6 +97,4 @@
 vm/load_to_load_unaligned_forwarding_vm_test: Pass, Crash # Unaligned offset. Issue 22151
 
 [ $compiler == none && ( $runtime == dartium || $runtime == drt ) ]
-mixin_super_test: Fail # Can't pass VMOptions to dartium.
-mixin_super_bound2_test: Fail # Can't pass VMOptions to dartium.
 issue23244_test: Fail # Can't run spawnFunction on dartium.
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index bb3cf05..a5f91bf 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -362,6 +362,9 @@
 mixin_super_bound_test: StaticWarning # legitimate StaticWarning, cannot be annotated
 mixin_super_bound2_test: CompileTimeError # Issue 23772
 mixin_super_test: CompileTimeError # Issue 23772
+mixin_super_2_test: CompileTimeError # Issue 23772
+mixin_super_use_test: CompileTimeError # Issue 23772
+mixin_superclass_test: CompileTimeError # Issue 23772
 named_constructor_test/01: StaticWarning
 named_constructor_test/03: StaticWarning
 named_parameters2_test: StaticWarning
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index 24de2b9..e42ce660 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -303,6 +303,11 @@
 mixin_invalid_bound_test/none: StaticWarning # legitimate StaticWarning, cannot be annotated
 mixin_invalid_bound2_test/none: StaticWarning # legitimate StaticWarning, cannot be annotated
 mixin_super_bound_test: StaticWarning # legitimate StaticWarning, cannot be annotated
+mixin_super_bound2_test: CompileTimeError # Issue 24478
+mixin_super_test: CompileTimeError # Issue 24478
+mixin_super_2_test: CompileTimeError # Issue 24478
+mixin_super_use_test: CompileTimeError # Issue 24478
+mixin_superclass_test: CompileTimeError # Issue 24478
 named_constructor_test/01: StaticWarning
 named_constructor_test/03: StaticWarning
 named_parameters2_test: StaticWarning
@@ -416,7 +421,8 @@
 switch7_negative_test: CompileTimeError
 switch_fallthru_test: StaticWarning
 test_negative_test: CompileTimeError
-top_level_non_prefixed_library_test: StaticWarning
+# Note: test is in error but analyzer doesn't notice due to bug #24502
+# top_level_non_prefixed_library_test: StaticWarning
 try_catch4_test: StaticWarning
 try_catch5_test: StaticWarning
 type_argument_in_super_type_test: StaticWarning
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 99ceb15..06637d1 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -49,7 +49,10 @@
 mixin_super_constructor_named_test/01: Fail # Issue 15101
 mixin_super_constructor_positionals_test/01: Fail # Issue 15101
 mixin_super_test: CompileTimeError # Issue 23773
+mixin_super_2_test: CompileTimeError # Issue 23773
 mixin_super_bound2_test: CompileTimeError # Issue 23773
+mixin_super_use_test: CompileTimeError # Issue 23773
+mixin_superclass_test: CompileTimeError # Issue 23773
 
 ref_before_declaration_test/00: MissingCompileTimeError
 ref_before_declaration_test/01: MissingCompileTimeError
@@ -368,8 +371,8 @@
 switch_label2_test: Crash # (switch (target){cas...  continue to a labeled switch case
 switch_label_test: Crash # (switch (animal){cas...  continue to a labeled switch case
 switch_try_catch_test: Crash # (switch (0){_0:case ...  continue to a labeled switch case
-sync_generator1_test/01: Timeout # Please triage this failure.
-sync_generator1_test/none: Timeout # Please triage this failure.
+sync_generator1_test/01: RuntimeError # Expect.equals(expected: <(1, 2, 3, 5, [6])>, actual: <(1)>) fails.
+sync_generator1_test/none: RuntimeError # Expect.equals(expected: <(1, 2, 3, 5, [6])>, actual: <(1)>) fails.
 sync_generator3_test/test1: RuntimeError # Please triage this failure.
 sync_generator3_test/test2: RuntimeError # Please triage this failure.
 syncstar_yield_test/copyParameters: RuntimeError # Please triage this failure.
@@ -379,3 +382,10 @@
 type_variable_field_initializer_closure_test: RuntimeError # Please triage this failure.
 type_variable_field_initializer_test: RuntimeError # Please triage this failure.
 type_variable_nested_test: RuntimeError # Please triage this failure.
+
+[ $compiler == dart2js && $cps_ir && $host_checked ]
+async_throw_in_catch_test/forceAwait: Crash # Issue 24485
+async_throw_in_catch_test/none: Crash # Issue 24485
+execute_finally9_test: Crash # Issue 24485
+regress_21795_test: Crash # Issue 24485
+regress_23537_test: Crash # Issue 24485
diff --git a/tests/language/mixin_illegal_superclass_test.dart b/tests/language/mixin_illegal_superclass_test.dart
deleted file mode 100644
index 03d2e6a..0000000
--- a/tests/language/mixin_illegal_superclass_test.dart
+++ /dev/null
@@ -1,121 +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.
-
-class S0 { }
-class S1 extends Object { }
-class S2 extends S0 { }
-
-class M0 { }
-class M1 extends Object { }
-class M2 extends M0 { }
-
-class C00 = S0 with M0;
-class C01 = S0 with M1;
-class C02 = S0 with M2;      /// 01: compile-time error
-class C03 = S0 with M0, M1;
-class C04 = S0 with M0, M2;  /// 02: compile-time error
-class C05 = S0 with M2, M0;  /// 03: compile-time error
-class C06 = S0 with M1, M2;  /// 04: compile-time error
-class C07 = S0 with M2, M1;  /// 05: compile-time error
-
-class C10 = S1 with M0;
-class C11 = S1 with M1;
-class C12 = S1 with M2;      /// 06: compile-time error
-class C13 = S1 with M0, M1;
-class C14 = S1 with M0, M2;  /// 07: compile-time error
-class C15 = S1 with M2, M0;  /// 08: compile-time error
-class C16 = S1 with M1, M2;  /// 09: compile-time error
-class C17 = S1 with M2, M1;  /// 10: compile-time error
-
-class C20 = S2 with M0;
-class C21 = S2 with M1;
-class C22 = S2 with M2;      /// 11: compile-time error
-class C23 = S2 with M0, M1;
-class C24 = S2 with M0, M2;  /// 12: compile-time error
-class C25 = S2 with M2, M0;  /// 13: compile-time error
-class C26 = S2 with M1, M2;  /// 14: compile-time error
-class C27 = S2 with M2, M1;  /// 15: compile-time error
-
-class D00 extends S0 with M0 { }
-class D01 extends S0 with M1 { }
-class D02 extends S0 with M2 { }      /// 16: compile-time error
-class D03 extends S0 with M0, M1 { }
-class D04 extends S0 with M0, M2 { }  /// 17: compile-time error
-class D05 extends S0 with M2, M0 { }  /// 18: compile-time error
-class D06 extends S0 with M1, M2 { }  /// 19: compile-time error
-class D07 extends S0 with M2, M1 { }  /// 20: compile-time error
-
-class D10 extends S1 with M0 { }
-class D11 extends S1 with M1 { }
-class D12 extends S1 with M2 { }      /// 21: compile-time error
-class D13 extends S1 with M0, M1 { }
-class D14 extends S1 with M0, M2 { }  /// 22: compile-time error
-class D15 extends S1 with M2, M0 { }  /// 23: compile-time error
-class D16 extends S1 with M1, M2 { }  /// 24: compile-time error
-class D17 extends S1 with M2, M1 { }  /// 25: compile-time error
-
-class D20 extends S2 with M0 { }
-class D21 extends S2 with M1 { }
-class D22 extends S2 with M2 { }      /// 26: compile-time error
-class D23 extends S2 with M0, M1 { }
-class D24 extends S2 with M0, M2 { }  /// 27: compile-time error
-class D25 extends S2 with M2, M0 { }  /// 28: compile-time error
-class D26 extends S2 with M1, M2 { }  /// 29: compile-time error
-class D27 extends S2 with M2, M1 { }  /// 30: compile-time error
-
-main() {
-  new C00();
-  new C01();
-  new C02();  /// 01: continued
-  new C03();
-  new C04();  /// 02: continued
-  new C05();  /// 03: continued
-  new C06();  /// 04: continued
-  new C07();  /// 05: continued
-
-  new C10();
-  new C11();
-  new C12();  /// 06: continued
-  new C13();
-  new C14();  /// 07: continued
-  new C15();  /// 08: continued
-  new C16();  /// 09: continued
-  new C17();  /// 10: continued
-
-  new C20();
-  new C21();
-  new C22();  /// 11: continued
-  new C23();
-  new C24();  /// 12: continued
-  new C25();  /// 13: continued
-  new C26();  /// 14: continued
-  new C27();  /// 15: continued
-
-  new D00();
-  new D01();
-  new D02();  /// 16: continued
-  new D03();
-  new D04();  /// 17: continued
-  new D05();  /// 18: continued
-  new D06();  /// 19: continued
-  new D07();  /// 20: continued
-
-  new D10();
-  new D11();
-  new D12();  /// 21: continued
-  new D13();
-  new D14();  /// 22: continued
-  new D15();  /// 23: continued
-  new D16();  /// 24: continued
-  new D17();  /// 25: continued
-
-  new D20();
-  new D21();
-  new D22();  /// 26: continued
-  new D23();
-  new D24();  /// 27: continued
-  new D25();  /// 28: continued
-  new D26();  /// 29: continued
-  new D27();  /// 30: continued
-}
diff --git a/tests/language/mixin_super_2_test.dart b/tests/language/mixin_super_2_test.dart
new file mode 100644
index 0000000..ad86c08
--- /dev/null
+++ b/tests/language/mixin_super_2_test.dart
@@ -0,0 +1,42 @@
+// 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";
+
+class B {
+  // 'super' resolves to Object, and in some tests, multiple points in the
+  // inheritance chain.
+  toString() => 'B(' + super.toString() + ')';
+}
+
+class R {
+  toString() => 'R[' + super.toString() + ']';
+}
+
+class D extends R with B {
+  toString() => 'D<' + super.toString() + '>';
+}
+
+class E extends D with B {
+  toString() => 'E{' + super.toString() + '}';
+}
+
+class F = R with B, B;
+
+class G extends F with B {
+  toString() => 'G{' + super.toString() + '}';
+}
+
+main(){
+  check(object, String expected) {
+    Expect.equals(expected, object.toString());
+  }
+
+  check(new B(), "B(Instance of 'B')");
+  check(new R(), "R[Instance of 'R']");
+  check(new D(), "D<B(R[Instance of 'D'])>");
+  check(new E(), "E{B(D<B(R[Instance of 'E'])>)}");
+  check(new F(), "B(B(R[Instance of 'F']))");
+  check(new G(), "G{B(B(B(R[Instance of 'G'])))}");
+}
diff --git a/tests/language/mixin_super_bound2_test.dart b/tests/language/mixin_super_bound2_test.dart
index 87e8b7a..c6fcd7a 100644
--- a/tests/language/mixin_super_bound2_test.dart
+++ b/tests/language/mixin_super_bound2_test.dart
@@ -1,7 +1,6 @@
 // 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=--supermixin
 
 import "package:expect/expect.dart";
 
diff --git a/tests/language/mixin_super_test.dart b/tests/language/mixin_super_test.dart
index 8a4ee98..6a5d5a3 100644
--- a/tests/language/mixin_super_test.dart
+++ b/tests/language/mixin_super_test.dart
@@ -1,7 +1,6 @@
 // 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=--supermixin
 
 import "package:expect/expect.dart";
 
diff --git a/tests/language/mixin_illegal_super_use_test.dart b/tests/language/mixin_super_use_test.dart
similarity index 64%
rename from tests/language/mixin_illegal_super_use_test.dart
rename to tests/language/mixin_super_use_test.dart
index 7f0d64a..cd95846 100644
--- a/tests/language/mixin_illegal_super_use_test.dart
+++ b/tests/language/mixin_super_use_test.dart
@@ -9,21 +9,15 @@
 
 class P0 {
   foo() {
-    super.toString();    /// 01: compile-time error
-    super.foo();         /// 02: compile-time error
-    super.bar = 100;     /// 03: compile-time error
+    super.toString();
 
     void inner() {
-      super.toString();  /// 04: compile-time error
-      super.foo();       /// 05: compile-time error
-      super.bar = 100;   /// 06: compile-time error
+      super.toString();
     }
     inner();
 
     (() {
-      super.toString();  /// 07: compile-time error
-      super.foo();       /// 08: compile-time error
-      super.bar = 100;   /// 09: compile-time error
+      super.toString();
     })();
 
     return 42;
@@ -32,7 +26,7 @@
 
 class P1 {
   bar() {
-    super.toString();    /// 10: compile-time error
+    super.toString();
     return 87;
   }
 
@@ -52,7 +46,7 @@
 
 class P2 {
   baz() {
-    super.toString();   /// 11: compile-time error
+    super.toString();
     return 99;
   }
 }
diff --git a/tests/language/mixin_superclass_test.dart b/tests/language/mixin_superclass_test.dart
new file mode 100644
index 0000000..ade41da
--- /dev/null
+++ b/tests/language/mixin_superclass_test.dart
@@ -0,0 +1,121 @@
+// 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.
+
+class S0 { }
+class S1 extends Object { }
+class S2 extends S0 { }
+
+class M0 { }
+class M1 extends Object { }
+class M2 extends M0 { }
+
+class C00 = S0 with M0;
+class C01 = S0 with M1;
+class C02 = S0 with M2;
+class C03 = S0 with M0, M1;
+class C04 = S0 with M0, M2;
+class C05 = S0 with M2, M0;
+class C06 = S0 with M1, M2;
+class C07 = S0 with M2, M1;
+
+class C10 = S1 with M0;
+class C11 = S1 with M1;
+class C12 = S1 with M2;
+class C13 = S1 with M0, M1;
+class C14 = S1 with M0, M2;
+class C15 = S1 with M2, M0;
+class C16 = S1 with M1, M2;
+class C17 = S1 with M2, M1;
+
+class C20 = S2 with M0;
+class C21 = S2 with M1;
+class C22 = S2 with M2;
+class C23 = S2 with M0, M1;
+class C24 = S2 with M0, M2;
+class C25 = S2 with M2, M0;
+class C26 = S2 with M1, M2;
+class C27 = S2 with M2, M1;
+
+class D00 extends S0 with M0 { }
+class D01 extends S0 with M1 { }
+class D02 extends S0 with M2 { }
+class D03 extends S0 with M0, M1 { }
+class D04 extends S0 with M0, M2 { }
+class D05 extends S0 with M2, M0 { }
+class D06 extends S0 with M1, M2 { }
+class D07 extends S0 with M2, M1 { }
+
+class D10 extends S1 with M0 { }
+class D11 extends S1 with M1 { }
+class D12 extends S1 with M2 { }
+class D13 extends S1 with M0, M1 { }
+class D14 extends S1 with M0, M2 { }
+class D15 extends S1 with M2, M0 { }
+class D16 extends S1 with M1, M2 { }
+class D17 extends S1 with M2, M1 { }
+
+class D20 extends S2 with M0 { }
+class D21 extends S2 with M1 { }
+class D22 extends S2 with M2 { }
+class D23 extends S2 with M0, M1 { }
+class D24 extends S2 with M0, M2 { }
+class D25 extends S2 with M2, M0 { }
+class D26 extends S2 with M1, M2 { }
+class D27 extends S2 with M2, M1 { }
+
+main() {
+  new C00();
+  new C01();
+  new C02();
+  new C03();
+  new C04();
+  new C05();
+  new C06();
+  new C07();
+
+  new C10();
+  new C11();
+  new C12();
+  new C13();
+  new C14();
+  new C15();
+  new C16();
+  new C17();
+
+  new C20();
+  new C21();
+  new C22();
+  new C23();
+  new C24();
+  new C25();
+  new C26();
+  new C27();
+
+  new D00();
+  new D01();
+  new D02();
+  new D03();
+  new D04();
+  new D05();
+  new D06();
+  new D07();
+
+  new D10();
+  new D11();
+  new D12();
+  new D13();
+  new D14();
+  new D15();
+  new D16();
+  new D17();
+
+  new D20();
+  new D21();
+  new D22();
+  new D23();
+  new D24();
+  new D25();
+  new D26();
+  new D27();
+}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index c667970..473f375 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -350,3 +350,6 @@
 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
+
+[ $compiler == dart2js && $cps_ir && $host_checked ]
+mirrors/circular_factory_redirection_test/02: Crash # Assertion failure: Constant constructor already computed for generative_constructor(A#circular2)
diff --git a/tests/standalone/io/http_proxy_advanced_test.dart b/tests/standalone/io/http_proxy_advanced_test.dart
new file mode 100644
index 0000000..aeafaf0
--- /dev/null
+++ b/tests/standalone/io/http_proxy_advanced_test.dart
@@ -0,0 +1,636 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:crypto/crypto.dart";
+import "package:expect/expect.dart";
+import "package:path/path.dart";
+import "dart:async";
+import "dart:io";
+import 'dart:convert';
+
+String localFile(path) => Platform.script.resolve(path).toFilePath();
+
+SecurityContext serverContext = new SecurityContext()
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
+
+SecurityContext clientContext = new SecurityContext()
+  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+
+class Server {
+  HttpServer server;
+  bool secure;
+  int proxyHops;
+  List<String> directRequestPaths;
+  int requestCount = 0;
+
+  Server(this.proxyHops, this.directRequestPaths, this.secure);
+
+  Future<Server> start() {
+    return (secure ?
+        HttpServer.bindSecure("localhost", 0, serverContext) :
+        HttpServer.bind("localhost", 0))
+    .then((s) {
+      server = s;
+      server.listen(requestHandler);
+      return this;
+    });
+  }
+
+  void requestHandler(HttpRequest request) {
+    var response = request.response;
+    requestCount++;
+    // Check whether a proxy or direct connection is expected.
+    bool direct = directRequestPaths.fold(
+        false,
+        (prev, path) => prev ? prev : path == request.uri.path);
+    if (!secure && !direct && proxyHops > 0) {
+      Expect.isNotNull(request.headers[HttpHeaders.VIA]);
+      Expect.equals(1, request.headers[HttpHeaders.VIA].length);
+      Expect.equals(
+          proxyHops,
+          request.headers[HttpHeaders.VIA][0].split(",").length);
+    } else {
+      Expect.isNull(request.headers[HttpHeaders.VIA]);
+    }
+    var body = new StringBuffer();
+    onRequestComplete() {
+      String path = request.uri.path.substring(1);
+      if (path != "A") {
+        String content = "$path$path$path";
+        Expect.equals(content, body.toString());
+      }
+      response.write(request.uri.path);
+      response.close();
+    }
+    request.listen((data) {
+      body.write(new String.fromCharCodes(data));
+    }, onDone: onRequestComplete);
+  }
+
+  void shutdown() {
+    server.close();
+  }
+
+  int get port => server.port;
+}
+
+Future<Server> setupServer(int proxyHops,
+                   {List<String> directRequestPaths: const <String>[],
+                    secure: false}) {
+  Server server = new Server(proxyHops, directRequestPaths, secure);
+  return server.start();
+}
+
+class ProxyServer {
+  final bool ipV6;
+  HttpServer server;
+  HttpClient client;
+  int requestCount = 0;
+  String authScheme;
+  String realm = "test";
+  String username;
+  String password;
+
+  var ha1;
+  String serverAlgorithm = "MD5";
+  String serverQop = "auth";
+  Set ncs = new Set();
+
+  var nonce = "12345678";  // No need for random nonce in test.
+
+  ProxyServer({this.ipV6: false}) : client = new HttpClient();
+
+  void useBasicAuthentication(String username, String password) {
+    this.username = username;
+    this.password = password;
+    authScheme = "Basic";
+  }
+
+  void useDigestAuthentication(String username, String password) {
+    this.username = username;
+    this.password = password;
+    authScheme = "Digest";
+
+    // Calculate ha1.
+    var hasher = new MD5();
+    hasher.add("${username}:${realm}:${password}".codeUnits);
+    ha1 = CryptoUtils.bytesToHex(hasher.close());
+  }
+
+  basicAuthenticationRequired(request) {
+    request.fold(null, (x, y) {}).then((_) {
+      var response = request.response;
+      response.headers.set(HttpHeaders.PROXY_AUTHENTICATE,
+                           "Basic, realm=$realm");
+      response.statusCode = HttpStatus.PROXY_AUTHENTICATION_REQUIRED;
+      response.close();
+    });
+  }
+
+  digestAuthenticationRequired(request, {stale: false}) {
+    request.fold(null, (x, y) {}).then((_) {
+      var response = request.response;
+      response.statusCode = HttpStatus.PROXY_AUTHENTICATION_REQUIRED;
+      StringBuffer authHeader = new StringBuffer();
+      authHeader.write('Digest');
+      authHeader.write(', realm="$realm"');
+      authHeader.write(', nonce="$nonce"');
+      if (stale) authHeader.write(', stale="true"');
+      if (serverAlgorithm != null) {
+        authHeader.write(', algorithm=$serverAlgorithm');
+      }
+      if (serverQop != null) authHeader.write(', qop="$serverQop"');
+      response.headers.set(HttpHeaders.PROXY_AUTHENTICATE, authHeader);
+      response.close();
+    });
+  }
+
+  Future<ProxyServer> start() {
+    var x = new Completer();
+    var host = ipV6 ? "::1" : "localhost";
+    HttpServer.bind(host, 0).then((s) {
+      server = s;
+      x.complete(this);
+      server.listen((HttpRequest request) {
+        requestCount++;
+        if (username != null && password != null) {
+          if (request.headers[HttpHeaders.PROXY_AUTHORIZATION] == null) {
+            if (authScheme == "Digest") {
+              digestAuthenticationRequired(request);
+            } else {
+              basicAuthenticationRequired(request);
+            }
+            return;
+          } else {
+            Expect.equals(
+                1, request.headers[HttpHeaders.PROXY_AUTHORIZATION].length);
+            String authorization =
+              request.headers[HttpHeaders.PROXY_AUTHORIZATION][0];
+            if (authScheme == "Basic") {
+              List<String> tokens = authorization.split(" ");
+              Expect.equals("Basic", tokens[0]);
+              String auth =
+                  CryptoUtils.bytesToBase64(UTF8.encode("$username:$password"));
+              if (auth != tokens[1]) {
+                basicAuthenticationRequired(request);
+                return;
+              }
+            } else {
+              HeaderValue header =
+                  HeaderValue.parse(
+                      authorization, parameterSeparator: ",");
+              Expect.equals("Digest", header.value);
+              var uri = header.parameters["uri"];
+              var qop = header.parameters["qop"];
+              var cnonce = header.parameters["cnonce"];
+              var nc = header.parameters["nc"];
+              Expect.equals(username, header.parameters["username"]);
+              Expect.equals(realm, header.parameters["realm"]);
+              Expect.equals("MD5", header.parameters["algorithm"]);
+              Expect.equals(nonce, header.parameters["nonce"]);
+              Expect.equals(request.uri.toString(), uri);
+              if (qop != null) {
+                // A server qop of auth-int is downgraded to none by the client.
+                Expect.equals("auth", serverQop);
+                Expect.equals("auth", header.parameters["qop"]);
+                Expect.isNotNull(cnonce);
+                Expect.isNotNull(nc);
+                Expect.isFalse(ncs.contains(nc));
+                ncs.add(nc);
+              } else {
+                Expect.isNull(cnonce);
+                Expect.isNull(nc);
+              }
+              Expect.isNotNull(header.parameters["response"]);
+
+              var hasher = new MD5();
+              hasher.add("${request.method}:${uri}".codeUnits);
+              var ha2 = CryptoUtils.bytesToHex(hasher.close());
+
+              var x;
+              hasher = new MD5();
+              if (qop == null || qop == "" || qop == "none") {
+                hasher.add("$ha1:${nonce}:$ha2".codeUnits);
+              } else {
+                hasher.add(
+                    "$ha1:${nonce}:${nc}:${cnonce}:${qop}:$ha2".codeUnits);
+              }
+              Expect.equals(CryptoUtils.bytesToHex(hasher.close()),
+                            header.parameters["response"]);
+
+              // Add a bogus Proxy-Authentication-Info for testing.
+              var info = 'rspauth="77180d1ab3d6c9de084766977790f482", '
+                         'cnonce="8f971178", '
+                         'nc=000002c74, '
+                         'qop=auth';
+              request.response.headers.set("Proxy-Authentication-Info", info);
+            }
+          }
+        }
+        // Open the connection from the proxy.
+        if (request.method == "CONNECT") {
+          var tmp = request.uri.toString().split(":");
+          Socket.connect(tmp[0], int.parse(tmp[1]))
+              .then((socket) {
+                request.response.reasonPhrase = "Connection established";
+                request.response.detachSocket()
+                    .then((detached) {
+                      socket.pipe(detached);
+                      detached.pipe(socket);
+                    });
+              });
+        } else {
+          client.openUrl(request.method, request.uri)
+            .then((HttpClientRequest clientRequest) {
+              // Forward all headers.
+              request.headers.forEach((String name, List<String> values) {
+                values.forEach((String value) {
+                  if (name != "content-length" && name != "via") {
+                    clientRequest.headers.add(name, value);
+                  }
+                });
+              });
+              // Special handling of Content-Length and Via.
+              clientRequest.contentLength = request.contentLength;
+              List<String> via = request.headers[HttpHeaders.VIA];
+              String viaPrefix = via == null ? "" : "${via[0]}, ";
+              clientRequest.headers.add(
+                  HttpHeaders.VIA, "${viaPrefix}1.1 localhost:$port");
+              // Copy all content.
+              return request.pipe(clientRequest);
+            })
+            .then((HttpClientResponse clientResponse) {
+              clientResponse.pipe(request.response);
+            });
+        }
+      });
+    });
+    return x.future;
+  }
+
+  void shutdown() {
+    server.close();
+    client.close();
+  }
+
+  int get port => server.port;
+}
+
+Future<ProxyServer> setupProxyServer({ipV6: false}) {
+  ProxyServer proxyServer = new ProxyServer(ipV6: ipV6);
+  return proxyServer.start();
+}
+
+
+int testProxyIPV6DoneCount = 0;
+void testProxyIPV6() {
+  setupProxyServer(ipV6: true).then((proxyServer) {
+  setupServer(1, directRequestPaths: ["/4"]).then((server) {
+  setupServer(1, directRequestPaths: ["/4"], secure: true).then((secureServer) {
+    HttpClient client = new HttpClient(context: clientContext);
+
+    List<String> proxy = ["PROXY [::1]:${proxyServer.port}"];
+    client.findProxy = (Uri uri) {
+      // Pick the proxy configuration based on the request path.
+      int index = int.parse(uri.path.substring(1));
+      return proxy[index];
+    };
+
+    for (int i = 0; i < proxy.length; i++) {
+      test(bool secure) {
+        String url = secure
+            ? "https://localhost:${secureServer.port}/$i"
+            : "http://localhost:${server.port}/$i";
+
+        client.postUrl(Uri.parse(url))
+          .then((HttpClientRequest clientRequest) {
+            String content = "$i$i$i";
+            clientRequest.write(content);
+            return clientRequest.close();
+          })
+          .then((HttpClientResponse response) {
+            response.listen((_) {}, onDone: () {
+              testProxyIPV6DoneCount++;
+              if (testProxyIPV6DoneCount == proxy.length * 2) {
+                Expect.equals(proxy.length, server.requestCount);
+                Expect.equals(proxy.length, secureServer.requestCount);
+                proxyServer.shutdown();
+                server.shutdown();
+                secureServer.shutdown();
+                client.close();
+              }
+            });
+          });
+      }
+
+      test(false);
+      test(true);
+    }
+  });
+  });
+  });
+}
+
+
+int testProxyFromEnviromentDoneCount = 0;
+void testProxyFromEnviroment() {
+  setupProxyServer().then((proxyServer) {
+  setupServer(1).then((server) {
+  setupServer(1, secure: true).then((secureServer) {
+    HttpClient client = new HttpClient(context: clientContext);
+
+    client.findProxy = (Uri uri) {
+      return HttpClient.findProxyFromEnvironment(
+          uri,
+          environment: {"http_proxy": "localhost:${proxyServer.port}",
+                        "https_proxy": "localhost:${proxyServer.port}"});
+    };
+
+    const int loopCount = 5;
+    for (int i = 0; i < loopCount; i++) {
+      test(bool secure) {
+        String url = secure
+            ? "https://localhost:${secureServer.port}/$i"
+            : "http://localhost:${server.port}/$i";
+
+        client.postUrl(Uri.parse(url))
+          .then((HttpClientRequest clientRequest) {
+            String content = "$i$i$i";
+            clientRequest.write(content);
+            return clientRequest.close();
+          })
+          .then((HttpClientResponse response) {
+            response.listen((_) {}, onDone: () {
+              testProxyFromEnviromentDoneCount++;
+              if (testProxyFromEnviromentDoneCount == loopCount * 2) {
+                Expect.equals(loopCount, server.requestCount);
+                Expect.equals(loopCount, secureServer.requestCount);
+                proxyServer.shutdown();
+                server.shutdown();
+                secureServer.shutdown();
+                client.close();
+              }
+            });
+          });
+      }
+
+      test(false);
+      test(true);
+    }
+  });
+  });
+  });
+}
+
+
+int testProxyAuthenticateCount = 0;
+Future testProxyAuthenticate(bool useDigestAuthentication) {
+  testProxyAuthenticateCount = 0;
+  var completer = new Completer();
+
+  setupProxyServer().then((proxyServer) {
+  setupServer(1).then((server) {
+  setupServer(1, secure: true).then((secureServer) {
+    HttpClient client = new HttpClient(context: clientContext);
+
+    Completer step1 = new Completer();
+    Completer step2 = new Completer();
+
+    if (useDigestAuthentication) {
+      proxyServer.useDigestAuthentication("dart", "password");
+    } else {
+      proxyServer.useBasicAuthentication("dart", "password");
+    }
+
+    // Test with no authentication.
+    client.findProxy = (Uri uri) {
+      return "PROXY localhost:${proxyServer.port}";
+    };
+
+    const int loopCount = 2;
+    for (int i = 0; i < loopCount; i++) {
+      test(bool secure) {
+        String url = secure
+            ? "https://localhost:${secureServer.port}/$i"
+            : "http://localhost:${server.port}/$i";
+
+        client.postUrl(Uri.parse(url))
+          .then((HttpClientRequest clientRequest) {
+            String content = "$i$i$i";
+            clientRequest.write(content);
+            return clientRequest.close();
+          })
+          .then((HttpClientResponse response) {
+            Expect.fail("No response expected");
+          }).
+          catchError((e) {
+            testProxyAuthenticateCount++;
+            if (testProxyAuthenticateCount == loopCount * 2) {
+              Expect.equals(0, server.requestCount);
+              Expect.equals(0, secureServer.requestCount);
+              step1.complete(null);
+            }
+        });
+      }
+
+      test(false);
+      test(true);
+    }
+    step1.future.then((_) {
+      testProxyAuthenticateCount = 0;
+      if (useDigestAuthentication) {
+        client.findProxy = (Uri uri) => "PROXY localhost:${proxyServer.port}";
+        client.addProxyCredentials(
+            "localhost",
+            proxyServer.port,
+            "test",
+            new HttpClientDigestCredentials("dart", "password"));
+      } else {
+        client.findProxy = (Uri uri) {
+          return "PROXY dart:password@localhost:${proxyServer.port}";
+        };
+      }
+
+      for (int i = 0; i < loopCount; i++) {
+        test(bool secure) {
+          var path = useDigestAuthentication ? "A" : "$i";
+          String url = secure
+              ? "https://localhost:${secureServer.port}/$path"
+              : "http://localhost:${server.port}/$path";
+
+          client.postUrl(Uri.parse(url))
+            .then((HttpClientRequest clientRequest) {
+              String content = "$i$i$i";
+              clientRequest.write(content);
+              return clientRequest.close();
+            })
+            .then((HttpClientResponse response) {
+              response.listen((_) {}, onDone: () {
+                testProxyAuthenticateCount++;
+                Expect.equals(HttpStatus.OK, response.statusCode);
+                if (testProxyAuthenticateCount == loopCount * 2) {
+                  Expect.equals(loopCount, server.requestCount);
+                  Expect.equals(loopCount, secureServer.requestCount);
+                  step2.complete(null);
+                }
+              });
+            });
+        }
+
+        test(false);
+        test(true);
+      }
+    });
+
+    step2.future.then((_) {
+      testProxyAuthenticateCount = 0;
+      client.findProxy = (Uri uri) {
+        return "PROXY localhost:${proxyServer.port}";
+      };
+
+      client.authenticateProxy = (host, port, scheme, realm) {
+        client.addProxyCredentials(
+            "localhost",
+            proxyServer.port,
+            "realm",
+            new HttpClientBasicCredentials("dart", "password"));
+        return new Future.value(true);
+      };
+
+      for (int i = 0; i < loopCount; i++) {
+        test(bool secure) {
+          String url = secure
+              ? "https://localhost:${secureServer.port}/A"
+              : "http://localhost:${server.port}/A";
+
+          client.postUrl(Uri.parse(url))
+            .then((HttpClientRequest clientRequest) {
+              String content = "$i$i$i";
+              clientRequest.write(content);
+              return clientRequest.close();
+            })
+            .then((HttpClientResponse response) {
+              response.listen((_) {}, onDone: () {
+                testProxyAuthenticateCount++;
+                Expect.equals(HttpStatus.OK, response.statusCode);
+                if (testProxyAuthenticateCount == loopCount * 2) {
+                  Expect.equals(loopCount * 2, server.requestCount);
+                  Expect.equals(loopCount * 2, secureServer.requestCount);
+                  proxyServer.shutdown();
+                  server.shutdown();
+                  secureServer.shutdown();
+                  client.close();
+                  completer.complete(null);
+                }
+              });
+            });
+        }
+        test(false);
+        test(true);
+      }
+    });
+
+  });
+  });
+  });
+
+  return completer.future;
+}
+
+int testRealProxyDoneCount = 0;
+void testRealProxy() {
+  setupServer(1).then((server) {
+    HttpClient client = new HttpClient(context: clientContext);
+     client.addProxyCredentials(
+         "localhost",
+         8080,
+         "test",
+         new HttpClientBasicCredentials("dart", "password"));
+
+    List<String> proxy =
+        ["PROXY localhost:8080",
+         "PROXY localhost:8080; PROXY hede.hule.hest:8080",
+         "PROXY hede.hule.hest:8080; PROXY localhost:8080",
+         "PROXY localhost:8080; DIRECT"];
+
+    client.findProxy = (Uri uri) {
+      // Pick the proxy configuration based on the request path.
+      int index = int.parse(uri.path.substring(1));
+      return proxy[index];
+    };
+
+    for (int i = 0; i < proxy.length; i++) {
+      client.getUrl(Uri.parse("http://localhost:${server.port}/$i"))
+        .then((HttpClientRequest clientRequest) {
+          String content = "$i$i$i";
+          clientRequest.contentLength = content.length;
+          clientRequest.write(content);
+          return clientRequest.close();
+        })
+        .then((HttpClientResponse response) {
+          response.listen((_) {}, onDone: () {
+            if (++testRealProxyDoneCount == proxy.length) {
+              Expect.equals(proxy.length, server.requestCount);
+              server.shutdown();
+              client.close();
+            }
+          });
+        });
+    }
+  });
+}
+
+int testRealProxyAuthDoneCount = 0;
+void testRealProxyAuth() {
+  setupServer(1).then((server) {
+    HttpClient client = new HttpClient(context: clientContext);
+
+    List<String> proxy =
+        ["PROXY dart:password@localhost:8080",
+         "PROXY dart:password@localhost:8080; PROXY hede.hule.hest:8080",
+         "PROXY hede.hule.hest:8080; PROXY dart:password@localhost:8080",
+         "PROXY dart:password@localhost:8080; DIRECT"];
+
+    client.findProxy = (Uri uri) {
+      // Pick the proxy configuration based on the request path.
+      int index = int.parse(uri.path.substring(1));
+      return proxy[index];
+    };
+
+    for (int i = 0; i < proxy.length; i++) {
+      client.getUrl(Uri.parse("http://localhost:${server.port}/$i"))
+        .then((HttpClientRequest clientRequest) {
+          String content = "$i$i$i";
+          clientRequest.contentLength = content.length;
+          clientRequest.write(content);
+          return clientRequest.close();
+        })
+        .then((HttpClientResponse response) {
+          response.listen((_) {}, onDone: () {
+            if (++testRealProxyAuthDoneCount == proxy.length) {
+              Expect.equals(proxy.length, server.requestCount);
+              server.shutdown();
+              client.close();
+            }
+          });
+        });
+    }
+  });
+}
+
+main() {
+  testProxyIPV6();
+  testProxyFromEnviroment();
+  // The two invocations use the same global variable for state -
+  // run one after the other.
+  testProxyAuthenticate(false)
+      .then((_) => testProxyAuthenticate(true));
+
+  // This test is not normally run. It can be used for locally testing
+  // with a real proxy server (e.g. Apache).
+  // testRealProxy();
+  // testRealProxyAuth();
+}
diff --git a/tests/standalone/io/http_proxy_test.dart b/tests/standalone/io/http_proxy_test.dart
index 9b8803b..e5607e9 100644
--- a/tests/standalone/io/http_proxy_test.dart
+++ b/tests/standalone/io/http_proxy_test.dart
@@ -285,7 +285,7 @@
 }
 
 testInvalidProxy() {
-  HttpClient client = new HttpClient();
+  HttpClient client = new HttpClient(context: clientContext);
 
   client.findProxy = (Uri uri) => "";
   client.getUrl(Uri.parse("http://www.google.com/test"))
@@ -307,7 +307,7 @@
 int testDirectDoneCount = 0;
 void testDirectProxy() {
   setupServer(0).then((server) {
-    HttpClient client = new HttpClient();
+    HttpClient client = new HttpClient(context: clientContext);
     List<String> proxy =
         ["DIRECT", " DIRECT ", "DIRECT ;", " DIRECT ; ",
          ";DIRECT", " ; DIRECT ", ";;DIRECT;;"];
@@ -407,54 +407,6 @@
   });
 }
 
-int testProxyIPV6DoneCount = 0;
-void testProxyIPV6() {
-  setupProxyServer(ipV6: true).then((proxyServer) {
-  setupServer(1, directRequestPaths: ["/4"]).then((server) {
-  setupServer(1, directRequestPaths: ["/4"], secure: true).then((secureServer) {
-    HttpClient client = new HttpClient();
-
-    List<String> proxy = ["PROXY [::1]:${proxyServer.port}"];
-    client.findProxy = (Uri uri) {
-      // Pick the proxy configuration based on the request path.
-      int index = int.parse(uri.path.substring(1));
-      return proxy[index];
-    };
-
-    for (int i = 0; i < proxy.length; i++) {
-      test(bool secure) {
-        String url = secure
-            ? "https://localhost:${secureServer.port}/$i"
-            : "http://localhost:${server.port}/$i";
-
-        client.postUrl(Uri.parse(url))
-          .then((HttpClientRequest clientRequest) {
-            String content = "$i$i$i";
-            clientRequest.write(content);
-            return clientRequest.close();
-          })
-          .then((HttpClientResponse response) {
-            response.listen((_) {}, onDone: () {
-              testProxyIPV6DoneCount++;
-              if (testProxyIPV6DoneCount == proxy.length * 2) {
-                Expect.equals(proxy.length, server.requestCount);
-                Expect.equals(proxy.length, secureServer.requestCount);
-                proxyServer.shutdown();
-                server.shutdown();
-                secureServer.shutdown();
-                client.close();
-              }
-            });
-          });
-      }
-
-      test(false);
-      test(true);
-    }
-  });
-  });
-  });
-}
 
 int testProxyChainDoneCount = 0;
 void testProxyChain() {
@@ -464,7 +416,7 @@
   proxyServer1.client.findProxy = (_) => "PROXY localhost:${proxyServer2.port}";
 
   setupServer(2, directRequestPaths: ["/4"]).then((server) {
-    HttpClient client = new HttpClient();
+    HttpClient client = new HttpClient(context: clientContext);
 
     List<String> proxy;
     if (Platform.operatingSystem == "windows") {
@@ -518,308 +470,9 @@
   });
 }
 
-int testProxyFromEnviromentDoneCount = 0;
-void testProxyFromEnviroment() {
-  setupProxyServer().then((proxyServer) {
-  setupServer(1).then((server) {
-  setupServer(1, secure: true).then((secureServer) {
-    HttpClient client = new HttpClient();
-
-    client.findProxy = (Uri uri) {
-      return HttpClient.findProxyFromEnvironment(
-          uri,
-          environment: {"http_proxy": "localhost:${proxyServer.port}",
-                        "https_proxy": "localhost:${proxyServer.port}"});
-    };
-
-    const int loopCount = 5;
-    for (int i = 0; i < loopCount; i++) {
-      test(bool secure) {
-        String url = secure
-            ? "https://localhost:${secureServer.port}/$i"
-            : "http://localhost:${server.port}/$i";
-
-        client.postUrl(Uri.parse(url))
-          .then((HttpClientRequest clientRequest) {
-            String content = "$i$i$i";
-            clientRequest.write(content);
-            return clientRequest.close();
-          })
-          .then((HttpClientResponse response) {
-            response.listen((_) {}, onDone: () {
-              testProxyFromEnviromentDoneCount++;
-              if (testProxyFromEnviromentDoneCount == loopCount * 2) {
-                Expect.equals(loopCount, server.requestCount);
-                Expect.equals(loopCount, secureServer.requestCount);
-                proxyServer.shutdown();
-                server.shutdown();
-                secureServer.shutdown();
-                client.close();
-              }
-            });
-          });
-      }
-
-      test(false);
-      test(true);
-    }
-  });
-  });
-  });
-}
-
-
-int testProxyAuthenticateCount = 0;
-Future testProxyAuthenticate(bool useDigestAuthentication) {
-  testProxyAuthenticateCount = 0;
-  var completer = new Completer();
-
-  setupProxyServer().then((proxyServer) {
-  setupServer(1).then((server) {
-  setupServer(1, secure: true).then((secureServer) {
-    HttpClient client = new HttpClient();
-
-    Completer step1 = new Completer();
-    Completer step2 = new Completer();
-
-    if (useDigestAuthentication) {
-      proxyServer.useDigestAuthentication("dart", "password");
-    } else {
-      proxyServer.useBasicAuthentication("dart", "password");
-    }
-
-    // Test with no authentication.
-    client.findProxy = (Uri uri) {
-      return "PROXY localhost:${proxyServer.port}";
-    };
-
-    const int loopCount = 2;
-    for (int i = 0; i < loopCount; i++) {
-      test(bool secure) {
-        String url = secure
-            ? "https://localhost:${secureServer.port}/$i"
-            : "http://localhost:${server.port}/$i";
-
-        client.postUrl(Uri.parse(url))
-          .then((HttpClientRequest clientRequest) {
-            String content = "$i$i$i";
-            clientRequest.write(content);
-            return clientRequest.close();
-          })
-          .then((HttpClientResponse response) {
-            Expect.fail("No response expected");
-          }).
-          catchError((e) {
-            testProxyAuthenticateCount++;
-            if (testProxyAuthenticateCount == loopCount * 2) {
-              Expect.equals(0, server.requestCount);
-              Expect.equals(0, secureServer.requestCount);
-              step1.complete(null);
-            }
-        });
-      }
-
-      test(false);
-      test(true);
-    }
-    step1.future.then((_) {
-      testProxyAuthenticateCount = 0;
-      if (useDigestAuthentication) {
-        client.findProxy = (Uri uri) => "PROXY localhost:${proxyServer.port}";
-        client.addProxyCredentials(
-            "localhost",
-            proxyServer.port,
-            "test",
-            new HttpClientDigestCredentials("dart", "password"));
-      } else {
-        client.findProxy = (Uri uri) {
-          return "PROXY dart:password@localhost:${proxyServer.port}";
-        };
-      }
-
-      for (int i = 0; i < loopCount; i++) {
-        test(bool secure) {
-          var path = useDigestAuthentication ? "A" : "$i";
-          String url = secure
-              ? "https://localhost:${secureServer.port}/$path"
-              : "http://localhost:${server.port}/$path";
-
-          client.postUrl(Uri.parse(url))
-            .then((HttpClientRequest clientRequest) {
-              String content = "$i$i$i";
-              clientRequest.write(content);
-              return clientRequest.close();
-            })
-            .then((HttpClientResponse response) {
-              response.listen((_) {}, onDone: () {
-                testProxyAuthenticateCount++;
-                Expect.equals(HttpStatus.OK, response.statusCode);
-                if (testProxyAuthenticateCount == loopCount * 2) {
-                  Expect.equals(loopCount, server.requestCount);
-                  Expect.equals(loopCount, secureServer.requestCount);
-                  step2.complete(null);
-                }
-              });
-            });
-        }
-
-        test(false);
-        test(true);
-      }
-    });
-
-    step2.future.then((_) {
-      testProxyAuthenticateCount = 0;
-      client.findProxy = (Uri uri) {
-        return "PROXY localhost:${proxyServer.port}";
-      };
-
-      client.authenticateProxy = (host, port, scheme, realm) {
-        client.addProxyCredentials(
-            "localhost",
-            proxyServer.port,
-            "realm",
-            new HttpClientBasicCredentials("dart", "password"));
-        return new Future.value(true);
-      };
-
-      for (int i = 0; i < loopCount; i++) {
-        test(bool secure) {
-          String url = secure
-              ? "https://localhost:${secureServer.port}/A"
-              : "http://localhost:${server.port}/A";
-
-          client.postUrl(Uri.parse(url))
-            .then((HttpClientRequest clientRequest) {
-              String content = "$i$i$i";
-              clientRequest.write(content);
-              return clientRequest.close();
-            })
-            .then((HttpClientResponse response) {
-              response.listen((_) {}, onDone: () {
-                testProxyAuthenticateCount++;
-                Expect.equals(HttpStatus.OK, response.statusCode);
-                if (testProxyAuthenticateCount == loopCount * 2) {
-                  Expect.equals(loopCount * 2, server.requestCount);
-                  Expect.equals(loopCount * 2, secureServer.requestCount);
-                  proxyServer.shutdown();
-                  server.shutdown();
-                  secureServer.shutdown();
-                  client.close();
-                  completer.complete(null);
-                }
-              });
-            });
-        }
-        test(false);
-        test(true);
-      }
-    });
-
-  });
-  });
-  });
-
-  return completer.future;
-}
-
-int testRealProxyDoneCount = 0;
-void testRealProxy() {
-  setupServer(1).then((server) {
-    HttpClient client = new HttpClient();
-     client.addProxyCredentials(
-         "localhost",
-         8080,
-         "test",
-         new HttpClientBasicCredentials("dart", "password"));
-
-    List<String> proxy =
-        ["PROXY localhost:8080",
-         "PROXY localhost:8080; PROXY hede.hule.hest:8080",
-         "PROXY hede.hule.hest:8080; PROXY localhost:8080",
-         "PROXY localhost:8080; DIRECT"];
-
-    client.findProxy = (Uri uri) {
-      // Pick the proxy configuration based on the request path.
-      int index = int.parse(uri.path.substring(1));
-      return proxy[index];
-    };
-
-    for (int i = 0; i < proxy.length; i++) {
-      client.getUrl(Uri.parse("http://localhost:${server.port}/$i"))
-        .then((HttpClientRequest clientRequest) {
-          String content = "$i$i$i";
-          clientRequest.contentLength = content.length;
-          clientRequest.write(content);
-          return clientRequest.close();
-        })
-        .then((HttpClientResponse response) {
-          response.listen((_) {}, onDone: () {
-            if (++testRealProxyDoneCount == proxy.length) {
-              Expect.equals(proxy.length, server.requestCount);
-              server.shutdown();
-              client.close();
-            }
-          });
-        });
-    }
-  });
-}
-
-int testRealProxyAuthDoneCount = 0;
-void testRealProxyAuth() {
-  setupServer(1).then((server) {
-    HttpClient client = new HttpClient();
-
-    List<String> proxy =
-        ["PROXY dart:password@localhost:8080",
-         "PROXY dart:password@localhost:8080; PROXY hede.hule.hest:8080",
-         "PROXY hede.hule.hest:8080; PROXY dart:password@localhost:8080",
-         "PROXY dart:password@localhost:8080; DIRECT"];
-
-    client.findProxy = (Uri uri) {
-      // Pick the proxy configuration based on the request path.
-      int index = int.parse(uri.path.substring(1));
-      return proxy[index];
-    };
-
-    for (int i = 0; i < proxy.length; i++) {
-      client.getUrl(Uri.parse("http://localhost:${server.port}/$i"))
-        .then((HttpClientRequest clientRequest) {
-          String content = "$i$i$i";
-          clientRequest.contentLength = content.length;
-          clientRequest.write(content);
-          return clientRequest.close();
-        })
-        .then((HttpClientResponse response) {
-          response.listen((_) {}, onDone: () {
-            if (++testRealProxyAuthDoneCount == proxy.length) {
-              Expect.equals(proxy.length, server.requestCount);
-              server.shutdown();
-              client.close();
-            }
-          });
-        });
-    }
-  });
-}
-
 main() {
   testInvalidProxy();
   testDirectProxy();
   testProxy();
-  // testProxyIPV6();  // TODO(24074): Move failing tests to separate files.
   testProxyChain();
-  // TODO(24074): Move failing tests to separate files.
-  // testProxyFromEnviroment();
-  // The two invocations of uses the same global variable for state -
-  // run one after the other.
-  // TODO(24074): Move failing tests to separate files.
-  // testProxyAuthenticate(false)
-  //    .then((_) => testProxyAuthenticate(true));
-
-  // This test is not normally run. It can be used for locally testing
-  // with a real proxy server (e.g. Apache).
-  // testRealProxy();
-  // testRealProxyAuth();
 }
diff --git a/tests/standalone/io/raw_datagram_socket_test.dart b/tests/standalone/io/raw_datagram_socket_test.dart
index 9b952d6..20d841e 100644
--- a/tests/standalone/io/raw_datagram_socket_test.dart
+++ b/tests/standalone/io/raw_datagram_socket_test.dart
@@ -127,7 +127,8 @@
             asyncEnd();
           }
         }
-        broadcastTimer = new Timer.periodic(new Duration(milliseconds: 10), send);
+        broadcastTimer =
+            new Timer.periodic(new Duration(milliseconds: 10), send);
       });
   }
 
@@ -194,7 +195,7 @@
   }
 }
 
-testSendReceive(InternetAddress bindAddress) {
+testSendReceive(InternetAddress bindAddress, int dataSize) {
   asyncStart();
 
   var total = 1000;
@@ -218,7 +219,7 @@
       }
 
       Uint8List createDataPackage(int seq) {
-        var data = new Uint8List(1000);
+        var data = new Uint8List(dataSize);
         (new ByteData.view(data.buffer, 0, 4)).setUint32(0, seq);
         return data;
       }
@@ -236,7 +237,7 @@
         // Send a datagram acknowledging the received sequence.
         int bytes = sender.send(
             createDataPackage(seq), bindAddress, receiver.port);
-        Expect.isTrue(bytes == 0 || bytes == 1000);
+        Expect.isTrue(bytes == 0 || bytes == dataSize);
       }
 
       void sendAck(address, port) {
@@ -287,6 +288,7 @@
             var datagram = receiver.receive();
             if (datagram != null) {
               Expect.equals(datagram.port, sender.port);
+              Expect.equals(dataSize, datagram.data.length);
               if (!bindAddress.isMulticast) {
                 Expect.equals(receiver.address, datagram.address);
               }
@@ -318,6 +320,12 @@
   }
   testBroadcast();
   testLoopbackMulticast();
-  testSendReceive(InternetAddress.LOOPBACK_IP_V4);
-  testSendReceive(InternetAddress.LOOPBACK_IP_V6);
+  testSendReceive(InternetAddress.LOOPBACK_IP_V4, 1000);
+  testSendReceive(InternetAddress.LOOPBACK_IP_V6, 1000);
+  if (!Platform.isMacOS) {
+    testSendReceive(InternetAddress.LOOPBACK_IP_V4, 32 * 1024);
+    testSendReceive(InternetAddress.LOOPBACK_IP_V6, 32 * 1024);
+    testSendReceive(InternetAddress.LOOPBACK_IP_V4, 64 * 1024 - 32);
+    testSendReceive(InternetAddress.LOOPBACK_IP_V6, 64 * 1024 - 32);
+  }
 }
diff --git a/tests/standalone/io/security_context_argument_test.dart b/tests/standalone/io/security_context_argument_test.dart
new file mode 100644
index 0000000..5e263f6
--- /dev/null
+++ b/tests/standalone/io/security_context_argument_test.dart
@@ -0,0 +1,41 @@
+// 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";
+import "dart:io";
+
+String localFile(path) => Platform.script.resolve(path).toFilePath();
+
+bool printException(e) { print(e); return true; }
+bool argumentError(e) => e is ArgumentError;
+bool argumentOrTypeError(e) => e is ArgumentError || e is TypeError;
+bool tlsException(e) => e is TlsException;
+
+void testUsePrivateKeyArguments() {
+    var c = new SecurityContext();
+    c.useCertificateChain(localFile('certificates/server_chain.pem'));
+    Expect.throws(() => c.usePrivateKey(
+          localFile('certificates/server_key.pem'), password: "dart" * 1000),
+        argumentError);
+    Expect.throws(() => c.usePrivateKey(
+          localFile('certificates/server_key.pem')),
+        tlsException);
+    Expect.throws(() => c.usePrivateKey(
+          localFile('certificates/server_key.pem'), password: "iHackSites"),
+        tlsException);
+    Expect.throws(() => c.usePrivateKey(
+          localFile('certificates/server_key_oops.pem'), password: "dartdart"),
+        tlsException);
+    Expect.throws(() => c.usePrivateKey(1), argumentOrTypeError);
+    Expect.throws(() => c.usePrivateKey(null), argumentError);
+    Expect.throws(() => c.usePrivateKey(
+          localFile('certificates/server_key_oops.pem'), password: 3),
+        argumentOrTypeError);
+    c.usePrivateKey(
+        localFile('certificates/server_key.pem'), password: "dartdart");
+}    
+
+void main() {
+  testUsePrivateKeyArguments();
+}
diff --git a/tests/standalone/io/server_socket_reference_issue21383_and_issue21384_test.dart b/tests/standalone/io/server_socket_reference_issue21383_and_issue21384_test.dart
deleted file mode 100644
index 95e0363..0000000
--- a/tests/standalone/io/server_socket_reference_issue21383_and_issue21384_test.dart
+++ /dev/null
@@ -1,73 +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:io';
-
-import 'package:async_helper/async_helper.dart';
-
-
-testBothListen() {
-  asyncStart();
-  ServerSocket.bind('127.0.0.1', 0).then((mainServer) {
-    mainServer.reference.create().then((refServer) {
-      refServer.listen((_) {});
-      mainServer.listen((_) {});
-      Timer.run(() {
-        mainServer.close();
-        refServer.close();
-        asyncEnd();
-      });
-    });
-  });
-}
-
-testRefServerListen() {
-  asyncStart();
-  ServerSocket.bind('127.0.0.1', 0).then((mainServer) {
-    mainServer.reference.create().then((refServer) {
-      refServer.listen((_) {});
-      Timer.run(() {
-        mainServer.close();
-        refServer.close();
-        asyncEnd();
-      });
-    });
-  });
-}
-
-testMainServerListen() {
-  asyncStart();
-  ServerSocket.bind('127.0.0.1', 0).then((mainServer) {
-    mainServer.reference.create().then((refServer) {
-      mainServer.listen((_) {});
-      Timer.run(() {
-        mainServer.close();
-        refServer.close();
-        asyncEnd();
-      });
-    });
-  });
-}
-
-testNoneListen() {
-  asyncStart();
-  ServerSocket.bind('127.0.0.1', 0).then((mainServer) {
-    mainServer.reference.create().then((refServer) {
-      Timer.run(() {
-        mainServer.close();
-        refServer.close();
-        asyncEnd();
-      });
-    });
-  });
-}
-
-main() {
-  testNoneListen();
-  testMainServerListen();
-  testRefServerListen();
-  testBothListen();
-}
-
diff --git a/tests/standalone/io/socket_bind_test.dart b/tests/standalone/io/socket_bind_test.dart
index 9d36c22..9c4e1ed 100644
--- a/tests/standalone/io/socket_bind_test.dart
+++ b/tests/standalone/io/socket_bind_test.dart
@@ -82,69 +82,6 @@
   });
 }
 
-testSocketReferenceInteroperability(String host) {
-  asyncStart();
-    ServerSocket.bind(host, 0).then((ServerSocket socket) {
-      Expect.isTrue(socket.port > 0);
-
-      asyncStart();
-      socket.reference.create().then((socket2) {
-        bool gotResponseFrom1;
-        bool gotResponseFrom2;
-
-        Expect.isTrue(socket.port > 0);
-        Expect.equals(socket.port, socket2.port);
-
-        asyncStart();
-        asyncStart();
-        asyncStart();
-        socket.listen((client) {
-          client.drain().whenComplete(asyncEnd);
-          client.write('1: hello world');
-          client.close().whenComplete(asyncEnd);
-          // NOTE: Closing the socket un-subscribes as well, which means the
-          // other client connection must go to the other socket.
-          socket.close().whenComplete(asyncEnd);
-        }, onDone: asyncEnd);
-
-        asyncStart();
-        asyncStart();
-        asyncStart();
-        socket2.listen((client) {
-          client.drain().whenComplete(asyncEnd);
-          client.write('2: hello world');
-          client.close().whenComplete(asyncEnd);
-          // NOTE: Closing the socket un-subscribes as well, which means the
-          // other client connection must go to the other socket.
-          socket2.close().whenComplete(asyncEnd);
-        }, onDone: asyncEnd);
-
-        var futures = [];
-        for (int i = 0; i < 2; i++) {
-          asyncStart();
-          futures.add(
-              Socket.connect(socket.address, socket.port).then((Socket socket) {
-            socket.close().whenComplete(asyncEnd);
-            asyncStart();
-            return socket
-                .transform(ASCII.decoder).join('').then((String result) {
-                if (result == '1: hello world') gotResponseFrom1 = true;
-                else if (result == '2: hello world') gotResponseFrom2 = true;
-                else throw 'Unexpected result from server: $result';
-                asyncEnd();
-             });
-          }));
-        }
-        asyncStart();
-        Future.wait(futures).then((_) {
-          Expect.isTrue(gotResponseFrom1);
-          Expect.isTrue(gotResponseFrom2);
-          asyncEnd();
-        });
-      });
-   });
-}
-
 testListenCloseListenClose(String host) async {
   asyncStart();
 
@@ -184,8 +121,6 @@
     negTestBindV6OnlyMismatch(host, true);
     negTestBindV6OnlyMismatch(host, false);
 
-    testSocketReferenceInteroperability(host);
-
     testListenCloseListenClose(host);
   }
 
diff --git a/tests/standalone/noopt_test.dart b/tests/standalone/noopt_test.dart
new file mode 100644
index 0000000..171f3a5
--- /dev/null
+++ b/tests/standalone/noopt_test.dart
@@ -0,0 +1,9 @@
+// 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=--noopt
+
+main() {
+  print("Hello, --noopt World!");
+}
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index f552859..a1b6c50 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -62,6 +62,7 @@
 out_of_memory_test: Skip
 verbose_gc_to_bmu_test: Skip
 precompilation_test: Skip # Standalone only test.
+noopt_test: Skip # Standalone only test.
 
 [ $compiler == dartanalyzer || $compiler == dart2analyzer ]
 javascript_int_overflow_literal_test/01: Fail, OK
@@ -105,9 +106,11 @@
 unboxed_int_converter_test: Skip
 pair_location_remapping_test: Skip
 precompilation_test: Skip # Standalone only test.
+noopt_test: Skip # Standalone only test.
 
 [ $runtime == vm && $arch == ia32]
 precompilation_test: Skip # Not expected to pass on ia32.
+noopt_test: Skip # Not expected to pass on ia32.
 
 [ $runtime == vm && $arch == arm]
 precompilation_test: Skip # Issue 24427
diff --git a/tests/try/poi/apply_updates_test.dart b/tests/try/poi/apply_updates_test.dart
index 361ee03..e8c8429 100644
--- a/tests/try/poi/apply_updates_test.dart
+++ b/tests/try/poi/apply_updates_test.dart
@@ -40,7 +40,7 @@
   Future run() => loadMainApp().then((LibraryElement library) {
     // Capture the current version of [before] before invoking the [updater].
     PartialFunctionElement before = library.localLookup(expectedUpdate);
-    var beforeNode = before.parseNode(compiler);
+    var beforeNode = before.parseNode(compiler.parsing);
 
     var context = new IncrementalCompilerContext();
     LibraryUpdater updater =
@@ -56,10 +56,10 @@
 
     // Check that the [updater] didn't modify the changed element.
     Expect.identical(before, update.before);
-    Expect.identical(beforeNode, before.parseNode(compiler));
+    Expect.identical(beforeNode, before.parseNode(compiler.parsing));
 
     PartialFunctionElement after = update.after;
-    var afterNode = after.parseNode(compiler);
+    var afterNode = after.parseNode(compiler.parsing);
 
     // Check that pretty-printing the elements match [source] (before), and
     // [newSource] (after).
@@ -72,7 +72,7 @@
 
     // Check that the update was applied by pretty-printing [before]. Make no
     // assumptions about [after], as the update may destroy that element.
-    beforeNode = before.parseNode(compiler);
+    beforeNode = before.parseNode(compiler.parsing);
     Expect.notEquals(source, '$beforeNode');
     Expect.stringEquals(newSource, '$beforeNode');
   });
diff --git a/tools/VERSION b/tools/VERSION
index 774c773..6143c4e 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 1
 MINOR 13
 PATCH 0
-PRERELEASE 5
+PRERELEASE 6
 PRERELEASE_PATCH 0
diff --git a/tools/deps/dartium.deps/DEPS b/tools/deps/dartium.deps/DEPS
index 3c6dd66..0662675 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": "202671",
+  "dartium_webkit_revision": "202673",
 
   # We use mirrors of all github repos to guarantee reproducibility and
   # consistency between what users see and what the bots see.
@@ -36,7 +36,7 @@
   "collection_rev": "@1da9a07f32efa2ba0c391b289e2037391e31da0e",
   "crypto_rev" : "@2df57a1e26dd88e8d0614207d4b062c73209917d",
   "csslib_tag" : "@0.12.0",
-  "dart2js_info_rev" : "@bad01369f1f605ab688d505c135db54de927318f",
+  "dart2js_info_rev" : "@ffd03ee45f7459efd3039ff565b4d0aa2e7cd9e7",
   "glob_rev": "@704cf75e4f26b417505c5c611bdaacd8808467dd",
   "html_tag" : "@0.12.1+1",
   "http_rev" : "@9b93e1542c753090c50b46ef1592d44bc858bfe7",
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index fe4e03e..6f31a7d 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -515,7 +515,7 @@
     return ', '.join(map(param_name, self.param_infos[:parameter_count]))
 
   def isCallback(self, type_registry, type_id):
-    if type_id:
+    if type_id and not type_id.endswith('[]'):
       callback_type = type_registry._database._all_interfaces[type_id]
       return callback_type.operations[0].id == 'handleEvent' if len(callback_type.operations) > 0 else False
     else:
@@ -1446,7 +1446,8 @@
             return_type == 'Future' or
             return_type == 'SqlDatabase' or # renamed to Database
             return_type == 'HTMLElement' or
-            return_type == 'MutationObserver')
+            return_type == 'MutationObserver' or
+            return_type.endswith('[]'))
 
 def wrap_type_blink(return_type, type_registry):
     """Returns True if the type is a blink type that requires wrap_jso but
diff --git a/tools/dom/src/dartium_CustomElementSupport.dart b/tools/dom/src/dartium_CustomElementSupport.dart
index a14e07f..d80f2c4 100644
--- a/tools/dom/src/dartium_CustomElementSupport.dart
+++ b/tools/dom/src/dartium_CustomElementSupport.dart
@@ -26,11 +26,12 @@
     }
   }
 
-  Element upgrade(Element element) {
-    if (element.runtimeType != _nativeType) {
+  Element upgrade(element) {
+    if (element.runtimeType != js.JsObjectImpl) {
       throw new UnsupportedError('Element is incorrect type');
     }
-    return _Utils.changeElementWrapper(element, _type);
+
+    return createCustomUpgrader(_nativeType, element);
   }
 }
 
diff --git a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
index 952f556..30400a1 100644
--- a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
@@ -149,3 +149,8 @@
   // TODO(17738): Implement this.
   throw new UnimplementedError();
 }
+
+/// Dartium functions that are a NOOP in dart2js.
+unwrap_jso(dartClass_instance) => dartClass_instance;
+wrap_jso(jsObject) => jsObject;
+createCustomUpgrader(Type customElementClass, $this) => $this;
diff --git a/tools/dom/templates/html/dartium/html_dartium.darttemplate b/tools/dom/templates/html/dartium/html_dartium.darttemplate
index b15dab2..25336a7 100644
--- a/tools/dom/templates/html/dartium/html_dartium.darttemplate
+++ b/tools/dom/templates/html/dartium/html_dartium.darttemplate
@@ -351,6 +351,9 @@
  **********                                                          **********
  ******************************************************************************/
 
+// List of known tagName to DartClass for custom elements, used for upgrade.
+var _knownCustomeElements = new Map<String, Type>();
+
 Rectangle make_dart_rectangle(r) =>
     r == null ? null : new Rectangle(r['left'], r['top'], r['width'], r['height']);
 
@@ -370,19 +373,7 @@
 /**
  * Return the JsObject associated with a Dart class [dartClass_instance].
  */
-unwrap_jso(dartClass_instance) {
-  try {
-    if (dartClass_instance != null)
-      return dartClass_instance is NativeFieldWrapperClass2 ?
-          dartClass_instance.blink_jsObject : dartClass_instance;
-    else
-      return null;
-  } catch(NoSuchMethodException) {
-    // No blink_jsObject then return the dartClass_instance is probably an
-    // array that was already converted to a Dart class e.g., Uint8ClampedList.
-    return dartClass_instance;
-  }
-}
+unwrap_jso(dartClass_instance) => js.unwrap_jso(dartClass_instance);
 
 /**
  * Create Dart class that maps to the JS Type, add the JsObject as an expando
@@ -390,10 +381,26 @@
  */
 wrap_jso(jsObject) {
   try {
-    if (jsObject is! js.JsObject) {
+    if (jsObject is! js.JsObject || jsObject == null) {
       // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
+      // or it's a simple type.
       return jsObject;
     }
+
+    // TODO(alanknight): With upgraded custom elements this causes a failure because
+    // we need a new wrapper after the type changes. We could possibly invalidate this
+    // if the constructor name didn't match?
+    var wrapper = js.getDartHtmlWrapperFor(jsObject);
+    if (wrapper != null) {
+      return wrapper;
+    }
+
+    if (jsObject is js.JsArray) {
+      var wrappingList = new _DartHtmlWrappingList(jsObject);
+      js.setDartHtmlWrapperFor(jsObject, wrappingList);
+      return wrappingList;
+    }
+
     // Try the most general type conversions on it.
     // TODO(alanknight): We may be able to do better. This maintains identity,
     // which is useful, but expensive. And if we nest something that only
@@ -416,10 +423,24 @@
       // Got a dart_class (it's a custom element) use it it's already set up.
       dartClass_instance = jsObject['dart_class'];
     } else {
-      var func = getHtmlCreateFunction(jsTypeName);
-      if (func != null) {
-        dartClass_instance = func();
-        dartClass_instance.blink_jsObject = jsObject;
+      var localName = jsObject['localName'];
+      var customElementClass = _knownCustomeElements[localName];
+      // Custom Element to upgrade.
+      if (jsTypeName == 'HTMLElement' && customElementClass != null) {
+        try {
+          dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
+        } finally {
+          dartClass_instance.blink_jsObject = jsObject;
+          jsObject['dart_class'] = dartClass_instance;
+          js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
+       }
+      } else {
+        var func = getHtmlCreateFunction(jsTypeName);
+        if (func != null) {
+          dartClass_instance = func();
+          dartClass_instance.blink_jsObject = jsObject;
+          js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
+        }
       }
     }
     return dartClass_instance;
@@ -538,6 +559,41 @@
 // Conversion function place holder (currently not used in dart2js or dartium).
 List convertDartToNative_StringArray(List<String> input) => input;
 
+/**
+ * Wraps a JsArray and will call wrap_jso on its entries.
+ */
+class _DartHtmlWrappingList extends ListBase {
+  _DartHtmlWrappingList(this._basicList);
+
+  final js.JsArray _basicList;
+
+  operator [](int index) => wrap_jso(_basicList[index]);
+
+  operator []=(int index, value) => _basicList[index] = unwrap_jso(value);
+
+  int get length => _basicList.length;
+  int set length(int newLength) => _basicList.length = newLength;
+}
+
+/**
+ * Upgrade the JS HTMLElement to the Dart class.  Used by Dart's Polymer.
+ */
+createCustomUpgrader(Type customElementClass, $this) {
+  var dartClass;
+  try {
+    dartClass = _blink.Blink_Utils.constructElement(customElementClass, $this);
+  } catch (e) {
+    throw e;
+  } finally {
+    // Need to remember the Dart class that was created for this custom so
+    // return it and setup the blink_jsObject to the $this that we'll be working
+    // with as we talk to blink. 
+    $this['dart_class'] = dartClass;
+  }
+
+  return dartClass;
+}
+
 $else
 class JsoNativeFieldWrapper extends NativeFieldWrapperClass2 {}
 
@@ -547,5 +603,6 @@
 convertDartToNative_Dictionary(Map dict) => dict;
 List convertDartToNative_StringArray(List<String> input) => input;
 convertDartToNative_List(List input) => input;
+createCustomUpgrader(Type customElementClass, $this) => $this;
 
 $endif
diff --git a/tools/dom/templates/html/impl/impl_Document.darttemplate b/tools/dom/templates/html/impl/impl_Document.darttemplate
index fb6d6b18..99b2dc0 100644
--- a/tools/dom/templates/html/impl/impl_Document.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Document.darttemplate
@@ -83,6 +83,8 @@
       wrapped = wrap_jso(newElement);
       if (wrapped == null) {
         wrapped = wrap_jso_custom_element(newElement);
+      } else {
+        wrapped.blink_jsObject['dart_class'] = wrapped;
       }
     }
 
@@ -126,6 +128,8 @@
       wrapped = wrap_jso(newElement);
       if (wrapped == null) {
         wrapped = wrap_jso_custom_element(newElement);
+      } else {
+        wrapped.blink_jsObject['dart_class'] = wrapped;
       }
     }
 
diff --git a/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate b/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
index 0a0ff4c..6bc60a1 100644
--- a/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
@@ -377,6 +377,9 @@
       }
       var elemProto = js.context['Object'].callMethod("create", [baseElement['prototype']]);
 
+      // Remember for any upgrading done in wrap_jso.
+      _knownCustomeElements[tag] = customElementClass;
+
       // TODO(terry): Hack to stop recursion re-creating custom element when the
       //              created() constructor of the custom element does e.g.,
       //
diff --git a/tools/dom/templates/html/impl/impl_MutationObserver.darttemplate b/tools/dom/templates/html/impl/impl_MutationObserver.darttemplate
index 079ca0f..de07dcb 100644
--- a/tools/dom/templates/html/impl/impl_MutationObserver.darttemplate
+++ b/tools/dom/templates/html/impl/impl_MutationObserver.darttemplate
@@ -22,7 +22,7 @@
   @DocsEditable()
   $if JSINTEROP
   static MutationObserver _create(callback) => wrap_jso(_blink.BlinkMutationObserver.instance.constructorCallback_1_((mutations, observer) {
-    callback(mutations, wrap_jso(observer));
+    callback(wrap_jso(mutations), wrap_jso(observer));
   }));
   $else
   static MutationObserver _create(callback) => _blink.BlinkMutationObserver.instance.constructorCallback_1_(callback);