Version 1.21.0-dev.8.0

Merge dbf8d06eab8140bcc49b2b8eed3b149fb215c3dc into dev
diff --git a/.travis.yml b/.travis.yml
index 2f868f8..f458e35 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -81,8 +81,8 @@
   - TEST=package
 matrix:
   allow_failures:
-    - env: TEST=node
     - env: ANALYZER=master CXX=g++
+    - env: ANALYZER=master DDC_BROWSERS=ChromeCanaryTravis
 notifications:
   email:
     recipients:
diff --git a/DEPS b/DEPS
index bfad3e5..9aef0a8 100644
--- a/DEPS
+++ b/DEPS
@@ -64,7 +64,7 @@
   "glob_tag": "@1.1.3",
   "html_tag" : "@0.13.1",
   "http_multi_server_tag" : "@2.0.2",
-  "http_parser_tag" : "@3.0.2",
+  "http_parser_tag" : "@3.0.3",
   "http_tag" : "@0.11.3+9",
   "http_throttle_rev" : "@284344cd357e435c6c8ff9a4a21f02b9e384a541",
   "idl_parser_rev": "@7fbe68cab90c38147dee4f48c30ad0d496c17915",
diff --git a/pkg/analysis_server/.gitignore b/pkg/analysis_server/.gitignore
new file mode 100644
index 0000000..16a1724
--- /dev/null
+++ b/pkg/analysis_server/.gitignore
@@ -0,0 +1 @@
+.packages
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 9855905..0f5bcc7 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -95,9 +95,6 @@
 
 /* Styles for index */
 
-.subindex {
-}
-
 .subindex ul {
   padding-left: 0;
   margin-left: 0;
@@ -233,11 +230,12 @@
     <ul>
       <li><a href="#domain_server">Server</a></li>
       <li><a href="#domain_analysis">Analysis</a></li>
-      <li><a href="#domain_completion">Code Completion</a></li>
+      <li><a href="#domain_completion">Completion</a></li>
       <li><a href="#domain_search">Search</a></li>
       <li><a href="#domain_edit">Edit</a></li>
       <li><a href="#domain_execution">Execution</a></li>
-    </ul>
+      <li><a href="#domain_diagnostic">Diagnostic</a></li>
+</ul>
     <p>
       The specifications of the API’s refer to data structures beyond
       the standard JSON primitives. These data structures are
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 083874b..47293f7 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -16,7 +16,6 @@
 import 'package:analyzer/plugin/options.dart';
 import 'package:analyzer/plugin/resolver_provider.dart';
 import 'package:analyzer/source/analysis_options_provider.dart';
-import 'package:analyzer/source/config.dart';
 import 'package:analyzer/source/package_map_provider.dart';
 import 'package:analyzer/source/package_map_resolver.dart';
 import 'package:analyzer/source/path_filter.dart';
@@ -477,10 +476,6 @@
    */
   final PubPackageMapProvider _packageMapProvider;
 
-  /// Provider of analysis options.
-  AnalysisOptionsProvider analysisOptionsProvider =
-      new AnalysisOptionsProvider();
-
   /**
    * A list of the globs used to determine which files should be analyzed.
    */
@@ -685,9 +680,19 @@
    * if exists, or in one of the parent folders, or `null` if no analysis
    * options file is found or if the contents of the file are not valid YAML.
    */
-  Map<String, Object> readOptions(Folder folder) {
+  Map<String, Object> readOptions(Folder folder, Packages packages) {
     try {
-      return analysisOptionsProvider.getOptions(folder, crawlUp: true);
+      Map<String, List<Folder>> packageMap =
+          new ContextBuilder(resourceProvider, null, null)
+              .convertPackagesToMap(packages);
+      List<UriResolver> resolvers = <UriResolver>[
+        new ResourceUriResolver(resourceProvider),
+        new PackageMapUriResolver(resourceProvider, packageMap),
+      ];
+      SourceFactory sourceFactory =
+          new SourceFactory(resolvers, packages, resourceProvider);
+      return new AnalysisOptionsProvider(sourceFactory)
+          .getOptions(folder, crawlUp: true);
     } catch (_) {
       // Parse errors are reported by GenerateOptionsErrorsTask.
     }
@@ -916,7 +921,8 @@
     if (AnalysisEngine.isAnalysisOptionsFileName(path, pathContext)) {
       var analysisContext = info.context;
       if (analysisContext is context.AnalysisContextImpl) {
-        Map<String, Object> options = readOptions(info.folder);
+        Map<String, Object> options =
+            readOptions(info.folder, info.disposition.packages);
         processOptionsForContext(info, options,
             optionsRemoved: changeType == ChangeType.REMOVE);
         analysisContext.sourceFactory = _createSourceFactory(
@@ -1069,7 +1075,8 @@
     ContextInfo info = new ContextInfo(this, parent, folder, packagespecFile,
         normalizedPackageRoots[folder.path], disposition);
 
-    Map<String, Object> optionMap = readOptions(info.folder);
+    Map<String, Object> optionMap =
+        readOptions(info.folder, disposition.packages);
     AnalysisOptions options =
         new AnalysisOptionsImpl.from(defaultContextOptions);
     applyToAnalysisOptions(options, optionMap);
@@ -1096,17 +1103,6 @@
         pubspec = child;
       }
     }
-    if (pubspec != null) {
-      File pubSource = resourceProvider.getFile(pubspec.path);
-      if (enableNewAnalysisDriver) {
-        // TODO(scheglov) implement for the new analysis driver
-      } else {
-        setConfiguration(
-            info.context,
-            new AnalysisConfiguration.fromPubspec(
-                pubSource, resourceProvider, disposition.packages));
-      }
-    }
 
     if (enableNewAnalysisDriver) {
       // TODO(scheglov) implement for the new analysis driver
@@ -1264,18 +1260,6 @@
     if (maps.length == 1) {
       embeddedOptions = maps.first;
     }
-
-    AnalysisConfiguration configuration = getConfiguration(info.context);
-    if (configuration != null) {
-      Map configMap = configuration.options;
-      if (configMap != null) {
-        if (embeddedOptions != null) {
-          embeddedOptions = new Merger().merge(embeddedOptions, configMap);
-        } else {
-          embeddedOptions = configMap;
-        }
-      }
-    }
     return embeddedOptions;
   }
 
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index 9621afb..eda11af 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -133,6 +133,10 @@
    * Implement the `analysis.getNavigation` request.
    */
   Response getNavigation(Request request) {
+    if (server.options.enableNewAnalysisDriver) {
+      // TODO(scheglov) implement for the new analysis driver
+      return new Response.getNavigationInvalidFile(request);
+    }
     var params = new AnalysisGetNavigationParams.fromRequest(request);
     String file = params.file;
     Future<AnalysisDoneReason> analysisFuture =
diff --git a/pkg/analysis_server/lib/src/search/search_domain.dart b/pkg/analysis_server/lib/src/search/search_domain.dart
index cdd39a3..b77f2df 100644
--- a/pkg/analysis_server/lib/src/search/search_domain.dart
+++ b/pkg/analysis_server/lib/src/search/search_domain.dart
@@ -49,6 +49,15 @@
         searchEngine = server.searchEngine;
 
   Future findElementReferences(protocol.Request request) async {
+    if (server.options.enableNewAnalysisDriver) {
+      // TODO(scheglov) implement for the new analysis driver
+      String searchId = (_nextSearchId++).toString();
+      var result = new protocol.SearchFindElementReferencesResult();
+      result.id = searchId;
+      _sendSearchResult(request, result);
+      _sendSearchNotification(searchId, true, <protocol.SearchResult>[]);
+      return;
+    }
     var params =
         new protocol.SearchFindElementReferencesParams.fromRequest(request);
     await server.onAnalysisComplete;
@@ -145,6 +154,14 @@
    * Implement the `search.getTypeHierarchy` request.
    */
   Future getTypeHierarchy(protocol.Request request) async {
+    if (server.options.enableNewAnalysisDriver) {
+      // TODO(scheglov) implement for the new analysis driver
+      protocol.Response response =
+          new protocol.SearchGetTypeHierarchyResult(hierarchyItems: [])
+              .toResponse(request.id);
+      server.sendResponse(response);
+      return;
+    }
     var params = new protocol.SearchGetTypeHierarchyParams.fromRequest(request);
     String file = params.file;
     // wait for analysis
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index df6df7b..051ae23 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -389,7 +389,7 @@
     analysisServerOptions.enableIncrementalResolutionValidation =
         results[INCREMENTAL_RESOLUTION_VALIDATION];
     analysisServerOptions.enableNewAnalysisDriver =
-      results[ENABLE_NEW_ANALYSIS_DRIVER];
+        results[ENABLE_NEW_ANALYSIS_DRIVER];
     analysisServerOptions.enablePubSummaryManager =
         results[ENABLE_PUB_SUMMARY_MANAGER];
     analysisServerOptions.finerGrainedInvalidation =
@@ -428,7 +428,8 @@
           .defaultSdkDirectory(PhysicalResourceProvider.INSTANCE)
           .path;
     }
-    bool useSummaries = analysisServerOptions.fileReadMode == 'as-is';
+    bool useSummaries = analysisServerOptions.fileReadMode == 'as-is' ||
+        analysisServerOptions.enableNewAnalysisDriver;
     // TODO(brianwilkerson) It would be nice to avoid creating an SDK that
     // cannot be re-used, but the SDK is needed to create a package map provider
     // in the case where we need to run `pub` in order to get the package map.
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index ce0bf7d..1039788 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -25,7 +25,7 @@
 import 'package:analyzer/src/util/glob.dart';
 import 'package:linter/src/plugin/linter_plugin.dart';
 import 'package:linter/src/rules/avoid_as.dart';
-import 'package:path/path.dart';
+import 'package:path/path.dart' as path;
 import 'package:plugin/manager.dart';
 import 'package:plugin/plugin.dart';
 import 'package:test/test.dart';
@@ -45,11 +45,11 @@
 @reflectiveTest
 class AbstractContextManagerTest extends ContextManagerTest {
   void test_contextsInAnalysisRoot_nestedContext() {
-    String subProjPath = posix.join(projPath, 'subproj');
+    String subProjPath = path.posix.join(projPath, 'subproj');
     Folder subProjFolder = resourceProvider.newFolder(subProjPath);
     resourceProvider.newFile(
-        posix.join(subProjPath, 'pubspec.yaml'), 'contents');
-    String subProjFilePath = posix.join(subProjPath, 'file.dart');
+        path.posix.join(subProjPath, 'pubspec.yaml'), 'contents');
+    String subProjFilePath = path.posix.join(subProjPath, 'file.dart');
     resourceProvider.newFile(subProjFilePath, 'contents');
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
     // Make sure that there really are contexts for both the main project and
@@ -167,16 +167,16 @@
 
   test_ignoreFilesInPackagesFolder() {
     // create a context with a pubspec.yaml file
-    String pubspecPath = posix.join(projPath, 'pubspec.yaml');
+    String pubspecPath = path.posix.join(projPath, 'pubspec.yaml');
     resourceProvider.newFile(pubspecPath, 'pubspec');
     // create a file in the "packages" folder
-    String filePath1 = posix.join(projPath, 'packages', 'file1.dart');
+    String filePath1 = path.posix.join(projPath, 'packages', 'file1.dart');
     resourceProvider.newFile(filePath1, 'contents');
     // "packages" files are ignored initially
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
     expect(callbacks.currentContextFilePaths[projPath], isEmpty);
     // "packages" files are ignored during watch
-    String filePath2 = posix.join(projPath, 'packages', 'file2.dart');
+    String filePath2 = path.posix.join(projPath, 'packages', 'file2.dart');
     resourceProvider.newFile(filePath2, 'contents');
     return pumpEventQueue().then((_) {
       expect(callbacks.currentContextFilePaths[projPath], isEmpty);
@@ -197,11 +197,11 @@
   }
 
   void test_isInAnalysisRoot_inNestedContext() {
-    String subProjPath = posix.join(projPath, 'subproj');
+    String subProjPath = path.posix.join(projPath, 'subproj');
     Folder subProjFolder = resourceProvider.newFolder(subProjPath);
     resourceProvider.newFile(
-        posix.join(subProjPath, 'pubspec.yaml'), 'contents');
-    String subProjFilePath = posix.join(subProjPath, 'file.dart');
+        path.posix.join(subProjPath, 'pubspec.yaml'), 'contents');
+    String subProjFilePath = path.posix.join(subProjPath, 'file.dart');
     resourceProvider.newFile(subProjFilePath, 'contents');
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
     // Make sure that there really is a context for the subproject.
@@ -253,7 +253,7 @@
 
   test_refresh_folder_with_packagespec() {
     // create a context with a .packages file
-    String packagespecFile = posix.join(projPath, '.packages');
+    String packagespecFile = path.posix.join(projPath, '.packages');
     resourceProvider.newFile(packagespecFile, '');
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
     return pumpEventQueue().then((_) {
@@ -273,10 +273,10 @@
   test_refresh_folder_with_packagespec_subfolders() {
     // Create a folder with no .packages file, containing two subfolders with
     // .packages files.
-    String subdir1Path = posix.join(projPath, 'subdir1');
-    String subdir2Path = posix.join(projPath, 'subdir2');
-    String packagespec1Path = posix.join(subdir1Path, '.packages');
-    String packagespec2Path = posix.join(subdir2Path, '.packages');
+    String subdir1Path = path.posix.join(projPath, 'subdir1');
+    String subdir2Path = path.posix.join(projPath, 'subdir2');
+    String packagespec1Path = path.posix.join(subdir1Path, '.packages');
+    String packagespec2Path = path.posix.join(subdir2Path, '.packages');
     resourceProvider.newFile(packagespec1Path, '');
     resourceProvider.newFile(packagespec2Path, '');
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
@@ -297,7 +297,7 @@
 
   test_refresh_folder_with_pubspec() {
     // create a context with a pubspec.yaml file
-    String pubspecPath = posix.join(projPath, 'pubspec.yaml');
+    String pubspecPath = path.posix.join(projPath, 'pubspec.yaml');
     resourceProvider.newFile(pubspecPath, 'pubspec');
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
     return pumpEventQueue().then((_) {
@@ -314,10 +314,10 @@
   test_refresh_folder_with_pubspec_subfolders() {
     // Create a folder with no pubspec.yaml, containing two subfolders with
     // pubspec.yaml files.
-    String subdir1Path = posix.join(projPath, 'subdir1');
-    String subdir2Path = posix.join(projPath, 'subdir2');
-    String pubspec1Path = posix.join(subdir1Path, 'pubspec.yaml');
-    String pubspec2Path = posix.join(subdir2Path, 'pubspec.yaml');
+    String subdir1Path = path.posix.join(projPath, 'subdir1');
+    String subdir2Path = path.posix.join(projPath, 'subdir2');
+    String pubspec1Path = path.posix.join(subdir1Path, 'pubspec.yaml');
+    String pubspec2Path = path.posix.join(subdir2Path, 'pubspec.yaml');
     resourceProvider.newFile(pubspec1Path, 'pubspec');
     resourceProvider.newFile(pubspec2Path, 'pubspec');
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
@@ -338,12 +338,12 @@
 
   test_refresh_oneContext() {
     // create two contexts with pubspec.yaml files
-    String pubspecPath = posix.join(projPath, 'pubspec.yaml');
+    String pubspecPath = path.posix.join(projPath, 'pubspec.yaml');
     resourceProvider.newFile(pubspecPath, 'pubspec1');
 
     String proj2Path = '/my/proj2';
     resourceProvider.newFolder(proj2Path);
-    String pubspec2Path = posix.join(proj2Path, 'pubspec.yaml');
+    String pubspec2Path = path.posix.join(proj2Path, 'pubspec.yaml');
     resourceProvider.newFile(pubspec2Path, 'pubspec2');
 
     List<String> roots = <String>[projPath, proj2Path];
@@ -396,7 +396,7 @@
   }
 
   void test_setRoots_addFolderWithDartFile() {
-    String filePath = posix.join(projPath, 'foo.dart');
+    String filePath = path.posix.join(projPath, 'foo.dart');
     resourceProvider.newFile(filePath, 'contents');
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
     // verify
@@ -414,7 +414,7 @@
   }
 
   void test_setRoots_addFolderWithDartFileInSubfolder() {
-    String filePath = posix.join(projPath, 'foo', 'bar.dart');
+    String filePath = path.posix.join(projPath, 'foo', 'bar.dart');
     resourceProvider.newFile(filePath, 'contents');
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
     // verify
@@ -424,7 +424,7 @@
   }
 
   void test_setRoots_addFolderWithDummyLink() {
-    String filePath = posix.join(projPath, 'foo.dart');
+    String filePath = path.posix.join(projPath, 'foo.dart');
     resourceProvider.newDummyLink(filePath);
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
     // verify
@@ -497,12 +497,12 @@
   }
 
   void test_setRoots_addFolderWithPackagespec() {
-    String packagespecPath = posix.join(projPath, '.packages');
+    String packagespecPath = path.posix.join(projPath, '.packages');
     resourceProvider.newFile(packagespecPath,
         'unittest:file:///home/somebody/.pub/cache/unittest-0.9.9/lib/');
     String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
     File mainFile =
-        resourceProvider.newFile(posix.join(libPath, 'main.dart'), '');
+        resourceProvider.newFile(path.posix.join(libPath, 'main.dart'), '');
     Source source = mainFile.createSource();
 
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
@@ -523,7 +523,7 @@
 
   void test_setRoots_addFolderWithPackagespecAndPackageRoot() {
     // The package root should take priority.
-    String packagespecPath = posix.join(projPath, '.packages');
+    String packagespecPath = path.posix.join(projPath, '.packages');
     resourceProvider.newFile(packagespecPath,
         'unittest:file:///home/somebody/.pub/cache/unittest-0.9.9/lib/');
     String packageRootPath = '/package/root/';
@@ -535,7 +535,7 @@
   }
 
   void test_setRoots_addFolderWithPubspec() {
-    String pubspecPath = posix.join(projPath, 'pubspec.yaml');
+    String pubspecPath = path.posix.join(projPath, 'pubspec.yaml');
     resourceProvider.newFile(pubspecPath, 'pubspec');
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
     // verify
@@ -545,8 +545,8 @@
   }
 
   void test_setRoots_addFolderWithPubspec_andPackagespec() {
-    String pubspecPath = posix.join(projPath, 'pubspec.yaml');
-    String packagespecPath = posix.join(projPath, '.packages');
+    String pubspecPath = path.posix.join(projPath, 'pubspec.yaml');
+    String packagespecPath = path.posix.join(projPath, '.packages');
     resourceProvider.newFile(pubspecPath, 'pubspec');
     resourceProvider.newFile(packagespecPath, '');
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
@@ -931,7 +931,7 @@
   }
 
   void test_setRoots_noContext_inDotFolder() {
-    String pubspecPath = posix.join(projPath, '.pub', 'pubspec.yaml');
+    String pubspecPath = path.posix.join(projPath, '.pub', 'pubspec.yaml');
     resourceProvider.newFile(pubspecPath, 'name: test');
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
     // verify
@@ -941,7 +941,7 @@
   }
 
   void test_setRoots_noContext_inPackagesFolder() {
-    String pubspecPath = posix.join(projPath, 'packages', 'pubspec.yaml');
+    String pubspecPath = path.posix.join(projPath, 'packages', 'pubspec.yaml');
     resourceProvider.newFile(pubspecPath, 'name: test');
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
     // verify
@@ -951,7 +951,7 @@
   }
 
   void test_setRoots_packageResolver() {
-    String filePath = posix.join(projPath, 'lib', 'foo.dart');
+    String filePath = path.posix.join(projPath, 'lib', 'foo.dart');
     newFile([projPath, ContextManagerImpl.PACKAGE_SPEC_NAME], 'foo:lib/');
     resourceProvider.newFile(filePath, 'contents');
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
@@ -991,7 +991,7 @@
 
   void test_setRoots_removeFolderWithPackagespec() {
     // create a pubspec
-    String pubspecPath = posix.join(projPath, '.packages');
+    String pubspecPath = path.posix.join(projPath, '.packages');
     resourceProvider.newFile(pubspecPath, '');
     // add one root - there is a context
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
@@ -1041,7 +1041,7 @@
 
   void test_setRoots_removeFolderWithPubspec() {
     // create a pubspec
-    String pubspecPath = posix.join(projPath, 'pubspec.yaml');
+    String pubspecPath = path.posix.join(projPath, 'pubspec.yaml');
     resourceProvider.newFile(pubspecPath, 'pubspec');
     // add one root - there is a context
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
@@ -1124,7 +1124,7 @@
     Map<String, int> filePaths = callbacks.currentContextFilePaths[projPath];
     expect(filePaths, isEmpty);
     // add link
-    String filePath = posix.join(projPath, 'foo.dart');
+    String filePath = path.posix.join(projPath, 'foo.dart');
     resourceProvider.newDummyLink(filePath);
     // the link was ignored
     return pumpEventQueue().then((_) {
@@ -1138,7 +1138,7 @@
     Map<String, int> filePaths = callbacks.currentContextFilePaths[projPath];
     expect(filePaths, hasLength(0));
     // add file
-    String filePath = posix.join(projPath, 'foo.dart');
+    String filePath = path.posix.join(projPath, 'foo.dart');
     resourceProvider.newFile(filePath, 'contents');
     // the file was added
     return pumpEventQueue().then((_) {
@@ -1244,7 +1244,7 @@
     Map<String, int> filePaths = callbacks.currentContextFilePaths[projPath];
     expect(filePaths, hasLength(0));
     // add file in subfolder
-    String filePath = posix.join(projPath, 'foo', 'bar.dart');
+    String filePath = path.posix.join(projPath, 'foo', 'bar.dart');
     resourceProvider.newFile(filePath, 'contents');
     // the file was added
     return pumpEventQueue().then((_) {
@@ -1425,7 +1425,7 @@
   }
 
   test_watch_deleteFile() {
-    String filePath = posix.join(projPath, 'foo.dart');
+    String filePath = path.posix.join(projPath, 'foo.dart');
     // add root with a file
     File file = resourceProvider.newFile(filePath, 'contents');
     Folder projFolder = file.parent;
@@ -1446,7 +1446,7 @@
   }
 
   test_watch_deleteFolder() {
-    String filePath = posix.join(projPath, 'foo.dart');
+    String filePath = path.posix.join(projPath, 'foo.dart');
     // add root with a file
     File file = resourceProvider.newFile(filePath, 'contents');
     Folder projFolder = file.parent;
@@ -1595,7 +1595,7 @@
   }
 
   test_watch_modifyFile() {
-    String filePath = posix.join(projPath, 'foo.dart');
+    String filePath = path.posix.join(projPath, 'foo.dart');
     // add root with a file
     resourceProvider.newFile(filePath, 'contents');
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
@@ -1614,11 +1614,11 @@
 
   test_watch_modifyPackageMapDependency_fail() async {
     // create a dependency file
-    String dependencyPath = posix.join(projPath, 'dep');
+    String dependencyPath = path.posix.join(projPath, 'dep');
     resourceProvider.newFile(dependencyPath, 'contents');
     packageMapProvider.dependencies.add(dependencyPath);
     // create a Dart file
-    String dartFilePath = posix.join(projPath, 'main.dart');
+    String dartFilePath = path.posix.join(projPath, 'main.dart');
     resourceProvider.newFile(dartFilePath, 'contents');
     // the created context has the expected empty package map
     manager.setRoots(<String>[projPath], <String>[], <String, String>{});
@@ -1743,7 +1743,7 @@
       '**/${AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE}'
     ];
     return patterns
-        .map((pattern) => new Glob(posix.separator, pattern))
+        .map((pattern) => new Glob(path.posix.separator, pattern))
         .toList();
   }
 
@@ -1757,7 +1757,7 @@
   Map<String, List<Folder>> get _currentPackageMap => _packageMap(projPath);
 
   void deleteFile(List<String> pathComponents) {
-    String filePath = posix.joinAll(pathComponents);
+    String filePath = path.posix.joinAll(pathComponents);
     resourceProvider.deleteFile(filePath);
   }
 
@@ -1765,13 +1765,13 @@
       ErrorProcessor.getProcessor(callbacks.currentContext, error);
 
   String newFile(List<String> pathComponents, [String content = '']) {
-    String filePath = posix.joinAll(pathComponents);
+    String filePath = path.posix.joinAll(pathComponents);
     resourceProvider.newFile(filePath, content);
     return filePath;
   }
 
   String newFolder(List<String> pathComponents) {
-    String folderPath = posix.joinAll(pathComponents);
+    String folderPath = path.posix.joinAll(pathComponents);
     resourceProvider.newFolder(folderPath);
     return folderPath;
   }
@@ -1935,6 +1935,43 @@
     expect(getProcessor(missing_return).severity, isNull);
   }
 
+  test_analysis_options_include() async {
+    // Create files.
+    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+    newFile([libPath, 'main.dart']);
+    String sdkExtPath = newFolder([projPath, 'sdk_ext']);
+    newFile([sdkExtPath, 'entry.dart']);
+    String sdkExtSrcPath = newFolder([projPath, 'sdk_ext', 'src']);
+    newFile([sdkExtSrcPath, 'part.dart']);
+    // Setup analysis options file which includes another options file.
+    newFile(
+        [projPath, optionsFileName],
+        r'''
+include: other_options.yaml
+''');
+    newFile(
+        [projPath, 'other_options.yaml'],
+        r'''
+analyzer:
+  language:
+    enableGenericMethods: true
+  errors:
+    unused_local_variable: false
+linter:
+  rules:
+    - camel_case_types
+''');
+    // Setup context.
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+    await pumpEventQueue();
+
+    // Verify options were set.
+    expect(options.enableGenericMethods, isTrue);
+    expect(errorProcessors, hasLength(1));
+    expect(lints, hasLength(1));
+    expect(lints[0].name, 'camel_case_types');
+  }
+
   test_analysis_options_parse_failure() async {
     // Create files.
     String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
@@ -1955,217 +1992,6 @@
     // No error means success.
   }
 
-  test_configed_options() async {
-    // Create files.
-    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
-    newFile([projPath, 'test', 'test.dart']);
-    newFile(
-        [projPath, 'pubspec.yaml'],
-        r'''
-dependencies:
-  test_pack: any
-analyzer:
-  configuration: test_pack/config
-''');
-
-    // Setup .packages file
-    newFile(
-        [projPath, '.packages'],
-        r'''
-test_pack:lib/''');
-
-    // Setup config.yaml.
-    newFile(
-        [libPath, 'config', 'config.yaml'],
-        r'''
-analyzer:
-  strong-mode: true
-  language:
-    enableSuperMixins: true
-  errors:
-    missing_return: false
-linter:
-  rules:
-    - avoid_as
-''');
-
-    // Setup analysis options
-    newFile(
-        [projPath, optionsFileName],
-        r'''
-analyzer:
-  exclude:
-    - 'test/**'
-  language:
-    enableGenericMethods: true
-  errors:
-    unused_local_variable: false
-linter:
-  rules:
-    - camel_case_types
-''');
-
-    // Setup context.
-    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-    await pumpEventQueue();
-
-    // Confirm that one context was created.
-    var contexts =
-        manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
-    expect(contexts, isNotNull);
-    expect(contexts, hasLength(1));
-
-    var context = contexts.first;
-
-    // Verify options.
-    // * from `config.yaml`:
-    expect(context.analysisOptions.strongMode, isTrue);
-    expect(context.analysisOptions.enableSuperMixins, isTrue);
-    // * from analysis options:
-    expect(context.analysisOptions.enableGenericMethods, isTrue);
-
-    // * verify tests are excluded
-    expect(callbacks.currentContextFilePaths[projPath].keys,
-        unorderedEquals(['/my/proj/$optionsFileName']));
-
-    // Verify filter setup.
-    expect(errorProcessors, hasLength(2));
-
-    // * (config.)
-    expect(getProcessor(missing_return).severity, isNull);
-
-    // * (options.)
-    expect(getProcessor(unused_local_variable).severity, isNull);
-
-    // Verify lints.
-    var lintNames = lints.map((lint) => lint.name);
-    expect(
-        lintNames,
-        unorderedEquals(
-            ['avoid_as' /* config */, 'camel_case_types' /* options */]));
-  }
-
-  test_embedder_and_configed_options() async {
-    // Create files.
-    String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
-    String sdkExtPath = newFolder([projPath, 'sdk_ext']);
-    newFile([projPath, 'test', 'test.dart']);
-    newFile([sdkExtPath, 'entry.dart']);
-
-    // Setup pubspec with configuration.
-    newFile(
-        [projPath, 'pubspec.yaml'],
-        r'''
-dependencies:
-  test_pack: any
-analyzer:
-  configuration: test_pack/config
-''');
-
-    // Setup _embedder.yaml.
-    newFile(
-        [libPath, '_embedder.yaml'],
-        r'''
-embedded_libs:
-  "dart:foobar": "../sdk_ext/entry.dart"
-analyzer:
-  strong-mode: true
-  language:
-    enableSuperMixins: true
-  errors:
-    missing_return: false
-linter:
-  rules:
-    - avoid_as
-''');
-
-    // Setup .packages file
-    newFile(
-        [projPath, '.packages'],
-        r'''
-test_pack:lib/''');
-
-    // Setup analysis options
-    newFile(
-        [projPath, optionsFileName],
-        r'''
-analyzer:
-  exclude:
-    - 'test/**'
-  language:
-    enableGenericMethods: true
-  errors:
-    unused_local_variable: false
-linter:
-  rules:
-    - camel_case_types
-''');
-
-    // Setup config.yaml.
-    newFile(
-        [libPath, 'config', 'config.yaml'],
-        r'''
-analyzer:
-  errors:
-    missing_required_param: error
-linter:
-  rules:
-    - always_specify_types
-''');
-
-    // Setup context.
-    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-    await pumpEventQueue();
-
-    // Confirm that one context was created.
-    var contexts =
-        manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
-    expect(contexts, isNotNull);
-    expect(contexts, hasLength(1));
-    var context = contexts[0];
-
-    // Verify options.
-    // * from `_embedder.yaml`:
-    expect(context.analysisOptions.strongMode, isTrue);
-    expect(context.analysisOptions.enableSuperMixins, isTrue);
-    // * from analysis options:
-    expect(context.analysisOptions.enableGenericMethods, isTrue);
-
-    // * verify tests are excluded
-    expect(
-        callbacks.currentContextFilePaths[projPath].keys,
-        unorderedEquals(
-            ['/my/proj/sdk_ext/entry.dart', '/my/proj/$optionsFileName']));
-
-    // Verify filter setup.
-    expect(errorProcessors, hasLength(3));
-
-    // * (embedder.)
-    expect(getProcessor(missing_return).severity, isNull);
-
-    // * (config.)
-    expect(getProcessor(missing_required_param).severity, ErrorSeverity.ERROR);
-
-    // * (options.)
-    expect(getProcessor(unused_local_variable).severity, isNull);
-
-    // Verify lints.
-    var lintNames = lints.map((lint) => lint.name);
-
-    expect(
-        lintNames,
-        unorderedEquals([
-          'avoid_as' /* embedder */,
-          'always_specify_types' /* config*/,
-          'camel_case_types' /* options */
-        ]));
-
-    // Sanity check embedder libs.
-    var source = context.sourceFactory.forUri('dart:foobar');
-    expect(source, isNotNull);
-    expect(source.fullName, '/my/proj/sdk_ext/entry.dart');
-  }
-
   test_embedder_options() async {
     // Create files.
     String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
diff --git a/pkg/analysis_server/test/integration/analysis/get_hover_test.dart b/pkg/analysis_server/test/integration/analysis/get_hover_test.dart
index 921a266..7c6a742 100644
--- a/pkg/analysis_server/test/integration/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/get_hover_test.dart
@@ -7,7 +7,7 @@
 import 'dart:async';
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:path/path.dart';
+import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -78,7 +78,7 @@
       expect(info.offset, equals(offset));
       expect(info.length, equals(length));
       if (isCore) {
-        expect(basename(info.containingLibraryPath), equals('core.dart'));
+        expect(path.basename(info.containingLibraryPath), equals('core.dart'));
         expect(info.containingLibraryName, equals('dart.core'));
       } else if (isLocal || isLiteral) {
         expect(info.containingLibraryPath, isNull);
diff --git a/pkg/analysis_server/test/integration/analysis/package_root_test.dart b/pkg/analysis_server/test/integration/analysis/package_root_test.dart
index 4febe5ad..5ad9c38 100644
--- a/pkg/analysis_server/test/integration/analysis/package_root_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/package_root_test.dart
@@ -5,7 +5,7 @@
 library test.integration.analysis.packageRoot;
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:path/path.dart';
+import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -21,9 +21,9 @@
 class Test extends AbstractAnalysisServerIntegrationTest {
   test_package_root() {
     String projPath = sourcePath('project');
-    String mainPath = join(projPath, 'main.dart');
+    String mainPath = path.join(projPath, 'main.dart');
     String packagesPath = sourcePath('packages');
-    String fooBarPath = join(packagesPath, 'foo', 'bar.dart');
+    String fooBarPath = path.join(packagesPath, 'foo', 'bar.dart');
     String mainText = """
 library main;
 
diff --git a/pkg/analysis_server/test/integration/analysis/update_content_test.dart b/pkg/analysis_server/test/integration/analysis/update_content_test.dart
index c9d5400..1d275ce2 100644
--- a/pkg/analysis_server/test/integration/analysis/update_content_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/update_content_test.dart
@@ -37,7 +37,7 @@
         .then((result) => analysisFinished)
         .then((_) {
           // There should be no errors now because the contents on disk have been
-          // overriden with goodText.
+          // overridden with goodText.
           expect(currentAnalysisErrors[pathname], isEmpty);
           return sendAnalysisUpdateContent({
             pathname: new ChangeContentOverlay(
diff --git a/pkg/analysis_server/test/single_context_manager_test.dart b/pkg/analysis_server/test/single_context_manager_test.dart
index 97b4ec6..eafa488 100644
--- a/pkg/analysis_server/test/single_context_manager_test.dart
+++ b/pkg/analysis_server/test/single_context_manager_test.dart
@@ -14,7 +14,7 @@
 import 'package:analyzer/src/generated/source_io.dart';
 import 'package:analyzer/src/util/glob.dart';
 import 'package:linter/src/plugin/linter_plugin.dart';
-import 'package:path/path.dart';
+import 'package:path/path.dart' as path;
 import 'package:plugin/manager.dart';
 import 'package:plugin/plugin.dart';
 import 'package:test/test.dart';
@@ -43,18 +43,18 @@
       '**/*.${AnalysisEngine.SUFFIX_HTML}',
     ];
     return patterns
-        .map((pattern) => new Glob(posix.separator, pattern))
+        .map((pattern) => new Glob(path.posix.separator, pattern))
         .toList();
   }
 
   String newFile(List<String> pathComponents, [String content = '']) {
-    String filePath = posix.joinAll(pathComponents);
+    String filePath = path.posix.joinAll(pathComponents);
     resourceProvider.newFile(filePath, content);
     return filePath;
   }
 
   String newFolder(List<String> pathComponents) {
-    String folderPath = posix.joinAll(pathComponents);
+    String folderPath = path.posix.joinAll(pathComponents);
     resourceProvider.newFolder(folderPath);
     return folderPath;
   }
@@ -99,7 +99,7 @@
     resourceProvider.newFolder(root1);
     resourceProvider.newFolder(root2);
     manager.setRoots(<String>[root1, root2], <String>[], <String, String>{});
-    expect(manager.isIgnored('$context/root3/file.dart'), isTrue);
+    expect(manager.isIgnored('/context/root3/file.dart'), isTrue);
   }
 
   void test_isInAnalysisRoot_false_inExcludedPath() {
@@ -117,7 +117,7 @@
     resourceProvider.newFolder(root1);
     resourceProvider.newFolder(root2);
     manager.setRoots(<String>[root1, root2], <String>[], <String, String>{});
-    expect(manager.isInAnalysisRoot('$context/root3/file.dart'), isFalse);
+    expect(manager.isInAnalysisRoot('/context/root3/file.dart'), isFalse);
   }
 
   void test_isInAnalysisRoot_true() {
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index 07a0577..44e480f 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -125,14 +125,7 @@
       For convenience, the API is divided into domains. Each domain is
       specified in a separate section below:
     </p>
-    <ul>
-      <li><a href="#domain_server">Server</a></li>
-      <li><a href="#domain_analysis">Analysis</a></li>
-      <li><a href="#domain_completion">Code Completion</a></li>
-      <li><a href="#domain_search">Search</a></li>
-      <li><a href="#domain_edit">Edit</a></li>
-      <li><a href="#domain_execution">Execution</a></li>
-    </ul>
+    <toc></toc>
     <p>
       The specifications of the API’s refer to data structures beyond
       the standard JSON primitives. These data structures are
diff --git a/pkg/analysis_server/tool/spec/to_html.dart b/pkg/analysis_server/tool/spec/to_html.dart
index b17cdfe..d71fa64 100644
--- a/pkg/analysis_server/tool/spec/to_html.dart
+++ b/pkg/analysis_server/tool/spec/to_html.dart
@@ -116,9 +116,6 @@
 
 /* Styles for index */
 
-.subindex {
-}
-
 .subindex ul {
   padding-left: 0;
   margin-left: 0;
@@ -196,6 +193,7 @@
   void head(void callback()) => element('head', {}, callback);
   void html(void callback()) => element('html', {}, callback);
   void i(void callback()) => element('i', {}, callback);
+  void li(void callback()) => element('li', {}, callback);
   void link(String id, void callback()) {
     element('a', {'href': '#$id'}, callback);
   }
@@ -204,6 +202,7 @@
   void pre(void callback()) => element('pre', {}, callback);
   void title(void callback()) => element('title', {}, callback);
   void tt(void callback()) => element('tt', {}, callback);
+  void ul(void callback()) => element('ul', {}, callback);
 }
 
 /**
@@ -270,6 +269,22 @@
     }
   }
 
+  void generateTableOfContents() {
+    ul(() {
+      writeln();
+
+      for (var domain in api.domains.where((domain) => !domain.experimental)) {
+        write('      ');
+        li(() {
+          link('domain_${domain.name}', () {
+            write(_toTitleCase(domain.name));
+          });
+        });
+        writeln();
+      }
+    });
+  }
+
   void generateIndex() {
     h3(() => write('Domains'));
     for (var domain in api.domains) {
@@ -425,6 +440,9 @@
           case 'version':
             translateHtml(node, squashParagraphs: squashParagraphs);
             break;
+          case 'toc':
+            generateTableOfContents();
+            break;
           case 'index':
             generateIndex();
             break;
@@ -769,3 +787,8 @@
     }
   }
 }
+
+String _toTitleCase(String str) {
+  if (str.isEmpty) return str;
+  return str.substring(0, 1).toUpperCase() + str.substring(1);
+}
diff --git a/pkg/analyzer/lib/source/analysis_options_provider.dart b/pkg/analyzer/lib/source/analysis_options_provider.dart
index 808c835..90cf8a1 100644
--- a/pkg/analyzer/lib/source/analysis_options_provider.dart
+++ b/pkg/analyzer/lib/source/analysis_options_provider.dart
@@ -10,6 +10,7 @@
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/source/source_resource.dart';
+import 'package:analyzer/src/task/options.dart';
 import 'package:analyzer/src/util/yaml.dart';
 import 'package:source_span/source_span.dart';
 import 'package:yaml/yaml.dart';
@@ -25,6 +26,8 @@
   /// Provide the options found in either
   /// [root]/[AnalysisEngine.ANALYSIS_OPTIONS_FILE] or
   /// [root]/[AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE].
+  /// Recursively merge options referenced by an include directive
+  /// and remove the include directive from the resulting options map.
   /// Return an empty options map if the file does not exist.
   Map<String, YamlNode> getOptions(Folder root, {bool crawlUp: false}) {
     Resource resource;
@@ -42,17 +45,21 @@
   }
 
   /// Provide the options found in [file].
+  /// Recursively merge options referenced by an include directive
+  /// and remove the include directive from the resulting options map.
   /// Return an empty options map if the file does not exist.
   Map<String, YamlNode> getOptionsFromFile(File file) {
     return getOptionsFromSource(new FileSource(file));
   }
 
   /// Provide the options found in [source].
+  /// Recursively merge options referenced by an include directive
+  /// and remove the include directive from the resulting options map.
   /// Return an empty options map if the file does not exist.
   Map<String, YamlNode> getOptionsFromSource(Source source) {
     Map<String, YamlNode> options =
         getOptionsFromString(_readAnalysisOptions(source));
-    YamlNode node = options.remove('include');
+    YamlNode node = options.remove(AnalyzerOptions.include);
     if (sourceFactory != null && node is YamlScalar) {
       var path = node.value;
       if (path is String) {
@@ -64,6 +71,8 @@
   }
 
   /// Provide the options found in [optionsSource].
+  /// An include directive, if present, will be left as-is,
+  /// and the referenced options will NOT be merged into the result.
   /// Return an empty options map if the source is null.
   Map<String, YamlNode> getOptionsFromString(String optionsSource) {
     Map<String, YamlNode> options = <String, YamlNode>{};
diff --git a/pkg/analyzer/lib/source/config.dart b/pkg/analyzer/lib/source/config.dart
deleted file mode 100644
index db44b4e..0000000
--- a/pkg/analyzer/lib/source/config.dart
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/source/analysis_options_provider.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/task/model.dart';
-import 'package:analyzer/task/model.dart';
-import 'package:package_config/packages.dart';
-import 'package:yaml/src/yaml_node.dart';
-import 'package:yaml/yaml.dart';
-
-/// The descriptor used to associate analysis configuration with analysis
-/// contexts in configuration data.
-final ResultDescriptor<AnalysisConfiguration> ANALYSIS_CONFIGURATION =
-    new ResultDescriptorImpl('analysis.config', null);
-
-/// Return configuration associated with this [context], or `null` if there is
-/// none.
-AnalysisConfiguration getConfiguration(AnalysisContext context) =>
-    context.getConfigurationData(ANALYSIS_CONFIGURATION);
-
-/// Associate this [config] with the given [context].
-void setConfiguration(AnalysisContext context, AnalysisConfiguration config) {
-  context.setConfigurationData(ANALYSIS_CONFIGURATION, config);
-}
-
-/// Analysis configuration.
-abstract class AnalysisConfiguration {
-  final AnalysisOptionsProvider optionsProvider = new AnalysisOptionsProvider();
-  final Packages packages;
-  final ResourceProvider resourceProvider;
-  AnalysisConfiguration(this.resourceProvider, this.packages);
-
-  factory AnalysisConfiguration.fromPubspec(
-          File pubspec, ResourceProvider resourceProvider, Packages packages) =>
-      new PubspecConfiguration(pubspec, resourceProvider, packages);
-
-  /// Get a map of options defined by this configuration (or `null` if none
-  /// are specified).
-  Map get options;
-}
-
-/// Describes an analysis configuration.
-class AnalysisConfigurationDescriptor {
-  /// The name of the package hosting the configuration.
-  String package;
-
-  /// The name of the configuration "pragma".
-  String pragma;
-
-  AnalysisConfigurationDescriptor.fromAnalyzerOptions(Map analyzerOptions) {
-    Object config = analyzerOptions['configuration'];
-    if (config is String) {
-      List<String> items = config.split('/');
-      if (items.length == 2) {
-        package = items[0].trim();
-        pragma = items[1].trim();
-      }
-    }
-  }
-
-  /// Return true if this descriptor is valid.
-  bool get isValid => package != null && pragma != null;
-}
-
-/// Pubspec-specified analysis configuration.
-class PubspecConfiguration extends AnalysisConfiguration {
-  final File pubspec;
-  PubspecConfiguration(
-      this.pubspec, ResourceProvider resourceProvider, Packages packages)
-      : super(resourceProvider, packages);
-
-  @override
-  Map get options {
-    //Safest not to cache (requested infrequently).
-    if (pubspec.exists) {
-      try {
-        String contents = pubspec.readAsStringSync();
-        YamlNode map = loadYamlNode(contents);
-        if (map is YamlMap) {
-          YamlNode config = map['analyzer'];
-          if (config is YamlMap) {
-            AnalysisConfigurationDescriptor descriptor =
-                new AnalysisConfigurationDescriptor.fromAnalyzerOptions(config);
-
-            if (descriptor.isValid) {
-              //Create a path, given descriptor and packagemap
-              Uri uri = packages.asMap()[descriptor.package];
-              Uri pragma = new Uri.file('config/${descriptor.pragma}.yaml',
-                  windows: false);
-              Uri optionsUri = uri.resolveUri(pragma);
-              String path = resourceProvider.pathContext.fromUri(optionsUri);
-              File file = resourceProvider.getFile(path);
-              if (file.exists) {
-                return optionsProvider.getOptionsFromFile(file);
-              }
-            }
-          }
-        }
-      } catch (_) {
-        // Skip exceptional configurations.
-      }
-    }
-    return null;
-  }
-}
diff --git a/pkg/analyzer/lib/src/analysis_options/error/option_codes.dart b/pkg/analyzer/lib/src/analysis_options/error/option_codes.dart
index 4b39a45..768ec94 100644
--- a/pkg/analyzer/lib/src/analysis_options/error/option_codes.dart
+++ b/pkg/analyzer/lib/src/analysis_options/error/option_codes.dart
@@ -23,6 +23,19 @@
       const AnalysisOptionsErrorCode('PARSE_ERROR', '{0}');
 
   /**
+   * An error code indicating that there is a syntactic error
+   * in the included file.
+   *
+   * Parameters:
+   * 0: the path of the file containing the error
+   * 1: the starting offset of the text in the file that contains the error
+   * 2: the ending offset of the text in the file that contains the error
+   * 3: the error message
+   */
+  static const INCLUDED_FILE_PARSE_ERROR = const AnalysisOptionsErrorCode(
+      'INCLUDED_FILE_PARSE_ERROR', '{3} in {0}({1}..{2})');
+
+  /**
    * Initialize a newly created error code to have the given [name].
    */
   const AnalysisOptionsErrorCode(String name, String message,
@@ -44,6 +57,30 @@
  */
 class AnalysisOptionsWarningCode extends ErrorCode {
   /**
+   * An error code indicating a specified include file could not be found.
+   *
+   * Parameters:
+   * 0: the uri of the file to be included
+   * 1: the path of the file containing the include directive
+   */
+  static const AnalysisOptionsWarningCode INCLUDE_FILE_NOT_FOUND =
+      const AnalysisOptionsWarningCode('INCLUDE_FILE_NOT_FOUND',
+          "The include file {0} in {1} cannot be found.");
+
+  /**
+   * An error code indicating a specified include file has a warning.
+   *
+   * Parameters:
+   * 0: the path of the file containing the warnings
+   * 1: the starting offset of the text in the file that contains the warning
+   * 2: the ending offset of the text in the file that contains the warning
+   * 3: the warning message
+   */
+  static const AnalysisOptionsWarningCode INCLUDED_FILE_WARNING =
+      const AnalysisOptionsWarningCode('INCLUDED_FILE_WARNING',
+          "Warning in the included options file {0}({1}..{2}): {3}");
+
+  /**
    * An error code indicating that a plugin is being configured with an
    * unsupported option and legal options are provided.
    *
diff --git a/pkg/analyzer/lib/src/context/builder.dart b/pkg/analyzer/lib/src/context/builder.dart
index 75875f7..5037995 100644
--- a/pkg/analyzer/lib/src/context/builder.dart
+++ b/pkg/analyzer/lib/src/context/builder.dart
@@ -77,14 +77,12 @@
    * The resolver provider used to create a package: URI resolver, or `null` if
    * the normal (Package Specification DEP) lookup mechanism is to be used.
    */
-  @deprecated
   ResolverProvider packageResolverProvider;
 
   /**
    * The resolver provider used to create a file: URI resolver, or `null` if
    * the normal file URI resolver is to be used.
    */
-  @deprecated
   ResolverProvider fileResolverProvider;
 
   /**
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 543e382..7486496b 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -1139,7 +1139,6 @@
   final FileState file;
   final Uri uri;
 
-  Set<FileState> transitiveDependencies;
   String _dependencySignature;
 
   _LibraryNode(this.driver, this.file, this.uri);
@@ -1152,8 +1151,7 @@
       signature.addString(driver._sdkBundle.apiSignature);
 
       // Add all unlinked API signatures.
-      computeTransitiveDependencies();
-      transitiveDependencies
+      file.transitiveFiles
           .map((file) => file.apiSignature)
           .forEach(signature.addBytes);
 
@@ -1170,20 +1168,6 @@
     return other is _LibraryNode && other.uri == uri;
   }
 
-  void computeTransitiveDependencies() {
-    if (transitiveDependencies == null) {
-      transitiveDependencies = new Set<FileState>();
-
-      void appendDependencies(FileState file) {
-        if (transitiveDependencies.add(file)) {
-          file.dependencies.forEach(appendDependencies);
-        }
-      }
-
-      appendDependencies(file);
-    }
-  }
-
   @override
   String toString() => uri.toString();
 }
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_byte_store.dart b/pkg/analyzer/lib/src/dart/analysis/file_byte_store.dart
index 46f4648..3e18290 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_byte_store.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_byte_store.dart
@@ -10,6 +10,17 @@
 import 'package:path/path.dart';
 
 /**
+ * The request that is sent from the main isolate to the clean-up isolate.
+ */
+class CacheCleanUpRequest {
+  final String cachePath;
+  final int maxSizeBytes;
+  final SendPort replyTo;
+
+  CacheCleanUpRequest(this.cachePath, this.maxSizeBytes, this.replyTo);
+}
+
+/**
  * [ByteStore] that stores values as files.
  */
 class FileByteStore implements ByteStore {
@@ -17,7 +28,7 @@
   static SendPort _cleanUpSendPort;
 
   final String _cachePath;
-  final String _tempName = 'temp_${pid}';
+  final String _tempName = 'temp_$pid';
   final int _maxSizeBytes;
 
   int _bytesWrittenSinceCleanup = 0;
@@ -74,7 +85,8 @@
       _evictionIsolateIsRunning = true;
       try {
         ReceivePort response = new ReceivePort();
-        _cleanUpSendPort.send([_cachePath, _maxSizeBytes, response.sendPort]);
+        _cleanUpSendPort.send(new CacheCleanUpRequest(
+            _cachePath, _maxSizeBytes, response.sendPort));
         await response.first;
       } finally {
         _evictionIsolateIsRunning = false;
@@ -90,18 +102,11 @@
   static void _cacheCleanUpFunction(SendPort initialReplyTo) {
     ReceivePort port = new ReceivePort();
     initialReplyTo.send(port.sendPort);
-    port.listen((args) async {
-      if (args is List &&
-          args.length == 3 &&
-          args[0] is String &&
-          args[1] is int &&
-          args[2] is SendPort) {
-        String cachePath = args[0] as String;
-        int maxSizeBytes = args[1] as int;
-        await _cleanUpFolder(cachePath, maxSizeBytes);
-        // Let that client know that we're done.
-        SendPort replyTo = args[2] as SendPort;
-        replyTo.send(true);
+    port.listen((request) async {
+      if (request is CacheCleanUpRequest) {
+        await _cleanUpFolder(request.cachePath, request.maxSizeBytes);
+        // Let the client know that we're done.
+        request.replyTo.send(true);
       }
     });
   }
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index 89a3d7b..da38aca 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -25,6 +25,7 @@
 import 'package:analyzer/src/util/fast_uri.dart';
 import 'package:convert/convert.dart';
 import 'package:crypto/crypto.dart';
+import 'package:meta/meta.dart';
 
 /**
  * [FileContentOverlay] is used to temporary override content of files.
@@ -90,7 +91,8 @@
   List<FileState> _importedFiles;
   List<FileState> _exportedFiles;
   List<FileState> _partedFiles;
-  List<FileState> _dependencies;
+  Set<FileState> _directReferencedFiles = new Set<FileState>();
+  Set<FileState> _transitiveFiles;
 
   FileState._(this._fsState, this.path, this.uri, this.source);
 
@@ -110,9 +112,10 @@
   String get contentHash => _contentHash;
 
   /**
-   * Return the list of all direct dependencies.
+   * Return the set of all directly referenced files - imported, exported or
+   * parted.
    */
-  List<FileState> get dependencies => _dependencies;
+  Set<FileState> get directReferencedFiles => _directReferencedFiles;
 
   /**
    * The list of files this file exports.
@@ -157,6 +160,25 @@
   List<FileState> get partedFiles => _partedFiles;
 
   /**
+   * Return the set of transitive files - the file itself and all of the
+   * directly or indirectly referenced files.
+   */
+  Set<FileState> get transitiveFiles {
+    if (_transitiveFiles == null) {
+      _transitiveFiles = new Set<FileState>();
+
+      void appendReferenced(FileState file) {
+        if (_transitiveFiles.add(file)) {
+          file._directReferencedFiles.forEach(appendReferenced);
+        }
+      }
+
+      appendReferenced(this);
+    }
+    return _transitiveFiles;
+  }
+
+  /**
    * The [UnlinkedUnit] of the file.
    */
   UnlinkedUnit get unlinked => _unlinked;
@@ -289,12 +311,25 @@
       }
     }
 
-    // Compute direct dependencies.
-    _dependencies = (new Set<FileState>()
-          ..addAll(_importedFiles)
-          ..addAll(_exportedFiles)
-          ..addAll(_partedFiles))
-        .toList();
+    // Compute referenced files.
+    Set<FileState> oldDirectReferencedFiles = _directReferencedFiles;
+    _directReferencedFiles = new Set<FileState>()
+      ..addAll(_importedFiles)
+      ..addAll(_exportedFiles)
+      ..addAll(_partedFiles);
+
+    // If the set of directly referenced files of this file is changed,
+    // then the transitive sets of files that include this file are also
+    // changed. Reset these transitive sets.
+    if (_directReferencedFiles.length != oldDirectReferencedFiles.length ||
+        !_directReferencedFiles.containsAll(oldDirectReferencedFiles)) {
+      for (FileState file in _fsState._uriToFile.values) {
+        if (file._transitiveFiles != null &&
+            file._transitiveFiles.contains(this)) {
+          file._transitiveFiles = null;
+        }
+      }
+    }
 
     // Return whether the API signature changed.
     return apiSignatureChanged;
@@ -368,6 +403,8 @@
    */
   final Map<FileState, List<FileState>> _partToLibraries = {};
 
+  FileSystemStateTestView _testView;
+
   FileSystemState(
       this._logger,
       this._byteStore,
@@ -375,13 +412,18 @@
       this._resourceProvider,
       this._sourceFactory,
       this._analysisOptions,
-      this._salt);
+      this._salt) {
+    _testView = new FileSystemStateTestView(this);
+  }
 
   /**
    * Return the set of known files.
    */
   Set<String> get knownFiles => _pathToFiles.keys.toSet();
 
+  @visibleForTesting
+  FileSystemStateTestView get test => _testView;
+
   /**
    * Return the canonical [FileState] for the given absolute [path]. The
    * returned file has the last known state since if was last refreshed.
@@ -453,3 +495,16 @@
       ..insert(0, canonicalFile);
   }
 }
+
+@visibleForTesting
+class FileSystemStateTestView {
+  final FileSystemState state;
+
+  FileSystemStateTestView(this.state);
+
+  Set<FileState> get filesWithoutTransitive {
+    return state._uriToFile.values
+        .where((f) => f._transitiveFiles == null)
+        .toSet();
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/analysis/referenced_names.dart b/pkg/analyzer/lib/src/dart/analysis/referenced_names.dart
new file mode 100644
index 0000000..811aa92
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/analysis/referenced_names.dart
@@ -0,0 +1,250 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+
+/**
+ * Compute the set of external names referenced in the [unit].
+ */
+Set<String> computeReferencedNames(CompilationUnit unit) {
+  _ReferencedNamesComputer computer = new _ReferencedNamesComputer();
+  unit.accept(computer);
+  return computer.names;
+}
+
+/**
+ * Chained set of local names, that hide corresponding external names.
+ */
+class _LocalNameScope {
+  final _LocalNameScope enclosing;
+  Set<String> names;
+
+  _LocalNameScope(this.enclosing);
+
+  factory _LocalNameScope.forBlock(_LocalNameScope enclosing, Block node) {
+    _LocalNameScope scope = new _LocalNameScope(enclosing);
+    for (Statement statement in node.statements) {
+      if (statement is FunctionDeclarationStatement) {
+        scope.add(statement.functionDeclaration.name);
+      } else if (statement is VariableDeclarationStatement) {
+        scope.addVariableNames(statement.variables);
+      }
+    }
+    return scope;
+  }
+
+  factory _LocalNameScope.forClass(
+      _LocalNameScope enclosing, ClassDeclaration node) {
+    _LocalNameScope scope = new _LocalNameScope(enclosing);
+    scope.addTypeParameters(node.typeParameters);
+    for (ClassMember member in node.members) {
+      if (member is FieldDeclaration) {
+        scope.addVariableNames(member.fields);
+      } else if (member is MethodDeclaration) {
+        scope.add(member.name);
+      }
+    }
+    return scope;
+  }
+
+  factory _LocalNameScope.forClassTypeAlias(
+      _LocalNameScope enclosing, ClassTypeAlias node) {
+    _LocalNameScope scope = new _LocalNameScope(enclosing);
+    scope.addTypeParameters(node.typeParameters);
+    return scope;
+  }
+
+  factory _LocalNameScope.forFunction(
+      _LocalNameScope enclosing, FunctionDeclaration node) {
+    _LocalNameScope scope = new _LocalNameScope(enclosing);
+    scope.addTypeParameters(node.functionExpression.typeParameters);
+    scope.addFormalParameters(node.functionExpression.parameters);
+    return scope;
+  }
+
+  factory _LocalNameScope.forFunctionTypeAlias(
+      _LocalNameScope enclosing, FunctionTypeAlias node) {
+    _LocalNameScope scope = new _LocalNameScope(enclosing);
+    scope.addTypeParameters(node.typeParameters);
+    return scope;
+  }
+
+  factory _LocalNameScope.forMethod(
+      _LocalNameScope enclosing, MethodDeclaration node) {
+    _LocalNameScope scope = new _LocalNameScope(enclosing);
+    scope.addTypeParameters(node.typeParameters);
+    scope.addFormalParameters(node.parameters);
+    return scope;
+  }
+
+  factory _LocalNameScope.forUnit(CompilationUnit node) {
+    _LocalNameScope scope = new _LocalNameScope(null);
+    for (CompilationUnitMember declaration in node.declarations) {
+      if (declaration is NamedCompilationUnitMember) {
+        scope.add(declaration.name);
+      } else if (declaration is TopLevelVariableDeclaration) {
+        scope.addVariableNames(declaration.variables);
+      }
+    }
+    return scope;
+  }
+
+  void add(SimpleIdentifier identifier) {
+    if (identifier != null) {
+      names ??= new Set<String>();
+      names.add(identifier.name);
+    }
+  }
+
+  void addFormalParameters(FormalParameterList parameterList) {
+    if (parameterList != null) {
+      parameterList.parameters
+          .map((p) => p is NormalFormalParameter ? p.identifier : null)
+          .forEach(add);
+    }
+  }
+
+  void addTypeParameters(TypeParameterList typeParameterList) {
+    if (typeParameterList != null) {
+      typeParameterList.typeParameters.map((p) => p.name).forEach(add);
+    }
+  }
+
+  void addVariableNames(VariableDeclarationList variableList) {
+    for (VariableDeclaration variable in variableList.variables) {
+      add(variable.name);
+    }
+  }
+
+  bool contains(String name) {
+    if (names != null && names.contains(name)) {
+      return true;
+    }
+    if (enclosing != null) {
+      return enclosing.contains(name);
+    }
+    return false;
+  }
+}
+
+class _ReferencedNamesComputer extends GeneralizingAstVisitor {
+  final Set<String> names = new Set<String>();
+  final Set<String> importPrefixNames = new Set<String>();
+
+  _LocalNameScope localScope = new _LocalNameScope(null);
+
+  @override
+  visitBlock(Block node) {
+    _LocalNameScope outerScope = localScope;
+    try {
+      localScope = new _LocalNameScope.forBlock(localScope, node);
+      super.visitBlock(node);
+    } finally {
+      localScope = outerScope;
+    }
+  }
+
+  @override
+  visitClassDeclaration(ClassDeclaration node) {
+    _LocalNameScope outerScope = localScope;
+    try {
+      localScope = new _LocalNameScope.forClass(localScope, node);
+      super.visitClassDeclaration(node);
+    } finally {
+      localScope = outerScope;
+    }
+  }
+
+  @override
+  visitClassTypeAlias(ClassTypeAlias node) {
+    _LocalNameScope outerScope = localScope;
+    try {
+      localScope = new _LocalNameScope.forClassTypeAlias(localScope, node);
+      super.visitClassTypeAlias(node);
+    } finally {
+      localScope = outerScope;
+    }
+  }
+
+  @override
+  visitCompilationUnit(CompilationUnit node) {
+    localScope = new _LocalNameScope.forUnit(node);
+    super.visitCompilationUnit(node);
+  }
+
+  @override
+  visitConstructorName(ConstructorName node) {
+    if (node.parent is! ConstructorDeclaration) {
+      super.visitConstructorName(node);
+    }
+  }
+
+  @override
+  visitFunctionDeclaration(FunctionDeclaration node) {
+    _LocalNameScope outerScope = localScope;
+    try {
+      localScope = new _LocalNameScope.forFunction(localScope, node);
+      super.visitFunctionDeclaration(node);
+    } finally {
+      localScope = outerScope;
+    }
+  }
+
+  @override
+  visitFunctionTypeAlias(FunctionTypeAlias node) {
+    _LocalNameScope outerScope = localScope;
+    try {
+      localScope = new _LocalNameScope.forFunctionTypeAlias(localScope, node);
+      super.visitFunctionTypeAlias(node);
+    } finally {
+      localScope = outerScope;
+    }
+  }
+
+  @override
+  visitImportDirective(ImportDirective node) {
+    if (node.prefix != null) {
+      importPrefixNames.add(node.prefix.name);
+    }
+    super.visitImportDirective(node);
+  }
+
+  @override
+  visitMethodDeclaration(MethodDeclaration node) {
+    _LocalNameScope outerScope = localScope;
+    try {
+      localScope = new _LocalNameScope.forMethod(localScope, node);
+      super.visitMethodDeclaration(node);
+    } finally {
+      localScope = outerScope;
+    }
+  }
+
+  @override
+  visitSimpleIdentifier(SimpleIdentifier node) {
+    // Ignore all declarations.
+    if (node.inDeclarationContext()) {
+      return;
+    }
+    // Ignore class names references from constructors.
+    AstNode parent = node.parent;
+    if (parent is ConstructorDeclaration && parent.returnType == node) {
+      return;
+    }
+    // Prepare name.
+    String name = node.name;
+    // Ignore unqualified names shadowed by local elements.
+    if (!node.isQualified) {
+      if (localScope.contains(name)) {
+        return;
+      }
+      if (importPrefixNames.contains(name)) {
+        return;
+      }
+    }
+    // Do add the name.
+    names.add(name);
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index dbb50df..3ec4819 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -2336,7 +2336,7 @@
    * If this element is resynthesized from the summary, return the unlinked
    * initializer, otherwise return `null`.
    */
-  UnlinkedConst get _unlinkedConst;
+  UnlinkedExpr get _unlinkedConst;
 
   /**
    * Return a representation of the value of this variable, forcing the value
@@ -3129,7 +3129,7 @@
    * Return annotations for the given [unlinkedConsts] in the [unit].
    */
   List<ElementAnnotation> _buildAnnotations(
-      CompilationUnitElementImpl unit, List<UnlinkedConst> unlinkedConsts) {
+      CompilationUnitElementImpl unit, List<UnlinkedExpr> unlinkedConsts) {
     int length = unlinkedConsts.length;
     if (length != 0) {
       List<ElementAnnotation> annotations = new List<ElementAnnotation>(length);
@@ -3143,7 +3143,7 @@
     }
   }
 
-  static int _findElementIndexUsingIdentical(List items, Object item) {
+  static int findElementIndexUsingIdentical(List items, Object item) {
     int length = items.length;
     for (int i = 0; i < length; i++) {
       if (identical(items[i], item)) {
@@ -4387,8 +4387,8 @@
     String identifier = super.identifier;
     Element enclosing = this.enclosingElement;
     if (enclosing is ExecutableElement) {
-      int id = ElementImpl._findElementIndexUsingIdentical(
-          enclosing.functions, this);
+      int id =
+          ElementImpl.findElementIndexUsingIdentical(enclosing.functions, this);
       identifier += "@$id";
     }
     return identifier;
@@ -6046,7 +6046,7 @@
     String identifier = super.identifier;
     Element enclosing = this.enclosingElement;
     if (enclosing is ExecutableElement) {
-      int id = ElementImpl._findElementIndexUsingIdentical(
+      int id = ElementImpl.findElementIndexUsingIdentical(
           enclosing.localVariables, this);
       identifier += "@$id";
     }
@@ -6811,7 +6811,7 @@
   /**
    * Subclasses need this getter, see [ConstVariableElement._unlinkedConst].
    */
-  UnlinkedConst get _unlinkedConst => _unlinkedVariable?.initializer?.bodyExpr;
+  UnlinkedExpr get _unlinkedConst => _unlinkedVariable?.initializer?.bodyExpr;
 }
 
 /**
@@ -7178,7 +7178,7 @@
   /**
    * Subclasses need this getter, see [ConstVariableElement._unlinkedConst].
    */
-  UnlinkedConst get _unlinkedConst => _unlinkedParam?.initializer?.bodyExpr;
+  UnlinkedExpr get _unlinkedConst => _unlinkedParam?.initializer?.bodyExpr;
 
   @override
   accept(ElementVisitor visitor) => visitor.visitParameterElement(this);
@@ -7760,14 +7760,14 @@
  */
 abstract class ResynthesizerContext {
   /**
-   * Build [ElementAnnotationImpl] for the given [UnlinkedConst].
+   * Build [ElementAnnotationImpl] for the given [UnlinkedExpr].
    */
-  ElementAnnotationImpl buildAnnotation(ElementImpl context, UnlinkedConst uc);
+  ElementAnnotationImpl buildAnnotation(ElementImpl context, UnlinkedExpr uc);
 
   /**
-   * Build [Expression] for the given [UnlinkedConst].
+   * Build [Expression] for the given [UnlinkedExpr].
    */
-  Expression buildExpression(ElementImpl context, UnlinkedConst uc);
+  Expression buildExpression(ElementImpl context, UnlinkedExpr uc);
 
   /**
    * Build explicit top-level property accessors.
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index d9914a2..a81585b 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -326,12 +326,12 @@
    * that do not invoke the overridden super method.
    *
    * Parameters:
-   * 0: the name of the class declaring the overriden method
+   * 0: the name of the class declaring the overridden method
    */
   static const HintCode MUST_CALL_SUPER = const HintCode(
       'MUST_CALL_SUPER',
-      "This method overrides a method annotated as @mustCall super in '{0}', "
-      "but does invoke the overriden method.");
+      "This method overrides a method annotated as @mustCallSuper in '{0}', "
+      "but does invoke the overridden method.");
 
   /**
    * A condition in a control flow statement could evaluate to `null` because it
diff --git a/pkg/analyzer/lib/src/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
index 6dd6c16..db0eb79 100644
--- a/pkg/analyzer/lib/src/generated/constant.dart
+++ b/pkg/analyzer/lib/src/generated/constant.dart
@@ -97,7 +97,6 @@
 /// In addition, this class defines several values that can be returned to
 /// indicate various conditions encountered during evaluation. These are
 /// documented with the static fields that define those values.
-@deprecated
 class ConstantEvaluator {
   /**
    * The source containing the expression(s) that will be evaluated.
diff --git a/pkg/analyzer/lib/src/generated/declaration_resolver.dart b/pkg/analyzer/lib/src/generated/declaration_resolver.dart
index 595acb9..90f3483 100644
--- a/pkg/analyzer/lib/src/generated/declaration_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/declaration_resolver.dart
@@ -154,8 +154,17 @@
   @override
   Object visitExportDirective(ExportDirective node) {
     super.visitExportDirective(node);
-    _resolveAnnotations(
-        node, node.metadata, _enclosingUnit.getAnnotations(node.offset));
+    List<ElementAnnotation> annotations =
+        _enclosingUnit.getAnnotations(node.offset);
+    if (annotations.isEmpty && node.metadata.isNotEmpty) {
+      int index = (node.parent as CompilationUnit)
+          .directives
+          .where((directive) => directive is ExportDirective)
+          .toList()
+          .indexOf(node);
+      annotations = _walker.element.library.exports[index].metadata;
+    }
+    _resolveAnnotations(node, node.metadata, annotations);
     return null;
   }
 
@@ -263,8 +272,17 @@
   @override
   Object visitImportDirective(ImportDirective node) {
     super.visitImportDirective(node);
-    _resolveAnnotations(
-        node, node.metadata, _enclosingUnit.getAnnotations(node.offset));
+    List<ElementAnnotation> annotations =
+        _enclosingUnit.getAnnotations(node.offset);
+    if (annotations.isEmpty && node.metadata.isNotEmpty) {
+      int index = (node.parent as CompilationUnit)
+          .directives
+          .where((directive) => directive is ImportDirective)
+          .toList()
+          .indexOf(node);
+      annotations = _walker.element.library.imports[index].metadata;
+    }
+    _resolveAnnotations(node, node.metadata, annotations);
     return null;
   }
 
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 6a78ba5..9576b15 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -1290,7 +1290,7 @@
 
   @override
   @deprecated
-  int cacheSize = DEFAULT_CACHE_SIZE;
+  int cacheSize = 64;
 
   @override
   bool dart2jsHint = false;
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index a608bad..0291fde 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -298,8 +298,9 @@
    * parameters, followed by a left-parenthesis. This is used by
    * [parseTypeAlias] to determine whether or not to parse a return type.
    */
-  @deprecated
   bool get hasReturnTypeInTypeAlias {
+    // TODO(brianwilkerson) This is too expensive as implemented and needs to be
+    // re-implemented or removed.
     Token next = skipReturnType(_currentToken);
     if (next == null) {
       return false;
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 8208abb..b345876 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -8669,7 +8669,7 @@
   /**
    * A table mapping elements to the overridden type of that element.
    */
-  Map<VariableElement, DartType> _overridenTypes =
+  Map<VariableElement, DartType> _overriddenTypes =
       new HashMap<VariableElement, DartType>();
 
   /**
@@ -8685,7 +8685,7 @@
    * @param overrides the overrides to be applied
    */
   void applyOverrides(Map<VariableElement, DartType> overrides) {
-    _overridenTypes.addAll(overrides);
+    _overriddenTypes.addAll(overrides);
   }
 
   /**
@@ -8694,7 +8694,7 @@
    *
    * @return the overrides in the current scope
    */
-  Map<VariableElement, DartType> captureLocalOverrides() => _overridenTypes;
+  Map<VariableElement, DartType> captureLocalOverrides() => _overriddenTypes;
 
   /**
    * Return a map from the elements for the variables in the given list that have their types
@@ -8711,7 +8711,7 @@
       for (VariableDeclaration variable in variableList.variables) {
         VariableElement element = variable.element;
         if (element != null) {
-          DartType type = _overridenTypes[element];
+          DartType type = _overriddenTypes[element];
           if (type != null) {
             overrides[element] = type;
           }
@@ -8731,8 +8731,8 @@
   DartType getType(Element element) {
     Element nonAccessor =
         element is PropertyAccessorElement ? element.variable : element;
-    DartType type = _overridenTypes[nonAccessor];
-    if (_overridenTypes.containsKey(nonAccessor)) {
+    DartType type = _overriddenTypes[nonAccessor];
+    if (_overriddenTypes.containsKey(nonAccessor)) {
       return type;
     }
     return type ?? _outerScope?.getType(element);
@@ -8742,7 +8742,7 @@
    * Clears the overridden type of the given [element].
    */
   void resetType(VariableElement element) {
-    _overridenTypes[element] = null;
+    _overriddenTypes[element] = null;
   }
 
   /**
@@ -8752,7 +8752,7 @@
    * @param type the overridden type of the given element
    */
   void setType(VariableElement element, DartType type) {
-    _overridenTypes[element] = type;
+    _overriddenTypes[element] = type;
   }
 }
 
diff --git a/pkg/analyzer/lib/src/generated/sdk.dart b/pkg/analyzer/lib/src/generated/sdk.dart
index a03afbe..397fb9d 100644
--- a/pkg/analyzer/lib/src/generated/sdk.dart
+++ b/pkg/analyzer/lib/src/generated/sdk.dart
@@ -120,7 +120,8 @@
   /**
    * Initialize a newly created manager.
    */
-  DartSdkManager(this.defaultSdkDirectory, this.canUseSummaries);
+  DartSdkManager(this.defaultSdkDirectory, this.canUseSummaries,
+      [dynamic ignored]);
 
   /**
    * Return any SDK that has been created, or `null` if no SDKs have been
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 3cbfe97..1d91db3 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -64,19 +64,6 @@
   }
 }
 
-class _UnlinkedConstOperationReader extends fb.Reader<idl.UnlinkedConstOperation> {
-  const _UnlinkedConstOperationReader() : super();
-
-  @override
-  int get size => 1;
-
-  @override
-  idl.UnlinkedConstOperation read(fb.BufferContext bc, int offset) {
-    int index = const fb.Uint8Reader().read(bc, offset);
-    return index < idl.UnlinkedConstOperation.values.length ? idl.UnlinkedConstOperation.values[index] : idl.UnlinkedConstOperation.pushInt;
-  }
-}
-
 class _UnlinkedConstructorInitializerKindReader extends fb.Reader<idl.UnlinkedConstructorInitializerKind> {
   const _UnlinkedConstructorInitializerKindReader() : super();
 
@@ -116,6 +103,19 @@
   }
 }
 
+class _UnlinkedExprOperationReader extends fb.Reader<idl.UnlinkedExprOperation> {
+  const _UnlinkedExprOperationReader() : super();
+
+  @override
+  int get size => 1;
+
+  @override
+  idl.UnlinkedExprOperation read(fb.BufferContext bc, int offset) {
+    int index = const fb.Uint8Reader().read(bc, offset);
+    return index < idl.UnlinkedExprOperation.values.length ? idl.UnlinkedExprOperation.values[index] : idl.UnlinkedExprOperation.pushInt;
+  }
+}
+
 class _UnlinkedParamKindReader extends fb.Reader<idl.UnlinkedParamKind> {
   const _UnlinkedParamKindReader() : super();
 
@@ -3425,7 +3425,7 @@
 }
 
 class UnlinkedClassBuilder extends Object with _UnlinkedClassMixin implements idl.UnlinkedClass {
-  List<UnlinkedConstBuilder> _annotations;
+  List<UnlinkedExprBuilder> _annotations;
   CodeRangeBuilder _codeRange;
   UnlinkedDocumentationCommentBuilder _documentationComment;
   List<UnlinkedExecutableBuilder> _executables;
@@ -3441,12 +3441,12 @@
   List<UnlinkedTypeParamBuilder> _typeParameters;
 
   @override
-  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+  List<UnlinkedExprBuilder> get annotations => _annotations ??= <UnlinkedExprBuilder>[];
 
   /**
    * Annotations for this class.
    */
-  void set annotations(List<UnlinkedConstBuilder> value) {
+  void set annotations(List<UnlinkedExprBuilder> value) {
     this._annotations = value;
   }
 
@@ -3585,7 +3585,7 @@
     this._typeParameters = value;
   }
 
-  UnlinkedClassBuilder({List<UnlinkedConstBuilder> annotations, CodeRangeBuilder codeRange, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedExecutableBuilder> executables, List<UnlinkedVariableBuilder> fields, bool hasNoSupertype, List<EntityRefBuilder> interfaces, bool isAbstract, bool isMixinApplication, List<EntityRefBuilder> mixins, String name, int nameOffset, EntityRefBuilder supertype, List<UnlinkedTypeParamBuilder> typeParameters})
+  UnlinkedClassBuilder({List<UnlinkedExprBuilder> annotations, CodeRangeBuilder codeRange, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedExecutableBuilder> executables, List<UnlinkedVariableBuilder> fields, bool hasNoSupertype, List<EntityRefBuilder> interfaces, bool isAbstract, bool isMixinApplication, List<EntityRefBuilder> mixins, String name, int nameOffset, EntityRefBuilder supertype, List<UnlinkedTypeParamBuilder> typeParameters})
     : _annotations = annotations,
       _codeRange = codeRange,
       _documentationComment = documentationComment,
@@ -3778,7 +3778,7 @@
 
   _UnlinkedClassImpl(this._bc, this._bcOffset);
 
-  List<idl.UnlinkedConst> _annotations;
+  List<idl.UnlinkedExpr> _annotations;
   idl.CodeRange _codeRange;
   idl.UnlinkedDocumentationComment _documentationComment;
   List<idl.UnlinkedExecutable> _executables;
@@ -3794,8 +3794,8 @@
   List<idl.UnlinkedTypeParam> _typeParameters;
 
   @override
-  List<idl.UnlinkedConst> get annotations {
-    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bc, _bcOffset, 5, const <idl.UnlinkedConst>[]);
+  List<idl.UnlinkedExpr> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedExpr>(const _UnlinkedExprReader()).vTableGet(_bc, _bcOffset, 5, const <idl.UnlinkedExpr>[]);
     return _annotations;
   }
 
@@ -4240,313 +4240,10 @@
   String toString() => convert.JSON.encode(toJson());
 }
 
-class UnlinkedConstBuilder extends Object with _UnlinkedConstMixin implements idl.UnlinkedConst {
-  List<idl.UnlinkedExprAssignOperator> _assignmentOperators;
-  List<double> _doubles;
-  List<int> _ints;
-  bool _isValidConst;
-  List<idl.UnlinkedConstOperation> _operations;
-  List<EntityRefBuilder> _references;
-  List<String> _strings;
-
-  @override
-  List<idl.UnlinkedExprAssignOperator> get assignmentOperators => _assignmentOperators ??= <idl.UnlinkedExprAssignOperator>[];
-
-  /**
-   * Sequence of operators used by assignment operations.
-   */
-  void set assignmentOperators(List<idl.UnlinkedExprAssignOperator> value) {
-    this._assignmentOperators = value;
-  }
-
-  @override
-  List<double> get doubles => _doubles ??= <double>[];
-
-  /**
-   * Sequence of 64-bit doubles consumed by the operation `pushDouble`.
-   */
-  void set doubles(List<double> value) {
-    this._doubles = value;
-  }
-
-  @override
-  List<int> get ints => _ints ??= <int>[];
-
-  /**
-   * Sequence of unsigned 32-bit integers consumed by the operations
-   * `pushArgument`, `pushInt`, `shiftOr`, `concatenate`, `invokeConstructor`,
-   * `makeList`, and `makeMap`.
-   */
-  void set ints(List<int> value) {
-    assert(value == null || value.every((e) => e >= 0));
-    this._ints = value;
-  }
-
-  @override
-  bool get isValidConst => _isValidConst ??= false;
-
-  /**
-   * Indicates whether the expression is a valid potentially constant
-   * expression.
-   */
-  void set isValidConst(bool value) {
-    this._isValidConst = value;
-  }
-
-  @override
-  List<idl.UnlinkedConstOperation> get operations => _operations ??= <idl.UnlinkedConstOperation>[];
-
-  /**
-   * Sequence of operations to execute (starting with an empty stack) to form
-   * the constant value.
-   */
-  void set operations(List<idl.UnlinkedConstOperation> value) {
-    this._operations = value;
-  }
-
-  @override
-  List<EntityRefBuilder> get references => _references ??= <EntityRefBuilder>[];
-
-  /**
-   * Sequence of language constructs consumed by the operations
-   * `pushReference`, `invokeConstructor`, `makeList`, and `makeMap`.  Note
-   * that in the case of `pushReference` (and sometimes `invokeConstructor` the
-   * actual entity being referred to may be something other than a type.
-   */
-  void set references(List<EntityRefBuilder> value) {
-    this._references = value;
-  }
-
-  @override
-  List<String> get strings => _strings ??= <String>[];
-
-  /**
-   * Sequence of strings consumed by the operations `pushString` and
-   * `invokeConstructor`.
-   */
-  void set strings(List<String> value) {
-    this._strings = value;
-  }
-
-  UnlinkedConstBuilder({List<idl.UnlinkedExprAssignOperator> assignmentOperators, List<double> doubles, List<int> ints, bool isValidConst, List<idl.UnlinkedConstOperation> operations, List<EntityRefBuilder> references, List<String> strings})
-    : _assignmentOperators = assignmentOperators,
-      _doubles = doubles,
-      _ints = ints,
-      _isValidConst = isValidConst,
-      _operations = operations,
-      _references = references,
-      _strings = strings;
-
-  /**
-   * Flush [informative] data recursively.
-   */
-  void flushInformative() {
-    _references?.forEach((b) => b.flushInformative());
-  }
-
-  /**
-   * Accumulate non-[informative] data into [signature].
-   */
-  void collectApiSignature(api_sig.ApiSignature signature) {
-    if (this._operations == null) {
-      signature.addInt(0);
-    } else {
-      signature.addInt(this._operations.length);
-      for (var x in this._operations) {
-        signature.addInt(x.index);
-      }
-    }
-    if (this._ints == null) {
-      signature.addInt(0);
-    } else {
-      signature.addInt(this._ints.length);
-      for (var x in this._ints) {
-        signature.addInt(x);
-      }
-    }
-    if (this._references == null) {
-      signature.addInt(0);
-    } else {
-      signature.addInt(this._references.length);
-      for (var x in this._references) {
-        x?.collectApiSignature(signature);
-      }
-    }
-    if (this._strings == null) {
-      signature.addInt(0);
-    } else {
-      signature.addInt(this._strings.length);
-      for (var x in this._strings) {
-        signature.addString(x);
-      }
-    }
-    if (this._doubles == null) {
-      signature.addInt(0);
-    } else {
-      signature.addInt(this._doubles.length);
-      for (var x in this._doubles) {
-        signature.addDouble(x);
-      }
-    }
-    signature.addBool(this._isValidConst == true);
-    if (this._assignmentOperators == null) {
-      signature.addInt(0);
-    } else {
-      signature.addInt(this._assignmentOperators.length);
-      for (var x in this._assignmentOperators) {
-        signature.addInt(x.index);
-      }
-    }
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    fb.Offset offset_assignmentOperators;
-    fb.Offset offset_doubles;
-    fb.Offset offset_ints;
-    fb.Offset offset_operations;
-    fb.Offset offset_references;
-    fb.Offset offset_strings;
-    if (!(_assignmentOperators == null || _assignmentOperators.isEmpty)) {
-      offset_assignmentOperators = fbBuilder.writeListUint8(_assignmentOperators.map((b) => b.index).toList());
-    }
-    if (!(_doubles == null || _doubles.isEmpty)) {
-      offset_doubles = fbBuilder.writeListFloat64(_doubles);
-    }
-    if (!(_ints == null || _ints.isEmpty)) {
-      offset_ints = fbBuilder.writeListUint32(_ints);
-    }
-    if (!(_operations == null || _operations.isEmpty)) {
-      offset_operations = fbBuilder.writeListUint8(_operations.map((b) => b.index).toList());
-    }
-    if (!(_references == null || _references.isEmpty)) {
-      offset_references = fbBuilder.writeList(_references.map((b) => b.finish(fbBuilder)).toList());
-    }
-    if (!(_strings == null || _strings.isEmpty)) {
-      offset_strings = fbBuilder.writeList(_strings.map((b) => fbBuilder.writeString(b)).toList());
-    }
-    fbBuilder.startTable();
-    if (offset_assignmentOperators != null) {
-      fbBuilder.addOffset(6, offset_assignmentOperators);
-    }
-    if (offset_doubles != null) {
-      fbBuilder.addOffset(4, offset_doubles);
-    }
-    if (offset_ints != null) {
-      fbBuilder.addOffset(1, offset_ints);
-    }
-    if (_isValidConst == true) {
-      fbBuilder.addBool(5, true);
-    }
-    if (offset_operations != null) {
-      fbBuilder.addOffset(0, offset_operations);
-    }
-    if (offset_references != null) {
-      fbBuilder.addOffset(2, offset_references);
-    }
-    if (offset_strings != null) {
-      fbBuilder.addOffset(3, offset_strings);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-class _UnlinkedConstReader extends fb.TableReader<_UnlinkedConstImpl> {
-  const _UnlinkedConstReader();
-
-  @override
-  _UnlinkedConstImpl createObject(fb.BufferContext bc, int offset) => new _UnlinkedConstImpl(bc, offset);
-}
-
-class _UnlinkedConstImpl extends Object with _UnlinkedConstMixin implements idl.UnlinkedConst {
-  final fb.BufferContext _bc;
-  final int _bcOffset;
-
-  _UnlinkedConstImpl(this._bc, this._bcOffset);
-
-  List<idl.UnlinkedExprAssignOperator> _assignmentOperators;
-  List<double> _doubles;
-  List<int> _ints;
-  bool _isValidConst;
-  List<idl.UnlinkedConstOperation> _operations;
-  List<idl.EntityRef> _references;
-  List<String> _strings;
-
-  @override
-  List<idl.UnlinkedExprAssignOperator> get assignmentOperators {
-    _assignmentOperators ??= const fb.ListReader<idl.UnlinkedExprAssignOperator>(const _UnlinkedExprAssignOperatorReader()).vTableGet(_bc, _bcOffset, 6, const <idl.UnlinkedExprAssignOperator>[]);
-    return _assignmentOperators;
-  }
-
-  @override
-  List<double> get doubles {
-    _doubles ??= const fb.Float64ListReader().vTableGet(_bc, _bcOffset, 4, const <double>[]);
-    return _doubles;
-  }
-
-  @override
-  List<int> get ints {
-    _ints ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 1, const <int>[]);
-    return _ints;
-  }
-
-  @override
-  bool get isValidConst {
-    _isValidConst ??= const fb.BoolReader().vTableGet(_bc, _bcOffset, 5, false);
-    return _isValidConst;
-  }
-
-  @override
-  List<idl.UnlinkedConstOperation> get operations {
-    _operations ??= const fb.ListReader<idl.UnlinkedConstOperation>(const _UnlinkedConstOperationReader()).vTableGet(_bc, _bcOffset, 0, const <idl.UnlinkedConstOperation>[]);
-    return _operations;
-  }
-
-  @override
-  List<idl.EntityRef> get references {
-    _references ??= const fb.ListReader<idl.EntityRef>(const _EntityRefReader()).vTableGet(_bc, _bcOffset, 2, const <idl.EntityRef>[]);
-    return _references;
-  }
-
-  @override
-  List<String> get strings {
-    _strings ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bc, _bcOffset, 3, const <String>[]);
-    return _strings;
-  }
-}
-
-abstract class _UnlinkedConstMixin implements idl.UnlinkedConst {
-  @override
-  Map<String, Object> toJson() {
-    Map<String, Object> _result = <String, Object>{};
-    if (assignmentOperators.isNotEmpty) _result["assignmentOperators"] = assignmentOperators.map((_value) => _value.toString().split('.')[1]).toList();
-    if (doubles.isNotEmpty) _result["doubles"] = doubles.map((_value) => _value.isFinite ? _value : _value.toString()).toList();
-    if (ints.isNotEmpty) _result["ints"] = ints;
-    if (isValidConst != false) _result["isValidConst"] = isValidConst;
-    if (operations.isNotEmpty) _result["operations"] = operations.map((_value) => _value.toString().split('.')[1]).toList();
-    if (references.isNotEmpty) _result["references"] = references.map((_value) => _value.toJson()).toList();
-    if (strings.isNotEmpty) _result["strings"] = strings;
-    return _result;
-  }
-
-  @override
-  Map<String, Object> toMap() => {
-    "assignmentOperators": assignmentOperators,
-    "doubles": doubles,
-    "ints": ints,
-    "isValidConst": isValidConst,
-    "operations": operations,
-    "references": references,
-    "strings": strings,
-  };
-
-  @override
-  String toString() => convert.JSON.encode(toJson());
-}
-
 class UnlinkedConstructorInitializerBuilder extends Object with _UnlinkedConstructorInitializerMixin implements idl.UnlinkedConstructorInitializer {
   List<String> _argumentNames;
-  List<UnlinkedConstBuilder> _arguments;
-  UnlinkedConstBuilder _expression;
+  List<UnlinkedExprBuilder> _arguments;
+  UnlinkedExprBuilder _expression;
   idl.UnlinkedConstructorInitializerKind _kind;
   String _name;
 
@@ -4563,24 +4260,24 @@
   }
 
   @override
-  List<UnlinkedConstBuilder> get arguments => _arguments ??= <UnlinkedConstBuilder>[];
+  List<UnlinkedExprBuilder> get arguments => _arguments ??= <UnlinkedExprBuilder>[];
 
   /**
    * If [kind] is `thisInvocation` or `superInvocation`, the arguments of the
    * invocation.  Otherwise empty.
    */
-  void set arguments(List<UnlinkedConstBuilder> value) {
+  void set arguments(List<UnlinkedExprBuilder> value) {
     this._arguments = value;
   }
 
   @override
-  UnlinkedConstBuilder get expression => _expression;
+  UnlinkedExprBuilder get expression => _expression;
 
   /**
    * If [kind] is `field`, the expression of the field initializer.
    * Otherwise `null`.
    */
-  void set expression(UnlinkedConstBuilder value) {
+  void set expression(UnlinkedExprBuilder value) {
     this._expression = value;
   }
 
@@ -4607,7 +4304,7 @@
     this._name = value;
   }
 
-  UnlinkedConstructorInitializerBuilder({List<String> argumentNames, List<UnlinkedConstBuilder> arguments, UnlinkedConstBuilder expression, idl.UnlinkedConstructorInitializerKind kind, String name})
+  UnlinkedConstructorInitializerBuilder({List<String> argumentNames, List<UnlinkedExprBuilder> arguments, UnlinkedExprBuilder expression, idl.UnlinkedConstructorInitializerKind kind, String name})
     : _argumentNames = argumentNames,
       _arguments = arguments,
       _expression = expression,
@@ -4699,8 +4396,8 @@
   _UnlinkedConstructorInitializerImpl(this._bc, this._bcOffset);
 
   List<String> _argumentNames;
-  List<idl.UnlinkedConst> _arguments;
-  idl.UnlinkedConst _expression;
+  List<idl.UnlinkedExpr> _arguments;
+  idl.UnlinkedExpr _expression;
   idl.UnlinkedConstructorInitializerKind _kind;
   String _name;
 
@@ -4711,14 +4408,14 @@
   }
 
   @override
-  List<idl.UnlinkedConst> get arguments {
-    _arguments ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bc, _bcOffset, 3, const <idl.UnlinkedConst>[]);
+  List<idl.UnlinkedExpr> get arguments {
+    _arguments ??= const fb.ListReader<idl.UnlinkedExpr>(const _UnlinkedExprReader()).vTableGet(_bc, _bcOffset, 3, const <idl.UnlinkedExpr>[]);
     return _arguments;
   }
 
   @override
-  idl.UnlinkedConst get expression {
-    _expression ??= const _UnlinkedConstReader().vTableGet(_bc, _bcOffset, 1, null);
+  idl.UnlinkedExpr get expression {
+    _expression ??= const _UnlinkedExprReader().vTableGet(_bc, _bcOffset, 1, null);
     return _expression;
   }
 
@@ -4857,7 +4554,7 @@
 }
 
 class UnlinkedEnumBuilder extends Object with _UnlinkedEnumMixin implements idl.UnlinkedEnum {
-  List<UnlinkedConstBuilder> _annotations;
+  List<UnlinkedExprBuilder> _annotations;
   CodeRangeBuilder _codeRange;
   UnlinkedDocumentationCommentBuilder _documentationComment;
   String _name;
@@ -4865,12 +4562,12 @@
   List<UnlinkedEnumValueBuilder> _values;
 
   @override
-  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+  List<UnlinkedExprBuilder> get annotations => _annotations ??= <UnlinkedExprBuilder>[];
 
   /**
    * Annotations for this enum.
    */
-  void set annotations(List<UnlinkedConstBuilder> value) {
+  void set annotations(List<UnlinkedExprBuilder> value) {
     this._annotations = value;
   }
 
@@ -4926,7 +4623,7 @@
     this._values = value;
   }
 
-  UnlinkedEnumBuilder({List<UnlinkedConstBuilder> annotations, CodeRangeBuilder codeRange, UnlinkedDocumentationCommentBuilder documentationComment, String name, int nameOffset, List<UnlinkedEnumValueBuilder> values})
+  UnlinkedEnumBuilder({List<UnlinkedExprBuilder> annotations, CodeRangeBuilder codeRange, UnlinkedDocumentationCommentBuilder documentationComment, String name, int nameOffset, List<UnlinkedEnumValueBuilder> values})
     : _annotations = annotations,
       _codeRange = codeRange,
       _documentationComment = documentationComment,
@@ -5025,7 +4722,7 @@
 
   _UnlinkedEnumImpl(this._bc, this._bcOffset);
 
-  List<idl.UnlinkedConst> _annotations;
+  List<idl.UnlinkedExpr> _annotations;
   idl.CodeRange _codeRange;
   idl.UnlinkedDocumentationComment _documentationComment;
   String _name;
@@ -5033,8 +4730,8 @@
   List<idl.UnlinkedEnumValue> _values;
 
   @override
-  List<idl.UnlinkedConst> get annotations {
-    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bc, _bcOffset, 4, const <idl.UnlinkedConst>[]);
+  List<idl.UnlinkedExpr> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedExpr>(const _UnlinkedExprReader()).vTableGet(_bc, _bcOffset, 4, const <idl.UnlinkedExpr>[]);
     return _annotations;
   }
 
@@ -5234,8 +4931,8 @@
 }
 
 class UnlinkedExecutableBuilder extends Object with _UnlinkedExecutableMixin implements idl.UnlinkedExecutable {
-  List<UnlinkedConstBuilder> _annotations;
-  UnlinkedConstBuilder _bodyExpr;
+  List<UnlinkedExprBuilder> _annotations;
+  UnlinkedExprBuilder _bodyExpr;
   CodeRangeBuilder _codeRange;
   List<UnlinkedConstructorInitializerBuilder> _constantInitializers;
   int _constCycleSlot;
@@ -5266,24 +4963,24 @@
   int _visibleOffset;
 
   @override
-  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+  List<UnlinkedExprBuilder> get annotations => _annotations ??= <UnlinkedExprBuilder>[];
 
   /**
    * Annotations for this executable.
    */
-  void set annotations(List<UnlinkedConstBuilder> value) {
+  void set annotations(List<UnlinkedExprBuilder> value) {
     this._annotations = value;
   }
 
   @override
-  UnlinkedConstBuilder get bodyExpr => _bodyExpr;
+  UnlinkedExprBuilder get bodyExpr => _bodyExpr;
 
   /**
    * If this executable's function body is declared using `=>`, the expression
    * to the right of the `=>`.  May be omitted if neither type inference nor
    * constant evaluation depends on the function body.
    */
-  void set bodyExpr(UnlinkedConstBuilder value) {
+  void set bodyExpr(UnlinkedExprBuilder value) {
     this._bodyExpr = value;
   }
 
@@ -5607,7 +5304,7 @@
     this._visibleOffset = value;
   }
 
-  UnlinkedExecutableBuilder({List<UnlinkedConstBuilder> annotations, UnlinkedConstBuilder bodyExpr, CodeRangeBuilder codeRange, List<UnlinkedConstructorInitializerBuilder> constantInitializers, int constCycleSlot, UnlinkedDocumentationCommentBuilder documentationComment, int inferredReturnTypeSlot, bool isAbstract, bool isAsynchronous, bool isConst, bool isExternal, bool isFactory, bool isGenerator, bool isRedirectedConstructor, bool isStatic, idl.UnlinkedExecutableKind kind, List<UnlinkedExecutableBuilder> localFunctions, List<UnlinkedLabelBuilder> localLabels, List<UnlinkedVariableBuilder> localVariables, String name, int nameEnd, int nameOffset, List<UnlinkedParamBuilder> parameters, int periodOffset, EntityRefBuilder redirectedConstructor, String redirectedConstructorName, EntityRefBuilder returnType, List<UnlinkedTypeParamBuilder> typeParameters, int visibleLength, int visibleOffset})
+  UnlinkedExecutableBuilder({List<UnlinkedExprBuilder> annotations, UnlinkedExprBuilder bodyExpr, CodeRangeBuilder codeRange, List<UnlinkedConstructorInitializerBuilder> constantInitializers, int constCycleSlot, UnlinkedDocumentationCommentBuilder documentationComment, int inferredReturnTypeSlot, bool isAbstract, bool isAsynchronous, bool isConst, bool isExternal, bool isFactory, bool isGenerator, bool isRedirectedConstructor, bool isStatic, idl.UnlinkedExecutableKind kind, List<UnlinkedExecutableBuilder> localFunctions, List<UnlinkedLabelBuilder> localLabels, List<UnlinkedVariableBuilder> localVariables, String name, int nameEnd, int nameOffset, List<UnlinkedParamBuilder> parameters, int periodOffset, EntityRefBuilder redirectedConstructor, String redirectedConstructorName, EntityRefBuilder returnType, List<UnlinkedTypeParamBuilder> typeParameters, int visibleLength, int visibleOffset})
     : _annotations = annotations,
       _bodyExpr = bodyExpr,
       _codeRange = codeRange,
@@ -5892,8 +5589,8 @@
 
   _UnlinkedExecutableImpl(this._bc, this._bcOffset);
 
-  List<idl.UnlinkedConst> _annotations;
-  idl.UnlinkedConst _bodyExpr;
+  List<idl.UnlinkedExpr> _annotations;
+  idl.UnlinkedExpr _bodyExpr;
   idl.CodeRange _codeRange;
   List<idl.UnlinkedConstructorInitializer> _constantInitializers;
   int _constCycleSlot;
@@ -5924,14 +5621,14 @@
   int _visibleOffset;
 
   @override
-  List<idl.UnlinkedConst> get annotations {
-    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bc, _bcOffset, 6, const <idl.UnlinkedConst>[]);
+  List<idl.UnlinkedExpr> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedExpr>(const _UnlinkedExprReader()).vTableGet(_bc, _bcOffset, 6, const <idl.UnlinkedExpr>[]);
     return _annotations;
   }
 
   @override
-  idl.UnlinkedConst get bodyExpr {
-    _bodyExpr ??= const _UnlinkedConstReader().vTableGet(_bc, _bcOffset, 29, null);
+  idl.UnlinkedExpr get bodyExpr {
+    _bodyExpr ??= const _UnlinkedExprReader().vTableGet(_bc, _bcOffset, 29, null);
     return _bodyExpr;
   }
 
@@ -6180,18 +5877,18 @@
 }
 
 class UnlinkedExportNonPublicBuilder extends Object with _UnlinkedExportNonPublicMixin implements idl.UnlinkedExportNonPublic {
-  List<UnlinkedConstBuilder> _annotations;
+  List<UnlinkedExprBuilder> _annotations;
   int _offset;
   int _uriEnd;
   int _uriOffset;
 
   @override
-  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+  List<UnlinkedExprBuilder> get annotations => _annotations ??= <UnlinkedExprBuilder>[];
 
   /**
    * Annotations for this export directive.
    */
-  void set annotations(List<UnlinkedConstBuilder> value) {
+  void set annotations(List<UnlinkedExprBuilder> value) {
     this._annotations = value;
   }
 
@@ -6230,7 +5927,7 @@
     this._uriOffset = value;
   }
 
-  UnlinkedExportNonPublicBuilder({List<UnlinkedConstBuilder> annotations, int offset, int uriEnd, int uriOffset})
+  UnlinkedExportNonPublicBuilder({List<UnlinkedExprBuilder> annotations, int offset, int uriEnd, int uriOffset})
     : _annotations = annotations,
       _offset = offset,
       _uriEnd = uriEnd,
@@ -6295,14 +5992,14 @@
 
   _UnlinkedExportNonPublicImpl(this._bc, this._bcOffset);
 
-  List<idl.UnlinkedConst> _annotations;
+  List<idl.UnlinkedExpr> _annotations;
   int _offset;
   int _uriEnd;
   int _uriOffset;
 
   @override
-  List<idl.UnlinkedConst> get annotations {
-    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bc, _bcOffset, 3, const <idl.UnlinkedConst>[]);
+  List<idl.UnlinkedExpr> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedExpr>(const _UnlinkedExprReader()).vTableGet(_bc, _bcOffset, 3, const <idl.UnlinkedExpr>[]);
     return _annotations;
   }
 
@@ -6504,8 +6201,311 @@
   String toString() => convert.JSON.encode(toJson());
 }
 
+class UnlinkedExprBuilder extends Object with _UnlinkedExprMixin implements idl.UnlinkedExpr {
+  List<idl.UnlinkedExprAssignOperator> _assignmentOperators;
+  List<double> _doubles;
+  List<int> _ints;
+  bool _isValidConst;
+  List<idl.UnlinkedExprOperation> _operations;
+  List<EntityRefBuilder> _references;
+  List<String> _strings;
+
+  @override
+  List<idl.UnlinkedExprAssignOperator> get assignmentOperators => _assignmentOperators ??= <idl.UnlinkedExprAssignOperator>[];
+
+  /**
+   * Sequence of operators used by assignment operations.
+   */
+  void set assignmentOperators(List<idl.UnlinkedExprAssignOperator> value) {
+    this._assignmentOperators = value;
+  }
+
+  @override
+  List<double> get doubles => _doubles ??= <double>[];
+
+  /**
+   * Sequence of 64-bit doubles consumed by the operation `pushDouble`.
+   */
+  void set doubles(List<double> value) {
+    this._doubles = value;
+  }
+
+  @override
+  List<int> get ints => _ints ??= <int>[];
+
+  /**
+   * Sequence of unsigned 32-bit integers consumed by the operations
+   * `pushArgument`, `pushInt`, `shiftOr`, `concatenate`, `invokeConstructor`,
+   * `makeList`, and `makeMap`.
+   */
+  void set ints(List<int> value) {
+    assert(value == null || value.every((e) => e >= 0));
+    this._ints = value;
+  }
+
+  @override
+  bool get isValidConst => _isValidConst ??= false;
+
+  /**
+   * Indicates whether the expression is a valid potentially constant
+   * expression.
+   */
+  void set isValidConst(bool value) {
+    this._isValidConst = value;
+  }
+
+  @override
+  List<idl.UnlinkedExprOperation> get operations => _operations ??= <idl.UnlinkedExprOperation>[];
+
+  /**
+   * Sequence of operations to execute (starting with an empty stack) to form
+   * the constant value.
+   */
+  void set operations(List<idl.UnlinkedExprOperation> value) {
+    this._operations = value;
+  }
+
+  @override
+  List<EntityRefBuilder> get references => _references ??= <EntityRefBuilder>[];
+
+  /**
+   * Sequence of language constructs consumed by the operations
+   * `pushReference`, `invokeConstructor`, `makeList`, and `makeMap`.  Note
+   * that in the case of `pushReference` (and sometimes `invokeConstructor` the
+   * actual entity being referred to may be something other than a type.
+   */
+  void set references(List<EntityRefBuilder> value) {
+    this._references = value;
+  }
+
+  @override
+  List<String> get strings => _strings ??= <String>[];
+
+  /**
+   * Sequence of strings consumed by the operations `pushString` and
+   * `invokeConstructor`.
+   */
+  void set strings(List<String> value) {
+    this._strings = value;
+  }
+
+  UnlinkedExprBuilder({List<idl.UnlinkedExprAssignOperator> assignmentOperators, List<double> doubles, List<int> ints, bool isValidConst, List<idl.UnlinkedExprOperation> operations, List<EntityRefBuilder> references, List<String> strings})
+    : _assignmentOperators = assignmentOperators,
+      _doubles = doubles,
+      _ints = ints,
+      _isValidConst = isValidConst,
+      _operations = operations,
+      _references = references,
+      _strings = strings;
+
+  /**
+   * Flush [informative] data recursively.
+   */
+  void flushInformative() {
+    _references?.forEach((b) => b.flushInformative());
+  }
+
+  /**
+   * Accumulate non-[informative] data into [signature].
+   */
+  void collectApiSignature(api_sig.ApiSignature signature) {
+    if (this._operations == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._operations.length);
+      for (var x in this._operations) {
+        signature.addInt(x.index);
+      }
+    }
+    if (this._ints == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._ints.length);
+      for (var x in this._ints) {
+        signature.addInt(x);
+      }
+    }
+    if (this._references == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._references.length);
+      for (var x in this._references) {
+        x?.collectApiSignature(signature);
+      }
+    }
+    if (this._strings == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._strings.length);
+      for (var x in this._strings) {
+        signature.addString(x);
+      }
+    }
+    if (this._doubles == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._doubles.length);
+      for (var x in this._doubles) {
+        signature.addDouble(x);
+      }
+    }
+    signature.addBool(this._isValidConst == true);
+    if (this._assignmentOperators == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._assignmentOperators.length);
+      for (var x in this._assignmentOperators) {
+        signature.addInt(x.index);
+      }
+    }
+  }
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    fb.Offset offset_assignmentOperators;
+    fb.Offset offset_doubles;
+    fb.Offset offset_ints;
+    fb.Offset offset_operations;
+    fb.Offset offset_references;
+    fb.Offset offset_strings;
+    if (!(_assignmentOperators == null || _assignmentOperators.isEmpty)) {
+      offset_assignmentOperators = fbBuilder.writeListUint8(_assignmentOperators.map((b) => b.index).toList());
+    }
+    if (!(_doubles == null || _doubles.isEmpty)) {
+      offset_doubles = fbBuilder.writeListFloat64(_doubles);
+    }
+    if (!(_ints == null || _ints.isEmpty)) {
+      offset_ints = fbBuilder.writeListUint32(_ints);
+    }
+    if (!(_operations == null || _operations.isEmpty)) {
+      offset_operations = fbBuilder.writeListUint8(_operations.map((b) => b.index).toList());
+    }
+    if (!(_references == null || _references.isEmpty)) {
+      offset_references = fbBuilder.writeList(_references.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (!(_strings == null || _strings.isEmpty)) {
+      offset_strings = fbBuilder.writeList(_strings.map((b) => fbBuilder.writeString(b)).toList());
+    }
+    fbBuilder.startTable();
+    if (offset_assignmentOperators != null) {
+      fbBuilder.addOffset(6, offset_assignmentOperators);
+    }
+    if (offset_doubles != null) {
+      fbBuilder.addOffset(4, offset_doubles);
+    }
+    if (offset_ints != null) {
+      fbBuilder.addOffset(1, offset_ints);
+    }
+    if (_isValidConst == true) {
+      fbBuilder.addBool(5, true);
+    }
+    if (offset_operations != null) {
+      fbBuilder.addOffset(0, offset_operations);
+    }
+    if (offset_references != null) {
+      fbBuilder.addOffset(2, offset_references);
+    }
+    if (offset_strings != null) {
+      fbBuilder.addOffset(3, offset_strings);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedExprReader extends fb.TableReader<_UnlinkedExprImpl> {
+  const _UnlinkedExprReader();
+
+  @override
+  _UnlinkedExprImpl createObject(fb.BufferContext bc, int offset) => new _UnlinkedExprImpl(bc, offset);
+}
+
+class _UnlinkedExprImpl extends Object with _UnlinkedExprMixin implements idl.UnlinkedExpr {
+  final fb.BufferContext _bc;
+  final int _bcOffset;
+
+  _UnlinkedExprImpl(this._bc, this._bcOffset);
+
+  List<idl.UnlinkedExprAssignOperator> _assignmentOperators;
+  List<double> _doubles;
+  List<int> _ints;
+  bool _isValidConst;
+  List<idl.UnlinkedExprOperation> _operations;
+  List<idl.EntityRef> _references;
+  List<String> _strings;
+
+  @override
+  List<idl.UnlinkedExprAssignOperator> get assignmentOperators {
+    _assignmentOperators ??= const fb.ListReader<idl.UnlinkedExprAssignOperator>(const _UnlinkedExprAssignOperatorReader()).vTableGet(_bc, _bcOffset, 6, const <idl.UnlinkedExprAssignOperator>[]);
+    return _assignmentOperators;
+  }
+
+  @override
+  List<double> get doubles {
+    _doubles ??= const fb.Float64ListReader().vTableGet(_bc, _bcOffset, 4, const <double>[]);
+    return _doubles;
+  }
+
+  @override
+  List<int> get ints {
+    _ints ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 1, const <int>[]);
+    return _ints;
+  }
+
+  @override
+  bool get isValidConst {
+    _isValidConst ??= const fb.BoolReader().vTableGet(_bc, _bcOffset, 5, false);
+    return _isValidConst;
+  }
+
+  @override
+  List<idl.UnlinkedExprOperation> get operations {
+    _operations ??= const fb.ListReader<idl.UnlinkedExprOperation>(const _UnlinkedExprOperationReader()).vTableGet(_bc, _bcOffset, 0, const <idl.UnlinkedExprOperation>[]);
+    return _operations;
+  }
+
+  @override
+  List<idl.EntityRef> get references {
+    _references ??= const fb.ListReader<idl.EntityRef>(const _EntityRefReader()).vTableGet(_bc, _bcOffset, 2, const <idl.EntityRef>[]);
+    return _references;
+  }
+
+  @override
+  List<String> get strings {
+    _strings ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bc, _bcOffset, 3, const <String>[]);
+    return _strings;
+  }
+}
+
+abstract class _UnlinkedExprMixin implements idl.UnlinkedExpr {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (assignmentOperators.isNotEmpty) _result["assignmentOperators"] = assignmentOperators.map((_value) => _value.toString().split('.')[1]).toList();
+    if (doubles.isNotEmpty) _result["doubles"] = doubles.map((_value) => _value.isFinite ? _value : _value.toString()).toList();
+    if (ints.isNotEmpty) _result["ints"] = ints;
+    if (isValidConst != false) _result["isValidConst"] = isValidConst;
+    if (operations.isNotEmpty) _result["operations"] = operations.map((_value) => _value.toString().split('.')[1]).toList();
+    if (references.isNotEmpty) _result["references"] = references.map((_value) => _value.toJson()).toList();
+    if (strings.isNotEmpty) _result["strings"] = strings;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "assignmentOperators": assignmentOperators,
+    "doubles": doubles,
+    "ints": ints,
+    "isValidConst": isValidConst,
+    "operations": operations,
+    "references": references,
+    "strings": strings,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
 class UnlinkedImportBuilder extends Object with _UnlinkedImportMixin implements idl.UnlinkedImport {
-  List<UnlinkedConstBuilder> _annotations;
+  List<UnlinkedExprBuilder> _annotations;
   List<UnlinkedCombinatorBuilder> _combinators;
   List<UnlinkedConfigurationBuilder> _configurations;
   bool _isDeferred;
@@ -6518,12 +6518,12 @@
   int _uriOffset;
 
   @override
-  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+  List<UnlinkedExprBuilder> get annotations => _annotations ??= <UnlinkedExprBuilder>[];
 
   /**
    * Annotations for this import declaration.
    */
-  void set annotations(List<UnlinkedConstBuilder> value) {
+  void set annotations(List<UnlinkedExprBuilder> value) {
     this._annotations = value;
   }
 
@@ -6640,7 +6640,7 @@
     this._uriOffset = value;
   }
 
-  UnlinkedImportBuilder({List<UnlinkedConstBuilder> annotations, List<UnlinkedCombinatorBuilder> combinators, List<UnlinkedConfigurationBuilder> configurations, bool isDeferred, bool isImplicit, int offset, int prefixOffset, int prefixReference, String uri, int uriEnd, int uriOffset})
+  UnlinkedImportBuilder({List<UnlinkedExprBuilder> annotations, List<UnlinkedCombinatorBuilder> combinators, List<UnlinkedConfigurationBuilder> configurations, bool isDeferred, bool isImplicit, int offset, int prefixOffset, int prefixReference, String uri, int uriEnd, int uriOffset})
     : _annotations = annotations,
       _combinators = combinators,
       _configurations = configurations,
@@ -6768,7 +6768,7 @@
 
   _UnlinkedImportImpl(this._bc, this._bcOffset);
 
-  List<idl.UnlinkedConst> _annotations;
+  List<idl.UnlinkedExpr> _annotations;
   List<idl.UnlinkedCombinator> _combinators;
   List<idl.UnlinkedConfiguration> _configurations;
   bool _isDeferred;
@@ -6781,8 +6781,8 @@
   int _uriOffset;
 
   @override
-  List<idl.UnlinkedConst> get annotations {
-    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bc, _bcOffset, 8, const <idl.UnlinkedConst>[]);
+  List<idl.UnlinkedExpr> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedExpr>(const _UnlinkedExprReader()).vTableGet(_bc, _bcOffset, 8, const <idl.UnlinkedExpr>[]);
     return _annotations;
   }
 
@@ -7043,7 +7043,7 @@
 }
 
 class UnlinkedParamBuilder extends Object with _UnlinkedParamMixin implements idl.UnlinkedParam {
-  List<UnlinkedConstBuilder> _annotations;
+  List<UnlinkedExprBuilder> _annotations;
   CodeRangeBuilder _codeRange;
   String _defaultValueCode;
   int _inferredTypeSlot;
@@ -7060,12 +7060,12 @@
   int _visibleOffset;
 
   @override
-  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+  List<UnlinkedExprBuilder> get annotations => _annotations ??= <UnlinkedExprBuilder>[];
 
   /**
    * Annotations for this parameter.
    */
-  void set annotations(List<UnlinkedConstBuilder> value) {
+  void set annotations(List<UnlinkedExprBuilder> value) {
     this._annotations = value;
   }
 
@@ -7232,7 +7232,7 @@
     this._visibleOffset = value;
   }
 
-  UnlinkedParamBuilder({List<UnlinkedConstBuilder> annotations, CodeRangeBuilder codeRange, String defaultValueCode, int inferredTypeSlot, int inheritsCovariantSlot, UnlinkedExecutableBuilder initializer, bool isFunctionTyped, bool isInitializingFormal, idl.UnlinkedParamKind kind, String name, int nameOffset, List<UnlinkedParamBuilder> parameters, EntityRefBuilder type, int visibleLength, int visibleOffset})
+  UnlinkedParamBuilder({List<UnlinkedExprBuilder> annotations, CodeRangeBuilder codeRange, String defaultValueCode, int inferredTypeSlot, int inheritsCovariantSlot, UnlinkedExecutableBuilder initializer, bool isFunctionTyped, bool isInitializingFormal, idl.UnlinkedParamKind kind, String name, int nameOffset, List<UnlinkedParamBuilder> parameters, EntityRefBuilder type, int visibleLength, int visibleOffset})
     : _annotations = annotations,
       _codeRange = codeRange,
       _defaultValueCode = defaultValueCode,
@@ -7388,7 +7388,7 @@
 
   _UnlinkedParamImpl(this._bc, this._bcOffset);
 
-  List<idl.UnlinkedConst> _annotations;
+  List<idl.UnlinkedExpr> _annotations;
   idl.CodeRange _codeRange;
   String _defaultValueCode;
   int _inferredTypeSlot;
@@ -7405,8 +7405,8 @@
   int _visibleOffset;
 
   @override
-  List<idl.UnlinkedConst> get annotations {
-    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bc, _bcOffset, 9, const <idl.UnlinkedConst>[]);
+  List<idl.UnlinkedExpr> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedExpr>(const _UnlinkedExprReader()).vTableGet(_bc, _bcOffset, 9, const <idl.UnlinkedExpr>[]);
     return _annotations;
   }
 
@@ -7541,17 +7541,17 @@
 }
 
 class UnlinkedPartBuilder extends Object with _UnlinkedPartMixin implements idl.UnlinkedPart {
-  List<UnlinkedConstBuilder> _annotations;
+  List<UnlinkedExprBuilder> _annotations;
   int _uriEnd;
   int _uriOffset;
 
   @override
-  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+  List<UnlinkedExprBuilder> get annotations => _annotations ??= <UnlinkedExprBuilder>[];
 
   /**
    * Annotations for this part declaration.
    */
-  void set annotations(List<UnlinkedConstBuilder> value) {
+  void set annotations(List<UnlinkedExprBuilder> value) {
     this._annotations = value;
   }
 
@@ -7579,7 +7579,7 @@
     this._uriOffset = value;
   }
 
-  UnlinkedPartBuilder({List<UnlinkedConstBuilder> annotations, int uriEnd, int uriOffset})
+  UnlinkedPartBuilder({List<UnlinkedExprBuilder> annotations, int uriEnd, int uriOffset})
     : _annotations = annotations,
       _uriEnd = uriEnd,
       _uriOffset = uriOffset;
@@ -7639,13 +7639,13 @@
 
   _UnlinkedPartImpl(this._bc, this._bcOffset);
 
-  List<idl.UnlinkedConst> _annotations;
+  List<idl.UnlinkedExpr> _annotations;
   int _uriEnd;
   int _uriOffset;
 
   @override
-  List<idl.UnlinkedConst> get annotations {
-    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bc, _bcOffset, 2, const <idl.UnlinkedConst>[]);
+  List<idl.UnlinkedExpr> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedExpr>(const _UnlinkedExprReader()).vTableGet(_bc, _bcOffset, 2, const <idl.UnlinkedExpr>[]);
     return _annotations;
   }
 
@@ -8148,7 +8148,7 @@
 }
 
 class UnlinkedTypedefBuilder extends Object with _UnlinkedTypedefMixin implements idl.UnlinkedTypedef {
-  List<UnlinkedConstBuilder> _annotations;
+  List<UnlinkedExprBuilder> _annotations;
   CodeRangeBuilder _codeRange;
   UnlinkedDocumentationCommentBuilder _documentationComment;
   String _name;
@@ -8158,12 +8158,12 @@
   List<UnlinkedTypeParamBuilder> _typeParameters;
 
   @override
-  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+  List<UnlinkedExprBuilder> get annotations => _annotations ??= <UnlinkedExprBuilder>[];
 
   /**
    * Annotations for this typedef.
    */
-  void set annotations(List<UnlinkedConstBuilder> value) {
+  void set annotations(List<UnlinkedExprBuilder> value) {
     this._annotations = value;
   }
 
@@ -8239,7 +8239,7 @@
     this._typeParameters = value;
   }
 
-  UnlinkedTypedefBuilder({List<UnlinkedConstBuilder> annotations, CodeRangeBuilder codeRange, UnlinkedDocumentationCommentBuilder documentationComment, String name, int nameOffset, List<UnlinkedParamBuilder> parameters, EntityRefBuilder returnType, List<UnlinkedTypeParamBuilder> typeParameters})
+  UnlinkedTypedefBuilder({List<UnlinkedExprBuilder> annotations, CodeRangeBuilder codeRange, UnlinkedDocumentationCommentBuilder documentationComment, String name, int nameOffset, List<UnlinkedParamBuilder> parameters, EntityRefBuilder returnType, List<UnlinkedTypeParamBuilder> typeParameters})
     : _annotations = annotations,
       _codeRange = codeRange,
       _documentationComment = documentationComment,
@@ -8366,7 +8366,7 @@
 
   _UnlinkedTypedefImpl(this._bc, this._bcOffset);
 
-  List<idl.UnlinkedConst> _annotations;
+  List<idl.UnlinkedExpr> _annotations;
   idl.CodeRange _codeRange;
   idl.UnlinkedDocumentationComment _documentationComment;
   String _name;
@@ -8376,8 +8376,8 @@
   List<idl.UnlinkedTypeParam> _typeParameters;
 
   @override
-  List<idl.UnlinkedConst> get annotations {
-    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bc, _bcOffset, 4, const <idl.UnlinkedConst>[]);
+  List<idl.UnlinkedExpr> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedExpr>(const _UnlinkedExprReader()).vTableGet(_bc, _bcOffset, 4, const <idl.UnlinkedExpr>[]);
     return _annotations;
   }
 
@@ -8456,19 +8456,19 @@
 }
 
 class UnlinkedTypeParamBuilder extends Object with _UnlinkedTypeParamMixin implements idl.UnlinkedTypeParam {
-  List<UnlinkedConstBuilder> _annotations;
+  List<UnlinkedExprBuilder> _annotations;
   EntityRefBuilder _bound;
   CodeRangeBuilder _codeRange;
   String _name;
   int _nameOffset;
 
   @override
-  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+  List<UnlinkedExprBuilder> get annotations => _annotations ??= <UnlinkedExprBuilder>[];
 
   /**
    * Annotations for this type parameter.
    */
-  void set annotations(List<UnlinkedConstBuilder> value) {
+  void set annotations(List<UnlinkedExprBuilder> value) {
     this._annotations = value;
   }
 
@@ -8514,7 +8514,7 @@
     this._nameOffset = value;
   }
 
-  UnlinkedTypeParamBuilder({List<UnlinkedConstBuilder> annotations, EntityRefBuilder bound, CodeRangeBuilder codeRange, String name, int nameOffset})
+  UnlinkedTypeParamBuilder({List<UnlinkedExprBuilder> annotations, EntityRefBuilder bound, CodeRangeBuilder codeRange, String name, int nameOffset})
     : _annotations = annotations,
       _bound = bound,
       _codeRange = codeRange,
@@ -8598,15 +8598,15 @@
 
   _UnlinkedTypeParamImpl(this._bc, this._bcOffset);
 
-  List<idl.UnlinkedConst> _annotations;
+  List<idl.UnlinkedExpr> _annotations;
   idl.EntityRef _bound;
   idl.CodeRange _codeRange;
   String _name;
   int _nameOffset;
 
   @override
-  List<idl.UnlinkedConst> get annotations {
-    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bc, _bcOffset, 3, const <idl.UnlinkedConst>[]);
+  List<idl.UnlinkedExpr> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedExpr>(const _UnlinkedExprReader()).vTableGet(_bc, _bcOffset, 3, const <idl.UnlinkedExpr>[]);
     return _annotations;
   }
 
@@ -8670,7 +8670,7 @@
   String _fallbackModePath;
   List<UnlinkedImportBuilder> _imports;
   bool _isPartOf;
-  List<UnlinkedConstBuilder> _libraryAnnotations;
+  List<UnlinkedExprBuilder> _libraryAnnotations;
   UnlinkedDocumentationCommentBuilder _libraryDocumentationComment;
   String _libraryName;
   int _libraryNameLength;
@@ -8781,13 +8781,13 @@
   }
 
   @override
-  List<UnlinkedConstBuilder> get libraryAnnotations => _libraryAnnotations ??= <UnlinkedConstBuilder>[];
+  List<UnlinkedExprBuilder> get libraryAnnotations => _libraryAnnotations ??= <UnlinkedExprBuilder>[];
 
   /**
    * Annotations for the library declaration, or the empty list if there is no
    * library declaration.
    */
-  void set libraryAnnotations(List<UnlinkedConstBuilder> value) {
+  void set libraryAnnotations(List<UnlinkedExprBuilder> value) {
     this._libraryAnnotations = value;
   }
 
@@ -8901,7 +8901,7 @@
     this._variables = value;
   }
 
-  UnlinkedUnitBuilder({List<int> apiSignature, List<UnlinkedClassBuilder> classes, CodeRangeBuilder codeRange, List<UnlinkedEnumBuilder> enums, List<UnlinkedExecutableBuilder> executables, List<UnlinkedExportNonPublicBuilder> exports, String fallbackModePath, List<UnlinkedImportBuilder> imports, bool isPartOf, List<UnlinkedConstBuilder> libraryAnnotations, UnlinkedDocumentationCommentBuilder libraryDocumentationComment, String libraryName, int libraryNameLength, int libraryNameOffset, List<int> lineStarts, List<UnlinkedPartBuilder> parts, UnlinkedPublicNamespaceBuilder publicNamespace, List<UnlinkedReferenceBuilder> references, List<UnlinkedTypedefBuilder> typedefs, List<UnlinkedVariableBuilder> variables})
+  UnlinkedUnitBuilder({List<int> apiSignature, List<UnlinkedClassBuilder> classes, CodeRangeBuilder codeRange, List<UnlinkedEnumBuilder> enums, List<UnlinkedExecutableBuilder> executables, List<UnlinkedExportNonPublicBuilder> exports, String fallbackModePath, List<UnlinkedImportBuilder> imports, bool isPartOf, List<UnlinkedExprBuilder> libraryAnnotations, UnlinkedDocumentationCommentBuilder libraryDocumentationComment, String libraryName, int libraryNameLength, int libraryNameOffset, List<int> lineStarts, List<UnlinkedPartBuilder> parts, UnlinkedPublicNamespaceBuilder publicNamespace, List<UnlinkedReferenceBuilder> references, List<UnlinkedTypedefBuilder> typedefs, List<UnlinkedVariableBuilder> variables})
     : _apiSignature = apiSignature,
       _classes = classes,
       _codeRange = codeRange,
@@ -9210,7 +9210,7 @@
   String _fallbackModePath;
   List<idl.UnlinkedImport> _imports;
   bool _isPartOf;
-  List<idl.UnlinkedConst> _libraryAnnotations;
+  List<idl.UnlinkedExpr> _libraryAnnotations;
   idl.UnlinkedDocumentationComment _libraryDocumentationComment;
   String _libraryName;
   int _libraryNameLength;
@@ -9277,8 +9277,8 @@
   }
 
   @override
-  List<idl.UnlinkedConst> get libraryAnnotations {
-    _libraryAnnotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bc, _bcOffset, 14, const <idl.UnlinkedConst>[]);
+  List<idl.UnlinkedExpr> get libraryAnnotations {
+    _libraryAnnotations ??= const fb.ListReader<idl.UnlinkedExpr>(const _UnlinkedExprReader()).vTableGet(_bc, _bcOffset, 14, const <idl.UnlinkedExpr>[]);
     return _libraryAnnotations;
   }
 
@@ -9399,7 +9399,7 @@
 }
 
 class UnlinkedVariableBuilder extends Object with _UnlinkedVariableMixin implements idl.UnlinkedVariable {
-  List<UnlinkedConstBuilder> _annotations;
+  List<UnlinkedExprBuilder> _annotations;
   CodeRangeBuilder _codeRange;
   UnlinkedDocumentationCommentBuilder _documentationComment;
   int _inferredTypeSlot;
@@ -9415,12 +9415,12 @@
   int _visibleOffset;
 
   @override
-  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+  List<UnlinkedExprBuilder> get annotations => _annotations ??= <UnlinkedExprBuilder>[];
 
   /**
    * Annotations for this variable.
    */
-  void set annotations(List<UnlinkedConstBuilder> value) {
+  void set annotations(List<UnlinkedExprBuilder> value) {
     this._annotations = value;
   }
 
@@ -9573,7 +9573,7 @@
     this._visibleOffset = value;
   }
 
-  UnlinkedVariableBuilder({List<UnlinkedConstBuilder> annotations, CodeRangeBuilder codeRange, UnlinkedDocumentationCommentBuilder documentationComment, int inferredTypeSlot, UnlinkedExecutableBuilder initializer, bool isConst, bool isFinal, bool isStatic, String name, int nameOffset, int propagatedTypeSlot, EntityRefBuilder type, int visibleLength, int visibleOffset})
+  UnlinkedVariableBuilder({List<UnlinkedExprBuilder> annotations, CodeRangeBuilder codeRange, UnlinkedDocumentationCommentBuilder documentationComment, int inferredTypeSlot, UnlinkedExecutableBuilder initializer, bool isConst, bool isFinal, bool isStatic, String name, int nameOffset, int propagatedTypeSlot, EntityRefBuilder type, int visibleLength, int visibleOffset})
     : _annotations = annotations,
       _codeRange = codeRange,
       _documentationComment = documentationComment,
@@ -9712,7 +9712,7 @@
 
   _UnlinkedVariableImpl(this._bc, this._bcOffset);
 
-  List<idl.UnlinkedConst> _annotations;
+  List<idl.UnlinkedExpr> _annotations;
   idl.CodeRange _codeRange;
   idl.UnlinkedDocumentationComment _documentationComment;
   int _inferredTypeSlot;
@@ -9728,8 +9728,8 @@
   int _visibleOffset;
 
   @override
-  List<idl.UnlinkedConst> get annotations {
-    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bc, _bcOffset, 8, const <idl.UnlinkedConst>[]);
+  List<idl.UnlinkedExpr> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedExpr>(const _UnlinkedExprReader()).vTableGet(_bc, _bcOffset, 8, const <idl.UnlinkedExpr>[]);
     return _annotations;
   }
 
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index 023c370..09fbfe4 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -210,13 +210,152 @@
 }
 
 /**
+ * Enum used to indicate the kind of an constructor initializer.
+ */
+enum UnlinkedConstructorInitializerKind : byte {
+  /**
+   * Initialization of a field.
+   */
+  field,
+
+  /**
+   * Invocation of a constructor in the same class.
+   */
+  thisInvocation,
+
+  /**
+   * Invocation of a superclass' constructor.
+   */
+  superInvocation
+}
+
+/**
+ * Enum used to indicate the kind of an executable.
+ */
+enum UnlinkedExecutableKind : byte {
+  /**
+   * Executable is a function or method.
+   */
+  functionOrMethod,
+
+  /**
+   * Executable is a getter.
+   */
+  getter,
+
+  /**
+   * Executable is a setter.
+   */
+  setter,
+
+  /**
+   * Executable is a constructor.
+   */
+  constructor
+}
+
+/**
+ * Enum representing the various kinds of assignment operations combined
+ * with:
+ *    [UnlinkedExprOperation.assignToRef],
+ *    [UnlinkedExprOperation.assignToProperty],
+ *    [UnlinkedExprOperation.assignToIndex].
+ */
+enum UnlinkedExprAssignOperator : byte {
+  /**
+   * Perform simple assignment `target = operand`.
+   */
+  assign,
+
+  /**
+   * Perform `target ??= operand`.
+   */
+  ifNull,
+
+  /**
+   * Perform `target *= operand`.
+   */
+  multiply,
+
+  /**
+   * Perform `target /= operand`.
+   */
+  divide,
+
+  /**
+   * Perform `target ~/= operand`.
+   */
+  floorDivide,
+
+  /**
+   * Perform `target %= operand`.
+   */
+  modulo,
+
+  /**
+   * Perform `target += operand`.
+   */
+  plus,
+
+  /**
+   * Perform `target -= operand`.
+   */
+  minus,
+
+  /**
+   * Perform `target <<= operand`.
+   */
+  shiftLeft,
+
+  /**
+   * Perform `target >>= operand`.
+   */
+  shiftRight,
+
+  /**
+   * Perform `target &= operand`.
+   */
+  bitAnd,
+
+  /**
+   * Perform `target ^= operand`.
+   */
+  bitXor,
+
+  /**
+   * Perform `target |= operand`.
+   */
+  bitOr,
+
+  /**
+   * Perform `++target`.
+   */
+  prefixIncrement,
+
+  /**
+   * Perform `--target`.
+   */
+  prefixDecrement,
+
+  /**
+   * Perform `target++`.
+   */
+  postfixIncrement,
+
+  /**
+   * Perform `target++`.
+   */
+  postfixDecrement
+}
+
+/**
  * Enum representing the various kinds of operations which may be performed to
- * produce a constant value.  These options are assumed to execute in the
+ * in an expression.  These options are assumed to execute in the
  * context of a stack which is initially empty.
  */
-enum UnlinkedConstOperation : byte {
+enum UnlinkedExprOperation : byte {
   /**
-   * Push the next value from [UnlinkedConst.ints] (a 32-bit unsigned integer)
+   * Push the next value from [UnlinkedExpr.ints] (a 32-bit unsigned integer)
    * onto the stack.
    *
    * Note that Dart supports integers larger than 32 bits; these are
@@ -225,15 +364,15 @@
   pushInt,
 
   /**
-   * Get the number of components from [UnlinkedConst.ints], then do this number
+   * Get the number of components from [UnlinkedExpr.ints], then do this number
    * of times the following operations: multiple the current value by 2^32, "or"
-   * it with the next value in [UnlinkedConst.ints]. The initial value is zero.
+   * it with the next value in [UnlinkedExpr.ints]. The initial value is zero.
    * Push the result into the stack.
    */
   pushLongInt,
 
   /**
-   * Push the next value from [UnlinkedConst.doubles] (a double precision
+   * Push the next value from [UnlinkedExpr.doubles] (a double precision
    * floating point value) onto the stack.
    */
   pushDouble,
@@ -249,13 +388,13 @@
   pushFalse,
 
   /**
-   * Push the next value from [UnlinkedConst.strings] onto the stack.
+   * Push the next value from [UnlinkedExpr.strings] onto the stack.
    */
   pushString,
 
   /**
    * Pop the top n values from the stack (where n is obtained from
-   * [UnlinkedConst.ints]), convert them to strings (if they aren't already),
+   * [UnlinkedExpr.ints]), convert them to strings (if they aren't already),
    * concatenate them into a single string, and push it back onto the stack.
    *
    * This operation is used to represent constants whose value is a literal
@@ -264,7 +403,7 @@
   concatenate,
 
   /**
-   * Get the next value from [UnlinkedConst.strings], convert it to a symbol,
+   * Get the next value from [UnlinkedExpr.strings], convert it to a symbol,
    * and push it onto the stack.
    */
   makeSymbol,
@@ -276,14 +415,14 @@
 
   /**
    * Push the value of the function parameter with the name obtained from
-   * [UnlinkedConst.strings].
+   * [UnlinkedExpr.strings].
    */
   pushParameter,
 
   /**
    * Evaluate a (potentially qualified) identifier expression and push the
    * resulting value onto the stack.  The identifier to be evaluated is
-   * obtained from [UnlinkedConst.references].
+   * obtained from [UnlinkedExpr.references].
    *
    * This operation is used to represent the following kinds of constants
    * (which are indistinguishable from an unresolved AST alone):
@@ -299,20 +438,20 @@
 
   /**
    * Pop the top value from the stack, extract the value of the property with
-   * the name obtained from [UnlinkedConst.strings], and push the result back
+   * the name obtained from [UnlinkedExpr.strings], and push the result back
    * onto the stack.
    */
   extractProperty,
 
   /**
    * Pop the top `n` values from the stack (where `n` is obtained from
-   * [UnlinkedConst.ints]) into a list (filled from the end) and take the next
-   * `n` values from [UnlinkedConst.strings] and use the lists of names and
+   * [UnlinkedExpr.ints]) into a list (filled from the end) and take the next
+   * `n` values from [UnlinkedExpr.strings] and use the lists of names and
    * values to create named arguments.  Then pop the top `m` values from the
-   * stack (where `m` is obtained from [UnlinkedConst.ints]) into a list (filled
+   * stack (where `m` is obtained from [UnlinkedExpr.ints]) into a list (filled
    * from the end) and use them as positional arguments.  Use the lists of
    * positional and names arguments to invoke a constant constructor obtained
-   * from [UnlinkedConst.references], and push the resulting value back onto the
+   * from [UnlinkedExpr.references], and push the resulting value back onto the
    * stack.
    *
    * Note that for an invocation of the form `const a.b(...)` (where no type
@@ -326,14 +465,14 @@
 
   /**
    * Pop the top n values from the stack (where n is obtained from
-   * [UnlinkedConst.ints]), place them in a [List], and push the result back
+   * [UnlinkedExpr.ints]), place them in a [List], and push the result back
    * onto the stack.  The type parameter for the [List] is implicitly `dynamic`.
    */
   makeUntypedList,
 
   /**
    * Pop the top 2*n values from the stack (where n is obtained from
-   * [UnlinkedConst.ints]), interpret them as key/value pairs, place them in a
+   * [UnlinkedExpr.ints]), interpret them as key/value pairs, place them in a
    * [Map], and push the result back onto the stack.  The two type parameters
    * for the [Map] are implicitly `dynamic`.
    */
@@ -341,17 +480,17 @@
 
   /**
    * Pop the top n values from the stack (where n is obtained from
-   * [UnlinkedConst.ints]), place them in a [List], and push the result back
+   * [UnlinkedExpr.ints]), place them in a [List], and push the result back
    * onto the stack.  The type parameter for the [List] is obtained from
-   * [UnlinkedConst.references].
+   * [UnlinkedExpr.references].
    */
   makeTypedList,
 
   /**
    * Pop the top 2*n values from the stack (where n is obtained from
-   * [UnlinkedConst.ints]), interpret them as key/value pairs, place them in a
+   * [UnlinkedExpr.ints]), interpret them as key/value pairs, place them in a
    * [Map], and push the result back onto the stack.  The two type parameters for
-   * the [Map] are obtained from [UnlinkedConst.references].
+   * the [Map] are obtained from [UnlinkedExpr.references].
    */
   makeTypedMap,
 
@@ -495,13 +634,13 @@
 
   /**
    * Pop from the stack `value` and get the next `target` reference from
-   * [UnlinkedConst.references] - a top-level variable (prefixed or not), an
+   * [UnlinkedExpr.references] - a top-level variable (prefixed or not), an
    * assignable field of a class (prefixed or not), or a sequence of getters
    * ending with an assignable property `a.b.b.c.d.e`.  In general `a.b` cannot
    * not be distinguished between: `a` is a prefix and `b` is a top-level
    * variable; or `a` is an object and `b` is the name of a property.  Perform
    * `reference op= value` where `op` is the next assignment operator from
-   * [UnlinkedConst.assignmentOperators].  Push `value` back into the stack.
+   * [UnlinkedExpr.assignmentOperators].  Push `value` back into the stack.
    *
    * If the assignment operator is a prefix/postfix increment/decrement, then
    * `value` is not present in the stack, so it should not be popped and the
@@ -516,7 +655,7 @@
    * `target`.  This operation is used when we know that the `target` is an
    * object reference expression, e.g. `new Foo().a.b.c` or `a.b[0].c.d`.
    * Perform `target.property op= value` where `op` is the next assignment
-   * operator from [UnlinkedConst.assignmentOperators].  Push `value` back into
+   * operator from [UnlinkedExpr.assignmentOperators].  Push `value` back into
    * the stack.
    *
    * If the assignment operator is a prefix/postfix increment/decrement, then
@@ -529,7 +668,7 @@
   /**
    * Pop from the stack `index`, `target` and `value`.  Perform
    * `target[index] op= value`  where `op` is the next assignment operator from
-   * [UnlinkedConst.assignmentOperators].  Push `value` back into the stack.
+   * [UnlinkedExpr.assignmentOperators].  Push `value` back into the stack.
    *
    * If the assignment operator is a prefix/postfix increment/decrement, then
    * `value` is not present in the stack, so it should not be popped and the
@@ -546,15 +685,15 @@
 
   /**
    * Pop the top `n` values from the stack (where `n` is obtained from
-   * [UnlinkedConst.ints]) into a list (filled from the end) and take the next
-   * `n` values from [UnlinkedConst.strings] and use the lists of names and
+   * [UnlinkedExpr.ints]) into a list (filled from the end) and take the next
+   * `n` values from [UnlinkedExpr.strings] and use the lists of names and
    * values to create named arguments.  Then pop the top `m` values from the
-   * stack (where `m` is obtained from [UnlinkedConst.ints]) into a list (filled
+   * stack (where `m` is obtained from [UnlinkedExpr.ints]) into a list (filled
    * from the end) and use them as positional arguments.  Use the lists of
    * positional and names arguments to invoke a method (or a function) with
-   * the reference from [UnlinkedConst.references].  If `k` is nonzero (where
-   * `k` is obtained from [UnlinkedConst.ints]), obtain `k` type arguments from
-   * [UnlinkedConst.references] and use them as generic type arguments for the
+   * the reference from [UnlinkedExpr.references].  If `k` is nonzero (where
+   * `k` is obtained from [UnlinkedExpr.ints]), obtain `k` type arguments from
+   * [UnlinkedExpr.references] and use them as generic type arguments for the
    * aforementioned method or function.  Push the result of the invocation onto
    * the stack.
    *
@@ -567,15 +706,15 @@
 
   /**
    * Pop the top `n` values from the stack (where `n` is obtained from
-   * [UnlinkedConst.ints]) into a list (filled from the end) and take the next
-   * `n` values from [UnlinkedConst.strings] and use the lists of names and
+   * [UnlinkedExpr.ints]) into a list (filled from the end) and take the next
+   * `n` values from [UnlinkedExpr.strings] and use the lists of names and
    * values to create named arguments.  Then pop the top `m` values from the
-   * stack (where `m` is obtained from [UnlinkedConst.ints]) into a list (filled
+   * stack (where `m` is obtained from [UnlinkedExpr.ints]) into a list (filled
    * from the end) and use them as positional arguments.  Use the lists of
    * positional and names arguments to invoke the method with the name from
-   * [UnlinkedConst.strings] of the target popped from the stack.  If `k` is
-   * nonzero (where `k` is obtained from [UnlinkedConst.ints]), obtain `k` type
-   * arguments from [UnlinkedConst.references] and use them as generic type
+   * [UnlinkedExpr.strings] of the target popped from the stack.  If `k` is
+   * nonzero (where `k` is obtained from [UnlinkedExpr.ints]), obtain `k` type
+   * arguments from [UnlinkedExpr.references] and use them as generic type
    * arguments for the aforementioned method.  Push the result of the
    * invocation onto the stack.
    *
@@ -597,13 +736,13 @@
 
   /**
    * Pop the top value from the stack and cast it to the type with reference
-   * from [UnlinkedConst.references], push the result into the stack.
+   * from [UnlinkedExpr.references], push the result into the stack.
    */
   typeCast,
 
   /**
    * Pop the top value from the stack and check whether it is a subclass of the
-   * type with reference from [UnlinkedConst.references], push the result into
+   * type with reference from [UnlinkedExpr.references], push the result into
    * the stack.
    */
   typeCheck,
@@ -614,7 +753,7 @@
   throwException,
 
   /**
-   * Obtain two values `n` and `m` from [UnlinkedConst.ints].  Then, starting at
+   * Obtain two values `n` and `m` from [UnlinkedExpr.ints].  Then, starting at
    * the executable element for the expression being evaluated, if n > 0, pop to
    * the nth enclosing function element.  Then, push the mth local function of
    * that element onto the stack.
@@ -623,145 +762,6 @@
 }
 
 /**
- * Enum used to indicate the kind of an constructor initializer.
- */
-enum UnlinkedConstructorInitializerKind : byte {
-  /**
-   * Initialization of a field.
-   */
-  field,
-
-  /**
-   * Invocation of a constructor in the same class.
-   */
-  thisInvocation,
-
-  /**
-   * Invocation of a superclass' constructor.
-   */
-  superInvocation
-}
-
-/**
- * Enum used to indicate the kind of an executable.
- */
-enum UnlinkedExecutableKind : byte {
-  /**
-   * Executable is a function or method.
-   */
-  functionOrMethod,
-
-  /**
-   * Executable is a getter.
-   */
-  getter,
-
-  /**
-   * Executable is a setter.
-   */
-  setter,
-
-  /**
-   * Executable is a constructor.
-   */
-  constructor
-}
-
-/**
- * Enum representing the various kinds of assignment operations combined
- * with:
- *    [UnlinkedConstOperation.assignToRef],
- *    [UnlinkedConstOperation.assignToProperty],
- *    [UnlinkedConstOperation.assignToIndex].
- */
-enum UnlinkedExprAssignOperator : byte {
-  /**
-   * Perform simple assignment `target = operand`.
-   */
-  assign,
-
-  /**
-   * Perform `target ??= operand`.
-   */
-  ifNull,
-
-  /**
-   * Perform `target *= operand`.
-   */
-  multiply,
-
-  /**
-   * Perform `target /= operand`.
-   */
-  divide,
-
-  /**
-   * Perform `target ~/= operand`.
-   */
-  floorDivide,
-
-  /**
-   * Perform `target %= operand`.
-   */
-  modulo,
-
-  /**
-   * Perform `target += operand`.
-   */
-  plus,
-
-  /**
-   * Perform `target -= operand`.
-   */
-  minus,
-
-  /**
-   * Perform `target <<= operand`.
-   */
-  shiftLeft,
-
-  /**
-   * Perform `target >>= operand`.
-   */
-  shiftRight,
-
-  /**
-   * Perform `target &= operand`.
-   */
-  bitAnd,
-
-  /**
-   * Perform `target ^= operand`.
-   */
-  bitXor,
-
-  /**
-   * Perform `target |= operand`.
-   */
-  bitOr,
-
-  /**
-   * Perform `++target`.
-   */
-  prefixIncrement,
-
-  /**
-   * Perform `--target`.
-   */
-  prefixDecrement,
-
-  /**
-   * Perform `target++`.
-   */
-  postfixIncrement,
-
-  /**
-   * Perform `target++`.
-   */
-  postfixDecrement
-}
-
-/**
  * Enum used to indicate the kind of a parameter.
  */
 enum UnlinkedParamKind : byte {
@@ -1398,7 +1398,7 @@
   /**
    * Annotations for this class.
    */
-  annotations:[UnlinkedConst] (id: 5);
+  annotations:[UnlinkedExpr] (id: 5);
 
   /**
    * Code range of the class.
@@ -1521,61 +1521,6 @@
 }
 
 /**
- * Unlinked summary information about a compile-time constant expression, or a
- * potentially constant expression.
- *
- * Constant expressions are represented using a simple stack-based language
- * where [operations] is a sequence of operations to execute starting with an
- * empty stack.  Once all operations have been executed, the stack should
- * contain a single value which is the value of the constant.  Note that some
- * operations consume additional data from the other fields of this class.
- */
-table UnlinkedConst {
-  /**
-   * Sequence of operators used by assignment operations.
-   */
-  assignmentOperators:[UnlinkedExprAssignOperator] (id: 6);
-
-  /**
-   * Sequence of 64-bit doubles consumed by the operation `pushDouble`.
-   */
-  doubles:[double] (id: 4);
-
-  /**
-   * Sequence of unsigned 32-bit integers consumed by the operations
-   * `pushArgument`, `pushInt`, `shiftOr`, `concatenate`, `invokeConstructor`,
-   * `makeList`, and `makeMap`.
-   */
-  ints:[uint] (id: 1);
-
-  /**
-   * Indicates whether the expression is a valid potentially constant
-   * expression.
-   */
-  isValidConst:bool (id: 5);
-
-  /**
-   * Sequence of operations to execute (starting with an empty stack) to form
-   * the constant value.
-   */
-  operations:[UnlinkedConstOperation] (id: 0);
-
-  /**
-   * Sequence of language constructs consumed by the operations
-   * `pushReference`, `invokeConstructor`, `makeList`, and `makeMap`.  Note
-   * that in the case of `pushReference` (and sometimes `invokeConstructor` the
-   * actual entity being referred to may be something other than a type.
-   */
-  references:[EntityRef] (id: 2);
-
-  /**
-   * Sequence of strings consumed by the operations `pushString` and
-   * `invokeConstructor`.
-   */
-  strings:[string] (id: 3);
-}
-
-/**
  * Unlinked summary information about a constructor initializer.
  */
 table UnlinkedConstructorInitializer {
@@ -1590,13 +1535,13 @@
    * If [kind] is `thisInvocation` or `superInvocation`, the arguments of the
    * invocation.  Otherwise empty.
    */
-  arguments:[UnlinkedConst] (id: 3);
+  arguments:[UnlinkedExpr] (id: 3);
 
   /**
    * If [kind] is `field`, the expression of the field initializer.
    * Otherwise `null`.
    */
-  expression:UnlinkedConst (id: 1);
+  expression:UnlinkedExpr (id: 1);
 
   /**
    * The kind of the constructor initializer (field, redirect, super).
@@ -1643,7 +1588,7 @@
   /**
    * Annotations for this enum.
    */
-  annotations:[UnlinkedConst] (id: 4);
+  annotations:[UnlinkedExpr] (id: 4);
 
   /**
    * Code range of the enum.
@@ -1702,14 +1647,14 @@
   /**
    * Annotations for this executable.
    */
-  annotations:[UnlinkedConst] (id: 6);
+  annotations:[UnlinkedExpr] (id: 6);
 
   /**
    * If this executable's function body is declared using `=>`, the expression
    * to the right of the `=>`.  May be omitted if neither type inference nor
    * constant evaluation depends on the function body.
    */
-  bodyExpr:UnlinkedConst (id: 29);
+  bodyExpr:UnlinkedExpr (id: 29);
 
   /**
    * Code range of the executable.
@@ -1893,7 +1838,7 @@
   /**
    * Annotations for this export directive.
    */
-  annotations:[UnlinkedConst] (id: 3);
+  annotations:[UnlinkedExpr] (id: 3);
 
   /**
    * Offset of the "export" keyword.
@@ -1936,13 +1881,67 @@
 }
 
 /**
+ * Unlinked summary information about an expression.
+ *
+ * Expressions are represented using a simple stack-based language
+ * where [operations] is a sequence of operations to execute starting with an
+ * empty stack.  Once all operations have been executed, the stack should
+ * contain a single value which is the value of the constant.  Note that some
+ * operations consume additional data from the other fields of this class.
+ */
+table UnlinkedExpr {
+  /**
+   * Sequence of operators used by assignment operations.
+   */
+  assignmentOperators:[UnlinkedExprAssignOperator] (id: 6);
+
+  /**
+   * Sequence of 64-bit doubles consumed by the operation `pushDouble`.
+   */
+  doubles:[double] (id: 4);
+
+  /**
+   * Sequence of unsigned 32-bit integers consumed by the operations
+   * `pushArgument`, `pushInt`, `shiftOr`, `concatenate`, `invokeConstructor`,
+   * `makeList`, and `makeMap`.
+   */
+  ints:[uint] (id: 1);
+
+  /**
+   * Indicates whether the expression is a valid potentially constant
+   * expression.
+   */
+  isValidConst:bool (id: 5);
+
+  /**
+   * Sequence of operations to execute (starting with an empty stack) to form
+   * the constant value.
+   */
+  operations:[UnlinkedExprOperation] (id: 0);
+
+  /**
+   * Sequence of language constructs consumed by the operations
+   * `pushReference`, `invokeConstructor`, `makeList`, and `makeMap`.  Note
+   * that in the case of `pushReference` (and sometimes `invokeConstructor` the
+   * actual entity being referred to may be something other than a type.
+   */
+  references:[EntityRef] (id: 2);
+
+  /**
+   * Sequence of strings consumed by the operations `pushString` and
+   * `invokeConstructor`.
+   */
+  strings:[string] (id: 3);
+}
+
+/**
  * Unlinked summary information about an import declaration.
  */
 table UnlinkedImport {
   /**
    * Annotations for this import declaration.
    */
-  annotations:[UnlinkedConst] (id: 8);
+  annotations:[UnlinkedExpr] (id: 8);
 
   /**
    * Combinators contained in this import declaration.
@@ -2036,7 +2035,7 @@
   /**
    * Annotations for this parameter.
    */
-  annotations:[UnlinkedConst] (id: 9);
+  annotations:[UnlinkedExpr] (id: 9);
 
   /**
    * Code range of the parameter.
@@ -2134,7 +2133,7 @@
   /**
    * Annotations for this part declaration.
    */
-  annotations:[UnlinkedConst] (id: 2);
+  annotations:[UnlinkedExpr] (id: 2);
 
   /**
    * End of the URI string (including quotes) relative to the beginning of the
@@ -2240,7 +2239,7 @@
   /**
    * Annotations for this typedef.
    */
-  annotations:[UnlinkedConst] (id: 4);
+  annotations:[UnlinkedExpr] (id: 4);
 
   /**
    * Code range of the typedef.
@@ -2286,7 +2285,7 @@
   /**
    * Annotations for this type parameter.
    */
-  annotations:[UnlinkedConst] (id: 3);
+  annotations:[UnlinkedExpr] (id: 3);
 
   /**
    * Bound of the type parameter, if a bound is explicitly declared.  Otherwise
@@ -2370,7 +2369,7 @@
    * Annotations for the library declaration, or the empty list if there is no
    * library declaration.
    */
-  libraryAnnotations:[UnlinkedConst] (id: 14);
+  libraryAnnotations:[UnlinkedExpr] (id: 14);
 
   /**
    * Documentation comment for the library, or `null` if there is no
@@ -2438,7 +2437,7 @@
   /**
    * Annotations for this variable.
    */
-  annotations:[UnlinkedConst] (id: 8);
+  annotations:[UnlinkedExpr] (id: 8);
 
   /**
    * Code range of the variable.
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index 07ce297d8..eeb604a 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -971,7 +971,7 @@
    * Annotations for this class.
    */
   @Id(5)
-  List<UnlinkedConst> get annotations;
+  List<UnlinkedExpr> get annotations;
 
   /**
    * Code range of the class.
@@ -1119,481 +1119,6 @@
 }
 
 /**
- * Unlinked summary information about a compile-time constant expression, or a
- * potentially constant expression.
- *
- * Constant expressions are represented using a simple stack-based language
- * where [operations] is a sequence of operations to execute starting with an
- * empty stack.  Once all operations have been executed, the stack should
- * contain a single value which is the value of the constant.  Note that some
- * operations consume additional data from the other fields of this class.
- */
-abstract class UnlinkedConst extends base.SummaryClass {
-  /**
-   * Sequence of operators used by assignment operations.
-   */
-  @Id(6)
-  List<UnlinkedExprAssignOperator> get assignmentOperators;
-
-  /**
-   * Sequence of 64-bit doubles consumed by the operation `pushDouble`.
-   */
-  @Id(4)
-  List<double> get doubles;
-
-  /**
-   * Sequence of unsigned 32-bit integers consumed by the operations
-   * `pushArgument`, `pushInt`, `shiftOr`, `concatenate`, `invokeConstructor`,
-   * `makeList`, and `makeMap`.
-   */
-  @Id(1)
-  List<int> get ints;
-
-  /**
-   * Indicates whether the expression is a valid potentially constant
-   * expression.
-   */
-  @Id(5)
-  bool get isValidConst;
-
-  /**
-   * Sequence of operations to execute (starting with an empty stack) to form
-   * the constant value.
-   */
-  @Id(0)
-  List<UnlinkedConstOperation> get operations;
-
-  /**
-   * Sequence of language constructs consumed by the operations
-   * `pushReference`, `invokeConstructor`, `makeList`, and `makeMap`.  Note
-   * that in the case of `pushReference` (and sometimes `invokeConstructor` the
-   * actual entity being referred to may be something other than a type.
-   */
-  @Id(2)
-  List<EntityRef> get references;
-
-  /**
-   * Sequence of strings consumed by the operations `pushString` and
-   * `invokeConstructor`.
-   */
-  @Id(3)
-  List<String> get strings;
-}
-
-/**
- * Enum representing the various kinds of operations which may be performed to
- * produce a constant value.  These options are assumed to execute in the
- * context of a stack which is initially empty.
- */
-enum UnlinkedConstOperation {
-  /**
-   * Push the next value from [UnlinkedConst.ints] (a 32-bit unsigned integer)
-   * onto the stack.
-   *
-   * Note that Dart supports integers larger than 32 bits; these are
-   * represented by composing 32-bit values using the [pushLongInt] operation.
-   */
-  pushInt,
-
-  /**
-   * Get the number of components from [UnlinkedConst.ints], then do this number
-   * of times the following operations: multiple the current value by 2^32, "or"
-   * it with the next value in [UnlinkedConst.ints]. The initial value is zero.
-   * Push the result into the stack.
-   */
-  pushLongInt,
-
-  /**
-   * Push the next value from [UnlinkedConst.doubles] (a double precision
-   * floating point value) onto the stack.
-   */
-  pushDouble,
-
-  /**
-   * Push the constant `true` onto the stack.
-   */
-  pushTrue,
-
-  /**
-   * Push the constant `false` onto the stack.
-   */
-  pushFalse,
-
-  /**
-   * Push the next value from [UnlinkedConst.strings] onto the stack.
-   */
-  pushString,
-
-  /**
-   * Pop the top n values from the stack (where n is obtained from
-   * [UnlinkedConst.ints]), convert them to strings (if they aren't already),
-   * concatenate them into a single string, and push it back onto the stack.
-   *
-   * This operation is used to represent constants whose value is a literal
-   * string containing string interpolations.
-   */
-  concatenate,
-
-  /**
-   * Get the next value from [UnlinkedConst.strings], convert it to a symbol,
-   * and push it onto the stack.
-   */
-  makeSymbol,
-
-  /**
-   * Push the constant `null` onto the stack.
-   */
-  pushNull,
-
-  /**
-   * Push the value of the function parameter with the name obtained from
-   * [UnlinkedConst.strings].
-   */
-  pushParameter,
-
-  /**
-   * Evaluate a (potentially qualified) identifier expression and push the
-   * resulting value onto the stack.  The identifier to be evaluated is
-   * obtained from [UnlinkedConst.references].
-   *
-   * This operation is used to represent the following kinds of constants
-   * (which are indistinguishable from an unresolved AST alone):
-   *
-   * - A qualified reference to a static constant variable (e.g. `C.v`, where
-   *   C is a class and `v` is a constant static variable in `C`).
-   * - An identifier expression referring to a constant variable.
-   * - A simple or qualified identifier denoting a class or type alias.
-   * - A simple or qualified identifier denoting a top-level function or a
-   *   static method.
-   */
-  pushReference,
-
-  /**
-   * Pop the top value from the stack, extract the value of the property with
-   * the name obtained from [UnlinkedConst.strings], and push the result back
-   * onto the stack.
-   */
-  extractProperty,
-
-  /**
-   * Pop the top `n` values from the stack (where `n` is obtained from
-   * [UnlinkedConst.ints]) into a list (filled from the end) and take the next
-   * `n` values from [UnlinkedConst.strings] and use the lists of names and
-   * values to create named arguments.  Then pop the top `m` values from the
-   * stack (where `m` is obtained from [UnlinkedConst.ints]) into a list (filled
-   * from the end) and use them as positional arguments.  Use the lists of
-   * positional and names arguments to invoke a constant constructor obtained
-   * from [UnlinkedConst.references], and push the resulting value back onto the
-   * stack.
-   *
-   * Note that for an invocation of the form `const a.b(...)` (where no type
-   * arguments are specified), it is impossible to tell from the unresolved AST
-   * alone whether `a` is a class name and `b` is a constructor name, or `a` is
-   * a prefix name and `b` is a class name.  For consistency between AST based
-   * and elements based summaries, references to default constructors are always
-   * recorded as references to corresponding classes.
-   */
-  invokeConstructor,
-
-  /**
-   * Pop the top n values from the stack (where n is obtained from
-   * [UnlinkedConst.ints]), place them in a [List], and push the result back
-   * onto the stack.  The type parameter for the [List] is implicitly `dynamic`.
-   */
-  makeUntypedList,
-
-  /**
-   * Pop the top 2*n values from the stack (where n is obtained from
-   * [UnlinkedConst.ints]), interpret them as key/value pairs, place them in a
-   * [Map], and push the result back onto the stack.  The two type parameters
-   * for the [Map] are implicitly `dynamic`.
-   */
-  makeUntypedMap,
-
-  /**
-   * Pop the top n values from the stack (where n is obtained from
-   * [UnlinkedConst.ints]), place them in a [List], and push the result back
-   * onto the stack.  The type parameter for the [List] is obtained from
-   * [UnlinkedConst.references].
-   */
-  makeTypedList,
-
-  /**
-   * Pop the top 2*n values from the stack (where n is obtained from
-   * [UnlinkedConst.ints]), interpret them as key/value pairs, place them in a
-   * [Map], and push the result back onto the stack.  The two type parameters for
-   * the [Map] are obtained from [UnlinkedConst.references].
-   */
-  makeTypedMap,
-
-  /**
-   * Pop the top 2 values from the stack, evaluate `v1 == v2`, and push the
-   * result back onto the stack.
-   */
-  equal,
-
-  /**
-   * Pop the top 2 values from the stack, evaluate `v1 != v2`, and push the
-   * result back onto the stack.
-   */
-  notEqual,
-
-  /**
-   * Pop the top value from the stack, compute its boolean negation, and push
-   * the result back onto the stack.
-   */
-  not,
-
-  /**
-   * Pop the top 2 values from the stack, compute `v1 && v2`, and push the
-   * result back onto the stack.
-   */
-  and,
-
-  /**
-   * Pop the top 2 values from the stack, compute `v1 || v2`, and push the
-   * result back onto the stack.
-   */
-  or,
-
-  /**
-   * Pop the top value from the stack, compute its integer complement, and push
-   * the result back onto the stack.
-   */
-  complement,
-
-  /**
-   * Pop the top 2 values from the stack, compute `v1 ^ v2`, and push the
-   * result back onto the stack.
-   */
-  bitXor,
-
-  /**
-   * Pop the top 2 values from the stack, compute `v1 & v2`, and push the
-   * result back onto the stack.
-   */
-  bitAnd,
-
-  /**
-   * Pop the top 2 values from the stack, compute `v1 | v2`, and push the
-   * result back onto the stack.
-   */
-  bitOr,
-
-  /**
-   * Pop the top 2 values from the stack, compute `v1 >> v2`, and push the
-   * result back onto the stack.
-   */
-  bitShiftRight,
-
-  /**
-   * Pop the top 2 values from the stack, compute `v1 << v2`, and push the
-   * result back onto the stack.
-   */
-  bitShiftLeft,
-
-  /**
-   * Pop the top 2 values from the stack, compute `v1 + v2`, and push the
-   * result back onto the stack.
-   */
-  add,
-
-  /**
-   * Pop the top value from the stack, compute its integer negation, and push
-   * the result back onto the stack.
-   */
-  negate,
-
-  /**
-   * Pop the top 2 values from the stack, compute `v1 - v2`, and push the
-   * result back onto the stack.
-   */
-  subtract,
-
-  /**
-   * Pop the top 2 values from the stack, compute `v1 * v2`, and push the
-   * result back onto the stack.
-   */
-  multiply,
-
-  /**
-   * Pop the top 2 values from the stack, compute `v1 / v2`, and push the
-   * result back onto the stack.
-   */
-  divide,
-
-  /**
-   * Pop the top 2 values from the stack, compute `v1 ~/ v2`, and push the
-   * result back onto the stack.
-   */
-  floorDivide,
-
-  /**
-   * Pop the top 2 values from the stack, compute `v1 > v2`, and push the
-   * result back onto the stack.
-   */
-  greater,
-
-  /**
-   * Pop the top 2 values from the stack, compute `v1 < v2`, and push the
-   * result back onto the stack.
-   */
-  less,
-
-  /**
-   * Pop the top 2 values from the stack, compute `v1 >= v2`, and push the
-   * result back onto the stack.
-   */
-  greaterEqual,
-
-  /**
-   * Pop the top 2 values from the stack, compute `v1 <= v2`, and push the
-   * result back onto the stack.
-   */
-  lessEqual,
-
-  /**
-   * Pop the top 2 values from the stack, compute `v1 % v2`, and push the
-   * result back onto the stack.
-   */
-  modulo,
-
-  /**
-   * Pop the top 3 values from the stack, compute `v1 ? v2 : v3`, and push the
-   * result back onto the stack.
-   */
-  conditional,
-
-  /**
-   * Pop from the stack `value` and get the next `target` reference from
-   * [UnlinkedConst.references] - a top-level variable (prefixed or not), an
-   * assignable field of a class (prefixed or not), or a sequence of getters
-   * ending with an assignable property `a.b.b.c.d.e`.  In general `a.b` cannot
-   * not be distinguished between: `a` is a prefix and `b` is a top-level
-   * variable; or `a` is an object and `b` is the name of a property.  Perform
-   * `reference op= value` where `op` is the next assignment operator from
-   * [UnlinkedConst.assignmentOperators].  Push `value` back into the stack.
-   *
-   * If the assignment operator is a prefix/postfix increment/decrement, then
-   * `value` is not present in the stack, so it should not be popped and the
-   * corresponding value of the `target` after/before update is pushed into the
-   * stack instead.
-   */
-  assignToRef,
-
-  /**
-   * Pop from the stack `target` and `value`.  Get the name of the property from
-   * `UnlinkedConst.strings` and assign the `value` to the named property of the
-   * `target`.  This operation is used when we know that the `target` is an
-   * object reference expression, e.g. `new Foo().a.b.c` or `a.b[0].c.d`.
-   * Perform `target.property op= value` where `op` is the next assignment
-   * operator from [UnlinkedConst.assignmentOperators].  Push `value` back into
-   * the stack.
-   *
-   * If the assignment operator is a prefix/postfix increment/decrement, then
-   * `value` is not present in the stack, so it should not be popped and the
-   * corresponding value of the `target` after/before update is pushed into the
-   * stack instead.
-   */
-  assignToProperty,
-
-  /**
-   * Pop from the stack `index`, `target` and `value`.  Perform
-   * `target[index] op= value`  where `op` is the next assignment operator from
-   * [UnlinkedConst.assignmentOperators].  Push `value` back into the stack.
-   *
-   * If the assignment operator is a prefix/postfix increment/decrement, then
-   * `value` is not present in the stack, so it should not be popped and the
-   * corresponding value of the `target` after/before update is pushed into the
-   * stack instead.
-   */
-  assignToIndex,
-
-  /**
-   * Pop from the stack `index` and `target`.  Push into the stack the result
-   * of evaluation of `target[index]`.
-   */
-  extractIndex,
-
-  /**
-   * Pop the top `n` values from the stack (where `n` is obtained from
-   * [UnlinkedConst.ints]) into a list (filled from the end) and take the next
-   * `n` values from [UnlinkedConst.strings] and use the lists of names and
-   * values to create named arguments.  Then pop the top `m` values from the
-   * stack (where `m` is obtained from [UnlinkedConst.ints]) into a list (filled
-   * from the end) and use them as positional arguments.  Use the lists of
-   * positional and names arguments to invoke a method (or a function) with
-   * the reference from [UnlinkedConst.references].  If `k` is nonzero (where
-   * `k` is obtained from [UnlinkedConst.ints]), obtain `k` type arguments from
-   * [UnlinkedConst.references] and use them as generic type arguments for the
-   * aforementioned method or function.  Push the result of the invocation onto
-   * the stack.
-   *
-   * In general `a.b` cannot not be distinguished between: `a` is a prefix and
-   * `b` is a top-level function; or `a` is an object and `b` is the name of a
-   * method.  This operation should be used for a sequence of identifiers
-   * `a.b.b.c.d.e` ending with an invokable result.
-   */
-  invokeMethodRef,
-
-  /**
-   * Pop the top `n` values from the stack (where `n` is obtained from
-   * [UnlinkedConst.ints]) into a list (filled from the end) and take the next
-   * `n` values from [UnlinkedConst.strings] and use the lists of names and
-   * values to create named arguments.  Then pop the top `m` values from the
-   * stack (where `m` is obtained from [UnlinkedConst.ints]) into a list (filled
-   * from the end) and use them as positional arguments.  Use the lists of
-   * positional and names arguments to invoke the method with the name from
-   * [UnlinkedConst.strings] of the target popped from the stack.  If `k` is
-   * nonzero (where `k` is obtained from [UnlinkedConst.ints]), obtain `k` type
-   * arguments from [UnlinkedConst.references] and use them as generic type
-   * arguments for the aforementioned method.  Push the result of the
-   * invocation onto the stack.
-   *
-   * This operation should be used for invocation of a method invocation
-   * where `target` is known to be an object instance.
-   */
-  invokeMethod,
-
-  /**
-   * Begin a new cascade section.  Duplicate the top value of the stack.
-   */
-  cascadeSectionBegin,
-
-  /**
-   * End a new cascade section.  Pop the top value from the stack and throw it
-   * away.
-   */
-  cascadeSectionEnd,
-
-  /**
-   * Pop the top value from the stack and cast it to the type with reference
-   * from [UnlinkedConst.references], push the result into the stack.
-   */
-  typeCast,
-
-  /**
-   * Pop the top value from the stack and check whether it is a subclass of the
-   * type with reference from [UnlinkedConst.references], push the result into
-   * the stack.
-   */
-  typeCheck,
-
-  /**
-   * Pop the top value from the stack and raise an exception with this value.
-   */
-  throwException,
-
-  /**
-   * Obtain two values `n` and `m` from [UnlinkedConst.ints].  Then, starting at
-   * the executable element for the expression being evaluated, if n > 0, pop to
-   * the nth enclosing function element.  Then, push the mth local function of
-   * that element onto the stack.
-   */
-  pushLocalFunctionReference,
-}
-
-/**
  * Unlinked summary information about a constructor initializer.
  */
 abstract class UnlinkedConstructorInitializer extends base.SummaryClass {
@@ -1610,14 +1135,14 @@
    * invocation.  Otherwise empty.
    */
   @Id(3)
-  List<UnlinkedConst> get arguments;
+  List<UnlinkedExpr> get arguments;
 
   /**
    * If [kind] is `field`, the expression of the field initializer.
    * Otherwise `null`.
    */
   @Id(1)
-  UnlinkedConst get expression;
+  UnlinkedExpr get expression;
 
   /**
    * The kind of the constructor initializer (field, redirect, super).
@@ -1692,7 +1217,7 @@
    * Annotations for this enum.
    */
   @Id(4)
-  List<UnlinkedConst> get annotations;
+  List<UnlinkedExpr> get annotations;
 
   /**
    * Code range of the enum.
@@ -1765,7 +1290,7 @@
    * Annotations for this executable.
    */
   @Id(6)
-  List<UnlinkedConst> get annotations;
+  List<UnlinkedExpr> get annotations;
 
   /**
    * If this executable's function body is declared using `=>`, the expression
@@ -1773,7 +1298,7 @@
    * constant evaluation depends on the function body.
    */
   @Id(29)
-  UnlinkedConst get bodyExpr;
+  UnlinkedExpr get bodyExpr;
 
   /**
    * Code range of the executable.
@@ -2022,7 +1547,7 @@
    * Annotations for this export directive.
    */
   @Id(3)
-  List<UnlinkedConst> get annotations;
+  List<UnlinkedExpr> get annotations;
 
   /**
    * Offset of the "export" keyword.
@@ -2074,11 +1599,72 @@
 }
 
 /**
+ * Unlinked summary information about an expression.
+ *
+ * Expressions are represented using a simple stack-based language
+ * where [operations] is a sequence of operations to execute starting with an
+ * empty stack.  Once all operations have been executed, the stack should
+ * contain a single value which is the value of the constant.  Note that some
+ * operations consume additional data from the other fields of this class.
+ */
+abstract class UnlinkedExpr extends base.SummaryClass {
+  /**
+   * Sequence of operators used by assignment operations.
+   */
+  @Id(6)
+  List<UnlinkedExprAssignOperator> get assignmentOperators;
+
+  /**
+   * Sequence of 64-bit doubles consumed by the operation `pushDouble`.
+   */
+  @Id(4)
+  List<double> get doubles;
+
+  /**
+   * Sequence of unsigned 32-bit integers consumed by the operations
+   * `pushArgument`, `pushInt`, `shiftOr`, `concatenate`, `invokeConstructor`,
+   * `makeList`, and `makeMap`.
+   */
+  @Id(1)
+  List<int> get ints;
+
+  /**
+   * Indicates whether the expression is a valid potentially constant
+   * expression.
+   */
+  @Id(5)
+  bool get isValidConst;
+
+  /**
+   * Sequence of operations to execute (starting with an empty stack) to form
+   * the constant value.
+   */
+  @Id(0)
+  List<UnlinkedExprOperation> get operations;
+
+  /**
+   * Sequence of language constructs consumed by the operations
+   * `pushReference`, `invokeConstructor`, `makeList`, and `makeMap`.  Note
+   * that in the case of `pushReference` (and sometimes `invokeConstructor` the
+   * actual entity being referred to may be something other than a type.
+   */
+  @Id(2)
+  List<EntityRef> get references;
+
+  /**
+   * Sequence of strings consumed by the operations `pushString` and
+   * `invokeConstructor`.
+   */
+  @Id(3)
+  List<String> get strings;
+}
+
+/**
  * Enum representing the various kinds of assignment operations combined
  * with:
- *    [UnlinkedConstOperation.assignToRef],
- *    [UnlinkedConstOperation.assignToProperty],
- *    [UnlinkedConstOperation.assignToIndex].
+ *    [UnlinkedExprOperation.assignToRef],
+ *    [UnlinkedExprOperation.assignToProperty],
+ *    [UnlinkedExprOperation.assignToIndex].
  */
 enum UnlinkedExprAssignOperator {
   /**
@@ -2168,6 +1754,419 @@
 }
 
 /**
+ * Enum representing the various kinds of operations which may be performed to
+ * in an expression.  These options are assumed to execute in the
+ * context of a stack which is initially empty.
+ */
+enum UnlinkedExprOperation {
+  /**
+   * Push the next value from [UnlinkedExpr.ints] (a 32-bit unsigned integer)
+   * onto the stack.
+   *
+   * Note that Dart supports integers larger than 32 bits; these are
+   * represented by composing 32-bit values using the [pushLongInt] operation.
+   */
+  pushInt,
+
+  /**
+   * Get the number of components from [UnlinkedExpr.ints], then do this number
+   * of times the following operations: multiple the current value by 2^32, "or"
+   * it with the next value in [UnlinkedExpr.ints]. The initial value is zero.
+   * Push the result into the stack.
+   */
+  pushLongInt,
+
+  /**
+   * Push the next value from [UnlinkedExpr.doubles] (a double precision
+   * floating point value) onto the stack.
+   */
+  pushDouble,
+
+  /**
+   * Push the constant `true` onto the stack.
+   */
+  pushTrue,
+
+  /**
+   * Push the constant `false` onto the stack.
+   */
+  pushFalse,
+
+  /**
+   * Push the next value from [UnlinkedExpr.strings] onto the stack.
+   */
+  pushString,
+
+  /**
+   * Pop the top n values from the stack (where n is obtained from
+   * [UnlinkedExpr.ints]), convert them to strings (if they aren't already),
+   * concatenate them into a single string, and push it back onto the stack.
+   *
+   * This operation is used to represent constants whose value is a literal
+   * string containing string interpolations.
+   */
+  concatenate,
+
+  /**
+   * Get the next value from [UnlinkedExpr.strings], convert it to a symbol,
+   * and push it onto the stack.
+   */
+  makeSymbol,
+
+  /**
+   * Push the constant `null` onto the stack.
+   */
+  pushNull,
+
+  /**
+   * Push the value of the function parameter with the name obtained from
+   * [UnlinkedExpr.strings].
+   */
+  pushParameter,
+
+  /**
+   * Evaluate a (potentially qualified) identifier expression and push the
+   * resulting value onto the stack.  The identifier to be evaluated is
+   * obtained from [UnlinkedExpr.references].
+   *
+   * This operation is used to represent the following kinds of constants
+   * (which are indistinguishable from an unresolved AST alone):
+   *
+   * - A qualified reference to a static constant variable (e.g. `C.v`, where
+   *   C is a class and `v` is a constant static variable in `C`).
+   * - An identifier expression referring to a constant variable.
+   * - A simple or qualified identifier denoting a class or type alias.
+   * - A simple or qualified identifier denoting a top-level function or a
+   *   static method.
+   */
+  pushReference,
+
+  /**
+   * Pop the top value from the stack, extract the value of the property with
+   * the name obtained from [UnlinkedExpr.strings], and push the result back
+   * onto the stack.
+   */
+  extractProperty,
+
+  /**
+   * Pop the top `n` values from the stack (where `n` is obtained from
+   * [UnlinkedExpr.ints]) into a list (filled from the end) and take the next
+   * `n` values from [UnlinkedExpr.strings] and use the lists of names and
+   * values to create named arguments.  Then pop the top `m` values from the
+   * stack (where `m` is obtained from [UnlinkedExpr.ints]) into a list (filled
+   * from the end) and use them as positional arguments.  Use the lists of
+   * positional and names arguments to invoke a constant constructor obtained
+   * from [UnlinkedExpr.references], and push the resulting value back onto the
+   * stack.
+   *
+   * Note that for an invocation of the form `const a.b(...)` (where no type
+   * arguments are specified), it is impossible to tell from the unresolved AST
+   * alone whether `a` is a class name and `b` is a constructor name, or `a` is
+   * a prefix name and `b` is a class name.  For consistency between AST based
+   * and elements based summaries, references to default constructors are always
+   * recorded as references to corresponding classes.
+   */
+  invokeConstructor,
+
+  /**
+   * Pop the top n values from the stack (where n is obtained from
+   * [UnlinkedExpr.ints]), place them in a [List], and push the result back
+   * onto the stack.  The type parameter for the [List] is implicitly `dynamic`.
+   */
+  makeUntypedList,
+
+  /**
+   * Pop the top 2*n values from the stack (where n is obtained from
+   * [UnlinkedExpr.ints]), interpret them as key/value pairs, place them in a
+   * [Map], and push the result back onto the stack.  The two type parameters
+   * for the [Map] are implicitly `dynamic`.
+   */
+  makeUntypedMap,
+
+  /**
+   * Pop the top n values from the stack (where n is obtained from
+   * [UnlinkedExpr.ints]), place them in a [List], and push the result back
+   * onto the stack.  The type parameter for the [List] is obtained from
+   * [UnlinkedExpr.references].
+   */
+  makeTypedList,
+
+  /**
+   * Pop the top 2*n values from the stack (where n is obtained from
+   * [UnlinkedExpr.ints]), interpret them as key/value pairs, place them in a
+   * [Map], and push the result back onto the stack.  The two type parameters for
+   * the [Map] are obtained from [UnlinkedExpr.references].
+   */
+  makeTypedMap,
+
+  /**
+   * Pop the top 2 values from the stack, evaluate `v1 == v2`, and push the
+   * result back onto the stack.
+   */
+  equal,
+
+  /**
+   * Pop the top 2 values from the stack, evaluate `v1 != v2`, and push the
+   * result back onto the stack.
+   */
+  notEqual,
+
+  /**
+   * Pop the top value from the stack, compute its boolean negation, and push
+   * the result back onto the stack.
+   */
+  not,
+
+  /**
+   * Pop the top 2 values from the stack, compute `v1 && v2`, and push the
+   * result back onto the stack.
+   */
+  and,
+
+  /**
+   * Pop the top 2 values from the stack, compute `v1 || v2`, and push the
+   * result back onto the stack.
+   */
+  or,
+
+  /**
+   * Pop the top value from the stack, compute its integer complement, and push
+   * the result back onto the stack.
+   */
+  complement,
+
+  /**
+   * Pop the top 2 values from the stack, compute `v1 ^ v2`, and push the
+   * result back onto the stack.
+   */
+  bitXor,
+
+  /**
+   * Pop the top 2 values from the stack, compute `v1 & v2`, and push the
+   * result back onto the stack.
+   */
+  bitAnd,
+
+  /**
+   * Pop the top 2 values from the stack, compute `v1 | v2`, and push the
+   * result back onto the stack.
+   */
+  bitOr,
+
+  /**
+   * Pop the top 2 values from the stack, compute `v1 >> v2`, and push the
+   * result back onto the stack.
+   */
+  bitShiftRight,
+
+  /**
+   * Pop the top 2 values from the stack, compute `v1 << v2`, and push the
+   * result back onto the stack.
+   */
+  bitShiftLeft,
+
+  /**
+   * Pop the top 2 values from the stack, compute `v1 + v2`, and push the
+   * result back onto the stack.
+   */
+  add,
+
+  /**
+   * Pop the top value from the stack, compute its integer negation, and push
+   * the result back onto the stack.
+   */
+  negate,
+
+  /**
+   * Pop the top 2 values from the stack, compute `v1 - v2`, and push the
+   * result back onto the stack.
+   */
+  subtract,
+
+  /**
+   * Pop the top 2 values from the stack, compute `v1 * v2`, and push the
+   * result back onto the stack.
+   */
+  multiply,
+
+  /**
+   * Pop the top 2 values from the stack, compute `v1 / v2`, and push the
+   * result back onto the stack.
+   */
+  divide,
+
+  /**
+   * Pop the top 2 values from the stack, compute `v1 ~/ v2`, and push the
+   * result back onto the stack.
+   */
+  floorDivide,
+
+  /**
+   * Pop the top 2 values from the stack, compute `v1 > v2`, and push the
+   * result back onto the stack.
+   */
+  greater,
+
+  /**
+   * Pop the top 2 values from the stack, compute `v1 < v2`, and push the
+   * result back onto the stack.
+   */
+  less,
+
+  /**
+   * Pop the top 2 values from the stack, compute `v1 >= v2`, and push the
+   * result back onto the stack.
+   */
+  greaterEqual,
+
+  /**
+   * Pop the top 2 values from the stack, compute `v1 <= v2`, and push the
+   * result back onto the stack.
+   */
+  lessEqual,
+
+  /**
+   * Pop the top 2 values from the stack, compute `v1 % v2`, and push the
+   * result back onto the stack.
+   */
+  modulo,
+
+  /**
+   * Pop the top 3 values from the stack, compute `v1 ? v2 : v3`, and push the
+   * result back onto the stack.
+   */
+  conditional,
+
+  /**
+   * Pop from the stack `value` and get the next `target` reference from
+   * [UnlinkedExpr.references] - a top-level variable (prefixed or not), an
+   * assignable field of a class (prefixed or not), or a sequence of getters
+   * ending with an assignable property `a.b.b.c.d.e`.  In general `a.b` cannot
+   * not be distinguished between: `a` is a prefix and `b` is a top-level
+   * variable; or `a` is an object and `b` is the name of a property.  Perform
+   * `reference op= value` where `op` is the next assignment operator from
+   * [UnlinkedExpr.assignmentOperators].  Push `value` back into the stack.
+   *
+   * If the assignment operator is a prefix/postfix increment/decrement, then
+   * `value` is not present in the stack, so it should not be popped and the
+   * corresponding value of the `target` after/before update is pushed into the
+   * stack instead.
+   */
+  assignToRef,
+
+  /**
+   * Pop from the stack `target` and `value`.  Get the name of the property from
+   * `UnlinkedConst.strings` and assign the `value` to the named property of the
+   * `target`.  This operation is used when we know that the `target` is an
+   * object reference expression, e.g. `new Foo().a.b.c` or `a.b[0].c.d`.
+   * Perform `target.property op= value` where `op` is the next assignment
+   * operator from [UnlinkedExpr.assignmentOperators].  Push `value` back into
+   * the stack.
+   *
+   * If the assignment operator is a prefix/postfix increment/decrement, then
+   * `value` is not present in the stack, so it should not be popped and the
+   * corresponding value of the `target` after/before update is pushed into the
+   * stack instead.
+   */
+  assignToProperty,
+
+  /**
+   * Pop from the stack `index`, `target` and `value`.  Perform
+   * `target[index] op= value`  where `op` is the next assignment operator from
+   * [UnlinkedExpr.assignmentOperators].  Push `value` back into the stack.
+   *
+   * If the assignment operator is a prefix/postfix increment/decrement, then
+   * `value` is not present in the stack, so it should not be popped and the
+   * corresponding value of the `target` after/before update is pushed into the
+   * stack instead.
+   */
+  assignToIndex,
+
+  /**
+   * Pop from the stack `index` and `target`.  Push into the stack the result
+   * of evaluation of `target[index]`.
+   */
+  extractIndex,
+
+  /**
+   * Pop the top `n` values from the stack (where `n` is obtained from
+   * [UnlinkedExpr.ints]) into a list (filled from the end) and take the next
+   * `n` values from [UnlinkedExpr.strings] and use the lists of names and
+   * values to create named arguments.  Then pop the top `m` values from the
+   * stack (where `m` is obtained from [UnlinkedExpr.ints]) into a list (filled
+   * from the end) and use them as positional arguments.  Use the lists of
+   * positional and names arguments to invoke a method (or a function) with
+   * the reference from [UnlinkedExpr.references].  If `k` is nonzero (where
+   * `k` is obtained from [UnlinkedExpr.ints]), obtain `k` type arguments from
+   * [UnlinkedExpr.references] and use them as generic type arguments for the
+   * aforementioned method or function.  Push the result of the invocation onto
+   * the stack.
+   *
+   * In general `a.b` cannot not be distinguished between: `a` is a prefix and
+   * `b` is a top-level function; or `a` is an object and `b` is the name of a
+   * method.  This operation should be used for a sequence of identifiers
+   * `a.b.b.c.d.e` ending with an invokable result.
+   */
+  invokeMethodRef,
+
+  /**
+   * Pop the top `n` values from the stack (where `n` is obtained from
+   * [UnlinkedExpr.ints]) into a list (filled from the end) and take the next
+   * `n` values from [UnlinkedExpr.strings] and use the lists of names and
+   * values to create named arguments.  Then pop the top `m` values from the
+   * stack (where `m` is obtained from [UnlinkedExpr.ints]) into a list (filled
+   * from the end) and use them as positional arguments.  Use the lists of
+   * positional and names arguments to invoke the method with the name from
+   * [UnlinkedExpr.strings] of the target popped from the stack.  If `k` is
+   * nonzero (where `k` is obtained from [UnlinkedExpr.ints]), obtain `k` type
+   * arguments from [UnlinkedExpr.references] and use them as generic type
+   * arguments for the aforementioned method.  Push the result of the
+   * invocation onto the stack.
+   *
+   * This operation should be used for invocation of a method invocation
+   * where `target` is known to be an object instance.
+   */
+  invokeMethod,
+
+  /**
+   * Begin a new cascade section.  Duplicate the top value of the stack.
+   */
+  cascadeSectionBegin,
+
+  /**
+   * End a new cascade section.  Pop the top value from the stack and throw it
+   * away.
+   */
+  cascadeSectionEnd,
+
+  /**
+   * Pop the top value from the stack and cast it to the type with reference
+   * from [UnlinkedExpr.references], push the result into the stack.
+   */
+  typeCast,
+
+  /**
+   * Pop the top value from the stack and check whether it is a subclass of the
+   * type with reference from [UnlinkedExpr.references], push the result into
+   * the stack.
+   */
+  typeCheck,
+
+  /**
+   * Pop the top value from the stack and raise an exception with this value.
+   */
+  throwException,
+
+  /**
+   * Obtain two values `n` and `m` from [UnlinkedExpr.ints].  Then, starting at
+   * the executable element for the expression being evaluated, if n > 0, pop to
+   * the nth enclosing function element.  Then, push the mth local function of
+   * that element onto the stack.
+   */
+  pushLocalFunctionReference,
+}
+
+/**
  * Unlinked summary information about an import declaration.
  */
 abstract class UnlinkedImport extends base.SummaryClass {
@@ -2175,7 +2174,7 @@
    * Annotations for this import declaration.
    */
   @Id(8)
-  List<UnlinkedConst> get annotations;
+  List<UnlinkedExpr> get annotations;
 
   /**
    * Combinators contained in this import declaration.
@@ -2289,7 +2288,7 @@
    * Annotations for this parameter.
    */
   @Id(9)
-  List<UnlinkedConst> get annotations;
+  List<UnlinkedExpr> get annotations;
 
   /**
    * Code range of the parameter.
@@ -2427,7 +2426,7 @@
    * Annotations for this part declaration.
    */
   @Id(2)
-  List<UnlinkedConst> get annotations;
+  List<UnlinkedExpr> get annotations;
 
   /**
    * End of the URI string (including quotes) relative to the beginning of the
@@ -2551,7 +2550,7 @@
    * Annotations for this typedef.
    */
   @Id(4)
-  List<UnlinkedConst> get annotations;
+  List<UnlinkedExpr> get annotations;
 
   /**
    * Code range of the typedef.
@@ -2608,7 +2607,7 @@
    * Annotations for this type parameter.
    */
   @Id(3)
-  List<UnlinkedConst> get annotations;
+  List<UnlinkedExpr> get annotations;
 
   /**
    * Bound of the type parameter, if a bound is explicitly declared.  Otherwise
@@ -2713,7 +2712,7 @@
    * library declaration.
    */
   @Id(14)
-  List<UnlinkedConst> get libraryAnnotations;
+  List<UnlinkedExpr> get libraryAnnotations;
 
   /**
    * Documentation comment for the library, or `null` if there is no
@@ -2796,7 +2795,7 @@
    * Annotations for this variable.
    */
   @Id(8)
-  List<UnlinkedConst> get annotations;
+  List<UnlinkedExpr> get annotations;
 
   /**
    * Code range of the variable.
diff --git a/pkg/analyzer/lib/src/summary/link.dart b/pkg/analyzer/lib/src/summary/link.dart
index 87828c3..6b2e1d7 100644
--- a/pkg/analyzer/lib/src/summary/link.dart
+++ b/pkg/analyzer/lib/src/summary/link.dart
@@ -1449,7 +1449,7 @@
             constructorElement.enclosingElement.enclosingElement;
         collectDependencies(
             dependencies, constructorInitializer.expression, compilationUnit);
-        for (UnlinkedConst unlinkedConst in constructorInitializer.arguments) {
+        for (UnlinkedExpr unlinkedConst in constructorInitializer.arguments) {
           collectDependencies(dependencies, unlinkedConst, compilationUnit);
         }
       }
@@ -1534,26 +1534,26 @@
    */
   void collectDependencies(
       List<ConstNode> dependencies,
-      UnlinkedConst unlinkedConst,
+      UnlinkedExpr unlinkedConst,
       CompilationUnitElementForLink compilationUnit) {
     if (unlinkedConst == null) {
       return;
     }
     int refPtr = 0;
     int intPtr = 0;
-    for (UnlinkedConstOperation operation in unlinkedConst.operations) {
+    for (UnlinkedExprOperation operation in unlinkedConst.operations) {
       switch (operation) {
-        case UnlinkedConstOperation.pushInt:
+        case UnlinkedExprOperation.pushInt:
           intPtr++;
           break;
-        case UnlinkedConstOperation.pushLongInt:
+        case UnlinkedExprOperation.pushLongInt:
           int numInts = unlinkedConst.ints[intPtr++];
           intPtr += numInts;
           break;
-        case UnlinkedConstOperation.concatenate:
+        case UnlinkedExprOperation.concatenate:
           intPtr++;
           break;
-        case UnlinkedConstOperation.pushReference:
+        case UnlinkedExprOperation.pushReference:
           EntityRef ref = unlinkedConst.references[refPtr++];
           ConstVariableNode variable =
               compilationUnit.resolveRef(ref.reference).asConstVariable;
@@ -1561,14 +1561,14 @@
             dependencies.add(variable);
           }
           break;
-        case UnlinkedConstOperation.makeUntypedList:
-        case UnlinkedConstOperation.makeUntypedMap:
+        case UnlinkedExprOperation.makeUntypedList:
+        case UnlinkedExprOperation.makeUntypedMap:
           intPtr++;
           break;
-        case UnlinkedConstOperation.assignToRef:
+        case UnlinkedExprOperation.assignToRef:
           refPtr++;
           break;
-        case UnlinkedConstOperation.invokeMethodRef:
+        case UnlinkedExprOperation.invokeMethodRef:
           EntityRef ref = unlinkedConst.references[refPtr++];
           ConstVariableNode variable =
               compilationUnit.resolveRef(ref.reference).asConstVariable;
@@ -1579,20 +1579,20 @@
           int numTypeArguments = unlinkedConst.ints[intPtr++];
           refPtr += numTypeArguments;
           break;
-        case UnlinkedConstOperation.invokeMethod:
+        case UnlinkedExprOperation.invokeMethod:
           intPtr += 2;
           int numTypeArguments = unlinkedConst.ints[intPtr++];
           refPtr += numTypeArguments;
           break;
-        case UnlinkedConstOperation.makeTypedList:
+        case UnlinkedExprOperation.makeTypedList:
           refPtr++;
           intPtr++;
           break;
-        case UnlinkedConstOperation.makeTypedMap:
+        case UnlinkedExprOperation.makeTypedMap:
           refPtr += 2;
           intPtr++;
           break;
-        case UnlinkedConstOperation.invokeConstructor:
+        case UnlinkedExprOperation.invokeConstructor:
           EntityRef ref = unlinkedConst.references[refPtr++];
           ConstructorElementForLink element =
               compilationUnit.resolveRef(ref.reference).asConstructor;
@@ -1601,11 +1601,11 @@
           }
           intPtr += 2;
           break;
-        case UnlinkedConstOperation.typeCast:
-        case UnlinkedConstOperation.typeCheck:
+        case UnlinkedExprOperation.typeCast:
+        case UnlinkedExprOperation.typeCheck:
           refPtr++;
           break;
-        case UnlinkedConstOperation.pushLocalFunctionReference:
+        case UnlinkedExprOperation.pushLocalFunctionReference:
           intPtr += 2;
           break;
         default:
@@ -2072,7 +2072,7 @@
   final LibraryElementForLink library;
   final Linker linker;
   final TypeProvider typeProvider;
-  final UnlinkedConst unlinkedConst;
+  final UnlinkedExpr unlinkedConst;
 
   final List<DartType> stack = <DartType>[];
   int intPtr = 0;
@@ -2085,7 +2085,7 @@
     LibraryElementForLink library = unit.enclosingElement;
     Linker linker = library._linker;
     TypeProvider typeProvider = linker.typeProvider;
-    UnlinkedConst unlinkedConst = functionElement._unlinkedExecutable.bodyExpr;
+    UnlinkedExpr unlinkedConst = functionElement._unlinkedExecutable.bodyExpr;
     return new ExprTypeComputer._(
         functionElement, unit, library, linker, typeProvider, unlinkedConst);
   }
@@ -2100,169 +2100,169 @@
       return DynamicTypeImpl.instance;
     }
     // Perform RPN evaluation of the constant, using a stack of inferred types.
-    for (UnlinkedConstOperation operation in unlinkedConst.operations) {
+    for (UnlinkedExprOperation operation in unlinkedConst.operations) {
       switch (operation) {
-        case UnlinkedConstOperation.pushInt:
+        case UnlinkedExprOperation.pushInt:
           intPtr++;
           stack.add(typeProvider.intType);
           break;
-        case UnlinkedConstOperation.pushLongInt:
+        case UnlinkedExprOperation.pushLongInt:
           int numInts = _getNextInt();
           intPtr += numInts;
           stack.add(typeProvider.intType);
           break;
-        case UnlinkedConstOperation.pushDouble:
+        case UnlinkedExprOperation.pushDouble:
           stack.add(typeProvider.doubleType);
           break;
-        case UnlinkedConstOperation.pushTrue:
-        case UnlinkedConstOperation.pushFalse:
+        case UnlinkedExprOperation.pushTrue:
+        case UnlinkedExprOperation.pushFalse:
           stack.add(typeProvider.boolType);
           break;
-        case UnlinkedConstOperation.pushString:
+        case UnlinkedExprOperation.pushString:
           strPtr++;
           stack.add(typeProvider.stringType);
           break;
-        case UnlinkedConstOperation.concatenate:
+        case UnlinkedExprOperation.concatenate:
           stack.length -= _getNextInt();
           stack.add(typeProvider.stringType);
           break;
-        case UnlinkedConstOperation.makeSymbol:
+        case UnlinkedExprOperation.makeSymbol:
           strPtr++;
           stack.add(typeProvider.symbolType);
           break;
-        case UnlinkedConstOperation.pushNull:
+        case UnlinkedExprOperation.pushNull:
           stack.add(BottomTypeImpl.instance);
           break;
-        case UnlinkedConstOperation.pushReference:
+        case UnlinkedExprOperation.pushReference:
           _doPushReference();
           break;
-        case UnlinkedConstOperation.extractProperty:
+        case UnlinkedExprOperation.extractProperty:
           _doExtractProperty();
           break;
-        case UnlinkedConstOperation.invokeConstructor:
+        case UnlinkedExprOperation.invokeConstructor:
           _doInvokeConstructor();
           break;
-        case UnlinkedConstOperation.makeUntypedList:
+        case UnlinkedExprOperation.makeUntypedList:
           _doMakeUntypedList();
           break;
-        case UnlinkedConstOperation.makeUntypedMap:
+        case UnlinkedExprOperation.makeUntypedMap:
           _doMakeUntypedMap();
           break;
-        case UnlinkedConstOperation.makeTypedList:
+        case UnlinkedExprOperation.makeTypedList:
           _doMakeTypedList();
           break;
-        case UnlinkedConstOperation.makeTypedMap:
+        case UnlinkedExprOperation.makeTypedMap:
           _doMakeTypeMap();
           break;
-        case UnlinkedConstOperation.not:
+        case UnlinkedExprOperation.not:
           stack.length -= 1;
           stack.add(typeProvider.boolType);
           break;
-        case UnlinkedConstOperation.complement:
+        case UnlinkedExprOperation.complement:
           _computePrefixExpressionType('~');
           break;
-        case UnlinkedConstOperation.negate:
+        case UnlinkedExprOperation.negate:
           _computePrefixExpressionType('unary-');
           break;
-        case UnlinkedConstOperation.and:
-        case UnlinkedConstOperation.or:
-        case UnlinkedConstOperation.equal:
-        case UnlinkedConstOperation.notEqual:
+        case UnlinkedExprOperation.and:
+        case UnlinkedExprOperation.or:
+        case UnlinkedExprOperation.equal:
+        case UnlinkedExprOperation.notEqual:
           stack.length -= 2;
           stack.add(typeProvider.boolType);
           break;
-        case UnlinkedConstOperation.bitXor:
+        case UnlinkedExprOperation.bitXor:
           _computeBinaryExpressionType(TokenType.CARET);
           break;
-        case UnlinkedConstOperation.bitAnd:
+        case UnlinkedExprOperation.bitAnd:
           _computeBinaryExpressionType(TokenType.AMPERSAND);
           break;
-        case UnlinkedConstOperation.bitOr:
+        case UnlinkedExprOperation.bitOr:
           _computeBinaryExpressionType(TokenType.BAR);
           break;
-        case UnlinkedConstOperation.bitShiftRight:
+        case UnlinkedExprOperation.bitShiftRight:
           _computeBinaryExpressionType(TokenType.GT_GT);
           break;
-        case UnlinkedConstOperation.bitShiftLeft:
+        case UnlinkedExprOperation.bitShiftLeft:
           _computeBinaryExpressionType(TokenType.LT_LT);
           break;
-        case UnlinkedConstOperation.add:
+        case UnlinkedExprOperation.add:
           _computeBinaryExpressionType(TokenType.PLUS);
           break;
-        case UnlinkedConstOperation.subtract:
+        case UnlinkedExprOperation.subtract:
           _computeBinaryExpressionType(TokenType.MINUS);
           break;
-        case UnlinkedConstOperation.multiply:
+        case UnlinkedExprOperation.multiply:
           _computeBinaryExpressionType(TokenType.STAR);
           break;
-        case UnlinkedConstOperation.divide:
+        case UnlinkedExprOperation.divide:
           _computeBinaryExpressionType(TokenType.SLASH);
           break;
-        case UnlinkedConstOperation.floorDivide:
+        case UnlinkedExprOperation.floorDivide:
           _computeBinaryExpressionType(TokenType.TILDE_SLASH);
           break;
-        case UnlinkedConstOperation.greater:
+        case UnlinkedExprOperation.greater:
           _computeBinaryExpressionType(TokenType.GT);
           break;
-        case UnlinkedConstOperation.less:
+        case UnlinkedExprOperation.less:
           _computeBinaryExpressionType(TokenType.LT);
           break;
-        case UnlinkedConstOperation.greaterEqual:
+        case UnlinkedExprOperation.greaterEqual:
           _computeBinaryExpressionType(TokenType.GT_EQ);
           break;
-        case UnlinkedConstOperation.lessEqual:
+        case UnlinkedExprOperation.lessEqual:
           _computeBinaryExpressionType(TokenType.LT_EQ);
           break;
-        case UnlinkedConstOperation.modulo:
+        case UnlinkedExprOperation.modulo:
           _computeBinaryExpressionType(TokenType.PERCENT);
           break;
-        case UnlinkedConstOperation.conditional:
+        case UnlinkedExprOperation.conditional:
           _doConditional();
           break;
-        case UnlinkedConstOperation.assignToRef:
+        case UnlinkedExprOperation.assignToRef:
           _doAssignToRef();
           break;
-        case UnlinkedConstOperation.assignToProperty:
+        case UnlinkedExprOperation.assignToProperty:
           _doAssignToProperty();
           break;
-        case UnlinkedConstOperation.assignToIndex:
+        case UnlinkedExprOperation.assignToIndex:
           _doAssignToIndex();
           break;
-        case UnlinkedConstOperation.extractIndex:
+        case UnlinkedExprOperation.extractIndex:
           _doExtractIndex();
           break;
-        case UnlinkedConstOperation.invokeMethodRef:
+        case UnlinkedExprOperation.invokeMethodRef:
           _doInvokeMethodRef();
           break;
-        case UnlinkedConstOperation.invokeMethod:
+        case UnlinkedExprOperation.invokeMethod:
           _doInvokeMethod();
           break;
-        case UnlinkedConstOperation.cascadeSectionBegin:
+        case UnlinkedExprOperation.cascadeSectionBegin:
           stack.add(stack.last);
           break;
-        case UnlinkedConstOperation.cascadeSectionEnd:
+        case UnlinkedExprOperation.cascadeSectionEnd:
           stack.removeLast();
           break;
-        case UnlinkedConstOperation.typeCast:
+        case UnlinkedExprOperation.typeCast:
           stack.removeLast();
           DartType type = _getNextTypeRef();
           stack.add(type);
           break;
-        case UnlinkedConstOperation.typeCheck:
+        case UnlinkedExprOperation.typeCheck:
           stack.removeLast();
           refPtr++;
           stack.add(typeProvider.boolType);
           break;
-        case UnlinkedConstOperation.throwException:
+        case UnlinkedExprOperation.throwException:
           stack.removeLast();
           stack.add(BottomTypeImpl.instance);
           break;
-        case UnlinkedConstOperation.pushLocalFunctionReference:
+        case UnlinkedExprOperation.pushLocalFunctionReference:
           int popCount = _getNextInt();
           assert(popCount == 0); // TODO(paulberry): handle the nonzero case.
           stack.add(function.functions[_getNextInt()].type);
           break;
-        case UnlinkedConstOperation.pushParameter:
+        case UnlinkedExprOperation.pushParameter:
           stack.add(_findParameterType(_getNextString()));
           break;
         default:
@@ -2962,6 +2962,9 @@
           .toList();
 
   @override
+  String get identifier => '';
+
+  @override
   DartType get returnType {
     // If this is a variable whose type needs inferring, infer it.
     if (_variable.hasImplicitType) {
@@ -3085,6 +3088,18 @@
           .toList();
 
   @override
+  String get identifier {
+    String identifier = _unlinkedExecutable.name;
+    Element enclosing = this.enclosingElement;
+    if (enclosing is ExecutableElement) {
+      int id =
+          ElementImpl.findElementIndexUsingIdentical(enclosing.functions, this);
+      identifier += "@$id";
+    }
+    return identifier;
+  }
+
+  @override
   bool get _hasTypeBeenInferred => _inferredReturnType != null;
 
   @override
@@ -3988,9 +4003,9 @@
     if (inheritsCovariant) {
       return true;
     }
-    for (UnlinkedConst annotation in _unlinkedParam.annotations) {
+    for (UnlinkedExpr annotation in _unlinkedParam.annotations) {
       if (annotation.operations.length == 1 &&
-          annotation.operations[0] == UnlinkedConstOperation.pushReference) {
+          annotation.operations[0] == UnlinkedExprOperation.pushReference) {
         ReferenceableElementForLink element =
             this.compilationUnit.resolveRef(annotation.references[0].reference);
         if (element is PropertyAccessorElementForLink &&
@@ -4663,26 +4678,26 @@
       List<TypeInferenceNode> dependencies,
       UnlinkedExecutable unlinkedExecutable,
       CompilationUnitElementForLink compilationUnit) {
-    UnlinkedConst unlinkedConst = unlinkedExecutable?.bodyExpr;
+    UnlinkedExpr unlinkedConst = unlinkedExecutable?.bodyExpr;
     if (unlinkedConst == null) {
       return;
     }
     int refPtr = 0;
     int intPtr = 0;
 
-    for (UnlinkedConstOperation operation in unlinkedConst.operations) {
+    for (UnlinkedExprOperation operation in unlinkedConst.operations) {
       switch (operation) {
-        case UnlinkedConstOperation.pushInt:
+        case UnlinkedExprOperation.pushInt:
           intPtr++;
           break;
-        case UnlinkedConstOperation.pushLongInt:
+        case UnlinkedExprOperation.pushLongInt:
           int numInts = unlinkedConst.ints[intPtr++];
           intPtr += numInts;
           break;
-        case UnlinkedConstOperation.concatenate:
+        case UnlinkedExprOperation.concatenate:
           intPtr++;
           break;
-        case UnlinkedConstOperation.pushReference:
+        case UnlinkedExprOperation.pushReference:
           EntityRef ref = unlinkedConst.references[refPtr++];
           // TODO(paulberry): cache these resolved references for
           // later use by evaluate().
@@ -4692,28 +4707,28 @@
             dependencies.add(dependency);
           }
           break;
-        case UnlinkedConstOperation.invokeConstructor:
+        case UnlinkedExprOperation.invokeConstructor:
           refPtr++;
           intPtr += 2;
           break;
-        case UnlinkedConstOperation.makeUntypedList:
-        case UnlinkedConstOperation.makeUntypedMap:
+        case UnlinkedExprOperation.makeUntypedList:
+        case UnlinkedExprOperation.makeUntypedMap:
           intPtr++;
           break;
-        case UnlinkedConstOperation.makeTypedList:
+        case UnlinkedExprOperation.makeTypedList:
           refPtr++;
           intPtr++;
           break;
-        case UnlinkedConstOperation.makeTypedMap:
+        case UnlinkedExprOperation.makeTypedMap:
           refPtr += 2;
           intPtr++;
           break;
-        case UnlinkedConstOperation.assignToRef:
+        case UnlinkedExprOperation.assignToRef:
           // TODO(paulberry): if this reference refers to a variable, should it
           // be considered a type inference dependency?
           refPtr++;
           break;
-        case UnlinkedConstOperation.invokeMethodRef:
+        case UnlinkedExprOperation.invokeMethodRef:
           // TODO(paulberry): if this reference refers to a variable, should it
           // be considered a type inference dependency?
           refPtr++;
@@ -4721,16 +4736,16 @@
           int numTypeArguments = unlinkedConst.ints[intPtr++];
           refPtr += numTypeArguments;
           break;
-        case UnlinkedConstOperation.invokeMethod:
+        case UnlinkedExprOperation.invokeMethod:
           intPtr += 2;
           int numTypeArguments = unlinkedConst.ints[intPtr++];
           refPtr += numTypeArguments;
           break;
-        case UnlinkedConstOperation.typeCast:
-        case UnlinkedConstOperation.typeCheck:
+        case UnlinkedExprOperation.typeCast:
+        case UnlinkedExprOperation.typeCheck:
           refPtr++;
           break;
-        case UnlinkedConstOperation.pushLocalFunctionReference:
+        case UnlinkedExprOperation.pushLocalFunctionReference:
           int popCount = unlinkedConst.ints[intPtr++];
           assert(popCount == 0); // TODO(paulberry): handle the nonzero case.
           dependencies.add(functionElement
@@ -4981,6 +4996,9 @@
   @override
   bool get hasImplicitType => unlinkedVariable.type == null;
 
+  @override
+  String get identifier => unlinkedVariable.name;
+
   /**
    * Return the inferred type of the variable element.  Should only be called if
    * no type was explicitly declared.
diff --git a/pkg/analyzer/lib/src/summary/resynthesize.dart b/pkg/analyzer/lib/src/summary/resynthesize.dart
index 0baf656..30f0aec 100644
--- a/pkg/analyzer/lib/src/summary/resynthesize.dart
+++ b/pkg/analyzer/lib/src/summary/resynthesize.dart
@@ -301,12 +301,12 @@
 }
 
 /**
- * Builder of [Expression]s from [UnlinkedConst]s.
+ * Builder of [Expression]s from [UnlinkedExpr]s.
  */
 class _ConstExprBuilder {
   final _UnitResynthesizer resynthesizer;
   final ElementImpl context;
-  final UnlinkedConst uc;
+  final UnlinkedExpr uc;
 
   int intPtr = 0;
   int doublePtr = 0;
@@ -333,24 +333,24 @@
     if (!uc.isValidConst) {
       return AstFactory.identifier3(r'$$invalidConstExpr$$');
     }
-    for (UnlinkedConstOperation operation in uc.operations) {
+    for (UnlinkedExprOperation operation in uc.operations) {
       switch (operation) {
-        case UnlinkedConstOperation.pushNull:
+        case UnlinkedExprOperation.pushNull:
           _push(AstFactory.nullLiteral());
           break;
         // bool
-        case UnlinkedConstOperation.pushFalse:
+        case UnlinkedExprOperation.pushFalse:
           _push(AstFactory.booleanLiteral(false));
           break;
-        case UnlinkedConstOperation.pushTrue:
+        case UnlinkedExprOperation.pushTrue:
           _push(AstFactory.booleanLiteral(true));
           break;
         // literals
-        case UnlinkedConstOperation.pushInt:
+        case UnlinkedExprOperation.pushInt:
           int value = uc.ints[intPtr++];
           _push(AstFactory.integer(value));
           break;
-        case UnlinkedConstOperation.pushLongInt:
+        case UnlinkedExprOperation.pushLongInt:
           int value = 0;
           int count = uc.ints[intPtr++];
           for (int i = 0; i < count; i++) {
@@ -359,20 +359,20 @@
           }
           _push(AstFactory.integer(value));
           break;
-        case UnlinkedConstOperation.pushDouble:
+        case UnlinkedExprOperation.pushDouble:
           double value = uc.doubles[doublePtr++];
           _push(AstFactory.doubleLiteral(value));
           break;
-        case UnlinkedConstOperation.makeSymbol:
+        case UnlinkedExprOperation.makeSymbol:
           String component = uc.strings[stringPtr++];
           _push(AstFactory.symbolLiteral([component]));
           break;
         // String
-        case UnlinkedConstOperation.pushString:
+        case UnlinkedExprOperation.pushString:
           String value = uc.strings[stringPtr++];
           _push(AstFactory.string2(value));
           break;
-        case UnlinkedConstOperation.concatenate:
+        case UnlinkedExprOperation.concatenate:
           int count = uc.ints[intPtr++];
           List<InterpolationElement> elements = <InterpolationElement>[];
           for (int i = 0; i < count; i++) {
@@ -383,75 +383,75 @@
           _push(AstFactory.string(elements));
           break;
         // binary
-        case UnlinkedConstOperation.equal:
+        case UnlinkedExprOperation.equal:
           _pushBinary(TokenType.EQ_EQ);
           break;
-        case UnlinkedConstOperation.notEqual:
+        case UnlinkedExprOperation.notEqual:
           _pushBinary(TokenType.BANG_EQ);
           break;
-        case UnlinkedConstOperation.and:
+        case UnlinkedExprOperation.and:
           _pushBinary(TokenType.AMPERSAND_AMPERSAND);
           break;
-        case UnlinkedConstOperation.or:
+        case UnlinkedExprOperation.or:
           _pushBinary(TokenType.BAR_BAR);
           break;
-        case UnlinkedConstOperation.bitXor:
+        case UnlinkedExprOperation.bitXor:
           _pushBinary(TokenType.CARET);
           break;
-        case UnlinkedConstOperation.bitAnd:
+        case UnlinkedExprOperation.bitAnd:
           _pushBinary(TokenType.AMPERSAND);
           break;
-        case UnlinkedConstOperation.bitOr:
+        case UnlinkedExprOperation.bitOr:
           _pushBinary(TokenType.BAR);
           break;
-        case UnlinkedConstOperation.bitShiftLeft:
+        case UnlinkedExprOperation.bitShiftLeft:
           _pushBinary(TokenType.LT_LT);
           break;
-        case UnlinkedConstOperation.bitShiftRight:
+        case UnlinkedExprOperation.bitShiftRight:
           _pushBinary(TokenType.GT_GT);
           break;
-        case UnlinkedConstOperation.add:
+        case UnlinkedExprOperation.add:
           _pushBinary(TokenType.PLUS);
           break;
-        case UnlinkedConstOperation.subtract:
+        case UnlinkedExprOperation.subtract:
           _pushBinary(TokenType.MINUS);
           break;
-        case UnlinkedConstOperation.multiply:
+        case UnlinkedExprOperation.multiply:
           _pushBinary(TokenType.STAR);
           break;
-        case UnlinkedConstOperation.divide:
+        case UnlinkedExprOperation.divide:
           _pushBinary(TokenType.SLASH);
           break;
-        case UnlinkedConstOperation.floorDivide:
+        case UnlinkedExprOperation.floorDivide:
           _pushBinary(TokenType.TILDE_SLASH);
           break;
-        case UnlinkedConstOperation.modulo:
+        case UnlinkedExprOperation.modulo:
           _pushBinary(TokenType.PERCENT);
           break;
-        case UnlinkedConstOperation.greater:
+        case UnlinkedExprOperation.greater:
           _pushBinary(TokenType.GT);
           break;
-        case UnlinkedConstOperation.greaterEqual:
+        case UnlinkedExprOperation.greaterEqual:
           _pushBinary(TokenType.GT_EQ);
           break;
-        case UnlinkedConstOperation.less:
+        case UnlinkedExprOperation.less:
           _pushBinary(TokenType.LT);
           break;
-        case UnlinkedConstOperation.lessEqual:
+        case UnlinkedExprOperation.lessEqual:
           _pushBinary(TokenType.LT_EQ);
           break;
         // prefix
-        case UnlinkedConstOperation.complement:
+        case UnlinkedExprOperation.complement:
           _pushPrefix(TokenType.TILDE);
           break;
-        case UnlinkedConstOperation.negate:
+        case UnlinkedExprOperation.negate:
           _pushPrefix(TokenType.MINUS);
           break;
-        case UnlinkedConstOperation.not:
+        case UnlinkedExprOperation.not:
           _pushPrefix(TokenType.BANG);
           break;
         // conditional
-        case UnlinkedConstOperation.conditional:
+        case UnlinkedExprOperation.conditional:
           Expression elseExpr = _pop();
           Expression thenExpr = _pop();
           Expression condition = _pop();
@@ -459,35 +459,35 @@
               AstFactory.conditionalExpression(condition, thenExpr, elseExpr));
           break;
         // invokeMethodRef
-        case UnlinkedConstOperation.invokeMethodRef:
+        case UnlinkedExprOperation.invokeMethodRef:
           _pushInvokeMethodRef();
           break;
         // containers
-        case UnlinkedConstOperation.makeUntypedList:
+        case UnlinkedExprOperation.makeUntypedList:
           _pushList(null);
           break;
-        case UnlinkedConstOperation.makeTypedList:
+        case UnlinkedExprOperation.makeTypedList:
           TypeName itemType = _newTypeName();
           _pushList(AstFactory.typeArgumentList(<TypeName>[itemType]));
           break;
-        case UnlinkedConstOperation.makeUntypedMap:
+        case UnlinkedExprOperation.makeUntypedMap:
           _pushMap(null);
           break;
-        case UnlinkedConstOperation.makeTypedMap:
+        case UnlinkedExprOperation.makeTypedMap:
           TypeName keyType = _newTypeName();
           TypeName valueType = _newTypeName();
           _pushMap(AstFactory.typeArgumentList(<TypeName>[keyType, valueType]));
           break;
-        case UnlinkedConstOperation.pushReference:
+        case UnlinkedExprOperation.pushReference:
           _pushReference();
           break;
-        case UnlinkedConstOperation.extractProperty:
+        case UnlinkedExprOperation.extractProperty:
           _pushExtractProperty();
           break;
-        case UnlinkedConstOperation.invokeConstructor:
+        case UnlinkedExprOperation.invokeConstructor:
           _pushInstanceCreation();
           break;
-        case UnlinkedConstOperation.pushParameter:
+        case UnlinkedExprOperation.pushParameter:
           String name = uc.strings[stringPtr++];
           SimpleIdentifier identifier = AstFactory.identifier3(name);
           identifier.staticElement = _enclosingConstructor.parameters
@@ -496,17 +496,17 @@
                       'Unable to resolve constructor parameter: $name'));
           _push(identifier);
           break;
-        case UnlinkedConstOperation.assignToRef:
-        case UnlinkedConstOperation.assignToProperty:
-        case UnlinkedConstOperation.assignToIndex:
-        case UnlinkedConstOperation.extractIndex:
-        case UnlinkedConstOperation.invokeMethod:
-        case UnlinkedConstOperation.cascadeSectionBegin:
-        case UnlinkedConstOperation.cascadeSectionEnd:
-        case UnlinkedConstOperation.typeCast:
-        case UnlinkedConstOperation.typeCheck:
-        case UnlinkedConstOperation.throwException:
-        case UnlinkedConstOperation.pushLocalFunctionReference:
+        case UnlinkedExprOperation.assignToRef:
+        case UnlinkedExprOperation.assignToProperty:
+        case UnlinkedExprOperation.assignToIndex:
+        case UnlinkedExprOperation.extractIndex:
+        case UnlinkedExprOperation.invokeMethod:
+        case UnlinkedExprOperation.cascadeSectionBegin:
+        case UnlinkedExprOperation.cascadeSectionEnd:
+        case UnlinkedExprOperation.typeCast:
+        case UnlinkedExprOperation.typeCheck:
+        case UnlinkedExprOperation.throwException:
+        case UnlinkedExprOperation.pushLocalFunctionReference:
           throw new UnimplementedError(
               'Unexpected $operation in a constant expression.');
       }
@@ -1370,12 +1370,12 @@
   _ResynthesizerContext(this._unitResynthesizer);
 
   @override
-  ElementAnnotationImpl buildAnnotation(ElementImpl context, UnlinkedConst uc) {
+  ElementAnnotationImpl buildAnnotation(ElementImpl context, UnlinkedExpr uc) {
     return _unitResynthesizer.buildAnnotation(context, uc);
   }
 
   @override
-  Expression buildExpression(ElementImpl context, UnlinkedConst uc) {
+  Expression buildExpression(ElementImpl context, UnlinkedExpr uc) {
     return _unitResynthesizer._buildConstExpression(context, uc);
   }
 
@@ -1507,9 +1507,9 @@
   TypeProvider get typeProvider => summaryResynthesizer.typeProvider;
 
   /**
-   * Build [ElementAnnotationImpl] for the given [UnlinkedConst].
+   * Build [ElementAnnotationImpl] for the given [UnlinkedExpr].
    */
-  ElementAnnotationImpl buildAnnotation(ElementImpl context, UnlinkedConst uc) {
+  ElementAnnotationImpl buildAnnotation(ElementImpl context, UnlinkedExpr uc) {
     ElementAnnotationImpl elementAnnotation = new ElementAnnotationImpl(unit);
     Expression constExpr = _buildConstExpression(context, uc);
     if (constExpr is Identifier) {
@@ -1804,13 +1804,14 @@
     return result;
   }
 
-  Expression _buildConstExpression(ElementImpl context, UnlinkedConst uc) {
+  Expression _buildConstExpression(ElementImpl context, UnlinkedExpr uc) {
     return new _ConstExprBuilder(this, context, uc).build();
   }
 
   /**
    * Return the defining type for a [ConstructorElement] by applying
-   * [typeArgumentRefs] to the given linked [info].
+   * [typeArgumentRefs] to the given linked [info].  Return [DynamicTypeImpl]
+   * if the [info] is unresolved.
    */
   DartType _createConstructorDefiningType(
       TypeParameterizedElementMixin typeParameterContext,
@@ -1818,6 +1819,9 @@
       List<EntityRef> typeArgumentRefs) {
     bool isClass = info.element is ClassElement;
     _ReferenceInfo classInfo = isClass ? info : info.enclosing;
+    if (classInfo == null) {
+      return DynamicTypeImpl.instance;
+    }
     List<DartType> typeArguments = typeArgumentRefs
         .map((t) => buildType(t, typeParameterContext))
         .toList();
diff --git a/pkg/analyzer/lib/src/summary/summarize_ast.dart b/pkg/analyzer/lib/src/summary/summarize_ast.dart
index b81fe88..5d35783 100644
--- a/pkg/analyzer/lib/src/summary/summarize_ast.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_ast.dart
@@ -331,7 +331,7 @@
    * If the library has a library directive, the annotations for it (if any).
    * Otherwise `null`.
    */
-  List<UnlinkedConst> libraryAnnotations = const <UnlinkedConstBuilder>[];
+  List<UnlinkedExpr> libraryAnnotations = const <UnlinkedExprBuilder>[];
 
   /**
    * The number of slot ids which have been assigned to this compilation unit.
@@ -407,10 +407,10 @@
    * Serialize the given list of [annotations].  If there are no annotations,
    * the empty list is returned.
    */
-  List<UnlinkedConstBuilder> serializeAnnotations(
+  List<UnlinkedExprBuilder> serializeAnnotations(
       NodeList<Annotation> annotations) {
     if (annotations == null || annotations.isEmpty) {
-      return const <UnlinkedConstBuilder>[];
+      return const <UnlinkedExprBuilder>[];
     }
     return annotations.map((Annotation a) {
       // Closures can't appear inside annotations, so we don't need a
@@ -546,9 +546,9 @@
   }
 
   /**
-   * Serialize the given [expression], creating an [UnlinkedConstBuilder].
+   * Serialize the given [expression], creating an [UnlinkedExprBuilder].
    */
-  UnlinkedConstBuilder serializeConstExpr(
+  UnlinkedExprBuilder serializeConstExpr(
       Map<int, int> localClosureIndexMap, Expression expression,
       [Set<String> parameterNames]) {
     _ConstExprSerializer serializer =
diff --git a/pkg/analyzer/lib/src/summary/summarize_const_expr.dart b/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
index 18db39f..4662be8 100644
--- a/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
@@ -15,7 +15,7 @@
  */
 UnlinkedConstructorInitializer serializeConstructorInitializer(
     ConstructorInitializer node,
-    UnlinkedConstBuilder serializeConstExpr(Expression expr)) {
+    UnlinkedExprBuilder serializeConstExpr(Expression expr)) {
   if (node is ConstructorFieldInitializer) {
     return new UnlinkedConstructorInitializerBuilder(
         kind: UnlinkedConstructorInitializerKind.field,
@@ -23,7 +23,7 @@
         expression: serializeConstExpr(node.expression));
   }
 
-  List<UnlinkedConstBuilder> arguments = <UnlinkedConstBuilder>[];
+  List<UnlinkedExprBuilder> arguments = <UnlinkedExprBuilder>[];
   List<String> argumentNames = <String>[];
   void serializeArguments(List<Expression> args) {
     for (Expression arg in args) {
@@ -61,43 +61,43 @@
  */
 abstract class AbstractConstExprSerializer {
   /**
-   * See [UnlinkedConstBuilder.isValidConst].
+   * See [UnlinkedExprBuilder.isValidConst].
    */
   bool isValidConst = true;
 
   /**
-   * See [UnlinkedConstBuilder.nmae].
+   * See [UnlinkedExprBuilder.nmae].
    */
   String name = null;
 
   /**
-   * See [UnlinkedConstBuilder.operations].
+   * See [UnlinkedExprBuilder.operations].
    */
-  final List<UnlinkedConstOperation> operations = <UnlinkedConstOperation>[];
+  final List<UnlinkedExprOperation> operations = <UnlinkedExprOperation>[];
 
   /**
-   * See [UnlinkedConstBuilder.assignmentOperators].
+   * See [UnlinkedExprBuilder.assignmentOperators].
    */
   final List<UnlinkedExprAssignOperator> assignmentOperators =
       <UnlinkedExprAssignOperator>[];
 
   /**
-   * See [UnlinkedConstBuilder.ints].
+   * See [UnlinkedExprBuilder.ints].
    */
   final List<int> ints = <int>[];
 
   /**
-   * See [UnlinkedConstBuilder.doubles].
+   * See [UnlinkedExprBuilder.doubles].
    */
   final List<double> doubles = <double>[];
 
   /**
-   * See [UnlinkedConstBuilder.strings].
+   * See [UnlinkedExprBuilder.strings].
    */
   final List<String> strings = <String>[];
 
   /**
-   * See [UnlinkedConstBuilder.references].
+   * See [UnlinkedExprBuilder.references].
    */
   final List<EntityRefBuilder> references = <EntityRefBuilder>[];
 
@@ -163,7 +163,7 @@
       EntityRefBuilder constructor, ArgumentList argumentList) {
     _serializeArguments(argumentList);
     references.add(constructor);
-    operations.add(UnlinkedConstOperation.invokeConstructor);
+    operations.add(UnlinkedExprOperation.invokeConstructor);
   }
 
   /**
@@ -183,11 +183,11 @@
   }
 
   /**
-   * Return the [UnlinkedConstBuilder] that corresponds to the state of this
+   * Return the [UnlinkedExprBuilder] that corresponds to the state of this
    * serializer.
    */
-  UnlinkedConstBuilder toBuilder() {
-    return new UnlinkedConstBuilder(
+  UnlinkedExprBuilder toBuilder() {
+    return new UnlinkedExprBuilder(
         isValidConst: isValidConst,
         operations: operations,
         assignmentOperators: assignmentOperators,
@@ -232,24 +232,24 @@
     if (_isIdentifierSequence(expr)) {
       EntityRefBuilder ref = serializeIdentifierSequence(expr);
       references.add(ref);
-      operations.add(UnlinkedConstOperation.assignToRef);
+      operations.add(UnlinkedExprOperation.assignToRef);
     } else if (expr is PropertyAccess) {
       if (!expr.isCascaded) {
         _serialize(expr.target);
       }
       strings.add(expr.propertyName.name);
-      operations.add(UnlinkedConstOperation.assignToProperty);
+      operations.add(UnlinkedExprOperation.assignToProperty);
     } else if (expr is IndexExpression) {
       if (!expr.isCascaded) {
         _serialize(expr.target);
       }
       _serialize(expr.index);
-      operations.add(UnlinkedConstOperation.assignToIndex);
+      operations.add(UnlinkedExprOperation.assignToIndex);
     } else if (expr is PrefixedIdentifier) {
       strings.add(expr.prefix.name);
-      operations.add(UnlinkedConstOperation.pushParameter);
+      operations.add(UnlinkedExprOperation.pushParameter);
       strings.add(expr.identifier.name);
-      operations.add(UnlinkedConstOperation.assignToProperty);
+      operations.add(UnlinkedExprOperation.assignToProperty);
     } else {
       throw new StateError('Unsupported assignable: $expr');
     }
@@ -267,11 +267,12 @@
         numOfComponents++;
         ints.add(value & 0xFFFFFFFF);
       }
+
       pushComponents(value);
       ints[ints.length - 1 - numOfComponents] = numOfComponents;
-      operations.add(UnlinkedConstOperation.pushLongInt);
+      operations.add(UnlinkedExprOperation.pushLongInt);
     } else {
-      operations.add(UnlinkedConstOperation.pushInt);
+      operations.add(UnlinkedExprOperation.pushInt);
       ints.add(value);
     }
   }
@@ -283,34 +284,34 @@
     if (expr is IntegerLiteral) {
       _pushInt(expr.value);
     } else if (expr is DoubleLiteral) {
-      operations.add(UnlinkedConstOperation.pushDouble);
+      operations.add(UnlinkedExprOperation.pushDouble);
       doubles.add(expr.value);
     } else if (expr is BooleanLiteral) {
       if (expr.value) {
-        operations.add(UnlinkedConstOperation.pushTrue);
+        operations.add(UnlinkedExprOperation.pushTrue);
       } else {
-        operations.add(UnlinkedConstOperation.pushFalse);
+        operations.add(UnlinkedExprOperation.pushFalse);
       }
     } else if (expr is StringLiteral) {
       _serializeString(expr);
     } else if (expr is SymbolLiteral) {
       strings.add(expr.components.map((token) => token.lexeme).join('.'));
-      operations.add(UnlinkedConstOperation.makeSymbol);
+      operations.add(UnlinkedExprOperation.makeSymbol);
     } else if (expr is NullLiteral) {
-      operations.add(UnlinkedConstOperation.pushNull);
+      operations.add(UnlinkedExprOperation.pushNull);
     } else if (expr is Identifier) {
       if (expr is SimpleIdentifier && isParameterName(expr.name)) {
         strings.add(expr.name);
-        operations.add(UnlinkedConstOperation.pushParameter);
+        operations.add(UnlinkedExprOperation.pushParameter);
       } else if (expr is PrefixedIdentifier &&
           isParameterName(expr.prefix.name)) {
         strings.add(expr.prefix.name);
-        operations.add(UnlinkedConstOperation.pushParameter);
+        operations.add(UnlinkedExprOperation.pushParameter);
         strings.add(expr.identifier.name);
-        operations.add(UnlinkedConstOperation.extractProperty);
+        operations.add(UnlinkedExprOperation.extractProperty);
       } else {
         references.add(serializeIdentifier(expr));
-        operations.add(UnlinkedConstOperation.pushReference);
+        operations.add(UnlinkedExprOperation.pushReference);
       }
     } else if (expr is InstanceCreationExpression) {
       if (!expr.isConst) {
@@ -333,7 +334,7 @@
       _serialize(expr.condition);
       _serialize(expr.thenExpression);
       _serialize(expr.elseExpression);
-      operations.add(UnlinkedConstOperation.conditional);
+      operations.add(UnlinkedExprOperation.conditional);
     } else if (expr is PrefixExpression) {
       _serializePrefixExpression(expr);
     } else if (expr is PostfixExpression) {
@@ -346,7 +347,7 @@
       isValidConst = false;
       _serialize(expr.target);
       _serialize(expr.index);
-      operations.add(UnlinkedConstOperation.extractIndex);
+      operations.add(UnlinkedExprOperation.extractIndex);
     } else if (expr is AssignmentExpression) {
       _serializeAssignment(expr);
     } else if (expr is CascadeExpression) {
@@ -356,29 +357,29 @@
       List<int> indices = serializeFunctionExpression(expr);
       if (indices != null) {
         ints.addAll(serializeFunctionExpression(expr));
-        operations.add(UnlinkedConstOperation.pushLocalFunctionReference);
+        operations.add(UnlinkedExprOperation.pushLocalFunctionReference);
       } else {
         // Invalid expression; just push null.
-        operations.add(UnlinkedConstOperation.pushNull);
+        operations.add(UnlinkedExprOperation.pushNull);
       }
     } else if (expr is FunctionExpressionInvocation) {
       isValidConst = false;
       // TODO(scheglov) implement
-      operations.add(UnlinkedConstOperation.pushNull);
+      operations.add(UnlinkedExprOperation.pushNull);
     } else if (expr is AsExpression) {
       isValidConst = false;
       _serialize(expr.expression);
       references.add(serializeTypeName(expr.type));
-      operations.add(UnlinkedConstOperation.typeCast);
+      operations.add(UnlinkedExprOperation.typeCast);
     } else if (expr is IsExpression) {
       isValidConst = false;
       _serialize(expr.expression);
       references.add(serializeTypeName(expr.type));
-      operations.add(UnlinkedConstOperation.typeCheck);
+      operations.add(UnlinkedExprOperation.typeCheck);
     } else if (expr is ThrowExpression) {
       isValidConst = false;
       _serialize(expr.expression);
-      operations.add(UnlinkedConstOperation.throwException);
+      operations.add(UnlinkedExprOperation.throwException);
     } else {
       throw new StateError('Unknown expression type: $expr');
     }
@@ -448,43 +449,43 @@
     _serialize(expr.rightOperand);
     TokenType operator = expr.operator.type;
     if (operator == TokenType.EQ_EQ) {
-      operations.add(UnlinkedConstOperation.equal);
+      operations.add(UnlinkedExprOperation.equal);
     } else if (operator == TokenType.BANG_EQ) {
-      operations.add(UnlinkedConstOperation.notEqual);
+      operations.add(UnlinkedExprOperation.notEqual);
     } else if (operator == TokenType.AMPERSAND_AMPERSAND) {
-      operations.add(UnlinkedConstOperation.and);
+      operations.add(UnlinkedExprOperation.and);
     } else if (operator == TokenType.BAR_BAR) {
-      operations.add(UnlinkedConstOperation.or);
+      operations.add(UnlinkedExprOperation.or);
     } else if (operator == TokenType.CARET) {
-      operations.add(UnlinkedConstOperation.bitXor);
+      operations.add(UnlinkedExprOperation.bitXor);
     } else if (operator == TokenType.AMPERSAND) {
-      operations.add(UnlinkedConstOperation.bitAnd);
+      operations.add(UnlinkedExprOperation.bitAnd);
     } else if (operator == TokenType.BAR) {
-      operations.add(UnlinkedConstOperation.bitOr);
+      operations.add(UnlinkedExprOperation.bitOr);
     } else if (operator == TokenType.GT_GT) {
-      operations.add(UnlinkedConstOperation.bitShiftRight);
+      operations.add(UnlinkedExprOperation.bitShiftRight);
     } else if (operator == TokenType.LT_LT) {
-      operations.add(UnlinkedConstOperation.bitShiftLeft);
+      operations.add(UnlinkedExprOperation.bitShiftLeft);
     } else if (operator == TokenType.PLUS) {
-      operations.add(UnlinkedConstOperation.add);
+      operations.add(UnlinkedExprOperation.add);
     } else if (operator == TokenType.MINUS) {
-      operations.add(UnlinkedConstOperation.subtract);
+      operations.add(UnlinkedExprOperation.subtract);
     } else if (operator == TokenType.STAR) {
-      operations.add(UnlinkedConstOperation.multiply);
+      operations.add(UnlinkedExprOperation.multiply);
     } else if (operator == TokenType.SLASH) {
-      operations.add(UnlinkedConstOperation.divide);
+      operations.add(UnlinkedExprOperation.divide);
     } else if (operator == TokenType.TILDE_SLASH) {
-      operations.add(UnlinkedConstOperation.floorDivide);
+      operations.add(UnlinkedExprOperation.floorDivide);
     } else if (operator == TokenType.GT) {
-      operations.add(UnlinkedConstOperation.greater);
+      operations.add(UnlinkedExprOperation.greater);
     } else if (operator == TokenType.LT) {
-      operations.add(UnlinkedConstOperation.less);
+      operations.add(UnlinkedExprOperation.less);
     } else if (operator == TokenType.GT_EQ) {
-      operations.add(UnlinkedConstOperation.greaterEqual);
+      operations.add(UnlinkedExprOperation.greaterEqual);
     } else if (operator == TokenType.LT_EQ) {
-      operations.add(UnlinkedConstOperation.lessEqual);
+      operations.add(UnlinkedExprOperation.lessEqual);
     } else if (operator == TokenType.PERCENT) {
-      operations.add(UnlinkedConstOperation.modulo);
+      operations.add(UnlinkedExprOperation.modulo);
     } else {
       throw new StateError('Unknown operator: $operator');
     }
@@ -493,9 +494,9 @@
   void _serializeCascadeExpression(CascadeExpression expr) {
     _serialize(expr.target);
     for (Expression section in expr.cascadeSections) {
-      operations.add(UnlinkedConstOperation.cascadeSectionBegin);
+      operations.add(UnlinkedExprOperation.cascadeSectionBegin);
       _serialize(section);
-      operations.add(UnlinkedConstOperation.cascadeSectionEnd);
+      operations.add(UnlinkedExprOperation.cascadeSectionEnd);
     }
   }
 
@@ -506,9 +507,9 @@
     if (expr.typeArguments != null &&
         expr.typeArguments.arguments.length == 1) {
       references.add(serializeTypeName(expr.typeArguments.arguments[0]));
-      operations.add(UnlinkedConstOperation.makeTypedList);
+      operations.add(UnlinkedExprOperation.makeTypedList);
     } else {
-      operations.add(UnlinkedConstOperation.makeUntypedList);
+      operations.add(UnlinkedExprOperation.makeUntypedList);
     }
   }
 
@@ -522,9 +523,9 @@
         expr.typeArguments.arguments.length == 2) {
       references.add(serializeTypeName(expr.typeArguments.arguments[0]));
       references.add(serializeTypeName(expr.typeArguments.arguments[1]));
-      operations.add(UnlinkedConstOperation.makeTypedMap);
+      operations.add(UnlinkedExprOperation.makeTypedMap);
     } else {
-      operations.add(UnlinkedConstOperation.makeUntypedMap);
+      operations.add(UnlinkedExprOperation.makeUntypedMap);
     }
   }
 
@@ -541,7 +542,7 @@
       _serializeArguments(argumentList);
       references.add(ref);
       _serializeTypeArguments(invocation.typeArguments);
-      operations.add(UnlinkedConstOperation.invokeMethodRef);
+      operations.add(UnlinkedExprOperation.invokeMethodRef);
     } else {
       if (!invocation.isCascaded) {
         _serialize(target);
@@ -549,7 +550,7 @@
       _serializeArguments(argumentList);
       strings.add(methodName.name);
       _serializeTypeArguments(invocation.typeArguments);
-      operations.add(UnlinkedConstOperation.invokeMethod);
+      operations.add(UnlinkedExprOperation.invokeMethod);
     }
   }
 
@@ -572,13 +573,13 @@
     Expression operand = expr.operand;
     if (operator == TokenType.BANG) {
       _serialize(operand);
-      operations.add(UnlinkedConstOperation.not);
+      operations.add(UnlinkedExprOperation.not);
     } else if (operator == TokenType.MINUS) {
       _serialize(operand);
-      operations.add(UnlinkedConstOperation.negate);
+      operations.add(UnlinkedExprOperation.negate);
     } else if (operator == TokenType.TILDE) {
       _serialize(operand);
-      operations.add(UnlinkedConstOperation.complement);
+      operations.add(UnlinkedExprOperation.complement);
     } else if (operator == TokenType.PLUS_PLUS) {
       _serializePrefixPostfixIncDec(
           operand, UnlinkedExprAssignOperator.prefixIncrement);
@@ -601,38 +602,38 @@
     if (_isIdentifierSequence(expr)) {
       EntityRefBuilder ref = serializeIdentifierSequence(expr);
       references.add(ref);
-      operations.add(UnlinkedConstOperation.pushReference);
+      operations.add(UnlinkedExprOperation.pushReference);
     } else {
       _serialize(expr.target);
       strings.add(expr.propertyName.name);
-      operations.add(UnlinkedConstOperation.extractProperty);
+      operations.add(UnlinkedExprOperation.extractProperty);
     }
   }
 
   void _serializeString(StringLiteral expr) {
     if (expr is AdjacentStrings) {
       if (expr.strings.every((string) => string is SimpleStringLiteral)) {
-        operations.add(UnlinkedConstOperation.pushString);
+        operations.add(UnlinkedExprOperation.pushString);
         strings.add(expr.stringValue);
       } else {
         expr.strings.forEach(_serializeString);
-        operations.add(UnlinkedConstOperation.concatenate);
+        operations.add(UnlinkedExprOperation.concatenate);
         ints.add(expr.strings.length);
       }
     } else if (expr is SimpleStringLiteral) {
-      operations.add(UnlinkedConstOperation.pushString);
+      operations.add(UnlinkedExprOperation.pushString);
       strings.add(expr.value);
     } else {
       StringInterpolation interpolation = expr as StringInterpolation;
       for (InterpolationElement element in interpolation.elements) {
         if (element is InterpolationString) {
-          operations.add(UnlinkedConstOperation.pushString);
+          operations.add(UnlinkedExprOperation.pushString);
           strings.add(element.value);
         } else {
           _serialize((element as InterpolationExpression).expression);
         }
       }
-      operations.add(UnlinkedConstOperation.concatenate);
+      operations.add(UnlinkedExprOperation.concatenate);
       ints.add(interpolation.elements.length);
     }
   }
diff --git a/pkg/analyzer/lib/src/task/options.dart b/pkg/analyzer/lib/src/task/options.dart
index 60a6dbc..eb7455d 100644
--- a/pkg/analyzer/lib/src/task/options.dart
+++ b/pkg/analyzer/lib/src/task/options.dart
@@ -63,6 +63,7 @@
 
   static const String errors = 'errors';
   static const String exclude = 'exclude';
+  static const String include = 'include';
   static const String language = 'language';
   static const String plugins = 'plugins';
   static const String strong_mode = 'strong-mode';
@@ -228,10 +229,12 @@
       <ResultDescriptor>[ANALYSIS_OPTIONS_ERRORS, LINE_INFO],
       suitabilityFor: suitabilityFor);
 
-  final AnalysisOptionsProvider optionsProvider = new AnalysisOptionsProvider();
+  AnalysisOptionsProvider optionsProvider;
 
   GenerateOptionsErrorsTask(AnalysisContext context, AnalysisTarget target)
-      : super(context, target);
+      : super(context, target) {
+    optionsProvider = new AnalysisOptionsProvider(context?.sourceFactory);
+  }
 
   @override
   TaskDescriptor get descriptor => DESCRIPTOR;
@@ -243,16 +246,80 @@
     String content = getRequiredInput(CONTENT_INPUT_NAME);
 
     List<AnalysisError> errors = <AnalysisError>[];
+    Source initialSource = source;
+    SourceSpan initialIncludeSpan;
+
+    // Validate the specified options and any included option files
+    void validate(Source source, Map<String, YamlNode> options) {
+      List<AnalysisError> validationErrors =
+          new OptionsFileValidator(source).validate(options);
+      if (initialIncludeSpan != null && validationErrors.isNotEmpty) {
+        for (AnalysisError error in validationErrors) {
+          var args = [
+            source.fullName,
+            error.offset.toString(),
+            (error.offset + error.length - 1).toString(),
+            error.message,
+          ];
+          errors.add(new AnalysisError(
+              initialSource,
+              initialIncludeSpan.start.column + 1,
+              initialIncludeSpan.length,
+              AnalysisOptionsWarningCode.INCLUDED_FILE_WARNING,
+              args));
+        }
+      } else {
+        errors.addAll(validationErrors);
+      }
+
+      YamlNode node = options[AnalyzerOptions.include];
+      if (node == null) {
+        return;
+      }
+      SourceSpan span = node.span;
+      initialIncludeSpan ??= span;
+      String includeUri = span.text;
+      Source includedSource =
+          context.sourceFactory.resolveUri(source, includeUri);
+      if (!includedSource.exists()) {
+        errors.add(new AnalysisError(
+            initialSource,
+            initialIncludeSpan.start.column + 1,
+            initialIncludeSpan.length,
+            AnalysisOptionsWarningCode.INCLUDE_FILE_NOT_FOUND,
+            [includeUri, source.fullName]));
+        return;
+      }
+      try {
+        Map<String, YamlNode> options =
+            optionsProvider.getOptionsFromString(includedSource.contents.data);
+        validate(includedSource, options);
+      } on OptionsFormatException catch (e) {
+        var args = [
+          includedSource.fullName,
+          e.span.start.offset.toString(),
+          e.span.end.offset.toString(),
+          e.message,
+        ];
+        // Report errors for included option files
+        // on the include directive located in the initial options file.
+        errors.add(new AnalysisError(
+            initialSource,
+            initialIncludeSpan.start.column + 1,
+            initialIncludeSpan.length,
+            AnalysisOptionsErrorCode.INCLUDED_FILE_PARSE_ERROR,
+            args));
+      }
+    }
 
     try {
       Map<String, YamlNode> options =
           optionsProvider.getOptionsFromString(content);
-      errors.addAll(_validate(options));
+      validate(source, options);
     } on OptionsFormatException catch (e) {
       SourceSpan span = e.span;
-      var error = new AnalysisError(source, span.start.column + 1, span.length,
-          AnalysisOptionsErrorCode.PARSE_ERROR, [e.message]);
-      errors.add(error);
+      errors.add(new AnalysisError(source, span.start.column + 1, span.length,
+          AnalysisOptionsErrorCode.PARSE_ERROR, [e.message]));
     }
 
     //
@@ -262,9 +329,6 @@
     outputs[LINE_INFO] = computeLineInfo(content);
   }
 
-  List<AnalysisError> _validate(Map<String, YamlNode> options) =>
-      new OptionsFileValidator(source).validate(options);
-
   /// 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].
diff --git a/pkg/analyzer/test/generated/declaration_resolver_test.dart b/pkg/analyzer/test/generated/declaration_resolver_test.dart
index 869d7e0..eeaf82d 100644
--- a/pkg/analyzer/test/generated/declaration_resolver_test.dart
+++ b/pkg/analyzer/test/generated/declaration_resolver_test.dart
@@ -101,6 +101,33 @@
     checkMetadata('export');
   }
 
+  void test_metadata_exportDirective_resynthesized() {
+    CompilationUnit unit = resolveSource(r'''
+@a
+export "dart:async";
+
+@b
+export "dart:math";
+
+const a = null;
+const b = null;
+''');
+    expect(unit.directives[0].metadata.single.name.name, 'a');
+    expect(unit.directives[1].metadata.single.name.name, 'b');
+    var unitElement = unit.element as CompilationUnitElementImpl;
+    // Damage the unit element - as if "setAnnotations" were not called.
+    // The ExportElement(s) still have the metadata, we should use it.
+    unitElement.setAnnotations(unit.directives[0].offset, []);
+    unitElement.setAnnotations(unit.directives[1].offset, []);
+    expect(unitElement.library.exports[0].metadata, hasLength(1));
+    expect(unitElement.library.exports[1].metadata, hasLength(1));
+    // DeclarationResolver on the clone should succeed.
+    CompilationUnit clonedUnit = AstCloner.clone(unit);
+    new DeclarationResolver().resolve(clonedUnit, unit.element);
+    expect(unit.directives[0].metadata.single.name.name, 'a');
+    expect(unit.directives[1].metadata.single.name.name, 'b');
+  }
+
   void test_metadata_fieldDeclaration() {
     setupCode('class C { @a int x; }');
     checkMetadata('x');
@@ -163,6 +190,33 @@
     checkMetadata('import');
   }
 
+  void test_metadata_importDirective_resynthesized() {
+    CompilationUnit unit = resolveSource(r'''
+@a
+import "dart:async";
+
+@b
+import "dart:math";
+
+const a = null;
+const b = null;
+''');
+    expect(unit.directives[0].metadata.single.name.name, 'a');
+    expect(unit.directives[1].metadata.single.name.name, 'b');
+    var unitElement = unit.element as CompilationUnitElementImpl;
+    // Damage the unit element - as if "setAnnotations" were not called.
+    // The ImportElement(s) still have the metadata, we should use it.
+    unitElement.setAnnotations(unit.directives[0].offset, []);
+    unitElement.setAnnotations(unit.directives[1].offset, []);
+    expect(unitElement.library.imports[0].metadata, hasLength(1));
+    expect(unitElement.library.imports[1].metadata, hasLength(1));
+    // DeclarationResolver on the clone should succeed.
+    CompilationUnit clonedUnit = AstCloner.clone(unit);
+    new DeclarationResolver().resolve(clonedUnit, unit.element);
+    expect(unit.directives[0].metadata.single.name.name, 'a');
+    expect(unit.directives[1].metadata.single.name.name, 'b');
+  }
+
   void test_metadata_libraryDirective() {
     setupCode('@a library L;');
     checkMetadata('L');
diff --git a/pkg/analyzer/test/source/config_test.dart b/pkg/analyzer/test/source/config_test.dart
deleted file mode 100644
index 6ce08cd..0000000
--- a/pkg/analyzer/test/source/config_test.dart
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analyzer/source/config.dart';
-import 'package:test/test.dart';
-import 'package:yaml/yaml.dart';
-
-main() {
-  group('Analysis Config', () {
-    test('parseConfigSource', () {
-      String source = r'''
-analyzer:
-  configuration: google/strict
-''';
-      YamlMap options = loadYamlNode(source);
-      AnalysisConfigurationDescriptor descriptor =
-          new AnalysisConfigurationDescriptor.fromAnalyzerOptions(
-              options['analyzer']);
-      expect(descriptor.package, 'google');
-      expect(descriptor.pragma, 'strict');
-    });
-  });
-}
diff --git a/pkg/analyzer/test/source/test_all.dart b/pkg/analyzer/test/source/test_all.dart
index 98f3cde..a995c9b 100644
--- a/pkg/analyzer/test/source/test_all.dart
+++ b/pkg/analyzer/test/source/test_all.dart
@@ -7,7 +7,6 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'analysis_options_provider_test.dart' as analysis_options_provider_test;
-import 'config_test.dart' as config_test;
 import 'embedder_test.dart' as embedder_test;
 import 'error_processor_test.dart' as error_processor_test;
 import 'package_map_provider_test.dart' as package_map_provider_test;
@@ -19,7 +18,6 @@
 main() {
   defineReflectiveSuite(() {
     analysis_options_provider_test.main();
-    config_test.main();
     embedder_test.main();
     error_processor_test.main();
     package_map_provider_test.main();
diff --git a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
new file mode 100644
index 0000000..2ef6802
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
@@ -0,0 +1,360 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:typed_data';
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/source/package_map_resolver.dart';
+import 'package:analyzer/src/dart/analysis/byte_store.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart' show PerformanceLog;
+import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/generated/engine.dart'
+    show AnalysisOptions, AnalysisOptionsImpl;
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/util/fast_uri.dart';
+import 'package:convert/convert.dart';
+import 'package:crypto/crypto.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../context/mock_sdk.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(FileSystemStateTest);
+  });
+}
+
+@reflectiveTest
+class FileSystemStateTest {
+  static final MockSdk sdk = new MockSdk();
+
+  final MemoryResourceProvider provider = new MemoryResourceProvider();
+  final ByteStore byteStore = new MemoryByteStore();
+  final FileContentOverlay contentOverlay = new FileContentOverlay();
+
+  final StringBuffer logBuffer = new StringBuffer();
+  PerformanceLog logger;
+
+  FileSystemState fileSystemState;
+
+  void setUp() {
+    logger = new PerformanceLog(logBuffer);
+    SourceFactory sourceFactory = new SourceFactory([
+      new DartUriResolver(sdk),
+      new PackageMapUriResolver(provider, <String, List<Folder>>{
+        'aaa': [provider.getFolder(_p('/aaa/lib'))],
+        'bbb': [provider.getFolder(_p('/bbb/lib'))],
+      }),
+      new ResourceUriResolver(provider)
+    ], null, provider);
+    AnalysisOptions analysisOptions = new AnalysisOptionsImpl()
+      ..strongMode = true;
+    fileSystemState = new FileSystemState(logger, byteStore, contentOverlay,
+        provider, sourceFactory, analysisOptions, new Uint32List(0));
+  }
+
+  test_getFileForPath_doesNotExist() {
+    String path = _p('/aaa/lib/a.dart');
+    FileState file = fileSystemState.getFileForPath(path);
+    expect(file.path, path);
+    expect(file.uri, FastUri.parse('package:aaa/a.dart'));
+    expect(file.content, '');
+    expect(file.contentHash, _md5(''));
+    expect(file.importedFiles, isEmpty);
+    expect(file.exportedFiles, isEmpty);
+    expect(file.partedFiles, isEmpty);
+    expect(file.directReferencedFiles, isEmpty);
+    expect(file.isPart, isFalse);
+    expect(file.library, isNull);
+    expect(file.unlinked, isNotNull);
+    expect(file.unlinked.classes, isEmpty);
+  }
+
+  test_getFileForPath_library() {
+    String a1 = _p('/aaa/lib/a1.dart');
+    String a2 = _p('/aaa/lib/a2.dart');
+    String a3 = _p('/aaa/lib/a3.dart');
+    String a4 = _p('/aaa/lib/a4.dart');
+    String b1 = _p('/bbb/lib/b1.dart');
+    String b2 = _p('/bbb/lib/b2.dart');
+    String content_a1 = r'''
+import 'package:aaa/a2.dart';
+import 'package:bbb/b1.dart';
+export 'package:bbb/b2.dart';
+export 'package:aaa/a3.dart';
+part 'a4.dart';
+
+class A1 {}
+''';
+    provider.newFile(a1, content_a1);
+
+    FileState file = fileSystemState.getFileForPath(a1);
+    expect(file.path, a1);
+    expect(file.content, content_a1);
+    expect(file.contentHash, _md5(content_a1));
+
+    expect(file.isPart, isFalse);
+    expect(file.library, isNull);
+    expect(file.unlinked, isNotNull);
+    expect(file.unlinked.classes, hasLength(1));
+    expect(file.unlinked.classes[0].name, 'A1');
+
+    expect(file.importedFiles, hasLength(2));
+    expect(file.importedFiles[0].path, a2);
+    expect(file.importedFiles[0].uri, FastUri.parse('package:aaa/a2.dart'));
+    expect(file.importedFiles[0].source, isNotNull);
+    expect(file.importedFiles[1].path, b1);
+    expect(file.importedFiles[1].uri, FastUri.parse('package:bbb/b1.dart'));
+    expect(file.importedFiles[1].source, isNotNull);
+
+    expect(file.exportedFiles, hasLength(2));
+    expect(file.exportedFiles[0].path, b2);
+    expect(file.exportedFiles[0].uri, FastUri.parse('package:bbb/b2.dart'));
+    expect(file.exportedFiles[0].source, isNotNull);
+    expect(file.exportedFiles[1].path, a3);
+    expect(file.exportedFiles[1].uri, FastUri.parse('package:aaa/a3.dart'));
+    expect(file.exportedFiles[1].source, isNotNull);
+
+    expect(file.partedFiles, hasLength(1));
+    expect(file.partedFiles[0].path, a4);
+    expect(file.partedFiles[0].uri, FastUri.parse('package:aaa/a4.dart'));
+
+    expect(file.directReferencedFiles, hasLength(5));
+
+    expect(fileSystemState.getFilesForPath(a1), [file]);
+  }
+
+  test_getFileForPath_part() {
+    String a1 = _p('/aaa/lib/a1.dart');
+    String a2 = _p('/aaa/lib/a2.dart');
+    provider.newFile(
+        a1,
+        r'''
+library a1;
+part 'a2.dart';
+''');
+    provider.newFile(
+        a2,
+        r'''
+part of a1;
+class A2 {}
+''');
+
+    FileState file_a2 = fileSystemState.getFileForPath(a2);
+    expect(file_a2.path, a2);
+    expect(file_a2.uri, FastUri.parse('package:aaa/a2.dart'));
+
+    expect(file_a2.unlinked, isNotNull);
+    expect(file_a2.unlinked.classes, hasLength(1));
+    expect(file_a2.unlinked.classes[0].name, 'A2');
+
+    expect(file_a2.importedFiles, isEmpty);
+    expect(file_a2.exportedFiles, isEmpty);
+    expect(file_a2.partedFiles, isEmpty);
+    expect(file_a2.directReferencedFiles, isEmpty);
+
+    // The library is not known yet.
+    expect(file_a2.isPart, isTrue);
+    expect(file_a2.library, isNull);
+
+    // Ask for the library.
+    FileState file_a1 = fileSystemState.getFileForPath(a1);
+    expect(file_a1.partedFiles, hasLength(1));
+    expect(file_a1.partedFiles[0], same(file_a2));
+    expect(file_a1.directReferencedFiles, unorderedEquals([file_a2]));
+
+    // Now the part knows its library.
+    expect(file_a2.library, same(file_a1));
+
+    // Now update the library, and refresh its file.
+    // The 'a2.dart' is not referenced anymore.
+    // So the part file does not have the library anymore.
+    provider.newFile(
+        a1,
+        r'''
+library a1;
+part 'not-a2.dart';
+''');
+    file_a1.refresh();
+    expect(file_a2.library, isNull);
+  }
+
+  test_getFileForPath_samePath() {
+    String path = _p('/aaa/lib/a.dart');
+    FileState file1 = fileSystemState.getFileForPath(path);
+    FileState file2 = fileSystemState.getFileForPath(path);
+    expect(file2, same(file1));
+  }
+
+  test_getFileForUri_packageVsFileUri() {
+    String path = _p('/aaa/lib/a.dart');
+    var packageUri = FastUri.parse('package:aaa/a.dart');
+    var fileUri = provider.pathContext.toUri(path);
+
+    // The files with `package:` and `file:` URIs are different.
+    FileState filePackageUri = fileSystemState.getFileForUri(packageUri);
+    FileState fileFileUri = fileSystemState.getFileForUri(fileUri);
+    expect(filePackageUri, isNot(same(fileFileUri)));
+
+    expect(filePackageUri.path, path);
+    expect(filePackageUri.uri, packageUri);
+
+    expect(fileFileUri.path, path);
+    expect(fileFileUri.uri, fileUri);
+
+    // The file with the `package:` style URI is canonical, and is the first.
+    var files = fileSystemState.getFilesForPath(path);
+    expect(files, [filePackageUri, fileFileUri]);
+  }
+
+  test_refresh_differentApiSignature() {
+    String path = _p('/aaa/lib/a.dart');
+    provider.newFile(
+        path,
+        r'''
+class A {}
+''');
+    FileState file = fileSystemState.getFileForPath(path);
+    expect(file.unlinked.classes[0].name, 'A');
+    List<int> signature = file.apiSignature;
+
+    // Update the resource and refresh the file state.
+    provider.newFile(
+        path,
+        r'''
+class B {}
+''');
+    bool apiSignatureChanged = file.refresh();
+    expect(apiSignatureChanged, isTrue);
+
+    expect(file.unlinked.classes[0].name, 'B');
+    expect(file.apiSignature, isNot(signature));
+  }
+
+  test_refresh_sameApiSignature() {
+    String path = _p('/aaa/lib/a.dart');
+    provider.newFile(
+        path,
+        r'''
+class C {
+  foo() {
+    print(111);
+  }
+}
+''');
+    FileState file = fileSystemState.getFileForPath(path);
+    List<int> signature = file.apiSignature;
+
+    // Update the resource and refresh the file state.
+    provider.newFile(
+        path,
+        r'''
+class C {
+  foo() {
+    print(222);
+  }
+}
+''');
+    bool apiSignatureChanged = file.refresh();
+    expect(apiSignatureChanged, isFalse);
+
+    expect(file.apiSignature, signature);
+  }
+
+  test_transitiveFiles() {
+    String pa = _p('/aaa/lib/a.dart');
+    String pb = _p('/aaa/lib/b.dart');
+    String pc = _p('/aaa/lib/c.dart');
+    String pd = _p('/aaa/lib/d.dart');
+
+    FileState fa = fileSystemState.getFileForPath(pa);
+    FileState fb = fileSystemState.getFileForPath(pb);
+    FileState fc = fileSystemState.getFileForPath(pc);
+    FileState fd = fileSystemState.getFileForPath(pd);
+
+    // Compute transitive closures for all files.
+    fa.transitiveFiles;
+    fb.transitiveFiles;
+    fc.transitiveFiles;
+    fd.transitiveFiles;
+    expect(fileSystemState.test.filesWithoutTransitive, isEmpty);
+
+    // No imports, so just a single file.
+    provider.newFile(pa, "");
+    _assertTransitiveFiles(fa, [fa]);
+
+    // Import b.dart into a.dart, two files now.
+    provider.newFile(pa, "import 'b.dart';");
+    fa.refresh();
+    _assertFilesWithoutTransitive([fa]);
+    _assertTransitiveFiles(fa, [fa, fb]);
+
+    // Update b.dart so that it imports c.dart now.
+    provider.newFile(pb, "import 'c.dart';");
+    fb.refresh();
+    _assertFilesWithoutTransitive([fa, fb]);
+    _assertTransitiveFiles(fa, [fa, fb, fc]);
+    _assertTransitiveFiles(fb, [fb, fc]);
+    _assertFilesWithoutTransitive([]);
+
+    // Update b.dart so that it exports d.dart instead.
+    provider.newFile(pb, "export 'd.dart';");
+    fb.refresh();
+    _assertFilesWithoutTransitive([fa, fb]);
+    _assertTransitiveFiles(fa, [fa, fb, fd]);
+    _assertTransitiveFiles(fb, [fb, fd]);
+    _assertFilesWithoutTransitive([]);
+
+    // Update a.dart so that it does not import b.dart anymore.
+    provider.newFile(pa, "");
+    fa.refresh();
+    _assertFilesWithoutTransitive([fa]);
+    _assertTransitiveFiles(fa, [fa]);
+  }
+
+  test_transitiveFiles_cycle() {
+    String pa = _p('/aaa/lib/a.dart');
+    String pb = _p('/aaa/lib/b.dart');
+
+    provider.newFile(pa, "import 'b.dart';");
+    provider.newFile(pb, "import 'a.dart';");
+
+    FileState fa = fileSystemState.getFileForPath(pa);
+    FileState fb = fileSystemState.getFileForPath(pb);
+
+    // Compute transitive closures for all files.
+    fa.transitiveFiles;
+    fb.transitiveFiles;
+    _assertFilesWithoutTransitive([]);
+
+    // It's a cycle.
+    _assertTransitiveFiles(fa, [fa, fb]);
+    _assertTransitiveFiles(fb, [fa, fb]);
+
+    // Update a.dart so that it does not import b.dart anymore.
+    provider.newFile(pa, "");
+    fa.refresh();
+    _assertFilesWithoutTransitive([fa, fb]);
+    _assertTransitiveFiles(fa, [fa]);
+    _assertTransitiveFiles(fb, [fa, fb]);
+  }
+
+  void _assertFilesWithoutTransitive(List<FileState> expected) {
+    var actual = fileSystemState.test.filesWithoutTransitive;
+    expect(actual, unorderedEquals(expected));
+  }
+
+  void _assertTransitiveFiles(FileState file, List<FileState> expected) {
+    expect(file.transitiveFiles, unorderedEquals(expected));
+  }
+
+  String _p(String path) => provider.convertPath(path);
+
+  static String _md5(String content) {
+    return hex.encode(md5.convert(UTF8.encode(content)).bytes);
+  }
+}
diff --git a/pkg/analyzer/test/src/dart/analysis/referenced_names_test.dart b/pkg/analyzer/test/src/dart/analysis/referenced_names_test.dart
new file mode 100644
index 0000000..ee43d8d
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/analysis/referenced_names_test.dart
@@ -0,0 +1,390 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/analysis/referenced_names.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../../generated/parser_test.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ReferencedNamesBuilderTest);
+  });
+}
+
+@reflectiveTest
+class ReferencedNamesBuilderTest {
+  test_class_constructor() {
+    Set<String> names = _computeReferencedNames('''
+class U {
+  U.named(A a, B b) {
+    C c = null;
+  }
+}
+''');
+    expect(names, unorderedEquals(['A', 'B', 'C']));
+  }
+
+  test_class_field() {
+    Set<String> names = _computeReferencedNames('''
+class U {
+  A f = new B();
+}
+''');
+    expect(names, unorderedEquals(['A', 'B']));
+  }
+
+  test_class_getter() {
+    Set<String> names = _computeReferencedNames('''
+class U {
+  A get a => new B();
+}
+''');
+    expect(names, unorderedEquals(['A', 'B']));
+  }
+
+  test_class_members() {
+    Set<String> names = _computeReferencedNames('''
+class U {
+  int a;
+  int get b;
+  set c(_) {}
+  m(D d) {
+    a;
+    b;
+    c = 1;
+    m();
+  }
+}
+''');
+    expect(names, unorderedEquals(['int', 'D']));
+  }
+
+  test_class_members_dontHideQualified() {
+    Set<String> names = _computeReferencedNames('''
+class U {
+  int a;
+  int get b;
+  set c(_) {}
+  m(D d) {
+    d.a;
+    d.b;
+    d.c;
+  }
+}
+''');
+    expect(names, unorderedEquals(['int', 'D', 'a', 'b', 'c']));
+  }
+
+  test_class_method() {
+    Set<String> names = _computeReferencedNames('''
+class U {
+  A m(B p) {
+    C v = 0;
+  }
+}
+''');
+    expect(names, unorderedEquals(['A', 'B', 'C']));
+  }
+
+  test_class_method_localVariables() {
+    Set<String> names = _computeReferencedNames('''
+class U {
+  A m() {
+    B b = null;
+    b;
+    {
+      C c = null;
+      b;
+      c;
+    }
+    d;
+  }
+}
+''');
+    expect(names, unorderedEquals(['A', 'B', 'C', 'd']));
+  }
+
+  test_class_method_parameters() {
+    Set<String> names = _computeReferencedNames('''
+class U {
+  m(A a) {
+    a;
+    b;
+  }
+}
+''');
+    expect(names, unorderedEquals(['A', 'b']));
+  }
+
+  test_class_method_typeParameters() {
+    Set<String> names = _computeReferencedNames('''
+class U {
+  A m<T>(B b, T t) {
+    C c = 0;
+  }
+}
+''');
+    expect(names, unorderedEquals(['A', 'B', 'C']));
+  }
+
+  test_class_setter() {
+    Set<String> names = _computeReferencedNames('''
+class U {
+  set a(A a) {
+    B b = null;
+  }
+}
+''');
+    expect(names, unorderedEquals(['A', 'B']));
+  }
+
+  test_class_typeParameters() {
+    Set<String> names = _computeReferencedNames('''
+class U<T> {
+  T f = new A<T>();
+}
+''');
+    expect(names, unorderedEquals(['A']));
+  }
+
+  test_instantiatedNames_importPrefix() {
+    Set<String> names = _computeReferencedNames('''
+import 'a.dart' as p1;
+import 'b.dart' as p2;
+main() {
+  new p1.A();
+  new p1.A.c1();
+  new p1.B();
+  new p2.C();
+  new D();
+  new D.c2();
+}
+''');
+    expect(names, unorderedEquals(['A', 'B', 'C', 'D', 'c1', 'c2']));
+  }
+
+  test_localFunction() {
+    Set<String> names = _computeReferencedNames('''
+f(A a) {
+  g(B b) {}
+}
+''');
+    expect(names, unorderedEquals(['A', 'B']));
+  }
+
+  test_superToSubs_importPrefix() {
+    Set<String> names = _computeReferencedNames('''
+import 'a.dart' as p1;
+import 'b.dart' as p2;
+class U extends p1.A with p2.B implements p2.C {}
+''');
+    expect(names, unorderedEquals(['A', 'B', 'C']));
+  }
+
+  test_topLevelVariable() {
+    Set<String> names = _computeReferencedNames('''
+A v = new B(c);
+''');
+    expect(names, unorderedEquals(['A', 'B', 'c']));
+  }
+
+  test_topLevelVariable_multiple() {
+    Set<String> names = _computeReferencedNames('''
+A v1 = new B(c), v2 = new D<E>(f);
+''');
+    expect(names, unorderedEquals(['A', 'B', 'c', 'D', 'E', 'f']));
+  }
+
+  test_unit_classTypeAlias() {
+    Set<String> names = _computeReferencedNames('''
+class U = A with B implements C;
+''');
+    expect(names, unorderedEquals(['A', 'B', 'C']));
+  }
+
+  test_unit_classTypeAlias_typeParameters() {
+    Set<String> names = _computeReferencedNames('''
+class U<T1, T2 extends D> = A<T1> with B<T2> implements C<T1, T2>;
+''');
+    expect(names, unorderedEquals(['A', 'B', 'C', 'D']));
+  }
+
+  test_unit_function() {
+    Set<String> names = _computeReferencedNames('''
+A f(B b) {
+  C c = 0;
+}
+''');
+    expect(names, unorderedEquals(['A', 'B', 'C']));
+  }
+
+  test_unit_function_doc() {
+    Set<String> names = _computeReferencedNames('''
+/**
+ * Documentation [C.d] reference.
+ */
+A f(B b) {}
+''');
+    expect(names, unorderedEquals(['A', 'B', 'C', 'd']));
+  }
+
+  test_unit_function_dontHideQualified() {
+    Set<String> names = _computeReferencedNames('''
+class U {
+  int a;
+  int get b;
+  set c(_) {}
+  m(D d) {
+    d.a;
+    d.b;
+    d.c;
+  }
+}
+''');
+    expect(names, unorderedEquals(['int', 'D', 'a', 'b', 'c']));
+  }
+
+  test_unit_function_localFunction_parameter() {
+    Set<String> names = _computeReferencedNames('''
+A f() {
+  B g(x) {
+    x;
+    return null;
+  }
+  return null;
+}
+''');
+    expect(names, unorderedEquals(['A', 'B']));
+  }
+
+  test_unit_function_localFunctions() {
+    Set<String> names = _computeReferencedNames('''
+A f() {
+  B b = null;
+  C g() {}
+  g();
+}
+''');
+    expect(names, unorderedEquals(['A', 'B', 'C']));
+  }
+
+  test_unit_function_localsDontHideQualified() {
+    Set<String> names = _computeReferencedNames('''
+f(A a, B b) {
+  var v = 0;
+  a.v;
+  a.b;
+}
+''');
+    expect(names, unorderedEquals(['A', 'B', 'v', 'b']));
+  }
+
+  test_unit_function_localVariables() {
+    Set<String> names = _computeReferencedNames('''
+A f() {
+  B b = null;
+  b;
+  {
+    C c = null;
+    b;
+    c;
+  }
+  d;
+}
+''');
+    expect(names, unorderedEquals(['A', 'B', 'C', 'd']));
+  }
+
+  test_unit_function_parameters() {
+    Set<String> names = _computeReferencedNames('''
+A f(B b) {
+  C c = 0;
+  b;
+}
+''');
+    expect(names, unorderedEquals(['A', 'B', 'C']));
+  }
+
+  test_unit_function_parameters_dontHideQualified() {
+    Set<String> names = _computeReferencedNames('''
+f(x, C g()) {
+  g().x;
+}
+''');
+    expect(names, unorderedEquals(['C', 'x']));
+  }
+
+  test_unit_function_typeParameters() {
+    Set<String> names = _computeReferencedNames('''
+A f<T>(B b, T t) {
+  C c = 0;
+}
+''');
+    expect(names, unorderedEquals(['A', 'B', 'C']));
+  }
+
+  test_unit_functionTypeAlias() {
+    Set<String> names = _computeReferencedNames('''
+typedef A F(B B, C c(D d));
+''');
+    expect(names, unorderedEquals(['A', 'B', 'C', 'D']));
+  }
+
+  test_unit_functionTypeAlias_typeParameters() {
+    Set<String> names = _computeReferencedNames('''
+typedef A F<T>(B b, T t);
+''');
+    expect(names, unorderedEquals(['A', 'B']));
+  }
+
+  test_unit_getter() {
+    Set<String> names = _computeReferencedNames('''
+A get aaa {
+  return new B();
+}
+''');
+    expect(names, unorderedEquals(['A', 'B']));
+  }
+
+  test_unit_setter() {
+    Set<String> names = _computeReferencedNames('''
+set aaa(A a) {
+  B b = null;
+}
+''');
+    expect(names, unorderedEquals(['A', 'B']));
+  }
+
+  test_unit_topLevelDeclarations() {
+    Set<String> names = _computeReferencedNames('''
+class L1 {}
+class L2 = A with B implements C;
+A L3() => null;
+typedef A L4(B b);
+A get L5 => null;
+set L6(_) {}
+A L7, L8;
+main() {
+  L1;
+  L2;
+  L3;
+  L4;
+  L5;
+  L6;
+  L7;
+  L8;
+}
+''');
+    expect(names, unorderedEquals(['A', 'B', 'C']));
+  }
+
+  Set<String> _computeReferencedNames(String code) {
+    CompilationUnit unit =
+        ParserTestCase.parseCompilationUnit2(code, parseGenericMethods: true);
+    return computeReferencedNames(unit);
+  }
+}
diff --git a/pkg/analyzer/test/src/dart/analysis/test_all.dart b/pkg/analyzer/test/src/dart/analysis/test_all.dart
index 346ac5a..0ba933e 100644
--- a/pkg/analyzer/test/src/dart/analysis/test_all.dart
+++ b/pkg/analyzer/test/src/dart/analysis/test_all.dart
@@ -8,11 +8,15 @@
 
 import 'byte_store_test.dart' as byte_store;
 import 'driver_test.dart' as driver;
+import 'file_state_test.dart' as file_state;
+import 'referenced_names_test.dart' as referenced_names;
 
 /// Utility for manually running all tests.
 main() {
   defineReflectiveSuite(() {
     byte_store.main();
     driver.main();
+    file_state.main();
+    referenced_names.main();
   }, name: 'analysis');
 }
diff --git a/pkg/analyzer/test/src/summary/linker_test.dart b/pkg/analyzer/test/src/summary/linker_test.dart
index 2a0706c..cd70c5d 100644
--- a/pkg/analyzer/test/src/summary/linker_test.dart
+++ b/pkg/analyzer/test/src/summary/linker_test.dart
@@ -351,6 +351,20 @@
         '(D) → E');
   }
 
+  void test_inferredType_instanceField_conditional_genericFunctions() {
+    createLinker('''
+class C {
+  final f = true ? <T>(T t) => 0 : <T>(T t) => 1;
+}
+''');
+    LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+    library.libraryCycleForLink.ensureLinked();
+    ClassElementForLink_Class cls = library.getContainedName('C');
+    expect(cls.fields, hasLength(1));
+    var field = cls.fields[0];
+    expect(field.type.toString(), '(<bottom>) → dynamic');
+  }
+
   void test_inferredType_instanceField_dynamic() {
     createLinker('''
 var x;
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index bf040c6..664882b 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -2590,6 +2590,27 @@
 ''');
   }
 
+  test_constructor_redirected_factory_named_unresolved_class() {
+    checkLibrary(
+        '''
+class C<E> {
+  factory C() = D.named<E>;
+}
+''',
+        allowErrors: true);
+  }
+
+  test_constructor_redirected_factory_named_unresolved_constructor() {
+    checkLibrary(
+        '''
+class D {}
+class C<E> {
+  factory C() = D.named<E>;
+}
+''',
+        allowErrors: true);
+  }
+
   test_constructor_redirected_factory_unnamed() {
     checkLibrary('''
 class C {
@@ -2686,6 +2707,16 @@
 ''');
   }
 
+  test_constructor_redirected_factory_unnamed_unresolved() {
+    checkLibrary(
+        '''
+class C<E> {
+  factory C() = D<E>;
+}
+''',
+        allowErrors: true);
+  }
+
   test_constructor_redirected_thisInvocation_named() {
     checkLibrary('''
 class C {
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index 8b90c3c..018d86d 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -179,10 +179,10 @@
    * Check that [annotations] contains a single entry which is a reference to
    * a top level variable called `a` in the current library.
    */
-  void checkAnnotationA(List<UnlinkedConst> annotations) {
+  void checkAnnotationA(List<UnlinkedExpr> annotations) {
     expect(annotations, hasLength(1));
     _assertUnlinkedConst(annotations[0], operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'a',
           expectedKind: ReferenceKind.topLevelPropertyAccessor)
@@ -1547,9 +1547,9 @@
   test_constExpr_binary_add() {
     UnlinkedVariable variable = serializeVariableText('const v = 1 + 2;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.add
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.add
     ], ints: [
       1,
       2
@@ -1560,18 +1560,18 @@
     UnlinkedVariable variable =
         serializeVariableText('const v = true && false;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushTrue,
-      UnlinkedConstOperation.pushFalse,
-      UnlinkedConstOperation.and
+      UnlinkedExprOperation.pushTrue,
+      UnlinkedExprOperation.pushFalse,
+      UnlinkedExprOperation.and
     ]);
   }
 
   test_constExpr_binary_bitAnd() {
     UnlinkedVariable variable = serializeVariableText('const v = 1 & 2;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.bitAnd
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.bitAnd
     ], ints: [
       1,
       2
@@ -1581,9 +1581,9 @@
   test_constExpr_binary_bitOr() {
     UnlinkedVariable variable = serializeVariableText('const v = 1 | 2;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.bitOr
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.bitOr
     ], ints: [
       1,
       2
@@ -1593,9 +1593,9 @@
   test_constExpr_binary_bitShiftLeft() {
     UnlinkedVariable variable = serializeVariableText('const v = 1 << 2;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.bitShiftLeft
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.bitShiftLeft
     ], ints: [
       1,
       2
@@ -1605,9 +1605,9 @@
   test_constExpr_binary_bitShiftRight() {
     UnlinkedVariable variable = serializeVariableText('const v = 1 >> 2;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.bitShiftRight
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.bitShiftRight
     ], ints: [
       1,
       2
@@ -1617,9 +1617,9 @@
   test_constExpr_binary_bitXor() {
     UnlinkedVariable variable = serializeVariableText('const v = 1 ^ 2;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.bitXor
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.bitXor
     ], ints: [
       1,
       2
@@ -1629,9 +1629,9 @@
   test_constExpr_binary_divide() {
     UnlinkedVariable variable = serializeVariableText('const v = 1 / 2;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.divide
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.divide
     ], ints: [
       1,
       2
@@ -1641,9 +1641,9 @@
   test_constExpr_binary_equal() {
     UnlinkedVariable variable = serializeVariableText('const v = 1 == 2;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.equal
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.equal
     ], ints: [
       1,
       2
@@ -1653,9 +1653,9 @@
   test_constExpr_binary_equal_not() {
     UnlinkedVariable variable = serializeVariableText('const v = 1 != 2;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.notEqual
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.notEqual
     ], ints: [
       1,
       2
@@ -1665,9 +1665,9 @@
   test_constExpr_binary_floorDivide() {
     UnlinkedVariable variable = serializeVariableText('const v = 1 ~/ 2;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.floorDivide
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.floorDivide
     ], ints: [
       1,
       2
@@ -1677,9 +1677,9 @@
   test_constExpr_binary_greater() {
     UnlinkedVariable variable = serializeVariableText('const v = 1 > 2;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.greater
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.greater
     ], ints: [
       1,
       2
@@ -1689,9 +1689,9 @@
   test_constExpr_binary_greaterEqual() {
     UnlinkedVariable variable = serializeVariableText('const v = 1 >= 2;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.greaterEqual
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.greaterEqual
     ], ints: [
       1,
       2
@@ -1701,9 +1701,9 @@
   test_constExpr_binary_less() {
     UnlinkedVariable variable = serializeVariableText('const v = 1 < 2;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.less
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.less
     ], ints: [
       1,
       2
@@ -1713,9 +1713,9 @@
   test_constExpr_binary_lessEqual() {
     UnlinkedVariable variable = serializeVariableText('const v = 1 <= 2;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.lessEqual
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.lessEqual
     ], ints: [
       1,
       2
@@ -1725,9 +1725,9 @@
   test_constExpr_binary_modulo() {
     UnlinkedVariable variable = serializeVariableText('const v = 1 % 2;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.modulo
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.modulo
     ], ints: [
       1,
       2
@@ -1737,9 +1737,9 @@
   test_constExpr_binary_multiply() {
     UnlinkedVariable variable = serializeVariableText('const v = 1 * 2;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.multiply
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.multiply
     ], ints: [
       1,
       2
@@ -1750,18 +1750,18 @@
     UnlinkedVariable variable =
         serializeVariableText('const v = false || true;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushFalse,
-      UnlinkedConstOperation.pushTrue,
-      UnlinkedConstOperation.or
+      UnlinkedExprOperation.pushFalse,
+      UnlinkedExprOperation.pushTrue,
+      UnlinkedExprOperation.or
     ]);
   }
 
   test_constExpr_binary_subtract() {
     UnlinkedVariable variable = serializeVariableText('const v = 1 - 2;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.subtract
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.subtract
     ], ints: [
       1,
       2
@@ -1783,7 +1783,7 @@
     UnlinkedClass cls = serializeClassText(text, allowErrors: true);
     _assertUnlinkedConst(cls.executables[0].constantInitializers[0].expression,
         operators: [
-          UnlinkedConstOperation.pushReference
+          UnlinkedExprOperation.pushReference
         ],
         referenceValidators: [
           (EntityRef r) => checkTypeRef(r, null, null, 'T',
@@ -1799,10 +1799,10 @@
     UnlinkedVariable variable =
         serializeVariableText('const v = true ? 1 : 2;', allowErrors: true);
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushTrue,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.conditional
+      UnlinkedExprOperation.pushTrue,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.conditional
     ], ints: [
       1,
       2
@@ -1818,7 +1818,7 @@
 }
 ''');
     _assertUnlinkedConst(cls.executables[0].constantInitializers[0].expression,
-        operators: [UnlinkedConstOperation.pushParameter], strings: ['a']);
+        operators: [UnlinkedExprOperation.pushParameter], strings: ['a']);
   }
 
   test_constExpr_constructorParam_shadows_typeParam() {
@@ -1829,7 +1829,7 @@
 }
 ''');
     _assertUnlinkedConst(cls.executables[0].constantInitializers[0].expression,
-        operators: [UnlinkedConstOperation.pushParameter], strings: ['T']);
+        operators: [UnlinkedExprOperation.pushParameter], strings: ['T']);
   }
 
   test_constExpr_functionExpression_asArgument() {
@@ -1843,9 +1843,9 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.pushLocalFunctionReference,
-          UnlinkedConstOperation.invokeMethodRef
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.pushLocalFunctionReference,
+          UnlinkedExprOperation.invokeMethodRef
         ],
         ints: [
           5,
@@ -1872,10 +1872,10 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.pushLocalFunctionReference,
-          UnlinkedConstOperation.pushLocalFunctionReference,
-          UnlinkedConstOperation.invokeMethodRef
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.pushLocalFunctionReference,
+          UnlinkedExprOperation.pushLocalFunctionReference,
+          UnlinkedExprOperation.invokeMethodRef
         ],
         ints: [
           5,
@@ -1906,11 +1906,11 @@
     expect(executable.localFunctions, hasLength(2));
     _assertUnlinkedConst(executable.constantInitializers[0].expression,
         isValidConst: false,
-        operators: [UnlinkedConstOperation.pushLocalFunctionReference],
+        operators: [UnlinkedExprOperation.pushLocalFunctionReference],
         ints: [0, 0]);
     _assertUnlinkedConst(executable.constantInitializers[1].expression,
         isValidConst: false,
-        operators: [UnlinkedConstOperation.pushLocalFunctionReference],
+        operators: [UnlinkedExprOperation.pushLocalFunctionReference],
         ints: [0, 1]);
   }
 
@@ -1922,7 +1922,7 @@
 const v = const C<int, String>.named();
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -1954,7 +1954,7 @@
 const v = const C<int, String>.named();
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -1988,7 +1988,7 @@
 const v = const p.C<int, String>.named();
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -2018,7 +2018,7 @@
 const v = const C<int, String>();
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -2047,7 +2047,7 @@
 const v = const C<int, String>();
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -2076,7 +2076,7 @@
 const v = const p.C<int, String>();
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -2103,7 +2103,7 @@
 const v = const C.named();
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -2129,7 +2129,7 @@
 const v = const C.named();
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -2156,7 +2156,7 @@
 const v = const p.C.named();
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -2183,14 +2183,14 @@
     // Doubles: ^pointer
     // Strings: ^pointer 'e' 'g' 'f' ''
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushDouble,
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushDouble,
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       11,
       22,
@@ -2225,7 +2225,7 @@
 const v = const C();
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -2248,7 +2248,7 @@
 const v = const p.C();
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -2269,7 +2269,7 @@
 ''',
         allowErrors: true);
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -2289,7 +2289,7 @@
 ''',
         allowErrors: true);
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -2316,7 +2316,7 @@
 ''',
         allowErrors: true);
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -2340,7 +2340,7 @@
 ''',
         allowErrors: true);
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -2361,7 +2361,7 @@
 ''',
         allowErrors: true);
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -2375,9 +2375,9 @@
     UnlinkedVariable variable =
         serializeVariableText('const v = identical(42, null);');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushNull,
-      UnlinkedConstOperation.invokeMethodRef
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushNull,
+      UnlinkedExprOperation.invokeMethodRef
     ], ints: [
       42,
       0,
@@ -2399,7 +2399,7 @@
 const int v = C.length;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'length',
               expectedKind: ReferenceKind.propertyAccessor,
@@ -2422,7 +2422,7 @@
 const int v = p.C.length;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'length',
               expectedKind: ReferenceKind.propertyAccessor,
@@ -2440,7 +2440,7 @@
 const int v = a.length;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'length',
               expectedKind: ReferenceKind.unresolved,
@@ -2460,7 +2460,7 @@
 const int v = C.F.length;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'length',
               expectedKind: ReferenceKind.unresolved,
@@ -2483,7 +2483,7 @@
 const int v = a.length;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'length',
               expectedKind: ReferenceKind.unresolved,
@@ -2507,7 +2507,7 @@
 const int v = p.a.length;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'length',
               expectedKind: ReferenceKind.unresolved,
@@ -2525,10 +2525,10 @@
     UnlinkedVariable variable =
         serializeVariableText('const v = ("abc" + "edf").length;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.add,
-      UnlinkedConstOperation.extractProperty
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.add,
+      UnlinkedExprOperation.extractProperty
     ], strings: [
       'abc',
       'edf',
@@ -2540,8 +2540,8 @@
     UnlinkedVariable variable =
         serializeVariableText('const v = ("abc").length;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.extractProperty
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.extractProperty
     ], strings: [
       'abc',
       'length'
@@ -2552,8 +2552,8 @@
     UnlinkedVariable variable =
         serializeVariableText('const v = "abc".length;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.extractProperty
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.extractProperty
     ], strings: [
       'abc',
       'length'
@@ -2563,17 +2563,17 @@
   test_constExpr_makeSymbol() {
     UnlinkedVariable variable = serializeVariableText('const v = #a.bb.ccc;');
     _assertUnlinkedConst(variable.initializer.bodyExpr,
-        operators: [UnlinkedConstOperation.makeSymbol], strings: ['a.bb.ccc']);
+        operators: [UnlinkedExprOperation.makeSymbol], strings: ['a.bb.ccc']);
   }
 
   test_constExpr_makeTypedList() {
     UnlinkedVariable variable =
         serializeVariableText('const v = const <int>[11, 22, 33];');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.makeTypedList
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.makeTypedList
     ], ints: [
       11,
       22,
@@ -2589,10 +2589,10 @@
     UnlinkedVariable variable =
         serializeVariableText('const v = const <dynamic>[11, 22, 33];');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.makeTypedList
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.makeTypedList
     ], ints: [
       11,
       22,
@@ -2607,13 +2607,13 @@
     UnlinkedVariable variable = serializeVariableText(
         'const v = const <int, String>{11: "aaa", 22: "bbb", 33: "ccc"};');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.makeTypedMap
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.makeTypedMap
     ], ints: [
       11,
       22,
@@ -2635,13 +2635,13 @@
     UnlinkedVariable variable = serializeVariableText(
         'const v = const <dynamic, dynamic>{11: "aaa", 22: "bbb", 33: "ccc"};');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.makeTypedMap
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.makeTypedMap
     ], ints: [
       11,
       22,
@@ -2661,10 +2661,10 @@
     UnlinkedVariable variable =
         serializeVariableText('const v = const [11, 22, 33];');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.makeUntypedList
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.makeUntypedList
     ], ints: [
       11,
       22,
@@ -2677,13 +2677,13 @@
     UnlinkedVariable variable = serializeVariableText(
         'const v = const {11: "aaa", 22: "bbb", 33: "ccc"};');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.makeUntypedMap
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.makeUntypedMap
     ], ints: [
       11,
       22,
@@ -2699,11 +2699,11 @@
   test_constExpr_parenthesized() {
     UnlinkedVariable variable = serializeVariableText('const v = (1 + 2) * 3;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.add,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.multiply,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.add,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.multiply,
     ], ints: [
       1,
       2,
@@ -2714,8 +2714,8 @@
   test_constExpr_prefix_complement() {
     UnlinkedVariable variable = serializeVariableText('const v = ~2;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.complement
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.complement
     ], ints: [
       2
     ]);
@@ -2724,8 +2724,8 @@
   test_constExpr_prefix_negate() {
     UnlinkedVariable variable = serializeVariableText('const v = -(2);');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.negate
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.negate
     ], ints: [
       2
     ]);
@@ -2733,34 +2733,32 @@
 
   test_constExpr_prefix_not() {
     UnlinkedVariable variable = serializeVariableText('const v = !true;');
-    _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushTrue,
-      UnlinkedConstOperation.not
-    ]);
+    _assertUnlinkedConst(variable.initializer.bodyExpr,
+        operators: [UnlinkedExprOperation.pushTrue, UnlinkedExprOperation.not]);
   }
 
   test_constExpr_pushDouble() {
     UnlinkedVariable variable = serializeVariableText('const v = 123.4567;');
     _assertUnlinkedConst(variable.initializer.bodyExpr,
-        operators: [UnlinkedConstOperation.pushDouble], doubles: [123.4567]);
+        operators: [UnlinkedExprOperation.pushDouble], doubles: [123.4567]);
   }
 
   test_constExpr_pushFalse() {
     UnlinkedVariable variable = serializeVariableText('const v = false;');
     _assertUnlinkedConst(variable.initializer.bodyExpr,
-        operators: [UnlinkedConstOperation.pushFalse]);
+        operators: [UnlinkedExprOperation.pushFalse]);
   }
 
   test_constExpr_pushInt() {
     UnlinkedVariable variable = serializeVariableText('const v = 1;');
     _assertUnlinkedConst(variable.initializer.bodyExpr,
-        operators: [UnlinkedConstOperation.pushInt], ints: [1]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [1]);
   }
 
   test_constExpr_pushInt_max() {
     UnlinkedVariable variable = serializeVariableText('const v = 0xFFFFFFFF;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
+      UnlinkedExprOperation.pushInt,
     ], ints: [
       0xFFFFFFFF
     ]);
@@ -2769,8 +2767,8 @@
   test_constExpr_pushInt_negative() {
     UnlinkedVariable variable = serializeVariableText('const v = -5;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.negate
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.negate
     ], ints: [
       5
     ]);
@@ -2780,14 +2778,14 @@
     UnlinkedVariable variable =
         serializeVariableText('const v = 0xA123456789ABCDEF012345678;');
     _assertUnlinkedConst(variable.initializer.bodyExpr,
-        operators: [UnlinkedConstOperation.pushLongInt],
+        operators: [UnlinkedExprOperation.pushLongInt],
         ints: [4, 0xA, 0x12345678, 0x9ABCDEF0, 0x12345678]);
   }
 
   test_constExpr_pushLongInt_min2() {
     UnlinkedVariable variable = serializeVariableText('const v = 0x100000000;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushLongInt
+      UnlinkedExprOperation.pushLongInt
     ], ints: [
       2,
       1,
@@ -2799,7 +2797,7 @@
     UnlinkedVariable variable =
         serializeVariableText('const v = 0x10000000000000000;');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushLongInt
+      UnlinkedExprOperation.pushLongInt
     ], ints: [
       3,
       1,
@@ -2811,7 +2809,7 @@
   test_constExpr_pushNull() {
     UnlinkedVariable variable = serializeVariableText('const v = null;');
     _assertUnlinkedConst(variable.initializer.bodyExpr,
-        operators: [UnlinkedConstOperation.pushNull]);
+        operators: [UnlinkedExprOperation.pushNull]);
   }
 
   test_constExpr_pushReference_class() {
@@ -2820,7 +2818,7 @@
 const v = C;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'C',
           expectedKind: ReferenceKind.classOrEnum)
@@ -2833,7 +2831,7 @@
 const v = C;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'C',
           expectedKind: ReferenceKind.classOrEnum)
@@ -2846,7 +2844,7 @@
 const v = C.V1;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'V1',
               expectedKind: ReferenceKind.propertyAccessor,
@@ -2867,7 +2865,7 @@
 const v = C.V1;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'V1',
               expectedKind: ReferenceKind.propertyAccessor,
@@ -2884,7 +2882,7 @@
 const v = C.values;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'values',
               expectedKind: ReferenceKind.propertyAccessor,
@@ -2905,7 +2903,7 @@
 const v = C.values;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'values',
               expectedKind: ReferenceKind.propertyAccessor,
@@ -2924,7 +2922,7 @@
 const v = C.F;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'F',
               expectedKind: ReferenceKind.propertyAccessor,
@@ -2947,7 +2945,7 @@
 const v = C.F;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'F',
               expectedKind: ReferenceKind.propertyAccessor,
@@ -2971,7 +2969,7 @@
 const v = p.C.F;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'F',
               expectedKind: ReferenceKind.propertyAccessor,
@@ -2991,7 +2989,7 @@
 }
 ''').fields[0];
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'b',
               expectedKind: ReferenceKind.propertyAccessor,
@@ -3009,7 +3007,7 @@
 const v = C.x;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'x',
               expectedKind: ReferenceKind.propertyAccessor,
@@ -3032,7 +3030,7 @@
 const v = C.x;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'x',
               expectedKind: ReferenceKind.propertyAccessor,
@@ -3056,7 +3054,7 @@
 const v = p.C.x;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'x',
               expectedKind: ReferenceKind.propertyAccessor,
@@ -3076,7 +3074,7 @@
 const v = C.m;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'm',
               expectedKind: ReferenceKind.method,
@@ -3099,7 +3097,7 @@
 const v = C.m;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'm',
               expectedKind: ReferenceKind.method,
@@ -3123,7 +3121,7 @@
 const v = p.C.m;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'm',
               expectedKind: ReferenceKind.method,
@@ -3143,7 +3141,7 @@
 }
 ''').fields[0];
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'm',
               expectedKind: ReferenceKind.method,
@@ -3159,7 +3157,7 @@
 const v = f;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'f',
           expectedKind: ReferenceKind.topLevelFunction)
@@ -3177,7 +3175,7 @@
 const v = f;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'f',
           expectedKind: ReferenceKind.topLevelFunction)
@@ -3195,7 +3193,7 @@
 const v = p.f;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'f',
               expectedKind: ReferenceKind.topLevelFunction,
@@ -3211,7 +3209,7 @@
 const v = x;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'x',
           expectedKind: ReferenceKind.topLevelPropertyAccessor)
@@ -3225,7 +3223,7 @@
 const v = x;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'x',
           expectedKind: ReferenceKind.topLevelPropertyAccessor)
@@ -3239,7 +3237,7 @@
 const v = p.x;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'x',
           expectedKind: ReferenceKind.topLevelPropertyAccessor,
@@ -3253,7 +3251,7 @@
 const v = a;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'a',
           expectedKind: ReferenceKind.topLevelPropertyAccessor)
@@ -3267,7 +3265,7 @@
 const v = a;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'a',
           expectedKind: ReferenceKind.topLevelPropertyAccessor)
@@ -3281,7 +3279,7 @@
 const v = p.a;
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) {
         return checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'a',
@@ -3300,7 +3298,7 @@
     UnlinkedVariable variable =
         serializeClassText(text, allowErrors: true).fields[0];
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) {
         return checkParamTypeRef(r, 1);
@@ -3315,7 +3313,7 @@
 ''',
         allowErrors: true);
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'foo',
           expectedKind: ReferenceKind.unresolved)
@@ -3330,7 +3328,7 @@
 ''',
         allowErrors: true);
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'foo',
               expectedKind: ReferenceKind.unresolved,
@@ -3353,7 +3351,7 @@
 ''',
         allowErrors: true);
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'foo',
               expectedKind: ReferenceKind.unresolved,
@@ -3369,20 +3367,20 @@
     UnlinkedVariable variable =
         serializeVariableText('const v = "aaa" "b" "ccc";');
     _assertUnlinkedConst(variable.initializer.bodyExpr,
-        operators: [UnlinkedConstOperation.pushString], strings: ['aaabccc']);
+        operators: [UnlinkedExprOperation.pushString], strings: ['aaabccc']);
   }
 
   test_constExpr_pushString_adjacent_interpolation() {
     UnlinkedVariable variable =
         serializeVariableText(r'const v = "aaa" "bb ${42} bbb" "cccc";');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.concatenate,
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.concatenate,
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.concatenate,
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.concatenate,
     ], ints: [
       42,
       3,
@@ -3399,10 +3397,10 @@
     UnlinkedVariable variable =
         serializeVariableText(r'const v = "aaa ${42} bbb";');
     _assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.pushInt,
-      UnlinkedConstOperation.pushString,
-      UnlinkedConstOperation.concatenate
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.pushInt,
+      UnlinkedExprOperation.pushString,
+      UnlinkedExprOperation.concatenate
     ], ints: [
       42,
       3
@@ -3415,13 +3413,13 @@
   test_constExpr_pushString_simple() {
     UnlinkedVariable variable = serializeVariableText('const v = "abc";');
     _assertUnlinkedConst(variable.initializer.bodyExpr,
-        operators: [UnlinkedConstOperation.pushString], strings: ['abc']);
+        operators: [UnlinkedExprOperation.pushString], strings: ['abc']);
   }
 
   test_constExpr_pushTrue() {
     UnlinkedVariable variable = serializeVariableText('const v = true;');
     _assertUnlinkedConst(variable.initializer.bodyExpr,
-        operators: [UnlinkedConstOperation.pushTrue]);
+        operators: [UnlinkedExprOperation.pushTrue]);
   }
 
   test_constructor() {
@@ -3513,7 +3511,7 @@
     expect(initializer.kind, UnlinkedConstructorInitializerKind.field);
     expect(initializer.name, 'x');
     _assertUnlinkedConst(initializer.expression,
-        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [42]);
     expect(initializer.arguments, isEmpty);
   }
 
@@ -3531,7 +3529,7 @@
     expect(initializer.kind, UnlinkedConstructorInitializerKind.field);
     expect(initializer.name, 'x');
     _assertUnlinkedConst(initializer.expression,
-        operators: [UnlinkedConstOperation.pushParameter], strings: ['p']);
+        operators: [UnlinkedExprOperation.pushParameter], strings: ['p']);
     expect(initializer.arguments, isEmpty);
   }
 
@@ -3565,7 +3563,7 @@
     expect(initializer.expression, isNull);
     expect(initializer.arguments, hasLength(1));
     _assertUnlinkedConst(initializer.arguments[0],
-        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [42]);
   }
 
   test_constructor_initializers_superInvocation_namedExpression() {
@@ -3587,11 +3585,11 @@
     expect(initializer.expression, isNull);
     expect(initializer.arguments, hasLength(3));
     _assertUnlinkedConst(initializer.arguments[0],
-        operators: [UnlinkedConstOperation.pushInt], ints: [1]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [1]);
     _assertUnlinkedConst(initializer.arguments[1],
-        operators: [UnlinkedConstOperation.pushInt], ints: [2]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [2]);
     _assertUnlinkedConst(initializer.arguments[2],
-        operators: [UnlinkedConstOperation.pushInt], ints: [3]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [3]);
     expect(initializer.argumentNames, ['b', 'c']);
   }
 
@@ -3614,7 +3612,7 @@
     expect(initializer.expression, isNull);
     expect(initializer.arguments, hasLength(1));
     _assertUnlinkedConst(initializer.arguments[0],
-        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [42]);
   }
 
   test_constructor_initializers_thisInvocation_named() {
@@ -3633,9 +3631,9 @@
     expect(initializer.expression, isNull);
     expect(initializer.arguments, hasLength(2));
     _assertUnlinkedConst(initializer.arguments[0],
-        operators: [UnlinkedConstOperation.pushInt], ints: [1]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [1]);
     _assertUnlinkedConst(initializer.arguments[1],
-        operators: [UnlinkedConstOperation.pushString], strings: ['bbb']);
+        operators: [UnlinkedExprOperation.pushString], strings: ['bbb']);
   }
 
   test_constructor_initializers_thisInvocation_namedExpression() {
@@ -3654,11 +3652,11 @@
     expect(initializer.expression, isNull);
     expect(initializer.arguments, hasLength(3));
     _assertUnlinkedConst(initializer.arguments[0],
-        operators: [UnlinkedConstOperation.pushInt], ints: [1]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [1]);
     _assertUnlinkedConst(initializer.arguments[1],
-        operators: [UnlinkedConstOperation.pushInt], ints: [2]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [2]);
     _assertUnlinkedConst(initializer.arguments[2],
-        operators: [UnlinkedConstOperation.pushInt], ints: [3]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [3]);
     expect(initializer.argumentNames, ['b', 'c']);
   }
 
@@ -3678,9 +3676,9 @@
     expect(initializer.expression, isNull);
     expect(initializer.arguments, hasLength(2));
     _assertUnlinkedConst(initializer.arguments[0],
-        operators: [UnlinkedConstOperation.pushInt], ints: [1]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [1]);
     _assertUnlinkedConst(initializer.arguments[1],
-        operators: [UnlinkedConstOperation.pushString], strings: ['bbb']);
+        operators: [UnlinkedExprOperation.pushString], strings: ['bbb']);
   }
 
   test_constructor_initializing_formal() {
@@ -3765,7 +3763,7 @@
     expect(param.kind, UnlinkedParamKind.positional);
     expect(param.defaultValueCode, 'foo');
     _assertUnlinkedConst(param.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'foo',
           expectedKind: ReferenceKind.topLevelFunction)
@@ -3810,7 +3808,7 @@
     expect(parameter.defaultValueCode, '42');
     _assertCodeRange(parameter.codeRange, 13, 10);
     _assertUnlinkedConst(parameter.initializer.bodyExpr,
-        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [42]);
   }
 
   test_constructor_initializing_formal_non_function_typed() {
@@ -3842,7 +3840,7 @@
     expect(parameter.defaultValueCode, '42');
     _assertCodeRange(parameter.codeRange, 13, 11);
     _assertUnlinkedConst(parameter.initializer.bodyExpr,
-        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [42]);
   }
 
   test_constructor_initializing_formal_required() {
@@ -3874,7 +3872,7 @@
     expect(param.kind, UnlinkedParamKind.positional);
     expect(param.defaultValueCode, '42');
     _assertUnlinkedConst(param.initializer.bodyExpr,
-        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [42]);
   }
 
   test_constructor_named() {
@@ -5784,7 +5782,7 @@
     expect(param.initializer, isNotNull);
     expect(param.defaultValueCode, 'foo');
     _assertUnlinkedConst(param.initializer.bodyExpr, operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'foo',
           expectedKind: ReferenceKind.topLevelFunction)
@@ -5807,7 +5805,7 @@
     expect(param.defaultValueCode, '42');
     _assertCodeRange(param.codeRange, 3, 5);
     _assertUnlinkedConst(param.initializer.bodyExpr,
-        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [42]);
   }
 
   test_executable_param_kind_positional() {
@@ -5826,7 +5824,7 @@
     expect(param.defaultValueCode, '42');
     _assertCodeRange(param.codeRange, 3, 6);
     _assertUnlinkedConst(param.initializer.bodyExpr,
-        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [42]);
   }
 
   test_executable_param_kind_required() {
@@ -6390,10 +6388,10 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.pushReference,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.assignToIndex,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToIndex,
         ],
         assignmentOperators: [
           (UnlinkedExprAssignOperator.assign)
@@ -6436,19 +6434,19 @@
         isValidConst: false,
         operators: [
           // 5
-          UnlinkedConstOperation.pushInt,
+          UnlinkedExprOperation.pushInt,
           // a.b[1]
-          UnlinkedConstOperation.pushReference,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.extractIndex,
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.extractIndex,
           // c[2]
-          UnlinkedConstOperation.extractProperty,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.extractIndex,
+          UnlinkedExprOperation.extractProperty,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.extractIndex,
           // f[3] = 5
-          UnlinkedConstOperation.extractProperty,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.assignToIndex,
+          UnlinkedExprOperation.extractProperty,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToIndex,
         ],
         assignmentOperators: [
           (UnlinkedExprAssignOperator.assign)
@@ -6484,10 +6482,10 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.pushReference,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.assignToIndex,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToIndex,
         ],
         assignmentOperators: [
           (UnlinkedExprAssignOperator.assign)
@@ -6516,9 +6514,9 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.invokeConstructor,
-          UnlinkedConstOperation.assignToProperty,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.invokeConstructor,
+          UnlinkedExprOperation.assignToProperty,
         ],
         assignmentOperators: [
           (UnlinkedExprAssignOperator.assign)
@@ -6550,8 +6548,8 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.assignToRef,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToRef,
         ],
         assignmentOperators: [
           (UnlinkedExprAssignOperator.assign)
@@ -6589,8 +6587,8 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.assignToRef,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToRef,
         ],
         assignmentOperators: [
           (UnlinkedExprAssignOperator.assign)
@@ -6642,8 +6640,8 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.assignToRef,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToRef,
         ],
         assignmentOperators: [
           (UnlinkedExprAssignOperator.assign)
@@ -6674,8 +6672,8 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.assignToRef,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToRef,
         ],
         assignmentOperators: [
           (UnlinkedExprAssignOperator.assign)
@@ -6706,8 +6704,8 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.assignToRef,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToRef,
         ],
         assignmentOperators: [
           (UnlinkedExprAssignOperator.assign)
@@ -6739,14 +6737,14 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushReference,
+          UnlinkedExprOperation.pushReference,
           //   ..[1] = 2
-          UnlinkedConstOperation.cascadeSectionBegin,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.assignToIndex,
+          UnlinkedExprOperation.cascadeSectionBegin,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToIndex,
           // c
-          UnlinkedConstOperation.cascadeSectionEnd,
+          UnlinkedExprOperation.cascadeSectionEnd,
         ],
         assignmentOperators: [
           UnlinkedExprAssignOperator.assign,
@@ -6781,19 +6779,19 @@
         isValidConst: false,
         operators: [
           // new C()
-          UnlinkedConstOperation.invokeConstructor,
+          UnlinkedExprOperation.invokeConstructor,
           //   ..f1 = 1
-          UnlinkedConstOperation.cascadeSectionBegin,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.assignToProperty,
+          UnlinkedExprOperation.cascadeSectionBegin,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToProperty,
           // C
-          UnlinkedConstOperation.cascadeSectionEnd,
+          UnlinkedExprOperation.cascadeSectionEnd,
           //   ..f2 += 2
-          UnlinkedConstOperation.cascadeSectionBegin,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.assignToProperty,
+          UnlinkedExprOperation.cascadeSectionBegin,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToProperty,
           // C
-          UnlinkedConstOperation.cascadeSectionEnd,
+          UnlinkedExprOperation.cascadeSectionEnd,
         ],
         assignmentOperators: [
           UnlinkedExprAssignOperator.assign,
@@ -6836,29 +6834,29 @@
         isValidConst: false,
         operators: [
           // new A()
-          UnlinkedConstOperation.invokeConstructor,
+          UnlinkedExprOperation.invokeConstructor,
           // ..fa1 = 1
-          UnlinkedConstOperation.cascadeSectionBegin,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.assignToProperty,
-          UnlinkedConstOperation.cascadeSectionEnd,
+          UnlinkedExprOperation.cascadeSectionBegin,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToProperty,
+          UnlinkedExprOperation.cascadeSectionEnd,
           // ..b
-          UnlinkedConstOperation.cascadeSectionBegin,
+          UnlinkedExprOperation.cascadeSectionBegin,
           //   new B()
-          UnlinkedConstOperation.invokeConstructor,
+          UnlinkedExprOperation.invokeConstructor,
           //   ..fb = 2
-          UnlinkedConstOperation.cascadeSectionBegin,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.assignToProperty,
-          UnlinkedConstOperation.cascadeSectionEnd,
+          UnlinkedExprOperation.cascadeSectionBegin,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToProperty,
+          UnlinkedExprOperation.cascadeSectionEnd,
           // ..b = <pop value>
-          UnlinkedConstOperation.assignToProperty,
-          UnlinkedConstOperation.cascadeSectionEnd,
+          UnlinkedExprOperation.assignToProperty,
+          UnlinkedExprOperation.cascadeSectionEnd,
           // ..fa2 = 3
-          UnlinkedConstOperation.cascadeSectionBegin,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.assignToProperty,
-          UnlinkedConstOperation.cascadeSectionEnd,
+          UnlinkedExprOperation.cascadeSectionBegin,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToProperty,
+          UnlinkedExprOperation.cascadeSectionEnd,
         ],
         assignmentOperators: [
           UnlinkedExprAssignOperator.assign,
@@ -6904,21 +6902,21 @@
         isValidConst: false,
         operators: [
           // a
-          UnlinkedConstOperation.pushReference,
+          UnlinkedExprOperation.pushReference,
           //   ..m(5)
-          UnlinkedConstOperation.cascadeSectionBegin,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.invokeMethod,
+          UnlinkedExprOperation.cascadeSectionBegin,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.invokeMethod,
           //   ..abs()
-          UnlinkedConstOperation.invokeMethod,
+          UnlinkedExprOperation.invokeMethod,
           // a
-          UnlinkedConstOperation.cascadeSectionEnd,
+          UnlinkedExprOperation.cascadeSectionEnd,
           //   ..m(6)
-          UnlinkedConstOperation.cascadeSectionBegin,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.invokeMethod,
+          UnlinkedExprOperation.cascadeSectionBegin,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.invokeMethod,
           // a
-          UnlinkedConstOperation.cascadeSectionEnd,
+          UnlinkedExprOperation.cascadeSectionEnd,
         ],
         ints: [
           5, 0, 1, 0, // m(5)
@@ -6949,10 +6947,10 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.invokeConstructor,
-          UnlinkedConstOperation.extractProperty,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.extractIndex,
+          UnlinkedExprOperation.invokeConstructor,
+          UnlinkedExprOperation.extractProperty,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.extractIndex,
         ],
         ints: [
           0,
@@ -6981,8 +6979,8 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.invokeConstructor,
-          UnlinkedConstOperation.extractProperty,
+          UnlinkedExprOperation.invokeConstructor,
+          UnlinkedExprOperation.extractProperty,
         ],
         ints: [
           0,
@@ -7008,9 +7006,9 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.pushLocalFunctionReference,
-          UnlinkedConstOperation.invokeMethodRef
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.pushLocalFunctionReference,
+          UnlinkedExprOperation.invokeMethodRef
         ],
         ints: [
           5,
@@ -7037,10 +7035,10 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.pushLocalFunctionReference,
-          UnlinkedConstOperation.pushLocalFunctionReference,
-          UnlinkedConstOperation.invokeMethodRef
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.pushLocalFunctionReference,
+          UnlinkedExprOperation.pushLocalFunctionReference,
+          UnlinkedExprOperation.invokeMethodRef
         ],
         ints: [
           5,
@@ -7067,7 +7065,7 @@
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
-        operators: [UnlinkedConstOperation.pushLocalFunctionReference],
+        operators: [UnlinkedExprOperation.pushLocalFunctionReference],
         ints: [0, 0]);
   }
 
@@ -7080,7 +7078,7 @@
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
-        operators: [UnlinkedConstOperation.pushLocalFunctionReference],
+        operators: [UnlinkedExprOperation.pushLocalFunctionReference],
         ints: [0, 0]);
   }
 
@@ -7092,7 +7090,7 @@
 final v = ((a, b) {return 42;})(1, 2);
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr,
-        isValidConst: false, operators: [UnlinkedConstOperation.pushNull]);
+        isValidConst: false, operators: [UnlinkedExprOperation.pushNull]);
   }
 
   test_expr_functionExpressionInvocation_withExpressionBody() {
@@ -7103,7 +7101,7 @@
 final v = ((a, b) => 42)(1, 2);
 ''');
     _assertUnlinkedConst(variable.initializer.bodyExpr,
-        isValidConst: false, operators: [UnlinkedConstOperation.pushNull]);
+        isValidConst: false, operators: [UnlinkedExprOperation.pushNull]);
   }
 
   test_expr_inClosure() {
@@ -7112,7 +7110,7 @@
     }
     UnlinkedVariable variable = serializeVariableText('var v = () => 1;');
     _assertUnlinkedConst(variable.initializer.localFunctions[0].bodyExpr,
-        operators: [UnlinkedConstOperation.pushInt], ints: [1]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [1]);
   }
 
   test_expr_inClosure_noTypeInferenceNeeded() {
@@ -7130,7 +7128,7 @@
         serializeVariableText('var v = (x) => (y) => x;');
     _assertUnlinkedConst(
         variable.initializer.localFunctions[0].localFunctions[0].bodyExpr,
-        operators: [UnlinkedConstOperation.pushParameter],
+        operators: [UnlinkedExprOperation.pushParameter],
         strings: ['x']);
   }
 
@@ -7140,7 +7138,7 @@
     }
     UnlinkedVariable variable = serializeVariableText('var v = (x) => x;');
     _assertUnlinkedConst(variable.initializer.localFunctions[0].bodyExpr,
-        operators: [UnlinkedConstOperation.pushParameter], strings: ['x']);
+        operators: [UnlinkedExprOperation.pushParameter], strings: ['x']);
   }
 
   test_expr_inClosure_refersToParam_methodCall() {
@@ -7151,8 +7149,8 @@
     _assertUnlinkedConst(variable.initializer.localFunctions[0].bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushParameter,
-          UnlinkedConstOperation.invokeMethod
+          UnlinkedExprOperation.pushParameter,
+          UnlinkedExprOperation.invokeMethod
         ],
         strings: [
           'x',
@@ -7174,9 +7172,9 @@
     _assertUnlinkedConst(variable.initializer.localFunctions[0].bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushParameter,
-          UnlinkedConstOperation.extractProperty,
-          UnlinkedConstOperation.invokeMethod
+          UnlinkedExprOperation.pushParameter,
+          UnlinkedExprOperation.extractProperty,
+          UnlinkedExprOperation.invokeMethod
         ],
         strings: [
           'x',
@@ -7199,10 +7197,10 @@
     _assertUnlinkedConst(variable.initializer.localFunctions[0].bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushParameter,
-          UnlinkedConstOperation.pushLocalFunctionReference,
-          UnlinkedConstOperation.pushReference,
-          UnlinkedConstOperation.conditional,
+          UnlinkedExprOperation.pushParameter,
+          UnlinkedExprOperation.pushLocalFunctionReference,
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.conditional,
         ],
         strings: [
           'b'
@@ -7224,8 +7222,8 @@
     UnlinkedVariable variable = serializeVariableText('var v = (x) => x.y;');
     _assertUnlinkedConst(variable.initializer.localFunctions[0].bodyExpr,
         operators: [
-          UnlinkedConstOperation.pushParameter,
-          UnlinkedConstOperation.extractProperty
+          UnlinkedExprOperation.pushParameter,
+          UnlinkedExprOperation.extractProperty
         ],
         strings: [
           'x',
@@ -7242,9 +7240,9 @@
     _assertUnlinkedConst(variable.initializer.localFunctions[0].bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushNull,
-          UnlinkedConstOperation.pushParameter,
-          UnlinkedConstOperation.assignToProperty
+          UnlinkedExprOperation.pushNull,
+          UnlinkedExprOperation.pushParameter,
+          UnlinkedExprOperation.assignToProperty
         ],
         strings: [
           'x',
@@ -7262,9 +7260,9 @@
     UnlinkedVariable variable = serializeVariableText('var v = (x) => x.y.z;');
     _assertUnlinkedConst(variable.initializer.localFunctions[0].bodyExpr,
         operators: [
-          UnlinkedConstOperation.pushParameter,
-          UnlinkedConstOperation.extractProperty,
-          UnlinkedConstOperation.extractProperty
+          UnlinkedExprOperation.pushParameter,
+          UnlinkedExprOperation.extractProperty,
+          UnlinkedExprOperation.extractProperty
         ],
         strings: [
           'x',
@@ -7282,10 +7280,10 @@
     _assertUnlinkedConst(variable.initializer.localFunctions[0].bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushNull,
-          UnlinkedConstOperation.pushParameter,
-          UnlinkedConstOperation.extractProperty,
-          UnlinkedConstOperation.assignToProperty
+          UnlinkedExprOperation.pushNull,
+          UnlinkedExprOperation.pushParameter,
+          UnlinkedExprOperation.extractProperty,
+          UnlinkedExprOperation.assignToProperty
         ],
         strings: [
           'x',
@@ -7310,11 +7308,11 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.invokeConstructor,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.invokeMethod,
+          UnlinkedExprOperation.invokeConstructor,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.invokeMethod,
         ],
         ints: [
           0,
@@ -7350,8 +7348,8 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.invokeConstructor,
-          UnlinkedConstOperation.invokeMethod
+          UnlinkedExprOperation.invokeConstructor,
+          UnlinkedExprOperation.invokeMethod
         ],
         ints: [
           0,
@@ -7390,9 +7388,9 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.invokeMethodRef,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.invokeMethodRef,
         ],
         ints: [
           10,
@@ -7432,7 +7430,7 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.invokeMethodRef,
+          UnlinkedExprOperation.invokeMethodRef,
         ],
         ints: [
           0,
@@ -7463,8 +7461,8 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushReference,
-          UnlinkedConstOperation.invokeMethodRef
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.invokeMethodRef
         ],
         ints: [
           0,
@@ -7490,7 +7488,7 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.invokeMethodRef
+          UnlinkedExprOperation.invokeMethodRef
         ],
         ints: [
           0,
@@ -7516,10 +7514,10 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.add,
-          UnlinkedConstOperation.throwException,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.add,
+          UnlinkedExprOperation.throwException,
         ],
         ints: [
           1,
@@ -7537,8 +7535,8 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.typeCast,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.typeCast,
         ],
         ints: [
           42
@@ -7559,8 +7557,8 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.typeCheck,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.typeCheck,
         ],
         ints: [
           42
@@ -7591,7 +7589,7 @@
         serializeClassText('class C { static const int i = 0; }').fields[0];
     expect(variable.isConst, isTrue);
     _assertUnlinkedConst(variable.initializer.bodyExpr,
-        operators: [UnlinkedConstOperation.pushInt], ints: [0]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [0]);
   }
 
   test_field_documented() {
@@ -7612,7 +7610,7 @@
         serializeClassText('class C { final int i = 0; }').fields[0];
     expect(variable.isFinal, isTrue);
     _assertUnlinkedConst(variable.initializer.bodyExpr,
-        operators: [UnlinkedConstOperation.pushInt], ints: [0]);
+        operators: [UnlinkedExprOperation.pushInt], ints: [0]);
   }
 
   test_field_final_notConstExpr() {
@@ -7625,9 +7623,9 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.invokeMethodRef,
-          UnlinkedConstOperation.add,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.invokeMethodRef,
+          UnlinkedExprOperation.add,
         ],
         ints: [
           1,
@@ -7652,7 +7650,7 @@
 }''').fields[0];
     expect(variable.isFinal, isTrue);
     _assertUnlinkedConst(variable.initializer.bodyExpr,
-        operators: [UnlinkedConstOperation.makeTypedList],
+        operators: [UnlinkedExprOperation.makeTypedList],
         ints: [0],
         referenceValidators: [(EntityRef r) => checkParamTypeRef(r, 1)]);
   }
@@ -8686,7 +8684,7 @@
         'class A { const A.named(); } @A.named() class C {}');
     expect(cls.annotations, hasLength(1));
     _assertUnlinkedConst(cls.annotations[0], operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -8705,7 +8703,7 @@
         'import "foo.dart" as foo; @foo.A.named() class C {}');
     expect(cls.annotations, hasLength(1));
     _assertUnlinkedConst(cls.annotations[0], operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -8727,7 +8725,7 @@
         allowErrors: true);
     expect(cls.annotations, hasLength(1));
     _assertUnlinkedConst(cls.annotations[0], operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -8748,7 +8746,7 @@
         allowErrors: true);
     expect(cls.annotations, hasLength(1));
     _assertUnlinkedConst(cls.annotations[0], operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -8768,7 +8766,7 @@
         serializeClassText('@A.named() class C {}', allowErrors: true);
     expect(cls.annotations, hasLength(1));
     _assertUnlinkedConst(cls.annotations[0], operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -8786,7 +8784,7 @@
         allowErrors: true);
     expect(cls.annotations, hasLength(1));
     _assertUnlinkedConst(cls.annotations[0], operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -8804,7 +8802,7 @@
         serializeClassText('class A { const A(); } @A() class C {}');
     expect(cls.annotations, hasLength(1));
     _assertUnlinkedConst(cls.annotations[0], operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -8820,7 +8818,7 @@
         serializeClassText('import "foo.dart" as foo; @foo.A() class C {}');
     expect(cls.annotations, hasLength(1));
     _assertUnlinkedConst(cls.annotations[0], operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -8837,7 +8835,7 @@
         allowErrors: true);
     expect(cls.annotations, hasLength(1));
     _assertUnlinkedConst(cls.annotations[0], operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -8852,7 +8850,7 @@
         serializeClassText('@A() class C {}', allowErrors: true);
     expect(cls.annotations, hasLength(1));
     _assertUnlinkedConst(cls.annotations[0], operators: [
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       0
@@ -8867,8 +8865,8 @@
         serializeClassText('class A { const A(x); } @A(null) class C {}');
     expect(cls.annotations, hasLength(1));
     _assertUnlinkedConst(cls.annotations[0], operators: [
-      UnlinkedConstOperation.pushNull,
-      UnlinkedConstOperation.invokeConstructor,
+      UnlinkedExprOperation.pushNull,
+      UnlinkedExprOperation.invokeConstructor,
     ], ints: [
       0,
       1
@@ -8994,16 +8992,16 @@
   test_metadata_multiple_annotations() {
     UnlinkedClass cls =
         serializeClassText('const a = null, b = null; @a @b class C {}');
-    List<UnlinkedConst> annotations = cls.annotations;
+    List<UnlinkedExpr> annotations = cls.annotations;
     expect(annotations, hasLength(2));
     _assertUnlinkedConst(annotations[0], operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'a',
           expectedKind: ReferenceKind.topLevelPropertyAccessor)
     ]);
     _assertUnlinkedConst(annotations[1], operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'b',
           expectedKind: ReferenceKind.topLevelPropertyAccessor)
@@ -9022,7 +9020,7 @@
         serializeClassText('import "a.dart" as a; @a.b class C {}');
     expect(cls.annotations, hasLength(1));
     _assertUnlinkedConst(cls.annotations[0], operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'b',
           expectedKind: ReferenceKind.topLevelPropertyAccessor,
@@ -9037,7 +9035,7 @@
         allowErrors: true);
     expect(cls.annotations, hasLength(1));
     _assertUnlinkedConst(cls.annotations[0], operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'b',
           expectedKind: ReferenceKind.unresolved, expectedPrefix: 'a')
@@ -9092,7 +9090,7 @@
     UnlinkedClass cls = serializeClassText('@a class C {}', allowErrors: true);
     expect(cls.annotations, hasLength(1));
     _assertUnlinkedConst(cls.annotations[0], operators: [
-      UnlinkedConstOperation.pushReference
+      UnlinkedExprOperation.pushReference
     ], referenceValidators: [
       (EntityRef r) => checkTypeRef(r, null, null, 'a',
           expectedKind: ReferenceKind.unresolved)
@@ -10237,12 +10235,12 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.add,
-          UnlinkedConstOperation.assignToRef,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.add,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.add,
+          UnlinkedExprOperation.assignToRef,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.add,
         ],
         assignmentOperators: [
           expectedAssignOperator
@@ -10304,9 +10302,9 @@
     _assertUnlinkedConst(variable.initializer.bodyExpr,
         isValidConst: false,
         operators: [
-          UnlinkedConstOperation.assignToRef,
-          UnlinkedConstOperation.pushInt,
-          UnlinkedConstOperation.add,
+          UnlinkedExprOperation.assignToRef,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.add,
         ],
         assignmentOperators: [
           expectedAssignmentOperator
@@ -10324,9 +10322,9 @@
   /**
    * TODO(scheglov) rename "Const" to "Expr" everywhere
    */
-  void _assertUnlinkedConst(UnlinkedConst constExpr,
+  void _assertUnlinkedConst(UnlinkedExpr constExpr,
       {bool isValidConst: true,
-      List<UnlinkedConstOperation> operators: const <UnlinkedConstOperation>[],
+      List<UnlinkedExprOperation> operators: const <UnlinkedExprOperation>[],
       List<UnlinkedExprAssignOperator> assignmentOperators:
           const <UnlinkedExprAssignOperator>[],
       List<int> ints: const <int>[],
diff --git a/pkg/analyzer/test/src/task/options_test.dart b/pkg/analyzer/test/src/task/options_test.dart
index ce4bf2e..be0798c 100644
--- a/pkg/analyzer/test/src/task/options_test.dart
+++ b/pkg/analyzer/test/src/task/options_test.dart
@@ -226,6 +226,77 @@
     expect(errors[0].errorCode, AnalysisOptionsErrorCode.PARSE_ERROR);
   }
 
+  test_perform_include() {
+    newSource('/other_options.yaml', '');
+    String code = r'''
+include: other_options.yaml
+''';
+    AnalysisTarget target = newSource(optionsFilePath, code);
+    computeResult(target, ANALYSIS_OPTIONS_ERRORS);
+    expect(task, isGenerateOptionsErrorsTask);
+    List<AnalysisError> errors =
+        outputs[ANALYSIS_OPTIONS_ERRORS] as List<AnalysisError>;
+    expect(errors, hasLength(0));
+  }
+
+  test_perform_include_bad_value() {
+    newSource('/other_options.yaml', '''
+analyzer:
+  errors:
+    unused_local_variable: ftw
+''');
+    String code = r'''
+include: other_options.yaml
+''';
+    AnalysisTarget target = newSource(optionsFilePath, code);
+    computeResult(target, ANALYSIS_OPTIONS_ERRORS);
+    expect(task, isGenerateOptionsErrorsTask);
+    List<AnalysisError> errors =
+    outputs[ANALYSIS_OPTIONS_ERRORS] as List<AnalysisError>;
+    expect(errors, hasLength(1));
+    AnalysisError error = errors[0];
+    expect(error.errorCode, AnalysisOptionsWarningCode.INCLUDED_FILE_WARNING);
+    expect(error.source, target.source);
+    expect(error.offset, 10);
+    expect(error.length, 18);
+    expect(error.message, contains('other_options.yaml(47..49)'));
+  }
+
+  test_perform_include_bad_yaml() {
+    newSource('/other_options.yaml', ':');
+    String code = r'''
+include: other_options.yaml
+''';
+    AnalysisTarget target = newSource(optionsFilePath, code);
+    computeResult(target, ANALYSIS_OPTIONS_ERRORS);
+    expect(task, isGenerateOptionsErrorsTask);
+    List<AnalysisError> errors =
+    outputs[ANALYSIS_OPTIONS_ERRORS] as List<AnalysisError>;
+    expect(errors, hasLength(1));
+    AnalysisError error = errors[0];
+    expect(error.errorCode, AnalysisOptionsErrorCode.INCLUDED_FILE_PARSE_ERROR);
+    expect(error.source, target.source);
+    expect(error.offset, 10);
+    expect(error.length, 18);
+    expect(error.message, contains('other_options.yaml(0..0)'));
+  }
+
+  test_perform_include_missing() {
+    String code = r'''
+include: other_options.yaml
+''';
+    AnalysisTarget target = newSource(optionsFilePath, code);
+    computeResult(target, ANALYSIS_OPTIONS_ERRORS);
+    expect(task, isGenerateOptionsErrorsTask);
+    List<AnalysisError> errors =
+        outputs[ANALYSIS_OPTIONS_ERRORS] as List<AnalysisError>;
+    expect(errors, hasLength(1));
+    AnalysisError error = errors[0];
+    expect(error.errorCode, AnalysisOptionsWarningCode.INCLUDE_FILE_NOT_FOUND);
+    expect(error.offset, 10);
+    expect(error.length, 18);
+  }
+
   test_perform_OK() {
     String code = r'''
 analyzer:
diff --git a/pkg/compiler/lib/src/common/backend_api.dart b/pkg/compiler/lib/src/common/backend_api.dart
index b613093..2bb7001 100644
--- a/pkg/compiler/lib/src/common/backend_api.dart
+++ b/pkg/compiler/lib/src/common/backend_api.dart
@@ -17,7 +17,7 @@
 import '../constants/values.dart' show ConstantValue;
 import '../dart_types.dart' show DartType, InterfaceType;
 import '../elements/elements.dart'
-    show ClassElement, Element, FunctionElement, LibraryElement;
+    show ClassElement, Element, FunctionElement, MethodElement, LibraryElement;
 import '../enqueue.dart' show Enqueuer, EnqueueTask, ResolutionEnqueuer;
 import '../io/code_output.dart' show CodeBuffer;
 import '../io/source_information.dart' show SourceInformationStrategy;
@@ -313,7 +313,8 @@
 
   void forgetElement(Element element) {}
 
-  void registerMainHasArguments(Enqueuer enqueuer) {}
+  /// Computes the [WorldImpact] of calling [mainMethod] as the entry point.
+  WorldImpact computeMainImpact(Enqueuer enqueuer, MethodElement mainMethod) {}
 
   /// Returns the location of the patch-file associated with [libraryName]
   /// resolved from [plaformConfigUri].
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index ef0e751..c7bdcdf 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -683,6 +683,10 @@
         backend.enqueueHelpers(enqueuer.resolution);
         resolveLibraryMetadata();
         reporter.log('Resolving...');
+        if (mainFunction != null && !mainFunction.isMalformed) {
+          mainFunction.computeType(resolution);
+        }
+
         processQueue(enqueuer.resolution, mainFunction);
         enqueuer.resolution.logSummary(reporter.log);
 
@@ -847,28 +851,15 @@
     });
   }
 
-  void processQueue(Enqueuer enqueuer, Element main) {
+  void processQueue(Enqueuer enqueuer, MethodElement mainMethod) {
     selfTask.measureSubtask("Compiler.processQueue", () {
       enqueuer.applyImpact(
           impactStrategy,
           enqueuer.nativeEnqueuer
               .processNativeClasses(libraryLoader.libraries));
-      if (main != null && !main.isMalformed) {
-        FunctionElement mainMethod = main;
-        mainMethod.computeType(resolution);
-        if (mainMethod.functionSignature.parameterCount != 0) {
-          // The first argument could be a list of strings.
-          backend.backendClasses.listImplementation.ensureResolved(resolution);
-          enqueuer.registerInstantiatedType(
-              backend.backendClasses.listImplementation.rawType);
-          backend.backendClasses.stringImplementation
-              .ensureResolved(resolution);
-          enqueuer.registerInstantiatedType(
-              backend.backendClasses.stringImplementation.rawType);
-
-          backend.registerMainHasArguments(enqueuer);
-        }
-        enqueuer.addToWorkList(main);
+      if (mainMethod != null && !mainMethod.isMalformed) {
+        enqueuer.applyImpact(
+            impactStrategy, backend.computeMainImpact(enqueuer, mainMethod));
       }
       if (options.verbose) {
         progress.reset();
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index bb50941..6c7de3f 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -22,6 +22,7 @@
         AnalyzableElement,
         AstElement,
         ClassElement,
+        ConstructorElement,
         Element,
         Entity,
         FunctionElement,
@@ -158,9 +159,9 @@
       this.globalDependencies,
       Backend backend,
       CommonElements commonElements,
-      CacheStrategy cacheStrategy)
-      : this.name = 'resolution enqueuer',
-        this.backend = backend,
+      CacheStrategy cacheStrategy,
+      [this.name = 'resolution enqueuer'])
+      : this.backend = backend,
         this.commonElements = commonElements,
         this.nativeEnqueuer = backend.nativeResolutionEnqueuer(),
         processedElements = new Set<AstElement>(),
@@ -204,16 +205,20 @@
   }
 
   void _registerInstantiatedType(InterfaceType type,
-      {bool mirrorUsage: false,
+      {ConstructorElement constructor,
+      bool mirrorUsage: false,
       bool nativeUsage: false,
-      bool globalDependency: false}) {
+      bool globalDependency: false,
+      bool isRedirection: false}) {
     task.measure(() {
       ClassElement cls = type.element;
       cls.ensureResolved(resolution);
       bool isNative = backend.isNative(cls);
       _universe.registerTypeInstantiation(type,
+          constructor: constructor,
           isNative: isNative,
-          byMirrors: mirrorUsage, onImplemented: (ClassElement cls) {
+          byMirrors: mirrorUsage,
+          isRedirection: isRedirection, onImplemented: (ClassElement cls) {
         backend.registerImplementedClass(cls, this);
       });
       if (globalDependency && !mirrorUsage) {
@@ -453,7 +458,14 @@
         break;
       case StaticUseKind.CONSTRUCTOR_INVOKE:
       case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
-        _registerTypeUse(new TypeUse.instantiation(staticUse.type));
+        _registerInstantiatedType(staticUse.type,
+            constructor: staticUse.element, globalDependency: false);
+        break;
+      case StaticUseKind.REDIRECTION:
+        _registerInstantiatedType(staticUse.type,
+            constructor: staticUse.element,
+            globalDependency: false,
+            isRedirection: true);
         break;
       case StaticUseKind.DIRECT_INVOKE:
         invariant(
diff --git a/pkg/compiler/lib/src/js/rewrite_async.dart b/pkg/compiler/lib/src/js/rewrite_async.dart
index 5d37861..bc05656 100644
--- a/pkg/compiler/lib/src/js/rewrite_async.dart
+++ b/pkg/compiler/lib/src/js/rewrite_async.dart
@@ -5,13 +5,14 @@
 library rewrite_async;
 
 import 'dart:collection';
-import "dart:math" show max;
+import 'dart:math' show max;
 
 import 'package:js_runtime/shared/async_await_error_codes.dart' as error_codes;
 
 import '../common.dart';
+import '../io/source_information.dart' show SourceInformation;
 import '../util/util.dart' show Pair;
-import "js.dart" as js;
+import 'js.dart' as js;
 
 /// Rewrites a [js.Fun] with async/sync*/async* functions and await and yield
 /// (with dart-like semantics) to an equivalent function without these.
@@ -519,7 +520,8 @@
   js.Fun finishFunction(
       List<js.Parameter> parameters,
       js.Statement rewrittenBody,
-      js.VariableDeclarationList variableDeclarations);
+      js.VariableDeclarationList variableDeclarations,
+      SourceInformation sourceInformation);
 
   Iterable<js.VariableInitialization> variableInitializations();
 
@@ -705,7 +707,8 @@
     js.VariableDeclarationList variableDeclarations =
         new js.VariableDeclarationList(variables);
 
-    return finishFunction(node.params, rewrittenBody, variableDeclarations);
+    return finishFunction(node.params, rewrittenBody, variableDeclarations,
+        node.sourceInformation);
   }
 
   @override
@@ -851,7 +854,8 @@
     bool storeTarget = node.arguments.any(shouldTransform);
     return withCallTargetExpression(node.target, (target) {
       return withExpressions(node.arguments, (List<js.Expression> arguments) {
-        return new js.Call(target, arguments);
+        return new js.Call(target, arguments)
+            .withSourceInformation(node.sourceInformation);
       });
     }, store: storeTarget);
   }
@@ -1405,7 +1409,8 @@
   @override
   void visitThrow(js.Throw node) {
     withExpression(node.expression, (js.Expression expression) {
-      addStatement(new js.Throw(expression));
+      addStatement(new js.Throw(expression)
+          .withSourceInformation(node.sourceInformation));
     }, store: false);
   }
 
@@ -1712,14 +1717,13 @@
       addStatement(new js.Comment("implicit return"));
     }
     addStatement(js.js.statement(
-        "return #runtimeHelper(#returnValue, #successCode, #completer);",
-        {
-          "runtimeHelper": asyncHelper,
-          "successCode": js.number(error_codes.SUCCESS),
-          "returnValue":
-              analysis.hasExplicitReturns ? returnValue : new js.LiteralNull(),
-          "completer": completer
-        }));
+        "return #runtimeHelper(#returnValue, #successCode, #completer);", {
+      "runtimeHelper": asyncHelper,
+      "successCode": js.number(error_codes.SUCCESS),
+      "returnValue":
+          analysis.hasExplicitReturns ? returnValue : new js.LiteralNull(),
+      "completer": completer
+    }));
   }
 
   @override
@@ -1759,7 +1763,8 @@
   js.Fun finishFunction(
       List<js.Parameter> parameters,
       js.Statement rewrittenBody,
-      js.VariableDeclarationList variableDeclarations) {
+      js.VariableDeclarationList variableDeclarations,
+      SourceInformation sourceInformation) {
     return js.js(
         """
         function (#parameters) {
@@ -1787,7 +1792,7 @@
           "asyncHelper": asyncHelper,
           "completer": completer,
           "wrapBody": wrapBody,
-        });
+        }).withSourceInformation(sourceInformation);
   }
 }
 
@@ -1838,7 +1843,8 @@
   js.Fun finishFunction(
       List<js.Parameter> parameters,
       js.Statement rewrittenBody,
-      js.VariableDeclarationList variableDeclarations) {
+      js.VariableDeclarationList variableDeclarations,
+      SourceInformation sourceInformation) {
     // Each iterator invocation on the iterable should work on its own copy of
     // the parameters.
     // TODO(sigurdm): We only need to do this copying for parameters that are
@@ -1891,7 +1897,7 @@
           "handler": handler,
           "currentError": currentErrorName,
           "ERROR": js.number(error_codes.ERROR),
-        });
+        }).withSourceInformation(sourceInformation);
   }
 
   void addErrorExit() {
@@ -2030,7 +2036,8 @@
   js.Fun finishFunction(
       List<js.Parameter> parameters,
       js.Statement rewrittenBody,
-      js.VariableDeclarationList variableDeclarations) {
+      js.VariableDeclarationList variableDeclarations,
+      SourceInformation sourceInformation) {
     return js.js(
         """
         function (#parameters) {
@@ -2074,7 +2081,7 @@
           "streamOfController": streamOfController,
           "controller": controllerName,
           "wrapBody": wrapBody,
-        });
+        }).withSourceInformation(sourceInformation);
   }
 
   @override
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 3aca346..03e5839 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -59,6 +59,7 @@
         TransformedWorldImpact,
         WorldImpact,
         WorldImpactBuilder,
+        WorldImpactBuilderImpl,
         WorldImpactVisitor,
         StagedWorldImpactBuilder;
 import '../util/util.dart';
@@ -2577,12 +2578,23 @@
     aliasedSuperMembers.remove(element);
   }
 
-  void registerMainHasArguments(Enqueuer enqueuer) {
-    // If the main method takes arguments, this compilation could be the target
-    // of Isolate.spawnUri. Strictly speaking, that can happen also if main
-    // takes no arguments, but in this case the spawned isolate can't
-    // communicate with the spawning isolate.
-    enqueuer.enableIsolateSupport();
+  @override
+  WorldImpact computeMainImpact(Enqueuer enqueuer, MethodElement mainMethod) {
+    WorldImpactBuilderImpl mainImpact = new WorldImpactBuilderImpl();
+    if (mainMethod.parameters.isNotEmpty) {
+      impactTransformer.registerBackendImpact(
+          mainImpact, impacts.mainWithArguments);
+      mainImpact.registerStaticUse(
+          new StaticUse.staticInvoke(mainMethod, CallStructure.TWO_ARGS));
+      // If the main method takes arguments, this compilation could be the
+      // target of Isolate.spawnUri. Strictly speaking, that can happen also if
+      // main takes no arguments, but in this case the spawned isolate can't
+      // communicate with the spawning isolate.
+      enqueuer.enableIsolateSupport();
+    }
+    mainImpact.registerStaticUse(
+        new StaticUse.staticInvoke(mainMethod, CallStructure.NO_ARGS));
+    return mainImpact;
   }
 
   /// Returns the filename for the output-unit named [name].
@@ -3000,7 +3012,7 @@
   }
 
   void registerBackendImpact(
-      TransformedWorldImpact worldImpact, BackendImpact backendImpact) {
+      WorldImpactBuilder worldImpact, BackendImpact backendImpact) {
     for (Element staticUse in backendImpact.staticUses) {
       assert(staticUse != null);
       backend.registerBackendUse(staticUse);
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index 7726ed0..afbd270 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -83,6 +83,18 @@
     return _computeSignature;
   }
 
+  BackendImpact _mainWithArguments;
+
+  BackendImpact get mainWithArguments {
+    if (_mainWithArguments == null) {
+      _mainWithArguments = new BackendImpact(
+          instantiatedClasses: [
+            helpers.jsArrayClass,
+            helpers.jsStringClass]);
+    }
+    return _mainWithArguments;
+  }
+
   BackendImpact _asyncBody;
 
   BackendImpact get asyncBody {
diff --git a/pkg/compiler/lib/src/js_backend/enqueuer.dart b/pkg/compiler/lib/src/js_backend/enqueuer.dart
index 179a65d..07c1f06 100644
--- a/pkg/compiler/lib/src/js_backend/enqueuer.dart
+++ b/pkg/compiler/lib/src/js_backend/enqueuer.dart
@@ -17,7 +17,6 @@
 import '../elements/elements.dart'
     show
         ClassElement,
-        ConstructorElement,
         Element,
         Elements,
         Entity,
@@ -378,6 +377,7 @@
         break;
       case StaticUseKind.CONSTRUCTOR_INVOKE:
       case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
+      case StaticUseKind.REDIRECTION:
         registerTypeUse(new TypeUse.instantiation(staticUse.type));
         break;
       case StaticUseKind.DIRECT_INVOKE:
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index f93553d..16843b3 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -3681,13 +3681,10 @@
       isValidAsConstant = false;
     }
 
-    registry.registerStaticUse(
-        new StaticUse.constructorRedirect(redirectionTarget));
-    // TODO(johnniwinther): Register the effective target type as part of the
-    // static use instead.
-    registry.registerTypeUse(new TypeUse.instantiation(redirectionTarget
-        .enclosingClass.thisType
-        .subst(type.typeArguments, targetClass.typeVariables)));
+    registry.registerStaticUse(new StaticUse.constructorRedirect(
+        redirectionTarget,
+        redirectionTarget.enclosingClass.thisType
+            .subst(type.typeArguments, targetClass.typeVariables)));
     if (resolution.commonElements.isSymbolConstructor(enclosingElement)) {
       registry.registerFeature(Feature.SYMBOL_CONSTRUCTOR);
     }
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 3f407ca..1c922e5 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -29,6 +29,7 @@
 import 'nodes.dart';
 import 'ssa_branch_builder.dart';
 import 'type_builder.dart';
+import 'types.dart' show TypeMaskFactory;
 
 class SsaKernelBuilderTask extends CompilerTask {
   final JavaScriptBackend backend;
@@ -57,6 +58,14 @@
   final ResolvedAst resolvedAst;
   final CodegenRegistry registry;
 
+  /// A stack of [DartType]s that have been seen during inlining of factory
+  /// constructors.  These types are preserved in [HInvokeStatic]s and
+  /// [HCreate]s inside the inline code and registered during code generation
+  /// for these nodes.
+  // TODO(karlklose): consider removing this and keeping the (substituted) types
+  // of the type variables in an environment (like the [LocalsHandler]).
+  final List<DartType> currentImplicitInstantiations = <DartType>[];
+
   @override
   JavaScriptBackend get backend => compiler.backend;
 
@@ -320,6 +329,18 @@
     closeFunction();
   }
 
+  void addImplicitInstantiation(DartType type) {
+    if (type != null) {
+      currentImplicitInstantiations.add(type);
+    }
+  }
+
+  void removeImplicitInstantiation(DartType type) {
+    if (type != null) {
+      currentImplicitInstantiations.removeLast();
+    }
+  }
+
   void openFunction() {
     HBasicBlock block = graph.addNewBlock();
     open(graph.entry);
@@ -715,7 +736,9 @@
     stack.add(graph.addConstantNull(compiler));
   }
 
-  HInstruction setRtiIfNeeded(HInstruction object, ir.ListLiteral listLiteral) {
+  /// Set the runtime type information if necessary.
+  HInstruction setListRuntimeTypeInfoIfNeeded(
+      HInstruction object, ir.ListLiteral listLiteral) {
     InterfaceType type = localsHandler
         .substInContext(elements.getType(astAdapter.getNode(listLiteral)));
     if (!backend.classNeedsRti(type.element) || type.treatAsRaw) {
@@ -744,7 +767,8 @@
       }
       listInstruction = new HLiteralList(elements, backend.extendableArrayType);
       add(listInstruction);
-      listInstruction = setRtiIfNeeded(listInstruction, listLiteral);
+      listInstruction =
+          setListRuntimeTypeInfoIfNeeded(listInstruction, listLiteral);
     }
 
     TypeMask type = astAdapter.typeOfNewList(targetElement, listLiteral);
@@ -783,8 +807,52 @@
       inputs.add(argList);
     }
 
-    // TODO(het): Add type information
-    _pushStaticInvocation(constructor, inputs, backend.dynamicType);
+    assert(constructor.kind == ir.ProcedureKind.Factory);
+
+    InterfaceType type = localsHandler
+        .substInContext(elements.getType(astAdapter.getNode(mapLiteral)));
+
+    ir.Class cls = constructor.enclosingClass;
+
+    if (backend.classNeedsRti(astAdapter.getElement(cls))) {
+      List<HInstruction> typeInputs = <HInstruction>[];
+      type.typeArguments.forEach((DartType argument) {
+        typeInputs
+            .add(typeBuilder.analyzeTypeArgument(argument, sourceElement));
+      });
+
+      // We lift this common call pattern into a helper function to save space
+      // in the output.
+      if (typeInputs.every((HInstruction input) => input.isNull())) {
+        if (constructorArgs.isEmpty) {
+          constructor = astAdapter.mapLiteralUntypedEmptyMaker;
+        } else {
+          constructor = astAdapter.mapLiteralUntypedMaker;
+        }
+      } else {
+        inputs.addAll(typeInputs);
+      }
+    }
+
+    // If runtime type information is needed and the map literal has no type
+    // parameters, 'constructor' is a static function that forwards the call to
+    // the factory constructor without type parameters.
+    assert(constructor.kind == ir.ProcedureKind.Factory);
+
+    // The instruction type will always be a subtype of the mapLiteralClass, but
+    // type inference might discover a more specific type, or find nothing (in
+    // dart2js unit tests).
+    TypeMask mapType = new TypeMask.nonNullSubtype(
+        astAdapter.getElement(astAdapter.mapLiteralClass),
+        compiler.closedWorld);
+    TypeMask returnTypeMask = TypeMaskFactory.inferredReturnTypeForElement(
+        astAdapter.getElement(constructor), compiler);
+    TypeMask instructionType =
+        mapType.intersection(returnTypeMask, compiler.closedWorld);
+
+    addImplicitInstantiation(type);
+    _pushStaticInvocation(constructor, inputs, instructionType);
+    removeImplicitInstantiation(type);
   }
 
   @override
@@ -914,9 +982,13 @@
 
   void _pushStaticInvocation(
       ir.Node target, List<HInstruction> arguments, TypeMask typeMask) {
-    HInstruction instruction = new HInvokeStatic(
+    HInvokeStatic instruction = new HInvokeStatic(
         astAdapter.getMember(target), arguments, typeMask,
         targetCanThrow: astAdapter.getCanThrow(target));
+    if (currentImplicitInstantiations.isNotEmpty) {
+      instruction.instantiatedTypes =
+          new List<DartType>.from(currentImplicitInstantiations);
+    }
     instruction.sideEffects = astAdapter.getSideEffects(target);
 
     push(instruction);
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index c882259..cd9d7c0 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'dart:math' as math;
 import '../common.dart';
 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem;
 import '../common/tasks.dart' show CompilerTask;
@@ -210,8 +211,59 @@
     return false;
   }
 
+  // Returns the number of bits occupied by the value computed by [instruction].
+  // Returns `32` if the value is negative or does not fit in a smaller number
+  // of bits.
+  int bitWidth(HInstruction instruction) {
+    const int MAX = 32;
+    int constant(HInstruction insn) {
+      if (insn is HConstant && insn.isConstantInteger()) {
+        IntConstantValue constant = insn.constant;
+        return constant.primitiveValue;
+      }
+      return null;
+    }
+
+    if (instruction.isConstantInteger()) {
+      int value = constant(instruction);
+      if (value < 0) return MAX;
+      if (value > ((1 << 31) - 1)) return MAX;
+      return value.bitLength;
+    }
+    if (instruction is HBitAnd) {
+      return math.min(bitWidth(instruction.left), bitWidth(instruction.right));
+    }
+    if (instruction is HBitOr || instruction is HBitXor) {
+      HBinaryBitOp bitOp = instruction;
+      int leftWidth = bitWidth(bitOp.left);
+      if (leftWidth == MAX) return MAX;
+      return math.max(leftWidth, bitWidth(bitOp.right));
+    }
+    if (instruction is HShiftLeft) {
+      int shiftCount = constant(instruction.right);
+      if (shiftCount == null || shiftCount < 0 || shiftCount > 31) return MAX;
+      int leftWidth = bitWidth(instruction.left);
+      int width = leftWidth + shiftCount;
+      return math.min(width, MAX);
+    }
+    if (instruction is HShiftRight) {
+      int shiftCount = constant(instruction.right);
+      if (shiftCount == null || shiftCount < 0 || shiftCount > 31) return MAX;
+      int leftWidth = bitWidth(instruction.left);
+      if (leftWidth >= MAX) return MAX;
+      return math.max(leftWidth - shiftCount, 0);
+    }
+    if (instruction is HAdd) {
+      return math.min(
+          1 + math.max(bitWidth(instruction.left), bitWidth(instruction.right)),
+          MAX);
+    }
+    return MAX;
+  }
+
   bool requiresUintConversion(instruction) {
     if (instruction.isUInt31(compiler)) return false;
+    if (bitWidth(instruction) <= 31) return false;
     // If the result of a bit-operation is only used by other bit
     // operations, we do not have to convert to an unsigned integer.
     return hasNonBitOpUser(instruction, new Set<HPhi>());
diff --git a/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart b/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
index 4db25e9..cf58dce 100644
--- a/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
+++ b/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
@@ -263,12 +263,21 @@
   JumpTarget getTargetDefinition(ir.Node node) =>
       elements.getTargetDefinition(getNode(node));
 
+  ir.Class get mapLiteralClass =>
+      kernel.classes[_backend.helpers.mapLiteralClass];
+
   ir.Procedure get mapLiteralConstructor =>
       kernel.functions[_backend.helpers.mapLiteralConstructor];
 
   ir.Procedure get mapLiteralConstructorEmpty =>
       kernel.functions[_backend.helpers.mapLiteralConstructorEmpty];
 
+  ir.Procedure get mapLiteralUntypedEmptyMaker =>
+      kernel.functions[_backend.helpers.mapLiteralUntypedEmptyMaker];
+
+  ir.Procedure get mapLiteralUntypedMaker =>
+      kernel.functions[_backend.helpers.mapLiteralUntypedMaker];
+
   MemberElement get jsIndexableLength => _backend.helpers.jsIndexableLength;
 
   ir.Procedure get checkConcurrentModificationError =>
diff --git a/pkg/compiler/lib/src/ssa/kernel_string_builder.dart b/pkg/compiler/lib/src/ssa/kernel_string_builder.dart
index 21da2e4..38a3f63 100644
--- a/pkg/compiler/lib/src/ssa/kernel_string_builder.dart
+++ b/pkg/compiler/lib/src/ssa/kernel_string_builder.dart
@@ -43,9 +43,10 @@
       return;
     }
 
-    // TODO(het): If toString method is guaranteed to return a string, then call
-    // it directly instead of stringify. Or, better yet, do this later in the
-    // optimization phase.
+    // TODO(efortuna): If we decide to do inlining before finishing constructing
+    // the control flow graph, we'd want to do the optimization of
+    // calling toString here if the type is provably a string rather than in the
+    // optimization phase (which is where we currently do it).
 
     append(stringify(expression));
   }
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 5f11f1d..de90a81 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -814,7 +814,7 @@
         return node;
       }
       if (type.isFunctionType) {
-        HInstruction input = node.checkedInput; 
+        HInstruction input = node.checkedInput;
         // `null` always passes type conversion.
         if (input.isNull()) return input;
         // TODO(johnniwinther): Optimize function type conversions.
diff --git a/pkg/compiler/lib/src/universe/use.dart b/pkg/compiler/lib/src/universe/use.dart
index 5876a18..ce9a2c4 100644
--- a/pkg/compiler/lib/src/universe/use.dart
+++ b/pkg/compiler/lib/src/universe/use.dart
@@ -73,6 +73,7 @@
   CLOSURE,
   CONSTRUCTOR_INVOKE,
   CONST_CONSTRUCTOR_INVOKE,
+  REDIRECTION,
   DIRECT_INVOKE,
 }
 
@@ -266,9 +267,12 @@
         element, StaticUseKind.CONST_CONSTRUCTOR_INVOKE, type);
   }
 
-  /// Constructor redirection to [element].
-  factory StaticUse.constructorRedirect(ConstructorElement element) {
-    return new StaticUse.internal(element, StaticUseKind.GENERAL);
+  /// Constructor redirection to [element] on [type].
+  factory StaticUse.constructorRedirect(
+      ConstructorElement element, InterfaceType type) {
+    assert(invariant(element, type != null,
+        message: "No type provided for constructor invocation."));
+    return new StaticUse.internal(element, StaticUseKind.REDIRECTION, type);
   }
 
   /// Initialization of an instance field [element].
diff --git a/pkg/compiler/lib/src/universe/world_builder.dart b/pkg/compiler/lib/src/universe/world_builder.dart
index fa4108a..afcd031 100644
--- a/pkg/compiler/lib/src/universe/world_builder.dart
+++ b/pkg/compiler/lib/src/universe/world_builder.dart
@@ -14,9 +14,7 @@
 import '../core_types.dart' show CoreClasses;
 import '../dart_types.dart';
 import '../elements/elements.dart';
-import '../types/masks.dart' show CommonMasks;
 import '../universe/class_set.dart' show Instantiation;
-import '../util/enumset.dart';
 import '../util/util.dart';
 import '../world.dart' show World, ClosedWorld, OpenWorld, WorldImpl;
 import 'selector.dart' show Selector;
@@ -164,9 +162,10 @@
   /// Set of all fields that are statically known to be written to.
   Iterable<Element> get fieldSetters;
 
-  /// Call [f] for all directly or abstractly instantiated classes.
-  void forEachInstantiatedClass(
-      f(ClassElement cls, EnumSet<Instantiation> instantiations));
+  /// Call [f] for all classes with instantiated types. This includes the
+  /// directly and abstractly instantiated classes but also classes whose type
+  /// arguments are used in live factory constructors.
+  void forEachInstantiatedClass(f(ClassElement cls, InstantiationInfo info));
 
   /// `true` of `Object.runtimeType` is supported.
   bool get hasRuntimeTypeSupport;
@@ -182,22 +181,172 @@
   OpenWorld get openWorld;
 }
 
+/// The type and kind of an instantiation registered through
+/// `ResolutionWorldBuilder.registerTypeInstantiation`.
+class Instance {
+  final InterfaceType type;
+  final Instantiation kind;
+  final bool isRedirection;
+
+  Instance(this.type, this.kind, {this.isRedirection: false});
+
+  int get hashCode {
+    return Hashing.objectHash(
+        type, Hashing.objectHash(kind, Hashing.objectHash(isRedirection)));
+  }
+
+  bool operator ==(other) {
+    if (identical(this, other)) return true;
+    if (other is! Instance) return false;
+    return type == other.type &&
+        kind == other.kind &&
+        isRedirection == other.isRedirection;
+  }
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.write(type);
+    if (kind == Instantiation.DIRECTLY_INSTANTIATED) {
+      sb.write(' directly');
+    } else if (kind == Instantiation.ABSTRACTLY_INSTANTIATED) {
+      sb.write(' abstractly');
+    } else if (kind == Instantiation.UNINSTANTIATED) {
+      sb.write(' none');
+    }
+    if (isRedirection) {
+      sb.write(' redirect');
+    }
+    return sb.toString();
+  }
+}
+
+/// Information about instantiations of a class.
+class InstantiationInfo {
+  /// A map from constructor of the class to their instantiated types.
+  ///
+  /// For instance
+  ///
+  ///    import 'dart:html';
+  ///
+  ///    abstract class AbstractClass<S> {
+  ///      factory AbstractClass.a() = Class<S>.a;
+  ///      factory AbstractClass.b() => new Class<S>.b();
+  ///    }
+  ///    class Class<T> implements AbstractClass<T> {
+  ///      Class.a();
+  ///      Class.b();
+  ///      factory Class.c() = Class.b<T>;
+  ///    }
+  ///
+  ///
+  ///    main() {
+  ///      new Class.a();
+  ///      new Class<int>.a();
+  ///      new Class<String>.b();
+  ///      new Class<num>.c();
+  ///      new AbstractClass<double>.a();
+  ///      new AbstractClass<bool>.b();
+  ///      new DivElement(); // native instantiation
+  ///    }
+  ///
+  /// will generate the mappings
+  ///
+  ///    AbstractClass: {
+  ///      AbstractClass.a: {
+  ///        AbstractClass<double> none, // from `new AbstractClass<double>.a()`
+  ///      },
+  ///      AbstractClass.b: {
+  ///        AbstractClass<bool> none, // from `new AbstractClass<bool>.b()`
+  ///      },
+  ///    },
+  ///    Class: {
+  ///      Class.a: {
+  ///        Class directly, // from `new Class.a()`
+  ///        Class<int> directly, // from `new Class<int>.a()`
+  ///        Class<S> directly redirect, // from `factory AbstractClass.a`
+  ///      },
+  ///      Class.b: {
+  ///        Class<String> directly, // from `new Class<String>.b()`
+  ///        Class<T> directly redirect, // from `factory Class.c`
+  ///        Class<S> directly, // from `factory AbstractClass.b`
+  ///      },
+  ///      Class.c: {
+  ///        Class<num> directly, // from `new Class<num>.c()`
+  ///      },
+  ///    },
+  ///    DivElement: {
+  ///      DivElement: {
+  ///        DivElement abstractly, // from `new DivElement()`
+  ///      },
+  ///    }
+  ///
+  /// If the constructor is unknown, for instance for native or mirror usage,
+  /// `null` is used as key.
+  Map<ConstructorElement, Set<Instance>> instantiationMap;
+
+  /// Register [type] as the instantiation [kind] using [constructor].
+  void addInstantiation(
+      ConstructorElement constructor, InterfaceType type, Instantiation kind,
+      {bool isRedirection: false}) {
+    instantiationMap ??= <ConstructorElement, Set<Instance>>{};
+    instantiationMap
+        .putIfAbsent(constructor, () => new Set<Instance>())
+        .add(new Instance(type, kind, isRedirection: isRedirection));
+    switch (kind) {
+      case Instantiation.DIRECTLY_INSTANTIATED:
+        isDirectlyInstantiated = true;
+        break;
+      case Instantiation.ABSTRACTLY_INSTANTIATED:
+        isAbstractlyInstantiated = true;
+        break;
+      case Instantiation.UNINSTANTIATED:
+        break;
+      default:
+        throw new StateError("Instantiation $kind is not allowed.");
+    }
+  }
+
+  /// `true` if the class is either directly or abstractly instantiated.
+  bool get hasInstantiation =>
+      isDirectlyInstantiated || isAbstractlyInstantiated;
+
+  /// `true` if the class is directly instantiated.
+  bool isDirectlyInstantiated = false;
+
+  /// `true` if the class is abstractly instantiated.
+  bool isAbstractlyInstantiated = false;
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.write('InstantiationInfo[');
+    if (instantiationMap != null) {
+      bool needsComma = false;
+      instantiationMap
+          .forEach((ConstructorElement constructor, Set<Instance> set) {
+        if (needsComma) {
+          sb.write(', ');
+        }
+        if (constructor != null) {
+          sb.write(constructor);
+        } else {
+          sb.write('<unknown>');
+        }
+        sb.write(': ');
+        sb.write(set);
+        needsComma = true;
+      });
+    }
+    sb.write(']');
+    return sb.toString();
+  }
+}
+
 class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
-  /// The set of all directly instantiated classes, that is, classes with a
-  /// generative constructor that has been called directly and not only through
-  /// a super-call.
+  /// Instantiation information for all classes with instantiated types.
   ///
   /// Invariant: Elements are declaration elements.
-  // TODO(johnniwinther): [_directlyInstantiatedClasses] and
-  // [_instantiatedTypes] sets should be merged.
-  final Map<ClassElement, EnumSet<Instantiation>> _directlyInstantiatedClasses =
-      <ClassElement, EnumSet<Instantiation>>{};
-
-  /// The set of all directly instantiated types, that is, the types of the
-  /// directly instantiated classes.
-  ///
-  /// See [_directlyInstantiatedClasses].
-  final Set<DartType> _instantiatedTypes = new Set<DartType>();
+  final Map<ClassElement, InstantiationInfo> _instantiationInfo =
+      <ClassElement, InstantiationInfo>{};
 
   /// Classes implemented by directly instantiated classes.
   final Set<ClassElement> _implementedClasses = new Set<ClassElement>();
@@ -258,6 +407,10 @@
   bool hasIsolateSupport = false;
   bool hasFunctionApplySupport = false;
 
+  /// Used for testing the new more precise computation of instantiated types
+  /// and classes.
+  bool useInstantiationMap = false;
+
   OpenWorld _openWorld;
 
   ResolutionWorldBuilderImpl(Backend backend, CoreClasses coreClasses,
@@ -272,7 +425,13 @@
   /// super-call.
   // TODO(johnniwinther): Improve semantic precision.
   Iterable<ClassElement> get directlyInstantiatedClasses {
-    return _directlyInstantiatedClasses.keys;
+    Set<ClassElement> classes = new Set<ClassElement>();
+    getInstantiationMap().forEach((ClassElement cls, InstantiationInfo info) {
+      if (info.hasInstantiation) {
+        classes.add(cls);
+      }
+    });
+    return classes;
   }
 
   /// All directly instantiated types, that is, the types of the directly
@@ -280,7 +439,19 @@
   ///
   /// See [directlyInstantiatedClasses].
   // TODO(johnniwinther): Improve semantic precision.
-  Iterable<DartType> get instantiatedTypes => _instantiatedTypes;
+  Iterable<DartType> get instantiatedTypes {
+    Set<InterfaceType> types = new Set<InterfaceType>();
+    getInstantiationMap().forEach((_, InstantiationInfo info) {
+      if (info.instantiationMap != null) {
+        for (Set<Instance> instances in info.instantiationMap.values) {
+          for (Instance instance in instances) {
+            types.add(instance.type);
+          }
+        }
+      }
+    });
+    return types;
+  }
 
   /// Returns `true` if [cls] is considered to be implemented by an
   /// instantiated class, either directly, through subclasses or through
@@ -298,11 +469,15 @@
   // subclass and through subtype instantiated types/classes.
   // TODO(johnniwinther): Support unknown type arguments for generic types.
   void registerTypeInstantiation(InterfaceType type,
-      {bool byMirrors: false,
+      {ConstructorElement constructor,
+      bool byMirrors: false,
       bool isNative: false,
+      bool isRedirection: false,
       void onImplemented(ClassElement cls)}) {
-    _instantiatedTypes.add(type);
     ClassElement cls = type.element;
+    InstantiationInfo info =
+        _instantiationInfo.putIfAbsent(cls, () => new InstantiationInfo());
+    Instantiation kind = Instantiation.UNINSTANTIATED;
     if (!cls.isAbstract
         // We can't use the closed-world assumption with native abstract
         // classes; a native abstract class may have non-abstract subclasses
@@ -315,17 +490,17 @@
         // TODO(herhut): Track classes required by mirrors seperately.
         ||
         byMirrors) {
-      EnumSet<Instantiation> instantiations = _directlyInstantiatedClasses
-          .putIfAbsent(cls, () => new EnumSet<Instantiation>());
       if (isNative || byMirrors) {
-        instantiations.add(Instantiation.ABSTRACTLY_INSTANTIATED);
+        kind = Instantiation.ABSTRACTLY_INSTANTIATED;
       } else {
-        instantiations.add(Instantiation.DIRECTLY_INSTANTIATED);
+        kind = Instantiation.DIRECTLY_INSTANTIATED;
       }
     }
+    info.addInstantiation(constructor, type, kind,
+        isRedirection: isRedirection);
 
-    // TODO(johnniwinther): Replace this by separate more specific mappings that
-    // include the type arguments.
+    // TODO(johnniwinther): Use [_instantiationInfo] to compute this information
+    // instead.
     if (_implementedClasses.add(cls)) {
       onImplemented(cls);
       cls.allSupertypes.forEach((InterfaceType supertype) {
@@ -337,9 +512,8 @@
   }
 
   @override
-  void forEachInstantiatedClass(
-      f(ClassElement cls, EnumSet<Instantiation> instantiations)) {
-    _directlyInstantiatedClasses.forEach(f);
+  void forEachInstantiatedClass(f(ClassElement cls, InstantiationInfo info)) {
+    getInstantiationMap().forEach(f);
   }
 
   bool _hasMatchingSelector(Map<Selector, SelectorConstraints> selectors,
@@ -356,6 +530,50 @@
     return false;
   }
 
+  /// Returns the instantiation map used for computing the closed world.
+  ///
+  /// If [useInstantiationMap] is `true`, redirections are removed and
+  /// redirecting factories are converted to their effective target and type.
+  Map<ClassElement, InstantiationInfo> getInstantiationMap() {
+    if (!useInstantiationMap) return _instantiationInfo;
+
+    Map<ClassElement, InstantiationInfo> instantiationMap =
+        <ClassElement, InstantiationInfo>{};
+
+    InstantiationInfo infoFor(ClassElement cls) {
+      return instantiationMap.putIfAbsent(cls, () => new InstantiationInfo());
+    }
+
+    _instantiationInfo.forEach((cls, info) {
+      if (info.instantiationMap != null) {
+        info.instantiationMap
+            .forEach((ConstructorElement constructor, Set<Instance> set) {
+          for (Instance instance in set) {
+            if (instance.isRedirection) {
+              continue;
+            }
+            if (constructor == null || !constructor.isRedirectingFactory) {
+              infoFor(cls)
+                  .addInstantiation(constructor, instance.type, instance.kind);
+            } else {
+              ConstructorElement target = constructor.effectiveTarget;
+              InterfaceType targetType =
+                  constructor.computeEffectiveTargetType(instance.type);
+              Instantiation kind = Instantiation.DIRECTLY_INSTANTIATED;
+              if (target.enclosingClass.isAbstract) {
+                // If target is a factory constructor on an abstract class.
+                kind = Instantiation.UNINSTANTIATED;
+              }
+              infoFor(targetType.element)
+                  .addInstantiation(target, targetType, kind);
+            }
+          }
+        });
+      }
+    });
+    return instantiationMap;
+  }
+
   bool hasInvocation(Element member, OpenWorld world) {
     return _hasMatchingSelector(_invokedNames[member.name], member, world);
   }
@@ -422,6 +640,7 @@
       case StaticUseKind.FIELD_GET:
       case StaticUseKind.CONSTRUCTOR_INVOKE:
       case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
+      case StaticUseKind.REDIRECTION:
         break;
       case StaticUseKind.CLOSURE:
         allClosures.add(element);
@@ -438,12 +657,7 @@
     slowDirectlyNestedClosures(element).forEach(compiler.forgetElement);
     closurizedMembers.remove(element);
     fieldSetters.remove(element);
-    _directlyInstantiatedClasses.remove(element);
-    if (element is ClassElement) {
-      assert(invariant(element, element.thisType.isRaw,
-          message: 'Generic classes not supported (${element.thisType}).'));
-      _instantiatedTypes..remove(element.rawType)..remove(element.thisType);
-    }
+    _instantiationInfo.remove(element);
   }
 
   // TODO(ahe): Replace this method with something that is O(1), for example,
@@ -701,6 +915,7 @@
       case StaticUseKind.FIELD_GET:
       case StaticUseKind.CONSTRUCTOR_INVOKE:
       case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
+      case StaticUseKind.REDIRECTION:
       case StaticUseKind.DIRECT_INVOKE:
         break;
     }
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index dd786a4..c406d07 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -25,8 +25,8 @@
 import 'universe/function_set.dart' show FunctionSet;
 import 'universe/selector.dart' show Selector;
 import 'universe/side_effects.dart' show SideEffects;
-import 'universe/world_builder.dart' show ResolutionWorldBuilder;
-import 'util/enumset.dart';
+import 'universe/world_builder.dart'
+    show InstantiationInfo, ResolutionWorldBuilder;
 import 'util/util.dart' show Link;
 
 /// Common superinterface for [OpenWorld] and [ClosedWorld].
@@ -1007,7 +1007,10 @@
     /// Updates the `isDirectlyInstantiated` and `isIndirectlyInstantiated`
     /// properties of the [ClassHierarchyNode] for [cls].
 
-    void addSubtypes(ClassElement cls, EnumSet<Instantiation> instantiations) {
+    void addSubtypes(ClassElement cls, InstantiationInfo info) {
+      if (!info.hasInstantiation) {
+        return;
+      }
       if (cacheStrategy.hasIncrementalSupport && !alreadyPopulated.add(cls)) {
         return;
       }
@@ -1017,10 +1020,8 @@
       }
 
       _updateClassHierarchyNodeForClass(cls,
-          directlyInstantiated:
-              instantiations.contains(Instantiation.DIRECTLY_INSTANTIATED),
-          abstractlyInstantiated:
-              instantiations.contains(Instantiation.ABSTRACTLY_INSTANTIATED));
+          directlyInstantiated: info.isDirectlyInstantiated,
+          abstractlyInstantiated: info.isAbstractlyInstantiated);
 
       // Walk through the superclasses, and record the types
       // implemented by that type on the superclasses.
diff --git a/pkg/dev_compiler/lib/js/amd/dart_sdk.js b/pkg/dev_compiler/lib/js/amd/dart_sdk.js
index c2cb697..2ed8598 100644
--- a/pkg/dev_compiler/lib/js/amd/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/amd/dart_sdk.js
@@ -797,43 +797,48 @@
     }
     return flatten;
   };
-  dart.generic = function(typeConstructor) {
-    let length = typeConstructor.length;
-    if (length < 1) {
-      dart.throwInternalError('must have at least one generic type argument');
-    }
-    let resultMap = new Map();
-    function makeGenericType(...args) {
-      if (args.length != length && args.length != 0) {
-        dart.throwInternalError('requires ' + length + ' or 0 type arguments');
+  dart.generic = function(typeConstructor, setBaseClass) {
+    if (setBaseClass === void 0) setBaseClass = null;
+    return (() => {
+      let length = typeConstructor.length;
+      if (length < 1) {
+        dart.throwInternalError('must have at least one generic type argument');
       }
-      while (args.length < length)
-        args.push(dart.dynamic);
-      let value = resultMap;
-      for (let i = 0; i < length; i++) {
-        let arg = args[i];
-        if (arg == null) {
-          dart.throwInternalError('type arguments should not be null: ' + typeConstructor);
+      let resultMap = new Map();
+      function makeGenericType(...args) {
+        if (args.length != length && args.length != 0) {
+          dart.throwInternalError('requires ' + length + ' or 0 type arguments');
         }
-        let map = value;
-        value = map.get(arg);
-        if (value === void 0) {
-          if (i + 1 == length) {
-            value = typeConstructor.apply(null, args);
-            if (value) {
-              value[dart._typeArguments] = args;
-              value[dart._originalDeclaration] = makeGenericType;
-            }
-          } else {
-            value = new Map();
+        while (args.length < length)
+          args.push(dart.dynamic);
+        let value = resultMap;
+        for (let i = 0; i < length; i++) {
+          let arg = args[i];
+          if (arg == null) {
+            dart.throwInternalError('type arguments should not be null: ' + typeConstructor);
           }
-          map.set(arg, value);
+          let map = value;
+          value = map.get(arg);
+          if (value === void 0) {
+            if (i + 1 == length) {
+              value = typeConstructor.apply(null, args);
+              if (value) {
+                value[dart._typeArguments] = args;
+                value[dart._originalDeclaration] = makeGenericType;
+              }
+              map.set(arg, value);
+              if (setBaseClass) setBaseClass(value);
+            } else {
+              value = new Map();
+              map.set(arg, value);
+            }
+          }
         }
+        return value;
       }
-      return value;
-    }
-    makeGenericType[dart._genericTypeCtor] = typeConstructor;
-    return makeGenericType;
+      makeGenericType[dart._genericTypeCtor] = typeConstructor;
+      return makeGenericType;
+    })();
   };
   dart.getGenericClass = function(type) {
     return dart.safeGetOwnProperty(type, dart._originalDeclaration);
@@ -26760,7 +26765,6 @@
         return this[_nextLink];
       }
     }
-    dart.setBaseClass(_UserDoubleLinkedQueueEntry, collection._DoubleLink$(_UserDoubleLinkedQueueEntry));
     _UserDoubleLinkedQueueEntry[dart.implements] = () => [DoubleLinkedQueueEntryOfE()];
     dart.setSignature(_UserDoubleLinkedQueueEntry, {
       constructors: () => ({new: dart.definiteFunctionType(collection._UserDoubleLinkedQueueEntry$(E), [E])}),
@@ -26774,6 +26778,8 @@
       })
     });
     return _UserDoubleLinkedQueueEntry;
+  }, _UserDoubleLinkedQueueEntry => {
+    dart.setBaseClass(_UserDoubleLinkedQueueEntry, collection._DoubleLink$(_UserDoubleLinkedQueueEntry));
   });
   collection._UserDoubleLinkedQueueEntry = _UserDoubleLinkedQueueEntry();
   const _queue = Symbol('_queue');
@@ -26803,7 +26809,6 @@
         return this[_previousLink][_asNonSentinelEntry]();
       }
     }
-    dart.setBaseClass(_DoubleLinkedQueueEntry, collection._DoubleLink$(_DoubleLinkedQueueEntry));
     dart.setSignature(_DoubleLinkedQueueEntry, {
       constructors: () => ({new: dart.definiteFunctionType(collection._DoubleLinkedQueueEntry$(E), [DoubleLinkedQueueOfE()])}),
       fields: () => ({[_queue]: DoubleLinkedQueueOfE()}),
@@ -26815,6 +26820,8 @@
       })
     });
     return _DoubleLinkedQueueEntry;
+  }, _DoubleLinkedQueueEntry => {
+    dart.setBaseClass(_DoubleLinkedQueueEntry, collection._DoubleLink$(_DoubleLinkedQueueEntry));
   });
   collection._DoubleLinkedQueueEntry = _DoubleLinkedQueueEntry();
   const _elementCount = Symbol('_elementCount');
diff --git a/pkg/dev_compiler/lib/js/common/dart_sdk.js b/pkg/dev_compiler/lib/js/common/dart_sdk.js
index 78f09d2..f853c40 100644
--- a/pkg/dev_compiler/lib/js/common/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/common/dart_sdk.js
@@ -797,43 +797,48 @@
     }
     return flatten;
   };
-  dart.generic = function(typeConstructor) {
-    let length = typeConstructor.length;
-    if (length < 1) {
-      dart.throwInternalError('must have at least one generic type argument');
-    }
-    let resultMap = new Map();
-    function makeGenericType(...args) {
-      if (args.length != length && args.length != 0) {
-        dart.throwInternalError('requires ' + length + ' or 0 type arguments');
+  dart.generic = function(typeConstructor, setBaseClass) {
+    if (setBaseClass === void 0) setBaseClass = null;
+    return (() => {
+      let length = typeConstructor.length;
+      if (length < 1) {
+        dart.throwInternalError('must have at least one generic type argument');
       }
-      while (args.length < length)
-        args.push(dart.dynamic);
-      let value = resultMap;
-      for (let i = 0; i < length; i++) {
-        let arg = args[i];
-        if (arg == null) {
-          dart.throwInternalError('type arguments should not be null: ' + typeConstructor);
+      let resultMap = new Map();
+      function makeGenericType(...args) {
+        if (args.length != length && args.length != 0) {
+          dart.throwInternalError('requires ' + length + ' or 0 type arguments');
         }
-        let map = value;
-        value = map.get(arg);
-        if (value === void 0) {
-          if (i + 1 == length) {
-            value = typeConstructor.apply(null, args);
-            if (value) {
-              value[dart._typeArguments] = args;
-              value[dart._originalDeclaration] = makeGenericType;
-            }
-          } else {
-            value = new Map();
+        while (args.length < length)
+          args.push(dart.dynamic);
+        let value = resultMap;
+        for (let i = 0; i < length; i++) {
+          let arg = args[i];
+          if (arg == null) {
+            dart.throwInternalError('type arguments should not be null: ' + typeConstructor);
           }
-          map.set(arg, value);
+          let map = value;
+          value = map.get(arg);
+          if (value === void 0) {
+            if (i + 1 == length) {
+              value = typeConstructor.apply(null, args);
+              if (value) {
+                value[dart._typeArguments] = args;
+                value[dart._originalDeclaration] = makeGenericType;
+              }
+              map.set(arg, value);
+              if (setBaseClass) setBaseClass(value);
+            } else {
+              value = new Map();
+              map.set(arg, value);
+            }
+          }
         }
+        return value;
       }
-      return value;
-    }
-    makeGenericType[dart._genericTypeCtor] = typeConstructor;
-    return makeGenericType;
+      makeGenericType[dart._genericTypeCtor] = typeConstructor;
+      return makeGenericType;
+    })();
   };
   dart.getGenericClass = function(type) {
     return dart.safeGetOwnProperty(type, dart._originalDeclaration);
@@ -26760,7 +26765,6 @@
         return this[_nextLink];
       }
     }
-    dart.setBaseClass(_UserDoubleLinkedQueueEntry, collection._DoubleLink$(_UserDoubleLinkedQueueEntry));
     _UserDoubleLinkedQueueEntry[dart.implements] = () => [DoubleLinkedQueueEntryOfE()];
     dart.setSignature(_UserDoubleLinkedQueueEntry, {
       constructors: () => ({new: dart.definiteFunctionType(collection._UserDoubleLinkedQueueEntry$(E), [E])}),
@@ -26774,6 +26778,8 @@
       })
     });
     return _UserDoubleLinkedQueueEntry;
+  }, _UserDoubleLinkedQueueEntry => {
+    dart.setBaseClass(_UserDoubleLinkedQueueEntry, collection._DoubleLink$(_UserDoubleLinkedQueueEntry));
   });
   collection._UserDoubleLinkedQueueEntry = _UserDoubleLinkedQueueEntry();
   const _queue = Symbol('_queue');
@@ -26803,7 +26809,6 @@
         return this[_previousLink][_asNonSentinelEntry]();
       }
     }
-    dart.setBaseClass(_DoubleLinkedQueueEntry, collection._DoubleLink$(_DoubleLinkedQueueEntry));
     dart.setSignature(_DoubleLinkedQueueEntry, {
       constructors: () => ({new: dart.definiteFunctionType(collection._DoubleLinkedQueueEntry$(E), [DoubleLinkedQueueOfE()])}),
       fields: () => ({[_queue]: DoubleLinkedQueueOfE()}),
@@ -26815,6 +26820,8 @@
       })
     });
     return _DoubleLinkedQueueEntry;
+  }, _DoubleLinkedQueueEntry => {
+    dart.setBaseClass(_DoubleLinkedQueueEntry, collection._DoubleLink$(_DoubleLinkedQueueEntry));
   });
   collection._DoubleLinkedQueueEntry = _DoubleLinkedQueueEntry();
   const _elementCount = Symbol('_elementCount');
diff --git a/pkg/dev_compiler/lib/js/es6/dart_sdk.js b/pkg/dev_compiler/lib/js/es6/dart_sdk.js
index c16638f..bb1cb35 100644
--- a/pkg/dev_compiler/lib/js/es6/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/es6/dart_sdk.js
@@ -795,43 +795,48 @@
   }
   return flatten;
 };
-dart.generic = function(typeConstructor) {
-  let length = typeConstructor.length;
-  if (length < 1) {
-    dart.throwInternalError('must have at least one generic type argument');
-  }
-  let resultMap = new Map();
-  function makeGenericType(...args) {
-    if (args.length != length && args.length != 0) {
-      dart.throwInternalError('requires ' + length + ' or 0 type arguments');
+dart.generic = function(typeConstructor, setBaseClass) {
+  if (setBaseClass === void 0) setBaseClass = null;
+  return (() => {
+    let length = typeConstructor.length;
+    if (length < 1) {
+      dart.throwInternalError('must have at least one generic type argument');
     }
-    while (args.length < length)
-      args.push(dart.dynamic);
-    let value = resultMap;
-    for (let i = 0; i < length; i++) {
-      let arg = args[i];
-      if (arg == null) {
-        dart.throwInternalError('type arguments should not be null: ' + typeConstructor);
+    let resultMap = new Map();
+    function makeGenericType(...args) {
+      if (args.length != length && args.length != 0) {
+        dart.throwInternalError('requires ' + length + ' or 0 type arguments');
       }
-      let map = value;
-      value = map.get(arg);
-      if (value === void 0) {
-        if (i + 1 == length) {
-          value = typeConstructor.apply(null, args);
-          if (value) {
-            value[dart._typeArguments] = args;
-            value[dart._originalDeclaration] = makeGenericType;
-          }
-        } else {
-          value = new Map();
+      while (args.length < length)
+        args.push(dart.dynamic);
+      let value = resultMap;
+      for (let i = 0; i < length; i++) {
+        let arg = args[i];
+        if (arg == null) {
+          dart.throwInternalError('type arguments should not be null: ' + typeConstructor);
         }
-        map.set(arg, value);
+        let map = value;
+        value = map.get(arg);
+        if (value === void 0) {
+          if (i + 1 == length) {
+            value = typeConstructor.apply(null, args);
+            if (value) {
+              value[dart._typeArguments] = args;
+              value[dart._originalDeclaration] = makeGenericType;
+            }
+            map.set(arg, value);
+            if (setBaseClass) setBaseClass(value);
+          } else {
+            value = new Map();
+            map.set(arg, value);
+          }
+        }
       }
+      return value;
     }
-    return value;
-  }
-  makeGenericType[dart._genericTypeCtor] = typeConstructor;
-  return makeGenericType;
+    makeGenericType[dart._genericTypeCtor] = typeConstructor;
+    return makeGenericType;
+  })();
 };
 dart.getGenericClass = function(type) {
   return dart.safeGetOwnProperty(type, dart._originalDeclaration);
@@ -26758,7 +26763,6 @@
       return this[_nextLink];
     }
   }
-  dart.setBaseClass(_UserDoubleLinkedQueueEntry, collection._DoubleLink$(_UserDoubleLinkedQueueEntry));
   _UserDoubleLinkedQueueEntry[dart.implements] = () => [DoubleLinkedQueueEntryOfE()];
   dart.setSignature(_UserDoubleLinkedQueueEntry, {
     constructors: () => ({new: dart.definiteFunctionType(collection._UserDoubleLinkedQueueEntry$(E), [E])}),
@@ -26772,6 +26776,8 @@
     })
   });
   return _UserDoubleLinkedQueueEntry;
+}, _UserDoubleLinkedQueueEntry => {
+  dart.setBaseClass(_UserDoubleLinkedQueueEntry, collection._DoubleLink$(_UserDoubleLinkedQueueEntry));
 });
 collection._UserDoubleLinkedQueueEntry = _UserDoubleLinkedQueueEntry();
 const _queue = Symbol('_queue');
@@ -26801,7 +26807,6 @@
       return this[_previousLink][_asNonSentinelEntry]();
     }
   }
-  dart.setBaseClass(_DoubleLinkedQueueEntry, collection._DoubleLink$(_DoubleLinkedQueueEntry));
   dart.setSignature(_DoubleLinkedQueueEntry, {
     constructors: () => ({new: dart.definiteFunctionType(collection._DoubleLinkedQueueEntry$(E), [DoubleLinkedQueueOfE()])}),
     fields: () => ({[_queue]: DoubleLinkedQueueOfE()}),
@@ -26813,6 +26818,8 @@
     })
   });
   return _DoubleLinkedQueueEntry;
+}, _DoubleLinkedQueueEntry => {
+  dart.setBaseClass(_DoubleLinkedQueueEntry, collection._DoubleLink$(_DoubleLinkedQueueEntry));
 });
 collection._DoubleLinkedQueueEntry = _DoubleLinkedQueueEntry();
 const _elementCount = Symbol('_elementCount');
diff --git a/pkg/dev_compiler/lib/js/legacy/dart_sdk.js b/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
index 2312c34..09a7b16 100644
--- a/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
@@ -798,43 +798,48 @@
     }
     return flatten;
   };
-  dart.generic = function(typeConstructor) {
-    let length = typeConstructor.length;
-    if (length < 1) {
-      dart.throwInternalError('must have at least one generic type argument');
-    }
-    let resultMap = new Map();
-    function makeGenericType(...args) {
-      if (args.length != length && args.length != 0) {
-        dart.throwInternalError('requires ' + length + ' or 0 type arguments');
+  dart.generic = function(typeConstructor, setBaseClass) {
+    if (setBaseClass === void 0) setBaseClass = null;
+    return (() => {
+      let length = typeConstructor.length;
+      if (length < 1) {
+        dart.throwInternalError('must have at least one generic type argument');
       }
-      while (args.length < length)
-        args.push(dart.dynamic);
-      let value = resultMap;
-      for (let i = 0; i < length; i++) {
-        let arg = args[i];
-        if (arg == null) {
-          dart.throwInternalError('type arguments should not be null: ' + typeConstructor);
+      let resultMap = new Map();
+      function makeGenericType(...args) {
+        if (args.length != length && args.length != 0) {
+          dart.throwInternalError('requires ' + length + ' or 0 type arguments');
         }
-        let map = value;
-        value = map.get(arg);
-        if (value === void 0) {
-          if (i + 1 == length) {
-            value = typeConstructor.apply(null, args);
-            if (value) {
-              value[dart._typeArguments] = args;
-              value[dart._originalDeclaration] = makeGenericType;
-            }
-          } else {
-            value = new Map();
+        while (args.length < length)
+          args.push(dart.dynamic);
+        let value = resultMap;
+        for (let i = 0; i < length; i++) {
+          let arg = args[i];
+          if (arg == null) {
+            dart.throwInternalError('type arguments should not be null: ' + typeConstructor);
           }
-          map.set(arg, value);
+          let map = value;
+          value = map.get(arg);
+          if (value === void 0) {
+            if (i + 1 == length) {
+              value = typeConstructor.apply(null, args);
+              if (value) {
+                value[dart._typeArguments] = args;
+                value[dart._originalDeclaration] = makeGenericType;
+              }
+              map.set(arg, value);
+              if (setBaseClass) setBaseClass(value);
+            } else {
+              value = new Map();
+              map.set(arg, value);
+            }
+          }
         }
+        return value;
       }
-      return value;
-    }
-    makeGenericType[dart._genericTypeCtor] = typeConstructor;
-    return makeGenericType;
+      makeGenericType[dart._genericTypeCtor] = typeConstructor;
+      return makeGenericType;
+    })();
   };
   dart.getGenericClass = function(type) {
     return dart.safeGetOwnProperty(type, dart._originalDeclaration);
@@ -26761,7 +26766,6 @@
         return this[_nextLink];
       }
     }
-    dart.setBaseClass(_UserDoubleLinkedQueueEntry, collection._DoubleLink$(_UserDoubleLinkedQueueEntry));
     _UserDoubleLinkedQueueEntry[dart.implements] = () => [DoubleLinkedQueueEntryOfE()];
     dart.setSignature(_UserDoubleLinkedQueueEntry, {
       constructors: () => ({new: dart.definiteFunctionType(collection._UserDoubleLinkedQueueEntry$(E), [E])}),
@@ -26775,6 +26779,8 @@
       })
     });
     return _UserDoubleLinkedQueueEntry;
+  }, _UserDoubleLinkedQueueEntry => {
+    dart.setBaseClass(_UserDoubleLinkedQueueEntry, collection._DoubleLink$(_UserDoubleLinkedQueueEntry));
   });
   collection._UserDoubleLinkedQueueEntry = _UserDoubleLinkedQueueEntry();
   const _queue = Symbol('_queue');
@@ -26804,7 +26810,6 @@
         return this[_previousLink][_asNonSentinelEntry]();
       }
     }
-    dart.setBaseClass(_DoubleLinkedQueueEntry, collection._DoubleLink$(_DoubleLinkedQueueEntry));
     dart.setSignature(_DoubleLinkedQueueEntry, {
       constructors: () => ({new: dart.definiteFunctionType(collection._DoubleLinkedQueueEntry$(E), [DoubleLinkedQueueOfE()])}),
       fields: () => ({[_queue]: DoubleLinkedQueueOfE()}),
@@ -26816,6 +26821,8 @@
       })
     });
     return _DoubleLinkedQueueEntry;
+  }, _DoubleLinkedQueueEntry => {
+    dart.setBaseClass(_DoubleLinkedQueueEntry, collection._DoubleLink$(_DoubleLinkedQueueEntry));
   });
   collection._DoubleLinkedQueueEntry = _DoubleLinkedQueueEntry();
   const _elementCount = Symbol('_elementCount');
diff --git a/pkg/dev_compiler/lib/sdk/ddc_sdk.sum b/pkg/dev_compiler/lib/sdk/ddc_sdk.sum
index 79fff65..04077ed 100644
--- a/pkg/dev_compiler/lib/sdk/ddc_sdk.sum
+++ b/pkg/dev_compiler/lib/sdk/ddc_sdk.sum
Binary files differ
diff --git a/pkg/dev_compiler/lib/src/compiler/code_generator.dart b/pkg/dev_compiler/lib/src/compiler/code_generator.dart
index 231fcb9..b7f3d5a 100644
--- a/pkg/dev_compiler/lib/src/compiler/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/compiler/code_generator.dart
@@ -767,7 +767,8 @@
 
     // Emit things that come after the ES6 `class ... { ... }`.
     var jsPeerNames = _getJSPeerNames(classElem);
-    _setBaseClass(classElem, className, jsPeerNames, body);
+    JS.Statement deferredBaseClass =
+        _setBaseClass(classElem, className, jsPeerNames, body);
 
     _emitClassTypeTests(classElem, className, body);
 
@@ -779,9 +780,11 @@
     _emitClassMetadata(node.metadata, className, body);
 
     JS.Statement classDef = _statement(body);
+
     var typeFormals = classElem.typeParameters;
     if (typeFormals.isNotEmpty) {
-      classDef = _defineClassTypeArguments(classElem, typeFormals, classDef);
+      classDef = _defineClassTypeArguments(
+          classElem, typeFormals, classDef, className, deferredBaseClass);
     }
 
     body = <JS.Statement>[classDef];
@@ -1126,14 +1129,23 @@
 
   /// Wraps a possibly generic class in its type arguments.
   JS.Statement _defineClassTypeArguments(TypeDefiningElement element,
-      List<TypeParameterElement> formals, JS.Statement body) {
+      List<TypeParameterElement> formals, JS.Statement body,
+      [JS.Expression className, JS.Statement deferredBaseClass]) {
     assert(formals.isNotEmpty);
-    var genericCall = _callHelper('generic((#) => { #; #; return #; })', [
+    var typeConstructor = js.call('(#) => { #; #; return #; }', [
       _emitTypeFormals(formals),
       _typeTable.discharge(formals),
       body,
       element.name
     ]);
+
+    var genericArgs = [typeConstructor];
+    if (deferredBaseClass != null) {
+      genericArgs.add(js.call('(#) => { #; }', [className, deferredBaseClass]));
+    }
+
+    var genericCall = _callHelper('generic(#)', [genericArgs]);
+
     if (element.library.isDartAsync &&
         (element.name == "Future" || element.name == "_Future")) {
       genericCall = _callHelper('flattenFutures(#)', [genericCall]);
@@ -1601,9 +1613,10 @@
     }
   }
 
-  void _setBaseClass(ClassElement classElem, JS.Expression className,
+  JS.Statement _setBaseClass(ClassElement classElem, JS.Expression className,
       List<String> jsPeerNames, List<JS.Statement> body) {
-    if (jsPeerNames.isNotEmpty && classElem.typeParameters.isNotEmpty) {
+    var typeFormals = classElem.typeParameters;
+    if (jsPeerNames.isNotEmpty && typeFormals.isNotEmpty) {
       for (var peer in jsPeerNames) {
         // TODO(jmesserly): we should just extend Array in the first place
         var newBaseClass = _callHelper('global.#', [peer]);
@@ -1613,9 +1626,12 @@
     } else if (_hasDeferredSupertype.contains(classElem)) {
       var newBaseClass = _emitType(classElem.type.superclass,
           nameType: false, subClass: classElem, className: className);
-      body.add(_callHelperStatement(
-          'setBaseClass(#, #);', [className, newBaseClass]));
+      var deferredBaseClass = _callHelperStatement(
+          'setBaseClass(#, #);', [className, newBaseClass]);
+      if (typeFormals.isNotEmpty) return deferredBaseClass;
+      body.add(deferredBaseClass);
     }
+    return null;
   }
 
   void _defineNamedConstructors(List<ConstructorDeclaration> ctors,
@@ -2954,7 +2970,7 @@
             hoistType: hoistType,
             subClass: subClass,
             className: className));
-      } else if (lowerGeneric) {
+      } else if (lowerGeneric || element == subClass) {
         jsArgs = [];
       }
       if (jsArgs != null) {
diff --git a/pkg/dev_compiler/test/codegen/language/field_test.dart b/pkg/dev_compiler/test/codegen/language/field_test.dart
index 6a1937f..ca41740 100644
--- a/pkg/dev_compiler/test/codegen/language/field_test.dart
+++ b/pkg/dev_compiler/test/codegen/language/field_test.dart
@@ -52,11 +52,11 @@
     // The tests below are a little cumbersome because not
     // everything is implemented yet.
     var o = new Second();
-    // 'a' getter is overriden, always returns -12.
+    // 'a' getter is overridden, always returns -12.
     Expect.equals(-12, o.a);
     o.a = 2;
     Expect.equals(-12, o.a);
-    // 'b' setter is overriden to write 12 to field 'c'.
+    // 'b' setter is overridden to write 12 to field 'c'.
     o.b = o;
     Expect.equals(12, o.c);
   }
diff --git a/pkg/dev_compiler/test/codegen/language/recursive_generic_test.dart b/pkg/dev_compiler/test/codegen/language/recursive_generic_test.dart
new file mode 100644
index 0000000..3d8dcd6
--- /dev/null
+++ b/pkg/dev_compiler/test/codegen/language/recursive_generic_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+abstract class S<T extends S<T>> { m() => 123; get S_T => T; }
+class C<T extends C<T>> extends S<C> { m() => 456; get C_T => T; }
+
+main() {
+  Expect.equals(new C().m(), 456);
+  // TODO(jmesserly): this should be dart1 vs dart2, not DDC vs VM.
+  var isVM = const bool.fromEnvironment('dart.isVM');
+  Expect.equals(new C().S_T.toString(), isVM ? 'C' : 'C<C>');
+  Expect.equals(new C().C_T.toString(), isVM ? 'dynamic' : 'C');
+}
diff --git a/pkg/dev_compiler/tool/input_sdk/lib/convert/utf.dart b/pkg/dev_compiler/tool/input_sdk/lib/convert/utf.dart
index 69bb72c..486ab4d 100644
--- a/pkg/dev_compiler/tool/input_sdk/lib/convert/utf.dart
+++ b/pkg/dev_compiler/tool/input_sdk/lib/convert/utf.dart
@@ -37,7 +37,7 @@
    * The optional [allowMalformed] argument defines how [decoder] (and [decode])
    * deal with invalid or unterminated character sequences.
    *
-   * If it is `true` (and not overriden at the method invocation) [decode] and
+   * If it is `true` (and not overridden at the method invocation) [decode] and
    * the [decoder] replace invalid (or unterminated) octet
    * sequences with the Unicode Replacement character `U+FFFD` (�). Otherwise
    * they throw a [FormatException].
diff --git a/pkg/dev_compiler/tool/input_sdk/lib/js/dart2js/js_dart2js.dart b/pkg/dev_compiler/tool/input_sdk/lib/js/dart2js/js_dart2js.dart
index 1582f0d..34636a7 100644
--- a/pkg/dev_compiler/tool/input_sdk/lib/js/dart2js/js_dart2js.dart
+++ b/pkg/dev_compiler/tool/input_sdk/lib/js/dart2js/js_dart2js.dart
@@ -383,7 +383,7 @@
     super['length'] = length;
   }
 
-  // Methods overriden for better performance
+  // Methods overridden for better performance
 
   void add(E value) {
     callMethod('push', [value]);
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/classes.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/classes.dart
index 1c77871..1899f96 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/classes.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/classes.dart
@@ -97,7 +97,7 @@
 })()''');
 
 /// Memoize a generic type constructor function.
-generic(typeConstructor) => JS(
+generic(typeConstructor, [setBaseClass]) => JS(
     '',
     '''(() => {
   let length = $typeConstructor.length;
@@ -128,10 +128,12 @@
             value[$_typeArguments] = args;
             value[$_originalDeclaration] = makeGenericType;
           }
+          map.set(arg, value);
+          if ($setBaseClass) $setBaseClass(value);
         } else {
           value = new Map();
+          map.set(arg, value);
         }
-        map.set(arg, value);
       }
     }
     return value;
diff --git a/runtime/bin/builtin_impl_sources.gypi b/runtime/bin/builtin_impl_sources.gypi
index 846244a..a60f8a8 100644
--- a/runtime/bin/builtin_impl_sources.gypi
+++ b/runtime/bin/builtin_impl_sources.gypi
@@ -37,6 +37,7 @@
     'extensions_win.cc',
     'fdutils.h',
     'fdutils_android.cc',
+    'fdutils_fuchsia.cc',
     'fdutils_linux.cc',
     'fdutils_macos.cc',
     'file.cc',
diff --git a/runtime/bin/eventhandler_fuchsia.cc b/runtime/bin/eventhandler_fuchsia.cc
index 2d0ebe3..c298e22 100644
--- a/runtime/bin/eventhandler_fuchsia.cc
+++ b/runtime/bin/eventhandler_fuchsia.cc
@@ -10,13 +10,25 @@
 #include "bin/eventhandler.h"
 #include "bin/eventhandler_fuchsia.h"
 
-#include <magenta/status.h>
-#include <magenta/syscalls.h>
+#include <errno.h>      // NOLINT
+#include <fcntl.h>      // NOLINT
+#include <pthread.h>    // NOLINT
+#include <stdio.h>      // NOLINT
+#include <string.h>     // NOLINT
+#include <sys/epoll.h>  // NOLINT
+#include <sys/stat.h>   // NOLINT
+#include <unistd.h>     // NOLINT
 
+#include "bin/fdutils.h"
+#include "bin/lockers.h"
 #include "bin/log.h"
+#include "bin/socket.h"
 #include "bin/thread.h"
 #include "bin/utils.h"
+#include "platform/hashmap.h"
+#include "platform/utils.h"
 
+// #define EVENTHANDLER_LOGGING 1
 #if defined(EVENTHANDLER_LOGGING)
 #define LOG_ERR(msg, ...) Log::PrintErr(msg, ##__VA_ARGS__)
 #define LOG_INFO(msg, ...) Log::Print(msg, ##__VA_ARGS__)
@@ -28,115 +40,204 @@
 namespace dart {
 namespace bin {
 
-MagentaWaitManyInfo::MagentaWaitManyInfo()
-    : capacity_(kInitialCapacity), size_(0) {
-  descriptor_infos_ = static_cast<DescriptorInfo**>(
-      malloc(kInitialCapacity * sizeof(*descriptor_infos_)));
-  if (descriptor_infos_ == NULL) {
-    FATAL("Failed to allocate descriptor_infos array");
+#if defined(EVENTHANDLER_LOGGING)
+static void PrintEventMask(intptr_t fd, intptr_t events) {
+  Log::PrintErr("%d ", fd);
+  if ((events & EPOLLIN) != 0) {
+    Log::PrintErr("EPOLLIN ");
   }
-  items_ =
-      static_cast<mx_wait_item_t*>(malloc(kInitialCapacity * sizeof(*items_)));
-  if (items_ == NULL) {
-    FATAL("Failed to allocate items array");
+  if ((events & EPOLLPRI) != 0) {
+    Log::PrintErr("EPOLLPRI ");
   }
+  if ((events & EPOLLOUT) != 0) {
+    Log::PrintErr("EPOLLOUT ");
+  }
+  if ((events & EPOLLERR) != 0) {
+    Log::PrintErr("EPOLLERR ");
+  }
+  if ((events & EPOLLHUP) != 0) {
+    Log::PrintErr("EPOLLHUP ");
+  }
+  if ((events & EPOLLRDHUP) != 0) {
+    Log::PrintErr("EPOLLRDHUP ");
+  }
+  int all_events =
+      EPOLLIN | EPOLLPRI | EPOLLOUT | EPOLLERR | EPOLLHUP | EPOLLRDHUP;
+  if ((events & ~all_events) != 0) {
+    Log::PrintErr("(and %08x) ", events & ~all_events);
+  }
+
+  Log::PrintErr("\n");
 }
-
-
-MagentaWaitManyInfo::~MagentaWaitManyInfo() {
-  free(descriptor_infos_);
-  free(items_);
-}
-
-
-void MagentaWaitManyInfo::AddHandle(mx_handle_t handle,
-                                    mx_signals_t signals,
-                                    DescriptorInfo* di) {
-#if defined(DEBUG)
-  // Check that the handle is not already in the list.
-  for (intptr_t i = 0; i < size_; i++) {
-    if (items_[i].handle == handle) {
-      FATAL("The handle is already in the list!");
-    }
-  }
 #endif
-  intptr_t new_size = size_ + 1;
-  GrowArraysIfNeeded(new_size);
-  descriptor_infos_[size_] = di;
-  items_[size_].handle = handle;
-  items_[size_].waitfor = signals;
-  items_[size_].pending = 0;
-  size_ = new_size;
-  LOG_INFO("AddHandle(%ld, %ld, %p), size = %ld\n", handle, signals, di, size_);
+
+
+intptr_t DescriptorInfo::GetPollEvents() {
+  // Do not ask for EPOLLERR and EPOLLHUP explicitly as they are
+  // triggered anyway.
+  intptr_t events = 0;
+  if ((Mask() & (1 << kInEvent)) != 0) {
+    events |= EPOLLIN;
+  }
+  if ((Mask() & (1 << kOutEvent)) != 0) {
+    events |= EPOLLOUT;
+  }
+  return events;
 }
 
 
-void MagentaWaitManyInfo::RemoveHandle(mx_handle_t handle) {
-  intptr_t idx;
-  for (idx = 1; idx < size_; idx++) {
-    if (handle == items_[idx].handle) {
-      break;
-    }
-  }
-  if (idx == size_) {
-    FATAL("Handle is not in the list!");
-  }
-
-  if (idx != (size_ - 1)) {
-    descriptor_infos_[idx] = descriptor_infos_[size_ - 1];
-    items_[idx] = items_[size_ - 1];
-  }
-  descriptor_infos_[size_ - 1] = NULL;
-  items_[size_ - 1] = {MX_HANDLE_INVALID, 0, 0};
-  size_ = size_ - 1;
-  LOG_INFO("RemoveHandle(%ld), size = %ld\n", handle, size_);
+// Unregister the file descriptor for a DescriptorInfo structure with
+// epoll.
+static void RemoveFromEpollInstance(intptr_t epoll_fd_, DescriptorInfo* di) {
+  LOG_INFO("RemoveFromEpollInstance: fd = %ld\n", di->fd());
+  VOID_NO_RETRY_EXPECTED(epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, di->fd(), NULL));
 }
 
 
-void MagentaWaitManyInfo::GrowArraysIfNeeded(intptr_t desired_size) {
-  if (desired_size < capacity_) {
-    return;
+static void AddToEpollInstance(intptr_t epoll_fd_, DescriptorInfo* di) {
+  struct epoll_event event;
+  event.events = EPOLLRDHUP | di->GetPollEvents();
+  if (!di->IsListeningSocket()) {
+    event.events |= EPOLLET;
   }
-  intptr_t new_capacity = desired_size + (desired_size >> 1);
-  descriptor_infos_ = static_cast<DescriptorInfo**>(
-      realloc(descriptor_infos_, new_capacity * sizeof(*descriptor_infos_)));
-  if (descriptor_infos_ == NULL) {
-    FATAL("Failed to grow descriptor_infos array");
+  event.data.ptr = di;
+  LOG_INFO("AddToEpollInstance: fd = %ld\n", di->fd());
+  int status =
+      NO_RETRY_EXPECTED(epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, di->fd(), &event));
+  LOG_INFO("AddToEpollInstance: fd = %ld, status = %d\n", di->fd(), status);
+#if defined(EVENTHANDLER_LOGGING)
+  PrintEventMask(di->fd(), event.events);
+#endif
+  if (status == -1) {
+    // TODO(dart:io): Verify that the dart end is handling this correctly.
+
+    // Epoll does not accept the file descriptor. It could be due to
+    // already closed file descriptor, or unuspported devices, such
+    // as /dev/null. In such case, mark the file descriptor as closed,
+    // so dart will handle it accordingly.
+    di->NotifyAllDartPorts(1 << kCloseEvent);
   }
-  items_ = static_cast<mx_wait_item_t*>(
-      realloc(items_, new_capacity * sizeof(*items_)));
-  if (items_ == NULL) {
-    FATAL("Failed to grow items array");
-  }
-  capacity_ = new_capacity;
-  LOG_INFO("GrowArraysIfNeeded(%ld), capacity = %ld\n", desired_size,
-           capacity_);
 }
 
 
-EventHandlerImplementation::EventHandlerImplementation() {
-  mx_status_t status =
-      mx_channel_create(0, &interrupt_handles_[0], &interrupt_handles_[1]);
-  if (status != NO_ERROR) {
-    FATAL1("mx_channel_create failed: %s\n", mx_status_get_string(status));
+EventHandlerImplementation::EventHandlerImplementation()
+    : socket_map_(&HashMap::SamePointerValue, 16) {
+  intptr_t result;
+  result = NO_RETRY_EXPECTED(pipe(interrupt_fds_));
+  if (result != 0) {
+    FATAL("Pipe creation failed");
+  }
+  if (!FDUtils::SetNonBlocking(interrupt_fds_[0])) {
+    FATAL("Failed to set pipe fd non blocking\n");
+  }
+  if (!FDUtils::SetCloseOnExec(interrupt_fds_[0])) {
+    FATAL("Failed to set pipe fd close on exec\n");
+  }
+  if (!FDUtils::SetCloseOnExec(interrupt_fds_[1])) {
+    FATAL("Failed to set pipe fd close on exec\n");
   }
   shutdown_ = false;
-  info_.AddHandle(interrupt_handles_[0],
-                  MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED, NULL);
-  LOG_INFO("EventHandlerImplementation initialized\n");
+  // The initial size passed to epoll_create is ignore on newer (>=
+  // 2.6.8) Linux versions
+  static const int kEpollInitialSize = 64;
+  epoll_fd_ = NO_RETRY_EXPECTED(epoll_create(kEpollInitialSize));
+  if (epoll_fd_ == -1) {
+    FATAL1("Failed creating epoll file descriptor: %i", errno);
+  }
+  if (!FDUtils::SetCloseOnExec(epoll_fd_)) {
+    FATAL("Failed to set epoll fd close on exec\n");
+  }
+  // Register the interrupt_fd with the epoll instance.
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.ptr = NULL;
+  LOG_INFO("EventHandlerImplementation(): epoll_ctl: fd = %ld\n", epoll_fd_);
+  int status = NO_RETRY_EXPECTED(
+      epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupt_fds_[0], &event));
+  LOG_INFO("EventHandlerImplementation(): epoll_ctl: fd = %ld, status = %d\n",
+           epoll_fd_, status);
+  if (status == -1) {
+    FATAL("Failed adding interrupt fd to epoll instance");
+  }
+}
+
+
+static void DeleteDescriptorInfo(void* info) {
+  DescriptorInfo* di = reinterpret_cast<DescriptorInfo*>(info);
+  di->Close();
+  LOG_INFO("Closed %d\n", di->fd());
+  delete di;
 }
 
 
 EventHandlerImplementation::~EventHandlerImplementation() {
-  mx_status_t status = mx_handle_close(interrupt_handles_[0]);
-  if (status != NO_ERROR) {
-    FATAL1("mx_handle_close failed: %s\n", mx_status_get_string(status));
+  socket_map_.Clear(DeleteDescriptorInfo);
+  VOID_NO_RETRY_EXPECTED(close(epoll_fd_));
+  VOID_NO_RETRY_EXPECTED(close(interrupt_fds_[0]));
+  VOID_NO_RETRY_EXPECTED(close(interrupt_fds_[1]));
+}
+
+
+void EventHandlerImplementation::UpdateEpollInstance(intptr_t old_mask,
+                                                     DescriptorInfo* di) {
+  intptr_t new_mask = di->Mask();
+  LOG_INFO("UpdateEpollInstance: %d old=%ld, new=%ld\n", di->fd(), old_mask,
+           new_mask);
+  if ((old_mask != 0) && (new_mask == 0)) {
+    RemoveFromEpollInstance(epoll_fd_, di);
+  } else if ((old_mask == 0) && (new_mask != 0)) {
+    AddToEpollInstance(epoll_fd_, di);
+  } else if ((old_mask != 0) && (new_mask != 0) && (old_mask != new_mask)) {
+    ASSERT(!di->IsListeningSocket());
+    RemoveFromEpollInstance(epoll_fd_, di);
+    AddToEpollInstance(epoll_fd_, di);
   }
-  status = mx_handle_close(interrupt_handles_[1]);
-  if (status != NO_ERROR) {
-    FATAL1("mx_handle_close failed: %s\n", mx_status_get_string(status));
+}
+
+
+DescriptorInfo* EventHandlerImplementation::GetDescriptorInfo(
+    intptr_t fd,
+    bool is_listening) {
+  ASSERT(fd >= 0);
+  HashMap::Entry* entry = socket_map_.Lookup(GetHashmapKeyFromFd(fd),
+                                             GetHashmapHashFromFd(fd), true);
+  ASSERT(entry != NULL);
+  DescriptorInfo* di = reinterpret_cast<DescriptorInfo*>(entry->value);
+  if (di == NULL) {
+    // If there is no data in the hash map for this file descriptor a
+    // new DescriptorInfo for the file descriptor is inserted.
+    if (is_listening) {
+      di = new DescriptorInfoMultiple(fd);
+    } else {
+      di = new DescriptorInfoSingle(fd);
+    }
+    entry->value = di;
   }
-  LOG_INFO("EventHandlerImplementation destroyed\n");
+  ASSERT(fd == di->fd());
+  return di;
+}
+
+
+static ssize_t WriteToBlocking(int fd, const void* buffer, size_t count) {
+  size_t remaining = count;
+  char* buffer_pos = const_cast<char*>(reinterpret_cast<const char*>(buffer));
+  while (remaining > 0) {
+    ssize_t bytes_written = NO_RETRY_EXPECTED(write(fd, buffer_pos, remaining));
+    if (bytes_written == 0) {
+      return count - remaining;
+    } else if (bytes_written == -1) {
+      ASSERT(EAGAIN == EWOULDBLOCK);
+      // Error code EWOULDBLOCK should only happen for non blocking
+      // file descriptors.
+      ASSERT(errno != EWOULDBLOCK);
+      return -1;
+    } else {
+      ASSERT(bytes_written > 0);
+      remaining -= bytes_written;
+      buffer_pos += bytes_written;
+    }
+  }
+  return count;
 }
 
 
@@ -147,71 +248,171 @@
   msg.id = id;
   msg.dart_port = dart_port;
   msg.data = data;
-
-  mx_status_t status =
-      mx_channel_write(interrupt_handles_[1], 0, &msg, sizeof(msg), NULL, 0);
-  if (status != NO_ERROR) {
-    FATAL1("mx_channel_write failed: %s\n", mx_status_get_string(status));
+  // WriteToBlocking will write up to 512 bytes atomically, and since our msg
+  // is smaller than 512, we don't need a thread lock.
+  // See: http://linux.die.net/man/7/pipe, section 'Pipe_buf'.
+  ASSERT(kInterruptMessageSize < PIPE_BUF);
+  intptr_t result =
+      WriteToBlocking(interrupt_fds_[1], &msg, kInterruptMessageSize);
+  if (result != kInterruptMessageSize) {
+    if (result == -1) {
+      perror("Interrupt message failure:");
+    }
+    FATAL1("Interrupt message failure. Wrote %" Pd " bytes.", result);
   }
-  LOG_INFO("WakeupHandler(%ld, %ld, %lld)\n", id, dart_port, data);
 }
 
 
 void EventHandlerImplementation::HandleInterruptFd() {
-  LOG_INFO("HandleInterruptFd entry\n");
-  InterruptMessage msg;
-  uint32_t bytes = kInterruptMessageSize;
-  mx_status_t status;
-  while (true) {
-    status = mx_channel_read(interrupt_handles_[0], 0, &msg, bytes, &bytes,
-                             NULL, 0, NULL);
-    if (status != NO_ERROR) {
-      break;
-    }
-    ASSERT(bytes == kInterruptMessageSize);
-    if (msg.id == kTimerId) {
+  const intptr_t MAX_MESSAGES = kInterruptMessageSize;
+  InterruptMessage msg[MAX_MESSAGES];
+  ssize_t bytes = NO_RETRY_EXPECTED(
+      read(interrupt_fds_[0], msg, MAX_MESSAGES * kInterruptMessageSize));
+  LOG_INFO("HandleInterruptFd read %ld bytes\n", bytes);
+  for (ssize_t i = 0; i < bytes / kInterruptMessageSize; i++) {
+    if (msg[i].id == kTimerId) {
       LOG_INFO("HandleInterruptFd read timer update\n");
-      timeout_queue_.UpdateTimeout(msg.dart_port, msg.data);
-    } else if (msg.id == kShutdownId) {
+      timeout_queue_.UpdateTimeout(msg[i].dart_port, msg[i].data);
+    } else if (msg[i].id == kShutdownId) {
       LOG_INFO("HandleInterruptFd read shutdown\n");
       shutdown_ = true;
     } else {
-      // TODO(zra): Handle commands to add and remove handles from the
-      // MagentaWaitManyInfo.
-      UNIMPLEMENTED();
+      ASSERT((msg[i].data & COMMAND_MASK) != 0);
+      LOG_INFO("HandleInterruptFd command\n");
+      DescriptorInfo* di =
+          GetDescriptorInfo(msg[i].id, IS_LISTENING_SOCKET(msg[i].data));
+      if (IS_COMMAND(msg[i].data, kShutdownReadCommand)) {
+        ASSERT(!di->IsListeningSocket());
+        // Close the socket for reading.
+        LOG_INFO("\tSHUT_RD: %d\n", di->fd());
+        VOID_NO_RETRY_EXPECTED(shutdown(di->fd(), SHUT_RD));
+      } else if (IS_COMMAND(msg[i].data, kShutdownWriteCommand)) {
+        ASSERT(!di->IsListeningSocket());
+        // Close the socket for writing.
+        LOG_INFO("\tSHUT_WR: %d\n", di->fd());
+        VOID_NO_RETRY_EXPECTED(shutdown(di->fd(), SHUT_WR));
+      } else if (IS_COMMAND(msg[i].data, kCloseCommand)) {
+        // Close the socket and free system resources and move on to next
+        // message.
+        intptr_t old_mask = di->Mask();
+        Dart_Port port = msg[i].dart_port;
+        di->RemovePort(port);
+        intptr_t new_mask = di->Mask();
+        UpdateEpollInstance(old_mask, di);
+
+        LOG_INFO("\tCLOSE: %d: %lx -> %lx\n", di->fd(), old_mask, new_mask);
+        intptr_t fd = di->fd();
+        if (di->IsListeningSocket()) {
+          // We only close the socket file descriptor from the operating
+          // system if there are no other dart socket objects which
+          // are listening on the same (address, port) combination.
+          ListeningSocketRegistry* registry =
+              ListeningSocketRegistry::Instance();
+
+          MutexLocker locker(registry->mutex());
+
+          if (registry->CloseSafe(fd)) {
+            ASSERT(new_mask == 0);
+            socket_map_.Remove(GetHashmapKeyFromFd(fd),
+                               GetHashmapHashFromFd(fd));
+            di->Close();
+            LOG_INFO("Closed %d\n", di->fd());
+            delete di;
+          }
+        } else {
+          ASSERT(new_mask == 0);
+          socket_map_.Remove(GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd));
+          di->Close();
+          LOG_INFO("Closed %d\n", di->fd());
+          delete di;
+        }
+
+        DartUtils::PostInt32(port, 1 << kDestroyedEvent);
+      } else if (IS_COMMAND(msg[i].data, kReturnTokenCommand)) {
+        int count = TOKEN_COUNT(msg[i].data);
+        intptr_t old_mask = di->Mask();
+        LOG_INFO("\t Return Token: %d: %lx\n", di->fd(), old_mask);
+        di->ReturnTokens(msg[i].dart_port, count);
+        UpdateEpollInstance(old_mask, di);
+      } else if (IS_COMMAND(msg[i].data, kSetEventMaskCommand)) {
+        // `events` can only have kInEvent/kOutEvent flags set.
+        intptr_t events = msg[i].data & EVENT_MASK;
+        ASSERT(0 == (events & ~(1 << kInEvent | 1 << kOutEvent)));
+
+        intptr_t old_mask = di->Mask();
+        LOG_INFO("\t Set Event Mask: %d: %lx %lx\n", di->fd(), old_mask,
+                 msg[i].data & EVENT_MASK);
+        di->SetPortAndMask(msg[i].dart_port, msg[i].data & EVENT_MASK);
+        UpdateEpollInstance(old_mask, di);
+      } else {
+        UNREACHABLE();
+      }
     }
   }
-  // status == ERR_SHOULD_WAIT when we try to read and there are no messages
-  // available, so it is an error if we get here and status != ERR_SHOULD_WAIT.
-  if (status != ERR_SHOULD_WAIT) {
-    FATAL1("mx_channel_read failed: %s\n", mx_status_get_string(status));
-  }
   LOG_INFO("HandleInterruptFd exit\n");
 }
 
 
-void EventHandlerImplementation::HandleEvents() {
-  LOG_INFO("HandleEvents entry\n");
-  for (intptr_t i = 1; i < info_.size(); i++) {
-    const mx_wait_item_t& wait_item = info_.items()[i];
-    if (wait_item.pending & wait_item.waitfor) {
-      // Only the control handle has no descriptor info.
-      ASSERT(info_.descriptor_infos()[i] != NULL);
-      ASSERT(wait_item.handle != interrupt_handles_[0]);
-      // TODO(zra): Handle events on other handles. At the moment we are
-      // only interrupted when there is a message on interrupt_handles_[0].
-      UNIMPLEMENTED();
+intptr_t EventHandlerImplementation::GetPollEvents(intptr_t events,
+                                                   DescriptorInfo* di) {
+#ifdef EVENTHANDLER_LOGGING
+  PrintEventMask(di->fd(), events);
+#endif
+  if ((events & EPOLLERR) != 0) {
+    // Return error only if EPOLLIN is present.
+    return ((events & EPOLLIN) != 0) ? (1 << kErrorEvent) : 0;
+  }
+  intptr_t event_mask = 0;
+  if ((events & EPOLLIN) != 0) {
+    event_mask |= (1 << kInEvent);
+  }
+  if ((events & EPOLLOUT) != 0) {
+    event_mask |= (1 << kOutEvent);
+  }
+  if ((events & (EPOLLHUP | EPOLLRDHUP)) != 0) {
+    event_mask |= (1 << kCloseEvent);
+  }
+  return event_mask;
+}
+
+
+void EventHandlerImplementation::HandleEvents(struct epoll_event* events,
+                                              int size) {
+  bool interrupt_seen = false;
+  for (int i = 0; i < size; i++) {
+    if (events[i].data.ptr == NULL) {
+      interrupt_seen = true;
+    } else {
+      DescriptorInfo* di =
+          reinterpret_cast<DescriptorInfo*>(events[i].data.ptr);
+      intptr_t event_mask = GetPollEvents(events[i].events, di);
+
+      if ((event_mask & (1 << kErrorEvent)) != 0) {
+        di->NotifyAllDartPorts(event_mask);
+      }
+      event_mask &= ~(1 << kErrorEvent);
+
+      LOG_INFO("HandleEvents: fd=%ld events=%ld\n", di->fd(), event_mask);
+      if (event_mask != 0) {
+        intptr_t old_mask = di->Mask();
+        Dart_Port port = di->NextNotifyDartPort(event_mask);
+        ASSERT(port != 0);
+        UpdateEpollInstance(old_mask, di);
+        LOG_INFO("HandleEvents: Posting %ld to %ld for fd=%ld\n", event_mask,
+                 port, di->fd());
+        bool success = DartUtils::PostInt32(port, event_mask);
+        if (!success) {
+          // This can happen if e.g. the isolate that owns the port has died
+          // for some reason.
+          FATAL2("Failed to post event for fd %ld to port %ld", di->fd(), port);
+        }
+      }
     }
   }
-
-  if ((info_.items()[0].pending & MX_SIGNAL_PEER_CLOSED) != 0) {
-    FATAL("EventHandlerImplementation::Poll: Unexpected peer closed\n");
-  }
-  if ((info_.items()[0].pending & MX_SIGNAL_READABLE) != 0) {
-    LOG_INFO("HandleEvents interrupt_handles_[0] readable\n");
+  if (interrupt_seen) {
+    // Handle after socket events, so we avoid closing a socket before we handle
+    // the current events.
     HandleInterruptFd();
-  } else {
-    LOG_INFO("HandleEvents interrupt_handles_[0] not readable\n");
   }
 }
 
@@ -239,6 +440,8 @@
 
 
 void EventHandlerImplementation::Poll(uword args) {
+  static const intptr_t kMaxEvents = 16;
+  struct epoll_event events[kMaxEvents];
   EventHandler* handler = reinterpret_cast<EventHandler*>(args);
   EventHandlerImplementation* handler_impl = &handler->delegate_;
   ASSERT(handler_impl != NULL);
@@ -246,23 +449,21 @@
   while (!handler_impl->shutdown_) {
     int64_t millis = handler_impl->GetTimeout();
     ASSERT((millis == kInfinityTimeout) || (millis >= 0));
-    mx_time_t timeout =
-        millis * kMicrosecondsPerMillisecond * kNanosecondsPerMicrosecond;
-    const MagentaWaitManyInfo& info = handler_impl->info();
-    LOG_INFO("mx_handle_wait_many(%p, %ld, %lld)\n", info.items(), info.size(),
-             timeout);
-    mx_status_t status =
-        mx_handle_wait_many(info.items(), info.size(), timeout);
-    if ((status != NO_ERROR) && (status != ERR_TIMED_OUT)) {
-      FATAL1("mx_handle_wait_many failed: %s\n", mx_status_get_string(status));
+    LOG_INFO("epoll_wait(millis = %ld)\n", millis);
+    intptr_t result = NO_RETRY_EXPECTED(
+        epoll_wait(handler_impl->epoll_fd_, events, kMaxEvents, millis));
+    ASSERT(EAGAIN == EWOULDBLOCK);
+    LOG_INFO("epoll_wait(millis = %ld) -> %ld\n", millis, result);
+    if (result < 0) {
+      if (errno != EWOULDBLOCK) {
+        perror("Poll failed");
+      }
     } else {
-      LOG_INFO("mx_handle_wait_many returned: %ld\n", status);
       handler_impl->HandleTimeout();
-      handler_impl->HandleEvents();
+      handler_impl->HandleEvents(events, result);
     }
   }
   handler->NotifyShutdownDone();
-  LOG_INFO("EventHandlerImplementation notifying about shutdown\n");
 }
 
 
@@ -286,6 +487,17 @@
   WakeupHandler(id, dart_port, data);
 }
 
+void* EventHandlerImplementation::GetHashmapKeyFromFd(intptr_t fd) {
+  // The hashmap does not support keys with value 0.
+  return reinterpret_cast<void*>(fd + 1);
+}
+
+
+uint32_t EventHandlerImplementation::GetHashmapHashFromFd(intptr_t fd) {
+  // The hashmap does not support keys with value 0.
+  return dart::Utils::WordHash(fd + 1);
+}
+
 }  // namespace bin
 }  // namespace dart
 
diff --git a/runtime/bin/eventhandler_fuchsia.h b/runtime/bin/eventhandler_fuchsia.h
index acd4793..545fdb8 100644
--- a/runtime/bin/eventhandler_fuchsia.h
+++ b/runtime/bin/eventhandler_fuchsia.h
@@ -10,7 +10,9 @@
 #endif
 
 #include <errno.h>
-#include <magenta/syscalls.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
 
 #include "platform/signal_blocker.h"
 
@@ -23,8 +25,11 @@
 
   virtual ~DescriptorInfo() {}
 
+  intptr_t GetPollEvents();
+
   virtual void Close() {
-    VOID_TEMP_FAILURE_RETRY(close(fd_));
+    // Should be VOID_TEMP_FAILURE_RETRY
+    VOID_NO_RETRY_EXPECTED(close(fd_));
     fd_ = -1;
   }
 
@@ -53,57 +58,37 @@
   DISALLOW_COPY_AND_ASSIGN(DescriptorInfoMultiple);
 };
 
-// Information needed to call mx_handle_wait_many(), and to handle events.
-class MagentaWaitManyInfo {
- public:
-  MagentaWaitManyInfo();
-  ~MagentaWaitManyInfo();
-
-  intptr_t capacity() const { return capacity_; }
-  intptr_t size() const { return size_; }
-  DescriptorInfo** descriptor_infos() const { return descriptor_infos_; }
-  mx_wait_item_t* items() const { return items_; }
-
-  void AddHandle(mx_handle_t handle, mx_signals_t signals, DescriptorInfo* di);
-  void RemoveHandle(mx_handle_t handle);
-
- private:
-  static const intptr_t kInitialCapacity = 32;
-
-  void GrowArraysIfNeeded(intptr_t desired_size);
-
-  intptr_t capacity_;
-  intptr_t size_;
-  DescriptorInfo** descriptor_infos_;
-  mx_wait_item_t* items_;
-
-  DISALLOW_COPY_AND_ASSIGN(MagentaWaitManyInfo);
-};
-
 class EventHandlerImplementation {
  public:
   EventHandlerImplementation();
   ~EventHandlerImplementation();
 
+  void UpdateEpollInstance(intptr_t old_mask, DescriptorInfo* di);
+
+  // Gets the socket data structure for a given file
+  // descriptor. Creates a new one if one is not found.
+  DescriptorInfo* GetDescriptorInfo(intptr_t fd, bool is_listening);
   void SendData(intptr_t id, Dart_Port dart_port, int64_t data);
   void Start(EventHandler* handler);
   void Shutdown();
 
-  const MagentaWaitManyInfo& info() const { return info_; }
-
  private:
+  static void Poll(uword args);
+  static void* GetHashmapKeyFromFd(intptr_t fd);
+  static uint32_t GetHashmapHashFromFd(intptr_t fd);
+
   int64_t GetTimeout() const;
-  void HandleEvents();
+  void HandleEvents(struct epoll_event* events, int size);
   void HandleTimeout();
   void WakeupHandler(intptr_t id, Dart_Port dart_port, int64_t data);
+  intptr_t GetPollEvents(intptr_t events, DescriptorInfo* di);
   void HandleInterruptFd();
-  static void Poll(uword args);
 
+  HashMap socket_map_;
   TimeoutQueue timeout_queue_;
   bool shutdown_;
-  mx_handle_t interrupt_handles_[2];
-
-  MagentaWaitManyInfo info_;
+  int interrupt_fds_[2];
+  int epoll_fd_;
 
   DISALLOW_COPY_AND_ASSIGN(EventHandlerImplementation);
 };
diff --git a/runtime/bin/fdutils.h b/runtime/bin/fdutils.h
index 25cd4dd..81c4541 100644
--- a/runtime/bin/fdutils.h
+++ b/runtime/bin/fdutils.h
@@ -39,6 +39,9 @@
   // descriptor must be in blocking mode.
   static ssize_t WriteToBlocking(int fd, const void* buffer, size_t count);
 
+  // Closes fd without modifying errno.
+  static void SaveErrorAndClose(intptr_t fd);
+
  private:
   DISALLOW_ALLOCATION();
   DISALLOW_IMPLICIT_CONSTRUCTORS(FDUtils);
diff --git a/runtime/bin/fdutils_android.cc b/runtime/bin/fdutils_android.cc
index 5d8a8e0..ad5b91e 100644
--- a/runtime/bin/fdutils_android.cc
+++ b/runtime/bin/fdutils_android.cc
@@ -137,6 +137,13 @@
   return count;
 }
 
+
+void FDUtils::SaveErrorAndClose(intptr_t fd) {
+  int err = errno;
+  VOID_TEMP_FAILURE_RETRY(close(fd));
+  errno = err;
+}
+
 }  // namespace bin
 }  // namespace dart
 
diff --git a/runtime/bin/fdutils_fuchsia.cc b/runtime/bin/fdutils_fuchsia.cc
new file mode 100644
index 0000000..dd9e881
--- /dev/null
+++ b/runtime/bin/fdutils_fuchsia.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_FUCHSIA)
+
+#include "bin/fdutils.h"
+
+#include <errno.h>      // NOLINT
+#include <fcntl.h>      // NOLINT
+#include <sys/ioctl.h>  // NOLINT
+#include <unistd.h>     // NOLINT
+
+#include "platform/signal_blocker.h"
+
+namespace dart {
+namespace bin {
+
+bool FDUtils::SetCloseOnExec(intptr_t fd) {
+  intptr_t status;
+  status = NO_RETRY_EXPECTED(fcntl(fd, F_GETFD));
+  if (status < 0) {
+    perror("fcntl(F_GETFD) failed");
+    return false;
+  }
+  status |= FD_CLOEXEC;
+  if (NO_RETRY_EXPECTED(fcntl(fd, F_SETFD, status)) < 0) {
+    perror("fcntl(F_SETFD, FD_CLOEXEC) failed");
+    return false;
+  }
+  return true;
+}
+
+
+static bool SetBlockingHelper(intptr_t fd, bool blocking) {
+  intptr_t status;
+  status = NO_RETRY_EXPECTED(fcntl(fd, F_GETFL));
+  if (status < 0) {
+    perror("fcntl(F_GETFL) failed");
+    return false;
+  }
+  status = blocking ? (status & ~O_NONBLOCK) : (status | O_NONBLOCK);
+  if (NO_RETRY_EXPECTED(fcntl(fd, F_SETFL, status)) < 0) {
+    perror("fcntl(F_SETFL, O_NONBLOCK) failed");
+    return false;
+  }
+  return true;
+}
+
+
+bool FDUtils::SetNonBlocking(intptr_t fd) {
+  return SetBlockingHelper(fd, false);
+}
+
+
+bool FDUtils::SetBlocking(intptr_t fd) {
+  return SetBlockingHelper(fd, true);
+}
+
+
+bool FDUtils::IsBlocking(intptr_t fd, bool* is_blocking) {
+  intptr_t status;
+  status = NO_RETRY_EXPECTED(fcntl(fd, F_GETFL));
+  if (status < 0) {
+    return false;
+  }
+  *is_blocking = (status & O_NONBLOCK) == 0;
+  return true;
+}
+
+
+intptr_t FDUtils::AvailableBytes(intptr_t fd) {
+// TODO(MG-364): Enable this code when it is supported.
+#if 0
+  int available;  // ioctl for FIONREAD expects an 'int*' argument.
+  int result = NO_RETRY_EXPECTED(ioctl(fd, FIONREAD, &available));
+  if (result < 0) {
+    return result;
+  }
+  ASSERT(available >= 0);
+  return static_cast<intptr_t>(available);
+#endif
+  errno = ENOTSUP;
+  return -1;
+}
+
+
+ssize_t FDUtils::ReadFromBlocking(int fd, void* buffer, size_t count) {
+#ifdef DEBUG
+  bool is_blocking = false;
+  ASSERT(FDUtils::IsBlocking(fd, &is_blocking));
+  ASSERT(is_blocking);
+#endif
+  size_t remaining = count;
+  char* buffer_pos = reinterpret_cast<char*>(buffer);
+  while (remaining > 0) {
+    ssize_t bytes_read = NO_RETRY_EXPECTED(read(fd, buffer_pos, remaining));
+    if (bytes_read == 0) {
+      return count - remaining;
+    } else if (bytes_read == -1) {
+      ASSERT(EAGAIN == EWOULDBLOCK);
+      // Error code EWOULDBLOCK should only happen for non blocking
+      // file descriptors.
+      ASSERT(errno != EWOULDBLOCK);
+      return -1;
+    } else {
+      ASSERT(bytes_read > 0);
+      remaining -= bytes_read;
+      buffer_pos += bytes_read;
+    }
+  }
+  return count;
+}
+
+
+ssize_t FDUtils::WriteToBlocking(int fd, const void* buffer, size_t count) {
+#ifdef DEBUG
+  bool is_blocking = false;
+  ASSERT(FDUtils::IsBlocking(fd, &is_blocking));
+  ASSERT(is_blocking);
+#endif
+  size_t remaining = count;
+  char* buffer_pos = const_cast<char*>(reinterpret_cast<const char*>(buffer));
+  while (remaining > 0) {
+    ssize_t bytes_written = NO_RETRY_EXPECTED(write(fd, buffer_pos, remaining));
+    if (bytes_written == 0) {
+      return count - remaining;
+    } else if (bytes_written == -1) {
+      ASSERT(EAGAIN == EWOULDBLOCK);
+      // Error code EWOULDBLOCK should only happen for non blocking
+      // file descriptors.
+      ASSERT(errno != EWOULDBLOCK);
+      return -1;
+    } else {
+      ASSERT(bytes_written > 0);
+      remaining -= bytes_written;
+      buffer_pos += bytes_written;
+    }
+  }
+  return count;
+}
+
+
+void FDUtils::SaveErrorAndClose(intptr_t fd) {
+  int err = errno;
+  NO_RETRY_EXPECTED(close(fd));
+  errno = err;
+}
+
+}  // namespace bin
+}  // namespace dart
+
+#endif  // defined(TARGET_OS_FUCHSIA)
diff --git a/runtime/bin/fdutils_linux.cc b/runtime/bin/fdutils_linux.cc
index 5a174ee..7f4598b 100644
--- a/runtime/bin/fdutils_linux.cc
+++ b/runtime/bin/fdutils_linux.cc
@@ -137,6 +137,13 @@
   return count;
 }
 
+
+void FDUtils::SaveErrorAndClose(intptr_t fd) {
+  int err = errno;
+  VOID_TEMP_FAILURE_RETRY(close(fd));
+  errno = err;
+}
+
 }  // namespace bin
 }  // namespace dart
 
diff --git a/runtime/bin/fdutils_macos.cc b/runtime/bin/fdutils_macos.cc
index ab1a603..4a0e3c0 100644
--- a/runtime/bin/fdutils_macos.cc
+++ b/runtime/bin/fdutils_macos.cc
@@ -137,6 +137,13 @@
   return count;
 }
 
+
+void FDUtils::SaveErrorAndClose(intptr_t fd) {
+  int err = errno;
+  VOID_TEMP_FAILURE_RETRY(close(fd));
+  errno = err;
+}
+
 }  // namespace bin
 }  // namespace dart
 
diff --git a/runtime/bin/run_vm_tests_fuchsia.cc b/runtime/bin/run_vm_tests_fuchsia.cc
index 0424f8a..71cf5c3 100644
--- a/runtime/bin/run_vm_tests_fuchsia.cc
+++ b/runtime/bin/run_vm_tests_fuchsia.cc
@@ -276,15 +276,13 @@
   RETURN_IF_ERROR(r);
 
   mx_info_process_t proc_info;
-  mx_size_t info_size;
-  mx_status_t status =
-      mx_object_get_info(p, MX_INFO_PROCESS, sizeof(proc_info.rec), &proc_info,
-                         sizeof(proc_info), &info_size);
+  mx_status_t status = mx_object_get_info(p, MX_INFO_PROCESS, &proc_info,
+                                          sizeof(proc_info), nullptr, nullptr);
   RETURN_IF_ERROR(status);
 
   r = mx_handle_close(p);
   RETURN_IF_ERROR(r);
-  return proc_info.rec.return_code;
+  return proc_info.return_code;
 }
 
 
diff --git a/runtime/bin/socket_android.cc b/runtime/bin/socket_android.cc
index 07e6894..08e49be 100644
--- a/runtime/bin/socket_android.cc
+++ b/runtime/bin/socket_android.cc
@@ -25,13 +25,6 @@
 namespace dart {
 namespace bin {
 
-static void SaveErrorAndClose(intptr_t fd) {
-  int err = errno;
-  VOID_TEMP_FAILURE_RETRY(close(fd));
-  errno = err;
-}
-
-
 SocketAddress::SocketAddress(struct sockaddr* sa) {
   ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
   if (!Socket::FormatNumericAddress(*reinterpret_cast<RawAddr*>(sa), as_string_,
@@ -63,7 +56,7 @@
     return -1;
   }
   if (!FDUtils::SetCloseOnExec(fd)) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
   return fd;
@@ -76,7 +69,7 @@
   if ((result == 0) || (errno == EINPROGRESS)) {
     return fd;
   }
-  SaveErrorAndClose(fd);
+  FDUtils::SaveErrorAndClose(fd);
   return -1;
 }
 
@@ -88,7 +81,7 @@
   }
 
   if (!FDUtils::SetNonBlocking(fd)) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
   return Connect(fd, addr);
@@ -105,7 +98,7 @@
   intptr_t result = TEMP_FAILURE_RETRY(
       bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
   if ((result != 0) && (errno != EINPROGRESS)) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
 
@@ -323,7 +316,7 @@
   }
 
   if (!FDUtils::SetCloseOnExec(fd)) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
 
@@ -335,12 +328,12 @@
 
   if (NO_RETRY_EXPECTED(
           bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
 
   if (!FDUtils::SetNonBlocking(fd)) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
   return fd;
@@ -377,7 +370,7 @@
   }
 
   if (!FDUtils::SetCloseOnExec(fd)) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
 
@@ -393,7 +386,7 @@
 
   if (NO_RETRY_EXPECTED(
           bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
 
@@ -403,17 +396,17 @@
     // Don't close the socket until we have created a new socket, ensuring
     // that we do not get the bad port number again.
     intptr_t new_fd = CreateBindListen(addr, backlog, v6_only);
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return new_fd;
   }
 
   if (NO_RETRY_EXPECTED(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
 
   if (!FDUtils::SetNonBlocking(fd)) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
   return fd;
@@ -451,11 +444,11 @@
     }
   } else {
     if (!FDUtils::SetCloseOnExec(socket)) {
-      SaveErrorAndClose(socket);
+      FDUtils::SaveErrorAndClose(socket);
       return -1;
     }
     if (!FDUtils::SetNonBlocking(socket)) {
-      SaveErrorAndClose(socket);
+      FDUtils::SaveErrorAndClose(socket);
       return -1;
     }
   }
diff --git a/runtime/bin/socket_fuchsia.cc b/runtime/bin/socket_fuchsia.cc
index 7e8489b..a6498ce 100644
--- a/runtime/bin/socket_fuchsia.cc
+++ b/runtime/bin/socket_fuchsia.cc
@@ -10,56 +10,181 @@
 #include "bin/socket.h"
 #include "bin/socket_fuchsia.h"
 
+#include <errno.h>        // NOLINT
+#include <fcntl.h>        // NOLINT
+#include <ifaddrs.h>      // NOLINT
+#include <net/if.h>       // NOLINT
+#include <netinet/tcp.h>  // NOLINT
+#include <stdio.h>        // NOLINT
+#include <stdlib.h>       // NOLINT
+#include <string.h>       // NOLINT
+#include <sys/ioctl.h>    // NOLINT
+#include <sys/stat.h>     // NOLINT
+#include <unistd.h>       // NOLINT
+
+#include "bin/fdutils.h"
 #include "bin/file.h"
+#include "platform/signal_blocker.h"
+
+// #define SOCKET_LOG_INFO 1
+// #define SOCKET_LOG_ERROR 1
+
+// define SOCKET_LOG_ERROR to get log messages only for errors.
+// define SOCKET_LOG_INFO to get log messages for both information and errors.
+#if defined(SOCKET_LOG_INFO) || defined(SOCKET_LOG_ERROR)
+#define LOG_ERR(msg, ...)                                                      \
+  {                                                                            \
+    int err = errno;                                                           \
+    Log::PrintErr("Dart Socket ERROR: %s:%d: " msg, __FILE__, __LINE__,        \
+                  ##__VA_ARGS__);                                              \
+    errno = err;                                                               \
+  }
+#if defined(SOCKET_LOG_INFO)
+#define LOG_INFO(msg, ...)                                                     \
+  Log::Print("Dart Socket INFO: %s:%d: " msg, __FILE__, __LINE__, ##__VA_ARGS__)
+#else
+#define LOG_INFO(msg, ...)
+#endif  // defined(SOCKET_LOG_INFO)
+#else
+#define LOG_ERR(msg, ...)
+#define LOG_INFO(msg, ...)
+#endif  // defined(SOCKET_LOG_INFO) || defined(SOCKET_LOG_ERROR)
 
 namespace dart {
 namespace bin {
 
 SocketAddress::SocketAddress(struct sockaddr* sa) {
-  UNIMPLEMENTED();
+  ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
+  if (!Socket::FormatNumericAddress(*reinterpret_cast<RawAddr*>(sa), as_string_,
+                                    INET6_ADDRSTRLEN)) {
+    as_string_[0] = 0;
+  }
+  socklen_t salen = GetAddrLength(*reinterpret_cast<RawAddr*>(sa));
+  memmove(reinterpret_cast<void*>(&addr_), sa, salen);
 }
 
 
 bool Socket::FormatNumericAddress(const RawAddr& addr, char* address, int len) {
-  UNIMPLEMENTED();
-  return false;
+  socklen_t salen = SocketAddress::GetAddrLength(addr);
+  LOG_INFO("Socket::FormatNumericAddress: calling getnameinfo\n");
+  return (NO_RETRY_EXPECTED(getnameinfo(&addr.addr, salen, address, len, NULL,
+                                        0, NI_NUMERICHOST) == 0));
 }
 
 
 bool Socket::Initialize() {
-  UNIMPLEMENTED();
+  // Nothing to do on Fuchsia.
   return true;
 }
 
 
-intptr_t Socket::CreateConnect(const RawAddr& addr) {
-  UNIMPLEMENTED();
+static intptr_t Create(const RawAddr& addr) {
+  LOG_INFO("Create: calling socket(SOCK_STREAM)\n");
+  intptr_t fd = NO_RETRY_EXPECTED(socket(addr.ss.ss_family, SOCK_STREAM, 0));
+  if (fd < 0) {
+    LOG_ERR("Create: socket(SOCK_STREAM) failed\n");
+    return -1;
+  }
+  LOG_INFO("Create: socket(SOCK_STREAM) -> fd %ld\n", fd);
+  if (!FDUtils::SetCloseOnExec(fd)) {
+    LOG_ERR("Create: FDUtils::SetCloseOnExec(%ld) failed\n", fd);
+    FDUtils::SaveErrorAndClose(fd);
+    return -1;
+  }
+  return fd;
+}
+
+
+static intptr_t CheckConnect(intptr_t fd) {
+  int val;
+  socklen_t vallen = sizeof(val);
+  LOG_INFO("CheckConnect: calling getsockopt(%ld)\n", fd);
+  intptr_t result = getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &vallen);
+  if (result != 0) {
+    FATAL1("CheckConnect: getsockopt(%ld) failed\n", fd);
+  } else if (vallen != sizeof(val)) {
+    FATAL1("CheckConnect: getsockopt(%ld) vallen != sizeof(val)!?!?\n", fd);
+  } else if (val != 0) {
+    LOG_ERR("CheckConnect: getsockopt(%ld) val = %d\n", fd, val);
+    return val;
+  }
+  LOG_INFO("CheckConnect: getsockopt(%ld) connected\n", fd);
+  return 0;
+}
+
+
+static intptr_t Connect(intptr_t fd, const RawAddr& addr) {
+  LOG_INFO("Connect: calling connect(%ld)\n", fd);
+  intptr_t result = NO_RETRY_EXPECTED(
+      connect(fd, &addr.addr, SocketAddress::GetAddrLength(addr)));
+  if ((result == 0) || (errno == EINPROGRESS)) {
+    LOG_INFO("Connect: connect(%ld) succeeded\n", fd);
+    intptr_t error = 0;
+    // TODO(US-87): When the issue is resolved this check is no longer needed.
+    while ((error = CheckConnect(fd)) != 0) {
+      if (error != EINPROGRESS) {
+        errno = error;
+        FDUtils::SaveErrorAndClose(fd);
+        return -1;
+      }
+    }
+    return fd;
+  }
+  LOG_ERR("Connect: connect(%ld) failed\n", fd);
+  FDUtils::SaveErrorAndClose(fd);
   return -1;
 }
 
 
+intptr_t Socket::CreateConnect(const RawAddr& addr) {
+  intptr_t fd = Create(addr);
+  if (fd < 0) {
+    return fd;
+  }
+  if (!FDUtils::SetNonBlocking(fd)) {
+    LOG_ERR("CreateConnect: FDUtils::SetNonBlocking(%ld) failed\n", fd);
+    FDUtils::SaveErrorAndClose(fd);
+    return -1;
+  }
+  return Connect(fd, addr);
+}
+
+
 intptr_t Socket::CreateBindConnect(const RawAddr& addr,
                                    const RawAddr& source_addr) {
+  LOG_ERR("Socket::CreateBindConnect is unimplemented\n");
   UNIMPLEMENTED();
   return -1;
 }
 
 
 bool Socket::IsBindError(intptr_t error_number) {
-  UNIMPLEMENTED();
-  return false;
+  return error_number == EADDRINUSE || error_number == EADDRNOTAVAIL ||
+         error_number == EINVAL;
 }
 
 
 intptr_t Socket::Available(intptr_t fd) {
-  UNIMPLEMENTED();
-  return -1;
+  return FDUtils::AvailableBytes(fd);
 }
 
 
 intptr_t Socket::Read(intptr_t fd, void* buffer, intptr_t num_bytes) {
-  UNIMPLEMENTED();
-  return -1;
+  ASSERT(fd >= 0);
+  LOG_INFO("Socket::Read: calling read(%ld, %p, %ld)\n", fd, buffer, num_bytes);
+  ssize_t read_bytes = NO_RETRY_EXPECTED(read(fd, buffer, num_bytes));
+  ASSERT(EAGAIN == EWOULDBLOCK);
+  if ((read_bytes == -1) && (errno == EWOULDBLOCK)) {
+    // If the read would block we need to retry and therefore return 0
+    // as the number of bytes written.
+    read_bytes = 0;
+  } else if (read_bytes == -1) {
+    LOG_ERR("Socket::Read: read(%ld, %p, %ld) failed\n", fd, buffer, num_bytes);
+  } else {
+    LOG_INFO("Socket::Read: read(%ld, %p, %ld) succeeded\n", fd, buffer,
+             num_bytes);
+  }
+  return read_bytes;
 }
 
 
@@ -67,14 +192,30 @@
                           void* buffer,
                           intptr_t num_bytes,
                           RawAddr* addr) {
+  LOG_ERR("Socket::RecvFrom is unimplemented\n");
   UNIMPLEMENTED();
   return -1;
 }
 
 
 intptr_t Socket::Write(intptr_t fd, const void* buffer, intptr_t num_bytes) {
-  UNIMPLEMENTED();
-  return -1;
+  ASSERT(fd >= 0);
+  LOG_INFO("Socket::Write: calling write(%ld, %p, %ld)\n", fd, buffer,
+           num_bytes);
+  ssize_t written_bytes = NO_RETRY_EXPECTED(write(fd, buffer, num_bytes));
+  ASSERT(EAGAIN == EWOULDBLOCK);
+  if ((written_bytes == -1) && (errno == EWOULDBLOCK)) {
+    // If the would block we need to retry and therefore return 0 as
+    // the number of bytes written.
+    written_bytes = 0;
+  } else if (written_bytes == -1) {
+    LOG_ERR("Socket::Write: write(%ld, %p, %ld) failed\n", fd, buffer,
+            num_bytes);
+  } else {
+    LOG_INFO("Socket::Write: write(%ld, %p, %ld) succeeded\n", fd, buffer,
+             num_bytes);
+  }
+  return written_bytes;
 }
 
 
@@ -82,35 +223,46 @@
                         const void* buffer,
                         intptr_t num_bytes,
                         const RawAddr& addr) {
+  LOG_ERR("Socket::SendTo is unimplemented\n");
   UNIMPLEMENTED();
   return -1;
 }
 
 
 intptr_t Socket::GetPort(intptr_t fd) {
-  UNIMPLEMENTED();
-  return -1;
+  ASSERT(fd >= 0);
+  RawAddr raw;
+  socklen_t size = sizeof(raw);
+  LOG_INFO("Socket::GetPort: calling getsockname(%ld)\n", fd);
+  if (NO_RETRY_EXPECTED(getsockname(fd, &raw.addr, &size))) {
+    return 0;
+  }
+  return SocketAddress::GetAddrPort(raw);
 }
 
 
 SocketAddress* Socket::GetRemotePeer(intptr_t fd, intptr_t* port) {
+  LOG_ERR("Socket::GetRemotePeer is unimplemented\n");
   UNIMPLEMENTED();
   return NULL;
 }
 
 
 void Socket::GetError(intptr_t fd, OSError* os_error) {
+  LOG_ERR("Socket::GetError is unimplemented\n");
   UNIMPLEMENTED();
 }
 
 
 int Socket::GetType(intptr_t fd) {
+  LOG_ERR("Socket::GetType is unimplemented\n");
   UNIMPLEMENTED();
   return File::kOther;
 }
 
 
 intptr_t Socket::GetStdioHandle(intptr_t num) {
+  LOG_ERR("Socket::GetStdioHandle is unimplemented\n");
   UNIMPLEMENTED();
   return num;
 }
@@ -119,13 +271,45 @@
 AddressList<SocketAddress>* Socket::LookupAddress(const char* host,
                                                   int type,
                                                   OSError** os_error) {
-  // UNIMPLEMENTED
-  ASSERT(*os_error == NULL);
-  *os_error = new OSError(-1,
-                          "Socket::LookupAddress not implemented in "
-                          "Fuchsia Dart VM runtime",
-                          OSError::kGetAddressInfo);
-  return NULL;
+  // Perform a name lookup for a host name.
+  struct addrinfo hints;
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = SocketAddress::FromType(type);
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_flags = AI_ADDRCONFIG;
+  hints.ai_protocol = IPPROTO_TCP;
+  struct addrinfo* info = NULL;
+  LOG_INFO("Socket::LookupAddress: calling getaddrinfo\n");
+  int status = NO_RETRY_EXPECTED(getaddrinfo(host, 0, &hints, &info));
+  if (status != 0) {
+    // We failed, try without AI_ADDRCONFIG. This can happen when looking up
+    // e.g. '::1', when there are no global IPv6 addresses.
+    hints.ai_flags = 0;
+    LOG_INFO("Socket::LookupAddress: calling getaddrinfo again\n");
+    status = NO_RETRY_EXPECTED(getaddrinfo(host, 0, &hints, &info));
+    if (status != 0) {
+      ASSERT(*os_error == NULL);
+      *os_error =
+          new OSError(status, gai_strerror(status), OSError::kGetAddressInfo);
+      return NULL;
+    }
+  }
+  intptr_t count = 0;
+  for (struct addrinfo* c = info; c != NULL; c = c->ai_next) {
+    if ((c->ai_family == AF_INET) || (c->ai_family == AF_INET6)) {
+      count++;
+    }
+  }
+  intptr_t i = 0;
+  AddressList<SocketAddress>* addresses = new AddressList<SocketAddress>(count);
+  for (struct addrinfo* c = info; c != NULL; c = c->ai_next) {
+    if ((c->ai_family == AF_INET) || (c->ai_family == AF_INET6)) {
+      addresses->SetAt(i, new SocketAddress(c->ai_addr));
+      i++;
+    }
+  }
+  freeaddrinfo(info);
+  return addresses;
 }
 
 
@@ -133,18 +317,21 @@
                            char* host,
                            intptr_t host_len,
                            OSError** os_error) {
+  LOG_ERR("Socket::ReverseLookup is unimplemented\n");
   UNIMPLEMENTED();
   return false;
 }
 
 
 bool Socket::ParseAddress(int type, const char* address, RawAddr* addr) {
+  LOG_ERR("Socket::ParseAddress is unimplemented\n");
   UNIMPLEMENTED();
   return false;
 }
 
 
 intptr_t Socket::CreateBindDatagram(const RawAddr& addr, bool reuseAddress) {
+  LOG_ERR("Socket::CreateBindDatagram is unimplemented\n");
   UNIMPLEMENTED();
   return -1;
 }
@@ -166,71 +353,175 @@
 intptr_t ServerSocket::CreateBindListen(const RawAddr& addr,
                                         intptr_t backlog,
                                         bool v6_only) {
-  UNIMPLEMENTED();
-  return -1;
+  LOG_INFO("ServerSocket::CreateBindListen: calling socket(SOCK_STREAM)\n");
+  intptr_t fd = NO_RETRY_EXPECTED(socket(addr.ss.ss_family, SOCK_STREAM, 0));
+  if (fd < 0) {
+    LOG_ERR("ServerSocket::CreateBindListen: socket() failed\n");
+    return -1;
+  }
+  LOG_INFO("ServerSocket::CreateBindListen: socket(SOCK_STREAM) -> %ld\n", fd);
+
+  if (!FDUtils::SetCloseOnExec(fd)) {
+    LOG_ERR("ServerSocket::CreateBindListen: SetCloseOnExec(%ld) failed\n", fd);
+    FDUtils::SaveErrorAndClose(fd);
+    return -1;
+  }
+
+  LOG_INFO("ServerSocket::CreateBindListen: calling setsockopt(%ld)\n", fd);
+  int optval = 1;
+  VOID_NO_RETRY_EXPECTED(
+      setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
+
+  if (addr.ss.ss_family == AF_INET6) {
+    optval = v6_only ? 1 : 0;
+    LOG_INFO("ServerSocket::CreateBindListen: calling setsockopt(%ld)\n", fd);
+    VOID_NO_RETRY_EXPECTED(
+        setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)));
+  }
+
+  LOG_INFO("ServerSocket::CreateBindListen: calling bind(%ld)\n", fd);
+  if (NO_RETRY_EXPECTED(
+          bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) {
+    LOG_ERR("ServerSocket::CreateBindListen: bind(%ld) failed\n", fd);
+    FDUtils::SaveErrorAndClose(fd);
+    return -1;
+  }
+  LOG_INFO("ServerSocket::CreateBindListen: bind(%ld) succeeded\n", fd);
+
+  // Test for invalid socket port 65535 (some browsers disallow it).
+  if ((SocketAddress::GetAddrPort(addr) == 0) &&
+      (Socket::GetPort(fd) == 65535)) {
+    // Don't close the socket until we have created a new socket, ensuring
+    // that we do not get the bad port number again.
+    intptr_t new_fd = CreateBindListen(addr, backlog, v6_only);
+    FDUtils::SaveErrorAndClose(fd);
+    return new_fd;
+  }
+
+  LOG_INFO("ServerSocket::CreateBindListen: calling listen(%ld)\n", fd);
+  if (NO_RETRY_EXPECTED(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
+    LOG_ERR("ServerSocket::CreateBindListen: listen failed(%ld)\n", fd);
+    FDUtils::SaveErrorAndClose(fd);
+    return -1;
+  }
+  LOG_INFO("ServerSocket::CreateBindListen: listen(%ld) succeeded\n", fd);
+
+  if (!FDUtils::SetNonBlocking(fd)) {
+    LOG_ERR("CreateBindListen: FDUtils::SetNonBlocking(%ld) failed\n", fd);
+    FDUtils::SaveErrorAndClose(fd);
+    return -1;
+  }
+  return fd;
 }
 
 
 bool ServerSocket::StartAccept(intptr_t fd) {
-  UNIMPLEMENTED();
-  return false;
+  USE(fd);
+  return true;
+}
+
+
+static bool IsTemporaryAcceptError(int error) {
+  // On Linux a number of protocol errors should be treated as EAGAIN.
+  // These are the ones for TCP/IP.
+  return (error == EAGAIN) || (error == ENETDOWN) || (error == EPROTO) ||
+         (error == ENOPROTOOPT) || (error == EHOSTDOWN) || (error == ENONET) ||
+         (error == EHOSTUNREACH) || (error == EOPNOTSUPP) ||
+         (error == ENETUNREACH);
 }
 
 
 intptr_t ServerSocket::Accept(intptr_t fd) {
-  UNIMPLEMENTED();
-  return -1;
+  intptr_t socket;
+  struct sockaddr clientaddr;
+  socklen_t addrlen = sizeof(clientaddr);
+  LOG_INFO("ServerSocket::Accept: calling accept(%ld)\n", fd);
+  socket = NO_RETRY_EXPECTED(accept(fd, &clientaddr, &addrlen));
+  if (socket == -1) {
+    if (IsTemporaryAcceptError(errno)) {
+      // We need to signal to the caller that this is actually not an
+      // error. We got woken up from the poll on the listening socket,
+      // but there is no connection ready to be accepted.
+      ASSERT(kTemporaryFailure != -1);
+      socket = kTemporaryFailure;
+    } else {
+      LOG_ERR("ServerSocket::Accept: accept(%ld) failed\n", fd);
+    }
+  } else {
+    LOG_INFO("ServerSocket::Accept: accept(%ld) -> socket %ld\n", fd, socket);
+    if (!FDUtils::SetCloseOnExec(socket)) {
+      LOG_ERR("FDUtils::SetCloseOnExec(%ld) failed\n", socket);
+      FDUtils::SaveErrorAndClose(socket);
+      return -1;
+    }
+    if (!FDUtils::SetNonBlocking(socket)) {
+      LOG_ERR("FDUtils::SetNonBlocking(%ld) failed\n", socket);
+      FDUtils::SaveErrorAndClose(socket);
+      return -1;
+    }
+  }
+  return socket;
 }
 
 
 void Socket::Close(intptr_t fd) {
-  UNIMPLEMENTED();
+  ASSERT(fd >= 0);
+  NO_RETRY_EXPECTED(close(fd));
 }
 
 
 bool Socket::GetNoDelay(intptr_t fd, bool* enabled) {
+  LOG_ERR("Socket::GetNoDelay is unimplemented\n");
   UNIMPLEMENTED();
   return false;
 }
 
 
 bool Socket::SetNoDelay(intptr_t fd, bool enabled) {
-  UNIMPLEMENTED();
-  return false;
+  int on = enabled ? 1 : 0;
+  return NO_RETRY_EXPECTED(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
+                                      reinterpret_cast<char*>(&on),
+                                      sizeof(on))) == 0;
 }
 
 
 bool Socket::GetMulticastLoop(intptr_t fd, intptr_t protocol, bool* enabled) {
+  LOG_ERR("Socket::GetMulticastLoop is unimplemented\n");
   UNIMPLEMENTED();
   return false;
 }
 
 
 bool Socket::SetMulticastLoop(intptr_t fd, intptr_t protocol, bool enabled) {
+  LOG_ERR("Socket::SetMulticastLoop is unimplemented\n");
   UNIMPLEMENTED();
   return false;
 }
 
 
 bool Socket::GetMulticastHops(intptr_t fd, intptr_t protocol, int* value) {
+  LOG_ERR("Socket::GetMulticastHops is unimplemented\n");
   UNIMPLEMENTED();
   return false;
 }
 
 
 bool Socket::SetMulticastHops(intptr_t fd, intptr_t protocol, int value) {
+  LOG_ERR("Socket::SetMulticastHops is unimplemented\n");
   UNIMPLEMENTED();
   return false;
 }
 
 
 bool Socket::GetBroadcast(intptr_t fd, bool* enabled) {
+  LOG_ERR("Socket::GetBroadcast is unimplemented\n");
   UNIMPLEMENTED();
   return false;
 }
 
 
 bool Socket::SetBroadcast(intptr_t fd, bool enabled) {
+  LOG_ERR("Socket::SetBroadcast is unimplemented\n");
   UNIMPLEMENTED();
   return false;
 }
@@ -240,6 +531,7 @@
                            const RawAddr& addr,
                            const RawAddr&,
                            int interfaceIndex) {
+  LOG_ERR("Socket::JoinMulticast is unimplemented\n");
   UNIMPLEMENTED();
   return false;
 }
@@ -249,6 +541,7 @@
                             const RawAddr& addr,
                             const RawAddr&,
                             int interfaceIndex) {
+  LOG_ERR("Socket::LeaveMulticast is unimplemented\n");
   UNIMPLEMENTED();
   return false;
 }
diff --git a/runtime/bin/socket_fuchsia.h b/runtime/bin/socket_fuchsia.h
index 64c8545..a19df5d 100644
--- a/runtime/bin/socket_fuchsia.h
+++ b/runtime/bin/socket_fuchsia.h
@@ -9,4 +9,8 @@
 #error Do not include socket_fuchsia.h directly. Use socket.h.
 #endif
 
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+
 #endif  // RUNTIME_BIN_SOCKET_FUCHSIA_H_
diff --git a/runtime/bin/socket_linux.cc b/runtime/bin/socket_linux.cc
index e3d3103..af53878 100644
--- a/runtime/bin/socket_linux.cc
+++ b/runtime/bin/socket_linux.cc
@@ -28,13 +28,6 @@
 namespace dart {
 namespace bin {
 
-static void SaveErrorAndClose(intptr_t fd) {
-  int err = errno;
-  VOID_TEMP_FAILURE_RETRY(close(fd));
-  errno = err;
-}
-
-
 SocketAddress::SocketAddress(struct sockaddr* sa) {
   ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
   if (!Socket::FormatNumericAddress(*reinterpret_cast<RawAddr*>(sa), as_string_,
@@ -76,7 +69,7 @@
   if ((result == 0) || (errno == EINPROGRESS)) {
     return fd;
   }
-  SaveErrorAndClose(fd);
+  FDUtils::FDUtils::SaveErrorAndClose(fd);
   return -1;
 }
 
@@ -100,7 +93,7 @@
   intptr_t result = TEMP_FAILURE_RETRY(
       bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
   if ((result != 0) && (errno != EINPROGRESS)) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
 
@@ -329,7 +322,7 @@
 
   if (NO_RETRY_EXPECTED(
           bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
   return fd;
@@ -415,7 +408,7 @@
 
   if (NO_RETRY_EXPECTED(
           bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
 
@@ -425,12 +418,12 @@
     // Don't close the socket until we have created a new socket, ensuring
     // that we do not get the bad port number again.
     intptr_t new_fd = CreateBindListen(addr, backlog, v6_only);
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return new_fd;
   }
 
   if (NO_RETRY_EXPECTED(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
 
@@ -469,11 +462,11 @@
     }
   } else {
     if (!FDUtils::SetCloseOnExec(socket)) {
-      SaveErrorAndClose(socket);
+      FDUtils::SaveErrorAndClose(socket);
       return -1;
     }
     if (!FDUtils::SetNonBlocking(socket)) {
-      SaveErrorAndClose(socket);
+      FDUtils::SaveErrorAndClose(socket);
       return -1;
     }
   }
diff --git a/runtime/bin/socket_macos.cc b/runtime/bin/socket_macos.cc
index 4d0f53d..c1f48cc 100644
--- a/runtime/bin/socket_macos.cc
+++ b/runtime/bin/socket_macos.cc
@@ -27,13 +27,6 @@
 namespace dart {
 namespace bin {
 
-static void SaveErrorAndClose(intptr_t fd) {
-  int err = errno;
-  VOID_TEMP_FAILURE_RETRY(close(fd));
-  errno = err;
-}
-
-
 SocketAddress::SocketAddress(struct sockaddr* sa) {
   ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
   if (!Socket::FormatNumericAddress(*reinterpret_cast<RawAddr*>(sa), as_string_,
@@ -65,11 +58,11 @@
     return -1;
   }
   if (!FDUtils::SetCloseOnExec(fd)) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
   if (!FDUtils::SetNonBlocking(fd)) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
   return fd;
@@ -82,7 +75,7 @@
   if ((result == 0) || (errno == EINPROGRESS)) {
     return fd;
   }
-  SaveErrorAndClose(fd);
+  FDUtils::SaveErrorAndClose(fd);
   return -1;
 }
 
@@ -107,7 +100,7 @@
   intptr_t result = TEMP_FAILURE_RETRY(
       bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
   if ((result != 0) && (errno != EINPROGRESS)) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
 
@@ -318,7 +311,7 @@
   }
 
   if (!FDUtils::SetCloseOnExec(fd)) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
 
@@ -330,12 +323,12 @@
 
   if (NO_RETRY_EXPECTED(
           bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
 
   if (!FDUtils::SetNonBlocking(fd)) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
   return fd;
@@ -409,7 +402,7 @@
   }
 
   if (!FDUtils::SetCloseOnExec(fd)) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
 
@@ -425,7 +418,7 @@
 
   if (NO_RETRY_EXPECTED(
           bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
 
@@ -435,17 +428,17 @@
     // Don't close the socket until we have created a new socket, ensuring
     // that we do not get the bad port number again.
     intptr_t new_fd = CreateBindListen(addr, backlog, v6_only);
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return new_fd;
   }
 
   if (NO_RETRY_EXPECTED(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
 
   if (!FDUtils::SetNonBlocking(fd)) {
-    SaveErrorAndClose(fd);
+    FDUtils::SaveErrorAndClose(fd);
     return -1;
   }
   return fd;
@@ -473,11 +466,11 @@
     }
   } else {
     if (!FDUtils::SetCloseOnExec(socket)) {
-      SaveErrorAndClose(socket);
+      FDUtils::SaveErrorAndClose(socket);
       return -1;
     }
     if (!FDUtils::SetNonBlocking(socket)) {
-      SaveErrorAndClose(socket);
+      FDUtils::SaveErrorAndClose(socket);
       return -1;
     }
   }
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 1a09f7b..a085a72 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -2734,7 +2734,8 @@
  * Dart_kScriptTag
  *
  * This tag indicates that the root script should be loaded from
- * 'url'.  The 'library' parameter will always be null.  Once the root
+ * 'url'.  If the 'library' parameter is not null, it is the url of the
+ * package map that should be used when loading.  Once the root
  * script is loaded, the embedder should call Dart_LoadScript to
  * install the root script in the VM.  The return value should be an
  * error or null.
@@ -2753,9 +2754,10 @@
  * call Dart_LoadLibrary to provide the script source to the VM.  The
  * return value should be an error or null.
  */
-typedef Dart_Handle (*Dart_LibraryTagHandler)(Dart_LibraryTag tag,
-                                              Dart_Handle library,
-                                              Dart_Handle url);
+typedef Dart_Handle (*Dart_LibraryTagHandler)(
+    Dart_LibraryTag tag,
+    Dart_Handle library_or_package_map_url,
+    Dart_Handle url);
 
 /**
  * Sets library tag handler for the current isolate. This handler is
diff --git a/runtime/lib/regexp.cc b/runtime/lib/regexp.cc
index 7a50561..8779573 100644
--- a/runtime/lib/regexp.cc
+++ b/runtime/lib/regexp.cc
@@ -78,19 +78,34 @@
 }
 
 
-DEFINE_NATIVE_ENTRY(RegExp_ExecuteMatch, 3) {
-  // This function is intrinsified. See Intrinsifier::RegExp_ExecuteMatch.
+static RawObject* ExecuteMatch(Zone* zone,
+                               NativeArguments* arguments,
+                               bool sticky) {
   const RegExp& regexp = RegExp::CheckedHandle(arguments->NativeArgAt(0));
   ASSERT(!regexp.IsNull());
   GET_NON_NULL_NATIVE_ARGUMENT(String, subject, arguments->NativeArgAt(1));
   GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_index, arguments->NativeArgAt(2));
 
-  if (FLAG_interpret_irregexp || FLAG_precompiled_runtime) {
+  if (FLAG_interpret_irregexp) {
     return BytecodeRegExpMacroAssembler::Interpret(regexp, subject, start_index,
-                                                   zone);
+                                                   /*sticky=*/sticky, zone);
   }
 
-  return IRRegExpMacroAssembler::Execute(regexp, subject, start_index, zone);
+  return IRRegExpMacroAssembler::Execute(regexp, subject, start_index,
+                                         /*sticky=*/sticky, zone);
 }
 
+
+DEFINE_NATIVE_ENTRY(RegExp_ExecuteMatch, 3) {
+  // This function is intrinsified. See Intrinsifier::RegExp_ExecuteMatch.
+  return ExecuteMatch(zone, arguments, /*sticky=*/false);
+}
+
+
+DEFINE_NATIVE_ENTRY(RegExp_ExecuteMatchSticky, 3) {
+  // This function is intrinsified. See Intrinsifier::RegExp_ExecuteMatchSticky.
+  return ExecuteMatch(zone, arguments, /*sticky=*/true);
+}
+
+
 }  // namespace dart
diff --git a/runtime/lib/regexp_patch.dart b/runtime/lib/regexp_patch.dart
index a9ccd55..0c93204 100644
--- a/runtime/lib/regexp_patch.dart
+++ b/runtime/lib/regexp_patch.dart
@@ -160,11 +160,8 @@
     if (start < 0 || start > string.length) {
       throw new RangeError.range(start, 0, string.length);
     }
-    // Inefficient check that searches for a later match too.
-    // Change this when possible.
-    List<int> list = _ExecuteMatch(string, start);
+    List<int> list = _ExecuteMatchSticky(string, start);
     if (list == null) return null;
-    if (list[0] != start) return null;
     return new _RegExpMatch(this, string, list);
   }
 
@@ -238,6 +235,9 @@
 
   List _ExecuteMatch(String str, int start_index)
       native "RegExp_ExecuteMatch";
+
+  List _ExecuteMatchSticky(String str, int start_index)
+      native "RegExp_ExecuteMatchSticky";
 }
 
 class _AllMatchesIterable extends IterableBase<Match> {
diff --git a/runtime/observatory/HACKING.md b/runtime/observatory/HACKING.md
index e8c5500..fe47693 100644
--- a/runtime/observatory/HACKING.md
+++ b/runtime/observatory/HACKING.md
@@ -185,7 +185,7 @@
 See: __Run existing tests__
 
 [build_sdk]: https://github.com/dart-lang/sdk/wiki/Building "Building the Dart SDK"
-[download_dartium]: https://www.dartlang.org/tools/dartium/ "Download Dartium"
+[download_dartium]: https://webdev.dartlang.org/tools/dartium/ "Download Dartium"
 [build_dartium]: https://github.com/dart-lang/sdk/wiki/Building-Dartium "Build Dartium"
 [open_observatory]: http://localhost:8080/ "Open Observatory"
 [observatory_get_started]: https://dart-lang.github.io/observatory/get-started.html "Observatory get started"
diff --git a/runtime/observatory/lib/src/elements/view_footer.dart b/runtime/observatory/lib/src/elements/view_footer.dart
index f85b1d9..cd8cd94 100644
--- a/runtime/observatory/lib/src/elements/view_footer.dart
+++ b/runtime/observatory/lib/src/elements/view_footer.dart
@@ -40,7 +40,7 @@
   void render() {
     children = [
       new AnchorElement()
-        ..href = 'https://www.dartlang.org/tools/observatory'
+        ..href = 'https://dart-lang.github.io/observatory/'
         ..text = 'View documentation',
       new AnchorElement()
         ..href =
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index e0f6e05..c638dd9 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -1333,9 +1333,19 @@
     return invokeRpc('getSourceReport', params);
   }
 
-  Future<ServiceMap> reloadSources() {
-    return invokeRpc('_reloadSources', {}).then((_) {
+  Future<ServiceMap> reloadSources(
+      {String rootLibUri,
+       bool pause}) {
+    Map<String, dynamic> params = <String, dynamic>{};
+    if (rootLibUri != null) {
+      params['rootLibUri'] = rootLibUri;
+    }
+    if (pause != null) {
+      params['pause'] = pause;
+    }
+    return invokeRpc('reloadSources', params).then((result) {
       reloading = true;
+      return result;
     });
   }
 
diff --git a/runtime/observatory/tests/service/complex_reload/v1/main.dart b/runtime/observatory/tests/service/complex_reload/v1/main.dart
new file mode 100644
index 0000000..055565f
--- /dev/null
+++ b/runtime/observatory/tests/service/complex_reload/v1/main.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--error_on_bad_type --error_on_bad_override
+
+import 'dart:isolate';
+
+test() => 'apple';
+
+main() {
+  RawReceivePort keepAlive = new RawReceivePort();
+  print('slave isolate running');
+}
+
diff --git a/runtime/observatory/tests/service/complex_reload/v2/main.dart b/runtime/observatory/tests/service/complex_reload/v2/main.dart
new file mode 100644
index 0000000..b0cc841
--- /dev/null
+++ b/runtime/observatory/tests/service/complex_reload/v2/main.dart
@@ -0,0 +1,6 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--error_on_bad_type --error_on_bad_override
+
+test() => 'banana';
diff --git a/runtime/observatory/tests/service/complex_reload/v3/main.dart b/runtime/observatory/tests/service/complex_reload/v3/main.dart
new file mode 100644
index 0000000..751ca96
--- /dev/null
+++ b/runtime/observatory/tests/service/complex_reload/v3/main.dart
@@ -0,0 +1,6 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--error_on_bad_type --error_on_bad_override
+
+test() => 'cabbage';
diff --git a/runtime/observatory/tests/service/complex_reload_test.dart b/runtime/observatory/tests/service/complex_reload_test.dart
new file mode 100644
index 0000000..0b94084
--- /dev/null
+++ b/runtime/observatory/tests/service/complex_reload_test.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--error_on_bad_type --error_on_bad_override
+
+import 'test_helper.dart';
+import 'dart:async';
+import 'dart:developer';
+import 'dart:isolate' as I;
+import 'dart:io';
+import 'service_test_common.dart';
+import 'package:observatory/service.dart';
+import 'package:unittest/unittest.dart';
+
+testMain() async {
+  debugger();  // Stop here.
+  // Spawn the child isolate.
+  I.Isolate isolate =
+      await I.Isolate.spawnUri(Uri.parse('complex_reload/v1/main.dart'),
+                               [],
+                               null);
+  print(isolate);
+  debugger();
+}
+
+// Directory that we are running in.
+String directory = (Platform.isWindows ? '' : Platform.pathSeparator) +
+    Platform.script.pathSegments.sublist(
+        0,
+        Platform.script.pathSegments.length - 1).join(Platform.pathSeparator);
+
+Future<String> invokeTest(Isolate isolate) async {
+  await isolate.reload();
+  Library lib = isolate.rootLibrary;
+  await lib.load();
+  Instance result = await lib.evaluate('test()');
+  expect(result.isString, isTrue);
+  return result.valueAsString;
+}
+
+var tests = [
+  // Stopped at 'debugger' statement.
+  hasStoppedAtBreakpoint,
+  // Resume the isolate into the while loop.
+  resumeIsolate,
+  // Stop at 'debugger' statement.
+  hasStoppedAtBreakpoint,
+  (Isolate mainIsolate) async {
+    // Grab the VM.
+    VM vm = mainIsolate.vm;
+    await vm.reloadIsolates();
+    expect(vm.isolates.length, 2);
+
+    // Find the slave isolate.
+    Isolate slaveIsolate =
+        vm.isolates.firstWhere((Isolate i) => i != mainIsolate);
+    expect(slaveIsolate, isNotNull);
+
+    // Invoke test in v1.
+    String v1 = await invokeTest(slaveIsolate);
+    expect(v1, 'apple');
+
+    // Reload to v2.
+    var response = await slaveIsolate.reloadSources(
+       rootLibUri: '$directory/complex_reload/v2/main.dart',
+    );
+    expect(response['success'], isTrue);
+
+    // Invoke test in v2.
+    String v2 = await invokeTest(slaveIsolate);
+    expect(v2, 'banana');
+
+    // Reload to v3.
+    response = await slaveIsolate.reloadSources(
+      rootLibUri: '$directory/complex_reload/v3/main.dart',
+    );
+    expect(response['success'], isTrue);
+
+    // Invoke test in v3.
+    String v3 = await invokeTest(slaveIsolate);
+    expect(v3, 'cabbage');
+  }
+];
+
+main(args) => runIsolateTests(args, tests, testeeConcurrent: testMain);
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
index 638f447..52be6ac 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -70,6 +70,7 @@
 [ $system == windows ]
 dev_fs_weird_char_test: Skip # Windows disallows question mark in paths
 dev_fs_http_put_weird_char_test: Skip # Windows disallows carriage returns in paths
+complex_reload_test: Skip # Issue 27861
 
 # Service protocol is not supported in product mode.
 [ $mode == product ]
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index 231464c..101200b 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -142,6 +142,10 @@
 #error DART_PRECOMPILED_RUNTIME and DART_PRECOMPILER are mutually exclusive
 #endif  // defined(DART_PRECOMPILED_RUNTIME) && defined(DART_PRECOMPILER)
 
+#if defined(DART_PRECOMPILED_RUNTIME) && defined(DART_NOSNAPSHOT)
+#error DART_PRECOMPILED_RUNTIME and DART_NOSNAPSHOT are mutually exclusive
+#endif  // defined(DART_PRECOMPILED_RUNTIME) && defined(DART_NOSNAPSHOT)
+
 #if defined(DART_PRECOMPILED_RUNTIME)
 #define NOT_IN_PRECOMPILED(code)
 #else
diff --git a/runtime/tests/vm/dart/hello_fuchsia_test.dart b/runtime/tests/vm/dart/hello_fuchsia_test.dart
index 501ffe7..9ed439b 100644
--- a/runtime/tests/vm/dart/hello_fuchsia_test.dart
+++ b/runtime/tests/vm/dart/hello_fuchsia_test.dart
@@ -2,6 +2,216 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-main() {
+import "dart:async";
+import "dart:io";
+
+testSimpleBind() async {
+  var s = await RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0);
+  print("port = ${s.port}");
+  await s.close();
+}
+
+testSimpleConnect() async {
+  var server = await RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0);
+  print("server port = ${server.port}");
+  server.listen((socket) {
+    print("listen socket port = ${socket.port}");
+    socket.close();
+  });
+  var socket = await RawSocket.connect("127.0.0.1", server.port);
+  print("socket port = ${socket.port}");
+  await server.close();
+  await socket.close();
+}
+
+testSimpleReadWrite({bool dropReads}) async {
+  // This test creates a server and a client connects. The client then
+  // writes and the server echos. When the server has finished its
+  // echo it half-closes. When the client gets the close event is
+  // closes fully.
+
+  const messageSize = 1000;
+  int serverReadCount = 0;
+  int clientReadCount = 0;
+
+  List<int> createTestData() {
+    return new List<int>.generate(messageSize, (index) => index & 0xff);
+  }
+
+  void verifyTestData(List<int> data) {
+    assert(messageSize == data.length);
+    List<int> expected = createTestData();
+    for (int i = 0; i < messageSize; i++) {
+      assert(expected[i] == data[i]);
+    }
+  }
+
+  var server = await RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0);
+  server.listen((client) {
+    int bytesRead = 0;
+    int bytesWritten = 0;
+    bool closedEventReceived = false;
+    List<int> data = new List<int>(messageSize);
+    bool doneReading = false;
+
+    client.writeEventsEnabled = false;
+    client.listen((event) {
+      switch (event) {
+        case RawSocketEvent.READ:
+          if (doneReading) {
+            break;
+          }
+          if (dropReads) {
+            if (serverReadCount != 10) {
+              serverReadCount++;
+              break;
+            } else {
+              serverReadCount = 0;
+            }
+          }
+          print("client READ event bytesRead = $bytesRead");
+          assert(bytesWritten == 0);
+          assert(client.available() > 0);
+          var buffer = client.read(200);
+          print("client READ event: read ${buffer.length} more bytes");
+          data.setRange(bytesRead, bytesRead + buffer.length, buffer);
+          bytesRead += buffer.length;
+          if (bytesRead == data.length) {
+            verifyTestData(data);
+            print("client READ event. Done reading, enabling writes");
+            client.writeEventsEnabled = true;
+            doneReading = true;
+          }
+          break;
+        case RawSocketEvent.WRITE:
+          assert(!client.writeEventsEnabled);
+          bytesWritten += client.write(
+              data, bytesWritten, data.length - bytesWritten);
+          print("client WRITE event: $bytesWritten written");
+          if (bytesWritten < data.length) {
+            client.writeEventsEnabled = true;
+          }
+          if (bytesWritten == data.length) {
+            print("client WRITE event: done writing.");
+            client.shutdown(SocketDirection.SEND);
+          }
+          break;
+        case RawSocketEvent.READ_CLOSED:
+          print("client READ_CLOSED event");
+          server.close();
+          break;
+        case RawSocketEvent.CLOSED:
+          assert(!closedEventReceived);
+          print("client CLOSED event");
+          closedEventReceived = true;
+          break;
+        default: throw "Unexpected event $event";
+      }
+    },
+    onDone: () {assert(closedEventReceived);});
+  });
+
+  {
+    var completer = new Completer();
+    var socket = await RawSocket.connect("127.0.0.1", server.port);
+    int bytesRead = 0;
+    int bytesWritten = 0;
+    bool closedEventReceived = false;
+    List<int> data = createTestData();
+
+    socket.listen((event) {
+      switch (event) {
+        case RawSocketEvent.READ:
+          assert(socket.available() > 0);
+          if (dropReads) {
+            if (clientReadCount != 10) {
+              clientReadCount++;
+              break;
+            } else {
+              clientReadCount = 0;
+            }
+          }
+          print("server READ event: ${bytesRead} read");
+          var buffer = socket.read();
+          print("server READ event: read ${buffer.length} more bytes");
+          data.setRange(bytesRead, bytesRead + buffer.length, buffer);
+          bytesRead += buffer.length;
+          break;
+        case RawSocketEvent.WRITE:
+          assert(bytesRead == 0);
+          assert(!socket.writeEventsEnabled);
+          bytesWritten += socket.write(
+              data, bytesWritten, data.length - bytesWritten);
+          print("server WRITE event: ${bytesWritten} written");
+          if (bytesWritten < data.length) {
+            socket.writeEventsEnabled = true;
+          } else {
+            print("server WRITE event: done writing");
+            data = new List<int>(messageSize);
+          }
+          break;
+        case RawSocketEvent.READ_CLOSED:
+          print("server READ_CLOSED event");
+          verifyTestData(data);
+          socket.close();
+          break;
+        case RawSocketEvent.CLOSED:
+          assert(!closedEventReceived);
+          print("server CLOSED event");
+          closedEventReceived = true;
+          break;
+        default: throw "Unexpected event $event";
+      }
+    },
+    onDone: () {
+      assert(closedEventReceived);
+      completer.complete(null);
+    });
+
+    return completer.future;
+  }
+}
+
+Future testGoogleUrl(SecurityContext context, String outcome) async {
+  var client = new HttpClient(context: context);
+  // We need to use an external server that is backed by a
+  // built-in root certificate authority.
+  try {
+    // First, check if the lookup works.
+    await InternetAddress.lookup('www.google.com');
+    var request = await client.getUrl(Uri.parse('http://www.google.com'));
+    request.followRedirects = false;
+    var response = await request.close();
+    assert('pass' == outcome);
+    try { await response.drain(); } catch (e) {
+      print('drain failed: $e');
+    }
+  } catch (e) {
+    // Lookup failed or connection failed.  Don't report a failure.
+    print("SocketException: $e");
+  } finally {
+    client.close();
+  }
+}
+
+main() async {
   print("Hello, Fuchsia!");
+
+  print("testSimpleBind");
+  await testSimpleBind();
+  print("testSimpleBind done");
+
+  print("testSimpleConnect");
+  await testSimpleConnect();
+  print("testSimpleConnect done");
+
+  // print("testSimpleReadWrite");
+  // await testSimpleReadWrite(dropReads: false);
+  // print("testSimpleReadWrite done");
+
+  // print("testGoogleUrl");
+  // await testGoogleUrl(null, 'pass');
+  // print("testGoogleUrl done");
+
+  print("Goodbyte, Fuchsia!");
 }
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 61d2bac..20ba97a 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -163,3 +163,6 @@
 [ $hot_reload || $hot_reload_rollback ]
 dart/spawn_shutdown_test: Skip # We can shutdown an isolate before it reloads.
 dart/spawn_infinite_loop_test: Skip # We can shutdown an isolate before it reloads.
+
+[ $runtime == dartium ]
+dart/hello_fuchsia_test: Fail # Issue 27867
diff --git a/runtime/vm/BUILD.gn b/runtime/vm/BUILD.gn
index 8e47ef7..9bbc3a4 100644
--- a/runtime/vm/BUILD.gn
+++ b/runtime/vm/BUILD.gn
@@ -90,7 +90,6 @@
   configs += [
     "..:dart_config",
     "..:dart_maybe_product_config",
-    "..:dart_maybe_precompiled_runtime_config",
     "..:dart_no_snapshot_config",
   ]
   public_configs = [ ":libdart_vm_config" ]
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index 5b4c20f..a354ddc 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -321,8 +321,8 @@
                                      const uint8_t* buffer,
                                      intptr_t buffer_size) {
   Zone* zone = thread->zone();
-  kernel::Program* program =
-      ReadPrecompiledKernelFromBuffer(buffer, buffer_size);
+  kernel::KernelReader reader(buffer, buffer_size, true);
+  kernel::Program* program = reader.ReadPrecompiledProgram();
   if (program == NULL) {
     const String& message =
         String::Handle(zone, String::New("Failed to read Kernel file"));
@@ -343,7 +343,6 @@
   Library& library = Library::Handle(zone);
   String& dart_name = String::Handle(zone);
   String& kernel_name = String::Handle(zone);
-  kernel::KernelReader reader(NULL, -1, true);
   for (intptr_t i = 0; i < kBootstrapLibraryCount; ++i) {
     ObjectStore::BootstrapLibraryId id = bootstrap_libraries[i].index;
     library = isolate->object_store()->bootstrap_library(id);
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 7ae1810..536299c 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -112,6 +112,7 @@
   V(RegExp_getIsCaseSensitive, 1)                                              \
   V(RegExp_getGroupCount, 1)                                                   \
   V(RegExp_ExecuteMatch, 3)                                                    \
+  V(RegExp_ExecuteMatchSticky, 3)                                              \
   V(List_allocate, 2)                                                          \
   V(List_getIndexed, 2)                                                        \
   V(List_setIndexed, 3)                                                        \
diff --git a/runtime/vm/bootstrap_nocore.cc b/runtime/vm/bootstrap_nocore.cc
index d804b24..9fda4b3 100644
--- a/runtime/vm/bootstrap_nocore.cc
+++ b/runtime/vm/bootstrap_nocore.cc
@@ -59,8 +59,8 @@
                               const uint8_t* buffer,
                               intptr_t buffer_length) {
   Zone* zone = thread->zone();
-  kernel::Program* program =
-      ReadPrecompiledKernelFromBuffer(buffer, buffer_length);
+  kernel::KernelReader reader(buffer, buffer_length, true);
+  kernel::Program* program = reader.ReadPrecompiledProgram();
   if (program == NULL) {
     const String& message =
         String::Handle(zone, String::New("Failed to read Kernel file"));
@@ -81,7 +81,6 @@
   Library& library = Library::Handle(zone);
   String& dart_name = String::Handle(zone);
   String& kernel_name = String::Handle(zone);
-  kernel::KernelReader reader(NULL, -1, true);
   for (intptr_t i = 0; i < bootstrap_library_count; ++i) {
     ObjectStore::BootstrapLibraryId id = bootstrap_libraries[i].index;
     library = isolate->object_store()->bootstrap_library(id);
diff --git a/runtime/vm/cpu_arm.cc b/runtime/vm/cpu_arm.cc
index 16f2e18..e5a1dd9 100644
--- a/runtime/vm/cpu_arm.cc
+++ b/runtime/vm/cpu_arm.cc
@@ -207,14 +207,15 @@
   // - Qualcomm Krait CPUs (QCT APQ8064) in Nexus 4 and 7 incorrectly report
   //   that they lack integer division.
   // - Marvell Armada 370/XP incorrectly reports that it has integer division.
-  // - The Pixel lacks integer division even though ARMv8 requires it in A32.
+  // - Qualcomm Snapdragon 820/821 CPUs (MSM 8996 and MSM8996pro) in Xiaomi MI5
+  // and Pixel lack integer division even though ARMv8 requires it in A32.
   bool is_krait = CpuInfo::FieldContains(kCpuInfoHardware, "QCT APQ8064");
   bool is_armada_370xp =
       CpuInfo::FieldContains(kCpuInfoHardware, "Marvell Armada 370/XP");
-  bool is_pixel = CpuInfo::FieldContains(kCpuInfoHardware, "MSM8996pro");
+  bool is_snapdragon = CpuInfo::FieldContains(kCpuInfoHardware, "MSM8996");
   if (is_krait) {
     integer_division_supported_ = FLAG_use_integer_division;
-  } else if (is_armada_370xp || is_pixel) {
+  } else if (is_armada_370xp || is_snapdragon) {
     integer_division_supported_ = false;
   } else {
     integer_division_supported_ =
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index e5cf6ae..e58810d 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -5094,7 +5094,7 @@
         }
       }
     }
-    // Check for default VM provided values. If it was not overriden on the
+    // Check for default VM provided values. If it was not overridden on the
     // command line.
     if (Symbols::DartIsVM().Equals(name)) {
       return Symbols::True().raw();
@@ -6326,15 +6326,16 @@
 
 DART_EXPORT Dart_Handle
 Dart_Precompile(Dart_QualifiedFunctionName entry_points[], bool reset_fields) {
-  UNREACHABLE();
-  return 0;
+  return Api::NewError(
+      "This VM was built without support for AOT compilation.");
 }
 
 
 DART_EXPORT Dart_Handle
 Dart_CreatePrecompiledSnapshotAssembly(uint8_t** assembly_buffer,
                                        intptr_t* assembly_size) {
-  UNREACHABLE();
+  return Api::NewError(
+      "This VM was built without support for AOT compilation.");
   return 0;
 }
 
@@ -6348,8 +6349,8 @@
                                    intptr_t* instructions_blob_size,
                                    uint8_t** rodata_blob_buffer,
                                    intptr_t* rodata_blob_size) {
-  UNREACHABLE();
-  return 0;
+  return Api::NewError(
+      "This VM was built without support for AOT compilation.");
 }
 
 #else  // DART_PRECOMPILER
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 4b73efd..f1334b8 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -381,12 +381,11 @@
   Instance& stacktrace = Instance::Handle(zone);
   bool handler_exists = false;
   bool handler_needs_stacktrace = false;
+  // Find the exception handler and determine if the handler needs a
+  // stacktrace.
+  handler_exists = FindExceptionHandler(thread, &handler_pc, &handler_sp,
+                                        &handler_fp, &handler_needs_stacktrace);
   if (use_preallocated_stacktrace) {
-    stacktrace ^= isolate->object_store()->preallocated_stack_trace();
-    PreallocatedStacktraceBuilder frame_builder(stacktrace);
-    handler_exists =
-        FindExceptionHandler(thread, &handler_pc, &handler_sp, &handler_fp,
-                             &handler_needs_stacktrace);
     if (handler_pc == 0) {
       // No Dart frame.
       ASSERT(incoming_exception.raw() ==
@@ -396,37 +395,33 @@
       thread->long_jump_base()->Jump(1, error);
       UNREACHABLE();
     }
+    stacktrace ^= isolate->object_store()->preallocated_stack_trace();
+    PreallocatedStacktraceBuilder frame_builder(stacktrace);
     if (handler_needs_stacktrace) {
       BuildStackTrace(&frame_builder);
     }
   } else {
-    // Get stacktrace field of class Error. This is needed to determine whether
-    // we have a subclass of Error which carries around its stack trace.
-    const Field& stacktrace_field =
-        Field::Handle(zone, LookupStacktraceField(exception));
-
-    // Find the exception handler and determine if the handler needs a
-    // stacktrace.
-    handler_exists =
-        FindExceptionHandler(thread, &handler_pc, &handler_sp, &handler_fp,
-                             &handler_needs_stacktrace);
     if (!existing_stacktrace.IsNull()) {
       // If we have an existing stack trace then this better be a rethrow. The
       // reverse is not necessarily true (e.g. Dart_PropagateError can cause
       // a rethrow being called without an existing stacktrace.)
       ASSERT(is_rethrow);
-      ASSERT(stacktrace_field.IsNull() ||
-             (exception.GetField(stacktrace_field) != Object::null()));
       stacktrace = existing_stacktrace.raw();
-    } else if (!stacktrace_field.IsNull() || handler_needs_stacktrace) {
-      // Collect the stacktrace if needed.
-      ASSERT(existing_stacktrace.IsNull());
-      stacktrace = Exceptions::CurrentStacktrace();
-      // If we have an Error object, then set its stackTrace field only if it
-      // not yet initialized.
-      if (!stacktrace_field.IsNull() &&
-          (exception.GetField(stacktrace_field) == Object::null())) {
-        exception.SetField(stacktrace_field, stacktrace);
+    } else {
+      // Get stacktrace field of class Error to determine whether we have a
+      // subclass of Error which carries around its stack trace.
+      const Field& stacktrace_field =
+          Field::Handle(zone, LookupStacktraceField(exception));
+      if (!stacktrace_field.IsNull() || handler_needs_stacktrace) {
+        // Collect the stacktrace if needed.
+        ASSERT(existing_stacktrace.IsNull());
+        stacktrace = Exceptions::CurrentStacktrace();
+        // If we have an Error object, then set its stackTrace field only if it
+        // not yet initialized.
+        if (!stacktrace_field.IsNull() &&
+            (exception.GetField(stacktrace_field) == Object::null())) {
+          exception.SetField(stacktrace_field, stacktrace);
+        }
       }
     }
   }
@@ -511,12 +506,15 @@
 
   DartFrameIterator iterator;
   const Script& script = Script::Handle(zone, GetCallerScript(&iterator));
-  intptr_t line;
+  intptr_t line = -1;
   intptr_t column = -1;
-  if (script.HasSource()) {
-    script.GetTokenLocation(location, &line, &column);
-  } else {
-    script.GetTokenLocation(location, &line, NULL);
+  ASSERT(!script.IsNull());
+  if (location.IsReal()) {
+    if (script.HasSource() || script.kind() == RawScript::kKernelTag) {
+      script.GetTokenLocation(location, &line, &column);
+    } else {
+      script.GetTokenLocation(location, &line, NULL);
+    }
   }
   // Initialize '_url', '_line', and '_column' arguments.
   args.SetAt(0, String::Handle(zone, script.url()));
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index b8e84b5..fdf1d2e 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -428,7 +428,7 @@
 
 
 // Use CHA to determine if the call needs a class check: if the callee's
-// receiver is the same as the caller's receiver and there are no overriden
+// receiver is the same as the caller's receiver and there are no overridden
 // callee functions, then no class check is needed.
 bool FlowGraph::InstanceCallNeedsClassCheck(InstanceCallInstr* call,
                                             RawFunction::Kind kind) const {
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index d2ee67e..729608f 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -1096,15 +1096,6 @@
 }
 
 
-void FlowGraphCompiler::GeneratePatchableCall(TokenPosition token_pos,
-                                              const StubEntry& stub_entry,
-                                              RawPcDescriptors::Kind kind,
-                                              LocationSummary* locs) {
-  // No patchable calls on ia32.
-  GenerateCall(token_pos, stub_entry, kind, locs);
-}
-
-
 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
                                          TokenPosition token_pos,
                                          const StubEntry& stub_entry,
diff --git a/runtime/vm/intermediate_language_dbc.cc b/runtime/vm/intermediate_language_dbc.cc
index 207153d..f11a372 100644
--- a/runtime/vm/intermediate_language_dbc.cc
+++ b/runtime/vm/intermediate_language_dbc.cc
@@ -417,13 +417,17 @@
 }
 
 
-EMIT_NATIVE_CODE(InitStaticField, 1) {
+EMIT_NATIVE_CODE(InitStaticField,
+                 1,
+                 Location::NoLocation(),
+                 LocationSummary::kCall) {
   if (compiler->is_optimizing()) {
     __ Push(locs()->in(0).reg());
     __ InitStaticTOS();
   } else {
     __ InitStaticTOS();
   }
+  compiler->RecordAfterCall(this);
 }
 
 
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index c90b2c5..c3f905d 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -845,20 +845,17 @@
   __ movl(EDX, Immediate(argc_tag));
 
   const StubEntry* stub_entry;
-  if (link_lazily()) {
-    stub_entry = StubCode::CallBootstrapCFunction_entry();
-    __ movl(ECX, Immediate(NativeEntry::LinkNativeCallEntry()));
-    compiler->GeneratePatchableCall(token_pos(), *stub_entry,
-                                    RawPcDescriptors::kOther, locs());
-  } else {
-    stub_entry = (is_bootstrap_native())
-                     ? StubCode::CallBootstrapCFunction_entry()
-                     : StubCode::CallNativeCFunction_entry();
-    const ExternalLabel label(reinterpret_cast<uword>(native_c_function()));
-    __ movl(ECX, Immediate(label.address()));
-    compiler->GenerateCall(token_pos(), *stub_entry, RawPcDescriptors::kOther,
-                           locs());
-  }
+
+  // There is no lazy-linking support on ia32.
+  ASSERT(!link_lazily());
+  stub_entry = (is_bootstrap_native())
+                   ? StubCode::CallBootstrapCFunction_entry()
+                   : StubCode::CallNativeCFunction_entry();
+  const ExternalLabel label(reinterpret_cast<uword>(native_c_function()));
+  __ movl(ECX, Immediate(label.address()));
+  compiler->GenerateCall(token_pos(), *stub_entry, RawPcDescriptors::kOther,
+                         locs());
+
   __ popl(result);
 }
 
diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc
index 1f50387..26573ce 100644
--- a/runtime/vm/intrinsifier.cc
+++ b/runtime/vm/intrinsifier.cc
@@ -1160,6 +1160,16 @@
 
   return BuildInvokeMathCFunction(&builder, MethodRecognizer::kDoubleRound);
 }
+
+
+void Intrinsifier::RegExp_ExecuteMatch(Assembler* assembler) {
+  IntrinsifyRegExpExecuteMatch(assembler, /*sticky=*/false);
+}
+
+
+void Intrinsifier::RegExp_ExecuteMatchSticky(Assembler* assembler) {
+  IntrinsifyRegExpExecuteMatch(assembler, /*sticky=*/true);
+}
 #endif  // !defined(TARGET_ARCH_DBC)
 
 
diff --git a/runtime/vm/intrinsifier.h b/runtime/vm/intrinsifier.h
index 9242937..81d9e65 100644
--- a/runtime/vm/intrinsifier.h
+++ b/runtime/vm/intrinsifier.h
@@ -56,6 +56,8 @@
   GRAPH_INTRINSICS_LIST(DECLARE_FUNCTION)
 
 #undef DECLARE_FUNCTION
+
+  static void IntrinsifyRegExpExecuteMatch(Assembler* assembler, bool sticky);
 #endif
 };
 
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index d79a9da..99205a7 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -2218,7 +2218,8 @@
 }
 
 
-void Intrinsifier::RegExp_ExecuteMatch(Assembler* assembler) {
+void Intrinsifier::IntrinsifyRegExpExecuteMatch(Assembler* assembler,
+                                                bool sticky) {
   if (FLAG_interpret_irregexp) return;
 
   static const intptr_t kRegExpParamOffset = 2 * kWordSize;
@@ -2237,7 +2238,8 @@
   __ LoadClassId(R1, R1);
   __ AddImmediate(R1, R1, -kOneByteStringCid);
   __ add(R1, R2, Operand(R1, LSL, kWordSizeLog2));
-  __ ldr(R0, FieldAddress(R1, RegExp::function_offset(kOneByteStringCid)));
+  __ ldr(R0,
+         FieldAddress(R1, RegExp::function_offset(kOneByteStringCid, sticky)));
 
   // Registers are now set up for the lazy compile stub. It expects the function
   // in R0, the argument descriptor in R4, and IC-Data in R9.
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index a78bae6..06f623e 100644
--- a/runtime/vm/intrinsifier_arm64.cc
+++ b/runtime/vm/intrinsifier_arm64.cc
@@ -2284,7 +2284,8 @@
 }
 
 
-void Intrinsifier::RegExp_ExecuteMatch(Assembler* assembler) {
+void Intrinsifier::IntrinsifyRegExpExecuteMatch(Assembler* assembler,
+                                                bool sticky) {
   if (FLAG_interpret_irregexp) return;
 
   static const intptr_t kRegExpParamOffset = 2 * kWordSize;
@@ -2303,7 +2304,8 @@
   __ LoadClassId(R1, R1);
   __ AddImmediate(R1, R1, -kOneByteStringCid);
   __ add(R1, R2, Operand(R1, LSL, kWordSizeLog2));
-  __ ldr(R0, FieldAddress(R1, RegExp::function_offset(kOneByteStringCid)));
+  __ ldr(R0,
+         FieldAddress(R1, RegExp::function_offset(kOneByteStringCid, sticky)));
 
   // Registers are now set up for the lazy compile stub. It expects the function
   // in R0, the argument descriptor in R4, and IC-Data in R5.
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index 9b5cf1d..6c0f6a1 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -2230,7 +2230,8 @@
 }
 
 
-void Intrinsifier::RegExp_ExecuteMatch(Assembler* assembler) {
+void Intrinsifier::IntrinsifyRegExpExecuteMatch(Assembler* assembler,
+                                                bool sticky) {
   if (FLAG_interpret_irregexp) return;
 
   static const intptr_t kRegExpParamOffset = 3 * kWordSize;
@@ -2248,8 +2249,8 @@
   __ movl(EDI, Address(ESP, kStringParamOffset));
   __ LoadClassId(EDI, EDI);
   __ SubImmediate(EDI, Immediate(kOneByteStringCid));
-  __ movl(EAX, FieldAddress(EBX, EDI, TIMES_4,
-                            RegExp::function_offset(kOneByteStringCid)));
+  __ movl(EAX, FieldAddress(EBX, EDI, TIMES_4, RegExp::function_offset(
+                                                   kOneByteStringCid, sticky)));
 
   // Registers are now set up for the lazy compile stub. It expects the function
   // in EAX, the argument descriptor in EDX, and IC-Data in ECX.
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 54753a2..04707c7 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -2339,7 +2339,8 @@
 }
 
 
-void Intrinsifier::RegExp_ExecuteMatch(Assembler* assembler) {
+void Intrinsifier::IntrinsifyRegExpExecuteMatch(Assembler* assembler,
+                                                bool sticky) {
   if (FLAG_interpret_irregexp) return;
 
   static const intptr_t kRegExpParamOffset = 2 * kWordSize;
@@ -2359,7 +2360,8 @@
   __ AddImmediate(T2, -kOneByteStringCid);
   __ sll(T2, T2, kWordSizeLog2);
   __ addu(T2, T2, T1);
-  __ lw(T0, FieldAddress(T2, RegExp::function_offset(kOneByteStringCid)));
+  __ lw(T0,
+        FieldAddress(T2, RegExp::function_offset(kOneByteStringCid, sticky)));
 
   // Registers are now set up for the lazy compile stub. It expects the function
   // in T0, the argument descriptor in S4, and IC-Data in S5.
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index b888804..fa250d4 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -2192,7 +2192,8 @@
 }
 
 
-void Intrinsifier::RegExp_ExecuteMatch(Assembler* assembler) {
+void Intrinsifier::IntrinsifyRegExpExecuteMatch(Assembler* assembler,
+                                                bool sticky) {
   if (FLAG_interpret_irregexp) return;
 
   static const intptr_t kRegExpParamOffset = 3 * kWordSize;
@@ -2210,8 +2211,8 @@
   __ movq(RDI, Address(RSP, kStringParamOffset));
   __ LoadClassId(RDI, RDI);
   __ SubImmediate(RDI, Immediate(kOneByteStringCid));
-  __ movq(RAX, FieldAddress(RBX, RDI, TIMES_8,
-                            RegExp::function_offset(kOneByteStringCid)));
+  __ movq(RAX, FieldAddress(RBX, RDI, TIMES_8, RegExp::function_offset(
+                                                   kOneByteStringCid, sticky)));
 
   // Registers are now set up for the lazy compile stub. It expects the function
   // in RAX, the argument descriptor in R10, and IC-Data in RCX.
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 7f25aec..5e08876 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -1102,11 +1102,13 @@
 #ifndef PRODUCT
 bool Isolate::ReloadSources(JSONStream* js,
                             bool force_reload,
+                            const char* root_script_url,
+                            const char* packages_url,
                             bool dont_delete_reload_context) {
   ASSERT(!IsReloading());
   has_attempted_reload_ = true;
   reload_context_ = new IsolateReloadContext(this, js);
-  reload_context_->Reload(force_reload);
+  reload_context_->Reload(force_reload, root_script_url, packages_url);
   bool success = !reload_context_->reload_aborted();
   if (!dont_delete_reload_context) {
     DeleteReloadContext();
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 7d43c57..625be62 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -262,6 +262,8 @@
   // the caller to delete is separately if it is still needed.
   bool ReloadSources(JSONStream* js,
                      bool force_reload,
+                     const char* root_script_url = NULL,
+                     const char* packages_url = NULL,
                      bool dont_delete_reload_context = false);
 
   bool MakeRunnable();
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index 9d6569e..c375df3 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -420,7 +420,11 @@
 
   const Library& a_lib = Library::Handle(a.library());
   const Library& b_lib = Library::Handle(b.library());
-  return IsSameLibrary(a_lib, b_lib);
+
+  if (a_lib.IsNull() || b_lib.IsNull()) {
+    return a_lib.raw() == b_lib.raw();
+  }
+  return (a_lib.private_key() == b_lib.private_key());
 }
 
 
@@ -450,7 +454,7 @@
       reasons_to_cancel_reload_(zone_, 0),
       cid_mapper_(),
       modified_libs_(NULL),
-      script_uri_(String::null()),
+      script_url_(String::null()),
       error_(Error::null()),
       old_classes_set_storage_(Array::null()),
       class_map_storage_(Array::null()),
@@ -459,7 +463,9 @@
       become_map_storage_(Array::null()),
       become_enum_mappings_(GrowableObjectArray::null()),
       saved_root_library_(Library::null()),
-      saved_libraries_(GrowableObjectArray::null()) {
+      saved_libraries_(GrowableObjectArray::null()),
+      root_url_prefix_(String::null()),
+      old_root_url_prefix_(String::null()) {
   // NOTE: DO NOT ALLOCATE ANY RAW OBJECTS HERE. The IsolateReloadContext is not
   // associated with the isolate yet and if a GC is triggered here the raw
   // objects will not be properly accounted for.
@@ -502,20 +508,58 @@
 };
 
 
+static intptr_t CommonSuffixLength(const char* a, const char* b) {
+  const intptr_t a_length = strlen(a);
+  const intptr_t b_length = strlen(b);
+  intptr_t a_cursor = a_length;
+  intptr_t b_cursor = b_length;
+
+  while ((a_cursor >= 0) && (b_cursor >= 0)) {
+    if (a[a_cursor] != b[b_cursor]) {
+      break;
+    }
+    a_cursor--;
+    b_cursor--;
+  }
+
+  ASSERT((a_length - a_cursor) == (b_length - b_cursor));
+  return (a_length - a_cursor);
+}
+
+
 // NOTE: This function returns *after* FinalizeLoading is called.
-void IsolateReloadContext::Reload(bool force_reload) {
+void IsolateReloadContext::Reload(bool force_reload,
+                                  const char* root_script_url,
+                                  const char* packages_url_) {
   TIMELINE_SCOPE(Reload);
   Thread* thread = Thread::Current();
   ASSERT(isolate() == thread->isolate());
 
   // Grab root library before calling CheckpointBeforeReload.
-  const Library& root_lib = Library::Handle(object_store()->root_library());
-  ASSERT(!root_lib.IsNull());
-  const String& root_lib_url = String::Handle(root_lib.url());
+  const Library& old_root_lib = Library::Handle(object_store()->root_library());
+  ASSERT(!old_root_lib.IsNull());
+  const String& old_root_lib_url = String::Handle(old_root_lib.url());
+  // Root library url.
+  const String& root_lib_url =
+      (root_script_url == NULL) ? old_root_lib_url
+                                : String::Handle(String::New(root_script_url));
+
+  // Check to see if the base url of the loaded libraries has moved.
+  if (!old_root_lib_url.Equals(root_lib_url)) {
+    const char* old_root_library_url_c = old_root_lib_url.ToCString();
+    const char* root_library_url_c = root_lib_url.ToCString();
+    const intptr_t common_suffix_length =
+        CommonSuffixLength(root_library_url_c, old_root_library_url_c);
+    root_url_prefix_ = String::SubString(
+        root_lib_url, 0, root_lib_url.Length() - common_suffix_length + 1);
+    old_root_url_prefix_ =
+        String::SubString(old_root_lib_url, 0,
+                          old_root_lib_url.Length() - common_suffix_length + 1);
+  }
 
   // Check to see which libraries have been modified.
   modified_libs_ = FindModifiedLibraries(force_reload);
-  if (!modified_libs_->Contains(root_lib.index())) {
+  if (!modified_libs_->Contains(old_root_lib.index())) {
     ASSERT(modified_libs_->IsEmpty());
     reload_skipped_ = true;
     ReportOnJSON(js_);
@@ -570,17 +614,25 @@
   // for example, top level parse errors. We want to capture these errors while
   // propagating the UnwindError or an UnhandledException error.
   Object& result = Object::Handle(thread->zone());
+
+  String& packages_url = String::Handle();
+  if (packages_url_ != NULL) {
+    packages_url = String::New(packages_url_);
+  }
+
+  TIR_Print("---- ENTERING TAG HANDLER\n");
   {
     TransitionVMToNative transition(thread);
     Api::Scope api_scope(thread);
 
     Dart_Handle retval = (I->library_tag_handler())(
-        Dart_kScriptTag, Api::NewHandle(thread, Library::null()),
+        Dart_kScriptTag, Api::NewHandle(thread, packages_url.raw()),
         Api::NewHandle(thread, root_lib_url.raw()));
     result = Api::UnwrapHandle(retval);
   }
   //
   // WEIRD CONTROL FLOW ENDS.
+  TIR_Print("---- EXITED TAG HANDLER\n");
 
   BackgroundCompiler::Enable();
 
@@ -613,6 +665,7 @@
     AddClassMapping(new_cls, new_cls);
     return;
   }
+  VTIR_Print("Registering class: %s\n", new_cls.ToCString());
   new_cls.set_id(old_cls.id());
   isolate()->class_table()->SetAt(old_cls.id(), new_cls.raw());
   if (!old_cls.is_enum_class()) {
@@ -1225,21 +1278,8 @@
     }
   }
 
-  // Rehash constants map for all new classes and the closure class.
-  Class& cls = Class::Handle(zone_);
-  cls = I->class_table()->At(kClosureCid);
-  cls.RehashConstants(zone_);
-  {
-    ASSERT(class_map_storage_ != Array::null());
-    UnorderedHashMap<ClassMapTraits> map(class_map_storage_);
-    UnorderedHashMap<ClassMapTraits>::Iterator it(&map);
-    while (it.MoveNext()) {
-      const intptr_t entry = it.Current();
-      cls = Class::RawCast(map.GetKey(entry));
-      cls.RehashConstants(zone_);
-    }
-    map.Release();
-  }
+  // Rehash constants map for all classes.
+  RehashConstants();
 
 #ifdef DEBUG
   // Verify that all canonical instances are correctly setup in the
@@ -1252,6 +1292,28 @@
 }
 
 
+void IsolateReloadContext::RehashConstants() {
+  TIMELINE_SCOPE(RehashConstants);
+  ClassTable* class_table = I->class_table();
+  Class& cls = Class::Handle(zone_);
+  const intptr_t top = class_table->NumCids();
+  for (intptr_t cid = kInstanceCid; cid < top; cid++) {
+    if (!class_table->IsValidIndex(cid) || !class_table->HasValidClassAt(cid)) {
+      // Skip invalid classes.
+      continue;
+    }
+    if (RawObject::IsNumberClassId(cid) || RawObject::IsStringClassId(cid)) {
+      // Skip classes that cannot be affected by the 'become' operation.
+      continue;
+    }
+    // Rehash constants.
+    cls = class_table->At(cid);
+    VTIR_Print("Rehashing constants in class `%s`\n", cls.ToCString());
+    cls.RehashConstants(zone_);
+  }
+}
+
+
 bool IsolateReloadContext::IsDirty(const Library& lib) {
   const intptr_t index = lib.index();
   if (index == static_cast<classid_t>(-1)) {
@@ -1649,6 +1711,11 @@
   if (old.IsNull()) {
     return String::null();
   }
+#if defined(DEBUG)
+  VTIR_Print("`%s` is getting `%s`'s private key.\n",
+             String::Handle(replacement_or_new.url()).ToCString(),
+             String::Handle(old.url()).ToCString());
+#endif
   return old.private_key();
 }
 
@@ -1660,10 +1727,54 @@
   Library& lib = Library::Handle();
   lib ^= old_libraries_set.GetOrNull(replacement_or_new);
   old_libraries_set.Release();
+  if (lib.IsNull() && (root_url_prefix_ != String::null()) &&
+      (old_root_url_prefix_ != String::null())) {
+    return OldLibraryOrNullBaseMoved(replacement_or_new);
+  }
   return lib.raw();
 }
 
 
+// Attempt to find the pair to |replacement_or_new| with the knowledge that
+// the base url prefix has moved.
+RawLibrary* IsolateReloadContext::OldLibraryOrNullBaseMoved(
+    const Library& replacement_or_new) {
+  const String& url_prefix = String::Handle(root_url_prefix_);
+  const String& old_url_prefix = String::Handle(old_root_url_prefix_);
+  const intptr_t prefix_length = url_prefix.Length();
+  const intptr_t old_prefix_length = old_url_prefix.Length();
+  const String& new_url = String::Handle(replacement_or_new.url());
+  const String& suffix =
+      String::Handle(String::SubString(new_url, prefix_length));
+  if (!new_url.StartsWith(url_prefix)) {
+    return Library::null();
+  }
+  Library& old = Library::Handle();
+  String& old_url = String::Handle();
+  String& old_suffix = String::Handle();
+  GrowableObjectArray& saved_libs =
+      GrowableObjectArray::Handle(saved_libraries());
+  ASSERT(!saved_libs.IsNull());
+  for (intptr_t i = 0; i < saved_libs.Length(); i++) {
+    old = Library::RawCast(saved_libs.At(i));
+    old_url = old.url();
+    if (!old_url.StartsWith(old_url_prefix)) {
+      continue;
+    }
+    old_suffix ^= String::SubString(old_url, old_prefix_length);
+    if (old_suffix.IsNull()) {
+      continue;
+    }
+    if (old_suffix.Equals(suffix)) {
+      TIR_Print("`%s` is moving to `%s`\n", old_url.ToCString(),
+                new_url.ToCString());
+      return old.raw();
+    }
+  }
+  return Library::null();
+}
+
+
 void IsolateReloadContext::BuildLibraryMapping() {
   const GrowableObjectArray& libs =
       GrowableObjectArray::Handle(object_store()->libraries());
diff --git a/runtime/vm/isolate_reload.h b/runtime/vm/isolate_reload.h
index e5e5da1..f83297e 100644
--- a/runtime/vm/isolate_reload.h
+++ b/runtime/vm/isolate_reload.h
@@ -136,7 +136,9 @@
   explicit IsolateReloadContext(Isolate* isolate, JSONStream* js);
   ~IsolateReloadContext();
 
-  void Reload(bool force_reload);
+  void Reload(bool force_reload,
+              const char* root_script_url = NULL,
+              const char* packages_url = NULL);
 
   // All zone allocated objects must be allocated from this zone.
   Zone* zone() const { return zone_; }
@@ -254,6 +256,8 @@
 
   void PostCommit();
 
+  void RehashConstants();
+
   void ClearReplacedObjectBits();
 
   // atomic_install:
@@ -309,6 +313,9 @@
   RawClass* OldClassOrNull(const Class& replacement_or_new);
 
   RawLibrary* OldLibraryOrNull(const Library& replacement_or_new);
+
+  RawLibrary* OldLibraryOrNullBaseMoved(const Library& replacement_or_new);
+
   void BuildLibraryMapping();
 
   void AddClassMapping(const Class& replacement_or_new, const Class& original);
@@ -326,8 +333,8 @@
   RawClass* MappedClass(const Class& replacement_or_new);
   RawLibrary* MappedLibrary(const Library& replacement_or_new);
 
-  RawObject** from() { return reinterpret_cast<RawObject**>(&script_uri_); }
-  RawString* script_uri_;
+  RawObject** from() { return reinterpret_cast<RawObject**>(&script_url_); }
+  RawString* script_url_;
   RawError* error_;
   RawArray* old_classes_set_storage_;
   RawArray* class_map_storage_;
@@ -337,7 +344,11 @@
   RawGrowableObjectArray* become_enum_mappings_;
   RawLibrary* saved_root_library_;
   RawGrowableObjectArray* saved_libraries_;
-  RawObject** to() { return reinterpret_cast<RawObject**>(&saved_libraries_); }
+  RawString* root_url_prefix_;
+  RawString* old_root_url_prefix_;
+  RawObject** to() {
+    return reinterpret_cast<RawObject**>(&old_root_url_prefix_);
+  }
 
   friend class Isolate;
   friend class Class;  // AddStaticFieldMapping, AddEnumBecomeMapping.
diff --git a/runtime/vm/jit_optimizer.cc b/runtime/vm/jit_optimizer.cc
index 1a7cf2e..ff691b0 100644
--- a/runtime/vm/jit_optimizer.cc
+++ b/runtime/vm/jit_optimizer.cc
@@ -1,7 +1,7 @@
 // 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.
-
+#ifndef DART_PRECOMPILED_RUNTIME
 #include "vm/jit_optimizer.h"
 
 #include "vm/bit_vector.h"
@@ -1864,3 +1864,4 @@
 
 
 }  // namespace dart
+#endif  // DART_PRECOMPILED_RUNTIME
diff --git a/runtime/vm/kernel.h b/runtime/vm/kernel.h
index 93b828b..8e96941 100644
--- a/runtime/vm/kernel.h
+++ b/runtime/vm/kernel.h
@@ -9,6 +9,7 @@
 #include "platform/assert.h"
 #include "vm/allocation.h"
 #include "vm/globals.h"
+#include "vm/token_position.h"
 
 
 #define KERNEL_NODES_DO(M)                                                     \
@@ -308,7 +309,7 @@
 
 class LineStartingTable {
  public:
-  void ReadFrom(Reader* reader, intptr_t length);
+  void ReadFrom(Reader* reader);
   void WriteTo(Writer* writer);
   ~LineStartingTable() {
     for (intptr_t i = 0; i < size_; ++i) {
@@ -413,6 +414,7 @@
   virtual void VisitChildren(Visitor* visitor);
 
   String* import_uri() { return import_uri_; }
+  intptr_t source_uri_index() { return source_uri_index_; }
   String* name() { return name_; }
   List<Class>& classes() { return classes_; }
   List<Field>& fields() { return fields_; }
@@ -448,6 +450,7 @@
 
   Ref<String> name_;
   Ref<String> import_uri_;
+  intptr_t source_uri_index_;
   List<Class> classes_;
   List<Field> fields_;
   List<Procedure> procedures_;
@@ -471,6 +474,7 @@
 
   Library* parent() { return parent_; }
   String* name() { return name_; }
+  intptr_t source_uri_index() { return source_uri_index_; }
   bool is_abstract() { return is_abstract_; }
   List<Expression>& annotations() { return annotations_; }
 
@@ -489,6 +493,7 @@
 
   Ref<Library> parent_;
   Ref<String> name_;
+  intptr_t source_uri_index_;
   bool is_abstract_;
   List<Expression> annotations_;
 
@@ -629,21 +634,25 @@
   bool IsConst() { return (flags_ & kFlagConst) == kFlagConst; }
   bool IsFinal() { return (flags_ & kFlagFinal) == kFlagFinal; }
   bool IsStatic() { return (flags_ & kFlagStatic) == kFlagStatic; }
+  intptr_t source_uri_index() { return source_uri_index_; }
 
   DartType* type() { return type_; }
   InferredValue* inferred_value() { return inferred_value_; }
   Expression* initializer() { return initializer_; }
+  TokenPosition position() { return position_; }
 
  private:
-  Field() {}
+  Field() : position_(TokenPosition::kNoSource) {}
 
   template <typename T>
   friend class List;
 
   word flags_;
+  intptr_t source_uri_index_;
   Child<DartType> type_;
   Child<InferredValue> inferred_value_;
   Child<Expression> initializer_;
+  TokenPosition position_;
 
   DISALLOW_COPY_AND_ASSIGN(Field);
 };
@@ -725,6 +734,7 @@
   bool IsAbstract() { return (flags_ & kFlagAbstract) == kFlagAbstract; }
   bool IsExternal() { return (flags_ & kFlagExternal) == kFlagExternal; }
   bool IsConst() { return (flags_ & kFlagConst) == kFlagConst; }
+  intptr_t source_uri_index() { return source_uri_index_; }
 
  private:
   Procedure() : kind_(kIncompleteProcedure), flags_(0), function_(NULL) {}
@@ -734,6 +744,7 @@
 
   ProcedureKind kind_;
   word flags_;
+  intptr_t source_uri_index_;
   Child<FunctionNode> function_;
 
   DISALLOW_COPY_AND_ASSIGN(Procedure);
@@ -934,9 +945,11 @@
 
   virtual void AcceptTreeVisitor(TreeVisitor* visitor);
   virtual void AcceptExpressionVisitor(ExpressionVisitor* visitor) = 0;
+  TokenPosition position() { return position_; }
 
  protected:
-  Expression() {}
+  Expression() : position_(TokenPosition::kNoSource) {}
+  TokenPosition position_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(Expression);
@@ -1281,11 +1294,6 @@
  public:
   static StaticInvocation* ReadFrom(Reader* reader, bool is_const);
   virtual void WriteTo(Writer* writer);
-
-  explicit StaticInvocation(Procedure* procedure,
-                            Arguments* args,
-                            bool is_const)
-      : procedure_(procedure), arguments_(args), is_const_(is_const) {}
   ~StaticInvocation();
 
   virtual void AcceptExpressionVisitor(ExpressionVisitor* visitor);
@@ -2785,6 +2793,8 @@
   virtual void VisitChildren(Visitor* visitor);
 
   StringTable& string_table() { return string_table_; }
+  StringTable& source_uri_table() { return source_uri_table_; }
+  LineStartingTable& line_starting_table() { return line_starting_table_; }
   List<Library>& libraries() { return libraries_; }
   Procedure* main_method() { return main_method_; }
 
@@ -2794,6 +2804,8 @@
   List<Library> libraries_;
   Ref<Procedure> main_method_;
   StringTable string_table_;
+  StringTable source_uri_table_;
+  LineStartingTable line_starting_table_;
 
   DISALLOW_COPY_AND_ASSIGN(Program);
 };
diff --git a/runtime/vm/kernel_binary.cc b/runtime/vm/kernel_binary.cc
index 350690d..a870dd9 100644
--- a/runtime/vm/kernel_binary.cc
+++ b/runtime/vm/kernel_binary.cc
@@ -355,6 +355,13 @@
     }
   }
 
+  TokenPosition ReadPosition() {
+    intptr_t value = ReadUInt();
+    // Position is saved as unsigned,
+    // but actually ranges from -1 and up (thus the -1)
+    return TokenPosition(value - 1);
+  }
+
   intptr_t ReadListLength() { return ReadUInt(); }
 
   uint8_t ReadByte() { return buffer_[offset_++]; }
@@ -550,6 +557,11 @@
     offset_ += length;
   }
 
+  void WritePosition(TokenPosition position) {
+    intptr_t value = position.value() + 1;
+    WriteUInt(value);
+  }
+
   template <typename T>
   void WriteOptional(T* object) {
     if (object == NULL) {
@@ -794,8 +806,8 @@
 }
 
 
-void LineStartingTable::ReadFrom(Reader* reader, intptr_t length) {
-  size_ = length;
+void LineStartingTable::ReadFrom(Reader* reader) {
+  size_ = reader->helper()->program()->source_uri_table().strings().length();
   values_ = new intptr_t*[size_];
   for (intptr_t i = 0; i < size_; ++i) {
     intptr_t line_count = reader->ReadUInt();
@@ -803,9 +815,9 @@
     line_starts[0] = line_count;
     intptr_t previous_line_start = 0;
     for (intptr_t j = 0; j < line_count; ++j) {
-      intptr_t lineStart = reader->ReadUInt() + previous_line_start;
-      line_starts[j + 1] = lineStart;
-      previous_line_start = lineStart;
+      intptr_t line_start = reader->ReadUInt() + previous_line_start;
+      line_starts[j + 1] = line_start;
+      previous_line_start = line_start;
     }
     values_[i] = line_starts;
   }
@@ -834,7 +846,7 @@
   ASSERT(flags == 0);  // external libraries not supported
   name_ = Reference::ReadStringFrom(reader);
   import_uri_ = Reference::ReadStringFrom(reader);
-  reader->ReadUInt();
+  source_uri_index_ = reader->ReadUInt();
 
   int num_classes = reader->ReadUInt();
   classes().EnsureInitialized(num_classes);
@@ -860,7 +872,7 @@
   TRACE_WRITE_OFFSET();
   name_->WriteTo(writer);
   import_uri_->WriteTo(writer);
-  writer->WriteUInt(0);
+  writer->WriteUInt(source_uri_index_);
 
   writer->WriteUInt(classes_.length());
   for (int i = 0; i < classes_.length(); i++) {
@@ -883,7 +895,7 @@
 
   is_abstract_ = reader->ReadBool();
   name_ = Reference::ReadStringFrom(reader);
-  reader->ReadUInt();
+  source_uri_index_ = reader->ReadUInt();
   annotations_.ReadFromStatic<Expression>(reader);
 
   return this;
@@ -894,7 +906,7 @@
   TRACE_WRITE_OFFSET();
   writer->WriteBool(is_abstract_);
   name_->WriteTo(writer);
-  writer->WriteUInt(0);
+  writer->WriteUInt(source_uri_index_);
   annotations_.WriteTo(writer);
 }
 
@@ -1128,10 +1140,10 @@
   Tag tag = reader->ReadTag();
   ASSERT(tag == kField);
 
-  reader->ReadUInt();
+  position_ = reader->ReadPosition();
   flags_ = reader->ReadFlags();
   name_ = Name::ReadFrom(reader);
-  reader->ReadUInt();
+  source_uri_index_ = reader->ReadUInt();
   annotations_.ReadFromStatic<Expression>(reader);
   type_ = DartType::ReadFrom(reader);
   inferred_value_ = reader->ReadOptional<InferredValue>();
@@ -1143,10 +1155,10 @@
 void Field::WriteTo(Writer* writer) {
   TRACE_WRITE_OFFSET();
   writer->WriteTag(kField);
-  writer->WriteUInt(0);
+  writer->WritePosition(position_);
   writer->WriteFlags(flags_);
   name_->WriteTo(writer);
-  writer->WriteUInt(0);
+  writer->WriteUInt(source_uri_index_);
   annotations_.WriteTo(writer);
   type_->WriteTo(writer);
   writer->WriteOptional<InferredValue>(inferred_value_);
@@ -1191,7 +1203,7 @@
   kind_ = static_cast<ProcedureKind>(reader->ReadByte());
   flags_ = reader->ReadFlags();
   name_ = Name::ReadFrom(reader);
-  reader->ReadUInt();
+  source_uri_index_ = reader->ReadUInt();
   annotations_.ReadFromStatic<Expression>(reader);
   function_ = reader->ReadOptional<FunctionNode>();
   return this;
@@ -1206,7 +1218,7 @@
   writer->WriteByte(kind_);
   writer->WriteFlags(flags_);
   name_->WriteTo(writer);
-  writer->WriteUInt(0);
+  writer->WriteUInt(source_uri_index_);
   annotations_.WriteTo(writer);
   writer->WriteOptional<FunctionNode>(function_);
 }
@@ -1489,7 +1501,7 @@
 PropertyGet* PropertyGet::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
   PropertyGet* get = new PropertyGet();
-  reader->ReadUInt();
+  get->position_ = reader->ReadPosition();
   get->receiver_ = Expression::ReadFrom(reader);
   get->name_ = Name::ReadFrom(reader);
   get->interfaceTarget_ = Reference::ReadMemberFrom(reader, true);
@@ -1500,7 +1512,7 @@
 void PropertyGet::WriteTo(Writer* writer) {
   TRACE_WRITE_OFFSET();
   writer->WriteTag(kPropertyGet);
-  writer->WriteUInt(0);
+  writer->WritePosition(position_);
   receiver_->WriteTo(writer);
   name_->WriteTo(writer);
   Reference::WriteMemberTo(writer, interfaceTarget_, true);
@@ -1510,7 +1522,7 @@
 PropertySet* PropertySet::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
   PropertySet* set = new PropertySet();
-  reader->ReadUInt();
+  set->position_ = reader->ReadPosition();
   set->receiver_ = Expression::ReadFrom(reader);
   set->name_ = Name::ReadFrom(reader);
   set->value_ = Expression::ReadFrom(reader);
@@ -1522,7 +1534,7 @@
 void PropertySet::WriteTo(Writer* writer) {
   TRACE_WRITE_OFFSET();
   writer->WriteTag(kPropertySet);
-  writer->WriteUInt(0);
+  writer->WritePosition(position_);
   receiver_->WriteTo(writer);
   name_->WriteTo(writer);
   value_->WriteTo(writer);
@@ -1569,7 +1581,7 @@
 StaticGet* StaticGet::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
   StaticGet* get = new StaticGet();
-  reader->ReadUInt();
+  get->position_ = reader->ReadPosition();
   get->target_ = Reference::ReadMemberFrom(reader);
   return get;
 }
@@ -1578,7 +1590,7 @@
 void StaticGet::WriteTo(Writer* writer) {
   TRACE_WRITE_OFFSET();
   writer->WriteTag(kStaticGet);
-  writer->WriteUInt(0);
+  writer->WritePosition(position_);
   Reference::WriteMemberTo(writer, target_);
 }
 
@@ -1636,7 +1648,7 @@
 MethodInvocation* MethodInvocation::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
   MethodInvocation* invocation = new MethodInvocation();
-  reader->ReadUInt();
+  invocation->position_ = reader->ReadPosition();
   invocation->receiver_ = Expression::ReadFrom(reader);
   invocation->name_ = Name::ReadFrom(reader);
   invocation->arguments_ = Arguments::ReadFrom(reader);
@@ -1648,7 +1660,7 @@
 void MethodInvocation::WriteTo(Writer* writer) {
   TRACE_WRITE_OFFSET();
   writer->WriteTag(kMethodInvocation);
-  writer->WriteUInt(0);
+  writer->WritePosition(position_);
   receiver_->WriteTo(writer);
   name_->WriteTo(writer);
   arguments_->WriteTo(writer);
@@ -1677,19 +1689,19 @@
 
 StaticInvocation* StaticInvocation::ReadFrom(Reader* reader, bool is_const) {
   TRACE_READ_OFFSET();
-
-  reader->ReadUInt();
-  Member* member = Reference::ReadMemberFrom(reader);
-  Arguments* args = Arguments::ReadFrom(reader);
-
-  return new StaticInvocation(Procedure::Cast(member), args, is_const);
+  StaticInvocation* invocation = new StaticInvocation();
+  invocation->is_const_ = is_const;
+  invocation->position_ = reader->ReadPosition();
+  invocation->procedure_ = Procedure::Cast(Reference::ReadMemberFrom(reader));
+  invocation->arguments_ = Arguments::ReadFrom(reader);
+  return invocation;
 }
 
 
 void StaticInvocation::WriteTo(Writer* writer) {
   TRACE_WRITE_OFFSET();
   writer->WriteTag(is_const_ ? kConstStaticInvocation : kStaticInvocation);
-  writer->WriteUInt(0);
+  writer->WritePosition(position_);
   Reference::WriteMemberTo(writer, procedure_);
   arguments_->WriteTo(writer);
 }
@@ -1700,7 +1712,7 @@
   TRACE_READ_OFFSET();
   ConstructorInvocation* invocation = new ConstructorInvocation();
   invocation->is_const_ = is_const;
-  reader->ReadUInt();
+  invocation->position_ = reader->ReadPosition();
   invocation->target_ = Constructor::Cast(Reference::ReadMemberFrom(reader));
   invocation->arguments_ = Arguments::ReadFrom(reader);
   return invocation;
@@ -1711,7 +1723,7 @@
   TRACE_WRITE_OFFSET();
   writer->WriteTag(is_const_ ? kConstConstructorInvocation
                              : kConstructorInvocation);
-  writer->WriteUInt(0);
+  writer->WritePosition(position_);
   Reference::WriteMemberTo(writer, target_);
   arguments_->WriteTo(writer);
 }
@@ -1974,7 +1986,7 @@
 Throw* Throw::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
   Throw* t = new Throw();
-  reader->ReadUInt();
+  t->position_ = reader->ReadPosition();
   t->expression_ = Expression::ReadFrom(reader);
   return t;
 }
@@ -1983,7 +1995,7 @@
 void Throw::WriteTo(Writer* writer) {
   TRACE_WRITE_OFFSET();
   writer->WriteTag(kThrow);
-  writer->WriteUInt(0);
+  writer->WritePosition(position_);
   expression_->WriteTo(writer);
 }
 
@@ -2793,10 +2805,8 @@
   reader->helper()->set_program(program);
 
   program->string_table_.ReadFrom(reader);
-  StringTable dummy1;
-  dummy1.ReadFrom(reader);
-  LineStartingTable dummy2;
-  dummy2.ReadFrom(reader, dummy1.strings_.length());
+  program->source_uri_table_.ReadFrom(reader);
+  program->line_starting_table_.ReadFrom(reader);
 
   int libraries = reader->ReadUInt();
   program->libraries().EnsureInitialized(libraries);
@@ -2820,10 +2830,8 @@
   // NOTE: Currently we don't GC strings and we require that all referenced
   // strings in nodes are present in [string_table_].
   string_table_.WriteTo(writer);
-  StringTable dummy1;
-  dummy1.WriteTo(writer);
-  LineStartingTable dummy2;
-  dummy2.WriteTo(writer);
+  source_uri_table_.WriteTo(writer);
+  line_starting_table_.WriteTo(writer);
 
   libraries_.WriteTo(writer);
   Reference::WriteMemberTo(writer, main_method_);
diff --git a/runtime/vm/kernel_reader.cc b/runtime/vm/kernel_reader.cc
index 6c669e4..356d19c 100644
--- a/runtime/vm/kernel_reader.cc
+++ b/runtime/vm/kernel_reader.cc
@@ -93,10 +93,18 @@
   return reader_->LookupClass(klass).raw();
 }
 
+Program* KernelReader::ReadPrecompiledProgram() {
+  Program* program = ReadPrecompiledKernelFromBuffer(buffer_, buffer_length_);
+  if (program == NULL) return NULL;
+  intptr_t source_file_count = program->line_starting_table().size();
+  scripts_ = Array::New(source_file_count);
+  program_ = program;
+  return program;
+}
 
 Object& KernelReader::ReadProgram() {
   ASSERT(!bootstrapping_);
-  Program* program = ReadPrecompiledKernelFromBuffer(buffer_, buffer_length_);
+  Program* program = ReadPrecompiledProgram();
   if (program == NULL) {
     const dart::String& error = H.DartString("Failed to read .kernell file");
     return Object::Handle(Z, ApiError::New(error));
@@ -160,12 +168,7 @@
   }
   // Setup toplevel class (which contains library fields/procedures).
 
-  // TODO(27590): Figure out why we need this script stuff here.
-  Script& script = Script::Handle(
-      Z,
-      Script::New(H.DartString(""), H.DartString(""), RawScript::kScriptTag));
-  script.SetLocationOffset(0, 0);
-  script.Tokenize(H.DartString("nop() {}"));
+  Script& script = ScriptAt(kernel_library->source_uri_index());
   dart::Class& toplevel_class = dart::Class::Handle(
       Z, dart::Class::New(library, Symbols::TopLevel(), script,
                           TokenPosition::kNoSource));
@@ -183,10 +186,12 @@
 
     ActiveMemberScope active_member_scope(&active_class_, kernel_field);
     const dart::String& name = H.DartFieldName(kernel_field->name());
+    const Object& script_class =
+        ClassForScriptAt(toplevel_class, kernel_field->source_uri_index());
     dart::Field& field = dart::Field::Handle(
         Z, dart::Field::NewTopLevel(name, kernel_field->IsFinal(),
-                                    kernel_field->IsConst(), toplevel_class,
-                                    TokenPosition::kNoSource));
+                                    kernel_field->IsConst(), script_class,
+                                    kernel_field->position()));
     field.set_kernel_field(kernel_field);
     const AbstractType& type = T.TranslateType(kernel_field->type());
     field.SetFieldType(type);
@@ -293,8 +298,6 @@
 
   ActiveClassScope active_class_scope(&active_class_, kernel_klass, &klass);
 
-  TokenPosition pos(0);
-
   for (intptr_t i = 0; i < kernel_klass->fields().length(); i++) {
     Field* kernel_field = kernel_klass->fields()[i];
     ActiveMemberScope active_member_scope(&active_class_, kernel_field);
@@ -310,7 +313,7 @@
                             kernel_field->IsFinal() || kernel_field->IsConst(),
                             kernel_field->IsConst(),
                             false,  // is_reflectable
-                            klass, type, pos));
+                            klass, type, kernel_field->position()));
     field.set_kernel_field(kernel_field);
     field.set_has_initializer(kernel_field->initializer() != NULL);
     GenerateFieldAccessors(klass, field, kernel_field);
@@ -331,7 +334,7 @@
                                false,  // is_abstract
                                kernel_constructor->IsExternal(),
                                false,  // is_native
-                               klass, pos));
+                               klass, TokenPosition::kNoSource));
     klass.AddFunction(function);
     function.set_kernel_function(kernel_constructor);
     function.set_result_type(T.ReceiverType(klass));
@@ -367,7 +370,6 @@
                                             kernel_procedure->function());
 
   const dart::String& name = H.DartProcedureName(kernel_procedure);
-  TokenPosition pos(0);
   bool is_method = kernel_klass != NULL && !kernel_procedure->IsStatic();
   bool is_abstract = kernel_procedure->IsAbstract();
   bool is_external = kernel_procedure->IsExternal();
@@ -403,13 +405,15 @@
       break;
     }
   }
+  const Object& script_class =
+      ClassForScriptAt(owner, kernel_procedure->source_uri_index());
   dart::Function& function = dart::Function::ZoneHandle(
       Z, Function::New(name, GetFunctionType(kernel_procedure),
                        !is_method,  // is_static
                        false,       // is_const
                        is_abstract, is_external,
                        native_name != NULL,  // is_native
-                       owner, pos));
+                       script_class, TokenPosition::kNoSource));
   owner.AddFunction(function);
   function.set_kernel_function(kernel_procedure);
   function.set_is_debuggable(false);
@@ -429,11 +433,42 @@
   }
 }
 
+const Object& KernelReader::ClassForScriptAt(const dart::Class& klass,
+                                             intptr_t source_uri_index) {
+  Script& correct_script = ScriptAt(source_uri_index);
+  if (klass.script() != correct_script.raw()) {
+    // TODO(jensj): We could probably cache this so we don't create
+    // new PatchClasses all the time
+    return PatchClass::ZoneHandle(Z, PatchClass::New(klass, correct_script));
+  }
+  return klass;
+}
+
+Script& KernelReader::ScriptAt(intptr_t source_uri_index) {
+  Script& script = Script::ZoneHandle(Z);
+  script ^= scripts_.At(source_uri_index);
+  if (script.IsNull()) {
+    String* uri = program_->source_uri_table().strings()[source_uri_index];
+    script = Script::New(H.DartString(uri), dart::String::ZoneHandle(Z),
+                         RawScript::kKernelTag);
+    scripts_.SetAt(source_uri_index, script);
+    intptr_t* line_starts =
+        program_->line_starting_table().valuesFor(source_uri_index);
+    intptr_t line_count = line_starts[0];
+    Array& array_object = Array::Handle(Z, Array::New(line_count));
+    Smi& value = Smi::Handle(Z);
+    for (intptr_t i = 0; i < line_count; ++i) {
+      value = Smi::New(line_starts[i + 1]);
+      array_object.SetAt(i, value);
+    }
+    script.set_line_starts(array_object);
+  }
+  return script;
+}
+
 void KernelReader::GenerateFieldAccessors(const dart::Class& klass,
                                           const dart::Field& field,
                                           Field* kernel_field) {
-  TokenPosition pos(0);
-
   if (kernel_field->IsStatic() && kernel_field->initializer() != NULL) {
     // Static fields with initializers either have the static value set to the
     // initializer value if it is simple enough or else set to an uninitialized
@@ -449,6 +484,8 @@
   }
 
   const dart::String& getter_name = H.DartGetterName(kernel_field->name());
+  const Object& script_class =
+      ClassForScriptAt(klass, kernel_field->source_uri_index());
   Function& getter = Function::ZoneHandle(
       Z,
       Function::New(
@@ -465,7 +502,7 @@
           false,  // is_abstract
           false,  // is_external
           false,  // is_native
-          klass, pos));
+          script_class, kernel_field->position()));
   klass.AddFunction(getter);
   if (klass.IsTopLevel()) {
     dart::Library& library = dart::Library::Handle(Z, klass.library());
@@ -487,7 +524,7 @@
                          false,  // is_abstract
                          false,  // is_external
                          false,  // is_native
-                         klass, pos));
+                         script_class, kernel_field->position()));
     klass.AddFunction(setter);
     setter.set_kernel_function(kernel_field);
     setter.set_result_type(Object::void_type());
@@ -620,26 +657,15 @@
       // The class needs to have a script because all the functions in the class
       // will inherit it.  The predicate Function::IsOptimizable uses the
       // absence of a script to detect test functions that should not be
-      // optimized.  Use a dummy script.
-      //
-      // TODO(27590): We shouldn't need a dummy script per class.  At the
-      // least we could have a singleton.  At best, we'd change IsOptimizable to
-      // detect test functions some other way (like simply not setting the
-      // optimizable bit on those functions in the first place).
-      TokenPosition pos(0);
-      Script& script =
-          Script::Handle(Z, Script::New(H.DartString(""), H.DartString(""),
-                                        RawScript::kScriptTag));
-      handle =
-          &dart::Class::Handle(Z, dart::Class::New(library, name, script, pos));
+      // optimized.
+      Script& script = ScriptAt(klass->source_uri_index());
+      handle = &dart::Class::Handle(
+          Z, dart::Class::New(library, name, script, TokenPosition::kNoSource));
       library.AddClass(*handle);
     } else if (handle->script() == Script::null()) {
       // When bootstrapping we can encounter classes that do not yet have a
       // dummy script.
-      TokenPosition pos(0);
-      Script& script =
-          Script::Handle(Z, Script::New(H.DartString(""), H.DartString(""),
-                                        RawScript::kScriptTag));
+      Script& script = ScriptAt(klass->source_uri_index());
       handle->set_script(script);
     }
     // Insert the class in the cache before calling ReadPreliminaryClass so
diff --git a/runtime/vm/kernel_reader.h b/runtime/vm/kernel_reader.h
index 6b1db8a..a361c14 100644
--- a/runtime/vm/kernel_reader.h
+++ b/runtime/vm/kernel_reader.h
@@ -58,6 +58,8 @@
       : thread_(dart::Thread::Current()),
         zone_(thread_->zone()),
         isolate_(thread_->isolate()),
+        scripts_(Array::ZoneHandle(zone_)),
+        program_(NULL),
         translation_helper_(this, thread_, zone_, isolate_),
         type_translator_(&translation_helper_,
                          &active_class_,
@@ -66,6 +68,9 @@
         buffer_(buffer),
         buffer_length_(len) {}
 
+  // Returns either pointer to a program or null.
+  Program* ReadPrecompiledProgram();
+
   // Returns either a library or a failure object.
   dart::Object& ReadProgram();
 
@@ -89,6 +94,13 @@
                      Procedure* procedure,
                      Class* kernel_klass = NULL);
 
+  // If klass's script is not the script at the uri index, return a PatchClass
+  // for klass whose script corresponds to the uri index.
+  // Otherwise return klass.
+  const Object& ClassForScriptAt(const dart::Class& klass,
+                                 intptr_t source_uri_index);
+  Script& ScriptAt(intptr_t source_uri_index);
+
   void GenerateFieldAccessors(const dart::Class& klass,
                               const dart::Field& field,
                               Field* kernel_field);
@@ -104,6 +116,8 @@
   dart::Thread* thread_;
   dart::Zone* zone_;
   dart::Isolate* isolate_;
+  Array& scripts_;
+  Program* program_;
   ActiveClass active_class_;
   BuildingTranslationHelper translation_helper_;
   DartTypeTranslator type_translator_;
diff --git a/runtime/vm/kernel_to_il.cc b/runtime/vm/kernel_to_il.cc
index 5490abb..9ebcfc1 100644
--- a/runtime/vm/kernel_to_il.cc
+++ b/runtime/vm/kernel_to_il.cc
@@ -2287,24 +2287,26 @@
 }
 
 
-Fragment FlowGraphBuilder::InstanceCall(const dart::String& name,
+Fragment FlowGraphBuilder::InstanceCall(TokenPosition position,
+                                        const dart::String& name,
                                         Token::Kind kind,
                                         intptr_t argument_count,
                                         intptr_t num_args_checked) {
-  return InstanceCall(name, kind, argument_count, Array::null_array(),
+  return InstanceCall(position, name, kind, argument_count, Array::null_array(),
                       num_args_checked);
 }
 
 
-Fragment FlowGraphBuilder::InstanceCall(const dart::String& name,
+Fragment FlowGraphBuilder::InstanceCall(TokenPosition position,
+                                        const dart::String& name,
                                         Token::Kind kind,
                                         intptr_t argument_count,
                                         const Array& argument_names,
                                         intptr_t num_args_checked) {
   ArgumentArray arguments = GetArguments(argument_count);
-  InstanceCallInstr* call = new (Z)
-      InstanceCallInstr(TokenPosition::kNoSource, name, kind, arguments,
-                        argument_names, num_args_checked, ic_data_array_);
+  InstanceCallInstr* call =
+      new (Z) InstanceCallInstr(position, name, kind, arguments, argument_names,
+                                num_args_checked, ic_data_array_);
   Push(call);
   return Fragment(call);
 }
@@ -2321,11 +2323,10 @@
 }
 
 
-Fragment FlowGraphBuilder::ThrowException() {
+Fragment FlowGraphBuilder::ThrowException(TokenPosition position) {
   Fragment instructions;
   instructions += Drop();
-  instructions +=
-      Fragment(new (Z) ThrowInstr(TokenPosition::kNoSource)).closed();
+  instructions += Fragment(new (Z) ThrowInstr(position)).closed();
   // Use it's side effect of leaving a constant on the stack (does not change
   // the graph).
   NullConstant();
@@ -2360,10 +2361,22 @@
 }
 
 
+const dart::Field& MayCloneField(Zone* zone, const dart::Field& field) {
+  if ((Compiler::IsBackgroundCompilation() ||
+       FLAG_force_clone_compiler_objects) &&
+      field.IsOriginal()) {
+    return dart::Field::ZoneHandle(zone, field.CloneFromOriginal());
+  } else {
+    ASSERT(field.IsZoneHandle());
+    return field;
+  }
+}
+
+
 Fragment FlowGraphBuilder::LoadField(const dart::Field& field) {
-  LoadFieldInstr* load = new (Z)
-      LoadFieldInstr(Pop(), &field, AbstractType::ZoneHandle(Z, field.type()),
-                     TokenPosition::kNoSource);
+  LoadFieldInstr* load = new (Z) LoadFieldInstr(
+      Pop(), &MayCloneField(Z, field),
+      AbstractType::ZoneHandle(Z, field.type()), TokenPosition::kNoSource);
   Push(load);
   return Fragment(load);
 }
@@ -2409,7 +2422,8 @@
 
 
 Fragment FlowGraphBuilder::InitStaticField(const dart::Field& field) {
-  InitStaticFieldInstr* init = new (Z) InitStaticFieldInstr(Pop(), field);
+  InitStaticFieldInstr* init =
+      new (Z) InitStaticFieldInstr(Pop(), MayCloneField(Z, field));
   return Fragment(init);
 }
 
@@ -2458,9 +2472,10 @@
 }
 
 
-Fragment FlowGraphBuilder::StaticCall(const Function& target,
+Fragment FlowGraphBuilder::StaticCall(TokenPosition position,
+                                      const Function& target,
                                       intptr_t argument_count) {
-  return StaticCall(target, argument_count, Array::null_array());
+  return StaticCall(position, target, argument_count, Array::null_array());
 }
 
 
@@ -2486,13 +2501,13 @@
 }
 
 
-Fragment FlowGraphBuilder::StaticCall(const Function& target,
+Fragment FlowGraphBuilder::StaticCall(TokenPosition position,
+                                      const Function& target,
                                       intptr_t argument_count,
                                       const Array& argument_names) {
   ArgumentArray arguments = GetArguments(argument_count);
-  StaticCallInstr* call =
-      new (Z) StaticCallInstr(TokenPosition::kNoSource, target, argument_names,
-                              arguments, ic_data_array_);
+  StaticCallInstr* call = new (Z) StaticCallInstr(
+      position, target, argument_names, arguments, ic_data_array_);
   const intptr_t list_cid =
       GetResultCidOfListFactory(Z, target, argument_count);
   if (list_cid != kDynamicCid) {
@@ -2527,23 +2542,26 @@
   if (value->BindsToConstant()) {
     emit_store_barrier = kNoStoreBarrier;
   }
-  StoreInstanceFieldInstr* store = new (Z) StoreInstanceFieldInstr(
-      field, Pop(), value, emit_store_barrier, TokenPosition::kNoSource);
+  StoreInstanceFieldInstr* store = new (Z)
+      StoreInstanceFieldInstr(MayCloneField(Z, field), Pop(), value,
+                              emit_store_barrier, TokenPosition::kNoSource);
   return Fragment(store);
 }
 
 
 Fragment FlowGraphBuilder::StoreInstanceFieldGuarded(const dart::Field& field) {
   Fragment instructions;
+  const dart::Field& field_clone = MayCloneField(Z, field);
   if (FLAG_use_field_guards) {
     LocalVariable* store_expression = MakeTemporary();
     instructions += LoadLocal(store_expression);
-    instructions += GuardFieldClass(field, Thread::Current()->GetNextDeoptId());
+    instructions +=
+        GuardFieldClass(field_clone, Thread::Current()->GetNextDeoptId());
     instructions += LoadLocal(store_expression);
     instructions +=
-        GuardFieldLength(field, Thread::Current()->GetNextDeoptId());
+        GuardFieldLength(field_clone, Thread::Current()->GetNextDeoptId());
   }
-  instructions += StoreInstanceField(field);
+  instructions += StoreInstanceField(field_clone);
   return instructions;
 }
 
@@ -2580,8 +2598,8 @@
 
 
 Fragment FlowGraphBuilder::StoreStaticField(const dart::Field& field) {
-  return Fragment(
-      new (Z) StoreStaticFieldInstr(field, Pop(), TokenPosition::kNoSource));
+  return Fragment(new (Z) StoreStaticFieldInstr(MayCloneField(Z, field), Pop(),
+                                                TokenPosition::kNoSource));
 }
 
 
@@ -2629,12 +2647,12 @@
   instructions += Constant(H.DartSymbol("Malformed type."));
   instructions += PushArgument();  // message
 
-  instructions += StaticCall(constructor, 5);
+  instructions += StaticCall(TokenPosition::kNoSource, constructor, 5);
   instructions += Drop();
 
   // Throw the exception
   instructions += PushArgument();
-  instructions += ThrowException();
+  instructions += ThrowException(TokenPosition::kNoSource);
 
   return instructions;
 }
@@ -2669,7 +2687,7 @@
   instructions += NullConstant();
   instructions += PushArgument();  // existingArgumentNames
 
-  instructions += StaticCall(throw_function, 6);
+  instructions += StaticCall(TokenPosition::kNoSource, throw_function, 6);
   // Leave "result" on the stack since callers expect it to be there (even
   // though the function will result in an exception).
 
@@ -3431,7 +3449,8 @@
   // Forward them to the target.
   intptr_t argument_count = positional_argument_count + named_argument_count;
   if (!target.is_static()) ++argument_count;
-  body += StaticCall(target, argument_count, argument_names);
+  body += StaticCall(TokenPosition::kNoSource, target, argument_count,
+                     argument_names);
 
   // Return the result.
   body += Return();
@@ -3518,7 +3537,7 @@
       Z, mirror_class.LookupStaticFunction(dart::Library::PrivateCoreLibName(
              Symbols::AllocateInvocationMirror())));
   ASSERT(!allocation_function.IsNull());
-  body += StaticCall(allocation_function, 4);
+  body += StaticCall(TokenPosition::kMinSource, allocation_function, 4);
   body += PushArgument();  // For the call to noSuchMethod.
 
   ArgumentsDescriptor two_arguments(
@@ -3534,7 +3553,7 @@
         dart::Class::Handle(Z, I->object_store()->object_class()),
         Symbols::NoSuchMethod(), two_arguments);
   }
-  body += StaticCall(no_such_method, 2);
+  body += StaticCall(TokenPosition::kMinSource, no_such_method, 2);
   body += Return();
 
   return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1);
@@ -3598,7 +3617,8 @@
     // Invoke the getter to get the field value.
     body += LoadLocal(scope->VariableAt(0));
     body += PushArgument();
-    body += InstanceCall(getter_name, Token::kGET, 1);
+    body +=
+        InstanceCall(TokenPosition::kMinSource, getter_name, Token::kGET, 1);
   }
 
   body += PushArgument();
@@ -3617,8 +3637,8 @@
 
     body += ClosureCall(descriptor.Count(), argument_names);
   } else {
-    body += InstanceCall(Symbols::Call(), Token::kILLEGAL, descriptor.Count(),
-                         argument_names);
+    body += InstanceCall(TokenPosition::kMinSource, Symbols::Call(),
+                         Token::kILLEGAL, descriptor.Count(), argument_names);
   }
 
   body += Return();
@@ -3731,7 +3751,8 @@
       const Function& target = Function::ZoneHandle(
           Z, H.LookupConstructorByKernelConstructor(init->target()));
       intptr_t argument_count = init->arguments()->count() + 1;
-      instructions += StaticCall(target, argument_count, argument_names);
+      instructions += StaticCall(TokenPosition::kNoSource, target,
+                                 argument_count, argument_names);
       instructions += Drop();
     } else if (initializer->IsRedirectingInitializer()) {
       RedirectingInitializer* init = RedirectingInitializer::Cast(initializer);
@@ -3746,7 +3767,8 @@
       const Function& target = Function::ZoneHandle(
           Z, H.LookupConstructorByKernelConstructor(init->target()));
       intptr_t argument_count = init->arguments()->count() + 1;
-      instructions += StaticCall(target, argument_count, argument_names);
+      instructions += StaticCall(TokenPosition::kNoSource, target,
+                                 argument_count, argument_names);
       instructions += Drop();
     } else if (initializer->IsLocalInitializer()) {
       // The other initializers following this one might read the variable. This
@@ -4173,7 +4195,7 @@
         Fragment instructions = Constant(field);
         fragment_ = instructions + LoadStaticField();
       } else {
-        fragment_ = StaticCall(getter, 0);
+        fragment_ = StaticCall(node->position(), getter, 0);
       }
     }
   } else {
@@ -4182,7 +4204,7 @@
         Z, H.LookupStaticMethodByKernelProcedure(procedure));
 
     if (procedure->kind() == Procedure::kGetter) {
-      fragment_ = StaticCall(target, 0);
+      fragment_ = StaticCall(node->position(), target, 0);
     } else if (procedure->kind() == Procedure::kMethod) {
       ASSERT(procedure->IsStatic());
       Function& closure_function =
@@ -4223,7 +4245,7 @@
     Procedure* procedure = Procedure::Cast(target);
     const Function& target = Function::ZoneHandle(
         Z, H.LookupStaticMethodByKernelProcedure(procedure));
-    instructions += StaticCall(target, 1);
+    instructions += StaticCall(node->position(), target, 1);
 
     // Drop the unused result & leave the stored value on the stack.
     fragment_ = instructions + Drop();
@@ -4235,7 +4257,8 @@
   Fragment instructions = TranslateExpression(node->receiver());
   instructions += PushArgument();
   const dart::String& getter_name = H.DartGetterName(node->name());
-  fragment_ = instructions + InstanceCall(getter_name, Token::kGET, 1);
+  fragment_ = instructions +
+              InstanceCall(node->position(), getter_name, Token::kGET, 1);
 }
 
 
@@ -4249,7 +4272,7 @@
   instructions += PushArgument();
 
   const dart::String& setter_name = H.DartSetterName(node->name());
-  instructions += InstanceCall(setter_name, Token::kSET, 2);
+  instructions += InstanceCall(node->position(), setter_name, Token::kSET, 2);
   fragment_ = instructions + Drop();
 }
 
@@ -4279,7 +4302,7 @@
 
   Fragment instructions = TranslateExpression(node->receiver());
   instructions += PushArgument();
-  fragment_ = instructions + StaticCall(target, 1);
+  fragment_ = instructions + StaticCall(node->position(), target, 1);
 }
 
 
@@ -4296,7 +4319,7 @@
   instructions += TranslateExpression(node->value());
   instructions += StoreLocal(value);
   instructions += PushArgument();
-  instructions += StaticCall(target, 2);
+  instructions += StaticCall(node->position(), target, 2);
 
   fragment_ = instructions + Drop();
 }
@@ -4381,7 +4404,8 @@
     instructions += StrictCompare(Token::kEQ_STRICT, /*number_check=*/true);
   } else {
     instructions += TranslateArguments(node->arguments(), NULL);
-    instructions += StaticCall(target, argument_count, argument_names);
+    instructions +=
+        StaticCall(node->position(), target, argument_count, argument_names);
 
     if (target.IsGenerativeConstructor()) {
       // Drop the result of the constructor call and leave [instance_variable]
@@ -4438,8 +4462,9 @@
     num_args_checked = argument_count;
   }
 
-  fragment_ = instructions + InstanceCall(name, token_kind, argument_count,
-                                          argument_names, num_args_checked);
+  fragment_ = instructions + InstanceCall(node->position(), name, token_kind,
+                                          argument_count, argument_names,
+                                          num_args_checked);
 }
 
 
@@ -4456,7 +4481,8 @@
   Fragment instructions = TranslateExpression(node->receiver());
   instructions += PushArgument();
   instructions += TranslateArguments(node->arguments(), &argument_names);
-  fragment_ = instructions + StaticCall(target, argument_count, argument_names);
+  fragment_ = instructions + StaticCall(node->position(), target,
+                                        argument_count, argument_names);
 }
 
 
@@ -4516,7 +4542,8 @@
   const Function& target = Function::ZoneHandle(
       Z, H.LookupConstructorByKernelConstructor(klass, node->target()));
   intptr_t argument_count = node->arguments()->count() + 1;
-  instructions += StaticCall(target, argument_count, argument_names);
+  instructions +=
+      StaticCall(node->position(), target, argument_count, argument_names);
   fragment_ = instructions + Drop();
 }
 
@@ -4559,7 +4586,8 @@
     instructions += PushArgument();  // Negate?.
 
     instructions +=
-        InstanceCall(dart::Library::PrivateCoreLibName(Symbols::_instanceOf()),
+        InstanceCall(TokenPosition::kNoSource,
+                     dart::Library::PrivateCoreLibName(Symbols::_instanceOf()),
                      Token::kIS, 4);
   }
 
@@ -4599,6 +4627,7 @@
     instructions += PushArgument();  // Type.
 
     instructions += InstanceCall(
+        TokenPosition::kNoSource,
         dart::Library::PrivateCoreLibName(Symbols::_as()), Token::kAS, 3);
   }
 
@@ -4745,7 +4774,7 @@
   const Function& factory_method = Function::ZoneHandle(
       Z, factory_class.LookupFactory(
              dart::Library::PrivateCoreLibName(Symbols::ListLiteralFactory())));
-  fragment_ = instructions + StaticCall(factory_method, 2);
+  fragment_ = instructions + StaticCall(node->position(), factory_method, 2);
 }
 
 
@@ -4796,7 +4825,7 @@
   }
   instructions += PushArgument();  // The array.
 
-  fragment_ = instructions + StaticCall(factory_method, 2);
+  fragment_ = instructions + StaticCall(node->position(), factory_method, 2);
 }
 
 
@@ -4817,7 +4846,7 @@
 
   instructions += TranslateExpression(node->expression());
   instructions += PushArgument();
-  instructions += ThrowException();
+  instructions += ThrowException(node->position());
   ASSERT(instructions.is_closed());
 
   fragment_ = instructions;
@@ -5101,7 +5130,8 @@
 
   const dart::String& iterator_getter = dart::String::ZoneHandle(
       Z, dart::Field::GetterSymbol(Symbols::Iterator()));
-  instructions += InstanceCall(iterator_getter, Token::kGET, 1);
+  instructions +=
+      InstanceCall(TokenPosition::kNoSource, iterator_getter, Token::kGET, 1);
   LocalVariable* iterator = scopes_->iterator_variables[for_in_depth_];
   instructions += StoreLocal(iterator);
   instructions += Drop();
@@ -5110,7 +5140,8 @@
   ++loop_depth_;
   Fragment condition = LoadLocal(iterator);
   condition += PushArgument();
-  condition += InstanceCall(Symbols::MoveNext(), Token::kILLEGAL, 1);
+  condition += InstanceCall(TokenPosition::kNoSource, Symbols::MoveNext(),
+                            Token::kILLEGAL, 1);
   TargetEntryInstr* body_entry;
   TargetEntryInstr* loop_exit;
   condition += BranchIfTrue(&body_entry, &loop_exit);
@@ -5121,7 +5152,8 @@
   body += PushArgument();
   const dart::String& current_getter = dart::String::ZoneHandle(
       Z, dart::Field::GetterSymbol(Symbols::Current()));
-  body += InstanceCall(current_getter, Token::kGET, 1);
+  body +=
+      InstanceCall(TokenPosition::kNoSource, current_getter, Token::kGET, 1);
   body += StoreLocal(LookupVariable(node->variable()));
   body += Drop();
   body += TranslateStatement(node->body());
@@ -5242,12 +5274,12 @@
       body_fragment += NullConstant();
       body_fragment += PushArgument();  // line
 
-      body_fragment += StaticCall(constructor, 3);
+      body_fragment += StaticCall(TokenPosition::kNoSource, constructor, 3);
       body_fragment += Drop();
 
       // Throw the exception
       body_fragment += PushArgument();
-      body_fragment += ThrowException();
+      body_fragment += ThrowException(TokenPosition::kNoSource);
       body_fragment += Drop();
     }
 
@@ -5311,10 +5343,10 @@
         current_instructions += PushArgument();
         current_instructions += LoadLocal(scopes_->switch_variable);
         current_instructions += PushArgument();
-        current_instructions +=
-            InstanceCall(Symbols::EqualOperator(), Token::kEQ,
-                         /*argument_count=*/2,
-                         /*num_args_checked=*/2);
+        current_instructions += InstanceCall(
+            TokenPosition::kNoSource, Symbols::EqualOperator(), Token::kEQ,
+            /*argument_count=*/2,
+            /*num_args_checked=*/2);
         current_instructions += BranchIfTrue(&then, &otherwise);
 
         Fragment then_fragment(then);
@@ -5434,12 +5466,12 @@
   otherwise_fragment += IntConstant(0);
   otherwise_fragment += PushArgument();  // column
 
-  otherwise_fragment += StaticCall(constructor, 5);
+  otherwise_fragment += StaticCall(TokenPosition::kNoSource, constructor, 5);
   otherwise_fragment += Drop();
 
   // Throw _AssertionError exception.
   otherwise_fragment += PushArgument();
-  otherwise_fragment += ThrowException();
+  otherwise_fragment += ThrowException(TokenPosition::kNoSource);
   otherwise_fragment += Drop();
 
   fragment_ = Fragment(instructions.entry, then);
@@ -5594,6 +5626,7 @@
         catch_body += Constant(Object::bool_false());
         catch_body += PushArgument();  // negate
         catch_body += InstanceCall(
+            TokenPosition::kNoSource,
             dart::Library::PrivateCoreLibName(Symbols::_instanceOf()),
             Token::kIS, 4);
 
@@ -5711,6 +5744,7 @@
   for (intptr_t i = 0; i < scopes_->function_scopes.length(); ++i) {
     if (scopes_->function_scopes[i].function != node) continue;
 
+    // NOTE: This is not TokenPosition in the general sense!
     function = I->LookupClosureFunction(parsed_function_->function(),
                                         TokenPosition(i));
     if (function.IsNull()) {
@@ -5722,6 +5756,7 @@
         name = &H.DartSymbol(
             FunctionDeclaration::Cast(parent)->variable()->name());
       }
+      // NOTE: This is not TokenPosition in the general sense!
       function = Function::NewClosureFunction(
           *name, parsed_function_->function(), TokenPosition(i));
       function.set_is_debuggable(false);
diff --git a/runtime/vm/kernel_to_il.h b/runtime/vm/kernel_to_il.h
index 5f2539b..3f9db3e 100644
--- a/runtime/vm/kernel_to_il.h
+++ b/runtime/vm/kernel_to_il.h
@@ -753,17 +753,19 @@
   Fragment CreateArray();
   Fragment Goto(JoinEntryInstr* destination);
   Fragment IntConstant(int64_t value);
-  Fragment InstanceCall(const dart::String& name,
+  Fragment InstanceCall(TokenPosition position,
+                        const dart::String& name,
                         Token::Kind kind,
                         intptr_t argument_count,
                         intptr_t num_args_checked = 1);
-  Fragment InstanceCall(const dart::String& name,
+  Fragment InstanceCall(TokenPosition position,
+                        const dart::String& name,
                         Token::Kind kind,
                         intptr_t argument_count,
                         const Array& argument_names,
                         intptr_t num_args_checked = 1);
   Fragment ClosureCall(int argument_count, const Array& argument_names);
-  Fragment ThrowException();
+  Fragment ThrowException(TokenPosition position);
   Fragment RethrowException(int catch_try_index);
   Fragment LoadClassId();
   Fragment LoadField(const dart::Field& field);
@@ -780,8 +782,11 @@
   Fragment NativeCall(const dart::String* name, const Function* function);
   Fragment PushArgument();
   Fragment Return();
-  Fragment StaticCall(const Function& target, intptr_t argument_count);
-  Fragment StaticCall(const Function& target,
+  Fragment StaticCall(TokenPosition position,
+                      const Function& target,
+                      intptr_t argument_count);
+  Fragment StaticCall(TokenPosition position,
+                      const Function& target,
                       intptr_t argument_count,
                       const Array& argument_names);
   Fragment StoreIndexed(intptr_t class_id);
diff --git a/runtime/vm/method_recognizer.h b/runtime/vm/method_recognizer.h
index 580582f..5ab5eac 100644
--- a/runtime/vm/method_recognizer.h
+++ b/runtime/vm/method_recognizer.h
@@ -166,6 +166,8 @@
     0x25a786de)                                                                \
   V(_GrowableList, add, GrowableArray_add, Dynamic, 0x0d1358ed)                \
   V(_RegExp, _ExecuteMatch, RegExp_ExecuteMatch, Dynamic, 0x6036d7fa)          \
+  V(_RegExp, _ExecuteMatchSticky, RegExp_ExecuteMatchSticky, Dynamic,          \
+    0x71c67f7d)                                                                \
   V(Object, ==, ObjectEquals, Bool, 0x11662ed8)                                \
   V(Object, get:runtimeType, ObjectRuntimeType, Type, 0x00e7c26b)              \
   V(Object, _haveSameRuntimeType, ObjectHaveSameRuntimeType, Bool, 0x72aad7e2) \
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 673ae03..0cfa413 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -5696,21 +5696,36 @@
 }
 
 
+class StickySpecialization : public BitField<intptr_t, bool, 0, 1> {};
+class StringSpecializationCid
+    : public BitField<intptr_t, intptr_t, 1, RawObject::kClassIdTagSize> {};
+
+
 intptr_t Function::string_specialization_cid() const {
   ASSERT(kind() == RawFunction::kIrregexpFunction);
   const Array& pair = Array::Cast(Object::Handle(raw_ptr()->data_));
-  return Smi::Value(Smi::RawCast(pair.At(1)));
+  return StringSpecializationCid::decode(Smi::Value(Smi::RawCast(pair.At(1))));
+}
+
+
+bool Function::is_sticky_specialization() const {
+  ASSERT(kind() == RawFunction::kIrregexpFunction);
+  const Array& pair = Array::Cast(Object::Handle(raw_ptr()->data_));
+  return StickySpecialization::decode(Smi::Value(Smi::RawCast(pair.At(1))));
 }
 
 
 void Function::SetRegExpData(const RegExp& regexp,
-                             intptr_t string_specialization_cid) const {
+                             intptr_t string_specialization_cid,
+                             bool sticky) const {
   ASSERT(kind() == RawFunction::kIrregexpFunction);
   ASSERT(RawObject::IsStringClassId(string_specialization_cid));
   ASSERT(raw_ptr()->data_ == Object::null());
   const Array& pair = Array::Handle(Array::New(2, Heap::kOld));
   pair.SetAt(0, regexp);
-  pair.SetAt(1, Smi::Handle(Smi::New(string_specialization_cid)));
+  pair.SetAt(1, Smi::Handle(Smi::New(StickySpecialization::encode(sticky) |
+                                     StringSpecializationCid::encode(
+                                         string_specialization_cid))));
   set_data(pair);
 }
 
@@ -8767,6 +8782,8 @@
       return "patch";
     case RawScript::kEvaluateTag:
       return "evaluate";
+    case RawScript::kKernelTag:
+      return "kernel";
     default:
       UNIMPLEMENTED();
   }
@@ -8789,6 +8806,10 @@
   StorePointer(&raw_ptr()->source_, value.raw());
 }
 
+void Script::set_line_starts(const Array& value) const {
+  StorePointer(&raw_ptr()->line_starts_, value.raw());
+}
+
 
 void Script::set_kind(RawScript::Kind value) const {
   StoreNonPointer(&raw_ptr()->kind_, value);
@@ -8839,9 +8860,49 @@
                               intptr_t* token_len) const {
   ASSERT(line != NULL);
   Zone* zone = Thread::Current()->zone();
+
+  if (kind() == RawScript::kKernelTag) {
+    const Array& line_starts_array = Array::Handle(line_starts());
+    if (line_starts_array.IsNull()) {
+      // Scripts in the AOT snapshot do not have a line starts array.
+      *line = -1;
+      if (column != NULL) {
+        *column = -1;
+      }
+      if (token_len != NULL) {
+        *token_len = 1;
+      }
+      return;
+    }
+    ASSERT(line_starts_array.Length() > 0);
+    intptr_t offset = token_pos.value();
+    int min = 0;
+    int max = line_starts_array.Length() - 1;
+
+    // Binary search to find the line containing this offset.
+    Smi& smi = Smi::Handle();
+    while (min < max) {
+      int midpoint = (max - min + 1) / 2 + min;
+
+      smi ^= line_starts_array.At(midpoint);
+      if (smi.Value() > offset) {
+        max = midpoint - 1;
+      } else {
+        min = midpoint;
+      }
+    }
+    *line = min + 1;
+    smi ^= line_starts_array.At(min);
+    *column = offset - smi.Value() + 1;
+    if (token_len != NULL) {
+      *token_len = 1;
+    }
+    return;
+  }
+
   const TokenStream& tkns = TokenStream::Handle(zone, tokens());
   if (tkns.IsNull()) {
-    ASSERT(Dart::snapshot_kind() == Snapshot::kAppNoJIT);
+    ASSERT((Dart::snapshot_kind() == Snapshot::kAppNoJIT));
     *line = -1;
     if (column != NULL) {
       *column = -1;
@@ -22296,7 +22357,7 @@
   intptr_t line = -1;
   intptr_t column = -1;
   if (!script.IsNull() && token_pos.IsReal()) {
-    if (script.HasSource()) {
+    if (script.HasSource() || script.kind() == RawScript::kKernelTag) {
       script.GetTokenLocation(token_pos, &line, &column);
     } else {
       script.GetTokenLocation(token_pos, &line, NULL);
@@ -22394,16 +22455,28 @@
 }
 
 
-void RegExp::set_function(intptr_t cid, const Function& value) const {
-  StorePointer(FunctionAddr(cid), value.raw());
+void RegExp::set_function(intptr_t cid,
+                          bool sticky,
+                          const Function& value) const {
+  StorePointer(FunctionAddr(cid, sticky), value.raw());
 }
 
 
-void RegExp::set_bytecode(bool is_one_byte, const TypedData& bytecode) const {
-  if (is_one_byte) {
-    StorePointer(&raw_ptr()->one_byte_bytecode_, bytecode.raw());
+void RegExp::set_bytecode(bool is_one_byte,
+                          bool sticky,
+                          const TypedData& bytecode) const {
+  if (sticky) {
+    if (is_one_byte) {
+      StorePointer(&raw_ptr()->one_byte_sticky_.bytecode_, bytecode.raw());
+    } else {
+      StorePointer(&raw_ptr()->two_byte_sticky_.bytecode_, bytecode.raw());
+    }
   } else {
-    StorePointer(&raw_ptr()->two_byte_bytecode_, bytecode.raw());
+    if (is_one_byte) {
+      StorePointer(&raw_ptr()->one_byte_.bytecode_, bytecode.raw());
+    } else {
+      StorePointer(&raw_ptr()->two_byte_.bytecode_, bytecode.raw());
+    }
   }
 }
 
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 837b833..bf2b009 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2215,8 +2215,10 @@
 
   RawRegExp* regexp() const;
   intptr_t string_specialization_cid() const;
+  bool is_sticky_specialization() const;
   void SetRegExpData(const RegExp& regexp,
-                     intptr_t string_specialization_cid) const;
+                     intptr_t string_specialization_cid,
+                     bool sticky) const;
 
   RawString* native_name() const;
   void set_native_name(const String& name) const;
@@ -3501,6 +3503,10 @@
 
   RawTokenStream* tokens() const { return raw_ptr()->tokens_; }
 
+  RawArray* line_starts() const { return raw_ptr()->line_starts_; }
+
+  void set_line_starts(const Array& value) const;
+
   void Tokenize(const String& private_key, bool use_shared_tokens = true) const;
 
   RawLibrary* FindLibrary() const;
@@ -8451,37 +8457,59 @@
     return raw_ptr()->num_bracket_expressions_;
   }
 
-  RawTypedData* bytecode(bool is_one_byte) const {
-    return is_one_byte ? raw_ptr()->one_byte_bytecode_
-                       : raw_ptr()->two_byte_bytecode_;
+  RawTypedData* bytecode(bool is_one_byte, bool sticky) const {
+    if (sticky) {
+      return is_one_byte ? raw_ptr()->one_byte_sticky_.bytecode_
+                         : raw_ptr()->two_byte_sticky_.bytecode_;
+    } else {
+      return is_one_byte ? raw_ptr()->one_byte_.bytecode_
+                         : raw_ptr()->two_byte_.bytecode_;
+    }
   }
 
-  static intptr_t function_offset(intptr_t cid) {
-    switch (cid) {
-      case kOneByteStringCid:
-        return OFFSET_OF(RawRegExp, one_byte_function_);
-      case kTwoByteStringCid:
-        return OFFSET_OF(RawRegExp, two_byte_function_);
-      case kExternalOneByteStringCid:
-        return OFFSET_OF(RawRegExp, external_one_byte_function_);
-      case kExternalTwoByteStringCid:
-        return OFFSET_OF(RawRegExp, external_two_byte_function_);
+  static intptr_t function_offset(intptr_t cid, bool sticky) {
+    if (sticky) {
+      switch (cid) {
+        case kOneByteStringCid:
+          return OFFSET_OF(RawRegExp, one_byte_sticky_.function_);
+        case kTwoByteStringCid:
+          return OFFSET_OF(RawRegExp, two_byte_sticky_.function_);
+        case kExternalOneByteStringCid:
+          return OFFSET_OF(RawRegExp, external_one_byte_sticky_function_);
+        case kExternalTwoByteStringCid:
+          return OFFSET_OF(RawRegExp, external_two_byte_sticky_function_);
+      }
+    } else {
+      switch (cid) {
+        case kOneByteStringCid:
+          return OFFSET_OF(RawRegExp, one_byte_.function_);
+        case kTwoByteStringCid:
+          return OFFSET_OF(RawRegExp, two_byte_.function_);
+        case kExternalOneByteStringCid:
+          return OFFSET_OF(RawRegExp, external_one_byte_function_);
+        case kExternalTwoByteStringCid:
+          return OFFSET_OF(RawRegExp, external_two_byte_function_);
+      }
     }
 
     UNREACHABLE();
     return -1;
   }
 
-  RawFunction** FunctionAddr(intptr_t cid) const {
+  RawFunction** FunctionAddr(intptr_t cid, bool sticky) const {
     return reinterpret_cast<RawFunction**>(
-        FieldAddrAtOffset(function_offset(cid)));
+        FieldAddrAtOffset(function_offset(cid, sticky)));
   }
 
-  RawFunction* function(intptr_t cid) const { return *FunctionAddr(cid); }
+  RawFunction* function(intptr_t cid, bool sticky) const {
+    return *FunctionAddr(cid, sticky);
+  }
 
   void set_pattern(const String& pattern) const;
-  void set_function(intptr_t cid, const Function& value) const;
-  void set_bytecode(bool is_one_byte, const TypedData& bytecode) const;
+  void set_function(intptr_t cid, bool sticky, const Function& value) const;
+  void set_bytecode(bool is_one_byte,
+                    bool sticky,
+                    const TypedData& bytecode) const;
 
   void set_num_bracket_expressions(intptr_t value) const;
   void set_is_global() const { set_flags(flags() | kGlobal); }
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index b41ff6c..a5998b9 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -543,7 +543,7 @@
 };
 
 
-// This is executed before interating over the instances.
+// This is executed before iterating over the instances.
 void Class::CheckReload(const Class& replacement,
                         IsolateReloadContext* context) const {
   ASSERT(IsolateReloadContext::IsSameClass(*this, replacement));
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index d5441a5..6d2bd9e 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -1512,21 +1512,35 @@
   jsobj.AddProperty("isCaseSensitive", !is_ignore_case());
   jsobj.AddProperty("isMultiLine", is_multi_line());
 
-  Function& func = Function::Handle();
-  func = function(kOneByteStringCid);
-  jsobj.AddProperty("_oneByteFunction", func);
-  func = function(kTwoByteStringCid);
-  jsobj.AddProperty("_twoByteFunction", func);
-  func = function(kExternalOneByteStringCid);
-  jsobj.AddProperty("_externalOneByteFunction", func);
-  func = function(kExternalTwoByteStringCid);
-  jsobj.AddProperty("_externalTwoByteFunction", func);
-
-  TypedData& bc = TypedData::Handle();
-  bc = bytecode(true);
-  jsobj.AddProperty("_oneByteBytecode", bc);
-  bc = bytecode(false);
-  jsobj.AddProperty("_twoByteBytecode", bc);
+  if (!FLAG_interpret_irregexp) {
+    Function& func = Function::Handle();
+    func = function(kOneByteStringCid, /*sticky=*/false);
+    jsobj.AddProperty("_oneByteFunction", func);
+    func = function(kTwoByteStringCid, /*sticky=*/false);
+    jsobj.AddProperty("_twoByteFunction", func);
+    func = function(kExternalOneByteStringCid, /*sticky=*/false);
+    jsobj.AddProperty("_externalOneByteFunction", func);
+    func = function(kExternalTwoByteStringCid, /*sticky=*/false);
+    jsobj.AddProperty("_externalTwoByteFunction", func);
+    func = function(kOneByteStringCid, /*sticky=*/true);
+    jsobj.AddProperty("_oneByteFunctionSticky", func);
+    func = function(kTwoByteStringCid, /*sticky=*/true);
+    jsobj.AddProperty("_twoByteFunctionSticky", func);
+    func = function(kExternalOneByteStringCid, /*sticky=*/true);
+    jsobj.AddProperty("_externalOneByteFunctionSticky", func);
+    func = function(kExternalTwoByteStringCid, /*sticky=*/true);
+    jsobj.AddProperty("_externalTwoByteFunctionSticky", func);
+  } else {
+    TypedData& bc = TypedData::Handle();
+    bc = bytecode(/*is_one_byte=*/true, /*sticky=*/false);
+    jsobj.AddProperty("_oneByteBytecode", bc);
+    bc = bytecode(/*is_one_byte=*/false, /*sticky=*/false);
+    jsobj.AddProperty("_twoByteBytecode", bc);
+    bc = bytecode(/*is_one_byte=*/true, /*sticky=*/true);
+    jsobj.AddProperty("_oneByteBytecodeSticky", bc);
+    bc = bytecode(/*is_one_byte=*/false, /*sticky=*/true);
+    jsobj.AddProperty("_twoByteBytecodeSticky", bc);
+  }
 }
 
 
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 50900b4..9097b1d 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -970,6 +970,7 @@
     kSourceTag,
     kPatchTag,
     kEvaluateTag,
+    kKernelTag,
   };
 
  private:
@@ -979,6 +980,7 @@
   RawString* url_;
   RawString* resolved_url_;
   RawArray* compile_time_constants_;
+  RawArray* line_starts_;
   RawTokenStream* tokens_;
   RawString* source_;
   RawObject** to() { return reinterpret_cast<RawObject**>(&ptr()->source_); }
@@ -2116,14 +2118,29 @@
   }
   RawSmi* num_bracket_expressions_;
   RawString* pattern_;  // Pattern to be used for matching.
-  RawFunction* one_byte_function_;
-  RawFunction* two_byte_function_;
+  union {
+    RawFunction* function_;
+    RawTypedData* bytecode_;
+  } one_byte_;
+  union {
+    RawFunction* function_;
+    RawTypedData* bytecode_;
+  } two_byte_;
   RawFunction* external_one_byte_function_;
   RawFunction* external_two_byte_function_;
-  RawTypedData* one_byte_bytecode_;
-  RawTypedData* two_byte_bytecode_;
+  union {
+    RawFunction* function_;
+    RawTypedData* bytecode_;
+  } one_byte_sticky_;
+  union {
+    RawFunction* function_;
+    RawTypedData* bytecode_;
+  } two_byte_sticky_;
+  RawFunction* external_one_byte_sticky_function_;
+  RawFunction* external_two_byte_sticky_function_;
   RawObject** to() {
-    return reinterpret_cast<RawObject**>(&ptr()->two_byte_bytecode_);
+    return reinterpret_cast<RawObject**>(
+        &ptr()->external_two_byte_sticky_function_);
   }
 
   intptr_t num_registers_;
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index aebda45..2177722 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -2894,16 +2894,12 @@
                         reader->Read<int32_t>());
   regex.StoreNonPointer(&regex.raw_ptr()->type_flags_, reader->Read<int8_t>());
 
-  // TODO(18854): Need to implement a way of recreating the irrexp functions.
   const Function& no_function = Function::Handle(reader->zone());
-  regex.set_function(kOneByteStringCid, no_function);
-  regex.set_function(kTwoByteStringCid, no_function);
-  regex.set_function(kExternalOneByteStringCid, no_function);
-  regex.set_function(kExternalTwoByteStringCid, no_function);
-
-  const TypedData& no_bytecode = TypedData::Handle(reader->zone());
-  regex.set_bytecode(true, no_bytecode);
-  regex.set_bytecode(false, no_bytecode);
+  for (intptr_t cid = kOneByteStringCid; cid <= kExternalTwoByteStringCid;
+       cid++) {
+    regex.set_function(cid, /*sticky=*/false, no_function);
+    regex.set_function(cid, /*sticky=*/true, no_function);
+  }
 
   return regex.raw();
 }
diff --git a/runtime/vm/regexp.cc b/runtime/vm/regexp.cc
index 19b88c5..3516bc8 100644
--- a/runtime/vm/regexp.cc
+++ b/runtime/vm/regexp.cc
@@ -4824,6 +4824,7 @@
 
   const Function& function = parsed_function->function();
   const intptr_t specialization_cid = function.string_specialization_cid();
+  const intptr_t is_sticky = function.is_sticky_specialization();
   const bool is_one_byte = (specialization_cid == kOneByteStringCid ||
                             specialization_cid == kExternalOneByteStringCid);
   RegExp& regexp = RegExp::Handle(zone, function.regexp());
@@ -4851,12 +4852,12 @@
       RegExpCapture::ToNode(data->tree, 0, &compiler, compiler.accept());
 
   RegExpNode* node = captured_body;
-  bool is_end_anchored = data->tree->IsAnchoredAtEnd();
-  bool is_start_anchored = data->tree->IsAnchoredAtStart();
+  const bool is_end_anchored = data->tree->IsAnchoredAtEnd();
+  const bool is_start_anchored = data->tree->IsAnchoredAtStart();
   intptr_t max_length = data->tree->max_match();
-  if (!is_start_anchored) {
+  if (!is_start_anchored && !is_sticky) {
     // Add a .*? at the beginning, outside the body capture, unless
-    // this expression is anchored at the beginning.
+    // this expression is anchored at the beginning or is sticky.
     RegExpNode* loop_node = RegExpQuantifier::ToNode(
         0, RegExpTree::kInfinity, false, new (zone) RegExpCharacterClass('*'),
         &compiler, captured_body, data->contains_anchor);
@@ -4900,7 +4901,7 @@
   // Inserted here, instead of in Assembler, because it depends on information
   // in the AST that isn't replicated in the Node structure.
   static const intptr_t kMaxBacksearchLimit = 1024;
-  if (is_end_anchored && !is_start_anchored &&
+  if (is_end_anchored && !is_start_anchored && !is_sticky &&
       max_length < kMaxBacksearchLimit) {
     macro_assembler->SetCurrentPositionFromEnd(max_length);
   }
@@ -4927,6 +4928,7 @@
     RegExpCompileData* data,
     const RegExp& regexp,
     bool is_one_byte,
+    bool is_sticky,
     Zone* zone) {
   ASSERT(FLAG_interpret_irregexp);
   const String& pattern = String::Handle(zone, regexp.pattern());
@@ -4956,7 +4958,7 @@
   bool is_end_anchored = data->tree->IsAnchoredAtEnd();
   bool is_start_anchored = data->tree->IsAnchoredAtStart();
   intptr_t max_length = data->tree->max_match();
-  if (!is_start_anchored) {
+  if (!is_start_anchored && !is_sticky) {
     // Add a .*? at the beginning, outside the body capture, unless
     // this expression is anchored at the beginning.
     RegExpNode* loop_node = RegExpQuantifier::ToNode(
@@ -5002,7 +5004,7 @@
   // Inserted here, instead of in Assembler, because it depends on information
   // in the AST that isn't replicated in the Node structure.
   static const intptr_t kMaxBacksearchLimit = 1024;
-  if (is_end_anchored && !is_start_anchored &&
+  if (is_end_anchored && !is_start_anchored && !is_sticky &&
       max_length < kMaxBacksearchLimit) {
     macro_assembler->SetCurrentPositionFromEnd(max_length);
   }
@@ -5029,6 +5031,7 @@
                                       Zone* zone,
                                       const RegExp& regexp,
                                       intptr_t specialization_cid,
+                                      bool sticky,
                                       const Object& owner) {
   const intptr_t kParamCount = RegExpMacroAssembler::kParamCount;
 
@@ -5063,9 +5066,9 @@
   fn.set_result_type(Type::Handle(zone, Type::ArrayType()));
 
   // Cache the result.
-  regexp.set_function(specialization_cid, fn);
+  regexp.set_function(specialization_cid, sticky, fn);
 
-  fn.SetRegExpData(regexp, specialization_cid);
+  fn.SetRegExpData(regexp, specialization_cid, sticky);
   fn.set_is_debuggable(false);
 
   // The function is compiled lazily during the first call.
@@ -5098,12 +5101,13 @@
     const Class& owner =
         Class::Handle(zone, lib.LookupClass(Symbols::RegExp()));
 
-    CreateSpecializedFunction(thread, zone, regexp, kOneByteStringCid, owner);
-    CreateSpecializedFunction(thread, zone, regexp, kTwoByteStringCid, owner);
-    CreateSpecializedFunction(thread, zone, regexp, kExternalOneByteStringCid,
-                              owner);
-    CreateSpecializedFunction(thread, zone, regexp, kExternalTwoByteStringCid,
-                              owner);
+    for (intptr_t cid = kOneByteStringCid; cid <= kExternalTwoByteStringCid;
+         cid++) {
+      CreateSpecializedFunction(thread, zone, regexp, cid, /*sticky=*/false,
+                                owner);
+      CreateSpecializedFunction(thread, zone, regexp, cid, /*sticky=*/true,
+                                owner);
+    }
   }
 
   return regexp.raw();
diff --git a/runtime/vm/regexp.h b/runtime/vm/regexp.h
index e026073..dbb89a4 100644
--- a/runtime/vm/regexp.h
+++ b/runtime/vm/regexp.h
@@ -1398,6 +1398,7 @@
   static CompilationResult CompileBytecode(RegExpCompileData* data,
                                            const RegExp& regexp,
                                            bool is_one_byte,
+                                           bool sticky,
                                            Zone* zone);
 
   static RawRegExp* CreateRegExp(Thread* thread,
diff --git a/runtime/vm/regexp_assembler_bytecode.cc b/runtime/vm/regexp_assembler_bytecode.cc
index a67c37b..4f31fcf 100644
--- a/runtime/vm/regexp_assembler_bytecode.cc
+++ b/runtime/vm/regexp_assembler_bytecode.cc
@@ -457,11 +457,12 @@
 
 static intptr_t Prepare(const RegExp& regexp,
                         const String& subject,
+                        bool sticky,
                         Zone* zone) {
   bool is_one_byte =
       subject.IsOneByteString() || subject.IsExternalOneByteString();
 
-  if (regexp.bytecode(is_one_byte) == TypedData::null()) {
+  if (regexp.bytecode(is_one_byte, sticky) == TypedData::null()) {
     const String& pattern = String::Handle(zone, regexp.pattern());
 #if !defined(PRODUCT)
     TimelineDurationScope tds(Thread::Current(), Timeline::GetCompilerStream(),
@@ -486,13 +487,13 @@
       regexp.set_is_complex();
     }
 
-    RegExpEngine::CompilationResult result =
-        RegExpEngine::CompileBytecode(compile_data, regexp, is_one_byte, zone);
+    RegExpEngine::CompilationResult result = RegExpEngine::CompileBytecode(
+        compile_data, regexp, is_one_byte, sticky, zone);
     ASSERT(result.bytecode != NULL);
     ASSERT((regexp.num_registers() == -1) ||
            (regexp.num_registers() == result.num_registers));
     regexp.set_num_registers(result.num_registers);
-    regexp.set_bytecode(is_one_byte, *(result.bytecode));
+    regexp.set_bytecode(is_one_byte, sticky, *(result.bytecode));
   }
 
   ASSERT(regexp.num_registers() != -1);
@@ -505,6 +506,7 @@
 static IrregexpInterpreter::IrregexpResult ExecRaw(const RegExp& regexp,
                                                    const String& subject,
                                                    intptr_t index,
+                                                   bool sticky,
                                                    int32_t* output,
                                                    intptr_t output_size,
                                                    Zone* zone) {
@@ -527,7 +529,7 @@
   }
 
   const TypedData& bytecode =
-      TypedData::Handle(zone, regexp.bytecode(is_one_byte));
+      TypedData::Handle(zone, regexp.bytecode(is_one_byte, sticky));
   ASSERT(!bytecode.IsNull());
   IrregexpInterpreter::IrregexpResult result =
       IrregexpInterpreter::Match(bytecode, subject, raw_output, index, zone);
@@ -551,8 +553,9 @@
 RawInstance* BytecodeRegExpMacroAssembler::Interpret(const RegExp& regexp,
                                                      const String& subject,
                                                      const Smi& start_index,
+                                                     bool sticky,
                                                      Zone* zone) {
-  intptr_t required_registers = Prepare(regexp, subject, zone);
+  intptr_t required_registers = Prepare(regexp, subject, sticky, zone);
   if (required_registers < 0) {
     // Compiling failed with an exception.
     UNREACHABLE();
@@ -562,7 +565,7 @@
   int32_t* output_registers = zone->Alloc<int32_t>(required_registers);
 
   IrregexpInterpreter::IrregexpResult result =
-      ExecRaw(regexp, subject, start_index.Value(), output_registers,
+      ExecRaw(regexp, subject, start_index.Value(), sticky, output_registers,
               required_registers, zone);
 
   if (result == IrregexpInterpreter::RE_SUCCESS) {
diff --git a/runtime/vm/regexp_assembler_bytecode.h b/runtime/vm/regexp_assembler_bytecode.h
index e8d6174..df9e46f 100644
--- a/runtime/vm/regexp_assembler_bytecode.h
+++ b/runtime/vm/regexp_assembler_bytecode.h
@@ -107,6 +107,7 @@
   static RawInstance* Interpret(const RegExp& regexp,
                                 const String& str,
                                 const Smi& start_index,
+                                bool is_sticky,
                                 Zone* zone);
 
  private:
diff --git a/runtime/vm/regexp_assembler_ir.cc b/runtime/vm/regexp_assembler_ir.cc
index efb9d64..bfe90b2 100644
--- a/runtime/vm/regexp_assembler_ir.cc
+++ b/runtime/vm/regexp_assembler_ir.cc
@@ -317,9 +317,10 @@
 RawArray* IRRegExpMacroAssembler::Execute(const RegExp& regexp,
                                           const String& input,
                                           const Smi& start_offset,
+                                          bool sticky,
                                           Zone* zone) {
   const intptr_t cid = input.GetClassId();
-  const Function& fun = Function::Handle(regexp.function(cid));
+  const Function& fun = Function::Handle(regexp.function(cid, sticky));
   ASSERT(!fun.IsNull());
   // Create the argument list.
   const Array& args =
diff --git a/runtime/vm/regexp_assembler_ir.h b/runtime/vm/regexp_assembler_ir.h
index a08e05f..ae70952 100644
--- a/runtime/vm/regexp_assembler_ir.h
+++ b/runtime/vm/regexp_assembler_ir.h
@@ -40,6 +40,7 @@
   static RawArray* Execute(const RegExp& regexp,
                            const String& input,
                            const Smi& start_offset,
+                           bool sticky,
                            Zone* zone);
 
   virtual bool IsClosed() const { return (current_instruction_ == NULL); }
diff --git a/runtime/vm/regexp_test.cc b/runtime/vm/regexp_test.cc
index b7f5a77..7eb55ad 100644
--- a/runtime/vm/regexp_test.cc
+++ b/runtime/vm/regexp_test.cc
@@ -18,7 +18,8 @@
   const RegExp& regexp =
       RegExp::Handle(RegExpEngine::CreateRegExp(thread, pat, false, false));
   const Smi& idx = Smi::Handle(Smi::New(0));
-  return IRRegExpMacroAssembler::Execute(regexp, str, idx, zone);
+  return IRRegExpMacroAssembler::Execute(regexp, str, idx, /*sticky=*/false,
+                                         zone);
 }
 
 TEST_CASE(RegExp_OneByteString) {
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 022199e..5e34b4a 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -552,6 +552,15 @@
 };
 
 
+class StringParameter : public MethodParameter {
+ public:
+  StringParameter(const char* name, bool required)
+      : MethodParameter(name, required) {}
+
+  virtual bool Validate(const char* value) const { return (value != NULL); }
+};
+
+
 class RunnableIsolateParameter : public MethodParameter {
  public:
   explicit RunnableIsolateParameter(const char* name)
@@ -2442,8 +2451,12 @@
 
 
 static const MethodParameter* reload_sources_params[] = {
-    RUNNABLE_ISOLATE_PARAMETER, new BoolParameter("force", false),
-    new BoolParameter("pause", false), NULL,
+    RUNNABLE_ISOLATE_PARAMETER,
+    new BoolParameter("force", false),
+    new BoolParameter("pause", false),
+    new StringParameter("rootLibUri", false),
+    new StringParameter("packagesUri", false),
+    NULL,
 };
 
 
@@ -2479,7 +2492,8 @@
   const bool force_reload =
       BoolParameter::Parse(js->LookupParam("force"), false);
 
-  isolate->ReloadSources(js, force_reload);
+  isolate->ReloadSources(js, force_reload, js->LookupParam("rootLibUri"),
+                         js->LookupParam("packagesUri"));
 
   Service::CheckForPause(isolate, js);
 
diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc
index 0ac2ae9..ae9eaf8 100644
--- a/runtime/vm/simulator_dbc.cc
+++ b/runtime/vm/simulator_dbc.cc
@@ -2669,7 +2669,7 @@
   }
 
   {
-    BYTECODE(LoadFieldTOS, A_D);
+    BYTECODE(LoadFieldTOS, __D);
     const uint16_t offset_in_words = rD;
     RawInstance* instance = static_cast<RawInstance*>(SP[0]);
     SP[0] = reinterpret_cast<RawObject**>(instance->ptr())[offset_in_words];
@@ -2677,7 +2677,7 @@
   }
 
   {
-    BYTECODE(InitStaticTOS, A);
+    BYTECODE(InitStaticTOS, 0);
     RawField* field = static_cast<RawField*>(*SP--);
     RawObject* value = field->ptr()->value_.static_value_;
     if ((value == Object::sentinel().raw()) ||
diff --git a/runtime/vm/source_report.cc b/runtime/vm/source_report.cc
index 390c0f5..e156203 100644
--- a/runtime/vm/source_report.cc
+++ b/runtime/vm/source_report.cc
@@ -1,7 +1,7 @@
 // Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
-
+#ifndef PRODUCT
 #include "vm/source_report.h"
 
 #include "vm/compiler.h"
@@ -533,3 +533,4 @@
 }
 
 }  // namespace dart
+#endif  // PRODUCT
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index 1c138e7..c036981 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -288,8 +288,9 @@
     TransitionNativeToVM transition(Thread::Current());
     success = isolate->ReloadSources(&js,
                                      false,  // force_reload
+                                     NULL, NULL,
                                      true);  // dont_delete_reload_context
-    fprintf(stderr, "RELOAD REPORT:\n%s\n", js.ToCString());
+    OS::PrintErr("RELOAD REPORT:\n%s\n", js.ToCString());
   }
 
   if (success) {
diff --git a/runtime/vm/verifier.cc b/runtime/vm/verifier.cc
index 5bc4765..fc11867 100644
--- a/runtime/vm/verifier.cc
+++ b/runtime/vm/verifier.cc
@@ -92,7 +92,12 @@
   if (obj->GetClassId() >= kInstanceCid) {
     if (obj->IsCanonical()) {
       instanceHandle_ ^= obj;
-      ASSERT(instanceHandle_.CheckIsCanonical(thread_));
+      const bool is_canonical = instanceHandle_.CheckIsCanonical(thread_);
+      if (!is_canonical) {
+        OS::PrintErr("Instance `%s` is not canonical!\n",
+                     instanceHandle_.ToCString());
+      }
+      ASSERT(is_canonical);
     }
   }
 }
diff --git a/sdk/lib/convert/utf.dart b/sdk/lib/convert/utf.dart
index aeee9ef..86763cb 100644
--- a/sdk/lib/convert/utf.dart
+++ b/sdk/lib/convert/utf.dart
@@ -37,7 +37,7 @@
    * The optional [allowMalformed] argument defines how [decoder] (and [decode])
    * deal with invalid or unterminated character sequences.
    *
-   * If it is `true` (and not overriden at the method invocation) [decode] and
+   * If it is `true` (and not overridden at the method invocation) [decode] and
    * the [decoder] replace invalid (or unterminated) octet
    * sequences with the Unicode Replacement character `U+FFFD` (�). Otherwise
    * they throw a [FormatException].
diff --git a/sdk/lib/html/dartium/nativewrappers.dart b/sdk/lib/html/dartium/nativewrappers.dart
index 441749c..0d4e111 100644
--- a/sdk/lib/html/dartium/nativewrappers.dart
+++ b/sdk/lib/html/dartium/nativewrappers.dart
@@ -4,31 +4,10 @@
 
 library nativewrappers;
 
-class NativeFieldWrapperClass1 {
-  NativeFieldWrapperClass1() {
-    throw new UnsupportedError(
-        "Generative constructors not supported on native types.");
-  }
-}
+class NativeFieldWrapperClass1 { }
 
-class NativeFieldWrapperClass2 {
-  NativeFieldWrapperClass2() {
-    throw new UnsupportedError(
-        "Generative constructors not supported on native types.");
-  }
-}
+class NativeFieldWrapperClass2 { }
 
-class NativeFieldWrapperClass3 {
-  NativeFieldWrapperClass3() {
-    throw new UnsupportedError(
-        "Generative constructors not supported on native types.");
-  }
-}
+class NativeFieldWrapperClass3 { }
 
-class NativeFieldWrapperClass4 {
-  NativeFieldWrapperClass4() {
-    throw new UnsupportedError(
-        "Generative constructors not supported on native types.");
-  }
-}
-
+class NativeFieldWrapperClass4 { }
diff --git a/sdk/lib/js/dart2js/js_dart2js.dart b/sdk/lib/js/dart2js/js_dart2js.dart
index 61bf1da..b08f7ac 100644
--- a/sdk/lib/js/dart2js/js_dart2js.dart
+++ b/sdk/lib/js/dart2js/js_dart2js.dart
@@ -465,7 +465,7 @@
     super['length'] = length;
   }
 
-  // Methods overriden for better performance
+  // Methods overridden for better performance
 
   void add(E value) {
     callMethod('push', [value]);
diff --git a/sdk/lib/js/dartium/js_dartium.dart b/sdk/lib/js/dartium/js_dartium.dart
index fbda496..b14e032 100644
--- a/sdk/lib/js/dartium/js_dartium.dart
+++ b/sdk/lib/js/dartium/js_dartium.dart
@@ -1557,7 +1557,7 @@
     super['length'] = length;
   }
 
-  // Methods overriden for better performance
+  // Methods overridden for better performance
 
   void add(E value) {
     callMethod('push', [value]);
diff --git a/tests/co19/co19-kernel.status b/tests/co19/co19-kernel.status
index 8b0d135..49a7ba9 100644
--- a/tests/co19/co19-kernel.status
+++ b/tests/co19/co19-kernel.status
@@ -328,6 +328,13 @@
 Language/Libraries_and_Scripts/Imports/static_type_t01/07: Pass
 Language/Libraries_and_Scripts/Imports/static_type_t01/02: Pass
 
+# dartk: JIT failures (debug)
+[ $compiler == dartk && $runtime == vm && $mode == debug ]
+Language/Expressions/Shift/syntax_t15: Crash  # Invalid class id during isolate shutdown Heap::VerifyGC
+Language/Expressions/Spawning_an_Isolate/new_isolate_t01: Crash  # Class finalization issue
+Language/Libraries_and_Scripts/Scripts/top_level_main_t05: Crash  # !main_obj.IsNull()
+LibTest/typed_data/ByteBuffer/runtimeType_A01_t02: Pass, Crash  # Out of memory
+LibTest/collection/DoubleLinkedQueue/every_A01_t02: Pass, Crash  # Out of memory
 
 # dartk: precompilation failures
 [ $compiler == dartkp && $runtime == dart_precompiled ]
@@ -631,4 +638,4 @@
 LibTest/core/Invocation/isSetter_A01_t02: Crash
 LibTest/core/Invocation/memberName_A01_t01: RuntimeError
 LibTest/core/Invocation/namedArguments_A01_t01: Crash
-LibTest/core/Invocation/positionalArguments_A01_t01: Crash
\ No newline at end of file
+LibTest/core/Invocation/positionalArguments_A01_t01: Crash
diff --git a/tests/compiler/dart2js/dart2js.status b/tests/compiler/dart2js/dart2js.status
index 9b3a477..22d2c68 100644
--- a/tests/compiler/dart2js/dart2js.status
+++ b/tests/compiler/dart2js/dart2js.status
@@ -68,6 +68,7 @@
 uri_retention_test: Pass, Slow
 value_range_test: Pass, Slow
 jsinterop/world_test: Pass, Slow
+sourcemaps/stacktrace_test: Pass, Slow
 
 [ $mode == debug ]
 check_elements_invariants_test: Skip # Slow and only needs to be run in one
diff --git a/tests/compiler/dart2js/kernel/closed_world_test.dart b/tests/compiler/dart2js/kernel/closed_world_test.dart
index d277221..aa21341 100644
--- a/tests/compiler/dart2js/kernel/closed_world_test.dart
+++ b/tests/compiler/dart2js/kernel/closed_world_test.dart
@@ -9,24 +9,18 @@
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/common.dart';
-import 'package:compiler/src/common/names.dart';
 import 'package:compiler/src/common/resolution.dart';
 import 'package:compiler/src/compiler.dart';
-import 'package:compiler/src/constants/expressions.dart';
 import 'package:compiler/src/dart_types.dart';
 import 'package:compiler/src/elements/elements.dart';
 import 'package:compiler/src/enqueue.dart';
 import 'package:compiler/src/js_backend/backend.dart';
 import 'package:compiler/src/js_backend/type_variable_handler.dart';
-import 'package:compiler/src/resolution/registry.dart';
-import 'package:compiler/src/resolution/tree_elements.dart';
 import 'package:compiler/src/ssa/kernel_impact.dart';
 import 'package:compiler/src/serialization/equivalence.dart';
-import 'package:compiler/src/universe/call_structure.dart';
-import 'package:compiler/src/universe/feature.dart';
+import 'package:compiler/src/universe/world_builder.dart';
 import 'package:compiler/src/universe/world_impact.dart';
 import 'package:compiler/src/world.dart';
-import 'package:expect/expect.dart';
 import 'impact_test.dart';
 import '../memory_compiler.dart';
 import '../serialization/helper.dart';
@@ -34,8 +28,27 @@
 
 const SOURCE = const {
   'main.dart': '''
-main() {
-  print('Hello World!');
+abstract class A {
+  // redirecting factory in abstract class to other class
+  factory A.a() = D.a;
+  // redirecting factory in abstract class to factory in abstract class
+  factory A.b() = B.a;
+}
+abstract class B implements A {
+  factory B.a() => null;
+}
+class C implements B {
+  // redirecting factory in concrete to other class
+  factory C.a() = D.a;
+}
+class D implements C {
+  D.a();
+}
+main(args) {
+  new A.a();
+  new A.b();
+  new C.a();
+  print(new List<String>()..add('Hello World!'));
 }
 '''
 };
@@ -62,6 +75,9 @@
           Flags.useKernel,
           Flags.enableAssertMessage
         ]);
+    ResolutionWorldBuilderImpl worldBuilder =
+        compiler.enqueuer.resolution.universe;
+    worldBuilder.useInstantiationMap = true;
     compiler.resolution.retainCachesForTesting = true;
     await compiler.run(entryPoint);
     compiler.openWorld.closeWorld(compiler.reporter);
@@ -78,14 +94,20 @@
         compiler.globalDependencies,
         backend,
         compiler.commonElements,
-        compiler.cacheStrategy);
+        compiler.cacheStrategy,
+        'enqueuer from kernel');
     // TODO(johnniwinther): Store backend info separately. This replacement is
     // made to reset a field in [TypeVariableHandler] that prevents it from
     // enqueuing twice.
     backend.typeVariableHandler = new TypeVariableHandler(compiler);
 
     backend.enqueueHelpers(enqueuer);
-    enqueuer.addToWorkList(compiler.mainFunction);
+    enqueuer.applyImpact(
+        compiler.impactStrategy,
+        enqueuer.nativeEnqueuer
+            .processNativeClasses(compiler.libraryLoader.libraries));
+    enqueuer.applyImpact(compiler.impactStrategy,
+        backend.computeMainImpact(enqueuer, compiler.mainFunction));
     enqueuer.forEach((work) {
       AstElement element = work.element;
       ResolutionImpact resolutionImpact = build(compiler, element.resolvedAst);
@@ -106,6 +128,15 @@
         // Redirecting factory constructors are skipped in kernel.
         return false;
       }
+      if (element is ClassElement) {
+        for (ConstructorElement constructor in element.constructors) {
+          if (!constructor.isRedirectingFactory) {
+            return true;
+          }
+        }
+        // The class cannot itself be instantiated.
+        return false;
+      }
       return true;
     }, verbose: arguments.verbose);
     checkClosedWorlds(compiler.closedWorld, closedWorld,
diff --git a/tests/compiler/dart2js/resolver_test.dart b/tests/compiler/dart2js/resolver_test.dart
index 8d1ec64..f88787b 100644
--- a/tests/compiler/dart2js/resolver_test.dart
+++ b/tests/compiler/dart2js/resolver_test.dart
@@ -241,7 +241,8 @@
     compiler.resolveStatement("Foo foo;");
     ClassElement fooElement = compiler.mainApp.find("Foo");
     FunctionElement funElement = fooElement.lookupLocalMember("foo");
-    compiler.processQueue(compiler.enqueuer.resolution, funElement);
+    compiler.enqueuer.resolution.addToWorkList(funElement);
+    compiler.processQueue(compiler.enqueuer.resolution, null);
     DiagnosticCollector collector = compiler.diagnosticCollector;
     Expect.equals(0, collector.warnings.length);
     Expect.equals(1, collector.errors.length);
diff --git a/tests/compiler/dart2js/serialization/model_test_helper.dart b/tests/compiler/dart2js/serialization/model_test_helper.dart
index 152bd39..e3e6614 100644
--- a/tests/compiler/dart2js/serialization/model_test_helper.dart
+++ b/tests/compiler/dart2js/serialization/model_test_helper.dart
@@ -22,6 +22,8 @@
 import 'package:compiler/src/serialization/equivalence.dart';
 import 'package:compiler/src/tree/nodes.dart';
 import 'package:compiler/src/universe/class_set.dart';
+import 'package:compiler/src/universe/world_builder.dart';
+import 'package:compiler/src/util/enumset.dart';
 import 'package:compiler/src/world.dart' show ClosedWorld;
 import '../memory_compiler.dart';
 import 'helper.dart';
@@ -108,15 +110,19 @@
     {bool typeEquivalence(DartType a, DartType b): areTypesEquivalent,
     bool elementFilter(Element element),
     bool verbose: false}) {
-  Iterable<Element> processedElements1 = enqueuer1.processedElements;
-  Iterable<Element> processedElements2 = enqueuer2.processedElements;
-  if (elementFilter != null) {
-    processedElements1 = processedElements1.where(elementFilter);
-    processedElements2 = processedElements2.where(elementFilter);
-  }
-
-  checkSets(processedElements1, processedElements2,
+  checkSets(enqueuer1.processedElements, enqueuer2.processedElements,
       "Processed element mismatch", areElementsEquivalent,
+      elementFilter: elementFilter, verbose: verbose);
+
+  ResolutionWorldBuilderImpl worldBuilder1 = enqueuer1.universe;
+  ResolutionWorldBuilderImpl worldBuilder2 = enqueuer2.universe;
+
+  checkMaps(
+      worldBuilder1.getInstantiationMap(),
+      worldBuilder2.getInstantiationMap(),
+      "Instantiated classes mismatch",
+      areElementsEquivalent,
+      (a, b) => areInstantiationInfosEquivalent(a, b, typeEquivalence),
       verbose: verbose);
 
   checkSets(
@@ -419,3 +425,23 @@
       outputUnit2.imports,
       (a, b) => areElementsEquivalent(a.declaration, b.declaration));
 }
+
+bool areInstantiationInfosEquivalent(InstantiationInfo info1,
+    InstantiationInfo info2, bool typeEquivalence(DartType a, DartType b)) {
+  checkMaps(
+      info1.instantiationMap,
+      info2.instantiationMap,
+      'instantiationMap of\n   '
+      '${info1.instantiationMap}\nvs ${info2.instantiationMap}',
+      areElementsEquivalent,
+      (a, b) => areSetsEquivalent(
+          a, b, (a, b) => areInstancesEquivalent(a, b, typeEquivalence)));
+  return true;
+}
+
+bool areInstancesEquivalent(Instance instance1, Instance instance2,
+    bool typeEquivalence(DartType a, DartType b)) {
+  return typeEquivalence(instance1.type, instance2.type) &&
+      instance1.kind == instance2.kind &&
+      instance1.isRedirection == instance2.isRedirection;
+}
diff --git a/tests/compiler/dart2js/serialization/test_helper.dart b/tests/compiler/dart2js/serialization/test_helper.dart
index f081bbd..1808b7f 100644
--- a/tests/compiler/dart2js/serialization/test_helper.dart
+++ b/tests/compiler/dart2js/serialization/test_helper.dart
@@ -208,18 +208,20 @@
   // set.difference would work)
   Set remaining = set2.toSet();
   for (var element1 in set1) {
+    bool found = false;
     var correspondingElement;
     for (var element2 in remaining) {
       if (sameElement(element1, element2)) {
         if (checkElements != null) {
           checkElements(element1, element2);
         }
+        found = true;
         correspondingElement = element2;
         remaining.remove(element2);
         break;
       }
     }
-    if (correspondingElement != null) {
+    if (found) {
       common.add([element1, correspondingElement]);
     } else {
       unfound.add(element1);
@@ -474,7 +476,17 @@
     void onSameElement(a, b),
     void onUnfoundElement(a),
     void onExtraElement(b),
+    bool elementFilter(element),
+    elementConverter(element),
     String elementToString(key): defaultToString}) {
+  if (elementFilter != null) {
+    set1 = set1.where(elementFilter);
+    set2 = set2.where(elementFilter);
+  }
+  if (elementConverter != null) {
+    set1 = set1.map(elementConverter);
+    set2 = set2.map(elementConverter);
+  }
   List<List> common = <List>[];
   List unfound = [];
   Set remaining = computeSetDifference(set1, set2, common, unfound,
diff --git a/tests/compiler/dart2js/sourcemaps/diff.dart b/tests/compiler/dart2js/sourcemaps/diff.dart
index 7505892..9627b3c 100644
--- a/tests/compiler/dart2js/sourcemaps/diff.dart
+++ b/tests/compiler/dart2js/sourcemaps/diff.dart
@@ -11,11 +11,7 @@
 import 'sourcemap_helper.dart';
 import 'sourcemap_html_helper.dart';
 
-enum DiffKind {
-  UNMATCHED,
-  MATCHING,
-  IDENTICAL,
-}
+enum DiffKind { UNMATCHED, MATCHING, IDENTICAL, }
 
 /// Id for an output column.
 class DiffColumn {
diff --git a/tests/compiler/dart2js/sourcemaps/html_parts.dart b/tests/compiler/dart2js/sourcemaps/html_parts.dart
index 2691a09..d4e809f 100644
--- a/tests/compiler/dart2js/sourcemaps/html_parts.dart
+++ b/tests/compiler/dart2js/sourcemaps/html_parts.dart
@@ -125,15 +125,7 @@
   }
 }
 
-enum HtmlPartKind {
-  CODE,
-  LINE,
-  CONST,
-  NEWLINE,
-  TEXT,
-  TAG,
-  LINE_NUMBER,
-}
+enum HtmlPartKind { CODE, LINE, CONST, NEWLINE, TEXT, TAG, LINE_NUMBER, }
 
 abstract class HtmlPart {
   void printHtmlOn(StringBuffer buffer, HtmlPrintContext context);
diff --git a/tests/compiler/dart2js/sourcemaps/lax_json_test.dart b/tests/compiler/dart2js/sourcemaps/lax_json_test.dart
index 3d78c7e..4af0301 100644
--- a/tests/compiler/dart2js/sourcemaps/lax_json_test.dart
+++ b/tests/compiler/dart2js/sourcemaps/lax_json_test.dart
@@ -51,9 +51,8 @@
     expect(decode('{"foo":"bar"}'), equals({'foo': 'bar'}));
     expect(decode('{"foo":"bar",}'), equals({'foo': 'bar'}));
     expect(
-        decode(
-            '{"foo":true, "bar": false, "baz": true, '
-                '"boz": \nnull\n,"qux": false,}'),
+        decode('{"foo":true, "bar": false, "baz": true, '
+            '"boz": \nnull\n,"qux": false,}'),
         equals({
           'foo': true,
           'bar': false,
diff --git a/tests/compiler/dart2js/sourcemaps/output_structure.dart b/tests/compiler/dart2js/sourcemaps/output_structure.dart
index 648973a..21a5bc3 100644
--- a/tests/compiler/dart2js/sourcemaps/output_structure.dart
+++ b/tests/compiler/dart2js/sourcemaps/output_structure.dart
@@ -637,11 +637,7 @@
   String toString() => '[$from,$to[';
 }
 
-enum CodeKind {
-  LIBRARY,
-  CLASS,
-  MEMBER,
-}
+enum CodeKind { LIBRARY, CLASS, MEMBER, }
 
 class CodeLocation {
   final Uri uri;
diff --git a/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart b/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
index ddb6fdc..423c054 100644
--- a/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
+++ b/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
@@ -307,7 +307,9 @@
 
   void addAnnotations(List<Annotation> annotations) {
     currentAnnotations.addAll(annotations);
-    currentLine.annotations.addAll(annotations);
+    if (currentLine != null) {
+      currentLine.annotations.addAll(annotations);
+    }
   }
 
   void beginLine(int currentOffset) {
diff --git a/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart b/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart
index 9fcebdc..8ece3d4 100644
--- a/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart
+++ b/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart
@@ -27,29 +27,35 @@
 }
 ''',
   '''
+import 'package:expect/expect.dart';
 main() {
   @{1:main}test();
 }
+@NoInline()
 test() {
   @{2:test}throw '$EXCEPTION_MARKER';
 }
 ''',
   '''
+import 'package:expect/expect.dart';
 main() {
   @{1:main}Class.test();
 }
 class Class {
+  @NoInline()
   static test() {
     @{2:Class.test}throw '$EXCEPTION_MARKER';
   }
 }
 ''',
   '''
+import 'package:expect/expect.dart';
 main() {
   var c = new Class();
   c.@{1:main}test();
 }
 class Class {
+  @NoInline()
   test() {
     @{2:Class.test}throw '$EXCEPTION_MARKER';
   }
@@ -67,6 +73,85 @@
   }
 }
 ''',
+  '''
+import 'package:expect/expect.dart';
+main() {
+  @{1:main}test();
+}
+@NoInline()
+test() {
+  try {
+    @{2:test}throw '$EXCEPTION_MARKER';
+  } finally {
+  }
+}
+''',
+  '''
+import 'package:expect/expect.dart';
+main() {
+  @{1:main}test();
+}
+@NoInline()
+test() {
+  try {
+    @{2:test}throw '$EXCEPTION_MARKER';
+  } on Error catch (e) {
+  }
+}
+''',
+  '''
+import 'package:expect/expect.dart';
+main() {
+  @{1:main}test();
+}
+@NoInline()
+test() {
+  try {
+    @{2:test}throw '$EXCEPTION_MARKER';
+  } on String catch (e) {
+    rethrow;
+  }
+}
+''',
+  '''
+import 'package:expect/expect.dart';
+main() {
+  test(); // This call is no longer on the stack when the error is thrown.
+}
+@NoInline()
+test() async {
+  @{1:test}throw '$EXCEPTION_MARKER';
+}
+''',
+  '''
+import 'package:expect/expect.dart';
+main() {
+  test1();
+}
+@NoInline()
+test1() async {
+  // This call is no longer on the stack when the error is thrown.
+  await test2();
+}
+@NoInline()
+test2() async {
+  @{1:test2}throw '$EXCEPTION_MARKER';
+}
+''',
+  '''
+import 'package:expect/expect.dart';
+main() {
+  test1();
+}
+@NoInline()
+test1() async {
+  @{1:test1}test2();
+}
+@NoInline()
+test2() {
+  @{2:test2}throw '$EXCEPTION_MARKER';
+}
+''',
 ];
 
 class Test {
@@ -80,7 +165,6 @@
 const int _CR = 0x0D;
 const int _LBRACE = 0x7B;
 
-
 Test processTestCode(String code) {
   StringBuffer codeBuffer = new StringBuffer();
   Map<int, StackTraceLine> stackTraceMap = <int, StackTraceLine>{};
@@ -135,12 +219,12 @@
 void main(List<String> arguments) {
   asyncTest(() async {
     for (String code in TESTS) {
-      await runTest(processTestCode(code));
+      await runTest(processTestCode(code), verbose: arguments.contains('-v'));
     }
   });
 }
 
-Future runTest(Test test) async {
+Future runTest(Test test, {bool verbose: false}) async {
   Directory tmpDir = await createTempDir();
   String input = '${tmpDir.path}/$INPUT_FILE_NAME';
   new File(input).writeAsStringSync(test.code);
@@ -162,9 +246,13 @@
       JSON.decode(new File('$output.map').readAsStringSync()));
 
   print("Running d8 $output");
-  ProcessResult runResult =
-      Process.runSync(d8executable, [output]);
+  ProcessResult runResult = Process.runSync(d8executable,
+      ['sdk/lib/_internal/js_runtime/lib/preambles/d8.js', output]);
   String out = '${runResult.stderr}\n${runResult.stdout}';
+  if (verbose) {
+    print('d8 output:');
+    print(out);
+  }
   List<String> lines = out.split(new RegExp(r'(\r|\n|\r\n)'));
   List<StackTraceLine> jsStackTrace = <StackTraceLine>[];
   bool seenMarker = false;
@@ -210,6 +298,12 @@
       }
     }
   }
+  if (verbose) {
+    print('JavaScript stacktrace:');
+    print(jsStackTrace.join('\n'));
+    print('Dart stacktrace:');
+    print(dartStackTrace.join('\n'));
+  }
   Expect.equals(
       expectedIndex,
       test.expectedLines.length,
@@ -341,4 +435,4 @@
     return 'third_party/d8/macos/d8';
   }
   throw new UnsupportedError('Unsupported platform.');
-}
\ No newline at end of file
+}
diff --git a/tests/corelib/regexp/regexp_test.dart b/tests/corelib/regexp/regexp_test.dart
index 60483ba..3231f2a 100644
--- a/tests/corelib/regexp/regexp_test.dart
+++ b/tests/corelib/regexp/regexp_test.dart
@@ -591,4 +591,28 @@
   // Tests skipped from V8:
   // Test that RegExp.prototype.toString() throws TypeError for
   // incompatible receivers (ES5 section 15.10.6 and 15.10.6.4).
+
+  testSticky();
+}
+
+testSticky() {
+  var re = new RegExp(r"foo.bar");
+  Expect.isNotNull(re.matchAsPrefix("foo_bar", 0));
+  Expect.isNull(re.matchAsPrefix("..foo_bar", 0));
+  Expect.isNotNull(re.matchAsPrefix("..foo_bar", 2));
+
+  re = new RegExp(r"^foo");
+  Expect.isNotNull(re.matchAsPrefix("foobar", 0));
+  Expect.isNull(re.matchAsPrefix("..foo", 0));
+  Expect.isNull(re.matchAsPrefix("..foo", 2));
+
+  re = new RegExp(r"^foo", multiLine: true);
+  Expect.isNotNull(re.matchAsPrefix("foobar", 0));
+  Expect.isNull(re.matchAsPrefix("..\nfoo", 0));
+  Expect.isNotNull(re.matchAsPrefix("..\nfoo", 3));
+  Expect.isNull(re.matchAsPrefix("..\nfoofoo", 6));
+
+  re = new RegExp(r"bar$");
+  Expect.isNull(re.matchAsPrefix("foobar", 0));
+  Expect.isNotNull(re.matchAsPrefix("foobar", 3));
 }
diff --git a/tests/language/field_test.dart b/tests/language/field_test.dart
index 6a1937f..ca41740 100644
--- a/tests/language/field_test.dart
+++ b/tests/language/field_test.dart
@@ -52,11 +52,11 @@
     // The tests below are a little cumbersome because not
     // everything is implemented yet.
     var o = new Second();
-    // 'a' getter is overriden, always returns -12.
+    // 'a' getter is overridden, always returns -12.
     Expect.equals(-12, o.a);
     o.a = 2;
     Expect.equals(-12, o.a);
-    // 'b' setter is overriden to write 12 to field 'c'.
+    // 'b' setter is overridden to write 12 to field 'c'.
     o.b = o;
     Expect.equals(12, o.c);
   }
diff --git a/tests/language/language.status b/tests/language/language.status
index e6b27de..5a23a4d 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -261,7 +261,6 @@
 library_env_test/has_mirror_support: RuntimeError, OK
 
 [ $hot_reload || $hot_reload_rollback ]
-methods_as_constants_test: Skip # Issue 27803
 static_closure_identical_test: Pass, Fail # Closure identity
 cha_deopt1_test: Crash # Requires deferred libraries
 cha_deopt2_test: Crash # Requires deferred libraries
@@ -297,6 +296,10 @@
 tearoff_basic_test: Crash # Requires deferred libraries
 conditional_import_test: Crash # Requires deferred libraries
 conditional_import_string_test: Crash # Requires deferred libraries
+override_field_method1_negative_test: Pass, Crash # Issue 27835
+override_field_method2_negative_test: Pass, Crash # Issue 27835
+override_field_method4_negative_test: Pass, Crash # Issue 27835
+override_field_method5_negative_test: Pass, Crash # Issue 27835
 
 [$runtime != vm || $compiler != none]
 assert_initializer_test: SKIP  # not implemented yet, experiment is VM only.
diff --git a/tests/language/language_kernel.status b/tests/language/language_kernel.status
index 1346de2..3d87904 100644
--- a/tests/language/language_kernel.status
+++ b/tests/language/language_kernel.status
@@ -141,8 +141,6 @@
 enum_test: RuntimeError
 evaluation_redirecting_constructor_test: RuntimeError
 example_constructor_test: RuntimeError
-execute_finally8_test: RuntimeError
-execute_finally9_test: RuntimeError
 export_double_same_main_test: Crash
 export_main_test: Crash
 external_test/10: MissingRuntimeError
@@ -345,6 +343,15 @@
 vm/type_cast_vm_test: RuntimeError
 vm/type_vm_test: RuntimeError
 
+# dartk: JIT failures (debug)
+[ $compiler == dartk && $runtime == vm && $mode == debug ]
+async_star_regression_fisk_test: Crash  # Stack mismatch during expression translation.
+async_star_test: Crash  # Stack mismatch during expression translation.
+issue23244_test: Crash  # Class finalization issue
+not_enough_positional_arguments_test/02: Crash  # Crash
+not_enough_positional_arguments_test/05: Crash  # Crash
+vm/optimized_guarded_field_isolates_test: Crash  # Class finalization issue
+
 # dartk: precompilation failures
 [ $compiler == dartkp && $runtime == dart_precompiled ]
 accessor_conflict_export2_test: RuntimeError
@@ -697,4 +704,4 @@
 vm/debug_break_enabled_vm_test/none: CompileTimeError
 vm/reflect_core_vm_test: CompileTimeError
 vm/type_cast_vm_test: RuntimeError
-vm/type_vm_test: RuntimeError
\ No newline at end of file
+vm/type_vm_test: RuntimeError
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 9bcdd8e..ab4f18c 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -396,11 +396,8 @@
 convert/utf85_test: Pass, Timeout
 
 [ $hot_reload || $hot_reload_rollback ]
-async/zone_debug_test: Skip # Issue 27803
-async/intercept_print1_test: Skip # Issue 27803
 async/multiple_timer_test: Pass, Fail # Timing related
 async/stream_transformer_test: Pass, Fail # Closure identity
-convert/json_toEncodable_reviver_test: Skip # Issue 27803
 mirrors/closurization_equivalence_test: SkipByDesign # Method equality
 mirrors/fake_function_with_call_test: SkipByDesign # Method equality
 
diff --git a/tools/VERSION b/tools/VERSION
index da4c303..b4d1f0b 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,5 +28,5 @@
 MAJOR 1
 MINOR 21
 PATCH 0
-PRERELEASE 7
+PRERELEASE 8
 PRERELEASE_PATCH 0
diff --git a/tools/bots/bot_utils.py b/tools/bots/bot_utils.py
index 1e2ce69..dcd5433 100644
--- a/tools/bots/bot_utils.py
+++ b/tools/bots/bot_utils.py
@@ -352,6 +352,7 @@
   with open(checksum_filename, 'w') as f:
     f.write('%s *%s' % (checksum, mangled_filename))
 
+  print "MD5 checksum of %s is %s" % (filename, checksum)
   return checksum_filename
 
 def CreateSha256ChecksumFile(filename, mangled_filename=None):
@@ -365,6 +366,7 @@
   with open(checksum_filename, 'w') as f:
     f.write('%s *%s' % (checksum, mangled_filename))
 
+  print "SHA256 checksum of %s is %s" % (filename, checksum)
   return checksum_filename
 
 def GetChannelFromName(name):
diff --git a/tools/dartk_wrappers/dartk b/tools/dartk_wrappers/dartk
new file mode 100755
index 0000000..ca93a28
--- /dev/null
+++ b/tools/dartk_wrappers/dartk
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+# Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$BASH_SOURCE"
+WRAPPERS_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+DART_ROOT="$(cd "${WRAPPERS_DIR}/../.." ; pwd -P)"
+DARTK="$DART_ROOT/third_party/pkg/kernel/bin/dartk.dart"
+
+if [[ `uname` == 'Darwin' ]];
+then
+  DART="$DART_ROOT/tools/sdks/mac/dart-sdk/bin/dart"
+else
+  DART="$DART_ROOT/tools/sdks/linux/dart-sdk/bin/dart"
+fi
+
+exec "$DART" "$DARTK" "$@"
diff --git a/tools/testing/dart/compiler_configuration.dart b/tools/testing/dart/compiler_configuration.dart
index 868c74c..f348318 100644
--- a/tools/testing/dart/compiler_configuration.dart
+++ b/tools/testing/dart/compiler_configuration.dart
@@ -217,7 +217,7 @@
 
   @override
   String computeCompilerPath(String buildDir) {
-    return 'third_party/pkg/kernel/bin/dartk.dart';
+    return 'tools/dartk_wrappers/dartk$executableScriptSuffix';
   }
 
   CompilationCommand computeCompilationCommand(